@openclaw/nostr 2026.8.1-beta.2 → 2026.8.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.
- package/dist/api.js +4 -4
- package/dist/{channel-BifOvAwp.js → channel-BwnvE_wr.js} +24 -72
- package/dist/channel-plugin-api.js +1 -1
- package/dist/index.js +4 -0
- package/dist/secret-contract-api.js +37 -0
- package/dist/{setup-adapter-DLthHa2q.js → setup-adapter-KJ_iGKiG.js} +33 -2
- package/dist/setup-api.js +1 -1
- package/dist/setup-entry.js +4 -0
- package/dist/setup-plugin-api.js +8 -11
- package/dist/{setup-surface-DAhyNOcb.js → setup-surface-CzjfhV72.js} +8 -38
- package/node_modules/nostr-tools/lib/cjs/abstract-pool.js +7 -5
- package/node_modules/nostr-tools/lib/cjs/abstract-pool.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/abstract-relay.js +6 -4
- package/node_modules/nostr-tools/lib/cjs/abstract-relay.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/core.js +10 -6
- package/node_modules/nostr-tools/lib/cjs/core.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/index.js +37 -15
- package/node_modules/nostr-tools/lib/cjs/index.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/kinds.js +2 -0
- package/node_modules/nostr-tools/lib/cjs/kinds.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip04.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip10.js +2 -0
- package/node_modules/nostr-tools/lib/cjs/nip10.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip13.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip17.js +21 -3
- package/node_modules/nostr-tools/lib/cjs/nip17.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip18.js +2 -0
- package/node_modules/nostr-tools/lib/cjs/nip18.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip19.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip21.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip22.js +2 -0
- package/node_modules/nostr-tools/lib/cjs/nip22.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip25.js +2 -0
- package/node_modules/nostr-tools/lib/cjs/nip25.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip27.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip28.js +2 -0
- package/node_modules/nostr-tools/lib/cjs/nip28.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip29.js +288 -12
- package/node_modules/nostr-tools/lib/cjs/nip29.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip44.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/nip45.js +2 -0
- package/node_modules/nostr-tools/lib/cjs/nip45.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip46.js +16 -8
- package/node_modules/nostr-tools/lib/cjs/nip46.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip47.js +2 -0
- package/node_modules/nostr-tools/lib/cjs/nip47.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip57.js +2 -0
- package/node_modules/nostr-tools/lib/cjs/nip57.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip59.js +21 -3
- package/node_modules/nostr-tools/lib/cjs/nip59.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nip98.js +3 -1
- package/node_modules/nostr-tools/lib/cjs/nip98.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nipad.js +55 -0
- package/node_modules/nostr-tools/lib/cjs/nipad.js.map +7 -0
- package/node_modules/nostr-tools/lib/cjs/nipb0.js +2 -0
- package/node_modules/nostr-tools/lib/cjs/nipb0.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/nipb7.js +2 -0
- package/node_modules/nostr-tools/lib/cjs/nipb7.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/pool.js +9 -5
- package/node_modules/nostr-tools/lib/cjs/pool.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/pure.js +10 -6
- package/node_modules/nostr-tools/lib/cjs/pure.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/references.js.map +1 -1
- package/node_modules/nostr-tools/lib/cjs/relay.js +8 -4
- package/node_modules/nostr-tools/lib/cjs/relay.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/signer.js +2 -0
- package/node_modules/nostr-tools/lib/cjs/signer.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/utils.js +2 -0
- package/node_modules/nostr-tools/lib/cjs/utils.js.map +2 -2
- package/node_modules/nostr-tools/lib/cjs/wasm.js +10 -6
- package/node_modules/nostr-tools/lib/cjs/wasm.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/abstract-pool.js +7 -5
- package/node_modules/nostr-tools/lib/esm/abstract-pool.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/abstract-relay.js +6 -4
- package/node_modules/nostr-tools/lib/esm/abstract-relay.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/core.js +10 -6
- package/node_modules/nostr-tools/lib/esm/core.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/index.js +37 -15
- package/node_modules/nostr-tools/lib/esm/index.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/kinds.js +2 -0
- package/node_modules/nostr-tools/lib/esm/kinds.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip04.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip10.js +2 -0
- package/node_modules/nostr-tools/lib/esm/nip10.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip13.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip17.js +21 -3
- package/node_modules/nostr-tools/lib/esm/nip17.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip18.js +2 -0
- package/node_modules/nostr-tools/lib/esm/nip18.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip19.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip21.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip22.js +2 -0
- package/node_modules/nostr-tools/lib/esm/nip22.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip25.js +2 -0
- package/node_modules/nostr-tools/lib/esm/nip25.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip27.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip28.js +2 -0
- package/node_modules/nostr-tools/lib/esm/nip28.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip29.js +288 -12
- package/node_modules/nostr-tools/lib/esm/nip29.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip44.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/nip45.js +2 -0
- package/node_modules/nostr-tools/lib/esm/nip45.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip46.js +16 -8
- package/node_modules/nostr-tools/lib/esm/nip46.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip47.js +2 -0
- package/node_modules/nostr-tools/lib/esm/nip47.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip57.js +2 -0
- package/node_modules/nostr-tools/lib/esm/nip57.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip59.js +21 -3
- package/node_modules/nostr-tools/lib/esm/nip59.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nip98.js +3 -1
- package/node_modules/nostr-tools/lib/esm/nip98.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nipad.js +34 -0
- package/node_modules/nostr-tools/lib/esm/nipad.js.map +7 -0
- package/node_modules/nostr-tools/lib/esm/nipb0.js +2 -0
- package/node_modules/nostr-tools/lib/esm/nipb0.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/nipb7.js +2 -0
- package/node_modules/nostr-tools/lib/esm/nipb7.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/pool.js +9 -5
- package/node_modules/nostr-tools/lib/esm/pool.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/pure.js +10 -6
- package/node_modules/nostr-tools/lib/esm/pure.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/references.js.map +1 -1
- package/node_modules/nostr-tools/lib/esm/relay.js +8 -4
- package/node_modules/nostr-tools/lib/esm/relay.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/signer.js +2 -0
- package/node_modules/nostr-tools/lib/esm/signer.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/utils.js +2 -0
- package/node_modules/nostr-tools/lib/esm/utils.js.map +2 -2
- package/node_modules/nostr-tools/lib/esm/wasm.js +10 -6
- package/node_modules/nostr-tools/lib/esm/wasm.js.map +2 -2
- package/node_modules/nostr-tools/lib/nostr.bundle.js +37 -15
- package/node_modules/nostr-tools/lib/nostr.bundle.js.map +2 -2
- package/node_modules/nostr-tools/lib/types/core.d.ts +5 -0
- package/node_modules/nostr-tools/lib/types/nip29.d.ts +243 -3
- package/node_modules/nostr-tools/lib/types/nip29.test.d.ts +1 -0
- package/node_modules/nostr-tools/lib/types/nip46.test.d.ts +1 -0
- package/node_modules/nostr-tools/lib/types/nip98.d.ts +1 -1
- package/node_modules/nostr-tools/lib/types/nipad.d.ts +16 -0
- package/node_modules/nostr-tools/package.json +7 -1
- package/package.json +5 -5
package/dist/api.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { s as resolveNostrAccount } from "./setup-surface-
|
|
1
|
+
import { s as resolveNostrAccount } from "./setup-surface-CzjfhV72.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-
|
|
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";
|
|
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";
|
|
8
|
+
import { createFixedWindowRateLimiter as createFixedWindowRateLimiter$1 } from "openclaw/plugin-sdk/webhook-ingress";
|
|
8
9
|
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
9
10
|
import { isBlockedHostnameOrIp, isLoopbackHost } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
10
11
|
import { readJsonBodyWithLimit, requestBodyErrorToText } from "openclaw/plugin-sdk/webhook-request-guards";
|
|
11
|
-
import { createFixedWindowRateLimiter } from "openclaw/plugin-sdk/webhook-ingress";
|
|
12
12
|
import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
13
13
|
//#region extensions/nostr/src/nostr-profile-url-safety.ts
|
|
14
14
|
function validateUrlSafety(urlStr) {
|
|
@@ -184,7 +184,7 @@ function mergeProfiles(local, imported) {
|
|
|
184
184
|
}
|
|
185
185
|
//#endregion
|
|
186
186
|
//#region extensions/nostr/src/nostr-profile-http.ts
|
|
187
|
-
const profileRateLimiter = createFixedWindowRateLimiter({
|
|
187
|
+
const profileRateLimiter = createFixedWindowRateLimiter$1({
|
|
188
188
|
windowMs: 6e4,
|
|
189
189
|
maxRequests: 5,
|
|
190
190
|
maxTrackedKeys: 2048
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as listNostrAccountIds, c as normalizePubkey,
|
|
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";
|
|
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
|
-
import {
|
|
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";
|
|
5
5
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
6
6
|
import { createScopedDmSecurityResolver, createTopLevelChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
@@ -18,6 +18,9 @@ import { chunkTextForOutbound, sanitizeAssistantVisibleText, stripMarkdown } fro
|
|
|
18
18
|
import { SimplePool, finalizeEvent, getPublicKey, verifyEvent } from "nostr-tools";
|
|
19
19
|
import { decrypt, encrypt } from "nostr-tools/nip04";
|
|
20
20
|
import { createDirectDmPreCryptoGuardPolicy } from "openclaw/plugin-sdk/direct-dm-guard-policy";
|
|
21
|
+
import { createFixedWindowRateLimiter } from "openclaw/plugin-sdk/webhook-ingress";
|
|
22
|
+
import { retryAsync } from "openclaw/plugin-sdk/retry-runtime";
|
|
23
|
+
import { sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
|
|
21
24
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
22
25
|
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
23
26
|
import { buildChannelOutboundSessionRoute, stripChannelTargetPrefix } from "openclaw/plugin-sdk/core";
|
|
@@ -289,19 +292,16 @@ function createNostrCursorStateWriter(options) {
|
|
|
289
292
|
let activeFlush;
|
|
290
293
|
let recoveryFlush;
|
|
291
294
|
const writeWithRetry = async (cursor) => {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
295
|
+
try {
|
|
296
|
+
await retryAsync(() => options.write(cursor), {
|
|
297
|
+
attempts: CURSOR_WRITE_RETRY_MS.length,
|
|
298
|
+
minDelayMs: 0,
|
|
299
|
+
delayMs: ({ attempt }) => CURSOR_WRITE_RETRY_MS[attempt] ?? 0,
|
|
300
|
+
sleep: (delayMs) => sleepWithAbort(delayMs)
|
|
296
301
|
});
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
return;
|
|
300
|
-
} catch (error) {
|
|
301
|
-
lastError = error;
|
|
302
|
-
}
|
|
302
|
+
} catch (error) {
|
|
303
|
+
throw new Error("Nostr cursor state write failed.", { cause: error });
|
|
303
304
|
}
|
|
304
|
-
throw new Error("Nostr cursor state write failed.", { cause: lastError });
|
|
305
305
|
};
|
|
306
306
|
const enqueueWrite = (cursor) => {
|
|
307
307
|
const write = writeTail.then(() => writeWithRetry(cursor));
|
|
@@ -548,12 +548,8 @@ function createNostrIngress(options) {
|
|
|
548
548
|
const pending = await getQueue().listPending({ limit: options.maxPendingEvents });
|
|
549
549
|
const claims = await getQueue().listClaims();
|
|
550
550
|
if (pending.length + claims.length >= options.maxPendingEvents) throw new NostrIngressAdmissionRejectedError("backpressure", "Nostr event exceeds the durable ingress backlog.");
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
if (delayMs > 0) await new Promise((resolve) => {
|
|
554
|
-
setTimeout(resolve, delayMs);
|
|
555
|
-
});
|
|
556
|
-
try {
|
|
551
|
+
try {
|
|
552
|
+
return await retryAsync(async () => {
|
|
557
553
|
const result = await getQueue().enqueue(prepared.facts.eventId, prepared.payload, {
|
|
558
554
|
receivedAt: prepared.receivedAt,
|
|
559
555
|
laneKey: prepared.facts.laneKey
|
|
@@ -561,11 +557,15 @@ function createNostrIngress(options) {
|
|
|
561
557
|
options.afterDurableAppend(prepared.event);
|
|
562
558
|
monitor.requestDrain();
|
|
563
559
|
return result.kind === "accepted" ? "accepted" : "duplicate";
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
|
|
560
|
+
}, {
|
|
561
|
+
attempts: NOSTR_INGRESS_APPEND_RETRY_MS.length,
|
|
562
|
+
minDelayMs: 0,
|
|
563
|
+
delayMs: ({ attempt }) => NOSTR_INGRESS_APPEND_RETRY_MS[attempt] ?? 0,
|
|
564
|
+
sleep: (delayMs) => sleepWithAbort(delayMs)
|
|
565
|
+
});
|
|
566
|
+
} catch (error) {
|
|
567
|
+
throw new Error(`Nostr durable admission failed: ${formatErrorMessage(error)}`, { cause: error });
|
|
567
568
|
}
|
|
568
|
-
throw new Error(`Nostr durable admission failed: ${formatErrorMessage(lastError)}`, { cause: lastError });
|
|
569
569
|
};
|
|
570
570
|
return {
|
|
571
571
|
ready: async () => {
|
|
@@ -742,48 +742,6 @@ async function publishProfile(pool, sk, relays, profile, lastPublishedAt) {
|
|
|
742
742
|
return publishProfileEvent(pool, relays, createProfileEvent(sk, profile, lastPublishedAt));
|
|
743
743
|
}
|
|
744
744
|
//#endregion
|
|
745
|
-
//#region extensions/nostr/src/nostr-rate-limiter.ts
|
|
746
|
-
function createFixedWindowRateLimiter(params) {
|
|
747
|
-
const windowMs = Math.max(1, Math.floor(params.windowMs));
|
|
748
|
-
const maxRequests = Math.max(1, Math.floor(params.maxRequests));
|
|
749
|
-
const maxTrackedKeys = Math.max(1, Math.floor(params.maxTrackedKeys));
|
|
750
|
-
const state = /* @__PURE__ */ new Map();
|
|
751
|
-
const touch = (key, value) => {
|
|
752
|
-
state.delete(key);
|
|
753
|
-
state.set(key, value);
|
|
754
|
-
};
|
|
755
|
-
const prune = (nowMs) => {
|
|
756
|
-
for (const [key, entry] of state) if (nowMs - entry.windowStartMs >= windowMs) state.delete(key);
|
|
757
|
-
while (state.size > maxTrackedKeys) {
|
|
758
|
-
const oldest = state.keys().next().value;
|
|
759
|
-
if (!oldest) break;
|
|
760
|
-
state.delete(oldest);
|
|
761
|
-
}
|
|
762
|
-
};
|
|
763
|
-
return {
|
|
764
|
-
isRateLimited: (key, nowMs = Date.now()) => {
|
|
765
|
-
if (!key) return false;
|
|
766
|
-
prune(nowMs);
|
|
767
|
-
const existing = state.get(key);
|
|
768
|
-
if (!existing || nowMs - existing.windowStartMs >= windowMs) {
|
|
769
|
-
touch(key, {
|
|
770
|
-
count: 1,
|
|
771
|
-
windowStartMs: nowMs
|
|
772
|
-
});
|
|
773
|
-
return false;
|
|
774
|
-
}
|
|
775
|
-
const nextCount = existing.count + 1;
|
|
776
|
-
touch(key, {
|
|
777
|
-
count: nextCount,
|
|
778
|
-
windowStartMs: existing.windowStartMs
|
|
779
|
-
});
|
|
780
|
-
return nextCount > maxRequests;
|
|
781
|
-
},
|
|
782
|
-
size: () => state.size,
|
|
783
|
-
clear: () => state.clear()
|
|
784
|
-
};
|
|
785
|
-
}
|
|
786
|
-
//#endregion
|
|
787
745
|
//#region extensions/nostr/src/nostr-relay-subscription.ts
|
|
788
746
|
const DEFAULT_EOSE_CONFIRM_DEADLINE_MS = 1e4;
|
|
789
747
|
const LIBRARY_EOSE_TIMEOUT_MARGIN_MS = 1e3;
|
|
@@ -1357,7 +1315,6 @@ async function sendEncryptedDm(pool, sk, toPubkey, text, relays, metrics, circui
|
|
|
1357
1315
|
//#endregion
|
|
1358
1316
|
//#region extensions/nostr/src/gateway.ts
|
|
1359
1317
|
const activeBuses = /* @__PURE__ */ new Map();
|
|
1360
|
-
const metricsSnapshots = /* @__PURE__ */ new Map();
|
|
1361
1318
|
const ACCESS_GROUP_PREFIX = "accessGroup:";
|
|
1362
1319
|
function normalizeRelayLifecycleKey(relay) {
|
|
1363
1320
|
return new URL(relay).toString();
|
|
@@ -1426,7 +1383,6 @@ const startNostrGatewayAccount = async (ctx) => {
|
|
|
1426
1383
|
allowFrom: account.config.allowFrom,
|
|
1427
1384
|
command: runtime.channel.commands.shouldComputeCommandAuthorized(rawBody, ctx.cfg) ? { modeWhenAccessGroupsOff: "configured" } : void 0
|
|
1428
1385
|
});
|
|
1429
|
-
let busHandle = null;
|
|
1430
1386
|
const connectedRelays = /* @__PURE__ */ new Set();
|
|
1431
1387
|
const authorizeSender = async (input) => {
|
|
1432
1388
|
const resolved = await resolveInboundAccess(input.senderId, "");
|
|
@@ -1534,17 +1490,13 @@ const startNostrGatewayAccount = async (ctx) => {
|
|
|
1534
1490
|
else if (event.name === "relay.circuit_breaker.open") ctx.log?.warn?.(`[${account.accountId}] Circuit breaker opened for relay: ${event.labels?.relay}`);
|
|
1535
1491
|
else if (event.name === "relay.circuit_breaker.close") ctx.log?.info?.(`[${account.accountId}] Circuit breaker closed for relay: ${event.labels?.relay}`);
|
|
1536
1492
|
else if (event.name === "relay.error") ctx.log?.debug?.(`[${account.accountId}] Relay error: ${event.labels?.relay}`);
|
|
1537
|
-
if (busHandle) metricsSnapshots.set(account.accountId, busHandle.getMetrics());
|
|
1538
1493
|
}
|
|
1539
1494
|
});
|
|
1540
|
-
busHandle = bus;
|
|
1541
1495
|
activeBuses.set(account.accountId, bus);
|
|
1542
1496
|
ctx.log?.info?.(`[${account.accountId}] Nostr provider started with ${account.relays.length} configured relay(s)`);
|
|
1543
1497
|
return { stop: async () => {
|
|
1544
|
-
await bus.close();
|
|
1545
|
-
if (busHandle === bus) busHandle = null;
|
|
1546
1498
|
if (activeBuses.get(account.accountId) === bus) activeBuses.delete(account.accountId);
|
|
1547
|
-
|
|
1499
|
+
await bus.close();
|
|
1548
1500
|
ctx.log?.info?.(`[${account.accountId}] Nostr provider stopped`);
|
|
1549
1501
|
} };
|
|
1550
1502
|
},
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as nostrPlugin } from "./channel-
|
|
1
|
+
import { n as nostrPlugin } from "./channel-BwnvE_wr.js";
|
|
2
2
|
export { nostrPlugin };
|
package/dist/index.js
CHANGED
|
@@ -27,6 +27,10 @@ var nostr_default = defineBundledChannelEntry({
|
|
|
27
27
|
specifier: "./channel-plugin-api.js",
|
|
28
28
|
exportName: "nostrPlugin"
|
|
29
29
|
},
|
|
30
|
+
secrets: {
|
|
31
|
+
specifier: "./secret-contract-api.js",
|
|
32
|
+
exportName: "channelSecrets"
|
|
33
|
+
},
|
|
30
34
|
runtime: {
|
|
31
35
|
specifier: "./api.js",
|
|
32
36
|
exportName: "setNostrRuntime"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
2
|
+
import { collectSecretInputAssignment, createChannelSecretTargetRegistryEntries, getChannelRecord } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
3
|
+
//#region extensions/nostr/src/secret-contract.ts
|
|
4
|
+
const secretTargetRegistryEntries = createChannelSecretTargetRegistryEntries({
|
|
5
|
+
channelKey: "nostr",
|
|
6
|
+
channel: ["privateKey"]
|
|
7
|
+
});
|
|
8
|
+
function collectRuntimeConfigAssignments(params) {
|
|
9
|
+
const nostr = getChannelRecord(params.config, "nostr");
|
|
10
|
+
if (!nostr) return;
|
|
11
|
+
const accountId = normalizeAccountId(typeof nostr.defaultAccount === "string" ? nostr.defaultAccount : void 0);
|
|
12
|
+
collectSecretInputAssignment({
|
|
13
|
+
value: nostr.privateKey,
|
|
14
|
+
path: "channels.nostr.privateKey",
|
|
15
|
+
expected: "string",
|
|
16
|
+
defaults: params.defaults,
|
|
17
|
+
context: params.context,
|
|
18
|
+
active: nostr.enabled !== false,
|
|
19
|
+
inactiveReason: "Nostr channel is disabled.",
|
|
20
|
+
owner: {
|
|
21
|
+
ownerKind: "account",
|
|
22
|
+
ownerId: `nostr:${accountId}`,
|
|
23
|
+
requiredForGateway: false,
|
|
24
|
+
disposition: "isolate",
|
|
25
|
+
contract: nostr
|
|
26
|
+
},
|
|
27
|
+
apply: (value) => {
|
|
28
|
+
nostr.privateKey = value;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const channelSecrets = {
|
|
33
|
+
secretTargetRegistryEntries,
|
|
34
|
+
collectRuntimeConfigAssignments
|
|
35
|
+
};
|
|
36
|
+
//#endregion
|
|
37
|
+
export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
2
|
import { hasConfiguredSecretInput, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
3
|
+
import { decode } from "nostr-tools/nip19";
|
|
3
4
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing";
|
|
4
5
|
import { createSetupTranslator, createStandardChannelSetupStatus, patchTopLevelChannelConfigSection, splitSetupEntries } from "openclaw/plugin-sdk/setup";
|
|
5
6
|
import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
|
|
@@ -8,6 +9,32 @@ const DEFAULT_RELAYS = ["wss://relay.damus.io", "wss://nos.lol"];
|
|
|
8
9
|
//#endregion
|
|
9
10
|
//#region extensions/nostr/src/private-key.ts
|
|
10
11
|
const NOSTR_PRIVATE_KEY_ENV_VAR = "NOSTR_PRIVATE_KEY";
|
|
12
|
+
const SECP256K1_ORDER = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141");
|
|
13
|
+
/** Validate and normalize a private key (hex or NIP-19 nsec). */
|
|
14
|
+
function validatePrivateKey(key) {
|
|
15
|
+
const trimmed = key.trim();
|
|
16
|
+
let bytes;
|
|
17
|
+
if (trimmed.startsWith("nsec1") || trimmed.startsWith("NSEC1")) {
|
|
18
|
+
let decoded;
|
|
19
|
+
try {
|
|
20
|
+
decoded = decode(trimmed);
|
|
21
|
+
} catch {
|
|
22
|
+
throw new Error("Invalid nsec private key");
|
|
23
|
+
}
|
|
24
|
+
if (decoded.type !== "nsec") throw new Error("Invalid nsec key type");
|
|
25
|
+
bytes = decoded.data;
|
|
26
|
+
} else {
|
|
27
|
+
if (!/^[0-9a-fA-F]{64}$/.test(trimmed)) throw new Error("Private key must be 64 hex characters or nsec bech32 format");
|
|
28
|
+
bytes = Uint8Array.from({ length: 32 }, (_, index) => Number.parseInt(trimmed.slice(index * 2, index * 2 + 2), 16));
|
|
29
|
+
}
|
|
30
|
+
if (bytes.length !== 32) throw new Error("Private key must decode to 32 bytes");
|
|
31
|
+
const scalar = Array.from(bytes).reduce((value, byte) => value << 8n | BigInt(byte), 0n);
|
|
32
|
+
if (scalar === 0n || scalar >= SECP256K1_ORDER) throw new Error("Private key scalar is out of range");
|
|
33
|
+
return bytes;
|
|
34
|
+
}
|
|
35
|
+
function hasConfiguredNostrPrivateKey(value) {
|
|
36
|
+
return hasConfiguredSecretInput(value) || Boolean(process.env["NOSTR_PRIVATE_KEY"]?.trim());
|
|
37
|
+
}
|
|
11
38
|
function resolveNostrPrivateKey(value) {
|
|
12
39
|
const configured = normalizeSecretInputString(value);
|
|
13
40
|
if (configured || hasConfiguredSecretInput(value)) return configured ?? "";
|
|
@@ -53,7 +80,11 @@ function createNostrSetupAdapter(params) {
|
|
|
53
80
|
if (!input.useEnv) {
|
|
54
81
|
const privateKey = input.privateKey?.trim();
|
|
55
82
|
if (!privateKey) return "Nostr requires --private-key or --use-env.";
|
|
56
|
-
|
|
83
|
+
try {
|
|
84
|
+
validatePrivateKey(privateKey);
|
|
85
|
+
} catch {
|
|
86
|
+
return "Nostr private key must be valid nsec or 64-character hex.";
|
|
87
|
+
}
|
|
57
88
|
}
|
|
58
89
|
if (input.relayUrls?.trim()) return parseRelayUrls(input.relayUrls).error ?? null;
|
|
59
90
|
return null;
|
|
@@ -124,4 +155,4 @@ function createNostrSetupStatus(resolveAccount) {
|
|
|
124
155
|
});
|
|
125
156
|
}
|
|
126
157
|
//#endregion
|
|
127
|
-
export { parseRelayUrls as a, createNostrSetupStatus as i, createNostrSetupAdapter as n,
|
|
158
|
+
export { parseRelayUrls as a, validatePrivateKey as c, createNostrSetupStatus as i, DEFAULT_RELAYS as l, createNostrSetupAdapter as n, hasConfiguredNostrPrivateKey as o, createNostrSetupContract as r, resolveNostrPrivateKey as s, buildNostrSetupPatch as t };
|
package/dist/setup-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { r as nostrSetupWizard, t as nostrSetupAdapter } from "./setup-surface-
|
|
1
|
+
import { r as nostrSetupWizard, t as nostrSetupAdapter } from "./setup-surface-CzjfhV72.js";
|
|
2
2
|
export { nostrSetupAdapter, nostrSetupWizard };
|
package/dist/setup-entry.js
CHANGED
package/dist/setup-plugin-api.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { i as buildChannelConfigSchema, t as NostrConfigSchema } from "./config-schema-CkYd8ACn.js";
|
|
2
|
-
import { i as createNostrSetupStatus, n as createNostrSetupAdapter, o as
|
|
2
|
+
import { i as createNostrSetupStatus, l as DEFAULT_RELAYS, n as createNostrSetupAdapter, o as hasConfiguredNostrPrivateKey, r as createNostrSetupContract, s as resolveNostrPrivateKey } from "./setup-adapter-KJ_iGKiG.js";
|
|
3
3
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
4
|
-
import {
|
|
4
|
+
import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
5
|
+
import { createDelegatedSetupWizardProxy } from "openclaw/plugin-sdk/setup-runtime";
|
|
5
6
|
//#region extensions/nostr/src/channel.setup.ts
|
|
6
7
|
const channel = "nostr";
|
|
7
8
|
function getNostrConfig(cfg) {
|
|
8
9
|
return cfg.channels?.nostr;
|
|
9
10
|
}
|
|
10
11
|
function resolveDefaultSetupNostrAccountId(cfg) {
|
|
11
|
-
|
|
12
|
-
return typeof configured === "string" && configured.trim() ? configured.trim() : DEFAULT_ACCOUNT_ID;
|
|
12
|
+
return normalizeAccountId(getNostrConfig(cfg)?.defaultAccount);
|
|
13
13
|
}
|
|
14
14
|
function resolveSetupNostrAccount(params) {
|
|
15
15
|
const nostrCfg = getNostrConfig(params.cfg);
|
|
16
|
-
const accountId = params.accountId
|
|
16
|
+
const accountId = normalizeAccountId(params.accountId ?? resolveDefaultSetupNostrAccountId(params.cfg));
|
|
17
17
|
const privateKey = resolveNostrPrivateKey(nostrCfg?.privateKey);
|
|
18
|
-
const configured =
|
|
18
|
+
const configured = hasConfiguredNostrPrivateKey(nostrCfg?.privateKey);
|
|
19
19
|
return {
|
|
20
20
|
accountId,
|
|
21
21
|
name: typeof nostrCfg?.name === "string" ? nostrCfg.name : void 0,
|
|
@@ -38,7 +38,7 @@ function resolveSetupNostrAccount(params) {
|
|
|
38
38
|
}
|
|
39
39
|
const nostrSetupWizard = createDelegatedSetupWizardProxy({
|
|
40
40
|
channel,
|
|
41
|
-
loadWizard: async () => (await import("./setup-surface-
|
|
41
|
+
loadWizard: async () => (await import("./setup-surface-CzjfhV72.js").then((n) => n.i)).nostrSetupWizard,
|
|
42
42
|
status: createNostrSetupStatus(resolveSetupNostrAccount),
|
|
43
43
|
resolveShouldPromptAccountIds: () => false,
|
|
44
44
|
delegatePrepare: true,
|
|
@@ -61,10 +61,7 @@ const nostrSetupPlugin = {
|
|
|
61
61
|
},
|
|
62
62
|
reload: { configPrefixes: ["channels.nostr"] },
|
|
63
63
|
configSchema: buildChannelConfigSchema(NostrConfigSchema),
|
|
64
|
-
setupContract: createNostrSetupContract(createNostrSetupAdapter({
|
|
65
|
-
resolveAccountId: (cfg, accountId) => accountId?.trim() || resolveDefaultSetupNostrAccountId(cfg),
|
|
66
|
-
validatePrivateKey: (privateKey) => /^(?:nsec1|NSEC1)|^[0-9a-fA-F]{64}$/u.test(privateKey)
|
|
67
|
-
})),
|
|
64
|
+
setupContract: createNostrSetupContract(createNostrSetupAdapter({ resolveAccountId: (cfg, accountId) => accountId?.trim() || resolveDefaultSetupNostrAccountId(cfg) })),
|
|
68
65
|
setupWizard: nostrSetupWizard,
|
|
69
66
|
config: {
|
|
70
67
|
listAccountIds: (cfg) => resolveSetupNostrAccount({ cfg }).configured ? [resolveDefaultSetupNostrAccountId(cfg)] : [],
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { a as parseRelayUrls, i as createNostrSetupStatus, n as createNostrSetupAdapter, o as
|
|
1
|
+
import { a as parseRelayUrls, c as validatePrivateKey, i as createNostrSetupStatus, l as DEFAULT_RELAYS, n as createNostrSetupAdapter, o as hasConfiguredNostrPrivateKey, r as createNostrSetupContract, s as resolveNostrPrivateKey, t as buildNostrSetupPatch } from "./setup-adapter-KJ_iGKiG.js";
|
|
2
2
|
import { createAccountListHelpers } from "openclaw/plugin-sdk/account-helpers";
|
|
3
3
|
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
4
|
import { hasConfiguredSecretInput, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
5
|
-
import {
|
|
5
|
+
import { decode } from "nostr-tools/nip19";
|
|
6
|
+
import { getPublicKey } from "nostr-tools/pure";
|
|
6
7
|
import { DEFAULT_ACCOUNT_ID, normalizeAccountId, normalizeOptionalAccountId } from "openclaw/plugin-sdk/account-id";
|
|
7
8
|
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1 } from "openclaw/plugin-sdk/routing";
|
|
8
9
|
import { createSetupTranslator, createTopLevelChannelDmPolicy, createTopLevelChannelParsedAllowFromPrompt, defineTokenCredential, formatDocsLink, mergeAllowFromEntries, parseSetupEntriesWithParser, patchTopLevelChannelConfigSection, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
|
|
@@ -19,34 +20,13 @@ var __exportAll = (all, no_symbols) => {
|
|
|
19
20
|
};
|
|
20
21
|
//#endregion
|
|
21
22
|
//#region extensions/nostr/src/nostr-key-utils.ts
|
|
22
|
-
/**
|
|
23
|
-
* Validate and normalize a private key (accepts hex or nsec format)
|
|
24
|
-
*/
|
|
25
|
-
function validatePrivateKey(key) {
|
|
26
|
-
const trimmed = key.trim();
|
|
27
|
-
if (trimmed.startsWith("nsec1") || trimmed.startsWith("NSEC1")) {
|
|
28
|
-
const decoded = nip19.decode(trimmed);
|
|
29
|
-
if (decoded.type !== "nsec") throw new Error("Invalid nsec key: wrong type");
|
|
30
|
-
return decoded.data;
|
|
31
|
-
}
|
|
32
|
-
if (!/^[0-9a-fA-F]{64}$/.test(trimmed)) throw new Error("Private key must be 64 hex characters or nsec bech32 format");
|
|
33
|
-
const bytes = /* @__PURE__ */ new Uint8Array(32);
|
|
34
|
-
for (let i = 0; i < 32; i++) bytes[i] = Number.parseInt(trimmed.slice(i * 2, i * 2 + 2), 16);
|
|
35
|
-
return bytes;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Get public key from private key (hex or nsec format)
|
|
39
|
-
*/
|
|
40
23
|
function getPublicKeyFromPrivate(privateKey) {
|
|
41
24
|
return getPublicKey(validatePrivateKey(privateKey));
|
|
42
25
|
}
|
|
43
|
-
/**
|
|
44
|
-
* Normalize a pubkey to hex format (accepts npub or hex)
|
|
45
|
-
*/
|
|
46
26
|
function normalizePubkey(input) {
|
|
47
27
|
const trimmed = input.trim();
|
|
48
28
|
if (trimmed.startsWith("npub1") || trimmed.startsWith("NPUB1")) {
|
|
49
|
-
const decoded =
|
|
29
|
+
const decoded = decode(trimmed);
|
|
50
30
|
if (decoded.type !== "npub" || typeof decoded.data !== "string") throw new Error("Invalid npub key");
|
|
51
31
|
return decoded.data.toLowerCase();
|
|
52
32
|
}
|
|
@@ -59,7 +39,7 @@ const { listAccountIds: listNostrAccountIds, resolveDefaultAccountId: resolveDef
|
|
|
59
39
|
fallbackAccountIdWhenEmpty: false,
|
|
60
40
|
resolveImplicitAccountId: (cfg) => {
|
|
61
41
|
const account = cfg.channels?.nostr;
|
|
62
|
-
return
|
|
42
|
+
return hasConfiguredNostrPrivateKey(account?.privateKey) ? normalizeOptionalAccountId(account?.defaultAccount) ?? DEFAULT_ACCOUNT_ID : void 0;
|
|
63
43
|
}
|
|
64
44
|
});
|
|
65
45
|
/**
|
|
@@ -70,7 +50,7 @@ function resolveNostrAccount(opts) {
|
|
|
70
50
|
const nostrCfg = opts.cfg.channels?.nostr;
|
|
71
51
|
const baseEnabled = nostrCfg?.enabled !== false;
|
|
72
52
|
const privateKey = resolveNostrPrivateKey(nostrCfg?.privateKey);
|
|
73
|
-
const configured =
|
|
53
|
+
const configured = hasConfiguredNostrPrivateKey(nostrCfg?.privateKey);
|
|
74
54
|
let publicKey = "";
|
|
75
55
|
if (privateKey) try {
|
|
76
56
|
publicKey = getPublicKeyFromPrivate(privateKey);
|
|
@@ -146,17 +126,7 @@ const nostrDmPolicy = createTopLevelChannelDmPolicy({
|
|
|
146
126
|
mergeEntries: ({ existing, parsed }) => mergeAllowFromEntries(existing, parsed)
|
|
147
127
|
})
|
|
148
128
|
});
|
|
149
|
-
const nostrSetupAdapter = createNostrSetupAdapter({
|
|
150
|
-
resolveAccountId: (cfg, accountId) => accountId?.trim() || resolveDefaultNostrAccountId(cfg),
|
|
151
|
-
validatePrivateKey: (privateKey) => {
|
|
152
|
-
try {
|
|
153
|
-
getPublicKeyFromPrivate(privateKey);
|
|
154
|
-
return true;
|
|
155
|
-
} catch {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
});
|
|
129
|
+
const nostrSetupAdapter = createNostrSetupAdapter({ resolveAccountId: (cfg, accountId) => accountId?.trim() || resolveDefaultNostrAccountId(cfg) });
|
|
160
130
|
const nostrSetupContract = createNostrSetupContract(nostrSetupAdapter);
|
|
161
131
|
const nostrSetupWizard = {
|
|
162
132
|
channel,
|
|
@@ -244,4 +214,4 @@ const nostrSetupWizard = {
|
|
|
244
214
|
disable: (cfg) => setSetupChannelEnabled(cfg, channel, false)
|
|
245
215
|
};
|
|
246
216
|
//#endregion
|
|
247
|
-
export { listNostrAccountIds as a, normalizePubkey as c, setup_surface_exports as i,
|
|
217
|
+
export { listNostrAccountIds as a, normalizePubkey as c, setup_surface_exports as i, nostrSetupContract as n, resolveDefaultNostrAccountId as o, nostrSetupWizard as r, resolveNostrAccount as s, nostrSetupAdapter as t };
|
|
@@ -650,10 +650,12 @@ var Subscription = class {
|
|
|
650
650
|
this.closed = true;
|
|
651
651
|
}
|
|
652
652
|
this.relay.openSubs.delete(this.id);
|
|
653
|
-
this.
|
|
654
|
-
|
|
655
|
-
this.relay.
|
|
656
|
-
|
|
653
|
+
if (!this.id.startsWith("<forced-ping>")) {
|
|
654
|
+
this.relay.ongoingOperations--;
|
|
655
|
+
if (this.relay.ongoingOperations === 0) {
|
|
656
|
+
this.relay.idleSince = Date.now();
|
|
657
|
+
this.relay.scheduleIdleClose();
|
|
658
|
+
}
|
|
657
659
|
}
|
|
658
660
|
this.onclose?.(reason);
|
|
659
661
|
}
|
|
@@ -1004,7 +1006,7 @@ var AbstractSimplePool = class {
|
|
|
1004
1006
|
});
|
|
1005
1007
|
} catch (err) {
|
|
1006
1008
|
this.onRelayConnectionFailure?.(url);
|
|
1007
|
-
return
|
|
1009
|
+
return Promise.reject("connection failure: " + String(err));
|
|
1008
1010
|
}
|
|
1009
1011
|
return r.publish(event).catch(async (err) => {
|
|
1010
1012
|
if (err instanceof Error && err.message.startsWith("auth-required: ") && params?.onauth) {
|