Snapshot commit rolling up ~255 files of coherent-but-multi-domain in-flight
work that had accumulated on this branch. Split by area:
Contracts + covenants
- New: AsmFxSwap, DeviantOpenMintNBA, DeviantTieredMintOracleFT,
TermCouponVault, UniformReserve, UniformReserveAggregate.
- Verify-artifact refresh (src/verify/artifacts/*.json + canonical.ts).
Wallet + shell (shells/app + src/wallet)
- App.tsx, MainScreen, ArtemisionScreen, AssetDetail, AgoraScreen,
SettingsScreen, Unlock, TokenImportModal, UniformFiat/DepositPanel,
KatalogosPanel (renamed from PinaxPanel), shell.css.
- src/wallet: wallet.ts, runtime.ts, index.ts. Core registry/chipnetFile.
- Deleted stale hook: useAllDevBalances.ts.
Cross-chain + correspondent (services/correspondent + scripts)
- Correspondent server/bch/config updates for PYUSD Solana, EURC Sepolia,
aggregate reserve flows.
- New scripts: PYUSD roundtrip, EURC onboarding, GMX game loop /
genesis / mint sanity, tiered mint fee, aggregate reserve, product2
shares dividends, product3 t-bond, uniform fiat cell tests.
Telegram order-book (P2PExchange bot)
- db.ts, index.ts, en/ru locales — updates upstream from the extracted
standalone repo at D:/Dev/P2PExchange.
Docs — Parameters (specs), wiki, snapshots, design mockups
- Parameters: FIATm/MBA_Shares/Potidaea/Anthemus refinements +
ASM_CrossChain/DebitCredit + UniformFiat + Anthemus DEX MVP prompt +
Artemision + Athenae Politeia + Philosophy + SSHkeyServer runbook +
new dApp/{Artemision,Katalogos,Pinax,Pari_escrow,SURFACES}.
- wiki: cross-chain, games-tote, glossary, governance/voting-systems,
infra, wallet, wallet-ui-design, decisions (ADR log).
- snapshots: catch-up entries and INDEX regeneration.
- design: mockups refreshed (agora, asset-detail, assets-tab, potidaea)
+ Potidaea assets + tote deploy notes.
Housekeeping
- .gitignore: exclude the new root test/session state files
(.sol-vault-keys.json, .football-tote-state.json,
.tote-platform-state.json, .redeem-roundtrip-state.json,
.eurc-onboard-state.json — some contain oracle privkeys / vault
secretKeyBase58; NEVER commit) + the .usdm-historical-chart.html
chart output + MS Office `~$*` lock files + scripts/bundle-surfaces
`build/` output. Also add scripts/bundle-surfaces.mjs.
- CLAUDE.md, WALLET-COORDINATION.md, snapshots/INDEX.md, design/README.md
refreshed.
- package.json / package-lock.json bumps.
Verified: sensitive files at repo root confirmed ignored (git check-ignore
each). No `.env`, no raw WIF/xprv/mnemonic/secretKey/oraclePriv strings in
the staged diff. MS Word autosave file (`Parameters/Philosophy/~$*.docx`)
excluded and gitignored.
The WizardConnect responder work landed separately in the previous commit
(6987591); this is everything else that had accumulated alongside it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
148 lines
6 KiB
JavaScript
148 lines
6 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* bundle-surfaces.mjs — make the Artemision design surfaces deployable, one
|
|
* subdomain per page.
|
|
*
|
|
* The pages are authored to run from `file://` inside the repo, so they carry
|
|
* two repo-shaped dependencies that DO NOT survive being moved to a subdomain
|
|
* root:
|
|
*
|
|
* 1. `../../../design/cosmo-genesis.css` — three levels up. At a subdomain
|
|
* root there is no "three levels up", so the page loads unstyled.
|
|
* 2. `../Katalogos/index.html` and friends — sibling-folder links. On separate
|
|
* subdomains these are dead.
|
|
*
|
|
* This copies each page into its own output folder, inlines the design system
|
|
* next to it, and rewrites the cross-links to absolute subdomain URLs.
|
|
*
|
|
* node scripts/bundle-surfaces.mjs --domain example.com
|
|
* node scripts/bundle-surfaces.mjs --domain example.com --out build/surfaces
|
|
*
|
|
* Output: build/surfaces/<sub>/index.html + cosmo-genesis.css, one per surface.
|
|
* Everything is static — no server code, no build toolchain, no secrets.
|
|
*/
|
|
import { readFileSync, writeFileSync, mkdirSync, rmSync, existsSync } from 'node:fs';
|
|
import { join, dirname } from 'node:path';
|
|
|
|
const ROOT = join(import.meta.dirname, '..');
|
|
const args = process.argv.slice(2);
|
|
const arg = (name, fallback) => {
|
|
const i = args.indexOf(`--${name}`);
|
|
return i >= 0 && args[i + 1] ? args[i + 1] : fallback;
|
|
};
|
|
|
|
const DOMAIN = arg('domain');
|
|
const OUT = join(ROOT, arg('out', 'build/surfaces'));
|
|
if (!DOMAIN) {
|
|
console.error('usage: node scripts/bundle-surfaces.mjs --domain <example.com> [--out <dir>]');
|
|
process.exit(1);
|
|
}
|
|
|
|
/** subdomain → source page. The subdomain is the key. */
|
|
const SURFACES = {
|
|
artemision: 'Parameters/dApp/Artemision/website.html', // the public site
|
|
create: 'Parameters/dApp/Artemision/index.html', // the interactive desk
|
|
pinax: 'Parameters/dApp/Pinax/index.html',
|
|
katalogos: 'Parameters/dApp/Katalogos/index.html',
|
|
};
|
|
|
|
/** Repo-relative link → absolute subdomain URL. Longest patterns first. */
|
|
const LINK_MAP = [
|
|
['../Artemision/website.html', `https://artemision.${DOMAIN}/`],
|
|
['../Artemision/index.html', `https://create.${DOMAIN}/`],
|
|
['../Katalogos/index.html', `https://katalogos.${DOMAIN}/`],
|
|
['../Pinax/index.html', `https://pinax.${DOMAIN}/`],
|
|
['../Explorer/index.html', `https://katalogos.${DOMAIN}/`], // retired prototype → its successor
|
|
['../SURFACES.md', `https://artemision.${DOMAIN}/`],
|
|
// Same-folder links (the website ↔ desk pair live in one source folder).
|
|
['href="index.html"', `href="https://create.${DOMAIN}/"`],
|
|
['\'index.html\'', `'https://create.${DOMAIN}/'`],
|
|
];
|
|
|
|
const CSS_SRC = join(ROOT, 'design/cosmo-genesis.css');
|
|
if (!existsSync(CSS_SRC)) {
|
|
console.error(`missing design system at ${CSS_SRC}`);
|
|
process.exit(1);
|
|
}
|
|
const css = readFileSync(CSS_SRC, 'utf8');
|
|
|
|
rmSync(OUT, { recursive: true, force: true });
|
|
|
|
let built = 0;
|
|
for (const [sub, rel] of Object.entries(SURFACES)) {
|
|
const src = join(ROOT, rel);
|
|
if (!existsSync(src)) { console.error(` ! missing ${rel} — skipped`); continue; }
|
|
|
|
let html = readFileSync(src, 'utf8');
|
|
|
|
// 1. the design system now sits beside the page
|
|
const before = html;
|
|
html = html.replaceAll('../../../design/cosmo-genesis.css', 'cosmo-genesis.css');
|
|
if (html === before) console.warn(` ~ ${sub}: no cosmo-genesis.css link found — check the page`);
|
|
|
|
// 2. cross-links become absolute subdomain URLs
|
|
for (const [from, to] of LINK_MAP) html = html.replaceAll(from, to);
|
|
|
|
// 3. anything still pointing up a directory would 404 at a subdomain root
|
|
const stragglers = [...html.matchAll(/(?:href|src)="(\.\.\/[^"]*)"/g)].map((m) => m[1]);
|
|
if (stragglers.length) {
|
|
console.warn(` ~ ${sub}: unresolved relative links → ${[...new Set(stragglers)].join(', ')}`);
|
|
}
|
|
|
|
const dir = join(OUT, sub);
|
|
mkdirSync(dir, { recursive: true });
|
|
writeFileSync(join(dir, 'index.html'), html);
|
|
writeFileSync(join(dir, 'cosmo-genesis.css'), css);
|
|
console.log(` ✓ ${sub}.${DOMAIN} ← ${rel}`);
|
|
built++;
|
|
}
|
|
|
|
// nginx: one TLS server block per surface, all static, no backend.
|
|
const nginx = Object.keys(SURFACES).map((sub) => `
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name ${sub}.${DOMAIN};
|
|
# ACME first, then force TLS — WebCrypto and the clipboard API both require
|
|
# a secure context, and the Katalogos opens a WSS connection.
|
|
location /.well-known/acme-challenge/ { root /var/www/certbot; }
|
|
location / { return 301 https://$host$request_uri; }
|
|
}
|
|
|
|
server {
|
|
listen 443 ssl;
|
|
listen [::]:443 ssl;
|
|
http2 on;
|
|
server_name ${sub}.${DOMAIN};
|
|
|
|
ssl_certificate /etc/letsencrypt/live/${sub}.${DOMAIN}/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/${sub}.${DOMAIN}/privkey.pem;
|
|
|
|
root /var/www/surfaces/${sub};
|
|
index index.html;
|
|
|
|
# Static pages that talk to a public Electrum over WSS. No backend, no
|
|
# cookies, no keys — so the policy can be strict.
|
|
add_header X-Content-Type-Options "nosniff" always;
|
|
add_header X-Frame-Options "DENY" always;
|
|
add_header Referrer-Policy "no-referrer" always;
|
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
|
|
location = /index.html { add_header Cache-Control "no-cache"; }
|
|
location ~* \\.(css|js|svg|woff2?)$ { expires 7d; add_header Cache-Control "public"; }
|
|
location / { try_files $uri $uri/ =404; }
|
|
}`).join('\n');
|
|
|
|
mkdirSync(OUT, { recursive: true });
|
|
writeFileSync(join(OUT, 'surfaces.nginx.conf'), nginx.trimStart() + '\n');
|
|
|
|
const subs = Object.keys(SURFACES);
|
|
writeFileSync(join(OUT, 'DNS.txt'),
|
|
`A records to create (point each at the VPS that will serve these):\n\n` +
|
|
subs.map((s) => ` ${s}.${DOMAIN}\tA\t<VPS_IP>`).join('\n') +
|
|
`\n\nThen, on the VPS:\n\n certbot certonly --webroot -w /var/www/certbot ` +
|
|
subs.map((s) => `-d ${s}.${DOMAIN}`).join(' ') + `\n`);
|
|
|
|
console.log(`\n${built} surface(s) → ${OUT}`);
|
|
console.log(` surfaces.nginx.conf — ${subs.length} server blocks`);
|
|
console.log(` DNS.txt — the A records + the certbot line`);
|