@openclaw/nostr 2026.7.2-beta.2 → 2026.7.2-beta.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/dist/api.js CHANGED
@@ -1,7 +1,7 @@
1
- import { o as resolveNostrAccount } from "./setup-surface-B52P4uo2.js";
1
+ import { o as resolveNostrAccount } from "./setup-surface-BF7_7BEx.js";
2
2
  import { getPluginRuntimeGatewayRequestScope } from "./runtime-api.js";
3
3
  import { n as NostrProfileSchema } from "./config-schema-CelPzg1N.js";
4
- import { a as setNostrRuntime, i as getNostrRuntime, n as nostrPlugin, o as contentToProfile, r as publishNostrProfile, t as getNostrProfileState } from "./channel-B51rExHD.js";
4
+ import { a as setNostrRuntime, i as getNostrRuntime, n as nostrPlugin, o as contentToProfile, r as publishNostrProfile, t as getNostrProfileState } from "./channel-DgBHZ53s.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";
@@ -115,9 +115,9 @@ async function importProfileFromRelays(opts) {
115
115
  relaysQueried
116
116
  };
117
117
  const bestEvent = events.reduce((current, candidate) => candidate.event.created_at > current.event.created_at ? candidate : current);
118
- let content;
118
+ let parsedContent;
119
119
  try {
120
- content = JSON.parse(bestEvent.event.content);
120
+ parsedContent = JSON.parse(bestEvent.event.content);
121
121
  } catch {
122
122
  return {
123
123
  ok: false,
@@ -126,9 +126,15 @@ async function importProfileFromRelays(opts) {
126
126
  sourceRelay: bestEvent.relay
127
127
  };
128
128
  }
129
+ if (typeof parsedContent !== "object" || parsedContent === null || Array.isArray(parsedContent)) return {
130
+ ok: false,
131
+ error: "Profile event content must be a JSON object",
132
+ relaysQueried,
133
+ sourceRelay: bestEvent.relay
134
+ };
129
135
  return {
130
136
  ok: true,
131
- profile: sanitizeProfileUrls(contentToProfile(content)),
137
+ profile: sanitizeProfileUrls(contentToProfile(parsedContent)),
132
138
  event: {
133
139
  id: bestEvent.event.id,
134
140
  pubkey: bestEvent.event.pubkey,
@@ -1,4 +1,4 @@
1
- import { a as resolveDefaultNostrAccountId, c as validatePrivateKey, i as listNostrAccountIds, n as nostrSetupWizard, o as resolveNostrAccount, s as normalizePubkey, t as nostrSetupAdapter } from "./setup-surface-B52P4uo2.js";
1
+ import { a as resolveDefaultNostrAccountId, c as validatePrivateKey, i as listNostrAccountIds, n as nostrSetupWizard, o as resolveNostrAccount, s as normalizePubkey, t as nostrSetupAdapter } from "./setup-surface-BF7_7BEx.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-CelPzg1N.js";
3
3
  import { i as DEFAULT_RELAYS } from "./setup-adapter-DEU3o8MF.js";
4
4
  import { t as normalizeNostrStateAccountId } from "./state-account-id-CvBZ9s6P.js";
@@ -275,6 +275,16 @@ function contentToProfile(content) {
275
275
  return profile;
276
276
  }
277
277
  //#endregion
278
+ //#region extensions/nostr/src/relay-publish.ts
279
+ const CONNECTION_FAILURE_PREFIX = "connection failure: ";
280
+ async function publishNostrEventToRelay(pool, relay, event) {
281
+ const publishPromise = pool.publish([relay], event)[0];
282
+ if (!publishPromise) throw new Error(`Failed to create publish promise for relay ${relay}`);
283
+ const result = await publishPromise;
284
+ if (result.startsWith(CONNECTION_FAILURE_PREFIX)) throw new Error(result.slice(20));
285
+ return result;
286
+ }
287
+ //#endregion
278
288
  //#region extensions/nostr/src/nostr-profile.ts
279
289
  /**
280
290
  * Nostr Profile Management (NIP-01 kind:0)
@@ -323,7 +333,7 @@ async function publishProfileEvent(pool, relays, event) {
323
333
  const timeoutPromise = new Promise((_, reject) => {
324
334
  timer = setTimeout(() => reject(/* @__PURE__ */ new Error("timeout")), RELAY_PUBLISH_TIMEOUT_MS);
325
335
  });
326
- await Promise.race([...pool.publish([relay], event), timeoutPromise]);
336
+ await Promise.race([publishNostrEventToRelay(pool, relay, event), timeoutPromise]);
327
337
  successes.push(relay);
328
338
  } catch (err) {
329
339
  const errorMessage = formatErrorMessage(err);
@@ -820,7 +830,7 @@ async function startNostrBus(options) {
820
830
  return;
821
831
  }
822
832
  const replyTo = async (text) => {
823
- await sendEncryptedDm(pool, sk, event.pubkey, text, relays, metrics, circuitBreakers, healthTracker, onError);
833
+ await sendEncryptedDm(pool, sk, event.pubkey, text, relays, metrics, circuitBreakers, healthTracker, onError, event.id);
824
834
  };
825
835
  const rejectIfGlobalRateLimited = () => {
826
836
  updateRateLimiterSizeMetric();
@@ -918,7 +928,7 @@ async function startNostrBus(options) {
918
928
  abort: relayAbort.signal
919
929
  });
920
930
  const sendDm = async (toPubkey, text) => {
921
- await sendEncryptedDm(pool, sk, toPubkey, text, relays, metrics, circuitBreakers, healthTracker, onError);
931
+ return await sendEncryptedDm(pool, sk, toPubkey, text, relays, metrics, circuitBreakers, healthTracker, onError);
922
932
  };
923
933
  const publishProfile$1 = async (profile) => {
924
934
  const lastPublishedAt = (await readNostrProfileState({ accountId }))?.lastPublishedAt ?? void 0;
@@ -971,11 +981,14 @@ async function startNostrBus(options) {
971
981
  /**
972
982
  * Send an encrypted DM to a pubkey
973
983
  */
974
- async function sendEncryptedDm(pool, sk, toPubkey, text, relays, metrics, circuitBreakers, healthTracker, onError) {
984
+ async function sendEncryptedDm(pool, sk, toPubkey, text, relays, metrics, circuitBreakers, healthTracker, onError, replyToEventId) {
985
+ const ciphertext = encrypt(sk, toPubkey, text);
986
+ const tags = [["p", toPubkey]];
987
+ if (replyToEventId) tags.push(["e", replyToEventId]);
975
988
  const reply = finalizeEvent({
976
989
  kind: 4,
977
- content: encrypt(sk, toPubkey, text),
978
- tags: [["p", toPubkey]],
990
+ content: ciphertext,
991
+ tags,
979
992
  created_at: Math.floor(Date.now() / 1e3)
980
993
  }, sk);
981
994
  const sortedRelays = healthTracker.getSortedRelays(relays);
@@ -985,15 +998,13 @@ async function sendEncryptedDm(pool, sk, toPubkey, text, relays, metrics, circui
985
998
  if (cb && !cb.canAttempt()) continue;
986
999
  const startTime = Date.now();
987
1000
  try {
988
- const publishPromises = pool.publish([relay], reply);
989
- if (publishPromises.length === 0) throw new Error(`Failed to create publish promise for relay ${relay}`);
990
- await publishPromises[0];
1001
+ await publishNostrEventToRelay(pool, relay, reply);
991
1002
  const latency = Date.now() - startTime;
992
1003
  cb?.recordSuccess();
993
1004
  healthTracker.recordSuccess(relay, latency);
994
- return;
1005
+ return reply.id;
995
1006
  } catch (err) {
996
- lastError = err;
1007
+ lastError = err instanceof Error ? err : new Error(String(err));
997
1008
  const latency = Date.now() - startTime;
998
1009
  cb?.recordFailure();
999
1010
  healthTracker.recordFailure(relay);
@@ -1109,10 +1120,9 @@ const startNostrGatewayAccount = async (ctx) => {
1109
1120
  ctx.log?.warn?.(`[${account.accountId}] dropping Nostr DM after preflight drift (${senderPubkey}, ${resolvedAccess.senderAccess.reasonCode})`);
1110
1121
  return;
1111
1122
  }
1112
- const { dispatchInboundDirectDmWithRuntime } = await import("./inbound-direct-dm-runtime-EdLLVtkh.js");
1113
- await dispatchInboundDirectDmWithRuntime({
1123
+ const { dispatchInboundDirectDm } = await import("./inbound-direct-dm-runtime-DHn9NoYN.js");
1124
+ await dispatchInboundDirectDm({
1114
1125
  cfg: ctx.cfg,
1115
- runtime,
1116
1126
  channel: "nostr",
1117
1127
  channelLabel: "Nostr",
1118
1128
  accountId: account.accountId,
@@ -1216,10 +1226,9 @@ const nostrOutboundAdapter = {
1216
1226
  });
1217
1227
  const message = core.channel.text.convertMarkdownTables(text ?? "", tableMode);
1218
1228
  const normalizedTo = normalizePubkey(to);
1219
- await bus.sendDm(normalizedTo, message);
1220
1229
  return attachChannelToResult("nostr", {
1221
1230
  to: normalizedTo,
1222
- messageId: `nostr-${Date.now()}`
1231
+ messageId: await bus.sendDm(normalizedTo, message)
1223
1232
  });
1224
1233
  }
1225
1234
  };
@@ -1339,7 +1348,7 @@ const nostrPlugin = createChatChannelPlugin({
1339
1348
  targetResolver: {
1340
1349
  looksLikeId: (input) => {
1341
1350
  const trimmed = input.trim();
1342
- return trimmed.startsWith("npub1") || /^[0-9a-fA-F]{64}$/.test(trimmed);
1351
+ return trimmed.startsWith("npub1") || trimmed.startsWith("NPUB1") || /^[0-9a-fA-F]{64}$/.test(trimmed);
1343
1352
  },
1344
1353
  hint: "<npub|hex pubkey|nostr:npub...>"
1345
1354
  },
@@ -1,2 +1,2 @@
1
- import { n as nostrPlugin } from "./channel-B51rExHD.js";
1
+ import { n as nostrPlugin } from "./channel-DgBHZ53s.js";
2
2
  export { nostrPlugin };
@@ -0,0 +1,2 @@
1
+ import { dispatchInboundDirectDm } from "openclaw/plugin-sdk/channel-inbound";
2
+ export { dispatchInboundDirectDm };
package/dist/setup-api.js CHANGED
@@ -1,2 +1,2 @@
1
- import { n as nostrSetupWizard, t as nostrSetupAdapter } from "./setup-surface-B52P4uo2.js";
1
+ import { n as nostrSetupWizard, t as nostrSetupAdapter } from "./setup-surface-BF7_7BEx.js";
2
2
  export { nostrSetupAdapter, nostrSetupWizard };
@@ -43,7 +43,7 @@ function resolveSetupNostrAccount(params) {
43
43
  };
44
44
  }
45
45
  function looksLikeNostrPrivateKey(privateKey) {
46
- return privateKey.startsWith("nsec1") || /^[0-9a-fA-F]{64}$/.test(privateKey);
46
+ return privateKey.startsWith("nsec1") || privateKey.startsWith("NSEC1") || /^[0-9a-fA-F]{64}$/.test(privateKey);
47
47
  }
48
48
  const nostrSetupAdapter = createNostrSetupAdapter({
49
49
  resolveAccountId: (cfg, accountId) => accountId?.trim() || resolveDefaultSetupNostrAccountId(cfg),
@@ -51,7 +51,7 @@ const nostrSetupAdapter = createNostrSetupAdapter({
51
51
  });
52
52
  const nostrSetupWizard = createDelegatedSetupWizardProxy({
53
53
  channel,
54
- loadWizard: async () => (await import("./setup-surface-B52P4uo2.js").then((n) => n.r)).nostrSetupWizard,
54
+ loadWizard: async () => (await import("./setup-surface-BF7_7BEx.js").then((n) => n.r)).nostrSetupWizard,
55
55
  status: { ...createStandardChannelSetupStatus({
56
56
  channelLabel: "Nostr",
57
57
  configuredLabel: t("wizard.channels.statusConfigured"),
@@ -24,7 +24,7 @@ var __exportAll = (all, no_symbols) => {
24
24
  */
25
25
  function validatePrivateKey(key) {
26
26
  const trimmed = key.trim();
27
- if (trimmed.startsWith("nsec1")) {
27
+ if (trimmed.startsWith("nsec1") || trimmed.startsWith("NSEC1")) {
28
28
  const decoded = nip19.decode(trimmed);
29
29
  if (decoded.type !== "nsec") throw new Error("Invalid nsec key: wrong type");
30
30
  return decoded.data;
@@ -45,7 +45,7 @@ function getPublicKeyFromPrivate(privateKey) {
45
45
  */
46
46
  function normalizePubkey(input) {
47
47
  const trimmed = input.trim();
48
- if (trimmed.startsWith("npub1")) {
48
+ if (trimmed.startsWith("npub1") || trimmed.startsWith("NPUB1")) {
49
49
  const decoded = nip19.decode(trimmed);
50
50
  if (decoded.type !== "npub" || typeof decoded.data !== "string") throw new Error("Invalid npub key");
51
51
  return decoded.data.toLowerCase();
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@openclaw/nostr",
3
- "version": "2026.7.2-beta.2",
3
+ "version": "2026.7.2-beta.3",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/nostr",
9
- "version": "2026.7.2-beta.2",
9
+ "version": "2026.7.2-beta.3",
10
10
  "dependencies": {
11
11
  "nostr-tools": "2.23.9",
12
12
  "zod": "4.4.3"
13
13
  },
14
14
  "peerDependencies": {
15
- "openclaw": ">=2026.7.2-beta.2"
15
+ "openclaw": ">=2026.7.2-beta.3"
16
16
  },
17
17
  "peerDependenciesMeta": {
18
18
  "openclaw": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/nostr",
3
- "version": "2026.7.2-beta.2",
3
+ "version": "2026.7.2-beta.3",
4
4
  "description": "OpenClaw Nostr channel plugin for NIP-04 encrypted direct messages.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,7 +12,7 @@
12
12
  "zod": "4.4.3"
13
13
  },
14
14
  "peerDependencies": {
15
- "openclaw": ">=2026.7.2-beta.2"
15
+ "openclaw": ">=2026.7.2-beta.3"
16
16
  },
17
17
  "peerDependenciesMeta": {
18
18
  "openclaw": {
@@ -50,10 +50,10 @@
50
50
  "minHostVersion": ">=2026.4.10"
51
51
  },
52
52
  "compat": {
53
- "pluginApi": ">=2026.7.2-beta.2"
53
+ "pluginApi": ">=2026.7.2-beta.3"
54
54
  },
55
55
  "build": {
56
- "openclawVersion": "2026.7.2-beta.2"
56
+ "openclawVersion": "2026.7.2-beta.3"
57
57
  },
58
58
  "release": {
59
59
  "publishToClawHub": true,
@@ -1,2 +0,0 @@
1
- import { dispatchInboundDirectDmWithRuntime } from "openclaw/plugin-sdk/channel-inbound";
2
- export { dispatchInboundDirectDmWithRuntime };