Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
# The tests and build.js only use Node's standard library and the
# bundles committed in src/www/js/lib, so nothing is installed.
cache: npm
# The tests load a few packages (QR and UR decoding, descriptors) from the
# lockfile. Install scripts are not needed for the tests or build.js.
- name: Install
run: npm ci --ignore-scripts
- name: Tests
run: npm test
- name: dist/index.html matches the source
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ node build.js
sha256sum dist/index.html
```

`build.js` needs Node.js only; no packages are installed. The bundled libraries in `src/www/js/lib` are committed build outputs: six are built with esbuild by the `build_*.js` scripts from the pinned versions in `package-lock.json`, the rest are older browserify builds from `libs/`.
`build.js` needs Node.js only; no packages are installed. The bundled libraries in `src/www/js/lib` are committed build outputs: seven are built with esbuild by the `build_*.js` scripts from the pinned versions in `package-lock.json`, the rest are older browserify builds from `libs/`.

Before tagging a release, `npm run release:check` runs the tests, rebuilds `dist/index.html` and fails if the committed file differs from the source.

Expand Down
48 changes: 48 additions & 0 deletions build_qrscan.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Bundle src/www/js/lib/_qrscan_entry.js → src/www/js/lib/qrscan.js using
// esbuild + node-polyfill. Run via `node build_qrscan.js`.
//
// jsQR decodes QR codes; @ngraveio/bc-ur reassembles animated UR codes. Node's
// crypto module gets the same small shim as build_sp.js, and the build fails
// if the full crypto polyfill ends up bundled.

const path = require('path');
const esbuild = require('esbuild');
const { polyfillNode } = require('esbuild-plugin-polyfill-node');

const cryptoShim = {
name: 'crypto-shim',
setup(build) {
build.onResolve({ filter: /^crypto$/ }, () => ({
path: path.join(__dirname, 'src/www/js/lib/_crypto_shim.js'),
}));
},
};

esbuild.build({
entryPoints: ['src/www/js/lib/_qrscan_entry.js'],
bundle: true,
format: 'iife',
globalName: 'qrScan',
minify: true,
target: 'es2020',
outfile: 'src/www/js/lib/qrscan.js',
metafile: true,
plugins: [
cryptoShim,
polyfillNode({
globals: { buffer: true, process: true },
polyfills: { crypto: false, buffer: true, process: true, util: true, stream: true, events: true, string_decoder: true, assert: true },
}),
],
define: {
'global': 'globalThis',
},
}).then((result) => {
const leaked = Object.keys(result.metafile.inputs)
.filter((input) => /crypto-browserify|node_modules\/elliptic\//.test(input));
if (leaked.length) throw new Error(`qrscan.js must not bundle these: ${leaked.join(', ')}`);
console.log('qrscan.js bundled');
}).catch((e) => {
console.error(e);
process.exit(1);
});
1,122 changes: 1,054 additions & 68 deletions dist/index.html

Large diffs are not rendered by default.

114 changes: 114 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
"dev": "node --watch src/server.js",
"build": "node ./build.js",
"git": "npm run build && git pull && git add . && git commit -m \"$MSG\" && git push",
"test": "node test/raw-entropy.test.js && node test/entropy-staleness.test.js && node test/seed-safety.test.js",
"test": "node test/raw-entropy.test.js && node test/entropy-staleness.test.js && node test/seed-safety.test.js && node test/keys.test.js && node test/qrscan.test.js && node test/ui.test.js",
"release:check": "npm test && npm run build && git diff --exit-code -- dist/index.html"
},
"author": "SuperPhatArrow",
"license": "GPLv3",
"devDependencies": {
"@bcts/dcbor": "^1.0.0-beta.0",
"@bcts/sskr": "^1.0.0-beta.0",
"@ngraveio/bc-ur": "^1.1.13",
"@types/node": "^25.8.0",
"bip32": "^5.0.0-rc.0",
"bip322-js": "^3.0.0",
Expand All @@ -23,6 +24,7 @@
"bolt12-utils": "^0.1.1",
"browserify": "^17.0.0",
"esbuild-plugin-polyfill-node": "^0.3.0",
"jsqr": "^1.4.0",
"light-bolt11-decoder": "^3.2.0",
"silent-payments": "^2.1.0",
"slip39-ts": "^0.1.13",
Expand Down
69 changes: 67 additions & 2 deletions src/www/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -1341,8 +1341,10 @@ select option {
border: none;
outline: none;
cursor: pointer;
padding: 10px 16px;
font-size: 1.125rem;
padding: 10px 8px;
font-size: 0.875rem;
font-weight: 600;
line-height: 1.3;
transition: background-color 120ms, color 120ms;
border-radius: 7px;
}
Expand Down Expand Up @@ -3781,3 +3783,66 @@ pre {
@media (max-width: 420px) {
.cards { grid-template-columns: 1fr; }
}

/* ============================================================
Load tabs, word boxes, button rows, QR scanner, Nostr keys
============================================================ */
.tab button span[aria-hidden="true"] {
font-size: 1.125rem;
margin-right: 4px;
}
.tab button:focus-visible {
outline: 2px solid var(--q-accent-hi);
outline-offset: 2px;
}
.inputMnemonic-word.word-invalid {
border-color: var(--q-danger);
box-shadow: 0 0 0 1px var(--q-danger);
}
.button-row {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
margin: 8px 0;
}
.qr-scan__video {
display: block;
width: 100%;
max-height: 50vh;
object-fit: cover;
border-radius: var(--radius-sm);
background: #000;
margin: 8px 0;
}
.qr-scan__progress {
height: 6px;
border-radius: 3px;
background: var(--q-border-soft);
overflow: hidden;
margin: 8px 0;
}
.qr-scan__bar {
height: 100%;
width: 0;
background: var(--q-accent-hi);
transition: width 150ms;
}
.qr-scan__file {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
overflow: hidden;
}
.qr-scan__file:focus-visible + label {
outline: 2px solid var(--q-accent-hi);
outline-offset: 2px;
}
.nostr-keys details {
margin: 8px 0 16px;
}
.nostr-keys summary {
cursor: pointer;
color: var(--q-muted);
}
Loading
Loading