1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 | /**
* Module loader for the black-box tests, in the shape rooms-kit established.
*
* Default: the ClojureScript build (`test-dist/testlib.js`, produced by
* `shadow-cljs release testlib`) — the tests run against compiled output, never
* against src/.
*
* With `SUETA_TS=1` it instead loads the TypeScript implementation through
* harness/ts.mjs. That mode is the suite's own regression harness: a test that
* passes on the CLJS build but was never checked against the TS one cannot tell
* "the port is right" from "the assertion is wrong". Every assertion in
* test/*.test.mjs was run green in BOTH modes before the TypeScript was retired,
* and the mode stays wired so the record is reproducible from git history.
*
* Both modes are normalised to one flat module map, so no test knows which
* implementation it is driving.
*/
import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
const HERE = dirname(fileURLToPath(import.meta.url));
export const CLIENT = join(HERE, "..", "..");
export const TS_MODE = process.env.SUETA_TS === "1";
/** CLJS keeps "private" members as `_name` string keys (peer-kit's idiom). */
export const priv = TS_MODE ? (o, n) => o.__t[n] : (o, n) => o[`_${n}`].bind(o);
let cached = null;
export async function mods() {
if (cached) return cached;
if (TS_MODE) {
const { loadTs } = await import("../harness/ts.mjs");
const m = await loadTs();
cached = {
// config
APP_SALT: m.APP_SALT,
NS: m.NS,
nsKey: m.nsKey,
nsDb: m.nsDb,
// lib/crypto
RoomCrypto: m.RoomCrypto,
Sealer: m.Sealer,
AtRestCipher: m.AtRestCipher,
toB64: m.toB64,
fromB64: m.fromB64,
toB64url: m.toB64url,
fromB64url: m.fromB64url,
randomBytes: m.randomBytes,
newPeerId: m.newPeerId,
newRoomSecret: m.newRoomSecret,
// lib/encryption
makeLogEncryption: m.encryption.makeLogEncryption,
// lib/access
signerMatchesIdentity: m.access.signerMatchesIdentity,
HardenedIPFSAccessController: m.access.HardenedIPFSAccessController,
// lib/orbit-identity
SuetaIdentityProvider: m.orbitIdentity.SuetaIdentityProvider,
registerSuetaProvider: m.orbitIdentity.registerSuetaProvider,
// lib/descriptor, lib/turn
resolveRelayConfig: m.descriptor.resolveRelayConfig,
IceConfig: m.turn.IceConfig,
// lib/log, lib/net
openHelia: m.log.openHelia,
RoomLog: m.log.RoomLog,
Net: m.net.Net,
newSessionKey: m.net.newSessionKey,
// lib/mailbox
MailboxAuth: m.mailbox.MailboxAuth,
MailboxClient: m.mailbox.MailboxClient,
MailboxSync: m.mailbox.MailboxSync,
// lib/selftest
runSelfTest: m.selftest.runSelfTest,
// app
loadHistory: m.history.loadHistory,
trustObserve: m.trust.observe,
trustSetVerified: m.trust.setVerified,
trustIsVerified: m.trust.isVerified,
loadRooms: m.rooms.loadRooms,
touchRoom: m.rooms.touchRoom,
renameRoom: m.rooms.renameRoom,
forgetRoom: m.rooms.forgetRoom,
buildRoomSync: m.rooms.buildRoomSync,
mergeRooms: m.rooms.mergeRooms,
setOnRoomsChanged: m.rooms.setOnRoomsChanged,
migrateLegacyHistory: m.migrate.migrateLegacyHistory,
migrateStorageNS: m.migrateStorage.migrateStorageNS,
ChatStore: m.chat.ChatStore,
CallManager: m.call.CallManager,
// i18n
catalogKeys: (lang) => Object.keys({ en: m.en, ro: m.ro, hu: m.hu }[lang]).sort(),
// the FULL message under a key: a string, or the plural-variant object.
// catalogMsg below reports only the variant NAMES, which would leave the
// Romanian and Hungarian plural TEXT unsnapshotted.
catalogRaw: (lang, k) => {
const msg = { en: m.en, ro: m.ro, hu: m.hu }[lang][k];
return typeof msg === "string" ? msg : msg === undefined ? undefined : { ...msg };
},
catalogMsg: (lang, k) => {
const msg = { en: m.en, ro: m.ro, hu: m.hu }[lang][k];
return typeof msg === "string" ? msg : msg === undefined ? undefined : Object.keys(msg).sort();
},
t: m.i18n.t,
tn: m.i18n.tn,
};
return cached;
}
cached = await import(pathToFileURL(join(CLIENT, "test-dist", "testlib.js")).href);
return cached;
}
export const readVector = (name) =>
JSON.parse(readFileSync(join(HERE, "..", "vectors", `${name}.json`), "utf8"));
export const hex = (u8) => [...u8].map((b) => b.toString(16).padStart(2, "0")).join("");
export const fromHex = (s) => {
const out = new Uint8Array(s.length / 2);
for (let i = 0; i < out.length; i++) out[i] = parseInt(s.slice(i * 2, i * 2 + 2), 16);
return out;
};
export const json = (x) => JSON.parse(JSON.stringify(x));
|