@openclaw/nostr 2026.5.27 → 2026.5.28-beta.2
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
1
|
import { o as resolveNostrAccount } from "./setup-surface-CVEYWXAG.js";
|
|
2
2
|
import { getPluginRuntimeGatewayRequestScope } from "./runtime-api.js";
|
|
3
3
|
import { n as NostrProfileSchema } from "./config-schema-DIiXiBKr.js";
|
|
4
|
-
import { a as setNostrRuntime, i as getNostrRuntime, n as nostrPlugin, o as contentToProfile, r as publishNostrProfile, t as getNostrProfileState } from "./channel-
|
|
4
|
+
import { a as setNostrRuntime, i as getNostrRuntime, n as nostrPlugin, o as contentToProfile, r as publishNostrProfile, t as getNostrProfileState } from "./channel-UK7t4qb8.js";
|
|
5
5
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, readStringValue } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { SimplePool, verifyEvent } from "nostr-tools";
|
|
@@ -86,11 +86,12 @@ async function importProfileFromRelays(opts) {
|
|
|
86
86
|
let completed = 0;
|
|
87
87
|
for (const relay of relays) {
|
|
88
88
|
relaysQueried.push(relay);
|
|
89
|
-
const
|
|
89
|
+
const profileFilter = {
|
|
90
90
|
kinds: [0],
|
|
91
91
|
authors: [pubkey],
|
|
92
92
|
limit: 1
|
|
93
|
-
}
|
|
93
|
+
};
|
|
94
|
+
const sub = pool.subscribeMany([relay], profileFilter, {
|
|
94
95
|
onevent(event) {
|
|
95
96
|
events.push({
|
|
96
97
|
event,
|
|
@@ -5,7 +5,7 @@ import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
|
5
5
|
import { createScopedDmSecurityResolver, createTopLevelChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
6
6
|
import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
7
7
|
import { createChannelMessageAdapterFromOutbound } from "openclaw/plugin-sdk/channel-outbound";
|
|
8
|
-
import { buildPassiveChannelStatusSummary, buildTrafficStatusSummary, safeParseJsonWithSchema } from "openclaw/plugin-sdk/extension-shared";
|
|
8
|
+
import { buildPassiveChannelStatusSummary, buildTrafficStatusSummary, runStoppablePassiveMonitor, safeParseJsonWithSchema } from "openclaw/plugin-sdk/extension-shared";
|
|
9
9
|
import { createComputedAccountStatusAdapter } from "openclaw/plugin-sdk/status-helpers";
|
|
10
10
|
import { normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
11
11
|
import { z } from "zod";
|
|
@@ -991,11 +991,13 @@ async function startNostrBus(options) {
|
|
|
991
991
|
inflight.delete(event.id);
|
|
992
992
|
}
|
|
993
993
|
}
|
|
994
|
-
const
|
|
994
|
+
const dmFilter = {
|
|
995
995
|
kinds: [4],
|
|
996
996
|
"#p": [pk],
|
|
997
997
|
since
|
|
998
|
-
}
|
|
998
|
+
};
|
|
999
|
+
const relayAbort = new AbortController();
|
|
1000
|
+
const sub = pool.subscribeMany(relays, dmFilter, {
|
|
999
1001
|
onevent: handleEvent,
|
|
1000
1002
|
oneose: () => {
|
|
1001
1003
|
for (const relay of relays) metrics.emit("relay.message.eose", 1, { relay });
|
|
@@ -1007,7 +1009,8 @@ async function startNostrBus(options) {
|
|
|
1007
1009
|
options.onDisconnect?.(relay);
|
|
1008
1010
|
}
|
|
1009
1011
|
onError?.(/* @__PURE__ */ new Error(`Subscription closed: ${reason.join(", ")}`), "subscription");
|
|
1010
|
-
}
|
|
1012
|
+
},
|
|
1013
|
+
abort: relayAbort.signal
|
|
1011
1014
|
});
|
|
1012
1015
|
const sendDm = async (toPubkey, text) => {
|
|
1013
1016
|
await sendEncryptedDm(pool, sk, toPubkey, text, relays, metrics, circuitBreakers, healthTracker, onError);
|
|
@@ -1035,7 +1038,10 @@ async function startNostrBus(options) {
|
|
|
1035
1038
|
};
|
|
1036
1039
|
return {
|
|
1037
1040
|
close: () => {
|
|
1038
|
-
|
|
1041
|
+
relayAbort.abort("closed by caller");
|
|
1042
|
+
Promise.resolve(sub.close("closed by caller")).catch((err) => onError?.(err, "close subscription")).finally(() => {
|
|
1043
|
+
pool.close(relays);
|
|
1044
|
+
});
|
|
1039
1045
|
seen.stop();
|
|
1040
1046
|
perSenderRateLimiter.clear();
|
|
1041
1047
|
globalRateLimiter.clear();
|
|
@@ -1180,86 +1186,95 @@ const startNostrGatewayAccount = async (ctx) => {
|
|
|
1180
1186
|
ctx.log?.debug?.(`[${account.accountId}] blocked Nostr sender ${input.senderId} (${resolved.senderAccess.reasonCode})`);
|
|
1181
1187
|
return "block";
|
|
1182
1188
|
};
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
authorizeSender: async ({ senderPubkey, reply }) => await authorizeSender({
|
|
1188
|
-
senderId: senderPubkey,
|
|
1189
|
-
reply
|
|
1190
|
-
}),
|
|
1191
|
-
onMessage: async (senderPubkey, text, reply, meta) => {
|
|
1192
|
-
const resolvedAccess = await resolveInboundAccess(senderPubkey, text);
|
|
1193
|
-
if (resolvedAccess.senderAccess.decision !== "allow") {
|
|
1194
|
-
ctx.log?.warn?.(`[${account.accountId}] dropping Nostr DM after preflight drift (${senderPubkey}, ${resolvedAccess.senderAccess.reasonCode})`);
|
|
1195
|
-
return;
|
|
1196
|
-
}
|
|
1197
|
-
const { dispatchInboundDirectDmWithRuntime } = await import("./inbound-direct-dm-runtime-EdLLVtkh.js");
|
|
1198
|
-
await dispatchInboundDirectDmWithRuntime({
|
|
1199
|
-
cfg: ctx.cfg,
|
|
1200
|
-
runtime,
|
|
1201
|
-
channel: "nostr",
|
|
1202
|
-
channelLabel: "Nostr",
|
|
1189
|
+
await runStoppablePassiveMonitor({
|
|
1190
|
+
abortSignal: ctx.abortSignal,
|
|
1191
|
+
start: async () => {
|
|
1192
|
+
const bus = await startNostrBus({
|
|
1203
1193
|
accountId: account.accountId,
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
if (!outboundText.trim()) return;
|
|
1219
|
-
const tableMode = runtime.channel.text.resolveMarkdownTableMode({
|
|
1194
|
+
privateKey: account.privateKey,
|
|
1195
|
+
relays: account.relays,
|
|
1196
|
+
authorizeSender: async ({ senderPubkey, reply }) => await authorizeSender({
|
|
1197
|
+
senderId: senderPubkey,
|
|
1198
|
+
reply
|
|
1199
|
+
}),
|
|
1200
|
+
onMessage: async (senderPubkey, text, reply, meta) => {
|
|
1201
|
+
const resolvedAccess = await resolveInboundAccess(senderPubkey, text);
|
|
1202
|
+
if (resolvedAccess.senderAccess.decision !== "allow") {
|
|
1203
|
+
ctx.log?.warn?.(`[${account.accountId}] dropping Nostr DM after preflight drift (${senderPubkey}, ${resolvedAccess.senderAccess.reasonCode})`);
|
|
1204
|
+
return;
|
|
1205
|
+
}
|
|
1206
|
+
const { dispatchInboundDirectDmWithRuntime } = await import("./inbound-direct-dm-runtime-EdLLVtkh.js");
|
|
1207
|
+
await dispatchInboundDirectDmWithRuntime({
|
|
1220
1208
|
cfg: ctx.cfg,
|
|
1209
|
+
runtime,
|
|
1221
1210
|
channel: "nostr",
|
|
1222
|
-
|
|
1211
|
+
channelLabel: "Nostr",
|
|
1212
|
+
accountId: account.accountId,
|
|
1213
|
+
peer: {
|
|
1214
|
+
kind: "direct",
|
|
1215
|
+
id: senderPubkey
|
|
1216
|
+
},
|
|
1217
|
+
senderId: senderPubkey,
|
|
1218
|
+
senderAddress: `nostr:${senderPubkey}`,
|
|
1219
|
+
recipientAddress: `nostr:${account.publicKey}`,
|
|
1220
|
+
conversationLabel: senderPubkey,
|
|
1221
|
+
rawBody: text,
|
|
1222
|
+
messageId: meta.eventId,
|
|
1223
|
+
timestamp: meta.createdAt * 1e3,
|
|
1224
|
+
commandAuthorized: resolvedAccess.commandAccess.requested ? resolvedAccess.commandAccess.authorized : void 0,
|
|
1225
|
+
deliver: async (payload) => {
|
|
1226
|
+
const outboundText = payload && typeof payload === "object" && "text" in payload ? payload.text ?? "" : "";
|
|
1227
|
+
if (!outboundText.trim()) return;
|
|
1228
|
+
const tableMode = runtime.channel.text.resolveMarkdownTableMode({
|
|
1229
|
+
cfg: ctx.cfg,
|
|
1230
|
+
channel: "nostr",
|
|
1231
|
+
accountId: account.accountId
|
|
1232
|
+
});
|
|
1233
|
+
await reply(runtime.channel.text.convertMarkdownTables(outboundText, tableMode));
|
|
1234
|
+
},
|
|
1235
|
+
onRecordError: (err) => {
|
|
1236
|
+
ctx.log?.error?.(`[${account.accountId}] failed recording Nostr inbound session: ${String(err)}`);
|
|
1237
|
+
},
|
|
1238
|
+
onDispatchError: (err, info) => {
|
|
1239
|
+
ctx.log?.error?.(`[${account.accountId}] Nostr ${info.kind} reply failed: ${String(err)}`);
|
|
1240
|
+
}
|
|
1223
1241
|
});
|
|
1224
|
-
await reply(runtime.channel.text.convertMarkdownTables(outboundText, tableMode));
|
|
1225
1242
|
},
|
|
1226
|
-
|
|
1227
|
-
ctx.log?.error?.(`[${account.accountId}]
|
|
1243
|
+
onError: (error, context) => {
|
|
1244
|
+
ctx.log?.error?.(`[${account.accountId}] Nostr error (${context}): ${error.message}`);
|
|
1228
1245
|
},
|
|
1229
|
-
|
|
1230
|
-
ctx.log?.
|
|
1246
|
+
onConnect: (relay) => {
|
|
1247
|
+
ctx.log?.debug?.(`[${account.accountId}] Connected to relay: ${relay}`);
|
|
1248
|
+
},
|
|
1249
|
+
onDisconnect: (relay) => {
|
|
1250
|
+
ctx.log?.debug?.(`[${account.accountId}] Disconnected from relay: ${relay}`);
|
|
1251
|
+
},
|
|
1252
|
+
onEose: (relays) => {
|
|
1253
|
+
ctx.log?.debug?.(`[${account.accountId}] EOSE received from relays: ${relays}`);
|
|
1254
|
+
},
|
|
1255
|
+
onMetric: (event) => {
|
|
1256
|
+
if (event.name.startsWith("event.rejected.")) ctx.log?.debug?.(`[${account.accountId}] Metric: ${event.name} ${JSON.stringify(event.labels)}`);
|
|
1257
|
+
else if (event.name === "relay.circuit_breaker.open") ctx.log?.warn?.(`[${account.accountId}] Circuit breaker opened for relay: ${event.labels?.relay}`);
|
|
1258
|
+
else if (event.name === "relay.circuit_breaker.close") ctx.log?.info?.(`[${account.accountId}] Circuit breaker closed for relay: ${event.labels?.relay}`);
|
|
1259
|
+
else if (event.name === "relay.error") ctx.log?.debug?.(`[${account.accountId}] Relay error: ${event.labels?.relay}`);
|
|
1260
|
+
if (busHandle) metricsSnapshots.set(account.accountId, busHandle.getMetrics());
|
|
1231
1261
|
}
|
|
1232
1262
|
});
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
onMetric: (event) => {
|
|
1247
|
-
if (event.name.startsWith("event.rejected.")) ctx.log?.debug?.(`[${account.accountId}] Metric: ${event.name} ${JSON.stringify(event.labels)}`);
|
|
1248
|
-
else if (event.name === "relay.circuit_breaker.open") ctx.log?.warn?.(`[${account.accountId}] Circuit breaker opened for relay: ${event.labels?.relay}`);
|
|
1249
|
-
else if (event.name === "relay.circuit_breaker.close") ctx.log?.info?.(`[${account.accountId}] Circuit breaker closed for relay: ${event.labels?.relay}`);
|
|
1250
|
-
else if (event.name === "relay.error") ctx.log?.debug?.(`[${account.accountId}] Relay error: ${event.labels?.relay}`);
|
|
1251
|
-
if (busHandle) metricsSnapshots.set(account.accountId, busHandle.getMetrics());
|
|
1263
|
+
let stopped = false;
|
|
1264
|
+
busHandle = bus;
|
|
1265
|
+
activeBuses.set(account.accountId, bus);
|
|
1266
|
+
ctx.log?.info?.(`[${account.accountId}] Nostr provider started, connected to ${account.relays.length} relay(s)`);
|
|
1267
|
+
return { stop: () => {
|
|
1268
|
+
if (stopped) return;
|
|
1269
|
+
stopped = true;
|
|
1270
|
+
bus.close();
|
|
1271
|
+
if (busHandle === bus) busHandle = null;
|
|
1272
|
+
if (activeBuses.get(account.accountId) === bus) activeBuses.delete(account.accountId);
|
|
1273
|
+
metricsSnapshots.delete(account.accountId);
|
|
1274
|
+
ctx.log?.info?.(`[${account.accountId}] Nostr provider stopped`);
|
|
1275
|
+
} };
|
|
1252
1276
|
}
|
|
1253
1277
|
});
|
|
1254
|
-
busHandle = bus;
|
|
1255
|
-
activeBuses.set(account.accountId, bus);
|
|
1256
|
-
ctx.log?.info?.(`[${account.accountId}] Nostr provider started, connected to ${account.relays.length} relay(s)`);
|
|
1257
|
-
return { stop: () => {
|
|
1258
|
-
bus.close();
|
|
1259
|
-
activeBuses.delete(account.accountId);
|
|
1260
|
-
metricsSnapshots.delete(account.accountId);
|
|
1261
|
-
ctx.log?.info?.(`[${account.accountId}] Nostr provider stopped`);
|
|
1262
|
-
} };
|
|
1263
1278
|
};
|
|
1264
1279
|
const nostrPairingTextAdapter = {
|
|
1265
1280
|
idLabel: "nostrPubkey",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as nostrPlugin } from "./channel-
|
|
1
|
+
import { n as nostrPlugin } from "./channel-UK7t4qb8.js";
|
|
2
2
|
export { nostrPlugin };
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/nostr",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.28-beta.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/nostr",
|
|
9
|
-
"version": "2026.5.
|
|
9
|
+
"version": "2026.5.28-beta.2",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"nostr-tools": "2.23.5",
|
|
12
12
|
"zod": "4.4.3"
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"openclaw": ">=2026.5.
|
|
15
|
+
"openclaw": ">=2026.5.28-beta.2"
|
|
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.5.
|
|
3
|
+
"version": "2026.5.28-beta.2",
|
|
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.5.
|
|
15
|
+
"openclaw": ">=2026.5.28-beta.2"
|
|
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.5.
|
|
53
|
+
"pluginApi": ">=2026.5.28-beta.2"
|
|
54
54
|
},
|
|
55
55
|
"build": {
|
|
56
|
-
"openclawVersion": "2026.5.
|
|
56
|
+
"openclawVersion": "2026.5.28-beta.2"
|
|
57
57
|
},
|
|
58
58
|
"release": {
|
|
59
59
|
"publishToClawHub": true,
|
package/dist/test-api.js
DELETED