aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/feature-registry-check.js51
-rw-r--r--tools/minimal-smoke.js7
-rw-r--r--tools/nostr-login-test.js2
3 files changed, 27 insertions, 33 deletions
diff --git a/tools/feature-registry-check.js b/tools/feature-registry-check.js
index 9b7ac5e..0931156 100644
--- a/tools/feature-registry-check.js
+++ b/tools/feature-registry-check.js
@@ -1,40 +1,29 @@
-// Guard: src/features/index.js and build.js's ALL_FEATURES must agree.
+// Guard: src/features/index.js and build.js's featureIndexSource must agree.
// They drifted once (nwc was added to index.js only, so its i18n strings
// shipped but its code never did — the settings card silently never rendered,
// because build.js SWAPS OUT features/index.js for a generated module).
+//
+// The strongest form of agreement is equality: the checked-in module must be
+// code-identical (comments and whitespace aside) to what featureIndexSource
+// generates for the full feature set — imports, construction order, deferred
+// placeholder slots, and the deferred loader all included.
// bun tools/feature-registry-check.js
import { readFileSync } from 'node:fs';
+import { featureIndexSource, enabledFeatures } from '../build.js';
-const idx = readFileSync(new URL('../src/features/index.js', import.meta.url), 'utf8');
-const build = readFileSync(new URL('../build.js', import.meta.url), 'utf8');
+const strip = (s) => s
+ .replace(/\/\/[^\n]*/g, '') // line comments
+ .replace(/\s+/g, ' ') // whitespace runs
+ .replace(/, /g, ',').replace(/ ,/g, ',')
+ .trim();
-const inIndex = [...idx.matchAll(/import \{ (\w+Feature) \} from '\.\/([\w-]+)\.js'/g)]
- .map((m) => ({ fn: m[1], name: m[2] }));
-const registry = build.match(/const ALL_FEATURES = \{([^}]*)\}/s)?.[1] || '';
-const inBuild = [...registry.matchAll(/(\w+):\s*'(\w+Feature)'/g)].map((m) => ({ name: m[1], fn: m[2] }));
+const idx = readFileSync(new URL('../src/features/index.js', import.meta.url), 'utf8');
+const gen = featureIndexSource(enabledFeatures(undefined));
-let ok = true;
-for (const f of inIndex) {
- if (!inBuild.find((b) => b.fn === f.fn)) {
- console.log(`x ${f.fn} (${f.name}.js) is in features/index.js but NOT in build.js ALL_FEATURES — it will not ship`);
- ok = false;
- }
-}
-for (const b of inBuild) {
- if (!inIndex.find((f) => f.fn === b.fn)) {
- console.log(`x ${b.fn} is in build.js ALL_FEATURES but not imported in features/index.js`);
- ok = false;
- }
-}
-// Compare the ORDER FEATURES ARE CONSTRUCTED IN (hook precedence depends on
-// it), not the order they happen to be imported in.
-const built = [...(idx.match(/return \[([^\]]*)\]/s)?.[1] || '')
- .matchAll(/(\w+Feature)\(ctx\)/g)].map((m) => m[1]);
-const orderIdx = built.join(',');
-const orderBuild = inBuild.map((b) => b.fn).join(',');
-if (ok && orderIdx !== orderBuild) {
- console.log(`x feature ORDER differs (hook precedence depends on it)\n index.js: ${orderIdx}\n build.js: ${orderBuild}`);
- ok = false;
+if (strip(idx) !== strip(gen)) {
+ console.log('x src/features/index.js does not match build.js featureIndexSource (full set)');
+ console.log('\n--- generated (normalized) ---\n' + strip(gen));
+ console.log('\n--- checked in (normalized) ---\n' + strip(idx));
+ process.exit(1);
}
-if (ok) console.log(`ok ${inIndex.length} features registered consistently`);
-process.exit(ok ? 0 : 1);
+console.log(`ok features/index.js matches the generator (${enabledFeatures(undefined).length} features, deferred slots included)`);
diff --git a/tools/minimal-smoke.js b/tools/minimal-smoke.js
index bd0d588..f3f896c 100644
--- a/tools/minimal-smoke.js
+++ b/tools/minimal-smoke.js
@@ -29,7 +29,10 @@ check('no ark protocol code', !html.includes('Ark VTXO mailbox authorization'));
check('no swap protocol code', !html.includes('swap/reverse'));
check('no musig code', !html.includes('MuSig/noncecoef'));
check('no silent-payment engine', !html.includes('BIP0352') && !html.includes('__SP_WORKER__'));
-check('no nostr sync code', !html.includes('30078') && !html.includes('relay.coinos.io'));
+// The sync EVENT KIND must be gone; the coinos relay hostname alone is not a
+// sync marker anymore — recipient search (send-to-npub, core UX) carries
+// PROFILE_RELAYS for profile lookups even in the minimal build.
+check('no nostr sync code', !html.includes('30078'));
const server = Bun.serve({ port: 5198, fetch: () => new Response(html, { headers: { 'content-type': 'text/html' } }) });
@@ -62,6 +65,8 @@ try {
await sleep(400);
console.log('\n[1] import + core wallet');
+ await clickText('button', 'Get started'); // the front door gained a step
+ await sleep(300);
await clickText('button', 'Import existing');
await sleep(200);
await page.type('textarea', generateMnemonic(wordlist));
diff --git a/tools/nostr-login-test.js b/tools/nostr-login-test.js
index 468ffb4..25983a4 100644
--- a/tools/nostr-login-test.js
+++ b/tools/nostr-login-test.js
@@ -58,7 +58,7 @@ check('another account cannot decrypt it', denied);
console.log('\n[NIP-98 auth]');
{
- const { nip98Header } = await import('../src/nostr-login.js');
+ const { nip98Header } = await import('../src/nip98.js');
const { verifyEvent } = await import('nostr-tools/pure');
const { sha256: sha } = await import('@noble/hashes/sha256');
const body = JSON.stringify({ name: 'x' });