feat(#14): bump @nostr-dev-kit/ndk 2.8.1 → 3.0.3 + nostr-tools v1 → v2.20 + acl wire-name vocabulary #15
Merged
padreug
merged 4 commits from 2026-05-31 11:49:30 +00:00
issue-14-ndk-bump into dev
4 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| e8f245c917 |
fix(deps): cap nostr-tools at ~2.20.0 (regtest Node 20 / curves v2 ESM-only) (#14)
Some checks failed
Docker image / build-and-push-image (push) Has been cancelled
Caught during regtest dogfood after the previous three commits
landed. With `nostr-tools: ^2.17.2` pnpm resolved to 2.23.5, which
in turn pulls `@noble/curves@2.0.1` — ESM-only. The regtest
Dockerfile runs on Node 20.11.1, where CJS `require()` of pure-ESM
modules is hard-blocked:
Error [ERR_REQUIRE_ESM]: require() of ES Module
/app/node_modules/.pnpm/@noble+curves@2.0.1/.../secp256k1.js
from /app/node_modules/.pnpm/nostr-tools@2.23.5/.../index.js
not supported.
nostr-tools 2.21.0 was the cutover — that release flipped
`@noble/curves` from `1.2.0` to `2.0.1`. 2.20.0 is the last
nostr-tools 2.x release that's still CJS-friendly via @noble/curves
1.2.0. Capping our pin at `~2.20.0` keeps us within the
"nostr-tools >= 2.17.2" range NDK 3.0.3 asks for in its
peerDependency while sidestepping the ESM/CJS hazard.
This isn't a regression we introduce — it's a CJS-output footgun
unique to the regtest container's Node 20 + tsup-default-CJS
combination. Long-term fix paths (out of scope here):
* Bump the container's Node base image to >= 22 (where
`--experimental-require-module` is on by default for `.js`
files inside `package.json type: "commonjs"`)
* Switch tsup output to ESM (`tsup --format esm`) — wider
surface change across the daemon, the client CLI, and the
Dockerfile entrypoint
* Accept the cap forever (small downside: 2.21+ patch fixes
won't reach us until we fix one of the above)
The cap is intentionally tight (`~2.20.0` allows 2.20.x patches,
nothing newer) so a future `pnpm update` doesn't silently jump us
back over the 2.21 edge. Revisit when one of the long-term paths
above lands.
Refs aiolabs/nsecbunkerd#14, regtest dogfood 2026-05-31.
|
|||
| db1a834587 |
refactor(acl): align IMethod with NIP-46 wire-name vocabulary (#14)
NDK 3.x's `NDKNip46Backend` passes the wire method name verbatim to `pubkeyAllowed` — `nip04_encrypt`, `nip04_decrypt`, `nip44_encrypt`, `nip44_decrypt`, etc. NDK 2.8.1 normalized these to `encrypt`/`decrypt` before calling the permit callback; that normalization was the root of why our encrypt/decrypt path had never worked end-to-end against lnbits's bunker-backed signer (lnbits stores `PolicyRule.method` using wire names, our auth lookup looked for the normalized name → no match → request fell through to the never-resolved admin prompt and timed out at 15s). Source `IMethod` directly from NDK's exported `NIP46Method` union so it can't drift across future bumps. If NDK adds a new method (e.g. `nip60_*`) we pick it up for free. Drop the `method as IMethod` cast at the `signingAuthorizationCallback` call site — both sides now share the same vocabulary by construction. This is the substantive win that aiolabs/nsecbunkerd#14 is filed for. With this commit: - `sign_event` policy rules with kinds continue to match exactly as before (kind stringification path unchanged). - `nip04_encrypt` / `nip04_decrypt` / `nip44_encrypt` / `nip44_decrypt` policy rules — kind-less — now match the live-policy join (step 4 of `checkIfPubkeyAllowed`) by their method-name alone. lnbits's bunker-mediated `signer.nip44_decrypt` and `signer.nip44_encrypt` calls (per `aiolabs/lnbits` PR #38 phase 2.4) start succeeding end-to-end against any operator account whose Policy carries those rules — which `_ensure_policy`'s self-heal already ensures for every newly-bound operator (per coord log 2026-05-30T22:00Z). - `switch_relays` (new in NDK 3) flows through the auth check the same way as any other method. `requestToSigningConditionQuery` needs no further change — the existing `sign_event` switch case covers the only method that discriminates on kind; all other methods use the default `{ method }` query against the override layer, which is correct for the kind-less wire names too. Refs aiolabs/nsecbunkerd#14, aiolabs/nsecbunkerd#11 (whose live-policy join this finally puts to use). |
|||
| 94b5d55376 |
refactor: adapt source to NDK 3.0.3 / nostr-tools v2 surface (#14)
Mechanical adjustments to the source after the dep bump in the
previous commit. No semantic changes — every site adapts to API
drift between the pinned versions.
Surface changes addressed:
* `NDKKind` strict numeric enum (was wider in 2.8.1). 18 sites
passed the literal `24134` (NIP-46 admin-RPC response kind) to
`rpc.sendResponse` / `rpc.sendRequest`; NDK 3's `NDKKind` enum
omits 24134. Introduced `src/daemon/admin/kinds.ts` exporting
`NIP46_ADMIN_RESPONSE_KIND = 24134 as NDKKind` so the cast lives
once, and routed all 18 sites through the named constant.
* `NDKPrivateKeySigner` constructor now accepts nsec1 or hex
directly (the `@ai-guardrail` in NDK 3 source explicitly tells
callers not to `nip19.decode` ahead of construction). Simplified
`Daemon.startKey` and `createNewKey` accordingly — the bech32
decode workaround for #8 was tied to NDK 2.8.1's old behavior
and is no longer needed.
* `NDKPrivateKeySigner.privateKey` is `string` (hex) on the public
surface, not `Uint8Array`. `nostr-tools` v2's `nip19.nsecEncode`
wants `Uint8Array`. Replaced `nip19.nsecEncode(key.privateKey!)`
with `key.nsec` (NDK 3 exposes the getter directly), avoiding
both the type mismatch and the unnecessary round-trip. For the
one remaining hex-string-from-config call site, used
`nostrUtils.hexToBytes` to convert before encoding.
* `NDKPool` event rename: `'relay:notice'` → `'notice'`, with
flipped arg order `(notice, relay)` → `(relay, notice)`.
* `NDKUser.fromNip05` now requires the `ndk` instance as a 2nd
positional arg (was implicit-global before).
* `Nip46PermitCallbackParams.params` narrowed to `string |
NostrEvent`; type guards added at the two access sites
(`authorize.ts` and `acl/index.ts:requestToSigningConditionQuery`).
* `req.params` is now `(string | undefined)[]` instead of `any[]`;
`create_account.ts` `authorizationWithPayload` branch now
explicitly throws on missing username/domain before passing to
`createAccountReal` (validates what was implicit before).
* Removed `src/daemon/backend/publish-event.ts` (defined a strategy
that's never registered — wiring is commented out in
`backend/index.ts:22`; in NDK 3 the file refs the removed
`NDKNip46Backend.signEvent`). Dead since at least NDK 2.x; the
bump just made the breakage visible.
Pre-existing `tsc` errors at `src/db.ts` and `src/daemon/authorize.ts`
on `'PrismaClient'` / `'Request'` exports are unrelated to this PR —
the regtest container's nix derivation can't reach the prisma engine
binary store on this host (`nsecbunkerd#14` parked separately).
`pnpm run build` (tsup) is green; the Docker container runs
`prisma generate` against its own engine at image-build time and
resolves these at runtime.
#11's wire-name policy convention adoption is the next commit —
this one is purely keep-it-compiling work.
Refs aiolabs/nsecbunkerd#14.
|
|||
| 041f431bc2 |
chore(deps): bump @nostr-dev-kit/ndk 2.8.1 → 3.0.3 + nostr-tools v1 → v2 (#14)
NDK 2.8.1 (Apr 2024) is 2 years old and predates NIP-46 backend-side
nip44 support. With aiolabs/lnbits#38's phase-2.4 client-side migration
to bunker-mediated nip44_*, the bunker's lack of a `nip44_decrypt`
strategy registration causes wire RPCs to fall through to
`sendResponse(id, remotePubkey, "error", undefined, "Not authorized")`
at NDK 2.8.1's backend/index.ts:179. Even nip04 was silently broken:
2.8.1 normalizes the wire method to `encrypt`/`decrypt` for
`pubkeyAllowed` while lnbits's policy stores wire names. The
encrypt/decrypt path through nsecbunkerd has never actually worked
end-to-end; it just hadn't been exercised until phase 2.4 landed.
3.0.3 (Feb 2026) is the current `latest` dist-tag and ships:
- `nip44_encrypt` / `nip44_decrypt` backend handlers registered
by default + wire-name `pubkeyAllowed` semantics (the immediate fix)
- `switch_relays` NIP-46 support for client-side relay migration
- Configurable NDKNip46Signer timeout (pairs with lnbits PR #38's
matching client-side config)
- NIP-44 default outgoing encryption with NIP-04 compat fallback
- Async error handling fix in backend dispatch — failed strategies
report errors instead of silent drop (deb7f93d)
- "Not enough relays received this event" race-condition fix on
publish (relevant to open #7 — may close that one too)
- Signature verification moved in-house (off legacy nostr-tools v1
path)
- 2 years of security/perf updates in transitive @noble/* crypto
primitives
`nostr-tools` bumped from ^1.17.0 to ^2.17.2 alongside because NDK
3.x's `NDKPrivateKeySigner` imports `finalizeEvent` / `generateSecretKey`
+ uses the `./nip49` subpath, none of which exist in nostr-tools v1.17.
With v1.17 installed, `require('@nostr-dev-kit/ndk')` fails with
"Package subpath './nip49' is not defined". Confirmed against the
post-install module graph.
Source migrations for NDK 3 / nostr-tools v2 API surface land in the
follow-up commit; this commit is intentionally just the dep bump so
the diff stays reviewable. Refs aiolabs/nsecbunkerd#14 +
coord-log 2026-05-31T09:55Z.
|