@openclaw/nostr 2026.5.2 → 2026.5.3-beta.1

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.
Files changed (59) hide show
  1. package/dist/api.js +532 -0
  2. package/dist/channel-DfEqBtUh.js +1466 -0
  3. package/dist/channel-plugin-api.js +2 -0
  4. package/dist/config-schema-DIk4jlBg.js +64 -0
  5. package/dist/default-relays-DLwdWOTu.js +4 -0
  6. package/dist/inbound-direct-dm-runtime-22bZWcIW.js +2 -0
  7. package/dist/index.js +84 -0
  8. package/dist/runtime-api.js +2 -0
  9. package/dist/setup-api.js +2 -0
  10. package/dist/setup-entry.js +11 -0
  11. package/dist/setup-plugin-api.js +165 -0
  12. package/dist/setup-surface-DxAaUTyC.js +336 -0
  13. package/dist/test-api.js +2 -0
  14. package/package.json +15 -6
  15. package/api.ts +0 -10
  16. package/channel-plugin-api.ts +0 -1
  17. package/index.ts +0 -97
  18. package/runtime-api.ts +0 -6
  19. package/setup-api.ts +0 -1
  20. package/setup-entry.ts +0 -9
  21. package/setup-plugin-api.ts +0 -3
  22. package/src/channel-api.ts +0 -15
  23. package/src/channel.inbound.test.ts +0 -176
  24. package/src/channel.outbound.test.ts +0 -128
  25. package/src/channel.setup.ts +0 -231
  26. package/src/channel.test.ts +0 -519
  27. package/src/channel.ts +0 -207
  28. package/src/config-schema.ts +0 -98
  29. package/src/default-relays.ts +0 -1
  30. package/src/gateway.ts +0 -302
  31. package/src/inbound-direct-dm-runtime.ts +0 -1
  32. package/src/metrics.ts +0 -458
  33. package/src/nostr-bus.fuzz.test.ts +0 -360
  34. package/src/nostr-bus.inbound.test.ts +0 -526
  35. package/src/nostr-bus.integration.test.ts +0 -472
  36. package/src/nostr-bus.test.ts +0 -190
  37. package/src/nostr-bus.ts +0 -789
  38. package/src/nostr-key-utils.ts +0 -94
  39. package/src/nostr-profile-core.ts +0 -134
  40. package/src/nostr-profile-http-runtime.ts +0 -6
  41. package/src/nostr-profile-http.test.ts +0 -632
  42. package/src/nostr-profile-http.ts +0 -594
  43. package/src/nostr-profile-import.test.ts +0 -119
  44. package/src/nostr-profile-import.ts +0 -262
  45. package/src/nostr-profile-url-safety.ts +0 -21
  46. package/src/nostr-profile.fuzz.test.ts +0 -430
  47. package/src/nostr-profile.test.ts +0 -412
  48. package/src/nostr-profile.ts +0 -144
  49. package/src/nostr-state-store.test.ts +0 -237
  50. package/src/nostr-state-store.ts +0 -223
  51. package/src/runtime.ts +0 -9
  52. package/src/seen-tracker.ts +0 -289
  53. package/src/session-route.ts +0 -25
  54. package/src/setup-surface.ts +0 -265
  55. package/src/test-fixtures.ts +0 -45
  56. package/src/types.ts +0 -117
  57. package/test/setup.ts +0 -5
  58. package/test-api.ts +0 -1
  59. package/tsconfig.json +0 -16
@@ -1,360 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { createMetrics, type MetricName } from "./metrics.js";
3
- import { validatePrivateKey, isValidPubkey, normalizePubkey } from "./nostr-key-utils.js";
4
- import { createSeenTracker } from "./seen-tracker.js";
5
- import { TEST_HEX_PRIVATE_KEY } from "./test-fixtures.js";
6
-
7
- function createTracker(maxEntries = 100) {
8
- return createSeenTracker({ maxEntries });
9
- }
10
-
11
- function createPlainMetrics() {
12
- return createMetrics();
13
- }
14
-
15
- function createCollectingMetrics() {
16
- const events: unknown[] = [];
17
- return {
18
- events,
19
- metrics: createMetrics((event) => events.push(event)),
20
- };
21
- }
22
-
23
- // ============================================================================
24
- // Fuzz Tests for validatePrivateKey
25
- // ============================================================================
26
-
27
- describe("validatePrivateKey fuzz", () => {
28
- describe("type confusion", () => {
29
- it("rejects non-string input", () => {
30
- for (const value of [null, undefined, 123, true, {}, [], () => {}]) {
31
- expect(() => validatePrivateKey(value as unknown as string)).toThrow();
32
- }
33
- });
34
- });
35
-
36
- describe("unicode attacks", () => {
37
- it("rejects unicode and control-character attacks", () => {
38
- const invalidKeys = [
39
- "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde\u200Bf",
40
- `\u202E${TEST_HEX_PRIVATE_KEY}`,
41
- "0123456789\u0430bcdef0123456789abcdef0123456789abcdef0123456789abcdef",
42
- "0123456789abcdef0123456789abcdef0123456789abcdef0123456789ab😀",
43
- "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde\u0301",
44
- "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde\x00f",
45
- "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde\nf",
46
- "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde\rf",
47
- "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde\tf",
48
- "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde\ff",
49
- ];
50
-
51
- for (const key of invalidKeys) {
52
- expect(() => validatePrivateKey(key)).toThrow();
53
- }
54
- });
55
- });
56
-
57
- describe("edge cases", () => {
58
- it("rejects very long string", () => {
59
- const veryLong = "a".repeat(10000);
60
- expect(() => validatePrivateKey(veryLong)).toThrow();
61
- });
62
-
63
- it("rejects string of spaces matching length", () => {
64
- const spaces = " ".repeat(64);
65
- expect(() => validatePrivateKey(spaces)).toThrow();
66
- });
67
-
68
- it("rejects hex with spaces between characters", () => {
69
- const withSpaces =
70
- "01 23 45 67 89 ab cd ef 01 23 45 67 89 ab cd ef 01 23 45 67 89 ab cd ef 01 23 45 67 89 ab cd ef";
71
- expect(() => validatePrivateKey(withSpaces)).toThrow();
72
- });
73
- });
74
-
75
- describe("nsec format edge cases", () => {
76
- it("rejects nsec with invalid bech32 characters", () => {
77
- // 'b', 'i', 'o' are not valid bech32 characters
78
- const invalidBech32 = "nsec1qypqxpq9qtpqscx7peytbfwtdjmcv0mrz5rjpej8vjppfkqfqy8skqfv3l";
79
- expect(() => validatePrivateKey(invalidBech32)).toThrow();
80
- });
81
-
82
- it("rejects nsec with wrong prefix", () => {
83
- expect(() => validatePrivateKey("nsec0aaaa")).toThrow();
84
- });
85
-
86
- it("rejects partial nsec", () => {
87
- expect(() => validatePrivateKey("nsec1")).toThrow();
88
- });
89
- });
90
- });
91
-
92
- // ============================================================================
93
- // Fuzz Tests for isValidPubkey
94
- // ============================================================================
95
-
96
- describe("isValidPubkey fuzz", () => {
97
- describe("type confusion", () => {
98
- it("handles non-string input gracefully", () => {
99
- for (const value of [null, undefined, 123, {}]) {
100
- expect(isValidPubkey(value as unknown as string)).toBe(false);
101
- }
102
- });
103
- });
104
-
105
- describe("malicious inputs", () => {
106
- it("rejects prototype property names", () => {
107
- for (const value of ["__proto__", "constructor", "toString"]) {
108
- expect(isValidPubkey(value)).toBe(false);
109
- }
110
- });
111
- });
112
- });
113
-
114
- // ============================================================================
115
- // Fuzz Tests for normalizePubkey
116
- // ============================================================================
117
-
118
- describe("normalizePubkey fuzz", () => {
119
- describe("prototype pollution attempts", () => {
120
- it("throws for prototype property names", () => {
121
- for (const value of ["__proto__", "constructor", "prototype"]) {
122
- expect(() => normalizePubkey(value)).toThrow();
123
- }
124
- });
125
- });
126
-
127
- describe("case sensitivity", () => {
128
- it("normalizes uppercase to lowercase", () => {
129
- const upper = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF";
130
- expect(normalizePubkey(upper)).toBe(TEST_HEX_PRIVATE_KEY);
131
- });
132
-
133
- it("normalizes mixed case to lowercase", () => {
134
- const mixed = "0123456789AbCdEf0123456789AbCdEf0123456789AbCdEf0123456789AbCdEf";
135
- expect(normalizePubkey(mixed)).toBe(TEST_HEX_PRIVATE_KEY);
136
- });
137
- });
138
- });
139
-
140
- // ============================================================================
141
- // Fuzz Tests for SeenTracker
142
- // ============================================================================
143
-
144
- describe("SeenTracker fuzz", () => {
145
- describe("malformed IDs", () => {
146
- it("handles empty string IDs", () => {
147
- const tracker = createTracker();
148
- expect(() => tracker.add("")).not.toThrow();
149
- expect(tracker.peek("")).toBe(true);
150
- tracker.stop();
151
- });
152
-
153
- it("handles very long IDs", () => {
154
- const tracker = createTracker();
155
- const longId = "a".repeat(100000);
156
- expect(() => tracker.add(longId)).not.toThrow();
157
- expect(tracker.peek(longId)).toBe(true);
158
- tracker.stop();
159
- });
160
-
161
- it("handles unicode IDs", () => {
162
- const tracker = createTracker();
163
- const unicodeId = "事件ID_🎉_тест";
164
- expect(() => tracker.add(unicodeId)).not.toThrow();
165
- expect(tracker.peek(unicodeId)).toBe(true);
166
- tracker.stop();
167
- });
168
-
169
- it("handles IDs with null bytes", () => {
170
- const tracker = createTracker();
171
- const idWithNull = "event\x00id";
172
- expect(() => tracker.add(idWithNull)).not.toThrow();
173
- expect(tracker.peek(idWithNull)).toBe(true);
174
- tracker.stop();
175
- });
176
-
177
- it("handles prototype property names as IDs", () => {
178
- const tracker = createTracker();
179
-
180
- // These should not affect the tracker's internal operation
181
- expect(() => tracker.add("__proto__")).not.toThrow();
182
- expect(() => tracker.add("constructor")).not.toThrow();
183
- expect(() => tracker.add("toString")).not.toThrow();
184
- expect(() => tracker.add("hasOwnProperty")).not.toThrow();
185
-
186
- expect(tracker.peek("__proto__")).toBe(true);
187
- expect(tracker.peek("constructor")).toBe(true);
188
- expect(tracker.peek("toString")).toBe(true);
189
- expect(tracker.peek("hasOwnProperty")).toBe(true);
190
-
191
- tracker.stop();
192
- });
193
- });
194
-
195
- describe("rapid operations", () => {
196
- it("handles rapid add/check cycles", () => {
197
- const tracker = createTracker(1000);
198
-
199
- for (let i = 0; i < 10000; i++) {
200
- const id = `event-${i}`;
201
- tracker.add(id);
202
- // Recently added should be findable
203
- if (i < 1000) {
204
- tracker.peek(id);
205
- }
206
- }
207
-
208
- // Size should be capped at maxEntries
209
- expect(tracker.size()).toBeLessThanOrEqual(1000);
210
- tracker.stop();
211
- });
212
-
213
- it("handles concurrent-style operations", () => {
214
- const tracker = createTracker();
215
-
216
- // Simulate interleaved operations
217
- for (let i = 0; i < 100; i++) {
218
- tracker.add(`add-${i}`);
219
- tracker.peek(`peek-${i}`);
220
- tracker.has(`has-${i}`);
221
- if (i % 10 === 0) {
222
- tracker.delete(`add-${i - 5}`);
223
- }
224
- }
225
-
226
- expect(() => tracker.size()).not.toThrow();
227
- tracker.stop();
228
- });
229
- });
230
-
231
- describe("seed edge cases", () => {
232
- it("handles empty seed array", () => {
233
- const tracker = createTracker();
234
- expect(() => tracker.seed([])).not.toThrow();
235
- expect(tracker.size()).toBe(0);
236
- tracker.stop();
237
- });
238
-
239
- it("handles seed with duplicate IDs", () => {
240
- const tracker = createTracker();
241
- tracker.seed(["id1", "id1", "id1", "id2", "id2"]);
242
- expect(tracker.size()).toBe(2);
243
- tracker.stop();
244
- });
245
-
246
- it("handles seed larger than maxEntries", () => {
247
- const tracker = createTracker(5);
248
- const ids = Array.from({ length: 100 }, (_, i) => `id-${i}`);
249
- tracker.seed(ids);
250
- expect(tracker.size()).toBeLessThanOrEqual(5);
251
- tracker.stop();
252
- });
253
- });
254
- });
255
-
256
- // ============================================================================
257
- // Fuzz Tests for Metrics
258
- // ============================================================================
259
-
260
- describe("Metrics fuzz", () => {
261
- describe("invalid metric names", () => {
262
- it("handles unknown metric names gracefully", () => {
263
- const metrics = createPlainMetrics();
264
-
265
- // Cast to bypass type checking - testing runtime behavior
266
- expect(() => {
267
- metrics.emit("invalid.metric.name" as MetricName);
268
- }).not.toThrow();
269
- });
270
- });
271
-
272
- describe("invalid label values", () => {
273
- it("handles null relay label", () => {
274
- const metrics = createPlainMetrics();
275
- expect(() => {
276
- metrics.emit("relay.connect", 1, { relay: null as unknown as string });
277
- }).not.toThrow();
278
- });
279
-
280
- it("handles undefined relay label", () => {
281
- const metrics = createPlainMetrics();
282
- expect(() => {
283
- metrics.emit("relay.connect", 1, { relay: undefined as unknown as string });
284
- }).not.toThrow();
285
- });
286
-
287
- it("handles very long relay URL", () => {
288
- const metrics = createPlainMetrics();
289
- const longUrl = "wss://" + "a".repeat(10000) + ".com";
290
- expect(() => {
291
- metrics.emit("relay.connect", 1, { relay: longUrl });
292
- }).not.toThrow();
293
-
294
- const snapshot = metrics.getSnapshot();
295
- expect(snapshot.relays[longUrl]).toBeDefined();
296
- });
297
- });
298
-
299
- describe("extreme values", () => {
300
- it("handles NaN value", () => {
301
- const metrics = createPlainMetrics();
302
- expect(() => metrics.emit("event.received", Number.NaN)).not.toThrow();
303
-
304
- const snapshot = metrics.getSnapshot();
305
- expect(Number.isNaN(snapshot.eventsReceived)).toBe(true);
306
- });
307
-
308
- it("handles Infinity value", () => {
309
- const metrics = createPlainMetrics();
310
- expect(() => metrics.emit("event.received", Infinity)).not.toThrow();
311
-
312
- const snapshot = metrics.getSnapshot();
313
- expect(snapshot.eventsReceived).toBe(Infinity);
314
- });
315
-
316
- it("handles negative value", () => {
317
- const metrics = createPlainMetrics();
318
- metrics.emit("event.received", -1);
319
-
320
- const snapshot = metrics.getSnapshot();
321
- expect(snapshot.eventsReceived).toBe(-1);
322
- });
323
-
324
- it("handles very large value", () => {
325
- const metrics = createPlainMetrics();
326
- metrics.emit("event.received", Number.MAX_SAFE_INTEGER);
327
-
328
- const snapshot = metrics.getSnapshot();
329
- expect(snapshot.eventsReceived).toBe(Number.MAX_SAFE_INTEGER);
330
- });
331
- });
332
-
333
- describe("rapid emissions", () => {
334
- it("handles many rapid emissions", () => {
335
- const { events, metrics } = createCollectingMetrics();
336
-
337
- for (let i = 0; i < 10000; i++) {
338
- metrics.emit("event.received");
339
- }
340
-
341
- expect(events).toHaveLength(10000);
342
- const snapshot = metrics.getSnapshot();
343
- expect(snapshot.eventsReceived).toBe(10000);
344
- });
345
- });
346
-
347
- describe("reset during operation", () => {
348
- it("handles reset mid-operation safely", () => {
349
- const metrics = createPlainMetrics();
350
-
351
- metrics.emit("event.received");
352
- metrics.emit("event.received");
353
- metrics.reset();
354
- metrics.emit("event.received");
355
-
356
- const snapshot = metrics.getSnapshot();
357
- expect(snapshot.eventsReceived).toBe(1);
358
- });
359
- });
360
- });