/**
* Restore the v1.0.0 dist/ file tree as thin ESM re-export shims.
*
* v1.0.0 was compiled by tsc, so dist/ mirrored src/ one file per module, and
* the package's exports map pointed at ./dist/chat/index.js and
* ./dist/board/index.js. A shadow-cljs :esm build emits one FLAT file per
* :modules entry instead (dist/index.js, dist/chat.js, dist/board.js,
* dist/internals.js), so every historical path would 404 after the port.
*
* The table below is therefore the API contract: one entry per file the
* TypeScript build published, listing the exact names it exported, and which
* flat module now provides them. Each shim is generated deterministically
* (sorted, fixed formatting) so the committed dist stays byte-stable for
* deploy/check-dist.sh.
*
* `lib/protocol` was TYPES ONLY in TypeScript; it compiles to an empty module
* and is emitted as `export {};` — exactly what tsc produced.
*
* Adding a name here does NOT create it: it must already be a named export of
* the target module (see shadow-cljs.edn :exports), or Node throws at import.
* test/subpaths.test.mjs imports every path below and checks every name.
*/
import { mkdirSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
const DIST = new URL("../dist", import.meta.url).pathname;
/** path (under dist/, without .js) -> { from: module, names: [...] } */
const SHIMS = {
// ---- the two published subpath exports ----
"chat/index": { from: "chat", names: ["ChatClient", "newRoomSecret", "CHAT_SALT"] },
"board/index": { from: "board", names: ["BoardClient", "BOARD_SALT", "newRoomSecret"] },
// ---- lib/ (never a subpath export; kept for relative deep imports) ----
"lib/crypto": {
from: "internals",
names: ["randomBytes", "toB64", "fromB64", "toB64url", "fromB64url", "newPeerId", "Sealer",
"AtRestCipher", "RoomCrypto"],
also: { from: "index", names: ["newRoomSecret"] },
},
"lib/encryption": { from: "internals", names: ["makeLogEncryption"] },
"lib/descriptor": { from: "internals", names: ["resolveRelayConfig"] },
"lib/turn": { from: "internals", names: ["IceConfig"] },
"lib/access": { from: "internals", names: ["HardenedIPFSAccessController", "signerMatchesIdentity"] },
"lib/orbit-identity": { from: "internals", names: ["SuetaIdentityProvider", "registerSuetaProvider"] },
"lib/log": { from: "internals", names: ["openHelia", "RoomLog"] },
"lib/net": { from: "internals", names: ["newSessionKey", "Net"] },
"lib/protocol": { typesOnly: true },
// ---- node/ ----
"node/env": {
from: "internals",
names: ["selfPeerIds", "installOriginWebSocket", "installOriginFetch"],
also: { from: "index", names: ["installOrigin", "installBrowserGlobals"] },
},
};
const HEADER =
"// Generated by scripts/gen-subpaths.mjs — re-export shim for the file layout\n" +
"// the TypeScript build (v1.0.0) published. Do not edit; edit the table there.\n";
/**
* The flat modules live at dist/<mod>.js, so a shim at dist/a/b.js reaches them
* by climbing back to the root. `relative()` alone is wrong here: for
* dist/chat/index.js and the module "chat" it yields "" (it compares the shim's
* DIRECTORY with a name that is actually a FILE at the root). Count the depth.
*/
const specifier = (path, mod) => {
const depth = path.split("/").length - 1;
return depth === 0 ? `./${mod}` : `${"../".repeat(depth)}${mod}`;
};
let files = 0;
let names = 0;
for (const [path, spec] of Object.entries(SHIMS)) {
const file = join(DIST, `${path}.js`);
mkdirSync(dirname(file), { recursive: true });
let body = HEADER;
if (spec.typesOnly) {
body += "// (types only in the TypeScript original — no runtime exports)\nexport {};\n";
} else {
for (const part of [spec, spec.also].filter(Boolean)) {
const sorted = [...part.names].sort();
body += `export { ${sorted.join(", ")} } from "${specifier(path, part.from)}.js";\n`;
names += sorted.length;
}
}
writeFileSync(file, body);
files++;
}
console.log(`gen-subpaths: ${files} shims, ${names} re-exported names`);