@openclaw/nostr 2026.7.2-beta.7 → 2026.8.1-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 +3 -3
- package/dist/{channel-O6-jXoT5.js → channel-BifOvAwp.js} +38 -10
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{config-schema-CelPzg1N.js → config-schema-CkYd8ACn.js} +1 -0
- package/dist/doctor-contract-api.js +5 -7
- package/dist/{setup-adapter-BjKmSwdW.js → setup-adapter-DLthHa2q.js} +40 -12
- package/dist/setup-api.js +1 -1
- package/dist/setup-plugin-api.js +11 -39
- package/dist/{setup-surface-BJCFpe02.js → setup-surface-DAhyNOcb.js} +5 -18
- package/openclaw.plugin.json +29 -0
- package/package.json +8 -5
package/dist/api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { s as resolveNostrAccount } from "./setup-surface-
|
|
1
|
+
import { s as resolveNostrAccount } from "./setup-surface-DAhyNOcb.js";
|
|
2
2
|
import { getPluginRuntimeGatewayRequestScope } from "./runtime-api.js";
|
|
3
|
-
import { n as NostrProfileSchema } from "./config-schema-
|
|
4
|
-
import { a as getNostrRuntime, i as contentToProfile, n as nostrPlugin, o as setNostrRuntime, r as publishNostrProfile, t as getNostrProfileState } from "./channel-
|
|
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-BifOvAwp.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";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as listNostrAccountIds, c as normalizePubkey, l as validatePrivateKey, n as nostrSetupContract, o as resolveDefaultNostrAccountId, r as nostrSetupWizard, s as resolveNostrAccount
|
|
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-
|
|
3
|
-
import {
|
|
1
|
+
import { a as listNostrAccountIds, c as normalizePubkey, l as validatePrivateKey, n as nostrSetupContract, o as resolveDefaultNostrAccountId, r as nostrSetupWizard, s as resolveNostrAccount } from "./setup-surface-DAhyNOcb.js";
|
|
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 { s as DEFAULT_RELAYS } from "./setup-adapter-DLthHa2q.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";
|
|
@@ -9,10 +9,11 @@ import { missingTargetError } from "openclaw/plugin-sdk/channel-feedback";
|
|
|
9
9
|
import { DEFAULT_INGRESS_ADOPTION_STALL_MS, bindIngressLifecycleToReplyOptions, createChannelIngressError, createChannelIngressMonitor, createChannelMessageAdapterFromOutbound, runPassiveAccountLifecycle } from "openclaw/plugin-sdk/channel-outbound";
|
|
10
10
|
import { buildPassiveChannelStatusSummary, buildTrafficStatusSummary } from "openclaw/plugin-sdk/extension-shared";
|
|
11
11
|
import { createComputedAccountStatusAdapter } from "openclaw/plugin-sdk/status-helpers";
|
|
12
|
-
import { normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
12
|
+
import { isRecord as isNostrIngressRecord, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
13
13
|
import { resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
14
14
|
import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
|
|
15
15
|
import { attachChannelToResult } from "openclaw/plugin-sdk/channel-send-result";
|
|
16
|
+
import { channelReadyPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
16
17
|
import { chunkTextForOutbound, sanitizeAssistantVisibleText, stripMarkdown } from "openclaw/plugin-sdk/text-chunking";
|
|
17
18
|
import { SimplePool, finalizeEvent, getPublicKey, verifyEvent } from "nostr-tools";
|
|
18
19
|
import { decrypt, encrypt } from "nostr-tools/nip04";
|
|
@@ -382,9 +383,6 @@ var NostrIngressPermanentError = class extends Error {
|
|
|
382
383
|
this.name = "NostrIngressPermanentError";
|
|
383
384
|
}
|
|
384
385
|
};
|
|
385
|
-
function isNostrIngressRecord(value) {
|
|
386
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
387
|
-
}
|
|
388
386
|
function requiredString(value, field) {
|
|
389
387
|
if (typeof value === "string" && value.trim()) return value;
|
|
390
388
|
throw new NostrIngressPermanentError("invalid-event", `Nostr event is missing ${field}.`);
|
|
@@ -1361,6 +1359,9 @@ async function sendEncryptedDm(pool, sk, toPubkey, text, relays, metrics, circui
|
|
|
1361
1359
|
const activeBuses = /* @__PURE__ */ new Map();
|
|
1362
1360
|
const metricsSnapshots = /* @__PURE__ */ new Map();
|
|
1363
1361
|
const ACCESS_GROUP_PREFIX = "accessGroup:";
|
|
1362
|
+
function normalizeRelayLifecycleKey(relay) {
|
|
1363
|
+
return new URL(relay).toString();
|
|
1364
|
+
}
|
|
1364
1365
|
function parseNostrAccessGroupAllowFromEntry(entry) {
|
|
1365
1366
|
const trimmed = entry.trim();
|
|
1366
1367
|
if (!trimmed.startsWith(ACCESS_GROUP_PREFIX)) return null;
|
|
@@ -1396,17 +1397,20 @@ const startNostrGatewayAccount = async (ctx) => {
|
|
|
1396
1397
|
const account = ctx.account;
|
|
1397
1398
|
ctx.setStatus({
|
|
1398
1399
|
accountId: account.accountId,
|
|
1399
|
-
publicKey: account.publicKey
|
|
1400
|
+
publicKey: account.publicKey,
|
|
1401
|
+
lifecycle: "starting"
|
|
1400
1402
|
});
|
|
1401
1403
|
ctx.log?.info?.(`[${account.accountId}] starting Nostr provider (pubkey: ${account.publicKey})`);
|
|
1402
1404
|
if (!account.configured) throw new Error("Nostr private key not configured");
|
|
1405
|
+
const channelRuntime = ctx.channelRuntime;
|
|
1406
|
+
if (!channelRuntime?.inbound?.buildContext) throw new Error("Nostr requires its registered channel runtime context builder");
|
|
1403
1407
|
const runtime = getNostrRuntime();
|
|
1404
1408
|
const pairing = createChannelPairingController({
|
|
1405
1409
|
core: runtime,
|
|
1406
1410
|
channel: "nostr",
|
|
1407
1411
|
accountId: account.accountId
|
|
1408
1412
|
});
|
|
1409
|
-
const resolveInboundAccess = async (senderPubkey, rawBody) => await resolveStableChannelMessageIngress({
|
|
1413
|
+
const resolveInboundAccess = async (senderPubkey, rawBody, contextBinding) => await resolveStableChannelMessageIngress({
|
|
1410
1414
|
channelId: "nostr",
|
|
1411
1415
|
accountId: account.accountId,
|
|
1412
1416
|
identity: nostrIngressIdentity,
|
|
@@ -1417,11 +1421,13 @@ const startNostrGatewayAccount = async (ctx) => {
|
|
|
1417
1421
|
kind: "direct",
|
|
1418
1422
|
id: senderPubkey
|
|
1419
1423
|
},
|
|
1424
|
+
contextBinding,
|
|
1420
1425
|
dmPolicy: account.config.dmPolicy ?? "pairing",
|
|
1421
1426
|
allowFrom: account.config.allowFrom,
|
|
1422
1427
|
command: runtime.channel.commands.shouldComputeCommandAuthorized(rawBody, ctx.cfg) ? { modeWhenAccessGroupsOff: "configured" } : void 0
|
|
1423
1428
|
});
|
|
1424
1429
|
let busHandle = null;
|
|
1430
|
+
const connectedRelays = /* @__PURE__ */ new Set();
|
|
1425
1431
|
const authorizeSender = async (input) => {
|
|
1426
1432
|
const resolved = await resolveInboundAccess(input.senderId, "");
|
|
1427
1433
|
if (resolved.senderAccess.decision === "allow") return "allow";
|
|
@@ -1461,6 +1467,12 @@ const startNostrGatewayAccount = async (ctx) => {
|
|
|
1461
1467
|
}
|
|
1462
1468
|
const { dispatchInboundDirectDm } = await import("./inbound-direct-dm-runtime-DHn9NoYN.js");
|
|
1463
1469
|
await dispatchInboundDirectDm({
|
|
1470
|
+
channelRuntime,
|
|
1471
|
+
resolveChannelIngress: async (contextBinding) => {
|
|
1472
|
+
const exactAccess = await resolveInboundAccess(senderPubkey, text, contextBinding);
|
|
1473
|
+
if (!exactAccess.senderAccess.allowed) throw new Error(`Nostr sender authorization changed before dispatch (${senderPubkey})`);
|
|
1474
|
+
return exactAccess;
|
|
1475
|
+
},
|
|
1464
1476
|
cfg: ctx.cfg,
|
|
1465
1477
|
channel: "nostr",
|
|
1466
1478
|
channelLabel: "Nostr",
|
|
@@ -1501,9 +1513,17 @@ const startNostrGatewayAccount = async (ctx) => {
|
|
|
1501
1513
|
ctx.log?.error?.(`[${account.accountId}] Nostr error (${context}): ${error.message}`);
|
|
1502
1514
|
},
|
|
1503
1515
|
onConnect: (relay) => {
|
|
1516
|
+
connectedRelays.add(normalizeRelayLifecycleKey(relay));
|
|
1517
|
+
ctx.setStatus(channelReadyPatch({ accountId: account.accountId }));
|
|
1504
1518
|
ctx.log?.debug?.(`[${account.accountId}] Connected to relay: ${relay}`);
|
|
1505
1519
|
},
|
|
1506
1520
|
onDisconnect: (relay) => {
|
|
1521
|
+
connectedRelays.delete(normalizeRelayLifecycleKey(relay));
|
|
1522
|
+
if (connectedRelays.size === 0) ctx.setStatus({
|
|
1523
|
+
accountId: account.accountId,
|
|
1524
|
+
connected: false,
|
|
1525
|
+
lifecycle: "recovering"
|
|
1526
|
+
});
|
|
1507
1527
|
ctx.log?.debug?.(`[${account.accountId}] Disconnected from relay: ${relay}`);
|
|
1508
1528
|
},
|
|
1509
1529
|
onEose: (relays) => {
|
|
@@ -1618,6 +1638,14 @@ function normalizeNostrTarget(target) {
|
|
|
1618
1638
|
return target.trim();
|
|
1619
1639
|
}
|
|
1620
1640
|
}
|
|
1641
|
+
function inferNostrTargetChatType(target) {
|
|
1642
|
+
try {
|
|
1643
|
+
normalizePubkey(stripNostrTargetPrefix(target));
|
|
1644
|
+
return "direct";
|
|
1645
|
+
} catch {
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1621
1649
|
const resolveNostrDmPolicy = createScopedDmSecurityResolver({
|
|
1622
1650
|
channelKey: "nostr",
|
|
1623
1651
|
resolvePolicy: (account) => account.config.dmPolicy,
|
|
@@ -1692,7 +1720,6 @@ const nostrPlugin = createChatChannelPlugin({
|
|
|
1692
1720
|
},
|
|
1693
1721
|
reload: { configPrefixes: ["channels.nostr"] },
|
|
1694
1722
|
configSchema: buildChannelConfigSchema(NostrConfigSchema),
|
|
1695
|
-
setup: nostrSetupAdapter,
|
|
1696
1723
|
setupContract: nostrSetupContract,
|
|
1697
1724
|
setupWizard: nostrSetupWizard,
|
|
1698
1725
|
config: {
|
|
@@ -1707,6 +1734,7 @@ const nostrPlugin = createChatChannelPlugin({
|
|
|
1707
1734
|
messaging: {
|
|
1708
1735
|
targetPrefixes: ["nostr"],
|
|
1709
1736
|
normalizeTarget: normalizeNostrTarget,
|
|
1737
|
+
inferTargetChatType: ({ to }) => inferNostrTargetChatType(to),
|
|
1710
1738
|
targetResolver: {
|
|
1711
1739
|
looksLikeId: (input, normalized) => {
|
|
1712
1740
|
const trimmed = normalized?.trim() || stripNostrTargetPrefix(input);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as nostrPlugin } from "./channel-
|
|
1
|
+
import { n as nostrPlugin } from "./channel-BifOvAwp.js";
|
|
2
2
|
export { nostrPlugin };
|
|
@@ -46,6 +46,7 @@ const NostrConfigSchema = z.object({
|
|
|
46
46
|
defaultAccount: z.string().optional(),
|
|
47
47
|
/** Whether this channel is enabled */
|
|
48
48
|
enabled: z.boolean().optional(),
|
|
49
|
+
configWrites: z.boolean().optional(),
|
|
49
50
|
/** Markdown formatting overrides (tables). */
|
|
50
51
|
markdown: MarkdownConfigSchema,
|
|
51
52
|
/** Private key in hex or nsec bech32 format */
|
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
import { t as normalizeNostrStateAccountId } from "./state-account-id-CvBZ9s6P.js";
|
|
2
|
+
import { asFiniteNumber } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
3
|
import fs from "node:fs/promises";
|
|
3
4
|
import path from "node:path";
|
|
4
|
-
import { archiveLegacyStateSource } from "openclaw/plugin-sdk/runtime-doctor";
|
|
5
|
+
import { archiveLegacyStateSource } from "openclaw/plugin-sdk/runtime-doctor-migrations";
|
|
5
6
|
//#region extensions/nostr/doctor-contract-api.ts
|
|
6
7
|
const BUS_STATE_NAMESPACE = "bus-state";
|
|
7
8
|
const PROFILE_STATE_NAMESPACE = "profile-state";
|
|
8
9
|
const MAX_NOSTR_STATE_ENTRIES = 256;
|
|
9
|
-
function finiteNumberOrNull(value) {
|
|
10
|
-
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
11
|
-
}
|
|
12
10
|
function parseBusState(value) {
|
|
13
11
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
14
12
|
const parsed = value;
|
|
15
13
|
if (parsed.version !== 1 && parsed.version !== 2) return null;
|
|
16
14
|
return {
|
|
17
15
|
version: 2,
|
|
18
|
-
lastProcessedAt:
|
|
19
|
-
gatewayStartedAt:
|
|
16
|
+
lastProcessedAt: asFiniteNumber(parsed.lastProcessedAt) ?? null,
|
|
17
|
+
gatewayStartedAt: asFiniteNumber(parsed.gatewayStartedAt) ?? null,
|
|
20
18
|
recentEventIds: parsed.version === 2 && Array.isArray(parsed.recentEventIds) ? parsed.recentEventIds.filter((entry) => typeof entry === "string") : []
|
|
21
19
|
};
|
|
22
20
|
}
|
|
@@ -31,7 +29,7 @@ function parseProfileState(value) {
|
|
|
31
29
|
}
|
|
32
30
|
return {
|
|
33
31
|
version: 1,
|
|
34
|
-
lastPublishedAt:
|
|
32
|
+
lastPublishedAt: asFiniteNumber(parsed.lastPublishedAt) ?? null,
|
|
35
33
|
lastPublishedEventId: typeof parsed.lastPublishedEventId === "string" ? parsed.lastPublishedEventId : null,
|
|
36
34
|
lastPublishResults: rawResults === null || Object.keys(lastPublishResults).length === 0 ? null : lastPublishResults
|
|
37
35
|
};
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
|
+
import { hasConfiguredSecretInput, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
2
3
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing";
|
|
3
|
-
import { patchTopLevelChannelConfigSection, splitSetupEntries } from "openclaw/plugin-sdk/setup";
|
|
4
|
+
import { createSetupTranslator, createStandardChannelSetupStatus, patchTopLevelChannelConfigSection, splitSetupEntries } from "openclaw/plugin-sdk/setup";
|
|
4
5
|
import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
|
|
5
6
|
//#region extensions/nostr/src/default-relays.ts
|
|
6
7
|
const DEFAULT_RELAYS = ["wss://relay.damus.io", "wss://nos.lol"];
|
|
7
8
|
//#endregion
|
|
9
|
+
//#region extensions/nostr/src/private-key.ts
|
|
10
|
+
const NOSTR_PRIVATE_KEY_ENV_VAR = "NOSTR_PRIVATE_KEY";
|
|
11
|
+
function resolveNostrPrivateKey(value) {
|
|
12
|
+
const configured = normalizeSecretInputString(value);
|
|
13
|
+
if (configured || hasConfiguredSecretInput(value)) return configured ?? "";
|
|
14
|
+
return process.env["NOSTR_PRIVATE_KEY"]?.trim() ?? "";
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
8
17
|
//#region extensions/nostr/src/setup-adapter.ts
|
|
9
18
|
const channel = "nostr";
|
|
10
19
|
function buildNostrSetupPatch(accountId, patch) {
|
|
@@ -41,25 +50,23 @@ function createNostrSetupAdapter(params) {
|
|
|
41
50
|
patch: buildNostrSetupPatch(accountId, name?.trim() ? { name: name.trim() } : {})
|
|
42
51
|
}),
|
|
43
52
|
validateInput: ({ input }) => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const privateKey = typedInput.privateKey?.trim();
|
|
53
|
+
if (!input.useEnv) {
|
|
54
|
+
const privateKey = input.privateKey?.trim();
|
|
47
55
|
if (!privateKey) return "Nostr requires --private-key or --use-env.";
|
|
48
56
|
if (!params.validatePrivateKey(privateKey)) return "Nostr private key must be valid nsec or 64-character hex.";
|
|
49
57
|
}
|
|
50
|
-
if (
|
|
58
|
+
if (input.relayUrls?.trim()) return parseRelayUrls(input.relayUrls).error ?? null;
|
|
51
59
|
return null;
|
|
52
60
|
},
|
|
53
61
|
applyAccountConfig: ({ cfg, accountId, input }) => {
|
|
54
|
-
const
|
|
55
|
-
const relayResult = typedInput.relayUrls?.trim() ? parseRelayUrls(typedInput.relayUrls) : { relays: [] };
|
|
62
|
+
const relayResult = input.relayUrls?.trim() ? parseRelayUrls(input.relayUrls) : { relays: [] };
|
|
56
63
|
return patchTopLevelChannelConfigSection({
|
|
57
64
|
cfg,
|
|
58
65
|
channel,
|
|
59
66
|
enabled: true,
|
|
60
|
-
clearFields:
|
|
67
|
+
clearFields: input.useEnv ? ["privateKey"] : void 0,
|
|
61
68
|
patch: buildNostrSetupPatch(accountId, {
|
|
62
|
-
...
|
|
69
|
+
...input.useEnv ? {} : { privateKey: input.privateKey?.trim() },
|
|
63
70
|
...relayResult.relays.length > 0 ? { relays: relayResult.relays } : {}
|
|
64
71
|
})
|
|
65
72
|
});
|
|
@@ -89,11 +96,32 @@ function createNostrSetupContract(adapter) {
|
|
|
89
96
|
cli: {
|
|
90
97
|
flags: "--use-env",
|
|
91
98
|
description: "Use NOSTR_PRIVATE_KEY"
|
|
92
|
-
}
|
|
99
|
+
},
|
|
100
|
+
envVars: [NOSTR_PRIVATE_KEY_ENV_VAR]
|
|
93
101
|
}
|
|
94
102
|
},
|
|
95
|
-
|
|
103
|
+
adapter
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function createNostrSetupStatus(resolveAccount) {
|
|
107
|
+
const t = createSetupTranslator();
|
|
108
|
+
return createStandardChannelSetupStatus({
|
|
109
|
+
channelLabel: "Nostr",
|
|
110
|
+
configuredLabel: t("wizard.channels.statusConfigured"),
|
|
111
|
+
unconfiguredLabel: t("wizard.channels.statusNeedsPrivateKey"),
|
|
112
|
+
configuredHint: t("wizard.channels.statusConfigured"),
|
|
113
|
+
unconfiguredHint: t("wizard.channels.statusNeedsPrivateKey"),
|
|
114
|
+
configuredScore: 1,
|
|
115
|
+
unconfiguredScore: 0,
|
|
116
|
+
includeStatusLine: true,
|
|
117
|
+
resolveConfigured: ({ cfg, accountId }) => resolveAccount({
|
|
118
|
+
cfg,
|
|
119
|
+
accountId
|
|
120
|
+
}).configured,
|
|
121
|
+
resolveExtraStatusLines: ({ cfg }) => {
|
|
122
|
+
return [`Relays: ${resolveAccount({ cfg }).relays.length || DEFAULT_RELAYS.length}`];
|
|
123
|
+
}
|
|
96
124
|
});
|
|
97
125
|
}
|
|
98
126
|
//#endregion
|
|
99
|
-
export {
|
|
127
|
+
export { parseRelayUrls as a, createNostrSetupStatus as i, createNostrSetupAdapter as n, resolveNostrPrivateKey as o, createNostrSetupContract as r, DEFAULT_RELAYS 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-DAhyNOcb.js";
|
|
2
2
|
export { nostrSetupAdapter, nostrSetupWizard };
|
package/dist/setup-plugin-api.js
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
|
-
import { i as buildChannelConfigSchema, t as NostrConfigSchema } from "./config-schema-
|
|
2
|
-
import {
|
|
1
|
+
import { i as buildChannelConfigSchema, t as NostrConfigSchema } from "./config-schema-CkYd8ACn.js";
|
|
2
|
+
import { i as createNostrSetupStatus, n as createNostrSetupAdapter, o as resolveNostrPrivateKey, r as createNostrSetupContract, s as DEFAULT_RELAYS } from "./setup-adapter-DLthHa2q.js";
|
|
3
3
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
4
|
-
import { DEFAULT_ACCOUNT_ID, createDelegatedSetupWizardProxy
|
|
4
|
+
import { DEFAULT_ACCOUNT_ID, createDelegatedSetupWizardProxy } from "openclaw/plugin-sdk/setup-runtime";
|
|
5
5
|
//#region extensions/nostr/src/channel.setup.ts
|
|
6
|
-
const t = createSetupTranslator();
|
|
7
6
|
const channel = "nostr";
|
|
8
7
|
function getNostrConfig(cfg) {
|
|
9
8
|
return cfg.channels?.nostr;
|
|
10
9
|
}
|
|
11
|
-
function listSetupNostrAccountIds(cfg) {
|
|
12
|
-
const nostrCfg = getNostrConfig(cfg);
|
|
13
|
-
if (!(typeof nostrCfg?.privateKey === "string" ? nostrCfg.privateKey.trim() : "")) return [];
|
|
14
|
-
return [resolveDefaultSetupNostrAccountId(cfg)];
|
|
15
|
-
}
|
|
16
10
|
function resolveDefaultSetupNostrAccountId(cfg) {
|
|
17
11
|
const configured = getNostrConfig(cfg)?.defaultAccount;
|
|
18
12
|
return typeof configured === "string" && configured.trim() ? configured.trim() : DEFAULT_ACCOUNT_ID;
|
|
@@ -20,7 +14,7 @@ function resolveDefaultSetupNostrAccountId(cfg) {
|
|
|
20
14
|
function resolveSetupNostrAccount(params) {
|
|
21
15
|
const nostrCfg = getNostrConfig(params.cfg);
|
|
22
16
|
const accountId = params.accountId?.trim() || resolveDefaultSetupNostrAccountId(params.cfg);
|
|
23
|
-
const privateKey =
|
|
17
|
+
const privateKey = resolveNostrPrivateKey(nostrCfg?.privateKey);
|
|
24
18
|
const configured = Boolean(privateKey);
|
|
25
19
|
return {
|
|
26
20
|
accountId,
|
|
@@ -42,34 +36,10 @@ function resolveSetupNostrAccount(params) {
|
|
|
42
36
|
}
|
|
43
37
|
};
|
|
44
38
|
}
|
|
45
|
-
function looksLikeNostrPrivateKey(privateKey) {
|
|
46
|
-
return privateKey.startsWith("nsec1") || privateKey.startsWith("NSEC1") || /^[0-9a-fA-F]{64}$/.test(privateKey);
|
|
47
|
-
}
|
|
48
|
-
const nostrSetupAdapter = createNostrSetupAdapter({
|
|
49
|
-
resolveAccountId: (cfg, accountId) => accountId?.trim() || resolveDefaultSetupNostrAccountId(cfg),
|
|
50
|
-
validatePrivateKey: looksLikeNostrPrivateKey
|
|
51
|
-
});
|
|
52
|
-
const nostrSetupContract = createNostrSetupContract(nostrSetupAdapter);
|
|
53
39
|
const nostrSetupWizard = createDelegatedSetupWizardProxy({
|
|
54
40
|
channel,
|
|
55
|
-
loadWizard: async () => (await import("./setup-surface-
|
|
56
|
-
status:
|
|
57
|
-
channelLabel: "Nostr",
|
|
58
|
-
configuredLabel: t("wizard.channels.statusConfigured"),
|
|
59
|
-
unconfiguredLabel: t("wizard.channels.statusNeedsPrivateKey"),
|
|
60
|
-
configuredHint: t("wizard.channels.statusConfigured"),
|
|
61
|
-
unconfiguredHint: t("wizard.channels.statusNeedsPrivateKey"),
|
|
62
|
-
configuredScore: 1,
|
|
63
|
-
unconfiguredScore: 0,
|
|
64
|
-
includeStatusLine: true,
|
|
65
|
-
resolveConfigured: ({ cfg, accountId }) => resolveSetupNostrAccount({
|
|
66
|
-
cfg,
|
|
67
|
-
accountId
|
|
68
|
-
}).configured,
|
|
69
|
-
resolveExtraStatusLines: ({ cfg }) => {
|
|
70
|
-
return [`Relays: ${resolveSetupNostrAccount({ cfg }).relays.length || DEFAULT_RELAYS.length}`];
|
|
71
|
-
}
|
|
72
|
-
}) },
|
|
41
|
+
loadWizard: async () => (await import("./setup-surface-DAhyNOcb.js").then((n) => n.i)).nostrSetupWizard,
|
|
42
|
+
status: createNostrSetupStatus(resolveSetupNostrAccount),
|
|
73
43
|
resolveShouldPromptAccountIds: () => false,
|
|
74
44
|
delegatePrepare: true,
|
|
75
45
|
delegateFinalize: true
|
|
@@ -91,11 +61,13 @@ const nostrSetupPlugin = {
|
|
|
91
61
|
},
|
|
92
62
|
reload: { configPrefixes: ["channels.nostr"] },
|
|
93
63
|
configSchema: buildChannelConfigSchema(NostrConfigSchema),
|
|
94
|
-
|
|
95
|
-
|
|
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
|
+
})),
|
|
96
68
|
setupWizard: nostrSetupWizard,
|
|
97
69
|
config: {
|
|
98
|
-
listAccountIds:
|
|
70
|
+
listAccountIds: (cfg) => resolveSetupNostrAccount({ cfg }).configured ? [resolveDefaultSetupNostrAccountId(cfg)] : [],
|
|
99
71
|
resolveAccount: (cfg, accountId) => resolveSetupNostrAccount({
|
|
100
72
|
cfg,
|
|
101
73
|
accountId
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as parseRelayUrls, i as createNostrSetupStatus, n as createNostrSetupAdapter, o as resolveNostrPrivateKey, r as createNostrSetupContract, s as DEFAULT_RELAYS, t as buildNostrSetupPatch } from "./setup-adapter-DLthHa2q.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
5
|
import { getPublicKey, nip19 } from "nostr-tools";
|
|
6
6
|
import { DEFAULT_ACCOUNT_ID, normalizeAccountId, normalizeOptionalAccountId } from "openclaw/plugin-sdk/account-id";
|
|
7
7
|
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1 } from "openclaw/plugin-sdk/routing";
|
|
8
|
-
import { createSetupTranslator,
|
|
8
|
+
import { createSetupTranslator, createTopLevelChannelDmPolicy, createTopLevelChannelParsedAllowFromPrompt, defineTokenCredential, formatDocsLink, mergeAllowFromEntries, parseSetupEntriesWithParser, patchTopLevelChannelConfigSection, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
|
|
9
9
|
//#region \0rolldown/runtime.js
|
|
10
10
|
var __defProp = Object.defineProperty;
|
|
11
11
|
var __exportAll = (all, no_symbols) => {
|
|
@@ -59,7 +59,7 @@ const { listAccountIds: listNostrAccountIds, resolveDefaultAccountId: resolveDef
|
|
|
59
59
|
fallbackAccountIdWhenEmpty: false,
|
|
60
60
|
resolveImplicitAccountId: (cfg) => {
|
|
61
61
|
const account = cfg.channels?.nostr;
|
|
62
|
-
return
|
|
62
|
+
return resolveNostrPrivateKey(account?.privateKey) ? normalizeOptionalAccountId(account?.defaultAccount) ?? DEFAULT_ACCOUNT_ID : void 0;
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
65
|
/**
|
|
@@ -69,7 +69,7 @@ function resolveNostrAccount(opts) {
|
|
|
69
69
|
const accountId = normalizeAccountId(opts.accountId ?? resolveDefaultNostrAccountId(opts.cfg));
|
|
70
70
|
const nostrCfg = opts.cfg.channels?.nostr;
|
|
71
71
|
const baseEnabled = nostrCfg?.enabled !== false;
|
|
72
|
-
const privateKey =
|
|
72
|
+
const privateKey = resolveNostrPrivateKey(nostrCfg?.privateKey);
|
|
73
73
|
const configured = Boolean(privateKey);
|
|
74
74
|
let publicKey = "";
|
|
75
75
|
if (privateKey) try {
|
|
@@ -162,20 +162,7 @@ const nostrSetupWizard = {
|
|
|
162
162
|
channel,
|
|
163
163
|
resolveAccountIdForConfigure: ({ accountOverride, defaultAccountId }) => accountOverride?.trim() || defaultAccountId,
|
|
164
164
|
resolveShouldPromptAccountIds: () => false,
|
|
165
|
-
status:
|
|
166
|
-
channelLabel: "Nostr",
|
|
167
|
-
configuredLabel: t("wizard.channels.statusConfigured"),
|
|
168
|
-
unconfiguredLabel: t("wizard.channels.statusNeedsPrivateKey"),
|
|
169
|
-
configuredHint: t("wizard.channels.statusConfigured"),
|
|
170
|
-
unconfiguredHint: t("wizard.channels.statusNeedsPrivateKey"),
|
|
171
|
-
configuredScore: 1,
|
|
172
|
-
unconfiguredScore: 0,
|
|
173
|
-
includeStatusLine: true,
|
|
174
|
-
resolveConfigured: ({ cfg }) => resolveNostrAccount({ cfg }).configured,
|
|
175
|
-
resolveExtraStatusLines: ({ cfg }) => {
|
|
176
|
-
return [`Relays: ${resolveNostrAccount({ cfg }).relays.length || DEFAULT_RELAYS.length}`];
|
|
177
|
-
}
|
|
178
|
-
}),
|
|
165
|
+
status: createNostrSetupStatus(resolveNostrAccount),
|
|
179
166
|
introNote: {
|
|
180
167
|
title: t("wizard.nostr.setupTitle"),
|
|
181
168
|
lines: NOSTR_SETUP_HELP_LINES
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "nostr",
|
|
3
|
+
"doctorContract": {
|
|
4
|
+
"stateMigrations": true
|
|
5
|
+
},
|
|
3
6
|
"name": "Nostr",
|
|
4
7
|
"description": "OpenClaw Nostr channel plugin for NIP-04 encrypted direct messages.",
|
|
5
8
|
"activation": {
|
|
@@ -28,6 +31,9 @@
|
|
|
28
31
|
"enabled": {
|
|
29
32
|
"type": "boolean"
|
|
30
33
|
},
|
|
34
|
+
"configWrites": {
|
|
35
|
+
"type": "boolean"
|
|
36
|
+
},
|
|
31
37
|
"markdown": {
|
|
32
38
|
"type": "object",
|
|
33
39
|
"properties": {
|
|
@@ -73,6 +79,29 @@
|
|
|
73
79
|
],
|
|
74
80
|
"additionalProperties": false
|
|
75
81
|
},
|
|
82
|
+
{
|
|
83
|
+
"type": "object",
|
|
84
|
+
"properties": {
|
|
85
|
+
"source": {
|
|
86
|
+
"type": "string",
|
|
87
|
+
"const": "store"
|
|
88
|
+
},
|
|
89
|
+
"provider": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"pattern": "^[a-z][a-z0-9_-]{0,63}$"
|
|
92
|
+
},
|
|
93
|
+
"id": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"pattern": "^[A-Z][A-Z0-9_]{0,127}$"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"required": [
|
|
99
|
+
"source",
|
|
100
|
+
"provider",
|
|
101
|
+
"id"
|
|
102
|
+
],
|
|
103
|
+
"additionalProperties": false
|
|
104
|
+
},
|
|
76
105
|
{
|
|
77
106
|
"type": "object",
|
|
78
107
|
"properties": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/nostr",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.8.1-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.
|
|
15
|
+
"openclaw": ">=2026.8.1-beta.2"
|
|
16
16
|
},
|
|
17
17
|
"peerDependenciesMeta": {
|
|
18
18
|
"openclaw": {
|
|
@@ -65,7 +65,10 @@
|
|
|
65
65
|
"cli": {
|
|
66
66
|
"flags": "--use-env",
|
|
67
67
|
"description": "Use NOSTR_PRIVATE_KEY"
|
|
68
|
-
}
|
|
68
|
+
},
|
|
69
|
+
"envVars": [
|
|
70
|
+
"NOSTR_PRIVATE_KEY"
|
|
71
|
+
]
|
|
69
72
|
}
|
|
70
73
|
]
|
|
71
74
|
}
|
|
@@ -76,10 +79,10 @@
|
|
|
76
79
|
"minHostVersion": ">=2026.4.10"
|
|
77
80
|
},
|
|
78
81
|
"compat": {
|
|
79
|
-
"pluginApi": ">=2026.
|
|
82
|
+
"pluginApi": ">=2026.8.1-beta.2"
|
|
80
83
|
},
|
|
81
84
|
"build": {
|
|
82
|
-
"openclawVersion": "2026.
|
|
85
|
+
"openclawVersion": "2026.8.1-beta.2"
|
|
83
86
|
},
|
|
84
87
|
"release": {
|
|
85
88
|
"publishToClawHub": true,
|