eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1#!/usr/bin/env node
2// 🤖 Generates the NATIVE seed catalogue — appCatalogReport() for every
3// built-in app, as the JSON the iOS/Mac apps bundle
4// (ios/LChatCore/Sources/LChatCore/Seed/app-catalog.json, decoded by
5// AppRegistry). The seed is what lets native know every built-in app's
6// manifest facts (title, glyph, places, presentation, commands) with ZERO
7// per-app native code before any webview has reported the live catalogue;
8// the runtime appCatalog() pull supersedes it per space (custom + member
9// apps only exist there). Run after adding or changing an app:
10//
11// node tools/gen-app-catalog.mjs --write # regenerate the bundled seed
12// node tools/gen-app-catalog.mjs # print to stdout
13//
14// test/appcatalog-seed.test.mjs pins the committed seed against this
15// generator's output, so a drifted seed fails `npm test` — the same
16// drift-gate shape as the schema copies (test/schema-engine.test.mjs).
17import { readdirSync, writeFileSync, readFileSync } from "node:fs";
18import { fileURLToPath } from "node:url";
19import path from "node:path";
20
21const root = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
22const appsDir = path.join(root, "web", "static", "apps");
23export const seedPath = path.join(
24 root, "ios", "LChatCore", "Sources", "LChatCore", "Seed", "app-catalog.json");
25
26// appstudio.js needs a real DOM at module scope (it builds its editor
27// eagerly), so it can't load headless. It registers no places and no
28// commands — nothing a native picker or router reads — so the seed simply
29// omits it; spaces that install it still report it via the live pull.
30const SKIP = new Set(["appstudio.js"]);
31
32export async function collect() {
33 const files = readdirSync(appsDir)
34 .filter((f) => f.endsWith(".js") && !SKIP.has(f))
35 .sort();
36 for (const f of files) await import(path.join(appsDir, f));
37 const { appCatalogReport } = await import(path.join(appsDir, "..", "apps.js"));
38 // Sorted by name so regenerating is a stable diff.
39 return appCatalogReport().sort((a, b) => a.name.localeCompare(b.name));
40}
41
42const isMain = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
43if (isMain) {
44 const json = JSON.stringify(await collect(), null, 2) + "\n";
45 if (process.argv.includes("--write")) {
46 const before = (() => { try { return readFileSync(seedPath, "utf8"); } catch { return ""; } })();
47 writeFileSync(seedPath, json);
48 console.log(before === json ? `unchanged: ${seedPath}` : `wrote ${seedPath}`);
49 } else {
50 process.stdout.write(json);
51 }
52}
53