@openclaw/discord 2026.10.1-beta.2 → 2026.10.5-beta.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/.setup/account-inspect-8cCu6uPG.mjs +31 -0
- package/dist/.setup/{accounts-DXHCL8Zm.mjs → accounts-ljrzXBJi.mjs} +49 -47
- package/dist/.setup/{channel-type-D1_b5UhU.mjs → allow-list-B_ToXtew.mjs} +40 -107
- package/dist/.setup/{api-_oznjffB.mjs → api-CtmE1OUN.mjs} +27 -33
- package/dist/.setup/{approval-handler.runtime-BilYSrRF.mjs → approval-handler.runtime-D7FoZSn0.mjs} +31 -54
- package/dist/.setup/{approval-message-updates-CgRwc2_Q.mjs → approval-message-updates-CIGByUcE.mjs} +2 -2
- package/dist/.setup/{audit-DtvzxONM.mjs → audit-zSawfbsN.mjs} +5 -8
- package/dist/.setup/{channel-z5lQMS_9.mjs → channel-DI7DMzu0.mjs} +138 -217
- package/dist/.setup/{channel-access-BRp3Y-rF.mjs → channel-access-DasWY_OV.mjs} +6 -7
- package/dist/.setup/{channel.setup-DBJtugJO.mjs → channel.setup-DdFVN1mr.mjs} +36 -65
- package/dist/.setup/{components-CzXLR3QH.mjs → components-HN9052L1.mjs} +124 -147
- package/dist/.setup/{config-schema-CsemBDpS.mjs → config-schema-_uBILpQf.mjs} +8 -4
- package/dist/.setup/{conversation-binding-route-Bi62ApSt.mjs → conversation-binding-route-DTjCBx-O.mjs} +1 -1
- package/dist/.setup/{directory-config-BH1LA-gi.mjs → directory-config-3iVub-3m.mjs} +1 -1
- package/dist/.setup/{directory-live-C9xz7IPm.mjs → directory-live-DLygQVtW.mjs} +18 -22
- package/dist/.setup/{discord-J7aRzq2Q.mjs → discord-BGqgx-yd.mjs} +686 -854
- package/dist/.setup/{doctor-DxSAngJq.mjs → doctor-DSrNJ7m2.mjs} +36 -47
- package/dist/.setup/{doctor-contract-Bg3NPAMw.mjs → doctor-contract-Bwv8EuQ_.mjs} +7 -16
- package/dist/.setup/{handle-action-DlmFX-_G.mjs → handle-action-CXH1h1tq.mjs} +26 -39
- package/dist/.setup/{handle-action.guild-admin-BnyqTczR.mjs → handle-action.guild-admin-CHKW6PIs.mjs} +25 -31
- package/dist/.setup/{live-policy-config-emmPNyh4.mjs → live-policy-config-BPoB3eQi.mjs} +1 -1
- package/dist/.setup/{message-handler-BNToPZrx.mjs → message-handler-Ii_etru1.mjs} +17 -22
- package/dist/.setup/{message-handler.preflight-D0BcCyI7.mjs → message-handler.preflight-C7YuSRl_.mjs} +85 -134
- package/dist/.setup/{message-handler.preflight-pluralkit-D1g3eq0B.mjs → message-handler.preflight-pluralkit-C3iAG--b.mjs} +9 -9
- package/dist/.setup/{message-handler.process-CThRmCWK.mjs → message-handler.process-ClgWYH6o.mjs} +239 -211
- package/dist/.setup/{outbound-adapter-BPq0c2wY.mjs → outbound-adapter-D8OOIuKn.mjs} +76 -115
- package/dist/.setup/{outbound-session-route-DGPPKA0z.mjs → outbound-session-route-B0Hpwn3Q.mjs} +61 -119
- package/dist/.setup/output-activity-uBpMSX75.mjs +11 -0
- package/dist/.setup/{pluralkit-a6_NLfH9.mjs → pluralkit-B64dfq_j.mjs} +3 -1
- package/dist/.setup/{preflight-audio-DHGIHEpv.mjs → preflight-audio-wWgsZG5F.mjs} +1 -5
- package/dist/.setup/{presence-cache-Dg3_dADn.mjs → presence-cache-DCeTsL73.mjs} +3 -6
- package/dist/.setup/{probe-DIRY8vh7.mjs → probe-D3P1x4aN.mjs} +11 -19
- package/dist/.setup/{provider-D2OKMo0f.mjs → provider-D9EzOfG8.mjs} +4003 -4916
- package/dist/.setup/{provider-session.runtime-BupCTZQv.mjs → provider-session.runtime-CsnRvddI.mjs} +5 -5
- package/dist/.setup/provider.runtime-BQVcM7Pg.mjs +2 -0
- package/dist/.setup/{realtime-session.runtime-D5RSC8Mm.mjs → realtime-session.runtime-CxGBk8H-.mjs} +84 -113
- package/dist/.setup/{receive-recovery-GqF2PUN_.mjs → receive-recovery-eVmK2_hl.mjs} +4 -14
- package/dist/.setup/resolve-allowlist-common-DNSsUQRF.mjs +66 -0
- package/dist/.setup/resolve-channels-UdT38DzU.mjs +173 -0
- package/dist/.setup/{resolve-users-CxLcDmM0.mjs → resolve-users-DnCsrXZ_.mjs} +12 -41
- package/dist/.setup/{runtime-CwUA0RLr.mjs → runtime-CRTkKU1G.mjs} +205 -316
- package/dist/.setup/{runtime-CerRBfaa.mjs → runtime-DPm3gZXk.mjs} +2 -2
- package/dist/.setup/{secret-config-contract-uOE2J7yM.mjs → secret-config-contract-CIsH7R3B.mjs} +9 -18
- package/dist/.setup/{security-audit-D42cp5N7.mjs → security-audit-BFT84Uny.mjs} +1 -2
- package/dist/.setup/security-contract-DNyyjTZZ.mjs +19 -0
- package/dist/.setup/{send-2X7m2Zmw.mjs → send-DbILKgcm.mjs} +194 -251
- package/dist/.setup/{send.components-RqvgmCs3.mjs → send.components-FxOS3CeP.mjs} +49 -65
- package/dist/.setup/{send.outbound-B4QHSEzm.mjs → send.outbound-_jx4Xpd3.mjs} +182 -206
- package/dist/.setup/{retry-BKzO25k4.mjs → send.receipt-BAlzXd8e.mjs} +155 -231
- package/dist/.setup/{send.shared-BQIUh6Vn.mjs → send.shared-CjQ4jbMA.mjs} +129 -185
- package/dist/.setup/{sender-identity-CooeYfAn.mjs → sender-identity-BNBvGt1l.mjs} +1 -1
- package/dist/.setup/setup-plugin-api-xfOFmxHP.mjs +3 -0
- package/dist/.setup/{shared-CIJn6AEC.mjs → shared-CestGDpq.mjs} +32 -22
- package/dist/.setup/{subagent-hooks-BYlVnxzy.mjs → subagent-hooks-CME7dSGf.mjs} +5 -10
- package/dist/.setup/{system-events-CQ3if_pS.mjs → system-events-BwwSDCw4.mjs} +2 -2
- package/dist/.setup/target-parsing-C-HyNxcE.mjs +48 -0
- package/dist/.setup/{target-resolver-Dzxf80Y3.mjs → target-resolver-Bse8fuTi.mjs} +11 -27
- package/dist/.setup/targets-DZJjkzwv.mjs +3 -0
- package/dist/.setup/{thread-bindings-yNNlcUWE.mjs → thread-bindings-0hPTSK14.mjs} +61 -52
- package/dist/.setup/{thread-bindings.manager-plk0zJAW.mjs → thread-bindings.manager-CdNa6UIs.mjs} +141 -214
- package/dist/.setup/{thread-bindings.session-updates-C9aKtVs6.mjs → thread-bindings.session-updates-DGSljVf6.mjs} +62 -101
- package/dist/.setup/threading-BKe3E3tp.mjs +246 -0
- package/dist/.setup/{timeouts-pun7VJ02.mjs → timeouts-CuNARfyw.mjs} +10 -18
- package/dist/.setup/{transcripts-source-CNWswry-.mjs → transcripts-source-0qQYVu2H.mjs} +62 -380
- package/dist/.setup/{voice-runtime-Bc75quiH.mjs → voice-runtime-QlZJ4sHv.mjs} +197 -353
- package/dist/account-inspect-api.js +1 -1
- package/dist/action-runtime-api.js +1 -1
- package/dist/activities-api.js +745 -1
- package/dist/api.js +19 -18
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/directory-contract-api.js +1 -1
- package/dist/doctor-contract-api.js +1 -1
- package/dist/index.js +9 -5
- package/dist/runtime-api.js +21 -20
- package/dist/secret-contract-api.js +1 -1
- package/dist/security-audit-contract-api.js +1 -1
- package/dist/security-contract-api.js +1 -1
- package/dist/setup-entry.js +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/src/voice/audio-worker.runtime.js +40 -59
- package/dist/subagent-hooks-api.js +1 -1
- package/dist/transcripts-source-api.js +1 -1
- package/node_modules/discord-api-types/_generated_/rest/v10/interfaces.d.ts +21 -0
- package/node_modules/discord-api-types/_generated_/rest/v10/interfaces.d.ts.map +1 -1
- package/node_modules/discord-api-types/_generated_/rest/v9/interfaces.d.ts +21 -0
- package/node_modules/discord-api-types/_generated_/rest/v9/interfaces.d.ts.map +1 -1
- package/node_modules/discord-api-types/globals.d.ts +6 -0
- package/node_modules/discord-api-types/globals.d.ts.map +1 -1
- package/node_modules/discord-api-types/globals.js +6 -0
- package/node_modules/discord-api-types/globals.js.map +1 -1
- package/node_modules/discord-api-types/package.json +3 -3
- package/node_modules/discord-api-types/payloads/index.mjs +1 -0
- package/node_modules/discord-api-types/payloads/v10/applicationIdentityProfile.d.ts +207 -0
- package/node_modules/discord-api-types/payloads/v10/applicationIdentityProfile.d.ts.map +1 -0
- package/node_modules/discord-api-types/payloads/v10/applicationIdentityProfile.js +25 -0
- package/node_modules/discord-api-types/payloads/v10/applicationIdentityProfile.js.map +1 -0
- package/node_modules/discord-api-types/payloads/v10/autoModeration.d.ts +1 -1
- package/node_modules/discord-api-types/payloads/v10/autoModeration.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v10/guild.d.ts +27 -23
- package/node_modules/discord-api-types/payloads/v10/guild.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v10/guild.js +26 -22
- package/node_modules/discord-api-types/payloads/v10/guild.js.map +1 -1
- package/node_modules/discord-api-types/payloads/v10/index.d.ts +1 -0
- package/node_modules/discord-api-types/payloads/v10/index.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v10/index.js +1 -0
- package/node_modules/discord-api-types/payloads/v10/index.js.map +1 -1
- package/node_modules/discord-api-types/payloads/v10/index.mjs +1 -0
- package/node_modules/discord-api-types/payloads/v9/applicationIdentityProfile.d.ts +207 -0
- package/node_modules/discord-api-types/payloads/v9/applicationIdentityProfile.d.ts.map +1 -0
- package/node_modules/discord-api-types/payloads/v9/applicationIdentityProfile.js +25 -0
- package/node_modules/discord-api-types/payloads/v9/applicationIdentityProfile.js.map +1 -0
- package/node_modules/discord-api-types/payloads/v9/autoModeration.d.ts +1 -1
- package/node_modules/discord-api-types/payloads/v9/autoModeration.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/guild.d.ts +27 -23
- package/node_modules/discord-api-types/payloads/v9/guild.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/guild.js +26 -22
- package/node_modules/discord-api-types/payloads/v9/guild.js.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/index.d.ts +1 -0
- package/node_modules/discord-api-types/payloads/v9/index.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/index.js +1 -0
- package/node_modules/discord-api-types/payloads/v9/index.js.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/index.mjs +1 -0
- package/node_modules/discord-api-types/rest/common.d.ts +2 -0
- package/node_modules/discord-api-types/rest/common.d.ts.map +1 -1
- package/node_modules/discord-api-types/rest/common.js +2 -0
- package/node_modules/discord-api-types/rest/common.js.map +1 -1
- package/node_modules/discord-api-types/rest/v10/applicationIdentityProfile.d.ts +70 -0
- package/node_modules/discord-api-types/rest/v10/applicationIdentityProfile.d.ts.map +1 -0
- package/node_modules/discord-api-types/rest/v10/applicationIdentityProfile.js +3 -0
- package/node_modules/discord-api-types/rest/v10/applicationIdentityProfile.js.map +1 -0
- package/node_modules/discord-api-types/rest/v10/index.d.ts +1 -0
- package/node_modules/discord-api-types/rest/v10/index.d.ts.map +1 -1
- package/node_modules/discord-api-types/rest/v10/index.js +29 -0
- package/node_modules/discord-api-types/rest/v10/index.js.map +1 -1
- package/node_modules/discord-api-types/rest/v10/interactions.d.ts +4 -2
- package/node_modules/discord-api-types/rest/v10/interactions.d.ts.map +1 -1
- package/node_modules/discord-api-types/rest/v10/user.d.ts +2 -2
- package/node_modules/discord-api-types/rest/v10/user.d.ts.map +1 -1
- package/node_modules/discord-api-types/rest/v9/applicationIdentityProfile.d.ts +70 -0
- package/node_modules/discord-api-types/rest/v9/applicationIdentityProfile.d.ts.map +1 -0
- package/node_modules/discord-api-types/rest/v9/applicationIdentityProfile.js +3 -0
- package/node_modules/discord-api-types/rest/v9/applicationIdentityProfile.js.map +1 -0
- package/node_modules/discord-api-types/rest/v9/index.d.ts +1 -0
- package/node_modules/discord-api-types/rest/v9/index.d.ts.map +1 -1
- package/node_modules/discord-api-types/rest/v9/index.js +29 -0
- package/node_modules/discord-api-types/rest/v9/index.js.map +1 -1
- package/node_modules/discord-api-types/rest/v9/interactions.d.ts +4 -2
- package/node_modules/discord-api-types/rest/v9/interactions.d.ts.map +1 -1
- package/node_modules/discord-api-types/rest/v9/user.d.ts +2 -2
- package/node_modules/discord-api-types/rest/v9/user.d.ts.map +1 -1
- package/node_modules/discord-api-types/v10.mjs +1 -0
- package/node_modules/discord-api-types/v9.mjs +1 -0
- package/node_modules/ws/lib/websocket.js +17 -3
- package/node_modules/ws/package.json +1 -1
- package/openclaw.plugin.json +3 -6
- package/package.json +7 -12
- package/dist/.setup/account-inspect-CjKqkDnH.mjs +0 -45
- package/dist/.setup/activities-api-BL_hJ0JQ.mjs +0 -789
- package/dist/.setup/provider.runtime-BaW_JnfU.mjs +0 -2
- package/dist/.setup/resolve-allowlist-common-DUYRrrVB.mjs +0 -27
- package/dist/.setup/resolve-channels--MUatisx.mjs +0 -246
- package/dist/.setup/security-contract-DSHk7I2w.mjs +0 -26
- package/dist/.setup/setup-plugin-api-nn_giXvZ.mjs +0 -3
- package/dist/.setup/targets-Lf8D55w-.mjs +0 -3
- package/dist/control-ui/2afbdab1d3aa65a789d8a3eba666f4b1ec5df07073538fe30d6cf32093a1fb2d/index.js +0 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { i as listDiscordAccountIds, n as inspectDiscordAccountConfig, v as resolveDiscordAccountAvailability } from "./accounts-ljrzXBJi.mjs";
|
|
2
|
+
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
|
3
|
+
import { normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
4
|
+
//#region extensions/discord/src/account-inspect.ts
|
|
5
|
+
function inspectDiscordAccountPrimary(params) {
|
|
6
|
+
return inspectDiscordAccountConfig(params, {
|
|
7
|
+
includeName: true,
|
|
8
|
+
resolveFallbackToken: (accountId) => {
|
|
9
|
+
const envToken = accountId === DEFAULT_ACCOUNT_ID ? normalizeSecretInputString(params.envToken ?? process.env.DISCORD_BOT_TOKEN) : void 0;
|
|
10
|
+
return {
|
|
11
|
+
token: envToken?.replace(/^Bot\s+/i, "") ?? "",
|
|
12
|
+
source: envToken ? "env" : "none"
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function inspectDiscordAccount(params) {
|
|
18
|
+
const account = inspectDiscordAccountPrimary(params);
|
|
19
|
+
return {
|
|
20
|
+
...account,
|
|
21
|
+
...resolveDiscordAccountAvailability({
|
|
22
|
+
account,
|
|
23
|
+
resolveAccounts: () => listDiscordAccountIds(params.cfg).map((accountId) => inspectDiscordAccountPrimary({
|
|
24
|
+
...params,
|
|
25
|
+
accountId
|
|
26
|
+
}))
|
|
27
|
+
})
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { inspectDiscordAccount as t };
|
|
@@ -1,23 +1,18 @@
|
|
|
1
|
-
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
|
-
import { createAccountActionGate, createAccountListHelpers } from "openclaw/plugin-sdk/account-helpers";
|
|
3
1
|
import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
2
|
+
import { hasConfiguredSecretInput, normalizeResolvedSecretInputString, normalizeSecretInputString, resolveSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
3
|
+
import { createAccountActionGate, createAccountListHelpers } from "openclaw/plugin-sdk/account-helpers";
|
|
4
4
|
import { mapAllowFromEntries, normalizeChannelDmPolicy } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
5
5
|
import { resolveConfiguredFromCredentialStatuses } from "openclaw/plugin-sdk/channel-status";
|
|
6
6
|
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, normalizeAccountId as normalizeAccountId$1, resolveAccountEntry } from "openclaw/plugin-sdk/routing";
|
|
7
|
-
import {
|
|
7
|
+
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
8
8
|
import { getRuntimeConfigSnapshot, getRuntimeConfigSourceSnapshot, selectApplicableRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
9
9
|
//#region extensions/discord/src/account-token-inspect.ts
|
|
10
10
|
function inspectDiscordConfiguredToken(value) {
|
|
11
11
|
const normalized = normalizeSecretInputString(value);
|
|
12
|
-
if (normalized) return {
|
|
13
|
-
token: normalized.replace(/^Bot\s+/i, ""),
|
|
12
|
+
if (normalized || hasConfiguredSecretInput(value)) return {
|
|
13
|
+
token: normalized ? normalized.replace(/^Bot\s+/i, "") : "",
|
|
14
14
|
tokenSource: "config",
|
|
15
|
-
tokenStatus: "available"
|
|
16
|
-
};
|
|
17
|
-
if (hasConfiguredSecretInput(value)) return {
|
|
18
|
-
token: "",
|
|
19
|
-
tokenSource: "config",
|
|
20
|
-
tokenStatus: "configured_unavailable"
|
|
15
|
+
tokenStatus: normalized ? "available" : "configured_unavailable"
|
|
21
16
|
};
|
|
22
17
|
return null;
|
|
23
18
|
}
|
|
@@ -106,8 +101,7 @@ function normalizeDiscordToken(raw, path) {
|
|
|
106
101
|
value: raw,
|
|
107
102
|
path
|
|
108
103
|
});
|
|
109
|
-
|
|
110
|
-
return stripDiscordBotPrefix(trimmed);
|
|
104
|
+
return trimmed ? stripDiscordBotPrefix(trimmed) : void 0;
|
|
111
105
|
}
|
|
112
106
|
function resolveDiscordTokenValue(params) {
|
|
113
107
|
const resolved = resolveSecretInputString({
|
|
@@ -116,12 +110,19 @@ function resolveDiscordTokenValue(params) {
|
|
|
116
110
|
defaults: params.cfg.secrets?.defaults,
|
|
117
111
|
mode: "inspect"
|
|
118
112
|
});
|
|
119
|
-
if (resolved.status === "available")
|
|
120
|
-
|
|
121
|
-
|
|
113
|
+
if (resolved.status === "available") {
|
|
114
|
+
const token = stripDiscordBotPrefix(resolved.value);
|
|
115
|
+
return token ? {
|
|
116
|
+
token,
|
|
117
|
+
source: "config",
|
|
118
|
+
tokenStatus: "available"
|
|
119
|
+
} : void 0;
|
|
120
|
+
}
|
|
121
|
+
if (resolved.status === "configured_unavailable") return {
|
|
122
|
+
token: "",
|
|
123
|
+
source: "config",
|
|
124
|
+
tokenStatus: "configured_unavailable"
|
|
122
125
|
};
|
|
123
|
-
if (resolved.status === "configured_unavailable") return { status: "configured_unavailable" };
|
|
124
|
-
return { status: "missing" };
|
|
125
126
|
}
|
|
126
127
|
function resolveDiscordToken(cfg, opts = {}) {
|
|
127
128
|
const selectedCfg = selectDiscordRuntimeConfig(cfg);
|
|
@@ -134,16 +135,7 @@ function resolveDiscordToken(cfg, opts = {}) {
|
|
|
134
135
|
value: accountCfg?.token,
|
|
135
136
|
path: `channels.discord.accounts.${accountId}.token`
|
|
136
137
|
});
|
|
137
|
-
if (accountToken
|
|
138
|
-
token: accountToken.value,
|
|
139
|
-
source: "config",
|
|
140
|
-
tokenStatus: "available"
|
|
141
|
-
};
|
|
142
|
-
if (accountToken.status === "configured_unavailable") return {
|
|
143
|
-
token: "",
|
|
144
|
-
source: "config",
|
|
145
|
-
tokenStatus: "configured_unavailable"
|
|
146
|
-
};
|
|
138
|
+
if (accountToken) return accountToken;
|
|
147
139
|
if (hasAccountToken) return {
|
|
148
140
|
token: "",
|
|
149
141
|
source: "none",
|
|
@@ -154,16 +146,7 @@ function resolveDiscordToken(cfg, opts = {}) {
|
|
|
154
146
|
value: discordCfg?.token,
|
|
155
147
|
path: "channels.discord.token"
|
|
156
148
|
});
|
|
157
|
-
if (configToken
|
|
158
|
-
token: configToken.value,
|
|
159
|
-
source: "config",
|
|
160
|
-
tokenStatus: "available"
|
|
161
|
-
};
|
|
162
|
-
if (configToken.status === "configured_unavailable") return {
|
|
163
|
-
token: "",
|
|
164
|
-
source: "config",
|
|
165
|
-
tokenStatus: "configured_unavailable"
|
|
166
|
-
};
|
|
149
|
+
if (configToken) return configToken;
|
|
167
150
|
const envToken = accountId === DEFAULT_ACCOUNT_ID$1 ? normalizeDiscordToken(opts.envToken ?? process.env.DISCORD_BOT_TOKEN, "DISCORD_BOT_TOKEN") : void 0;
|
|
168
151
|
if (envToken) return {
|
|
169
152
|
token: envToken,
|
|
@@ -178,7 +161,7 @@ function resolveDiscordToken(cfg, opts = {}) {
|
|
|
178
161
|
}
|
|
179
162
|
//#endregion
|
|
180
163
|
//#region extensions/discord/src/accounts.ts
|
|
181
|
-
const { listAccountIds, resolveDefaultAccountId, resolveAccountConfig: mergeDiscordAccountConfig } = createAccountListHelpers("discord", {
|
|
164
|
+
const { listAccountIds: listDiscordAccountIds, resolveDefaultAccountId: resolveDefaultDiscordAccountId, resolveAccountConfig: mergeDiscordAccountConfig } = createAccountListHelpers("discord", {
|
|
182
165
|
implicitDefaultAccount: {
|
|
183
166
|
channelKeys: ["token"],
|
|
184
167
|
envVars: ["DISCORD_BOT_TOKEN"]
|
|
@@ -189,29 +172,48 @@ const { listAccountIds, resolveDefaultAccountId, resolveAccountConfig: mergeDisc
|
|
|
189
172
|
"botLoopProtection"
|
|
190
173
|
]
|
|
191
174
|
});
|
|
192
|
-
const listDiscordAccountIds = listAccountIds;
|
|
193
|
-
const resolveDefaultDiscordAccountId = resolveDefaultAccountId;
|
|
194
175
|
function resolveDiscordAccountConfig(cfg, accountId) {
|
|
195
176
|
return resolveAccountEntry(cfg.channels?.discord?.accounts, accountId);
|
|
196
177
|
}
|
|
197
|
-
function
|
|
178
|
+
function inspectDiscordAccountConfig(params, options) {
|
|
198
179
|
const accountId = normalizeAccountId(params.accountId ?? resolveDefaultDiscordAccountId(params.cfg));
|
|
180
|
+
const config = mergeDiscordAccountConfig(params.cfg, accountId);
|
|
181
|
+
const enabled = params.cfg.channels?.discord?.enabled !== false && config.enabled !== false;
|
|
199
182
|
const accountConfig = resolveDiscordAccountConfig(params.cfg, accountId);
|
|
183
|
+
const hasAccountToken = Boolean(accountConfig && Object.hasOwn(accountConfig, "token"));
|
|
184
|
+
return inspectDiscordAccountTokenState({
|
|
185
|
+
base: {
|
|
186
|
+
accountId,
|
|
187
|
+
enabled,
|
|
188
|
+
...options.includeName ? { name: normalizeOptionalString(config.name) } : {}
|
|
189
|
+
},
|
|
190
|
+
config,
|
|
191
|
+
accountToken: accountConfig?.token,
|
|
192
|
+
hasAccountToken,
|
|
193
|
+
channelToken: params.cfg.channels?.discord?.token,
|
|
194
|
+
resolveFallbackToken: () => options.resolveFallbackToken(accountId)
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function readConfiguredAccount(params) {
|
|
198
|
+
const accountId = normalizeAccountId(params.accountId ?? resolveDefaultDiscordAccountId(params.cfg));
|
|
199
|
+
return resolveDiscordAccountConfig(params.cfg, accountId);
|
|
200
|
+
}
|
|
201
|
+
function resolveDiscordAccountAllowFrom(params) {
|
|
202
|
+
const accountConfig = readConfiguredAccount(params);
|
|
200
203
|
const rootConfig = params.cfg.channels?.discord;
|
|
201
204
|
const allowFrom = accountConfig?.allowFrom ?? rootConfig?.allowFrom;
|
|
202
205
|
return allowFrom ? mapAllowFromEntries(allowFrom) : void 0;
|
|
203
206
|
}
|
|
204
207
|
function resolveDiscordAccountDmPolicy(params) {
|
|
205
|
-
const
|
|
206
|
-
const accountConfig = resolveDiscordAccountConfig(params.cfg, accountId);
|
|
208
|
+
const accountConfig = readConfiguredAccount(params);
|
|
207
209
|
const rootConfig = params.cfg.channels?.discord;
|
|
208
210
|
return normalizeChannelDmPolicy(accountConfig?.dmPolicy ?? rootConfig?.dmPolicy ?? "pairing");
|
|
209
211
|
}
|
|
210
212
|
function createDiscordActionGate(params) {
|
|
211
|
-
const
|
|
213
|
+
const accountConfig = readConfiguredAccount(params);
|
|
212
214
|
return createAccountActionGate({
|
|
213
215
|
baseActions: params.cfg.channels?.discord?.actions,
|
|
214
|
-
accountActions:
|
|
216
|
+
accountActions: accountConfig?.actions
|
|
215
217
|
});
|
|
216
218
|
}
|
|
217
219
|
function resolveDiscordAccount(params) {
|
|
@@ -267,4 +269,4 @@ function listDiscordStartupAccountIds(cfg) {
|
|
|
267
269
|
return [defaultAccountId, ...startupAccountIds.filter((candidateId) => candidateId !== defaultAccountId)];
|
|
268
270
|
}
|
|
269
271
|
//#endregion
|
|
270
|
-
export {
|
|
272
|
+
export { selectDiscordActivitiesRuntimeConfig as _, listDiscordStartupAccountIds as a, resolveDefaultDiscordAccountId as c, resolveDiscordAccountConfig as d, resolveDiscordAccountDisabledReason as f, resolveDiscordToken as g, normalizeDiscordToken as h, listDiscordAccountIds as i, resolveDiscordAccount as l, resolveDiscordMaxLinesPerMessage as m, inspectDiscordAccountConfig as n, listEnabledDiscordAccounts as o, resolveDiscordAccountDmPolicy as p, isDiscordAccountEnabledForRuntime as r, mergeDiscordAccountConfig as s, createDiscordActionGate as t, resolveDiscordAccountAllowFrom as u, resolveDiscordAccountAvailability as v };
|
|
@@ -5,6 +5,11 @@ import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtim
|
|
|
5
5
|
import { fetchWithSsrFGuard, isBlockedHostnameOrIp, isLoopbackHost } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
6
6
|
import { buildChannelKeyCandidates, normalizeChannelSlug, resolveChannelEntryMatchWithFallback, resolveChannelMatchConfig } from "openclaw/plugin-sdk/channel-targets";
|
|
7
7
|
import { resolveAllowlistMatchByCandidates } from "openclaw/plugin-sdk/allow-from";
|
|
8
|
+
//#region extensions/discord/src/channel-type.ts
|
|
9
|
+
function isDiscordThreadChannelType(channelType) {
|
|
10
|
+
return channelType === ChannelType.AnnouncementThread || channelType === ChannelType.PublicThread || channelType === ChannelType.PrivateThread;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
8
13
|
//#region extensions/discord/src/endpoint-runtime.ts
|
|
9
14
|
const DISCORD_ENDPOINT_RESPONSE_MAX_BYTES = 8388608;
|
|
10
15
|
const DISCORD_API_URL_ENV = "DISCORD_API_URL";
|
|
@@ -25,27 +30,16 @@ function normalizeRestApiBaseUrl(value) {
|
|
|
25
30
|
url.pathname = url.pathname.replace(/\/+$/u, "") || "/";
|
|
26
31
|
return url;
|
|
27
32
|
}
|
|
28
|
-
function normalizeGatewayOrigin(value) {
|
|
29
|
-
let url;
|
|
30
|
-
try {
|
|
31
|
-
url = new URL(value);
|
|
32
|
-
} catch {
|
|
33
|
-
throw new Error("Discord endpoint Gateway origin must be a valid URL");
|
|
34
|
-
}
|
|
35
|
-
if (url.protocol !== "wss:" && !(url.protocol === "ws:" && isLoopbackHost(url.hostname))) throw new Error("Discord endpoint Gateway origin must use WSS or loopback WS");
|
|
36
|
-
if (url.protocol === "wss:" && isBlockedHostnameOrIp(url.hostname)) throw new Error("Discord endpoint Gateway origin must not target a private/internal/special-use hostname or IP address");
|
|
37
|
-
if (url.username || url.password || url.hash || url.pathname !== "/" || url.search) throw new Error("Discord endpoint Gateway origin must be an origin without credentials, path, query, or fragment");
|
|
38
|
-
return url.origin;
|
|
39
|
-
}
|
|
40
33
|
function resolveDescriptor(apiUrl) {
|
|
41
34
|
const restApiBaseUrl = normalizeRestApiBaseUrl(apiUrl);
|
|
42
35
|
const gatewayBotUrl = new URL(`${restApiBaseUrl.pathname.replace(/\/+$/u, "")}/gateway/bot`, restApiBaseUrl.origin);
|
|
43
36
|
const gatewayOriginUrl = new URL(restApiBaseUrl.origin);
|
|
44
37
|
gatewayOriginUrl.protocol = gatewayOriginUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
38
|
+
if (gatewayOriginUrl.protocol === "wss:" && isBlockedHostnameOrIp(gatewayOriginUrl.hostname)) throw new Error("Discord endpoint Gateway origin must not target a private/internal/special-use hostname or IP address");
|
|
45
39
|
return Object.freeze({
|
|
46
40
|
restApiBaseUrl: restApiBaseUrl.toString().replace(/\/$/u, ""),
|
|
47
41
|
gatewayBotUrl: gatewayBotUrl.toString(),
|
|
48
|
-
gatewayOrigin:
|
|
42
|
+
gatewayOrigin: gatewayOriginUrl.origin
|
|
49
43
|
});
|
|
50
44
|
}
|
|
51
45
|
function isWithinRestApiBase(target, restApiBaseUrl) {
|
|
@@ -116,27 +110,22 @@ function getDiscordEndpointRuntime(env = process.env) {
|
|
|
116
110
|
});
|
|
117
111
|
}
|
|
118
112
|
function resolveDiscordEndpointMediaGuard(url, retainedRuntime) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (target.origin !== restOrigin) throw new Error("Discord endpoint media URL is outside the configured REST origin");
|
|
125
|
-
return {
|
|
126
|
-
maxRedirects: 0,
|
|
127
|
-
ssrfPolicy: {
|
|
128
|
-
allowedOrigins: [restOrigin],
|
|
129
|
-
hostnameAllowlist: [target.hostname]
|
|
130
|
-
}
|
|
131
|
-
};
|
|
113
|
+
const guard = resolveEndpointResourceGuard(url, "media", retainedRuntime);
|
|
114
|
+
return guard ? {
|
|
115
|
+
maxRedirects: guard.maxRedirects,
|
|
116
|
+
ssrfPolicy: guard.policy
|
|
117
|
+
} : void 0;
|
|
132
118
|
}
|
|
133
119
|
function resolveDiscordEndpointAttachmentGuard(url, retainedRuntime) {
|
|
120
|
+
return resolveEndpointResourceGuard(url, "attachment upload", retainedRuntime);
|
|
121
|
+
}
|
|
122
|
+
function resolveEndpointResourceGuard(url, kind, retainedRuntime) {
|
|
134
123
|
if (retainedRuntime === null) return;
|
|
135
124
|
const runtime = retainedRuntime ?? getDiscordEndpointRuntime();
|
|
136
125
|
if (!runtime) return;
|
|
137
|
-
const target = parseHttpAnchor(url,
|
|
126
|
+
const target = parseHttpAnchor(url, `Discord endpoint ${kind} URL`);
|
|
138
127
|
const restOrigin = new URL(runtime.descriptor.restApiBaseUrl).origin;
|
|
139
|
-
if (target.origin !== restOrigin) throw new Error(
|
|
128
|
+
if (target.origin !== restOrigin) throw new Error(`Discord endpoint ${kind} URL is outside the configured REST origin`);
|
|
140
129
|
return {
|
|
141
130
|
maxRedirects: 0,
|
|
142
131
|
policy: {
|
|
@@ -229,19 +218,6 @@ function normalizeDiscordSlug(value) {
|
|
|
229
218
|
function normalizeDiscordDisplaySlug(value) {
|
|
230
219
|
return normalizeLowercaseStringOrEmpty(value).normalize("NFC").replace(/^#/, "").replace(/[\s_]+/g, "-").replace(/[^\p{L}\p{M}\p{N}-]+/gu, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "");
|
|
231
220
|
}
|
|
232
|
-
function resolveDiscordAllowListNameMatch(list, candidate) {
|
|
233
|
-
const nameSlug = candidate.name ? normalizeDiscordSlug(candidate.name) : "";
|
|
234
|
-
if (nameSlug && list.names.has(nameSlug)) return {
|
|
235
|
-
matchKey: nameSlug,
|
|
236
|
-
matchSource: "name"
|
|
237
|
-
};
|
|
238
|
-
const tagSlug = candidate.tag ? normalizeDiscordSlug(candidate.tag) : "";
|
|
239
|
-
if (tagSlug && list.names.has(tagSlug)) return {
|
|
240
|
-
matchKey: tagSlug,
|
|
241
|
-
matchSource: "tag"
|
|
242
|
-
};
|
|
243
|
-
return null;
|
|
244
|
-
}
|
|
245
221
|
function allowListMatches(list, candidate, params) {
|
|
246
222
|
return resolveDiscordAllowListMatch({
|
|
247
223
|
allowList: list,
|
|
@@ -261,11 +237,13 @@ function resolveDiscordAllowListMatch(params) {
|
|
|
261
237
|
matchKey: candidate.id,
|
|
262
238
|
matchSource: "id"
|
|
263
239
|
};
|
|
264
|
-
if (params.allowNameMatching === true) {
|
|
265
|
-
const
|
|
266
|
-
|
|
240
|
+
if (params.allowNameMatching === true) for (const matchSource of ["name", "tag"]) {
|
|
241
|
+
const value = candidate[matchSource];
|
|
242
|
+
const matchKey = value ? normalizeDiscordSlug(value) : "";
|
|
243
|
+
if (matchKey && allowList.names.has(matchKey)) return {
|
|
267
244
|
allowed: true,
|
|
268
|
-
|
|
245
|
+
matchKey,
|
|
246
|
+
matchSource
|
|
269
247
|
};
|
|
270
248
|
}
|
|
271
249
|
return { allowed: false };
|
|
@@ -283,27 +261,16 @@ function resolveDiscordUserAllowed(params) {
|
|
|
283
261
|
tag: params.userTag
|
|
284
262
|
}, { allowNameMatching: params.allowNameMatching });
|
|
285
263
|
}
|
|
286
|
-
function resolveDiscordRoleAllowed(params) {
|
|
287
|
-
const allowList = normalizeDiscordAllowList(params.allowList, ["role:"]);
|
|
288
|
-
if (!allowList) return true;
|
|
289
|
-
if (allowList.allowAll) return true;
|
|
290
|
-
return params.memberRoleIds.some((roleId) => allowList.ids.has(roleId));
|
|
291
|
-
}
|
|
292
264
|
function resolveDiscordMemberAllowed(params) {
|
|
293
265
|
const hasUserRestriction = Array.isArray(params.userAllowList) && params.userAllowList.length > 0;
|
|
294
266
|
const hasRoleRestriction = Array.isArray(params.roleAllowList) && params.roleAllowList.length > 0;
|
|
295
267
|
if (!hasUserRestriction && !hasRoleRestriction) return true;
|
|
296
268
|
const userOk = hasUserRestriction ? resolveDiscordUserAllowed({
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
userName: params.userName,
|
|
300
|
-
userTag: params.userTag,
|
|
301
|
-
allowNameMatching: params.allowNameMatching
|
|
302
|
-
}) : false;
|
|
303
|
-
const roleOk = hasRoleRestriction ? resolveDiscordRoleAllowed({
|
|
304
|
-
allowList: params.roleAllowList,
|
|
305
|
-
memberRoleIds: params.memberRoleIds
|
|
269
|
+
...params,
|
|
270
|
+
allowList: params.userAllowList
|
|
306
271
|
}) : false;
|
|
272
|
+
const roles = hasRoleRestriction ? normalizeDiscordAllowList(params.roleAllowList, ["role:"]) : null;
|
|
273
|
+
const roleOk = Boolean(roles && (roles.allowAll || params.memberRoleIds.some((roleId) => roles.ids.has(roleId))));
|
|
307
274
|
return userOk || roleOk;
|
|
308
275
|
}
|
|
309
276
|
function resolveDiscordMemberAccessState(params) {
|
|
@@ -335,11 +302,7 @@ function resolveDiscordOwnerAllowFrom(params) {
|
|
|
335
302
|
if (!allowList) return;
|
|
336
303
|
const match = resolveDiscordAllowListMatch({
|
|
337
304
|
allowList,
|
|
338
|
-
candidate:
|
|
339
|
-
id: params.sender.id,
|
|
340
|
-
name: params.sender.name,
|
|
341
|
-
tag: params.sender.tag
|
|
342
|
-
},
|
|
305
|
+
candidate: params.sender,
|
|
343
306
|
allowNameMatching: params.allowNameMatching
|
|
344
307
|
});
|
|
345
308
|
if (!match.allowed || !match.matchKey || match.matchKey === "*") return;
|
|
@@ -374,33 +337,12 @@ function resolveDiscordGuildEntry(params) {
|
|
|
374
337
|
};
|
|
375
338
|
if (!guild) return null;
|
|
376
339
|
const slug = normalizeDiscordSlug(guild.name ?? "");
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
...
|
|
380
|
-
id: guildId ?? guild.id,
|
|
381
|
-
slug: slug || bySlug.slug
|
|
382
|
-
};
|
|
383
|
-
const wildcard = entries["*"];
|
|
384
|
-
if (wildcard) return {
|
|
385
|
-
...wildcard,
|
|
340
|
+
const byName = entries[slug] || entries["*"];
|
|
341
|
+
return byName ? {
|
|
342
|
+
...byName,
|
|
386
343
|
id: guildId ?? guild.id,
|
|
387
|
-
slug: slug ||
|
|
388
|
-
};
|
|
389
|
-
return null;
|
|
390
|
-
}
|
|
391
|
-
function buildDiscordChannelKeys(params) {
|
|
392
|
-
const allowNameMatch = params.allowNameMatch !== false;
|
|
393
|
-
return buildChannelKeyCandidates(params.id, allowNameMatch ? params.slug : void 0, allowNameMatch ? params.name : void 0);
|
|
394
|
-
}
|
|
395
|
-
function resolveDiscordChannelEntryMatch(channels, params, parentParams) {
|
|
396
|
-
const keys = buildDiscordChannelKeys(params);
|
|
397
|
-
const parentKeys = parentParams ? buildDiscordChannelKeys(parentParams) : void 0;
|
|
398
|
-
return resolveChannelEntryMatchWithFallback({
|
|
399
|
-
entries: channels,
|
|
400
|
-
keys,
|
|
401
|
-
parentKeys,
|
|
402
|
-
wildcardKey: "*"
|
|
403
|
-
});
|
|
344
|
+
slug: slug || byName.slug
|
|
345
|
+
} : null;
|
|
404
346
|
}
|
|
405
347
|
function hasConfiguredDiscordChannels(channels) {
|
|
406
348
|
return Boolean(channels && Object.keys(channels).length > 0);
|
|
@@ -435,16 +377,12 @@ function resolveDiscordChannelConfigWithFallback(params) {
|
|
|
435
377
|
const channels = guildInfo?.channels;
|
|
436
378
|
if (!hasConfiguredDiscordChannels(channels)) return null;
|
|
437
379
|
const resolvedParentSlug = parentSlug ?? (parentName ? normalizeDiscordSlug(parentName) : "");
|
|
438
|
-
const match =
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
}
|
|
444
|
-
id: parentId ?? "",
|
|
445
|
-
name: parentName,
|
|
446
|
-
slug: resolvedParentSlug
|
|
447
|
-
} : void 0);
|
|
380
|
+
const match = resolveChannelEntryMatchWithFallback({
|
|
381
|
+
entries: channels,
|
|
382
|
+
keys: buildChannelKeyCandidates(channelId, scope === "thread" ? void 0 : channelSlug, scope === "thread" ? void 0 : channelName),
|
|
383
|
+
parentKeys: parentId || parentName || parentSlug ? buildChannelKeyCandidates(parentId ?? "", resolvedParentSlug, parentName) : void 0,
|
|
384
|
+
wildcardKey: "*"
|
|
385
|
+
});
|
|
448
386
|
return resolveChannelMatchConfig(match, resolveDiscordChannelConfigEntry) ?? { allowed: false };
|
|
449
387
|
}
|
|
450
388
|
/** Boolean runtime API retained for plugins built against OpenClaw 2026.9.6. */
|
|
@@ -522,9 +460,4 @@ function shouldEmitDiscordReactionNotification(params) {
|
|
|
522
460
|
return false;
|
|
523
461
|
}
|
|
524
462
|
//#endregion
|
|
525
|
-
|
|
526
|
-
function isDiscordThreadChannelType(channelType) {
|
|
527
|
-
return channelType === ChannelType.AnnouncementThread || channelType === ChannelType.PublicThread || channelType === ChannelType.PrivateThread;
|
|
528
|
-
}
|
|
529
|
-
//#endregion
|
|
530
|
-
export { resolveDiscordEndpointMediaGuard as A, formatDiscordUserTag as C, assertDiscordEndpointGatewayUrl as D, parseDiscordRetryAfterBodySeconds as E, getDiscordEndpointRuntime as O, formatDiscordReactionEmoji as S, resolveTimestampMs as T, resolveDiscordOwnerAccess as _, normalizeDiscordAllowList as a, resolveGroupDmAllow as b, resolveDiscordAllowListMatch as c, resolveDiscordChannelPolicyCommandAuthorizer as d, resolveDiscordCommandAuthorized as f, resolveDiscordMentionPolicy as g, resolveDiscordMemberAllowed as h, isDiscordGroupAllowedByPolicy as i, resolveDiscordEndpointAttachmentGuard as k, resolveDiscordChannelConfig as l, resolveDiscordMemberAccessState as m, allowListMatches as n, normalizeDiscordDisplaySlug as o, resolveDiscordGuildEntry as p, hasConfiguredDiscordChannels as r, normalizeDiscordSlug as s, isDiscordThreadChannelType as t, resolveDiscordChannelConfigWithFallback as u, resolveDiscordOwnerAllowFrom as v, resolveDiscordSystemLocation as w, shouldEmitDiscordReactionNotification as x, resolveDiscordShouldRequireMention as y };
|
|
463
|
+
export { isDiscordThreadChannelType as A, resolveDiscordSystemLocation as C, getDiscordEndpointRuntime as D, assertDiscordEndpointGatewayUrl as E, resolveDiscordEndpointAttachmentGuard as O, formatDiscordUserTag as S, parseDiscordRetryAfterBodySeconds as T, resolveDiscordOwnerAllowFrom as _, normalizeDiscordDisplaySlug as a, shouldEmitDiscordReactionNotification as b, resolveDiscordChannelConfig as c, resolveDiscordCommandAuthorized as d, resolveDiscordGuildEntry as f, resolveDiscordOwnerAccess as g, resolveDiscordMentionPolicy as h, normalizeDiscordAllowList as i, resolveDiscordEndpointMediaGuard as k, resolveDiscordChannelConfigWithFallback as l, resolveDiscordMemberAllowed as m, hasConfiguredDiscordChannels as n, normalizeDiscordSlug as o, resolveDiscordMemberAccessState as p, isDiscordGroupAllowedByPolicy as r, resolveDiscordAllowListMatch as s, allowListMatches as t, resolveDiscordChannelPolicyCommandAuthorizer as u, resolveDiscordShouldRequireMention as v, resolveTimestampMs as w, formatDiscordReactionEmoji as x, resolveGroupDmAllow as y };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { D as getDiscordEndpointRuntime, T as parseDiscordRetryAfterBodySeconds } from "./allow-list-B_ToXtew.mjs";
|
|
2
|
+
import { sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
|
|
3
3
|
import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
4
|
-
import { captureChannelReadAuthority, resolveFetch } from "openclaw/plugin-sdk/fetch-runtime";
|
|
4
|
+
import { captureChannelReadAuthority, captureEffectAuthority, resolveFetch } from "openclaw/plugin-sdk/fetch-runtime";
|
|
5
5
|
import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
|
|
6
|
+
import { redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
|
|
6
7
|
import { parseRetryAfterHeaderSeconds, resolveRetryConfig, retryAsync } from "openclaw/plugin-sdk/retry-runtime";
|
|
7
8
|
import { readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
|
|
8
|
-
import { sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
|
|
9
9
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
10
10
|
//#region extensions/discord/src/error-body.ts
|
|
11
11
|
const DISCORD_RESPONSE_BODY_SUMMARY_MAX_CHARS = 240;
|
|
@@ -23,11 +23,10 @@ function summarizeDiscordResponseBody(body, opts = {}) {
|
|
|
23
23
|
return truncateUtf16Safe(redactToolPayloadText(summary), DISCORD_RESPONSE_BODY_SUMMARY_MAX_CHARS);
|
|
24
24
|
}
|
|
25
25
|
function isDiscordHtmlResponseBody(body, contentType) {
|
|
26
|
-
return /\bhtml\b/i.test(contentType ?? "") || /^\s
|
|
26
|
+
return /\bhtml\b/i.test(contentType ?? "") || /^\s*(?:<!doctype\s+html\b|<html\b)/i.test(body);
|
|
27
27
|
}
|
|
28
28
|
function isDiscordRateLimitResponseBody(body) {
|
|
29
|
-
|
|
30
|
-
return normalized.includes("error 1015") || normalized.includes("cloudflare") || normalized.includes("rate limit");
|
|
29
|
+
return /error 1015|cloudflare|rate limit/i.test(body);
|
|
31
30
|
}
|
|
32
31
|
//#endregion
|
|
33
32
|
//#region extensions/discord/src/api.ts
|
|
@@ -46,23 +45,21 @@ function parseDiscordApiErrorPayload(text) {
|
|
|
46
45
|
const trimmed = text.trim();
|
|
47
46
|
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return null;
|
|
48
47
|
try {
|
|
49
|
-
|
|
50
|
-
if (payload && typeof payload === "object") return payload;
|
|
48
|
+
return JSON.parse(trimmed);
|
|
51
49
|
} catch {
|
|
52
50
|
return null;
|
|
53
51
|
}
|
|
54
|
-
return null;
|
|
55
52
|
}
|
|
56
53
|
function parseRetryAfterSeconds(text, response) {
|
|
57
54
|
const payload = parseDiscordApiErrorPayload(text);
|
|
58
55
|
const retryAfter = parseDiscordRetryAfterBodySeconds(payload?.retry_after);
|
|
59
56
|
if (retryAfter !== void 0) return retryAfter;
|
|
60
57
|
const header = response.headers.get("Retry-After");
|
|
61
|
-
|
|
62
|
-
return parseRetryAfterHeaderSeconds(header);
|
|
58
|
+
return header ? parseRetryAfterHeaderSeconds(header) : void 0;
|
|
63
59
|
}
|
|
64
|
-
function formatRetryAfterSeconds(
|
|
65
|
-
|
|
60
|
+
function formatRetryAfterSeconds(raw) {
|
|
61
|
+
const value = parseDiscordRetryAfterBodySeconds(raw);
|
|
62
|
+
if (value === void 0) return;
|
|
66
63
|
return `${value < 10 ? value.toFixed(1) : Math.round(value).toString()}s`;
|
|
67
64
|
}
|
|
68
65
|
function formatDiscordApiErrorTextUntrusted(text, response) {
|
|
@@ -79,13 +76,9 @@ function formatDiscordApiErrorTextUntrusted(text, response) {
|
|
|
79
76
|
return summary;
|
|
80
77
|
}
|
|
81
78
|
const message = typeof payload.message === "string" && payload.message.trim() ? payload.message.trim() : "unknown error";
|
|
82
|
-
const retryAfter = formatRetryAfterSeconds(
|
|
79
|
+
const retryAfter = formatRetryAfterSeconds(payload.retry_after);
|
|
83
80
|
return retryAfter ? `${message} (retry after ${retryAfter})` : message;
|
|
84
81
|
}
|
|
85
|
-
function formatDiscordApiErrorText(text, response) {
|
|
86
|
-
const detail = formatDiscordApiErrorTextUntrusted(text, response);
|
|
87
|
-
return detail ? redactToolPayloadText(detail) : detail;
|
|
88
|
-
}
|
|
89
82
|
var DiscordApiError = class extends Error {
|
|
90
83
|
constructor(message, status, retryAfter) {
|
|
91
84
|
super(message);
|
|
@@ -93,13 +86,8 @@ var DiscordApiError = class extends Error {
|
|
|
93
86
|
this.retryAfter = retryAfter;
|
|
94
87
|
}
|
|
95
88
|
};
|
|
96
|
-
function getDiscordApiRetryAfterMs(err, retryConfig) {
|
|
97
|
-
if (!(err instanceof DiscordApiError) || typeof err.retryAfter !== "number") return;
|
|
98
|
-
return Math.min(Math.max(0, err.retryAfter * 1e3), retryConfig.maxDelayMs);
|
|
99
|
-
}
|
|
100
89
|
function normalizeDiscordRequestBody(body, headers) {
|
|
101
|
-
if (body === void 0) return;
|
|
102
|
-
if (typeof body === "string" || body instanceof Blob || body instanceof FormData || body instanceof URLSearchParams || body instanceof ArrayBuffer) return body;
|
|
90
|
+
if (body === void 0 || typeof body === "string" || body instanceof Blob || body instanceof FormData || body instanceof URLSearchParams || body instanceof ArrayBuffer) return body;
|
|
103
91
|
headers.set("Content-Type", headers.get("Content-Type") ?? "application/json");
|
|
104
92
|
return JSON.stringify(body);
|
|
105
93
|
}
|
|
@@ -118,6 +106,7 @@ function createDiscordRequestSignal(options) {
|
|
|
118
106
|
}
|
|
119
107
|
async function requestDiscord(path, token, options) {
|
|
120
108
|
const assertReadAuthority = captureChannelReadAuthority();
|
|
109
|
+
const effect = captureEffectAuthority();
|
|
121
110
|
const endpoint = options?.endpointRuntime === void 0 ? getDiscordEndpointRuntime() : options.endpointRuntime;
|
|
122
111
|
const fetchImpl = resolveFetch(endpoint ? (input, init) => endpoint.fetch(input, init, assertReadAuthority) : options?.fetcher ?? fetch);
|
|
123
112
|
if (!fetchImpl) throw new Error("fetch is not available");
|
|
@@ -129,15 +118,20 @@ async function requestDiscord(path, token, options) {
|
|
|
129
118
|
const requestSignal = createDiscordRequestSignal(options ?? {});
|
|
130
119
|
try {
|
|
131
120
|
assertReadAuthority?.();
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
121
|
+
const request = () => {
|
|
122
|
+
assertReadAuthority?.();
|
|
123
|
+
return fetchImpl(`${endpoint?.descriptor.restApiBaseUrl ?? DISCORD_API_BASE}${path}`, {
|
|
124
|
+
method: options?.method ?? (body === void 0 ? "GET" : "POST"),
|
|
125
|
+
headers,
|
|
126
|
+
body,
|
|
127
|
+
signal: requestSignal.signal
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
const res = endpoint ? await effect.run(request) : await effect.initiate(request);
|
|
138
131
|
if (!res.ok) {
|
|
139
132
|
const text = await readResponseTextLimited(res, DISCORD_API_ERROR_BODY_LIMIT_BYTES).catch(() => "");
|
|
140
|
-
const
|
|
133
|
+
const untrustedDetail = formatDiscordApiErrorTextUntrusted(text, res);
|
|
134
|
+
const detail = untrustedDetail ? redactToolPayloadText(untrustedDetail) : untrustedDetail;
|
|
141
135
|
const suffix = detail ? `: ${detail}` : "";
|
|
142
136
|
const retryAfter = res.status === 429 ? parseRetryAfterSeconds(text, res) ?? DISCORD_API_429_FALLBACK_RETRY_AFTER_SECONDS : void 0;
|
|
143
137
|
throw new DiscordApiError(`Discord API ${path} failed (${res.status})${suffix}`, res.status, retryAfter);
|
|
@@ -157,7 +151,7 @@ async function requestDiscord(path, token, options) {
|
|
|
157
151
|
...retryConfig,
|
|
158
152
|
label: options?.label ?? path,
|
|
159
153
|
shouldRetry: (err) => err instanceof DiscordApiError && err.status === 429,
|
|
160
|
-
retryAfterMs: (err) =>
|
|
154
|
+
retryAfterMs: (err) => err instanceof DiscordApiError && typeof err.retryAfter === "number" ? Math.min(Math.max(0, err.retryAfter * 1e3), retryConfig.maxDelayMs) : void 0,
|
|
161
155
|
sleep: (ms) => sleepWithAbort(ms, options?.signal)
|
|
162
156
|
});
|
|
163
157
|
}
|