@openclaw/nostr 2026.9.1-beta.1 → 2026.9.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 (38) hide show
  1. package/dist/api.js +7 -5
  2. package/dist/{channel-BwnvE_wr.js → channel-CLybVB2-.js} +10 -11
  3. package/dist/channel-plugin-api.js +1 -1
  4. package/dist/doctor-contract-api.js +2 -1
  5. package/dist/setup-api.js +1 -1
  6. package/dist/setup-plugin-api.js +1 -1
  7. package/dist/{setup-surface-CzjfhV72.js → setup-surface-mA5PMspO.js} +11 -10
  8. package/node_modules/nostr-tools/lib/cjs/index.js +20 -4
  9. package/node_modules/nostr-tools/lib/cjs/index.js.map +2 -2
  10. package/node_modules/nostr-tools/lib/cjs/nip17.js +19 -3
  11. package/node_modules/nostr-tools/lib/cjs/nip17.js.map +2 -2
  12. package/node_modules/nostr-tools/lib/cjs/nip46.js +7 -3
  13. package/node_modules/nostr-tools/lib/cjs/nip46.js.map +2 -2
  14. package/node_modules/nostr-tools/lib/cjs/nip59.js +19 -3
  15. package/node_modules/nostr-tools/lib/cjs/nip59.js.map +2 -2
  16. package/node_modules/nostr-tools/lib/cjs/nip98.js +1 -1
  17. package/node_modules/nostr-tools/lib/cjs/nip98.js.map +2 -2
  18. package/node_modules/nostr-tools/lib/cjs/nipad.js +55 -0
  19. package/node_modules/nostr-tools/lib/cjs/nipad.js.map +7 -0
  20. package/node_modules/nostr-tools/lib/esm/index.js +20 -4
  21. package/node_modules/nostr-tools/lib/esm/index.js.map +2 -2
  22. package/node_modules/nostr-tools/lib/esm/nip17.js +19 -3
  23. package/node_modules/nostr-tools/lib/esm/nip17.js.map +2 -2
  24. package/node_modules/nostr-tools/lib/esm/nip46.js +7 -3
  25. package/node_modules/nostr-tools/lib/esm/nip46.js.map +2 -2
  26. package/node_modules/nostr-tools/lib/esm/nip59.js +19 -3
  27. package/node_modules/nostr-tools/lib/esm/nip59.js.map +2 -2
  28. package/node_modules/nostr-tools/lib/esm/nip98.js +1 -1
  29. package/node_modules/nostr-tools/lib/esm/nip98.js.map +2 -2
  30. package/node_modules/nostr-tools/lib/esm/nipad.js +34 -0
  31. package/node_modules/nostr-tools/lib/esm/nipad.js.map +7 -0
  32. package/node_modules/nostr-tools/lib/nostr.bundle.js +20 -4
  33. package/node_modules/nostr-tools/lib/nostr.bundle.js.map +2 -2
  34. package/node_modules/nostr-tools/lib/types/nip46.test.d.ts +1 -0
  35. package/node_modules/nostr-tools/lib/types/nip98.d.ts +1 -1
  36. package/node_modules/nostr-tools/lib/types/nipad.d.ts +16 -0
  37. package/node_modules/nostr-tools/package.json +7 -1
  38. package/package.json +5 -5
package/dist/api.js CHANGED
@@ -1,7 +1,7 @@
1
- import { s as resolveNostrAccount } from "./setup-surface-CzjfhV72.js";
1
+ import { s as resolveNostrAccount } from "./setup-surface-mA5PMspO.js";
2
2
  import { getPluginRuntimeGatewayRequestScope } from "./runtime-api.js";
3
3
  import { n as NostrProfileSchema } from "./config-schema-CkYd8ACn.js";
4
- import { a as getNostrRuntime, i as contentToProfile, n as nostrPlugin, o as setNostrRuntime, r as publishNostrProfile, t as getNostrProfileState } from "./channel-BwnvE_wr.js";
4
+ import { a as getNostrRuntime, i as contentToProfile, n as nostrPlugin, o as setNostrRuntime, r as publishNostrProfile, t as getNostrProfileState } from "./channel-CLybVB2-.js";
5
5
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, readStringValue } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { z } from "zod";
7
7
  import { SimplePool } from "nostr-tools";
@@ -18,7 +18,8 @@ function validateUrlSafety(urlStr) {
18
18
  ok: false,
19
19
  error: "URL must use https:// protocol"
20
20
  };
21
- if (isBlockedHostnameOrIp(url.hostname.trim().toLowerCase())) return {
21
+ const hostname = url.hostname.trim().toLowerCase();
22
+ if (isBlockedHostnameOrIp(hostname)) return {
22
23
  ok: false,
23
24
  error: "URL must not point to private/internal addresses"
24
25
  };
@@ -208,7 +209,7 @@ function sendJson(res, status, body) {
208
209
  res.setHeader("Content-Type", "application/json; charset=utf-8");
209
210
  res.end(JSON.stringify(body));
210
211
  }
211
- async function readJsonBody(req, maxBytes = 64 * 1024, timeoutMs = 3e4) {
212
+ async function readJsonBody(req, maxBytes = 65536, timeoutMs = 3e4) {
212
213
  const result = await readJsonBodyWithLimit(req, {
213
214
  maxBytes,
214
215
  timeoutMs,
@@ -234,7 +235,8 @@ function isLoopbackRemoteAddress(remoteAddress) {
234
235
  }
235
236
  function isLoopbackOriginLike(value) {
236
237
  try {
237
- return isLoopbackHost(new URL(value).hostname);
238
+ const url = new URL(value);
239
+ return isLoopbackHost(url.hostname);
238
240
  } catch {
239
241
  return false;
240
242
  }
@@ -1,4 +1,4 @@
1
- import { a as listNostrAccountIds, c as normalizePubkey, n as nostrSetupContract, o as resolveDefaultNostrAccountId, r as nostrSetupWizard, s as resolveNostrAccount } from "./setup-surface-CzjfhV72.js";
1
+ import { a as listNostrAccountIds, c as normalizePubkey, n as nostrSetupContract, o as resolveDefaultNostrAccountId, r as nostrSetupWizard, s as resolveNostrAccount } from "./setup-surface-mA5PMspO.js";
2
2
  import { a as collectStatusIssuesFromLastError, i as buildChannelConfigSchema, n as NostrProfileSchema, o as createDefaultChannelRuntimeState, r as DEFAULT_ACCOUNT_ID, s as formatPairingApproveHint, t as NostrConfigSchema } from "./config-schema-CkYd8ACn.js";
3
3
  import { c as validatePrivateKey, l as DEFAULT_RELAYS } from "./setup-adapter-KJ_iGKiG.js";
4
4
  import { t as normalizeNostrStateAccountId } from "./state-account-id-CvBZ9s6P.js";
@@ -213,9 +213,7 @@ function createMetrics(onMetric) {
213
213
  case "memory.seen_tracker_size":
214
214
  state.memory.seenTrackerSize = value;
215
215
  break;
216
- case "memory.rate_limiter_entries":
217
- state.memory.rateLimiterEntries = value;
218
- break;
216
+ case "memory.rate_limiter_entries": state.memory.rateLimiterEntries = value;
219
217
  }
220
218
  }
221
219
  function getSnapshot() {
@@ -365,9 +363,7 @@ function createNostrCursorStateWriter(options) {
365
363
  return;
366
364
  } catch (error) {
367
365
  options.onBackgroundError?.(error);
368
- await new Promise((resolve) => {
369
- setTimeout(resolve, options.recoveryRetryMs ?? CURSOR_RECOVERY_RETRY_MS);
370
- });
366
+ await sleepWithAbort(CURSOR_RECOVERY_RETRY_MS);
371
367
  }
372
368
  })().finally(() => {
373
369
  recoveryFlush = void 0;
@@ -679,11 +675,12 @@ function createProfileEvent(sk, profile, lastPublishedAt) {
679
675
  const content = profileToContent(profile);
680
676
  const contentJson = JSON.stringify(content);
681
677
  const now = Math.floor(Date.now() / 1e3);
678
+ const createdAt = lastPublishedAt !== void 0 ? Math.max(now, lastPublishedAt + 1) : now;
682
679
  return finalizeEvent({
683
680
  kind: 0,
684
681
  content: contentJson,
685
682
  tags: [],
686
- created_at: lastPublishedAt !== void 0 ? Math.max(now, lastPublishedAt + 1) : now
683
+ created_at: createdAt
687
684
  }, sk);
688
685
  }
689
686
  /** Per-relay publish timeout (ms) */
@@ -862,7 +859,7 @@ async function writeNostrProfileState(params) {
862
859
  //#region extensions/nostr/src/nostr-bus.ts
863
860
  const STARTUP_LOOKBACK_SEC = 120;
864
861
  const STATE_PERSIST_DEBOUNCE_MS = 5e3;
865
- const NOSTR_INGRESS_ENVELOPE_OVERHEAD_BYTES = 16 * 1024;
862
+ const NOSTR_INGRESS_ENVELOPE_OVERHEAD_BYTES = 16384;
866
863
  const NOSTR_INGRESS_MAX_PENDING_EVENTS = 1e3;
867
864
  const DEFAULT_INBOUND_GUARD_POLICY = createDirectDmPreCryptoGuardPolicy();
868
865
  const CIRCUIT_BREAKER_THRESHOLD = 5;
@@ -1447,7 +1444,8 @@ const startNostrGatewayAccount = async (ctx) => {
1447
1444
  commandAuthorized: resolvedAccess.commandAccess.requested ? resolvedAccess.commandAccess.authorized : void 0,
1448
1445
  turnAdoptionLifecycle: bindIngressLifecycleToReplyOptions(lifecycle).turnAdoptionLifecycle,
1449
1446
  deliver: async (payload) => {
1450
- const sanitizedText = sanitizeAssistantVisibleText(payload && typeof payload === "object" && "text" in payload ? payload.text ?? "" : "");
1447
+ const outboundText = payload && typeof payload === "object" && "text" in payload ? payload.text ?? "" : "";
1448
+ const sanitizedText = sanitizeAssistantVisibleText(outboundText);
1451
1449
  if (!sanitizedText) return;
1452
1450
  const tableMode = runtime.channel.text.resolveMarkdownTableMode({
1453
1451
  cfg: ctx.cfg,
@@ -1542,9 +1540,10 @@ const nostrOutboundAdapter = {
1542
1540
  const message = stripMarkdown(core.channel.text.convertMarkdownTables(text ?? "", tableMode));
1543
1541
  if (!message) throw new Error("Nostr send requires non-empty text after markdown stripping.");
1544
1542
  const normalizedTo = normalizePubkey(to);
1543
+ const eventId = await bus.sendDm(normalizedTo, message);
1545
1544
  return attachChannelToResult("nostr", {
1546
1545
  to: normalizedTo,
1547
- messageId: await bus.sendDm(normalizedTo, message)
1546
+ messageId: eventId
1548
1547
  });
1549
1548
  }
1550
1549
  };
@@ -1,2 +1,2 @@
1
- import { n as nostrPlugin } from "./channel-BwnvE_wr.js";
1
+ import { n as nostrPlugin } from "./channel-CLybVB2-.js";
2
2
  export { nostrPlugin };
@@ -49,7 +49,8 @@ async function listLegacyFiles(params) {
49
49
  const files = [];
50
50
  for (const entry of entries) {
51
51
  if (!entry.isFile() || !entry.name.startsWith(params.prefix) || !entry.name.endsWith(suffix)) continue;
52
- const accountId = normalizeNostrStateAccountId(entry.name.slice(params.prefix.length, -5));
52
+ const rawAccountId = entry.name.slice(params.prefix.length, -5);
53
+ const accountId = normalizeNostrStateAccountId(rawAccountId);
53
54
  const filePath = path.join(dir, entry.name);
54
55
  try {
55
56
  const value = params.parse(await readJsonFile(filePath));
package/dist/setup-api.js CHANGED
@@ -1,2 +1,2 @@
1
- import { r as nostrSetupWizard, t as nostrSetupAdapter } from "./setup-surface-CzjfhV72.js";
1
+ import { r as nostrSetupWizard, t as nostrSetupAdapter } from "./setup-surface-mA5PMspO.js";
2
2
  export { nostrSetupAdapter, nostrSetupWizard };
@@ -38,7 +38,7 @@ function resolveSetupNostrAccount(params) {
38
38
  }
39
39
  const nostrSetupWizard = createDelegatedSetupWizardProxy({
40
40
  channel,
41
- loadWizard: async () => (await import("./setup-surface-CzjfhV72.js").then((n) => n.i)).nostrSetupWizard,
41
+ loadWizard: async () => (await import("./setup-surface-mA5PMspO.js").then((n) => n.i)).nostrSetupWizard,
42
42
  status: createNostrSetupStatus(resolveSetupNostrAccount),
43
43
  resolveShouldPromptAccountIds: () => false,
44
44
  delegatePrepare: true,
@@ -109,22 +109,23 @@ function parseNostrAllowFrom(raw) {
109
109
  }
110
110
  });
111
111
  }
112
+ const promptNostrAllowFrom = createTopLevelChannelParsedAllowFromPrompt({
113
+ channel,
114
+ defaultAccountId: resolveDefaultNostrAccountId,
115
+ noteTitle: t("wizard.nostr.allowlistTitle"),
116
+ noteLines: NOSTR_ALLOW_FROM_HELP_LINES,
117
+ message: t("wizard.nostr.allowFromPrompt"),
118
+ placeholder: "npub1..., 0123abcd...",
119
+ parseEntries: parseNostrAllowFrom,
120
+ mergeEntries: ({ existing, parsed }) => mergeAllowFromEntries(existing, parsed)
121
+ });
112
122
  const nostrDmPolicy = createTopLevelChannelDmPolicy({
113
123
  label: "Nostr",
114
124
  channel,
115
125
  policyKey: "channels.nostr.dmPolicy",
116
126
  allowFromKey: "channels.nostr.allowFrom",
117
127
  getCurrent: (cfg) => cfg.channels?.nostr?.dmPolicy ?? "pairing",
118
- promptAllowFrom: createTopLevelChannelParsedAllowFromPrompt({
119
- channel,
120
- defaultAccountId: resolveDefaultNostrAccountId,
121
- noteTitle: t("wizard.nostr.allowlistTitle"),
122
- noteLines: NOSTR_ALLOW_FROM_HELP_LINES,
123
- message: t("wizard.nostr.allowFromPrompt"),
124
- placeholder: "npub1..., 0123abcd...",
125
- parseEntries: parseNostrAllowFrom,
126
- mergeEntries: ({ existing, parsed }) => mergeAllowFromEntries(existing, parsed)
127
- })
128
+ promptAllowFrom: promptNostrAllowFrom
128
129
  });
129
130
  const nostrSetupAdapter = createNostrSetupAdapter({ resolveAccountId: (cfg, accountId) => accountId?.trim() || resolveDefaultNostrAccountId(cfg) });
130
131
  const nostrSetupContract = createNostrSetupContract(nostrSetupAdapter);
@@ -2589,13 +2589,29 @@ function wrapManyEvents(event, senderPrivateKey, recipientsPublicKeys) {
2589
2589
  return wrappeds;
2590
2590
  }
2591
2591
  function unwrapEvent(wrap, recipientPrivateKey) {
2592
- const unwrappedSeal = nip44Decrypt(wrap, recipientPrivateKey);
2593
- return nip44Decrypt(unwrappedSeal, recipientPrivateKey);
2592
+ if (wrap.kind !== GiftWrap) {
2593
+ throw new Error(`unexpected wrap kind ${wrap.kind}, expected ${GiftWrap}`);
2594
+ }
2595
+ const seal = nip44Decrypt(wrap, recipientPrivateKey);
2596
+ if (seal.kind !== Seal) {
2597
+ throw new Error(`unexpected seal kind ${seal.kind}, expected ${Seal}`);
2598
+ }
2599
+ if (!verifyEvent(seal)) {
2600
+ throw new Error("seal signature is invalid");
2601
+ }
2602
+ const rumor = nip44Decrypt(seal, recipientPrivateKey);
2603
+ if (rumor.pubkey !== seal.pubkey) {
2604
+ throw new Error(`rumor pubkey ${rumor.pubkey} does not match seal pubkey ${seal.pubkey}`);
2605
+ }
2606
+ return rumor;
2594
2607
  }
2595
2608
  function unwrapManyEvents(wrappedEvents, recipientPrivateKey) {
2596
2609
  let unwrappedEvents = [];
2597
2610
  wrappedEvents.forEach((e) => {
2598
- unwrappedEvents.push(unwrapEvent(e, recipientPrivateKey));
2611
+ try {
2612
+ unwrappedEvents.push(unwrapEvent(e, recipientPrivateKey));
2613
+ } catch (_err) {
2614
+ }
2599
2615
  });
2600
2616
  unwrappedEvents.sort((a, b) => a.created_at - b.created_at);
2601
2617
  return unwrappedEvents;
@@ -3987,7 +4003,7 @@ function validateEventTimestamp(event) {
3987
4003
  if (!event.created_at) {
3988
4004
  return false;
3989
4005
  }
3990
- return Math.round(new Date().getTime() / 1e3) - event.created_at < 60;
4006
+ return Math.abs(Math.round(new Date().getTime() / 1e3) - event.created_at) < 60;
3991
4007
  }
3992
4008
  function validateEventKind(event) {
3993
4009
  return event.kind === HTTPAuth;