mirror of
https://github.com/luxfi/explore.git
synced 2026-07-27 05:54:15 +00:00
Drops "subnet" from the P-chain surface, which is not our vocabulary:
useSubnets -> useNets (useSubnets.ts deleted)
PChainSubnet -> PChainNet
GetSubnetsResponse -> GetNetsResponse
One "subnet" deliberately survives — `subnetID` in lib/api/pchain/wire.spec.ts.
That is the UPSTREAM P-chain wire field, read through a raw
Record<string,string> cast, so renaming it would break response parsing. The
rule is about our own language, not about lying to the wire.
Also adds deploy/k8s/explore-fe/ingress-mainnet.yaml. explore.lux.network is
served by the Next.js deployment explore-fe-lux (ghcr.io/luxfi/explore), not
the Go `explorer` binary, which only backs api-explore.lux.network. This
replaces drift where the plain Ingress pointed explore.lux.network at
explorer:80 — the Go binary's embedded, stale build.
Two pre-commit gates had to be satisfied, both legitimate:
- eslint max-len: three className lines (BridgePage 230 chars, ChainRow 188 x2)
exceeded the 160 limit; wrapped.
- cspell: `platformvm` flagged unknown. It is the P-chain VM's actual name, so
it is added to cspell.jsonc `words` rather than renamed in code. (Note for
the next person: .cspell-words.txt is listed under ignorePaths — it is a file
excluded from checking, NOT the dictionary. Adding a word there does nothing.)
Verified: tsc --noEmit reports ZERO errors in every file this commit touches and
zero stale-symbol errors, so the rename resolves completely. The project's 223
pre-existing errors are all in untouched files and unchanged by this commit.
102 lines
3.9 KiB
JavaScript
102 lines
3.9 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Generate public/.well-known/explore.json from configs/app/chainRegistry.ts.
|
|
*
|
|
* Run at build time so the federation manifest is always in sync with the
|
|
* chains the explorer actually knows about. Output is byte-identical when
|
|
* the registry hasn't changed (stable key order, trailing newline).
|
|
*
|
|
* Usage:
|
|
* node scripts/generate-well-known.js # write public/.well-known/explore.json
|
|
* node scripts/generate-well-known.js --check # exit 1 if file out of sync
|
|
*/
|
|
'use strict';
|
|
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
|
|
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
const REGISTRY_PATH = path.join(REPO_ROOT, 'configs/app/chainRegistry.ts');
|
|
const OUT_PATH = path.join(REPO_ROOT, 'public/.well-known/explore.json');
|
|
|
|
/** Parse a minimal subset of chainRegistry.ts to extract { chainId, label, network } per CHAINS[] entry.
|
|
* Avoids running TypeScript at build time — the registry is hand-edited and stable enough for regex.
|
|
*/
|
|
function parseChainEntries(src) {
|
|
const start = src.indexOf('export const CHAINS');
|
|
if (start < 0) throw new Error('CHAINS export not found in chainRegistry.ts');
|
|
const end = src.indexOf('];', start);
|
|
if (end < 0) throw new Error('CHAINS export not terminated');
|
|
const block = src.slice(start, end);
|
|
|
|
// Match every chain object literal: { name: ..., label: ..., network: ..., chainId: <N>, ... }
|
|
const entryRe = /name:\s*'([^']+)',[\s\S]*?label:\s*'([^']+)',[\s\S]*?network:\s*'([^']+)',[\s\S]*?chainId:\s*(\d+)/g;
|
|
const entries = [];
|
|
let m;
|
|
while ((m = entryRe.exec(block)) !== null) {
|
|
entries.push({ name: m[1], label: m[2], network: m[3], chainId: Number(m[4]) });
|
|
}
|
|
return entries;
|
|
}
|
|
|
|
/** Display name for a federated chain. C-Chain (Contract Chain) is handled
|
|
* separately by the caller; other chains use the short `name` field plus
|
|
* " Network". Sovereign L1s are Networks (Lux nomenclature; never the
|
|
* legacy upstream term for them). */
|
|
function networkDisplayName(rawName) {
|
|
return `${ rawName.trim() } Network`;
|
|
}
|
|
|
|
/** Build the federation manifest. Mainnet chains only — testnet/devnet are operator-visible
|
|
* but not federation peers. Localnet is excluded entirely (chainId 1337 is reserved).
|
|
*/
|
|
function buildManifest(entries) {
|
|
const chains = entries
|
|
.filter((e) => e.network === 'mainnet')
|
|
.map((e) => ({
|
|
id: e.chainId,
|
|
name: e.label === 'Contract Chain' ? 'Lux Mainnet' : networkDisplayName(e.name),
|
|
}));
|
|
|
|
// Always include explicit Lux Testnet/Devnet so peers can discover them.
|
|
const testnet = entries.find((e) => e.network === 'testnet' && e.label === 'Contract Chain');
|
|
const devnet = entries.find((e) => e.network === 'devnet' && e.label === 'Contract Chain');
|
|
if (testnet) chains.splice(1, 0, { id: testnet.chainId, name: 'Lux Testnet' });
|
|
if (devnet) chains.splice(2, 0, { id: devnet.chainId, name: 'Lux Devnet' });
|
|
|
|
return {
|
|
brandId: 'lux',
|
|
appId: 'explore',
|
|
title: 'Lux Explorer',
|
|
domain: 'explore.lux.network',
|
|
url: 'https://explore.lux.network',
|
|
github: 'https://github.com/luxfi/explore',
|
|
chains,
|
|
peers: [],
|
|
capabilities: [ 'blocks', 'transactions', 'accounts', 'tokens' ],
|
|
apiVersion: '1',
|
|
};
|
|
}
|
|
|
|
function main() {
|
|
const src = fs.readFileSync(REGISTRY_PATH, 'utf8');
|
|
const manifest = buildManifest(parseChainEntries(src));
|
|
const out = JSON.stringify(manifest, null, 2) + '\n';
|
|
|
|
const check = process.argv.includes('--check');
|
|
if (check) {
|
|
const current = fs.existsSync(OUT_PATH) ? fs.readFileSync(OUT_PATH, 'utf8') : '';
|
|
if (current !== out) {
|
|
process.stderr.write(`${ path.relative(REPO_ROOT, OUT_PATH) } is out of sync. Run: node scripts/generate-well-known.js\n`);
|
|
process.exit(1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
fs.mkdirSync(path.dirname(OUT_PATH), { recursive: true });
|
|
fs.writeFileSync(OUT_PATH, out);
|
|
process.stdout.write(`Wrote ${ path.relative(REPO_ROOT, OUT_PATH) } (${ manifest.chains.length } chains)\n`);
|
|
}
|
|
|
|
main();
|