@nostrify/nostrify 0.48.2 → 0.48.3
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/.turbo/turbo-build.log +2 -3
- package/.turbo/turbo-typecheck.log +1 -1
- package/CHANGELOG.md +8 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/dist/BunkerURI.ts +0 -58
- package/dist/NBrowserSigner.ts +0 -100
- package/dist/NCache.ts +0 -73
- package/dist/NConnectSigner.ts +0 -188
- package/dist/NIP05.ts +0 -51
- package/dist/NIP50.ts +0 -24
- package/dist/NIP98.ts +0 -111
- package/dist/NIP98Client.ts +0 -36
- package/dist/NKinds.ts +0 -26
- package/dist/NPool.ts +0 -243
- package/dist/NRelay1.ts +0 -447
- package/dist/NSchema.ts +0 -291
- package/dist/NSecSigner.ts +0 -62
- package/dist/NSet.ts +0 -210
- package/dist/RelayError.ts +0 -22
- package/dist/ln/LNURL.ts +0 -146
- package/dist/ln/mod.ts +0 -4
- package/dist/ln/types/LNURLCallback.ts +0 -7
- package/dist/ln/types/LNURLDetails.ts +0 -19
- package/dist/mod.ts +0 -17
- package/dist/test/ErrorRelay.ts +0 -52
- package/dist/test/MockRelay.ts +0 -92
- package/dist/test/TestRelayServer.ts +0 -185
- package/dist/test/mod.ts +0 -28
- package/dist/uploaders/BlossomUploader.ts +0 -100
- package/dist/uploaders/NostrBuildUploader.ts +0 -89
- package/dist/uploaders/mod.ts +0 -2
- package/dist/utils/CircularSet.ts +0 -36
- package/dist/utils/Machina.ts +0 -66
- package/dist/utils/N64.ts +0 -23
- package/dist/utils/mod.ts +0 -2
package/dist/NSchema.ts
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
import type {
|
|
4
|
-
NostrClientAUTH,
|
|
5
|
-
NostrClientCLOSE,
|
|
6
|
-
NostrClientCOUNT,
|
|
7
|
-
NostrClientEVENT,
|
|
8
|
-
NostrClientMsg,
|
|
9
|
-
NostrClientREQ,
|
|
10
|
-
NostrConnectRequest,
|
|
11
|
-
NostrConnectResponse,
|
|
12
|
-
NostrEvent,
|
|
13
|
-
NostrFilter,
|
|
14
|
-
NostrMetadata,
|
|
15
|
-
NostrRelayAUTH,
|
|
16
|
-
NostrRelayCLOSED,
|
|
17
|
-
NostrRelayCOUNT,
|
|
18
|
-
NostrRelayEOSE,
|
|
19
|
-
NostrRelayEVENT,
|
|
20
|
-
NostrRelayMsg,
|
|
21
|
-
NostrRelayNOTICE,
|
|
22
|
-
NostrRelayOK,
|
|
23
|
-
} from "@nostrify/types";
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* A suite of [zod](https://github.com/colinhacks/zod) schemas for Nostr.
|
|
27
|
-
*
|
|
28
|
-
* ```ts
|
|
29
|
-
* import { NSchema as n } from '@nostrify/nostrify';
|
|
30
|
-
*
|
|
31
|
-
* const event: NostrEvent = n.event().parse(eventData);
|
|
32
|
-
* const metadata: NostrMetadata = n.json().pipe(n.metadata()).parse(event.content);
|
|
33
|
-
* const msg: NostrRelayMsg = n.relayMsg().parse(e.data);
|
|
34
|
-
* const nsec: `nsec1${string}` = n.bech32('nsec').parse(token);
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
|
-
class NSchema {
|
|
38
|
-
/** Schema to validate Nostr hex IDs such as event IDs and pubkeys. */
|
|
39
|
-
static id(): z.ZodString {
|
|
40
|
-
return z.string().regex(/^[0-9a-f]{64}$/);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Nostr event schema. */
|
|
44
|
-
static event(): z.ZodType<NostrEvent> {
|
|
45
|
-
return z.object({
|
|
46
|
-
id: NSchema.id(),
|
|
47
|
-
kind: z.number().int().nonnegative(),
|
|
48
|
-
pubkey: NSchema.id(),
|
|
49
|
-
tags: z.string().array().array(),
|
|
50
|
-
content: z.string(),
|
|
51
|
-
created_at: z.number().int().nonnegative(),
|
|
52
|
-
sig: z.string(),
|
|
53
|
-
}).required({
|
|
54
|
-
id: true,
|
|
55
|
-
kind: true,
|
|
56
|
-
pubkey: true,
|
|
57
|
-
tags: true,
|
|
58
|
-
content: true,
|
|
59
|
-
created_at: true,
|
|
60
|
-
sig: true,
|
|
61
|
-
}) as z.ZodType<NostrEvent>;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** Nostr filter schema. */
|
|
65
|
-
static filter(): z.ZodType<NostrFilter> {
|
|
66
|
-
return z.object({
|
|
67
|
-
kinds: z.number().int().nonnegative().array().optional(),
|
|
68
|
-
ids: NSchema.id().array().optional(),
|
|
69
|
-
authors: NSchema.id().array().optional(),
|
|
70
|
-
since: z.number().int().nonnegative().optional(),
|
|
71
|
-
until: z.number().int().nonnegative().optional(),
|
|
72
|
-
limit: z.number().int().nonnegative().optional(),
|
|
73
|
-
search: z.string().optional(),
|
|
74
|
-
})
|
|
75
|
-
.passthrough()
|
|
76
|
-
.transform((value) => {
|
|
77
|
-
const keys = [
|
|
78
|
-
"kinds",
|
|
79
|
-
"ids",
|
|
80
|
-
"authors",
|
|
81
|
-
"since",
|
|
82
|
-
"until",
|
|
83
|
-
"limit",
|
|
84
|
-
"search",
|
|
85
|
-
];
|
|
86
|
-
return Object.entries(value).reduce((acc, [key, val]) => {
|
|
87
|
-
if (keys.includes(key) || key.startsWith("#")) {
|
|
88
|
-
acc[key] = val;
|
|
89
|
-
}
|
|
90
|
-
return acc;
|
|
91
|
-
}, {} as Record<string, unknown>) as NostrFilter;
|
|
92
|
-
}) as z.ZodType<NostrFilter>;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Bech32 string.
|
|
97
|
-
* @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32
|
|
98
|
-
*/
|
|
99
|
-
static bech32<P extends string>(prefix?: P): z.ZodType<`${P}1${string}`> {
|
|
100
|
-
return z
|
|
101
|
-
.string()
|
|
102
|
-
.regex(/^[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}$/)
|
|
103
|
-
.refine((value) =>
|
|
104
|
-
prefix ? value.startsWith(`${prefix}1`) : true
|
|
105
|
-
) as z.ZodType<`${P}1${string}`>;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/** WebSocket URL starting with `ws://` or `wss://`. */
|
|
109
|
-
static relayUrl(): z.ZodType<`ws://${string}` | `wss://${string}`> {
|
|
110
|
-
return z
|
|
111
|
-
.string()
|
|
112
|
-
.url()
|
|
113
|
-
.regex(/^wss?:\/\//) as z.ZodType<`ws://${string}` | `wss://${string}`>;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** NIP-01 `EVENT` message from client to relay. */
|
|
117
|
-
static clientEVENT(): z.ZodType<NostrClientEVENT> {
|
|
118
|
-
return z.tuple([
|
|
119
|
-
z.literal("EVENT"),
|
|
120
|
-
NSchema.event(),
|
|
121
|
-
]) as unknown as z.ZodType<
|
|
122
|
-
NostrClientEVENT
|
|
123
|
-
>;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/** NIP-01 `REQ` message from client to relay. */
|
|
127
|
-
static clientREQ(): z.ZodType<NostrClientREQ> {
|
|
128
|
-
return z.tuple([z.literal("REQ"), z.string()]).rest(NSchema.filter());
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** NIP-45 `COUNT` message from client to relay. */
|
|
132
|
-
static clientCOUNT(): z.ZodType<NostrClientCOUNT> {
|
|
133
|
-
return z.tuple([z.literal("COUNT"), z.string()]).rest(NSchema.filter());
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/** NIP-01 `CLOSE` message from client to relay. */
|
|
137
|
-
static clientCLOSE(): z.ZodType<NostrClientCLOSE> {
|
|
138
|
-
return z.tuple([z.literal("CLOSE"), z.string()]) as unknown as z.ZodType<
|
|
139
|
-
NostrClientCLOSE
|
|
140
|
-
>;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/** NIP-42 `AUTH` message from client to relay. */
|
|
144
|
-
static clientAUTH(): z.ZodType<NostrClientAUTH> {
|
|
145
|
-
return z.tuple([
|
|
146
|
-
z.literal("AUTH"),
|
|
147
|
-
NSchema.event(),
|
|
148
|
-
]) as unknown as z.ZodType<
|
|
149
|
-
NostrClientAUTH
|
|
150
|
-
>;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/** NIP-01 message from client to relay. */
|
|
154
|
-
static clientMsg(): z.ZodType<NostrClientMsg> {
|
|
155
|
-
return z.union([
|
|
156
|
-
NSchema.clientEVENT(),
|
|
157
|
-
NSchema.clientREQ(),
|
|
158
|
-
NSchema.clientCOUNT(),
|
|
159
|
-
NSchema.clientCLOSE(),
|
|
160
|
-
NSchema.clientAUTH(),
|
|
161
|
-
]) as z.ZodType<NostrClientMsg>;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/** NIP-01 `EVENT` message from relay to client. */
|
|
165
|
-
static relayEVENT(): z.ZodType<NostrRelayEVENT> {
|
|
166
|
-
return z.tuple([
|
|
167
|
-
z.literal("EVENT"),
|
|
168
|
-
z.string(),
|
|
169
|
-
NSchema.event(),
|
|
170
|
-
]) as unknown as z.ZodType<NostrRelayEVENT>;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/** NIP-01 `OK` message from relay to client. */
|
|
174
|
-
static relayOK(): z.ZodType<NostrRelayOK> {
|
|
175
|
-
return z.tuple([
|
|
176
|
-
z.literal("OK"),
|
|
177
|
-
NSchema.id(),
|
|
178
|
-
z.boolean(),
|
|
179
|
-
z.string(),
|
|
180
|
-
]) as unknown as z.ZodType<NostrRelayOK>;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/** NIP-01 `EOSE` message from relay to client. */
|
|
184
|
-
static relayEOSE(): z.ZodType<NostrRelayEOSE> {
|
|
185
|
-
return z.tuple([z.literal("EOSE"), z.string()]) as unknown as z.ZodType<
|
|
186
|
-
NostrRelayEOSE
|
|
187
|
-
>;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/** NIP-01 `NOTICE` message from relay to client. */
|
|
191
|
-
static relayNOTICE(): z.ZodType<NostrRelayNOTICE> {
|
|
192
|
-
return z.tuple([z.literal("NOTICE"), z.string()]) as unknown as z.ZodType<
|
|
193
|
-
NostrRelayNOTICE
|
|
194
|
-
>;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/** NIP-01 `CLOSED` message from relay to client. */
|
|
198
|
-
static relayCLOSED(): z.ZodType<NostrRelayCLOSED> {
|
|
199
|
-
return z.tuple([
|
|
200
|
-
z.literal("CLOSED"),
|
|
201
|
-
z.string(),
|
|
202
|
-
z.string(),
|
|
203
|
-
]) as unknown as z.ZodType<NostrRelayCLOSED>;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/** NIP-42 `AUTH` message from relay to client. */
|
|
207
|
-
static relayAUTH(): z.ZodType<NostrRelayAUTH> {
|
|
208
|
-
return z.tuple([z.literal("AUTH"), z.string()]) as unknown as z.ZodType<
|
|
209
|
-
NostrRelayAUTH
|
|
210
|
-
>;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/** NIP-45 `COUNT` message from relay to client. */
|
|
214
|
-
static relayCOUNT(): z.ZodType<NostrRelayCOUNT> {
|
|
215
|
-
return z.tuple([
|
|
216
|
-
z.literal("COUNT"),
|
|
217
|
-
z.string(),
|
|
218
|
-
z.object({
|
|
219
|
-
count: z.number().int().nonnegative(),
|
|
220
|
-
approximate: z.boolean().optional(),
|
|
221
|
-
}),
|
|
222
|
-
]) as unknown as z.ZodType<NostrRelayCOUNT>;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/** NIP-01 message from relay to client. */
|
|
226
|
-
static relayMsg(): z.ZodType<NostrRelayMsg> {
|
|
227
|
-
return z.union([
|
|
228
|
-
NSchema.relayEVENT(),
|
|
229
|
-
NSchema.relayOK(),
|
|
230
|
-
NSchema.relayEOSE(),
|
|
231
|
-
NSchema.relayNOTICE(),
|
|
232
|
-
NSchema.relayCLOSED(),
|
|
233
|
-
NSchema.relayAUTH(),
|
|
234
|
-
NSchema.relayCOUNT(),
|
|
235
|
-
]);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/** Kind 0 content schema. */
|
|
239
|
-
static metadata(): z.ZodType<NostrMetadata> {
|
|
240
|
-
return z.object({
|
|
241
|
-
about: z.string().optional().catch(undefined),
|
|
242
|
-
banner: z.string().url().optional().catch(undefined),
|
|
243
|
-
bot: z.boolean().optional().catch(undefined),
|
|
244
|
-
display_name: z.string().optional().catch(undefined),
|
|
245
|
-
lud06: NSchema.bech32("lnurl").optional().catch(undefined),
|
|
246
|
-
lud16: z.string().email().optional().catch(undefined),
|
|
247
|
-
name: z.string().optional().catch(undefined),
|
|
248
|
-
nip05: z.string().email().optional().catch(undefined),
|
|
249
|
-
picture: z.string().url().optional().catch(undefined),
|
|
250
|
-
website: z.string().url().optional().catch(undefined),
|
|
251
|
-
}).passthrough() as z.ZodType<NostrMetadata>;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/** NIP-46 request content schema. */
|
|
255
|
-
static connectRequest(): z.ZodType<NostrConnectRequest> {
|
|
256
|
-
return z.object({
|
|
257
|
-
id: z.string(),
|
|
258
|
-
method: z.string(),
|
|
259
|
-
params: z.string().array(),
|
|
260
|
-
}) as z.ZodType<NostrConnectRequest>;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/** NIP-46 response content schema. */
|
|
264
|
-
static connectResponse(): z.ZodType<NostrConnectResponse> {
|
|
265
|
-
return z.object({
|
|
266
|
-
id: z.string(),
|
|
267
|
-
result: z.string(),
|
|
268
|
-
error: z.string().optional(),
|
|
269
|
-
}) as z.ZodType<NostrConnectResponse>;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Helper schema to parse a JSON string. It should then be piped into another schema. For example:
|
|
274
|
-
*
|
|
275
|
-
* ```ts
|
|
276
|
-
* const event = NSchema.json().pipe(NSchema.event()).parse(data);
|
|
277
|
-
* ```
|
|
278
|
-
*/
|
|
279
|
-
static json(): z.ZodType<unknown> {
|
|
280
|
-
return z.string().transform((value, ctx) => {
|
|
281
|
-
try {
|
|
282
|
-
return JSON.parse(value) as unknown;
|
|
283
|
-
} catch (_e) {
|
|
284
|
-
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Invalid JSON" });
|
|
285
|
-
return z.NEVER;
|
|
286
|
-
}
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
export { NSchema, z };
|
package/dist/NSecSigner.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
// deno-lint-ignore-file require-await
|
|
2
|
-
|
|
3
|
-
import { finalizeEvent, getPublicKey, nip04, nip44 } from 'nostr-tools';
|
|
4
|
-
|
|
5
|
-
import type { NostrEvent, NostrSigner } from '@nostrify/types';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* NIP-07-compatible signer with secret key. It is a drop-in replacement for `window.nostr`.
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
*
|
|
12
|
-
* ```ts
|
|
13
|
-
* const signer = new NSecSigner(secretKey);
|
|
14
|
-
* const pubkey = await signer.getPublicKey();
|
|
15
|
-
* const event = await signer.signEvent({ kind: 1, content: 'Hello, world!', tags: [], created_at: 0 });
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
export class NSecSigner implements NostrSigner {
|
|
19
|
-
#secretKey: Uint8Array;
|
|
20
|
-
private pubkey?: string;
|
|
21
|
-
|
|
22
|
-
constructor(secretKey: Uint8Array) {
|
|
23
|
-
this.#secretKey = secretKey;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async getPublicKey(): Promise<string> {
|
|
27
|
-
return this.pubkey ??= getPublicKey(this.#secretKey);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async signEvent(
|
|
31
|
-
event: Omit<NostrEvent, 'id' | 'pubkey' | 'sig'>,
|
|
32
|
-
): Promise<NostrEvent> {
|
|
33
|
-
// @ts-ignore this is fine
|
|
34
|
-
return finalizeEvent(event, this.#secretKey);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
readonly nip04 = {
|
|
38
|
-
encrypt: async (pubkey: string, plaintext: string): Promise<string> => {
|
|
39
|
-
return nip04.encrypt(this.#secretKey, pubkey, plaintext);
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
decrypt: async (pubkey: string, ciphertext: string): Promise<string> => {
|
|
43
|
-
return nip04.decrypt(this.#secretKey, pubkey, ciphertext);
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
#getConversationKey(pubkey: string): Uint8Array {
|
|
48
|
-
return nip44.v2.utils.getConversationKey(this.#secretKey, pubkey);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
readonly nip44 = {
|
|
52
|
-
encrypt: async (pubkey: string, plaintext: string): Promise<string> => {
|
|
53
|
-
const conversationKey = this.#getConversationKey(pubkey);
|
|
54
|
-
return nip44.v2.encrypt(plaintext, conversationKey);
|
|
55
|
-
},
|
|
56
|
-
|
|
57
|
-
decrypt: async (pubkey: string, ciphertext: string): Promise<string> => {
|
|
58
|
-
const conversationKey = this.#getConversationKey(pubkey);
|
|
59
|
-
return nip44.v2.decrypt(ciphertext, conversationKey);
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
}
|
package/dist/NSet.ts
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import type { NostrEvent } from '@nostrify/types';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Nostr event implementation of the `Set` interface.
|
|
5
|
-
*
|
|
6
|
-
* NSet is an implementation of the theory that a Nostr Storage is actually just a Set.
|
|
7
|
-
* Events are Nostr's only data type, and they are immutable, making the Set interface ideal.
|
|
8
|
-
*
|
|
9
|
-
* ```ts
|
|
10
|
-
* const events = new NSet();
|
|
11
|
-
*
|
|
12
|
-
* // Events can be added like a regular `Set`:
|
|
13
|
-
* events.add(event1);
|
|
14
|
-
* events.add(event2);
|
|
15
|
-
*
|
|
16
|
-
* // Can be iterated:
|
|
17
|
-
* for (const event of events) {
|
|
18
|
-
* if (matchFilters(filters, event)) {
|
|
19
|
-
* console.log(event);
|
|
20
|
-
* }
|
|
21
|
-
* }
|
|
22
|
-
* ```
|
|
23
|
-
*
|
|
24
|
-
* `NSet` will handle kind `5` deletions, removing events from the set.
|
|
25
|
-
* Replaceable (and parameterized) events will keep only the newest version.
|
|
26
|
-
* However, verification of `id` and `sig` is NOT performed.
|
|
27
|
-
*
|
|
28
|
-
* Any `Map` instance can be passed into `new NSet()`, making it compatible with
|
|
29
|
-
* [lru-cache](https://www.npmjs.com/package/lru-cache), among others.
|
|
30
|
-
*/
|
|
31
|
-
class NSet {
|
|
32
|
-
protected cache: Map<string, NostrEvent>;
|
|
33
|
-
|
|
34
|
-
constructor(map?: Map<string, NostrEvent>) {
|
|
35
|
-
this.cache = map ?? new Map();
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
get size(): number {
|
|
39
|
-
return this.cache.size;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
add(event: NostrEvent): this {
|
|
43
|
-
this.#processDeletions(event);
|
|
44
|
-
|
|
45
|
-
for (const e of this) {
|
|
46
|
-
if (NSet.deletes(e, event) || NSet.replaces(e, event)) {
|
|
47
|
-
return this;
|
|
48
|
-
} else if (NSet.replaces(event, e)) {
|
|
49
|
-
this.delete(e);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
this.cache.set(event.id, event);
|
|
54
|
-
return this;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
#processDeletions(event: NostrEvent): void {
|
|
58
|
-
if (event.kind === 5) {
|
|
59
|
-
for (const tag of event.tags) {
|
|
60
|
-
if (tag[0] === 'e') {
|
|
61
|
-
const e = this.cache.get(tag[1]);
|
|
62
|
-
if (e && e.pubkey === event.pubkey) {
|
|
63
|
-
this.delete(e);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
clear(): void {
|
|
71
|
-
this.cache.clear();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
delete(event: NostrEvent): boolean {
|
|
75
|
-
return this.cache.delete(event.id);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
forEach(
|
|
79
|
-
callbackfn: (event: NostrEvent, key: NostrEvent, set: typeof this) => void,
|
|
80
|
-
thisArg?: any,
|
|
81
|
-
): void {
|
|
82
|
-
return this.cache.forEach(
|
|
83
|
-
(event, _id) => callbackfn(event, event, this),
|
|
84
|
-
thisArg,
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
has(event: NostrEvent): boolean {
|
|
89
|
-
return this.cache.has(event.id);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
*entries(): IterableIterator<[NostrEvent, NostrEvent]> {
|
|
93
|
-
for (const event of this.values()) {
|
|
94
|
-
yield [event, event];
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
keys(): IterableIterator<NostrEvent> {
|
|
99
|
-
return this.values();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
*values(): IterableIterator<NostrEvent> {
|
|
103
|
-
for (const event of NSet.sortEvents([...this.cache.values()])) {
|
|
104
|
-
yield event;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
[Symbol.iterator](): IterableIterator<NostrEvent> {
|
|
109
|
-
return this.values();
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
[Symbol.toStringTag]: string = 'NSet';
|
|
113
|
-
|
|
114
|
-
/** Event kind is **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */
|
|
115
|
-
protected static isReplaceable(kind: number): boolean {
|
|
116
|
-
return [0, 3].includes(kind) || (10000 <= kind && kind < 20000);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** Event kind is **parameterized replaceable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */
|
|
120
|
-
protected static isAddressable(kind: number): boolean {
|
|
121
|
-
return 30000 <= kind && kind < 40000;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Returns true if `event` replaces `target`.
|
|
126
|
-
*
|
|
127
|
-
* Both events must be replaceable, belong to the same kind and pubkey (and `d` tag, for parameterized events), and the `event` must be newer than the `target`.
|
|
128
|
-
*/
|
|
129
|
-
protected static replaces(event: NostrEvent, target: NostrEvent): boolean {
|
|
130
|
-
const { kind, pubkey } = event;
|
|
131
|
-
|
|
132
|
-
if (NSet.isReplaceable(kind)) {
|
|
133
|
-
return kind === target.kind && pubkey === target.pubkey &&
|
|
134
|
-
NSet.sortEvents([event, target])[0] === event;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (NSet.isAddressable(kind)) {
|
|
138
|
-
const d1 = event.tags.find(([name]: string[]) => name === 'd')?.[1] || '';
|
|
139
|
-
const d2 = target.tags.find(([name]: string[]) => name === 'd')?.[1] || '';
|
|
140
|
-
|
|
141
|
-
return kind === target.kind &&
|
|
142
|
-
pubkey === target.pubkey &&
|
|
143
|
-
NSet.sortEvents([event, target])[0] === event &&
|
|
144
|
-
d1 === d2;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return false;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Returns true if the `event` deletes`target`.
|
|
152
|
-
*
|
|
153
|
-
* `event` must be a kind `5` event, and both events must share the same `pubkey`.
|
|
154
|
-
*/
|
|
155
|
-
protected static deletes(event: NostrEvent, target: NostrEvent): boolean {
|
|
156
|
-
const { kind, pubkey, tags } = event;
|
|
157
|
-
if (kind === 5 && pubkey === target.pubkey) {
|
|
158
|
-
for (const [name, value] of tags) {
|
|
159
|
-
if (name === 'e' && value === target.id) {
|
|
160
|
-
return true;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return false;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Sort events in reverse-chronological order by the `created_at` timestamp,
|
|
169
|
-
* and then by the event `id` (lexicographically) in case of ties.
|
|
170
|
-
* This mutates the array.
|
|
171
|
-
*/
|
|
172
|
-
protected static sortEvents(events: NostrEvent[]): NostrEvent[] {
|
|
173
|
-
return events.sort((a: NostrEvent, b: NostrEvent): number => {
|
|
174
|
-
if (a.created_at !== b.created_at) {
|
|
175
|
-
return b.created_at - a.created_at;
|
|
176
|
-
}
|
|
177
|
-
return a.id.localeCompare(b.id);
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
union<U>(_other: Set<U>): Set<NostrEvent | U> {
|
|
182
|
-
throw new Error('Method not implemented.');
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
intersection<U>(_other: Set<U>): Set<NostrEvent & U> {
|
|
186
|
-
throw new Error('Method not implemented.');
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
difference<U>(_other: Set<U>): Set<NostrEvent> {
|
|
190
|
-
throw new Error('Method not implemented.');
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
symmetricDifference<U>(_other: Set<U>): Set<NostrEvent | U> {
|
|
194
|
-
throw new Error('Method not implemented.');
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
isSubsetOf(_other: Set<unknown>): boolean {
|
|
198
|
-
throw new Error('Method not implemented.');
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
isSupersetOf(_other: Set<unknown>): boolean {
|
|
202
|
-
throw new Error('Method not implemented.');
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
isDisjointFrom(_other: Set<unknown>): boolean {
|
|
206
|
-
throw new Error('Method not implemented.');
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export { NSet };
|
package/dist/RelayError.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { NostrRelayOK } from '@nostrify/types';
|
|
2
|
-
|
|
3
|
-
/** NIP-01 command line result. */
|
|
4
|
-
export class RelayError extends Error {
|
|
5
|
-
constructor(prefix: string, message: string) {
|
|
6
|
-
super(`${prefix}: ${message}`);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/** Construct a RelayError from the reason message. */
|
|
10
|
-
static fromReason(reason: string): RelayError {
|
|
11
|
-
const [prefix, ...rest] = reason.split(': ');
|
|
12
|
-
return new RelayError(prefix, rest.join(': '));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** Throw a new RelayError if the OK message is false. */
|
|
16
|
-
static assert(msg: NostrRelayOK): void {
|
|
17
|
-
const [, , ok, reason] = msg;
|
|
18
|
-
if (!ok) {
|
|
19
|
-
throw RelayError.fromReason(reason);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|