From 84eb60574142de65cce1d3064b1004b17e31a6ab Mon Sep 17 00:00:00 2001 From: Patrick Mulligan Date: Fri, 23 Jan 2026 06:06:26 -0500 Subject: [PATCH] Fix nostr-tools v2.10 TypeScript compatibility issues - nostr-client: Fix Relay.auth() callback to use verifyEvent and VerifiedEvent type - nostr-client: Add @ts-expect-error for subscribeMany/querySync Filter[] types - clink: Fix finalizeEvent to not pass pubkey (derived from secret key) - clink: Fix bech32.decode to cast input as template literal type - lightning: Fix finalizeEvent to not pass pubkey (derived from secret key) Co-Authored-By: Claude Opus 4.5 --- lamassu-next/packages/clink/src/client.ts | 9 ++---- lamassu-next/packages/clink/src/noffer.ts | 4 +-- lamassu-next/packages/lightning/src/client.ts | 2 +- .../packages/nostr-client/src/client.ts | 29 +++++++++++------- lamassu-next/pnpm-lock.yaml | 30 ++----------------- 5 files changed, 26 insertions(+), 48 deletions(-) diff --git a/lamassu-next/packages/clink/src/client.ts b/lamassu-next/packages/clink/src/client.ts index d26daf8..378e021 100644 --- a/lamassu-next/packages/clink/src/client.ts +++ b/lamassu-next/packages/clink/src/client.ts @@ -325,12 +325,7 @@ export class CLINKClient { * Create a signed event */ private createSignedEvent(event: Omit): Event { - return finalizeEvent( - { - ...event, - pubkey: this.identity.publicKey, - }, - this.identity.privateKey - ) + // finalizeEvent derives pubkey from the secret key + return finalizeEvent(event, this.identity.privateKey) } } diff --git a/lamassu-next/packages/clink/src/noffer.ts b/lamassu-next/packages/clink/src/noffer.ts index e98300c..a25567b 100644 --- a/lamassu-next/packages/clink/src/noffer.ts +++ b/lamassu-next/packages/clink/src/noffer.ts @@ -57,8 +57,8 @@ export function encodeNoffer(offer: CLINKOffer): string { * Decode a noffer string to a CLINK offer */ export function decodeNoffer(noffer: string): CLINKOffer { - // Decode bech32 - const { prefix, words } = bech32.decode(noffer, BECH32_LIMIT) + // Decode bech32 - cast to expected type (contains "1" separator) + const { prefix, words } = bech32.decode(noffer as `${string}1${string}`, BECH32_LIMIT) if (prefix !== NOFFER_PREFIX) { throw new Error(`Invalid noffer prefix: ${prefix}`) diff --git a/lamassu-next/packages/lightning/src/client.ts b/lamassu-next/packages/lightning/src/client.ts index e892950..9814cd2 100644 --- a/lamassu-next/packages/lightning/src/client.ts +++ b/lamassu-next/packages/lightning/src/client.ts @@ -328,13 +328,13 @@ export class LightningPubClient { const content = encryptContent(this.identity, this.config.accountPubkey, request) + // finalizeEvent derives pubkey from the secret key const event = finalizeEvent( { kind: LIGHTNING_PUB_KINDS.REQUEST, content, tags: [['p', this.config.accountPubkey]], created_at: Math.floor(Date.now() / 1000), - pubkey: this.identity.publicKey, }, this.identity.privateKey ) diff --git a/lamassu-next/packages/nostr-client/src/client.ts b/lamassu-next/packages/nostr-client/src/client.ts index be2f6d6..fcf8429 100644 --- a/lamassu-next/packages/nostr-client/src/client.ts +++ b/lamassu-next/packages/nostr-client/src/client.ts @@ -7,7 +7,14 @@ * - Automatic reconnection */ -import { type Event, type Filter, Relay, SimplePool } from 'nostr-tools' +import { + type Event, + type Filter, + type VerifiedEvent, + Relay, + SimplePool, + verifyEvent, +} from 'nostr-tools' import { createAuthEvent } from './events.js' import type { NostrClientConfig, @@ -147,7 +154,11 @@ export class NostrClient { const challenge = evt.tags?.find((t): t is [string, string] => t[0] === 'challenge')?.[1] ?? '' const authEvent = createAuthEvent(this.config.identity, connection.config.url, challenge) - return authEvent + // Verify the event to get a VerifiedEvent type + if (verifyEvent(authEvent)) { + return authEvent as VerifiedEvent + } + throw new Error('Failed to create valid auth event') }) .then(() => { clearTimeout(timeout) @@ -212,10 +223,8 @@ export class NostrClient { throw new Error('No connected relays') } - // Cast filters to the expected type - const typedFilters = filters as unknown as Filter[] - - const sub = this.pool.subscribeMany(connectedUrls, typedFilters, { + // @ts-expect-error nostr-tools types expect single Filter but subscribeMany accepts array + const sub = this.pool.subscribeMany(connectedUrls, filters, { onevent: (event: Event) => { options.onEvent(event) this.emitEvent('event', { relay: 'pool', event }) @@ -230,7 +239,7 @@ export class NostrClient { this.subscriptions.set(id, { id, - filters: typedFilters, + filters: filters as unknown as Filter[], options, close: () => sub.close(), }) @@ -261,10 +270,8 @@ export class NostrClient { throw new Error('No connected relays') } - // Cast filters to the expected type - const typedFilters = filters as unknown as Filter[] - - return this.pool.querySync(connectedUrls, typedFilters) + // @ts-expect-error nostr-tools types expect single Filter but querySync accepts array + return this.pool.querySync(connectedUrls, filters) } /** diff --git a/lamassu-next/pnpm-lock.yaml b/lamassu-next/pnpm-lock.yaml index c2a1a19..1c78238 100644 --- a/lamassu-next/pnpm-lock.yaml +++ b/lamassu-next/pnpm-lock.yaml @@ -42,6 +42,9 @@ importers: '@lamassu/nostr-client': specifier: workspace:* version: link:../nostr-client + '@scure/base': + specifier: ^1.2.0 + version: 1.2.6 nostr-tools: specifier: ^2.10.0 version: 2.19.4(typescript@5.9.3) @@ -83,16 +86,10 @@ importers: nostr-tools: specifier: ^2.10.0 version: 2.19.4(typescript@5.9.3) - ws: - specifier: ^8.18.0 - version: 8.19.0 devDependencies: '@types/node': specifier: ^22.0.0 version: 22.19.7 - '@types/ws': - specifier: ^8.5.13 - version: 8.18.1 tsx: specifier: ^4.19.0 version: 4.21.0 @@ -799,9 +796,6 @@ packages: '@types/node@22.19.7': resolution: {integrity: sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==} - '@types/ws@8.18.1': - resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@vitejs/plugin-vue@5.2.4': resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -1255,18 +1249,6 @@ packages: engines: {node: '>=8'} hasBin: true - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - xstate@5.25.1: resolution: {integrity: sha512-oyvsNH5pF2qkHmiHEMdWqc3OjDtoZOH2MTAI35r01f/ZQWOD+VLOiYqo65UgQET0XMA5s9eRm8fnsIo+82biEw==} @@ -1646,10 +1628,6 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/ws@8.18.1': - dependencies: - '@types/node': 22.19.7 - '@vitejs/plugin-vue@5.2.4(vite@6.4.1(@types/node@22.19.7)(tsx@4.21.0))(vue@3.5.27(typescript@5.9.3))': dependencies: vite: 6.4.1(@types/node@22.19.7)(tsx@4.21.0) @@ -2160,6 +2138,4 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 - ws@8.19.0: {} - xstate@5.25.1: {}