nostr-core 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +28 -4
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/nip07.d.ts +36 -0
- package/dist/nip07.d.ts.map +1 -0
- package/dist/nip07.js +81 -0
- package/dist/nip07.js.map +1 -0
- package/dist/nip17.d.ts +11 -0
- package/dist/nip17.d.ts.map +1 -0
- package/dist/nip17.js +30 -0
- package/dist/nip17.js.map +1 -0
- package/dist/nip46.d.ts +49 -0
- package/dist/nip46.d.ts.map +1 -0
- package/dist/nip46.js +206 -0
- package/dist/nip46.js.map +1 -0
- package/dist/nip59.d.ts +14 -0
- package/dist/nip59.d.ts.map +1 -0
- package/dist/nip59.js +69 -0
- package/dist/nip59.js.map +1 -0
- package/dist/signer.d.ts +16 -0
- package/dist/signer.d.ts.map +1 -0
- package/dist/signer.js +24 -0
- package/dist/signer.js.map +1 -0
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pratik Patel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Dead-simple, vendor-neutral [Nostr Wallet Connect (NWC)](https://github.com/nostr-protocol/nips/blob/master/47.md) client for JavaScript and TypeScript.
|
|
4
4
|
|
|
5
|
+
[Demo](https://nostr-core-demo.netlify.app/)
|
|
6
|
+
|
|
5
7
|
```ts
|
|
6
8
|
import { NWC } from 'nostr-core'
|
|
7
9
|
|
|
@@ -23,6 +25,7 @@ nwc.close()
|
|
|
23
25
|
- **Full NIP-47 coverage** - `pay_invoice`, `get_balance`, `make_invoice`, `list_transactions`, `pay_keysend`, `sign_message`, and more
|
|
24
26
|
- **Auto-encryption** - detects NIP-04 or NIP-44 support and handles it transparently
|
|
25
27
|
- **Typed errors** - specific error classes for timeouts, connection failures, wallet rejections, and decryption issues
|
|
28
|
+
- **Signer abstraction** - unified `Signer` interface for secret keys, browser extensions (NIP-07), and remote signers (NIP-46)
|
|
26
29
|
- **Zero framework deps** - built on audited [noble](https://paulmillr.com/noble/) cryptography libraries only
|
|
27
30
|
- **ESM-only** - tree-shakeable, modern JavaScript
|
|
28
31
|
|
|
@@ -175,6 +178,9 @@ import {
|
|
|
175
178
|
// Key management
|
|
176
179
|
generateSecretKey, getPublicKey,
|
|
177
180
|
|
|
181
|
+
// Signer abstraction
|
|
182
|
+
createSecretKeySigner, Nip07Signer, NostrConnect,
|
|
183
|
+
|
|
178
184
|
// Events
|
|
179
185
|
finalizeEvent, verifyEvent, getEventHash, serializeEvent, validateEvent,
|
|
180
186
|
|
|
@@ -187,6 +193,9 @@ import {
|
|
|
187
193
|
// Bech32 encoding
|
|
188
194
|
nip19,
|
|
189
195
|
|
|
196
|
+
// NIP-07 & NIP-46
|
|
197
|
+
nip07, nip46,
|
|
198
|
+
|
|
190
199
|
// Filters
|
|
191
200
|
matchFilter, matchFilters,
|
|
192
201
|
|
|
@@ -207,14 +216,29 @@ If you've used `@getalby/sdk` before, here's why `nostr-core` is a better fit fo
|
|
|
207
216
|
| **Vendor lock-in** | None - pure NIP-47 protocol | Coupled to Alby (OAuth, webhooks, branding) | |
|
|
208
217
|
| **Error handling** | Typed hierarchy (8 specific classes) | Generic errors | |
|
|
209
218
|
| **Encryption** | Auto-detects NIP-04 / NIP-44 | Manual configuration | |
|
|
210
|
-
| **Fiat conversion** | Built-in (zero extra deps) |
|
|
211
|
-
| **Runtime support** | Node 18+, Deno, Bun, Cloudflare Workers |
|
|
212
|
-
| **API surface** | One class (`NWC`) |
|
|
219
|
+
| **Fiat conversion** | Built-in (zero extra deps) | `USD()` via `LN` client (v7+), backed by `@getalby/lightning-tools` | |
|
|
220
|
+
| **Runtime support** | Node 18+, Deno, Bun, Cloudflare Workers | Node.js (requires websocket polyfill pre-v18) | |
|
|
221
|
+
| **API surface** | One class (`NWC`) | `LN` + `NWCClient` + `NWAClient` + `NostrWebLNProvider` + `OAuthWebLNProvider` | |
|
|
213
222
|
|
|
214
223
|
**Use `@getalby/sdk`** if you need Alby OAuth or WebLN compatibility. **Use `nostr-core`** for everything else - including Lightning Address payments and fiat currency conversion, which are now supported natively.
|
|
215
224
|
|
|
216
225
|
See the full [comparison guide](./docs/guide/comparison.md) for details.
|
|
217
226
|
|
|
227
|
+
## Agent Skills (Claude Code Plugin)
|
|
228
|
+
|
|
229
|
+
nostr-core ships as a [Claude Code plugin](https://code.claude.com/docs/en/plugins) with 4 skills for AI agents building Lightning-enabled apps:
|
|
230
|
+
|
|
231
|
+
| Skill | Description |
|
|
232
|
+
|-------|-------------|
|
|
233
|
+
| `/nwc-integrate` | Set up nostr-core and connect to any NWC wallet |
|
|
234
|
+
| `/lightning-pay` | Pay invoices, Lightning Addresses, fiat, and keysend |
|
|
235
|
+
| `/wallet-monitor` | Real-time notifications, transaction history, analytics |
|
|
236
|
+
| `/nostr-primitives` | Low-level keys, events, relays, encryption, encoding |
|
|
237
|
+
|
|
238
|
+
Install: `/plugin install nostr-core-org/nostr-core`
|
|
239
|
+
|
|
240
|
+
See the [Skills documentation](./docs/skills.md) and [Agent README](./AGENT_README.md) for details.
|
|
241
|
+
|
|
218
242
|
## Dependencies
|
|
219
243
|
|
|
220
244
|
| Package | Purpose |
|
|
@@ -226,4 +250,4 @@ See the full [comparison guide](./docs/guide/comparison.md) for details.
|
|
|
226
250
|
|
|
227
251
|
## License
|
|
228
252
|
|
|
229
|
-
MIT
|
|
253
|
+
[MIT](./LICENSE)
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,20 @@ export type { Filter } from './filter.js';
|
|
|
11
11
|
export * as nip04 from './nip04.js';
|
|
12
12
|
export * as nip44 from './nip44.js';
|
|
13
13
|
export * as nip19 from './nip19.js';
|
|
14
|
+
export * as nip07 from './nip07.js';
|
|
15
|
+
export * as nip46 from './nip46.js';
|
|
16
|
+
export * as nip59 from './nip59.js';
|
|
17
|
+
export * as nip17 from './nip17.js';
|
|
18
|
+
export type { Signer, RelayMap } from './signer.js';
|
|
19
|
+
export { createSecretKeySigner } from './signer.js';
|
|
20
|
+
export { Nip07Signer, getExtension, Nip07Error, Nip07NotAvailableError } from './nip07.js';
|
|
21
|
+
export type { Nip07Extension } from './nip07.js';
|
|
22
|
+
export { NostrConnect, parseConnectionURI, Nip46Error, Nip46TimeoutError, Nip46ConnectionError, Nip46RemoteError } from './nip46.js';
|
|
23
|
+
export type { Nip46ConnectionOptions, Nip46Method } from './nip46.js';
|
|
24
|
+
export { createRumor, createSeal, createWrap, unwrap } from './nip59.js';
|
|
25
|
+
export type { Rumor } from './nip59.js';
|
|
26
|
+
export { wrapDirectMessage, unwrapDirectMessage } from './nip17.js';
|
|
27
|
+
export type { DirectMessage } from './nip17.js';
|
|
14
28
|
export { Relay, Subscription } from './relay.js';
|
|
15
29
|
export type { SubscriptionParams } from './relay.js';
|
|
16
30
|
export { RelayPool } from './pool.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAG9B,YAAY,EACV,cAAc,EACd,WAAW,EACX,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACxB,QAAQ,EACR,cAAc,GACf,MAAM,YAAY,CAAA;AAGnB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAGtG,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAGnE,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAG7D,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AACpH,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAGzF,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACvD,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGzC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AAGnC,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAG/D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,19 @@ export { matchFilter, matchFilters } from './filter.js';
|
|
|
16
16
|
export * as nip04 from './nip04.js';
|
|
17
17
|
export * as nip44 from './nip44.js';
|
|
18
18
|
export * as nip19 from './nip19.js';
|
|
19
|
+
export * as nip07 from './nip07.js';
|
|
20
|
+
export * as nip46 from './nip46.js';
|
|
21
|
+
export * as nip59 from './nip59.js';
|
|
22
|
+
export * as nip17 from './nip17.js';
|
|
23
|
+
export { createSecretKeySigner } from './signer.js';
|
|
24
|
+
// NIP-07
|
|
25
|
+
export { Nip07Signer, getExtension, Nip07Error, Nip07NotAvailableError } from './nip07.js';
|
|
26
|
+
// NIP-46
|
|
27
|
+
export { NostrConnect, parseConnectionURI, Nip46Error, Nip46TimeoutError, Nip46ConnectionError, Nip46RemoteError } from './nip46.js';
|
|
28
|
+
// NIP-59
|
|
29
|
+
export { createRumor, createSeal, createWrap, unwrap } from './nip59.js';
|
|
30
|
+
// NIP-17
|
|
31
|
+
export { wrapDirectMessage, unwrapDirectMessage } from './nip17.js';
|
|
19
32
|
// Networking
|
|
20
33
|
export { Relay, Subscription } from './relay.js';
|
|
21
34
|
export { RelayPool } from './pool.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,WAAW;AACX,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AA2B9B,gBAAgB;AAChB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,YAAY,CAAA;AAEnB,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAEtG,kBAAkB;AAClB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEnE,SAAS;AACT,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE7D,eAAe;AACf,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAGpH,UAAU;AACV,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAGvD,OAAO;AACP,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,WAAW;AACX,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AA2B9B,gBAAgB;AAChB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,YAAY,CAAA;AAEnB,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAEtG,kBAAkB;AAClB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEnE,SAAS;AACT,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE7D,eAAe;AACf,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAGpH,UAAU;AACV,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAGvD,OAAO;AACP,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AAInC,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAEnD,SAAS;AACT,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAG1F,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,UAAU,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAGpI,SAAS;AACT,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAGxE,SAAS;AACT,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAGnE,aAAa;AACb,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEhD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAGrC,QAAQ;AACR,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
|
package/dist/nip07.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { EventTemplate, VerifiedEvent } from './event.js';
|
|
2
|
+
import type { Signer, RelayMap } from './signer.js';
|
|
3
|
+
export declare class Nip07Error extends Error {
|
|
4
|
+
code: string;
|
|
5
|
+
constructor(message: string, code?: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class Nip07NotAvailableError extends Nip07Error {
|
|
8
|
+
constructor(message?: string);
|
|
9
|
+
}
|
|
10
|
+
export interface Nip07Extension {
|
|
11
|
+
getPublicKey(): Promise<string>;
|
|
12
|
+
signEvent(event: EventTemplate): Promise<VerifiedEvent>;
|
|
13
|
+
nip04?: {
|
|
14
|
+
encrypt(pubkey: string, plaintext: string): Promise<string>;
|
|
15
|
+
decrypt(pubkey: string, ciphertext: string): Promise<string>;
|
|
16
|
+
};
|
|
17
|
+
getRelays?(): Promise<RelayMap>;
|
|
18
|
+
}
|
|
19
|
+
declare global {
|
|
20
|
+
interface Window {
|
|
21
|
+
nostr?: Nip07Extension;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export declare function getExtension(): Nip07Extension;
|
|
25
|
+
export declare class Nip07Signer implements Signer {
|
|
26
|
+
private ext;
|
|
27
|
+
constructor();
|
|
28
|
+
getPublicKey(): Promise<string>;
|
|
29
|
+
signEvent(event: EventTemplate): Promise<VerifiedEvent>;
|
|
30
|
+
nip04: {
|
|
31
|
+
encrypt: (pubkey: string, plaintext: string) => Promise<string>;
|
|
32
|
+
decrypt: (pubkey: string, ciphertext: string) => Promise<string>;
|
|
33
|
+
};
|
|
34
|
+
getRelays(): Promise<RelayMap>;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=nip07.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nip07.d.ts","sourceRoot":"","sources":["../src/nip07.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAInD,qBAAa,UAAW,SAAQ,KAAK;IACnC,IAAI,EAAE,MAAM,CAAA;gBACA,OAAO,EAAE,MAAM,EAAE,IAAI,SAAgB;CAKlD;AAED,qBAAa,sBAAuB,SAAQ,UAAU;gBACxC,OAAO,SAA+D;CAInF;AAID,MAAM,WAAW,cAAc;IAC7B,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IAC/B,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;IACvD,KAAK,CAAC,EAAE;QACN,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QAC3D,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;KAC7D,CAAA;IACD,SAAS,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAA;CAChC;AAID,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,KAAK,CAAC,EAAE,cAAc,CAAA;KACvB;CACF;AAID,wBAAgB,YAAY,IAAI,cAAc,CAK7C;AAID,qBAAa,WAAY,YAAW,MAAM;IACxC,OAAO,CAAC,GAAG,CAAgB;;IAMrB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAQ/B,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAQ7D,KAAK;0BACqB,MAAM,aAAa,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;0BAU3C,MAAM,cAAc,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;MASrE;IAEK,SAAS,IAAI,OAAO,CAAC,QAAQ,CAAC;CAUrC"}
|
package/dist/nip07.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Error classes
|
|
2
|
+
export class Nip07Error extends Error {
|
|
3
|
+
code;
|
|
4
|
+
constructor(message, code = 'NIP07_ERROR') {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'Nip07Error';
|
|
7
|
+
this.code = code;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class Nip07NotAvailableError extends Nip07Error {
|
|
11
|
+
constructor(message = 'NIP-07 extension not available (window.nostr is undefined)') {
|
|
12
|
+
super(message, 'NIP07_NOT_AVAILABLE');
|
|
13
|
+
this.name = 'Nip07NotAvailableError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Helpers
|
|
17
|
+
export function getExtension() {
|
|
18
|
+
if (typeof window === 'undefined' || !window.nostr) {
|
|
19
|
+
throw new Nip07NotAvailableError();
|
|
20
|
+
}
|
|
21
|
+
return window.nostr;
|
|
22
|
+
}
|
|
23
|
+
// Signer implementation
|
|
24
|
+
export class Nip07Signer {
|
|
25
|
+
ext;
|
|
26
|
+
constructor() {
|
|
27
|
+
this.ext = getExtension();
|
|
28
|
+
}
|
|
29
|
+
async getPublicKey() {
|
|
30
|
+
try {
|
|
31
|
+
return await this.ext.getPublicKey();
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
throw new Nip07Error(`getPublicKey failed: ${err.message}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async signEvent(event) {
|
|
38
|
+
try {
|
|
39
|
+
return await this.ext.signEvent(event);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
throw new Nip07Error(`signEvent failed: ${err.message}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
nip04 = {
|
|
46
|
+
encrypt: async (pubkey, plaintext) => {
|
|
47
|
+
const nip04 = this.ext.nip04;
|
|
48
|
+
if (!nip04)
|
|
49
|
+
throw new Nip07Error('Extension does not support NIP-04', 'NIP07_NIP04_UNSUPPORTED');
|
|
50
|
+
try {
|
|
51
|
+
return await nip04.encrypt(pubkey, plaintext);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
throw new Nip07Error(`nip04.encrypt failed: ${err.message}`);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
decrypt: async (pubkey, ciphertext) => {
|
|
58
|
+
const nip04 = this.ext.nip04;
|
|
59
|
+
if (!nip04)
|
|
60
|
+
throw new Nip07Error('Extension does not support NIP-04', 'NIP07_NIP04_UNSUPPORTED');
|
|
61
|
+
try {
|
|
62
|
+
return await nip04.decrypt(pubkey, ciphertext);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
throw new Nip07Error(`nip04.decrypt failed: ${err.message}`);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
async getRelays() {
|
|
70
|
+
if (!this.ext.getRelays) {
|
|
71
|
+
throw new Nip07Error('Extension does not support getRelays', 'NIP07_RELAYS_UNSUPPORTED');
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
return await this.ext.getRelays();
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
throw new Nip07Error(`getRelays failed: ${err.message}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=nip07.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nip07.js","sourceRoot":"","sources":["../src/nip07.ts"],"names":[],"mappings":"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"}
|
package/dist/nip17.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { NostrEvent } from './event.js';
|
|
2
|
+
export type DirectMessage = {
|
|
3
|
+
sender: string;
|
|
4
|
+
content: string;
|
|
5
|
+
tags: string[][];
|
|
6
|
+
created_at: number;
|
|
7
|
+
id: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function wrapDirectMessage(content: string, senderSecretKey: Uint8Array, recipientPubkey: string, tags?: string[][]): NostrEvent;
|
|
10
|
+
export declare function unwrapDirectMessage(wrap: NostrEvent, recipientSecretKey: Uint8Array): DirectMessage;
|
|
11
|
+
//# sourceMappingURL=nip17.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nip17.d.ts","sourceRoot":"","sources":["../src/nip17.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAO5C,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,EAAE,EAAE,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,EAAE,EAAE,MAAM,CAAA;CACX,CAAA;AAID,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,UAAU,EAC3B,eAAe,EAAE,MAAM,EACvB,IAAI,GAAE,MAAM,EAAE,EAAO,GACpB,UAAU,CAeZ;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,UAAU,EAChB,kBAAkB,EAAE,UAAU,GAC7B,aAAa,CAcf"}
|
package/dist/nip17.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getPublicKey } from './crypto.js';
|
|
2
|
+
import { createRumor, createSeal, createWrap, unwrap } from './nip59.js';
|
|
3
|
+
// Kind constants
|
|
4
|
+
const DM_KIND = 14;
|
|
5
|
+
// Public API
|
|
6
|
+
export function wrapDirectMessage(content, senderSecretKey, recipientPubkey, tags = []) {
|
|
7
|
+
const senderPubkey = getPublicKey(senderSecretKey);
|
|
8
|
+
const rumor = createRumor({
|
|
9
|
+
kind: DM_KIND,
|
|
10
|
+
tags: [['p', recipientPubkey], ...tags],
|
|
11
|
+
content,
|
|
12
|
+
created_at: Math.floor(Date.now() / 1000),
|
|
13
|
+
}, senderPubkey);
|
|
14
|
+
const seal = createSeal(rumor, senderSecretKey, recipientPubkey);
|
|
15
|
+
return createWrap(seal, recipientPubkey);
|
|
16
|
+
}
|
|
17
|
+
export function unwrapDirectMessage(wrap, recipientSecretKey) {
|
|
18
|
+
const rumor = unwrap(wrap, recipientSecretKey);
|
|
19
|
+
if (rumor.kind !== DM_KIND) {
|
|
20
|
+
throw new Error(`Expected kind ${DM_KIND} direct message, got kind ${rumor.kind}`);
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
sender: rumor.pubkey,
|
|
24
|
+
content: rumor.content,
|
|
25
|
+
tags: rumor.tags,
|
|
26
|
+
created_at: rumor.created_at,
|
|
27
|
+
id: rumor.id,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=nip17.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nip17.js","sourceRoot":"","sources":["../src/nip17.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAGxE,iBAAiB;AACjB,MAAM,OAAO,GAAG,EAAE,CAAA;AAYlB,aAAa;AAEb,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,eAA2B,EAC3B,eAAuB,EACvB,OAAmB,EAAE;IAErB,MAAM,YAAY,GAAG,YAAY,CAAC,eAAe,CAAC,CAAA;IAElD,MAAM,KAAK,GAAG,WAAW,CACvB;QACE,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,eAAe,CAAC,EAAE,GAAG,IAAI,CAAC;QACvC,OAAO;QACP,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;KAC1C,EACD,YAAY,CACb,CAAA;IAED,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,EAAE,eAAe,EAAE,eAAe,CAAC,CAAA;IAChE,OAAO,UAAU,CAAC,IAAI,EAAE,eAAe,CAAC,CAAA;AAC1C,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,IAAgB,EAChB,kBAA8B;IAE9B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAA;IAE9C,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,iBAAiB,OAAO,6BAA6B,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;IACpF,CAAC;IAED,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,EAAE,EAAE,KAAK,CAAC,EAAE;KACb,CAAA;AACH,CAAC"}
|
package/dist/nip46.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type EventTemplate, type VerifiedEvent } from './event.js';
|
|
2
|
+
import type { Signer, RelayMap } from './signer.js';
|
|
3
|
+
export declare class Nip46Error extends Error {
|
|
4
|
+
code: string;
|
|
5
|
+
constructor(message: string, code?: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class Nip46TimeoutError extends Nip46Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class Nip46ConnectionError extends Nip46Error {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
export declare class Nip46RemoteError extends Nip46Error {
|
|
14
|
+
constructor(message: string);
|
|
15
|
+
}
|
|
16
|
+
export type Nip46Method = 'connect' | 'disconnect' | 'describe' | 'get_public_key' | 'sign_event' | 'nip04_encrypt' | 'nip04_decrypt' | 'get_relays';
|
|
17
|
+
export type Nip46ConnectionOptions = {
|
|
18
|
+
remotePubkey: string;
|
|
19
|
+
relayUrl: string;
|
|
20
|
+
secretKey?: Uint8Array;
|
|
21
|
+
};
|
|
22
|
+
export declare function parseConnectionURI(uri: string): Nip46ConnectionOptions;
|
|
23
|
+
export declare class NostrConnect implements Signer {
|
|
24
|
+
private remotePubkey;
|
|
25
|
+
private relayUrl;
|
|
26
|
+
private secretKey;
|
|
27
|
+
private publicKey;
|
|
28
|
+
private relay;
|
|
29
|
+
private _connected;
|
|
30
|
+
private pendingRequests;
|
|
31
|
+
private sub;
|
|
32
|
+
timeout: number;
|
|
33
|
+
constructor(connectionOrOpts: string | Nip46ConnectionOptions);
|
|
34
|
+
get connected(): boolean;
|
|
35
|
+
connect(): Promise<void>;
|
|
36
|
+
disconnect(): Promise<void>;
|
|
37
|
+
close(): void;
|
|
38
|
+
describe(): Promise<string[]>;
|
|
39
|
+
getPublicKey(): Promise<string>;
|
|
40
|
+
signEvent(event: EventTemplate): Promise<VerifiedEvent>;
|
|
41
|
+
nip04: {
|
|
42
|
+
encrypt: (pubkey: string, plaintext: string) => Promise<string>;
|
|
43
|
+
decrypt: (pubkey: string, ciphertext: string) => Promise<string>;
|
|
44
|
+
};
|
|
45
|
+
getRelays(): Promise<RelayMap>;
|
|
46
|
+
private _sendRequest;
|
|
47
|
+
private _handleResponse;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=nip46.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nip46.d.ts","sourceRoot":"","sources":["../src/nip46.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,aAAa,EAAmB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA;AAInG,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAOnD,qBAAa,UAAW,SAAQ,KAAK;IACnC,IAAI,EAAE,MAAM,CAAA;gBACA,OAAO,EAAE,MAAM,EAAE,IAAI,SAAgB;CAKlD;AAED,qBAAa,iBAAkB,SAAQ,UAAU;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,oBAAqB,SAAQ,UAAU;gBACtC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,gBAAiB,SAAQ,UAAU;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAID,MAAM,MAAM,WAAW,GACnB,SAAS,GACT,YAAY,GACZ,UAAU,GACV,gBAAgB,GAChB,YAAY,GACZ,eAAe,GACf,eAAe,GACf,YAAY,CAAA;AAEhB,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,UAAU,CAAA;CACvB,CAAA;AAUD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,sBAAsB,CActE;AAID,qBAAa,YAAa,YAAW,MAAM;IACzC,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,KAAK,CAAO;IACpB,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,eAAe,CAAoC;IAC3D,OAAO,CAAC,GAAG,CAAkD;IAEtD,OAAO,SAAQ;gBAEV,gBAAgB,EAAE,MAAM,GAAG,sBAAsB;IAY7D,IAAI,SAAS,IAAI,OAAO,CAEvB;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAkCxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAUjC,KAAK,IAAI,IAAI;IAaP,QAAQ,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAO7B,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAI/B,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAK7D,KAAK;0BACqB,MAAM,aAAa,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;0BAG3C,MAAM,cAAc,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;MAGrE;IAEK,SAAS,IAAI,OAAO,CAAC,QAAQ,CAAC;YAOtB,YAAY;IAoC1B,OAAO,CAAC,eAAe;CA2BxB"}
|
package/dist/nip46.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { randomBytes, bytesToHex } from '@noble/hashes/utils';
|
|
2
|
+
import { getPublicKey } from './crypto.js';
|
|
3
|
+
import { finalizeEvent } from './event.js';
|
|
4
|
+
import * as nip04 from './nip04.js';
|
|
5
|
+
import { Relay } from './relay.js';
|
|
6
|
+
// NIP-46 event kind
|
|
7
|
+
const NIP46_KIND = 24133;
|
|
8
|
+
// Error classes
|
|
9
|
+
export class Nip46Error extends Error {
|
|
10
|
+
code;
|
|
11
|
+
constructor(message, code = 'NIP46_ERROR') {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = 'Nip46Error';
|
|
14
|
+
this.code = code;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class Nip46TimeoutError extends Nip46Error {
|
|
18
|
+
constructor(message) {
|
|
19
|
+
super(message, 'NIP46_TIMEOUT');
|
|
20
|
+
this.name = 'Nip46TimeoutError';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export class Nip46ConnectionError extends Nip46Error {
|
|
24
|
+
constructor(message) {
|
|
25
|
+
super(message, 'NIP46_CONNECTION_ERROR');
|
|
26
|
+
this.name = 'Nip46ConnectionError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class Nip46RemoteError extends Nip46Error {
|
|
30
|
+
constructor(message) {
|
|
31
|
+
super(message, 'NIP46_REMOTE_ERROR');
|
|
32
|
+
this.name = 'Nip46RemoteError';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// URI parsing
|
|
36
|
+
export function parseConnectionURI(uri) {
|
|
37
|
+
const normalized = uri.replace('nostrconnect://', 'http://');
|
|
38
|
+
const url = new URL(normalized);
|
|
39
|
+
const remotePubkey = url.host || url.pathname.replace('//', '');
|
|
40
|
+
const relayUrl = url.searchParams.get('relay');
|
|
41
|
+
if (!remotePubkey) {
|
|
42
|
+
throw new Nip46Error('Invalid nostrconnect URI: missing remote pubkey', 'INVALID_URI');
|
|
43
|
+
}
|
|
44
|
+
if (!relayUrl) {
|
|
45
|
+
throw new Nip46Error('Invalid nostrconnect URI: missing relay parameter', 'INVALID_URI');
|
|
46
|
+
}
|
|
47
|
+
return { remotePubkey, relayUrl };
|
|
48
|
+
}
|
|
49
|
+
// NostrConnect class
|
|
50
|
+
export class NostrConnect {
|
|
51
|
+
remotePubkey;
|
|
52
|
+
relayUrl;
|
|
53
|
+
secretKey;
|
|
54
|
+
publicKey;
|
|
55
|
+
relay;
|
|
56
|
+
_connected = false;
|
|
57
|
+
pendingRequests = new Map();
|
|
58
|
+
sub;
|
|
59
|
+
timeout = 60000;
|
|
60
|
+
constructor(connectionOrOpts) {
|
|
61
|
+
const opts = typeof connectionOrOpts === 'string'
|
|
62
|
+
? parseConnectionURI(connectionOrOpts)
|
|
63
|
+
: connectionOrOpts;
|
|
64
|
+
this.remotePubkey = opts.remotePubkey;
|
|
65
|
+
this.relayUrl = opts.relayUrl;
|
|
66
|
+
this.secretKey = opts.secretKey || randomBytes(32);
|
|
67
|
+
this.publicKey = getPublicKey(this.secretKey);
|
|
68
|
+
this.relay = new Relay(this.relayUrl);
|
|
69
|
+
}
|
|
70
|
+
get connected() {
|
|
71
|
+
return this._connected;
|
|
72
|
+
}
|
|
73
|
+
async connect() {
|
|
74
|
+
try {
|
|
75
|
+
await this.relay.connect({ timeout: 5000 });
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
throw new Nip46ConnectionError(`Failed to connect to relay ${this.relayUrl}: ${err.message}`);
|
|
79
|
+
}
|
|
80
|
+
// Subscribe to responses from the remote signer
|
|
81
|
+
this.sub = this.relay.subscribe([
|
|
82
|
+
{
|
|
83
|
+
kinds: [NIP46_KIND],
|
|
84
|
+
authors: [this.remotePubkey],
|
|
85
|
+
'#p': [this.publicKey],
|
|
86
|
+
},
|
|
87
|
+
], {
|
|
88
|
+
onevent: (event) => {
|
|
89
|
+
this._handleResponse(event);
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
// Send connect RPC
|
|
93
|
+
try {
|
|
94
|
+
await this._sendRequest('connect', [this.publicKey]);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
this.relay.close();
|
|
98
|
+
throw new Nip46ConnectionError(`NIP-46 connect handshake failed: ${err.message}`);
|
|
99
|
+
}
|
|
100
|
+
this._connected = true;
|
|
101
|
+
}
|
|
102
|
+
async disconnect() {
|
|
103
|
+
if (!this._connected)
|
|
104
|
+
return;
|
|
105
|
+
try {
|
|
106
|
+
await this._sendRequest('disconnect', []);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Best effort
|
|
110
|
+
}
|
|
111
|
+
this.close();
|
|
112
|
+
}
|
|
113
|
+
close() {
|
|
114
|
+
// Reject all pending requests
|
|
115
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
116
|
+
clearTimeout(pending.timeout);
|
|
117
|
+
pending.reject(new Nip46Error('Connection closed'));
|
|
118
|
+
this.pendingRequests.delete(id);
|
|
119
|
+
}
|
|
120
|
+
this.sub?.close();
|
|
121
|
+
this.sub = undefined;
|
|
122
|
+
this.relay.close();
|
|
123
|
+
this._connected = false;
|
|
124
|
+
}
|
|
125
|
+
async describe() {
|
|
126
|
+
const result = await this._sendRequest('describe', []);
|
|
127
|
+
return JSON.parse(result);
|
|
128
|
+
}
|
|
129
|
+
// Signer interface
|
|
130
|
+
async getPublicKey() {
|
|
131
|
+
return this._sendRequest('get_public_key', []);
|
|
132
|
+
}
|
|
133
|
+
async signEvent(event) {
|
|
134
|
+
const result = await this._sendRequest('sign_event', [JSON.stringify(event)]);
|
|
135
|
+
return JSON.parse(result);
|
|
136
|
+
}
|
|
137
|
+
nip04 = {
|
|
138
|
+
encrypt: async (pubkey, plaintext) => {
|
|
139
|
+
return this._sendRequest('nip04_encrypt', [pubkey, plaintext]);
|
|
140
|
+
},
|
|
141
|
+
decrypt: async (pubkey, ciphertext) => {
|
|
142
|
+
return this._sendRequest('nip04_decrypt', [pubkey, ciphertext]);
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
async getRelays() {
|
|
146
|
+
const result = await this._sendRequest('get_relays', []);
|
|
147
|
+
return JSON.parse(result);
|
|
148
|
+
}
|
|
149
|
+
// Private methods
|
|
150
|
+
async _sendRequest(method, params) {
|
|
151
|
+
if (method !== 'connect' && !this._connected) {
|
|
152
|
+
throw new Nip46ConnectionError('Not connected. Call connect() first.');
|
|
153
|
+
}
|
|
154
|
+
const id = bytesToHex(randomBytes(16));
|
|
155
|
+
const request = JSON.stringify({ id, method, params });
|
|
156
|
+
// Encrypt with NIP-04
|
|
157
|
+
const encrypted = nip04.encrypt(this.secretKey, this.remotePubkey, request);
|
|
158
|
+
const eventTemplate = {
|
|
159
|
+
kind: NIP46_KIND,
|
|
160
|
+
created_at: Math.floor(Date.now() / 1000),
|
|
161
|
+
tags: [['p', this.remotePubkey]],
|
|
162
|
+
content: encrypted,
|
|
163
|
+
};
|
|
164
|
+
const event = finalizeEvent(eventTemplate, this.secretKey);
|
|
165
|
+
return new Promise((resolve, reject) => {
|
|
166
|
+
const timeout = setTimeout(() => {
|
|
167
|
+
this.pendingRequests.delete(id);
|
|
168
|
+
reject(new Nip46TimeoutError(`Request timed out: ${method}`));
|
|
169
|
+
}, this.timeout);
|
|
170
|
+
this.pendingRequests.set(id, { resolve, reject, timeout });
|
|
171
|
+
this.relay.publish(event).catch((err) => {
|
|
172
|
+
clearTimeout(timeout);
|
|
173
|
+
this.pendingRequests.delete(id);
|
|
174
|
+
reject(new Nip46Error(`Failed to publish ${method}: ${err.message}`));
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
_handleResponse(event) {
|
|
179
|
+
let decrypted;
|
|
180
|
+
try {
|
|
181
|
+
decrypted = nip04.decrypt(this.secretKey, this.remotePubkey, event.content);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return; // Ignore events we can't decrypt
|
|
185
|
+
}
|
|
186
|
+
let response;
|
|
187
|
+
try {
|
|
188
|
+
response = JSON.parse(decrypted);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return; // Ignore malformed responses
|
|
192
|
+
}
|
|
193
|
+
const pending = this.pendingRequests.get(response.id);
|
|
194
|
+
if (!pending)
|
|
195
|
+
return;
|
|
196
|
+
clearTimeout(pending.timeout);
|
|
197
|
+
this.pendingRequests.delete(response.id);
|
|
198
|
+
if (response.error) {
|
|
199
|
+
pending.reject(new Nip46RemoteError(response.error));
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
pending.resolve(response.result || '');
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=nip46.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nip46.js","sourceRoot":"","sources":["../src/nip46.ts"],"names":[],"mappings":"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"}
|
package/dist/nip59.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type EventTemplate, type NostrEvent } from './event.js';
|
|
2
|
+
export type Rumor = {
|
|
3
|
+
id: string;
|
|
4
|
+
kind: number;
|
|
5
|
+
tags: string[][];
|
|
6
|
+
content: string;
|
|
7
|
+
created_at: number;
|
|
8
|
+
pubkey: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function createRumor(event: EventTemplate, senderPubkey: string): Rumor;
|
|
11
|
+
export declare function createSeal(rumor: Rumor, senderSecretKey: Uint8Array, recipientPubkey: string): NostrEvent;
|
|
12
|
+
export declare function createWrap(seal: NostrEvent, recipientPubkey: string): NostrEvent;
|
|
13
|
+
export declare function unwrap(wrap: NostrEvent, recipientSecretKey: Uint8Array): Rumor;
|
|
14
|
+
//# sourceMappingURL=nip59.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nip59.d.ts","sourceRoot":"","sources":["../src/nip59.ts"],"names":[],"mappings":"AAGA,OAAO,EAA4C,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAA;AAS1G,MAAM,MAAM,KAAK,GAAG;IAClB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,EAAE,EAAE,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAaD,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,GAAG,KAAK,CAO7E;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,KAAK,EACZ,eAAe,EAAE,UAAU,EAC3B,eAAe,EAAE,MAAM,GACtB,UAAU,CAaZ;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,UAAU,EAChB,eAAe,EAAE,MAAM,GACtB,UAAU,CAcZ;AAED,wBAAgB,MAAM,CACpB,IAAI,EAAE,UAAU,EAChB,kBAAkB,EAAE,UAAU,GAC7B,KAAK,CA6BP"}
|
package/dist/nip59.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { generateSecretKey } from './crypto.js';
|
|
2
|
+
import { finalizeEvent, getEventHash, verifyEvent } from './event.js';
|
|
3
|
+
import * as nip44 from './nip44.js';
|
|
4
|
+
// Kind constants
|
|
5
|
+
const SEAL_KIND = 13;
|
|
6
|
+
const GIFT_WRAP_KIND = 1059;
|
|
7
|
+
// Helpers
|
|
8
|
+
function randomTimestamp() {
|
|
9
|
+
// Randomize up to 2 days in the past
|
|
10
|
+
const twoDays = 2 * 24 * 60 * 60;
|
|
11
|
+
const offset = Math.floor(Math.random() * twoDays);
|
|
12
|
+
return Math.floor(Date.now() / 1000) - offset;
|
|
13
|
+
}
|
|
14
|
+
// Public API
|
|
15
|
+
export function createRumor(event, senderPubkey) {
|
|
16
|
+
const rumor = {
|
|
17
|
+
...event,
|
|
18
|
+
pubkey: senderPubkey,
|
|
19
|
+
};
|
|
20
|
+
const id = getEventHash(rumor);
|
|
21
|
+
return { ...rumor, id };
|
|
22
|
+
}
|
|
23
|
+
export function createSeal(rumor, senderSecretKey, recipientPubkey) {
|
|
24
|
+
const convKey = nip44.getConversationKey(senderSecretKey, recipientPubkey);
|
|
25
|
+
const encrypted = nip44.encrypt(JSON.stringify(rumor), convKey);
|
|
26
|
+
return finalizeEvent({
|
|
27
|
+
kind: SEAL_KIND,
|
|
28
|
+
tags: [],
|
|
29
|
+
content: encrypted,
|
|
30
|
+
created_at: randomTimestamp(),
|
|
31
|
+
}, senderSecretKey);
|
|
32
|
+
}
|
|
33
|
+
export function createWrap(seal, recipientPubkey) {
|
|
34
|
+
const ephemeralKey = generateSecretKey();
|
|
35
|
+
const convKey = nip44.getConversationKey(ephemeralKey, recipientPubkey);
|
|
36
|
+
const encrypted = nip44.encrypt(JSON.stringify(seal), convKey);
|
|
37
|
+
return finalizeEvent({
|
|
38
|
+
kind: GIFT_WRAP_KIND,
|
|
39
|
+
tags: [['p', recipientPubkey]],
|
|
40
|
+
content: encrypted,
|
|
41
|
+
created_at: randomTimestamp(),
|
|
42
|
+
}, ephemeralKey);
|
|
43
|
+
}
|
|
44
|
+
export function unwrap(wrap, recipientSecretKey) {
|
|
45
|
+
if (wrap.kind !== GIFT_WRAP_KIND) {
|
|
46
|
+
throw new Error(`Expected kind ${GIFT_WRAP_KIND} gift wrap, got kind ${wrap.kind}`);
|
|
47
|
+
}
|
|
48
|
+
// Decrypt the gift wrap to get the seal
|
|
49
|
+
const convKey = nip44.getConversationKey(recipientSecretKey, wrap.pubkey);
|
|
50
|
+
const sealJson = nip44.decrypt(wrap.content, convKey);
|
|
51
|
+
const seal = JSON.parse(sealJson);
|
|
52
|
+
// Verify the seal signature
|
|
53
|
+
if (seal.kind !== SEAL_KIND) {
|
|
54
|
+
throw new Error(`Expected kind ${SEAL_KIND} seal, got kind ${seal.kind}`);
|
|
55
|
+
}
|
|
56
|
+
if (!verifyEvent(seal)) {
|
|
57
|
+
throw new Error('Seal signature verification failed');
|
|
58
|
+
}
|
|
59
|
+
// Decrypt the seal to get the rumor
|
|
60
|
+
const sealConvKey = nip44.getConversationKey(recipientSecretKey, seal.pubkey);
|
|
61
|
+
const rumorJson = nip44.decrypt(seal.content, sealConvKey);
|
|
62
|
+
const rumor = JSON.parse(rumorJson);
|
|
63
|
+
// Verify pubkey consistency: seal.pubkey must match rumor.pubkey
|
|
64
|
+
if (seal.pubkey !== rumor.pubkey) {
|
|
65
|
+
throw new Error('Seal pubkey does not match rumor pubkey — possible impersonation');
|
|
66
|
+
}
|
|
67
|
+
return rumor;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=nip59.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nip59.js","sourceRoot":"","sources":["../src/nip59.ts"],"names":[],"mappings":"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"}
|
package/dist/signer.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type EventTemplate, type VerifiedEvent } from './event.js';
|
|
2
|
+
export type RelayMap = Record<string, {
|
|
3
|
+
read: boolean;
|
|
4
|
+
write: boolean;
|
|
5
|
+
}>;
|
|
6
|
+
export interface Signer {
|
|
7
|
+
getPublicKey(): Promise<string>;
|
|
8
|
+
signEvent(event: EventTemplate): Promise<VerifiedEvent>;
|
|
9
|
+
nip04?: {
|
|
10
|
+
encrypt(pubkey: string, plaintext: string): Promise<string>;
|
|
11
|
+
decrypt(pubkey: string, ciphertext: string): Promise<string>;
|
|
12
|
+
};
|
|
13
|
+
getRelays?(): Promise<RelayMap>;
|
|
14
|
+
}
|
|
15
|
+
export declare function createSecretKeySigner(secretKey: Uint8Array): Signer;
|
|
16
|
+
//# sourceMappingURL=signer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../src/signer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA;AAGlF,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAAA;AAExE,MAAM,WAAW,MAAM;IACrB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IAC/B,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;IACvD,KAAK,CAAC,EAAE;QACN,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QAC3D,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;KAC7D,CAAA;IACD,SAAS,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAA;CAChC;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,CAqBnE"}
|
package/dist/signer.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { bytesToHex } from '@noble/hashes/utils';
|
|
2
|
+
import { schnorr } from '@noble/curves/secp256k1';
|
|
3
|
+
import { finalizeEvent } from './event.js';
|
|
4
|
+
import * as nip04 from './nip04.js';
|
|
5
|
+
export function createSecretKeySigner(secretKey) {
|
|
6
|
+
const pubkey = bytesToHex(schnorr.getPublicKey(secretKey));
|
|
7
|
+
return {
|
|
8
|
+
async getPublicKey() {
|
|
9
|
+
return pubkey;
|
|
10
|
+
},
|
|
11
|
+
async signEvent(event) {
|
|
12
|
+
return finalizeEvent(event, secretKey);
|
|
13
|
+
},
|
|
14
|
+
nip04: {
|
|
15
|
+
async encrypt(pubkey, plaintext) {
|
|
16
|
+
return nip04.encrypt(secretKey, pubkey, plaintext);
|
|
17
|
+
},
|
|
18
|
+
async decrypt(pubkey, ciphertext) {
|
|
19
|
+
return nip04.decrypt(secretKey, pubkey, ciphertext);
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=signer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signer.js","sourceRoot":"","sources":["../src/signer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AAEjD,OAAO,EAAE,aAAa,EAA0C,MAAM,YAAY,CAAA;AAClF,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AAcnC,MAAM,UAAU,qBAAqB,CAAC,SAAqB;IACzD,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAA;IAE1D,OAAO;QACL,KAAK,CAAC,YAAY;YAChB,OAAO,MAAM,CAAA;QACf,CAAC;QAED,KAAK,CAAC,SAAS,CAAC,KAAoB;YAClC,OAAO,aAAa,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;QACxC,CAAC;QAED,KAAK,EAAE;YACL,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,SAAiB;gBAC7C,OAAO,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,CAAA;YACpD,CAAC;YACD,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,UAAkB;gBAC9C,OAAO,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,CAAA;YACrD,CAAC;SACF;KACF,CAAA;AACH,CAAC"}
|