@nostrify/nostrify 0.46.7 → 0.46.9
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 +121 -2
- package/.turbo/turbo-setup.log +13 -0
- package/.turbo/turbo-test.log +91 -0
- package/BunkerURI.test.ts +19 -14
- package/CHANGELOG.md +16 -0
- package/NBrowserSigner.test.ts +49 -34
- package/NCache.test.ts +14 -7
- package/NCache.ts +2 -2
- package/NConnectSigner.test.ts +48 -31
- package/NConnectSigner.ts +3 -3
- package/NIP05.test.ts +36 -44
- package/NIP05.ts +6 -6
- package/NIP50.test.ts +35 -34
- package/NIP98.test.ts +89 -76
- package/NIP98.ts +2 -2
- package/NKinds.test.ts +37 -36
- package/NPool.test.ts +35 -24
- package/NPool.ts +42 -23
- package/NRelay1.test.ts +100 -68
- package/NRelay1.ts +13 -6
- package/NSchema.test.ts +98 -56
- package/NSchema.ts +74 -37
- package/NSecSigner.test.ts +19 -10
- package/NSecSigner.ts +4 -3
- package/NSet.test.ts +123 -50
- package/NSet.ts +13 -6
- package/RelayError.test.ts +11 -10
- package/RelayError.ts +1 -1
- package/dist/NCache.d.ts +2 -2
- package/dist/NCache.d.ts.map +1 -1
- package/dist/NConnectSigner.d.ts +1 -1
- package/dist/NConnectSigner.d.ts.map +1 -1
- package/dist/NIP05.d.ts +1 -1
- package/dist/NIP05.d.ts.map +1 -1
- package/dist/NIP98.d.ts +1 -1
- package/dist/NIP98.d.ts.map +1 -1
- package/dist/NPool.d.ts +2 -2
- package/dist/NPool.d.ts.map +1 -1
- package/dist/NRelay1.d.ts +5 -4
- package/dist/NRelay1.d.ts.map +1 -1
- package/dist/NSchema.d.ts +1 -1
- package/dist/NSchema.d.ts.map +1 -1
- package/dist/NSecSigner.d.ts +1 -2
- package/dist/NSecSigner.d.ts.map +1 -1
- package/dist/NSet.d.ts +1 -1
- package/dist/NSet.d.ts.map +1 -1
- package/dist/RelayError.d.ts +1 -1
- package/dist/RelayError.d.ts.map +1 -1
- package/dist/ln/LNURL.d.ts +4 -4
- package/dist/ln/LNURL.d.ts.map +1 -1
- package/dist/ln/mod.d.ts +3 -3
- package/dist/mod.d.ts +14 -14
- package/dist/test/ErrorRelay.d.ts +1 -1
- package/dist/test/ErrorRelay.d.ts.map +1 -1
- package/dist/test/MockRelay.d.ts +3 -3
- package/dist/test/MockRelay.d.ts.map +1 -1
- package/dist/test/TestRelayServer.d.ts +6 -3
- package/dist/test/TestRelayServer.d.ts.map +1 -1
- package/dist/test/mod.d.ts +3 -3
- package/dist/test/mod.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/uploaders/BlossomUploader.d.ts +1 -1
- package/dist/uploaders/BlossomUploader.d.ts.map +1 -1
- package/dist/uploaders/NostrBuildUploader.d.ts +1 -2
- package/dist/uploaders/NostrBuildUploader.d.ts.map +1 -1
- package/dist/uploaders/mod.d.ts +2 -2
- package/dist/utils/CircularSet.d.ts +1 -1
- package/dist/utils/CircularSet.d.ts.map +1 -1
- package/dist/utils/N64.d.ts +1 -1
- package/dist/utils/N64.d.ts.map +1 -1
- package/dist/utils/mod.d.ts +2 -2
- package/ln/LNURL.test.ts +70 -52
- package/ln/LNURL.ts +15 -15
- package/ln/mod.ts +3 -3
- package/mod.ts +14 -14
- package/package.json +5 -3
- package/test/ErrorRelay.test.ts +11 -10
- package/test/ErrorRelay.ts +17 -5
- package/test/MockRelay.test.ts +15 -8
- package/test/MockRelay.ts +3 -3
- package/test/TestRelayServer.ts +46 -17
- package/test/mod.ts +4 -4
- package/tsconfig.json +5 -3
- package/uploaders/BlossomUploader.test.ts +39 -22
- package/uploaders/BlossomUploader.ts +2 -2
- package/uploaders/NostrBuildUploader.test.ts +36 -18
- package/uploaders/NostrBuildUploader.ts +4 -4
- package/uploaders/mod.ts +2 -2
- package/utils/CircularSet.test.ts +5 -4
- package/utils/CircularSet.ts +3 -1
- package/utils/Machina.test.ts +30 -19
- package/utils/N64.test.ts +12 -11
- package/utils/N64.ts +2 -2
- package/utils/mod.ts +2 -2
- package/dist/BunkerURI.js +0 -48
- package/dist/BunkerURI.js.map +0 -1
- package/dist/NBrowserSigner.js +0 -92
- package/dist/NBrowserSigner.js.map +0 -1
- package/dist/NCache.js +0 -60
- package/dist/NCache.js.map +0 -1
- package/dist/NConnectSigner.js +0 -125
- package/dist/NConnectSigner.js.map +0 -1
- package/dist/NIP05.js +0 -35
- package/dist/NIP05.js.map +0 -1
- package/dist/NIP50.js +0 -22
- package/dist/NIP50.js.map +0 -1
- package/dist/NIP98.js +0 -67
- package/dist/NIP98.js.map +0 -1
- package/dist/NKinds.js +0 -23
- package/dist/NKinds.js.map +0 -1
- package/dist/NPool.js +0 -181
- package/dist/NPool.js.map +0 -1
- package/dist/NRelay1.js +0 -332
- package/dist/NRelay1.js.map +0 -1
- package/dist/NSchema.js +0 -210
- package/dist/NSchema.js.map +0 -1
- package/dist/NSecSigner.js +0 -49
- package/dist/NSecSigner.js.map +0 -1
- package/dist/NSet.js +0 -171
- package/dist/NSet.js.map +0 -1
- package/dist/RelayError.js +0 -19
- package/dist/RelayError.js.map +0 -1
- package/dist/ln/LNURL.js +0 -101
- package/dist/ln/LNURL.js.map +0 -1
- package/dist/ln/mod.js +0 -2
- package/dist/ln/mod.js.map +0 -1
- package/dist/ln/types/LNURLCallback.js +0 -2
- package/dist/ln/types/LNURLCallback.js.map +0 -1
- package/dist/ln/types/LNURLDetails.js +0 -2
- package/dist/ln/types/LNURLDetails.js.map +0 -1
- package/dist/mod.js +0 -15
- package/dist/mod.js.map +0 -1
- package/dist/test/ErrorRelay.js +0 -22
- package/dist/test/ErrorRelay.js.map +0 -1
- package/dist/test/MockRelay.js +0 -62
- package/dist/test/MockRelay.js.map +0 -1
- package/dist/test/TestRelayServer.js +0 -130
- package/dist/test/TestRelayServer.js.map +0 -1
- package/dist/test/mod.js +0 -21
- package/dist/test/mod.js.map +0 -1
- package/dist/uploaders/BlossomUploader.js +0 -67
- package/dist/uploaders/BlossomUploader.js.map +0 -1
- package/dist/uploaders/NostrBuildUploader.js +0 -63
- package/dist/uploaders/NostrBuildUploader.js.map +0 -1
- package/dist/uploaders/mod.js +0 -3
- package/dist/uploaders/mod.js.map +0 -1
- package/dist/utils/CircularSet.js +0 -31
- package/dist/utils/CircularSet.js.map +0 -1
- package/dist/utils/Machina.js +0 -62
- package/dist/utils/Machina.js.map +0 -1
- package/dist/utils/N64.js +0 -19
- package/dist/utils/N64.js.map +0 -1
- package/dist/utils/mod.js +0 -3
- package/dist/utils/mod.js.map +0 -1
package/NIP98.test.ts
CHANGED
|
@@ -1,181 +1,194 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import { deepStrictEqual, rejects } from "node:assert";
|
|
3
|
+
import { generateSecretKey } from "nostr-tools";
|
|
4
|
+
import { ZodError } from "zod";
|
|
4
5
|
|
|
5
|
-
import { NIP98 } from
|
|
6
|
-
import { NSecSigner } from
|
|
7
|
-
import { N64 } from
|
|
6
|
+
import { NIP98 } from "./NIP98.ts";
|
|
7
|
+
import { NSecSigner } from "./NSecSigner.ts";
|
|
8
|
+
import { N64 } from "./utils/mod.ts";
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
const request = new Request(
|
|
10
|
+
await test("NIP98.template", async () => {
|
|
11
|
+
const request = new Request("https://example.com");
|
|
11
12
|
const event = await NIP98.template(request);
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
[
|
|
16
|
-
[
|
|
14
|
+
deepStrictEqual(event.kind, 27235);
|
|
15
|
+
deepStrictEqual(event.tags, [
|
|
16
|
+
["method", "GET"],
|
|
17
|
+
["u", "https://example.com/"],
|
|
17
18
|
]);
|
|
18
19
|
});
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
const request = new Request(
|
|
22
|
-
method:
|
|
23
|
-
body:
|
|
21
|
+
await test("NIP98.template with payload", async () => {
|
|
22
|
+
const request = new Request("https://example.com", {
|
|
23
|
+
method: "POST",
|
|
24
|
+
body: "Hello, world!",
|
|
24
25
|
});
|
|
25
26
|
const event = await NIP98.template(request);
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
[
|
|
30
|
-
[
|
|
31
|
-
[
|
|
28
|
+
deepStrictEqual(event.kind, 27235);
|
|
29
|
+
deepStrictEqual(event.tags, [
|
|
30
|
+
["method", "POST"],
|
|
31
|
+
["u", "https://example.com/"],
|
|
32
|
+
[
|
|
33
|
+
"payload",
|
|
34
|
+
"315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3",
|
|
35
|
+
],
|
|
32
36
|
]);
|
|
33
37
|
});
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
await test("NIP98.verify", async () => {
|
|
36
40
|
const signer = new NSecSigner(generateSecretKey());
|
|
37
|
-
const request = new Request(
|
|
41
|
+
const request = new Request("https://example.com");
|
|
38
42
|
|
|
39
43
|
const t = await NIP98.template(request);
|
|
40
44
|
const event = await signer.signEvent(t);
|
|
41
45
|
|
|
42
|
-
request.headers.set(
|
|
46
|
+
request.headers.set("authorization", `Nostr ${N64.encodeEvent(event)}`);
|
|
43
47
|
|
|
44
48
|
const proof = await NIP98.verify(request);
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
deepStrictEqual(proof, event);
|
|
51
|
+
deepStrictEqual(proof.pubkey, await signer.getPublicKey());
|
|
48
52
|
});
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
const request = new Request(
|
|
54
|
+
await test("NIP98.verify fails with missing header", async () => {
|
|
55
|
+
const request = new Request("https://example.com");
|
|
52
56
|
|
|
53
|
-
await
|
|
57
|
+
await rejects(
|
|
54
58
|
() => NIP98.verify(request),
|
|
55
59
|
Error,
|
|
56
|
-
|
|
60
|
+
"Missing Nostr authorization header",
|
|
57
61
|
);
|
|
58
62
|
});
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
const request = new Request(
|
|
62
|
-
request.headers.set(
|
|
64
|
+
await test("NIP98.verify fails with missing token", async () => {
|
|
65
|
+
const request = new Request("https://example.com");
|
|
66
|
+
request.headers.set("authorization", "Nostr");
|
|
63
67
|
|
|
64
|
-
await
|
|
68
|
+
await rejects(
|
|
65
69
|
() => NIP98.verify(request),
|
|
66
70
|
Error,
|
|
67
|
-
|
|
71
|
+
"Missing Nostr authorization token",
|
|
68
72
|
);
|
|
69
73
|
});
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
const request = new Request(
|
|
73
|
-
request.headers.set(
|
|
75
|
+
await test("NIP98.verify fails with invalid token", async () => {
|
|
76
|
+
const request = new Request("https://example.com");
|
|
77
|
+
request.headers.set("authorization", "Nostr invalid");
|
|
74
78
|
|
|
75
|
-
await
|
|
79
|
+
await rejects(
|
|
76
80
|
() => NIP98.verify(request),
|
|
77
81
|
ZodError,
|
|
78
82
|
);
|
|
79
83
|
});
|
|
80
84
|
|
|
81
|
-
|
|
85
|
+
await test("NIP98.verify fails with invalid event", async () => {
|
|
82
86
|
const signer = new NSecSigner(generateSecretKey());
|
|
83
|
-
const request = new Request(
|
|
87
|
+
const request = new Request("https://example.com");
|
|
84
88
|
|
|
85
89
|
const t = await NIP98.template(request);
|
|
86
90
|
const event = await signer.signEvent(t);
|
|
87
91
|
|
|
88
|
-
event.sig =
|
|
92
|
+
event.sig = "invalid";
|
|
89
93
|
|
|
90
|
-
request.headers.set(
|
|
94
|
+
request.headers.set("authorization", `Nostr ${N64.encodeEvent(event)}`);
|
|
91
95
|
|
|
92
|
-
await
|
|
96
|
+
await rejects(
|
|
93
97
|
() => NIP98.verify(request),
|
|
94
98
|
Error,
|
|
95
|
-
|
|
99
|
+
"Event signature is invalid",
|
|
96
100
|
);
|
|
97
101
|
});
|
|
98
102
|
|
|
99
|
-
|
|
103
|
+
await test("NIP98.verify fails with wrong event kind", async () => {
|
|
100
104
|
const signer = new NSecSigner(generateSecretKey());
|
|
101
|
-
const request = new Request(
|
|
105
|
+
const request = new Request("https://example.com");
|
|
102
106
|
|
|
103
107
|
const t = await NIP98.template(request);
|
|
104
108
|
const event = await signer.signEvent({ ...t, kind: 1 });
|
|
105
109
|
|
|
106
|
-
request.headers.set(
|
|
110
|
+
request.headers.set("authorization", `Nostr ${N64.encodeEvent(event)}`);
|
|
107
111
|
|
|
108
|
-
await
|
|
112
|
+
await rejects(
|
|
109
113
|
() => NIP98.verify(request),
|
|
110
114
|
Error,
|
|
111
|
-
|
|
115
|
+
"Event must be kind 27235",
|
|
112
116
|
);
|
|
113
117
|
});
|
|
114
118
|
|
|
115
|
-
|
|
119
|
+
await test("NIP98.verify fails with wrong request URL", async () => {
|
|
116
120
|
const signer = new NSecSigner(generateSecretKey());
|
|
117
|
-
const request = new Request(
|
|
121
|
+
const request = new Request("https://example.com");
|
|
118
122
|
|
|
119
123
|
const t = await NIP98.template(request);
|
|
120
|
-
const event = await signer.signEvent({
|
|
124
|
+
const event = await signer.signEvent({
|
|
125
|
+
...t,
|
|
126
|
+
tags: [["u", "https://example.org/"]],
|
|
127
|
+
});
|
|
121
128
|
|
|
122
|
-
request.headers.set(
|
|
129
|
+
request.headers.set("authorization", `Nostr ${N64.encodeEvent(event)}`);
|
|
123
130
|
|
|
124
|
-
await
|
|
131
|
+
await rejects(
|
|
125
132
|
() => NIP98.verify(request),
|
|
126
133
|
Error,
|
|
127
|
-
|
|
134
|
+
"Event URL does not match request URL",
|
|
128
135
|
);
|
|
129
136
|
});
|
|
130
137
|
|
|
131
|
-
|
|
138
|
+
await test("NIP98.verify fails with wrong request method", async () => {
|
|
132
139
|
const signer = new NSecSigner(generateSecretKey());
|
|
133
|
-
const request = new Request(
|
|
140
|
+
const request = new Request("https://example.com");
|
|
134
141
|
|
|
135
142
|
const t = await NIP98.template(request);
|
|
136
|
-
const event = await signer.signEvent({
|
|
143
|
+
const event = await signer.signEvent({
|
|
144
|
+
...t,
|
|
145
|
+
tags: [["u", "https://example.com/"], ["method", "POST"]],
|
|
146
|
+
});
|
|
137
147
|
|
|
138
|
-
request.headers.set(
|
|
148
|
+
request.headers.set("authorization", `Nostr ${N64.encodeEvent(event)}`);
|
|
139
149
|
|
|
140
|
-
await
|
|
150
|
+
await rejects(
|
|
141
151
|
() => NIP98.verify(request),
|
|
142
152
|
Error,
|
|
143
|
-
|
|
153
|
+
"Event method does not match HTTP request method",
|
|
144
154
|
);
|
|
145
155
|
});
|
|
146
156
|
|
|
147
|
-
|
|
157
|
+
await test("NIP98.verify fails with expired event", async () => {
|
|
148
158
|
const signer = new NSecSigner(generateSecretKey());
|
|
149
|
-
const request = new Request(
|
|
159
|
+
const request = new Request("https://example.com");
|
|
150
160
|
|
|
151
161
|
const t = await NIP98.template(request);
|
|
152
162
|
const event = await signer.signEvent({ ...t, created_at: 0 });
|
|
153
163
|
|
|
154
|
-
request.headers.set(
|
|
164
|
+
request.headers.set("authorization", `Nostr ${N64.encodeEvent(event)}`);
|
|
155
165
|
|
|
156
|
-
await
|
|
166
|
+
await rejects(
|
|
157
167
|
() => NIP98.verify(request),
|
|
158
168
|
Error,
|
|
159
|
-
|
|
169
|
+
"Event expired",
|
|
160
170
|
);
|
|
161
171
|
});
|
|
162
172
|
|
|
163
|
-
|
|
173
|
+
await test("NIP98.verify fails with invalid payload", async () => {
|
|
164
174
|
const signer = new NSecSigner(generateSecretKey());
|
|
165
|
-
const request = new Request(
|
|
166
|
-
method:
|
|
167
|
-
body:
|
|
175
|
+
const request = new Request("https://example.com", {
|
|
176
|
+
method: "POST",
|
|
177
|
+
body: "Hello, world!",
|
|
168
178
|
});
|
|
169
179
|
|
|
170
180
|
const t = await NIP98.template(request);
|
|
171
|
-
const tags = t.tags.filter(([name]) => name !==
|
|
172
|
-
const event = await signer.signEvent({
|
|
181
|
+
const tags = t.tags.filter(([name]) => name !== "payload");
|
|
182
|
+
const event = await signer.signEvent({
|
|
183
|
+
...t,
|
|
184
|
+
tags: [...tags, ["payload", "invalid"]],
|
|
185
|
+
});
|
|
173
186
|
|
|
174
|
-
request.headers.set(
|
|
187
|
+
request.headers.set("authorization", `Nostr ${N64.encodeEvent(event)}`);
|
|
175
188
|
|
|
176
|
-
await
|
|
189
|
+
await rejects(
|
|
177
190
|
() => NIP98.verify(request),
|
|
178
191
|
Error,
|
|
179
|
-
|
|
192
|
+
"Event payload does not match request body",
|
|
180
193
|
);
|
|
181
194
|
});
|
package/NIP98.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { NostrEvent } from '@nostrify/types';
|
|
1
|
+
import type { NostrEvent } from '@nostrify/types';
|
|
2
2
|
import { encodeHex } from '@std/encoding/hex';
|
|
3
3
|
import { verifyEvent as _verifyEvent } from 'nostr-tools';
|
|
4
4
|
|
|
5
|
-
import { N64 } from './utils/N64.
|
|
5
|
+
import { N64 } from './utils/N64.ts';
|
|
6
6
|
|
|
7
7
|
/** [NIP-98](https://github.com/nostr-protocol/nips/blob/master/98.md) HTTP auth. */
|
|
8
8
|
export class NIP98 {
|
package/NKinds.test.ts
CHANGED
|
@@ -1,42 +1,43 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import { deepStrictEqual } from "node:assert";
|
|
2
3
|
|
|
3
|
-
import { NKinds } from
|
|
4
|
+
import { NKinds } from "./NKinds.ts";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
await test("NKinds", () => {
|
|
7
|
+
deepStrictEqual(NKinds.regular(1000), true);
|
|
8
|
+
deepStrictEqual(NKinds.regular(10000), false);
|
|
9
|
+
deepStrictEqual(NKinds.regular(0), false);
|
|
10
|
+
deepStrictEqual(NKinds.regular(44), true);
|
|
11
|
+
deepStrictEqual(NKinds.regular(45), false);
|
|
12
|
+
deepStrictEqual(NKinds.regular(100000), false);
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
deepStrictEqual(NKinds.replaceable(1000), false);
|
|
15
|
+
deepStrictEqual(NKinds.replaceable(10000), true);
|
|
16
|
+
deepStrictEqual(NKinds.replaceable(0), true);
|
|
17
|
+
deepStrictEqual(NKinds.replaceable(3), true);
|
|
18
|
+
deepStrictEqual(NKinds.replaceable(44), false);
|
|
19
|
+
deepStrictEqual(NKinds.replaceable(45), false);
|
|
20
|
+
deepStrictEqual(NKinds.replaceable(100000), false);
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
deepStrictEqual(NKinds.ephemeral(1000), false);
|
|
23
|
+
deepStrictEqual(NKinds.ephemeral(10000), false);
|
|
24
|
+
deepStrictEqual(NKinds.ephemeral(0), false);
|
|
25
|
+
deepStrictEqual(NKinds.ephemeral(3), false);
|
|
26
|
+
deepStrictEqual(NKinds.ephemeral(44), false);
|
|
27
|
+
deepStrictEqual(NKinds.ephemeral(45), false);
|
|
28
|
+
deepStrictEqual(NKinds.ephemeral(20000), true);
|
|
29
|
+
deepStrictEqual(NKinds.ephemeral(30000), false);
|
|
30
|
+
deepStrictEqual(NKinds.ephemeral(40000), false);
|
|
31
|
+
deepStrictEqual(NKinds.ephemeral(100000), false);
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
deepStrictEqual(NKinds.addressable(1000), false);
|
|
34
|
+
deepStrictEqual(NKinds.addressable(10000), false);
|
|
35
|
+
deepStrictEqual(NKinds.addressable(0), false);
|
|
36
|
+
deepStrictEqual(NKinds.addressable(3), false);
|
|
37
|
+
deepStrictEqual(NKinds.addressable(44), false);
|
|
38
|
+
deepStrictEqual(NKinds.addressable(45), false);
|
|
39
|
+
deepStrictEqual(NKinds.addressable(20000), false);
|
|
40
|
+
deepStrictEqual(NKinds.addressable(30000), true);
|
|
41
|
+
deepStrictEqual(NKinds.addressable(40000), false);
|
|
42
|
+
deepStrictEqual(NKinds.addressable(100000), false);
|
|
42
43
|
});
|
package/NPool.test.ts
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import type { NostrEvent } from "@nostrify/types";
|
|
3
|
+
import { deepStrictEqual, ok } from "node:assert";
|
|
4
|
+
import { finalizeEvent, generateSecretKey } from "nostr-tools";
|
|
4
5
|
|
|
5
|
-
import { NPool } from
|
|
6
|
-
import { NRelay1 } from
|
|
6
|
+
import { NPool } from "./NPool.ts";
|
|
7
|
+
import { NRelay1 } from "./NRelay1.ts";
|
|
7
8
|
|
|
8
|
-
import events from
|
|
9
|
-
import { TestRelayServer } from
|
|
9
|
+
import events from "../../fixtures/events.json" with { type: "json" };
|
|
10
|
+
import { TestRelayServer } from "./test/TestRelayServer.ts";
|
|
10
11
|
|
|
11
12
|
const event1s = events
|
|
12
13
|
.filter((e) => e.kind === 1)
|
|
13
14
|
.toSorted((_) => 0.5 - Math.random())
|
|
14
15
|
.slice(0, 10);
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
await test("NPool.query", async () => {
|
|
17
18
|
const controller = new AbortController();
|
|
18
19
|
const tid = setTimeout(() => controller.abort(), 5000);
|
|
19
20
|
|
|
20
|
-
await using server1 =
|
|
21
|
-
await using server2 =
|
|
21
|
+
await using server1 = await TestRelayServer.create();
|
|
22
|
+
await using server2 = await TestRelayServer.create();
|
|
22
23
|
|
|
23
24
|
for (const event of event1s) {
|
|
24
25
|
await server1.event(event);
|
|
@@ -37,18 +38,18 @@ Deno.test('NPool.query', async () => {
|
|
|
37
38
|
|
|
38
39
|
const events = await pool.query([{ kinds: [1], limit: 15 }]);
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
deepStrictEqual(events.length, 10);
|
|
42
|
+
ok(events[0].created_at >= events[1].created_at);
|
|
42
43
|
|
|
43
44
|
clearTimeout(tid);
|
|
44
45
|
});
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
await test("NPool.req", async () => {
|
|
47
48
|
const controller = new AbortController();
|
|
48
49
|
const tid = setTimeout(() => controller.abort(), 3000);
|
|
49
50
|
|
|
50
|
-
await using server1 =
|
|
51
|
-
await using server2 =
|
|
51
|
+
await using server1 = await TestRelayServer.create();
|
|
52
|
+
await using server2 = await TestRelayServer.create();
|
|
52
53
|
|
|
53
54
|
for (const event of event1s) {
|
|
54
55
|
await server1.event(event);
|
|
@@ -67,25 +68,29 @@ Deno.test('NPool.req', async () => {
|
|
|
67
68
|
eventRouter: () => [server1.url],
|
|
68
69
|
});
|
|
69
70
|
|
|
70
|
-
for await (
|
|
71
|
-
|
|
71
|
+
for await (
|
|
72
|
+
const msg of pool.req([{ kinds: [1], limit: 3 }], {
|
|
73
|
+
signal: controller.signal,
|
|
74
|
+
})
|
|
75
|
+
) {
|
|
76
|
+
if (msg[0] === "EVENT") {
|
|
72
77
|
events.push(msg[2]);
|
|
73
78
|
}
|
|
74
79
|
|
|
75
80
|
if (events.length === 3) break;
|
|
76
81
|
}
|
|
77
82
|
|
|
78
|
-
|
|
83
|
+
deepStrictEqual(events.length, 3);
|
|
79
84
|
|
|
80
85
|
clearTimeout(tid);
|
|
81
86
|
});
|
|
82
87
|
|
|
83
|
-
|
|
88
|
+
await test("NPool.event", async () => {
|
|
84
89
|
const controller = new AbortController();
|
|
85
90
|
const tid = setTimeout(() => controller.abort(), 5000);
|
|
86
91
|
|
|
87
|
-
await using server1 =
|
|
88
|
-
await using server2 =
|
|
92
|
+
await using server1 = await TestRelayServer.create();
|
|
93
|
+
await using server2 = await TestRelayServer.create();
|
|
89
94
|
|
|
90
95
|
for (const event of event1s) {
|
|
91
96
|
await server1.event(event);
|
|
@@ -94,8 +99,9 @@ Deno.test('NPool.event', async () => {
|
|
|
94
99
|
|
|
95
100
|
const event: NostrEvent = finalizeEvent({
|
|
96
101
|
kind: 1,
|
|
97
|
-
content:
|
|
98
|
-
|
|
102
|
+
content:
|
|
103
|
+
"This is an automated test from Nostrify: https://gitlab.com/soapbox-pub/nostrify",
|
|
104
|
+
tags: [["unique", "uniqueTag"]],
|
|
99
105
|
created_at: Math.floor(Date.now() / 1000),
|
|
100
106
|
}, generateSecretKey());
|
|
101
107
|
|
|
@@ -111,7 +117,12 @@ Deno.test('NPool.event', async () => {
|
|
|
111
117
|
|
|
112
118
|
await pool.event(event, { signal: controller.signal });
|
|
113
119
|
|
|
114
|
-
|
|
120
|
+
deepStrictEqual(
|
|
121
|
+
(await pool.query([{ kinds: [1], "#unique": ["uniqueTag"] }], {
|
|
122
|
+
signal: controller.signal,
|
|
123
|
+
})).length,
|
|
124
|
+
1,
|
|
125
|
+
);
|
|
115
126
|
|
|
116
127
|
clearTimeout(tid);
|
|
117
128
|
});
|
package/NPool.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type {
|
|
2
|
+
NostrEvent,
|
|
3
|
+
NostrFilter,
|
|
4
|
+
NostrRelayCLOSED,
|
|
5
|
+
NostrRelayEOSE,
|
|
6
|
+
NostrRelayEVENT,
|
|
7
|
+
NRelay,
|
|
8
|
+
} from '@nostrify/types';
|
|
2
9
|
import { getFilterLimit } from 'nostr-tools';
|
|
3
10
|
|
|
4
|
-
import { CircularSet } from './utils/CircularSet.
|
|
5
|
-
import { Machina } from './utils/Machina.
|
|
6
|
-
import { NSet } from './NSet.
|
|
11
|
+
import { CircularSet } from './utils/CircularSet.ts';
|
|
12
|
+
import { Machina } from './utils/Machina.ts';
|
|
13
|
+
import { NSet } from './NSet.ts';
|
|
7
14
|
|
|
8
15
|
export interface NPoolOpts<T extends NRelay> {
|
|
9
16
|
/** Creates an `NRelay` instance for the given URL. */
|
|
@@ -49,8 +56,11 @@ export interface NPoolOpts<T extends NRelay> {
|
|
|
49
56
|
*/
|
|
50
57
|
export class NPool<T extends NRelay = NRelay> implements NRelay {
|
|
51
58
|
private _relays = new Map<string, T>();
|
|
59
|
+
private opts: NPoolOpts<T>;
|
|
52
60
|
|
|
53
|
-
constructor(
|
|
61
|
+
constructor(opts: NPoolOpts<T>) {
|
|
62
|
+
this.opts = opts;
|
|
63
|
+
}
|
|
54
64
|
|
|
55
65
|
/** Get or create a relay instance for the given URL. */
|
|
56
66
|
public relay(url: string): T {
|
|
@@ -111,31 +121,38 @@ export class NPool<T extends NRelay = NRelay> implements NRelay {
|
|
|
111
121
|
const closes = new Set<string>();
|
|
112
122
|
const events = new CircularSet<string>(1000);
|
|
113
123
|
|
|
124
|
+
const relayPromises: Promise<void>[] = [];
|
|
125
|
+
|
|
114
126
|
for (const [url, filters] of routes.entries()) {
|
|
115
127
|
const relay = this.relay(url);
|
|
116
|
-
(async () => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
128
|
+
const relayPromise = (async () => {
|
|
129
|
+
try {
|
|
130
|
+
for await (const msg of relay.req(filters, { signal })) {
|
|
131
|
+
if (msg[0] === 'EOSE') {
|
|
132
|
+
eoses.add(url);
|
|
133
|
+
if (eoses.size === routes.size) {
|
|
134
|
+
machina.push(msg);
|
|
135
|
+
}
|
|
122
136
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
137
|
+
if (msg[0] === 'CLOSED') {
|
|
138
|
+
closes.add(url);
|
|
139
|
+
if (closes.size === routes.size) {
|
|
140
|
+
machina.push(msg);
|
|
141
|
+
}
|
|
128
142
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
143
|
+
if (msg[0] === 'EVENT') {
|
|
144
|
+
const [, , event] = msg;
|
|
145
|
+
if (!events.has(event.id)) {
|
|
146
|
+
events.add(event.id);
|
|
147
|
+
machina.push(msg);
|
|
148
|
+
}
|
|
135
149
|
}
|
|
136
150
|
}
|
|
151
|
+
} catch {
|
|
152
|
+
// Handle errors silently
|
|
137
153
|
}
|
|
138
|
-
})()
|
|
154
|
+
})();
|
|
155
|
+
relayPromises.push(relayPromise);
|
|
139
156
|
}
|
|
140
157
|
|
|
141
158
|
try {
|
|
@@ -144,6 +161,8 @@ export class NPool<T extends NRelay = NRelay> implements NRelay {
|
|
|
144
161
|
}
|
|
145
162
|
} finally {
|
|
146
163
|
controller.abort();
|
|
164
|
+
// Wait for all relay promises to complete to prevent hanging promises
|
|
165
|
+
await Promise.allSettled(relayPromises);
|
|
147
166
|
}
|
|
148
167
|
}
|
|
149
168
|
|