@openclaw/nostr 2026.3.11 → 2026.3.13
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/CHANGELOG.md +13 -0
- package/package.json +1 -1
- package/src/channel.ts +9 -10
- package/src/nostr-profile-http.test.ts +37 -28
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026.3.13
|
|
4
|
+
|
|
5
|
+
### Changes
|
|
6
|
+
|
|
7
|
+
- Version alignment with core OpenClaw release numbers.
|
|
8
|
+
|
|
9
|
+
## 2026.3.12
|
|
10
|
+
|
|
11
|
+
### Changes
|
|
12
|
+
|
|
13
|
+
- Version alignment with core OpenClaw release numbers.
|
|
14
|
+
|
|
3
15
|
## 2026.3.11
|
|
4
16
|
|
|
5
17
|
### Changes
|
|
18
|
+
|
|
6
19
|
- Version alignment with core OpenClaw release numbers.
|
|
7
20
|
|
|
8
21
|
## 2026.3.10
|
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -7,6 +7,10 @@ import {
|
|
|
7
7
|
mapAllowFromEntries,
|
|
8
8
|
type ChannelPlugin,
|
|
9
9
|
} from "openclaw/plugin-sdk/nostr";
|
|
10
|
+
import {
|
|
11
|
+
buildPassiveChannelStatusSummary,
|
|
12
|
+
buildTrafficStatusSummary,
|
|
13
|
+
} from "../../shared/channel-status-summary.js";
|
|
10
14
|
import type { NostrProfile } from "./config-schema.js";
|
|
11
15
|
import { NostrConfigSchema } from "./config-schema.js";
|
|
12
16
|
import type { MetricEvent, MetricsSnapshot } from "./metrics.js";
|
|
@@ -160,14 +164,10 @@ export const nostrPlugin: ChannelPlugin<ResolvedNostrAccount> = {
|
|
|
160
164
|
status: {
|
|
161
165
|
defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID),
|
|
162
166
|
collectStatusIssues: (accounts) => collectStatusIssuesFromLastError("nostr", accounts),
|
|
163
|
-
buildChannelSummary: ({ snapshot }) =>
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
lastStartAt: snapshot.lastStartAt ?? null,
|
|
168
|
-
lastStopAt: snapshot.lastStopAt ?? null,
|
|
169
|
-
lastError: snapshot.lastError ?? null,
|
|
170
|
-
}),
|
|
167
|
+
buildChannelSummary: ({ snapshot }) =>
|
|
168
|
+
buildPassiveChannelStatusSummary(snapshot, {
|
|
169
|
+
publicKey: snapshot.publicKey ?? null,
|
|
170
|
+
}),
|
|
171
171
|
buildAccountSnapshot: ({ account, runtime }) => ({
|
|
172
172
|
accountId: account.accountId,
|
|
173
173
|
name: account.name,
|
|
@@ -179,8 +179,7 @@ export const nostrPlugin: ChannelPlugin<ResolvedNostrAccount> = {
|
|
|
179
179
|
lastStartAt: runtime?.lastStartAt ?? null,
|
|
180
180
|
lastStopAt: runtime?.lastStopAt ?? null,
|
|
181
181
|
lastError: runtime?.lastError ?? null,
|
|
182
|
-
|
|
183
|
-
lastOutboundAt: runtime?.lastOutboundAt ?? null,
|
|
182
|
+
...buildTrafficStatusSummary(runtime),
|
|
184
183
|
}),
|
|
185
184
|
},
|
|
186
185
|
|
|
@@ -115,6 +115,13 @@ function createMockContext(overrides?: Partial<NostrProfileHttpContext>): NostrP
|
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
function expectOkResponse(res: ReturnType<typeof createMockResponse>) {
|
|
119
|
+
expect(res._getStatusCode()).toBe(200);
|
|
120
|
+
const data = JSON.parse(res._getData());
|
|
121
|
+
expect(data.ok).toBe(true);
|
|
122
|
+
return data;
|
|
123
|
+
}
|
|
124
|
+
|
|
118
125
|
function mockSuccessfulProfileImport() {
|
|
119
126
|
vi.mocked(importProfileFromRelays).mockResolvedValue({
|
|
120
127
|
ok: true,
|
|
@@ -208,6 +215,22 @@ describe("nostr-profile-http", () => {
|
|
|
208
215
|
});
|
|
209
216
|
|
|
210
217
|
describe("PUT /api/channels/nostr/:accountId/profile", () => {
|
|
218
|
+
function mockPublishSuccess() {
|
|
219
|
+
vi.mocked(publishNostrProfile).mockResolvedValue({
|
|
220
|
+
eventId: "event123",
|
|
221
|
+
createdAt: 1234567890,
|
|
222
|
+
successes: ["wss://relay.damus.io"],
|
|
223
|
+
failures: [],
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function expectBadRequestResponse(res: ReturnType<typeof createMockResponse>) {
|
|
228
|
+
expect(res._getStatusCode()).toBe(400);
|
|
229
|
+
const data = JSON.parse(res._getData());
|
|
230
|
+
expect(data.ok).toBe(false);
|
|
231
|
+
return data;
|
|
232
|
+
}
|
|
233
|
+
|
|
211
234
|
async function expectPrivatePictureRejected(pictureUrl: string) {
|
|
212
235
|
const ctx = createMockContext();
|
|
213
236
|
const handler = createNostrProfileHttpHandler(ctx);
|
|
@@ -219,9 +242,7 @@ describe("nostr-profile-http", () => {
|
|
|
219
242
|
|
|
220
243
|
await handler(req, res);
|
|
221
244
|
|
|
222
|
-
|
|
223
|
-
const data = JSON.parse(res._getData());
|
|
224
|
-
expect(data.ok).toBe(false);
|
|
245
|
+
const data = expectBadRequestResponse(res);
|
|
225
246
|
expect(data.error).toContain("private");
|
|
226
247
|
}
|
|
227
248
|
|
|
@@ -235,18 +256,11 @@ describe("nostr-profile-http", () => {
|
|
|
235
256
|
});
|
|
236
257
|
const res = createMockResponse();
|
|
237
258
|
|
|
238
|
-
|
|
239
|
-
eventId: "event123",
|
|
240
|
-
createdAt: 1234567890,
|
|
241
|
-
successes: ["wss://relay.damus.io"],
|
|
242
|
-
failures: [],
|
|
243
|
-
});
|
|
259
|
+
mockPublishSuccess();
|
|
244
260
|
|
|
245
261
|
await handler(req, res);
|
|
246
262
|
|
|
247
|
-
|
|
248
|
-
const data = JSON.parse(res._getData());
|
|
249
|
-
expect(data.ok).toBe(true);
|
|
263
|
+
const data = expectOkResponse(res);
|
|
250
264
|
expect(data.eventId).toBe("event123");
|
|
251
265
|
expect(data.successes).toContain("wss://relay.damus.io");
|
|
252
266
|
expect(data.persisted).toBe(true);
|
|
@@ -332,9 +346,7 @@ describe("nostr-profile-http", () => {
|
|
|
332
346
|
|
|
333
347
|
await handler(req, res);
|
|
334
348
|
|
|
335
|
-
|
|
336
|
-
const data = JSON.parse(res._getData());
|
|
337
|
-
expect(data.ok).toBe(false);
|
|
349
|
+
const data = expectBadRequestResponse(res);
|
|
338
350
|
// The schema validation catches non-https URLs before SSRF check
|
|
339
351
|
expect(data.error).toBe("Validation failed");
|
|
340
352
|
expect(data.details).toBeDefined();
|
|
@@ -368,12 +380,7 @@ describe("nostr-profile-http", () => {
|
|
|
368
380
|
const ctx = createMockContext();
|
|
369
381
|
const handler = createNostrProfileHttpHandler(ctx);
|
|
370
382
|
|
|
371
|
-
|
|
372
|
-
eventId: "event123",
|
|
373
|
-
createdAt: 1234567890,
|
|
374
|
-
successes: ["wss://relay.damus.io"],
|
|
375
|
-
failures: [],
|
|
376
|
-
});
|
|
383
|
+
mockPublishSuccess();
|
|
377
384
|
|
|
378
385
|
// Make 6 requests (limit is 5/min)
|
|
379
386
|
for (let i = 0; i < 6; i++) {
|
|
@@ -384,7 +391,7 @@ describe("nostr-profile-http", () => {
|
|
|
384
391
|
await handler(req, res);
|
|
385
392
|
|
|
386
393
|
if (i < 5) {
|
|
387
|
-
|
|
394
|
+
expectOkResponse(res);
|
|
388
395
|
} else {
|
|
389
396
|
expect(res._getStatusCode()).toBe(429);
|
|
390
397
|
const data = JSON.parse(res._getData());
|
|
@@ -414,6 +421,12 @@ describe("nostr-profile-http", () => {
|
|
|
414
421
|
});
|
|
415
422
|
|
|
416
423
|
describe("POST /api/channels/nostr/:accountId/profile/import", () => {
|
|
424
|
+
function expectImportSuccessResponse(res: ReturnType<typeof createMockResponse>) {
|
|
425
|
+
const data = expectOkResponse(res);
|
|
426
|
+
expect(data.imported.name).toBe("imported");
|
|
427
|
+
return data;
|
|
428
|
+
}
|
|
429
|
+
|
|
417
430
|
it("imports profile from relays", async () => {
|
|
418
431
|
const ctx = createMockContext();
|
|
419
432
|
const handler = createNostrProfileHttpHandler(ctx);
|
|
@@ -424,10 +437,7 @@ describe("nostr-profile-http", () => {
|
|
|
424
437
|
|
|
425
438
|
await handler(req, res);
|
|
426
439
|
|
|
427
|
-
|
|
428
|
-
const data = JSON.parse(res._getData());
|
|
429
|
-
expect(data.ok).toBe(true);
|
|
430
|
-
expect(data.imported.name).toBe("imported");
|
|
440
|
+
const data = expectImportSuccessResponse(res);
|
|
431
441
|
expect(data.saved).toBe(false); // autoMerge not requested
|
|
432
442
|
});
|
|
433
443
|
|
|
@@ -490,8 +500,7 @@ describe("nostr-profile-http", () => {
|
|
|
490
500
|
|
|
491
501
|
await handler(req, res);
|
|
492
502
|
|
|
493
|
-
|
|
494
|
-
const data = JSON.parse(res._getData());
|
|
503
|
+
const data = expectImportSuccessResponse(res);
|
|
495
504
|
expect(data.saved).toBe(true);
|
|
496
505
|
expect(ctx.updateConfigProfile).toHaveBeenCalled();
|
|
497
506
|
});
|