board / client / test / vectors / generate.mjs
  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);

static mirror of HEAD · about · clone: git clone https://git.ardegazu.ro/board.git