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 | /**
* BOARD_TS=1 node test/vectors/generate.mjs
*
* Golden-vector extractor for everything board owns above the vendored p2p lib.
*
* Run against the TypeScript implementation while it was still canon, per
* dev/docs/CLJS.md: "splice the real modules into a harness rather than
* transcribing their logic into a generator". harness/ts.mjs esbuild-bundles
* `src/**.ts` once and hands the REAL classes over; hard-private members come in
* through a mechanically injected `__t` bag, so not one line of logic is
* retyped, and every fixture records the input script beside the snapshot so it
* stays REPLAYABLE after the TypeScript is gone.
*
* The lib layer below `app/` is only partly re-extracted here: board's
* lib/{access,crypto,descriptor,encryption,log,net,orbit-identity,selftest,turn}.ts
* are byte-identical to chat's pre-CLJS ancestors (verified by diff), so those
* fixtures are reused verbatim as `vectors/rk-*.json` from rooms-kit and
* re-verified against THIS TypeScript by test/vectors.test.mjs in BOARD_TS=1
* mode. What IS extracted here is board's own: app/{ops,state,trust,boards,tools}
* and lib/{epoch,policy,wrapbox} (board-only).
*
* Not re-runnable after the TypeScript is retired (it needs esbuild, which the
* CLJS install drops). Kept in the tree as the provenance record.
*/
import { writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { installDom, localStorageStub } from "../harness/dom.mjs";
installDom();
const { mods, TS_MODE, priv } = await import("../helpers/load.mjs");
if (!TS_MODE) throw new Error("run with BOARD_TS=1: fixtures come from the TypeScript, never from the port");
const M = await mods();
const { installDetRandom, resetRandom, restoreRandom, hex } = await import("../helpers/det-random.mjs");
const F = await import("../helpers/app-fakes.mjs");
// installed BEFORE any script runs: element ids, IVs and ephemeral keys become
// a known stream, so the fixtures pin the bytes and not merely "it round-trips"
installDetRandom();
const { Identity } = await import("ardegazu-id-kit");
const OUT = dirname(fileURLToPath(import.meta.url));
const write = (name, data) => {
writeFileSync(join(OUT, `${name}.json`), `${JSON.stringify(data, null, 2)}\n`);
console.log(`wrote ${name}.json`);
};
/* ------------------------------------------------------------------ config -- */
write("config", {
appSalt: M.APP_SALT,
ns: M.NS,
// Every persistent name the app ever writes. A change here orphans existing
// users' identity seed, grants, board list, camera and block store.
keys: ["id", "id-prev", "name", "mode", "trust", "boards", "boards-gone", "lang", "storage-migrated"].map((k) => [
k,
M.nsKey(k),
]),
perBoardKeys: ["cam", "mbx-cursor", "mbx-queue", "mbx-sent", "mbx-retry", "mbx-ident"].map((k) => [
k,
M.nsKey(`${k}:ROOMID`),
]),
dbs: ["blocks", "data"].map((d) => [d, M.nsDb(d)]),
});
/* -------------------------------------------------------- board wire bytes -- */
write("ops", await F.opsScript(M));
write("tools", await F.toolsScript(M, priv, resetRandom));
write("projector", await F.projectorScript(M, priv));
write("live", await F.liveScript(M));
write("devicesync", await F.deviceSyncScript(M, Identity, localStorageStub));
/* --------------------------------------------------------- the access layer -- */
write("epoch", await F.epochScript(M, resetRandom, hex));
write("wrapbox", await F.wrapboxScript(M, Identity, resetRandom, hex));
restoreRandom();
write("policy", await F.policyScript(M, Identity));
/* ------------------------------------------------------------- app storage -- */
write("trust", await F.trustScript(M, localStorageStub));
write("boards", await F.boardsScript(M, localStorageStub));
// RETIRED with the cap itself: the outgoing queue is now uncapped (no silent
// drop-oldest — see lib/mailbox.cljs), so the "queuecap" fixture and the
// queueCapScript that recorded the TypeScript's 2000-item drop are gone.
// chat's mailbox transcript, re-recorded under BOARD's salt and namespace: the
// module is byte-identical apart from the queueCap lines, but the fixture pins
// nsKey strings and kMbx-sealed bytes, both of which are salt-derived
write("mailbox", await F.mailboxScript({ ...M, priv, localStorageStub }));
/* ---------------------------------------------------------------------- i18n -- */
{
const langs = ["en", "ro", "hu"];
const out = { keys: {}, snapshot: {} };
for (const lang of langs) {
out.keys[lang] = M.catalogKeys(lang);
// byte snapshot: the whole catalog, so a single changed character in a
// Romanian or Hungarian string fails the suite (the transliteration gate)
out.snapshot[lang] = Object.fromEntries(out.keys[lang].map((k) => [k, M.catalogRaw(lang, k)]));
}
// the plural sites, spelled out — Romanian's few/other split and Hungarian's
// uninflected numerals must survive the port
out.plurals = {};
for (const k of out.keys.en) {
const shapes = Object.fromEntries(langs.map((l) => [l, M.catalogMsg(l, k)]));
if (langs.some((l) => Array.isArray(shapes[l]))) out.plurals[k] = shapes;
}
write("i18n", out);
}
console.log("done");
process.exit(0);
|