aboutsummaryrefslogtreecommitdiffstats
path: root/dev.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-09-18 23:12:18 -0700
committerAdam Soltys <[email protected]>2026-09-18 23:12:18 -0700
commit703ee6e1281e72ec00f65768d7de7a015c242abb (patch)
tree8a643d0f1ad6d6e49db210aec45341a7b119e5ab /dev.js
parent9e0f9528cd6726836386658c4f38ba8a42bea3ac (diff)
downloadcoinosv3-703ee6e1281e72ec00f65768d7de7a015c242abb.tar.gz
coinosv3-703ee6e1281e72ec00f65768d7de7a015c242abb.zip
Accounts from the header, snapshot-first Spending restore, name ownership grants.
Header buttons always leave the current feature screen; an account with no remembered nostr identity opens Accounts instead of nothing. Logout confirms in place. A scan finishing after logout or an account switch no longer drops the new session into offline mode (stateGeneration guards in sync + ark). Spending restores from the snapshot first. A migration grant names the identity that owns an address; its manager may register it without becoming that identity (names/ownership.js). Browser tests for account access, profile retry, spending restore, thread reply focus, custom-emoji reactions and registry ownership. Co-Authored-By: Claude Fable 5.1 <[email protected]>
Diffstat (limited to 'dev.js')
-rw-r--r--dev.js18
1 files changed, 15 insertions, 3 deletions
diff --git a/dev.js b/dev.js
index 54a88a2..347ef41 100644
--- a/dev.js
+++ b/dev.js
@@ -6,12 +6,13 @@
// localhost or from a phone over the LAN/Tailscale — no per-device config, no
// CORS. HTTP backends by path prefix; WebSocket backends by exact path.
-import { buildHtml, buildJsQr } from './build.js';
+import { buildHtml, buildJsQr, buildNip46, buildVerifyWorker } from './build.js';
const port = Number(process.env.PORT || 5173);
const HTTP_PROXY = { '/boltz': 'http://localhost:9001', '/esplora': 'http://localhost:3000', '/sp': 'http://localhost:8888' };
const WS_PROXY = { '/electrum': 'ws://localhost:50003', '/sp/ws': 'ws://localhost:8888/ws' };
+const JS_ASSETS = { '/jsqr.js': buildJsQr, '/nip46.js': buildNip46, '/verify-worker.js': buildVerifyWorker };
const CORS = { 'access-control-allow-origin': '*', 'access-control-allow-methods': 'GET,POST,OPTIONS', 'access-control-allow-headers': 'content-type' };
Bun.serve({
@@ -40,11 +41,22 @@ Bun.serve({
return new Response(await r.arrayBuffer(), { status: r.status, headers: { 'content-type': r.headers.get('content-type') || 'application/json', ...CORS } });
}
}
- if (path === '/jsqr.js') {
- return new Response(await buildJsQr({ minify: false }), {
+ if (Object.hasOwn(JS_ASSETS, path)) {
+ return new Response(await JS_ASSETS[path]({ minify: false }), {
headers: { 'content-type': 'text/javascript; charset=utf-8', 'cache-control': NO_STORE },
});
}
+ if (/^\/(punks|punks-sm)\//.test(path)) {
+ // These are bundled images, not app routes. Returning index.html here
+ // produces broken avatars and rebuilds the app for every face.
+ if (!/^\/(punks|punks-sm)\/([1-9]|[1-5][0-9]|6[0-4])\.webp$/.test(path)) {
+ return new Response('Not found', { status: 404 });
+ }
+ const file = Bun.file('static' + path);
+ return await file.exists()
+ ? new Response(file, { headers: { 'content-type': 'image/webp', 'cache-control': NO_STORE } })
+ : new Response('Not found', { status: 404 });
+ }
const loc = path.match(/^\/locales\/([a-z]{2})\.json$/);
if (loc) {
const f = Bun.file('src/locales/' + loc[1] + '.json');