@openclaw/discord 2026.9.8 → 2026.10.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.
Files changed (147) hide show
  1. package/README.md +7 -0
  2. package/dist/.setup/{account-inspect-De8hOUxG.mjs → account-inspect-CjKqkDnH.mjs} +2 -2
  3. package/dist/.setup/{accounts-ChaMcixG.mjs → accounts-DXHCL8Zm.mjs} +9 -32
  4. package/dist/.setup/{active-turn-thread-route-fmHl1HNd.mjs → active-turn-thread-route-C4tp9noA.mjs} +5 -9
  5. package/dist/.setup/{activities-api-tvbsU2e3.mjs → activities-api-BL_hJ0JQ.mjs} +15 -18
  6. package/dist/.setup/{api-DVbJwZVt.mjs → api-_oznjffB.mjs} +1 -1
  7. package/dist/.setup/{approval-handler.runtime-DxCK2Rux.mjs → approval-handler.runtime-BilYSrRF.mjs} +22 -61
  8. package/dist/.setup/{approval-message-updates-BKFqavHZ.mjs → approval-message-updates-CgRwc2_Q.mjs} +2 -2
  9. package/dist/.setup/{audit-CLg9I71N.mjs → audit-DtvzxONM.mjs} +4 -4
  10. package/dist/.setup/{channel-access-C12aDZ0p.mjs → channel-access-BRp3Y-rF.mjs} +4 -17
  11. package/dist/.setup/{channel-type-DRCrEMss.mjs → channel-type-D1_b5UhU.mjs} +12 -16
  12. package/dist/.setup/{channel-DxlUVU9t.mjs → channel-z5lQMS_9.mjs} +79 -75
  13. package/dist/.setup/{channel.setup-CRo1GjV7.mjs → channel.setup-DBJtugJO.mjs} +14 -34
  14. package/dist/.setup/{components-Cq1PvIpN.mjs → components-CzXLR3QH.mjs} +56 -72
  15. package/dist/.setup/{config-schema-oxELUSDx.mjs → config-schema-CsemBDpS.mjs} +6 -17
  16. package/dist/.setup/{conversation-binding-route-Caz_XuFH.mjs → conversation-binding-route-Bi62ApSt.mjs} +1 -1
  17. package/dist/.setup/{directory-config-esqNn0Eo.mjs → directory-config-BH1LA-gi.mjs} +1 -1
  18. package/dist/.setup/{directory-live-DtKRHuGV.mjs → directory-live-C9xz7IPm.mjs} +10 -13
  19. package/dist/.setup/{discord-0xJYfdDD.mjs → discord-J7aRzq2Q.mjs} +101 -381
  20. package/dist/.setup/{doctor-BCl1H5tl.mjs → doctor-DxSAngJq.mjs} +31 -70
  21. package/dist/.setup/doctor-contract-Bg3NPAMw.mjs +137 -0
  22. package/dist/.setup/{handle-action-CUvQWnE7.mjs → handle-action-DlmFX-_G.mjs} +10 -11
  23. package/dist/.setup/{handle-action.guild-admin-Df-8gVle.mjs → handle-action.guild-admin-BnyqTczR.mjs} +67 -129
  24. package/dist/.setup/{live-policy-config-8Pv20CHc.mjs → live-policy-config-emmPNyh4.mjs} +1 -1
  25. package/dist/.setup/{message-handler-B-Jk4oDk.mjs → message-handler-BNToPZrx.mjs} +7 -6
  26. package/dist/.setup/{message-handler.preflight-v-__NSDq.mjs → message-handler.preflight-D0BcCyI7.mjs} +13 -23
  27. package/dist/.setup/{message-handler.preflight-pluralkit-CWLUBVcx.mjs → message-handler.preflight-pluralkit-D1g3eq0B.mjs} +5 -8
  28. package/dist/.setup/{message-handler.process-BNFFuChn.mjs → message-handler.process-CThRmCWK.mjs} +57 -96
  29. package/dist/.setup/{outbound-adapter-BobT-kse.mjs → outbound-adapter-BPq0c2wY.mjs} +11 -17
  30. package/dist/.setup/{outbound-session-route-zVGxxceg.mjs → outbound-session-route-DGPPKA0z.mjs} +21 -46
  31. package/dist/.setup/{presence-cache-Di3H3DIU.mjs → presence-cache-Dg3_dADn.mjs} +2 -4
  32. package/dist/.setup/{probe-LYrIHlBF.mjs → probe-DIRY8vh7.mjs} +17 -27
  33. package/dist/.setup/{provider-B_G5hASF.mjs → provider-D2OKMo0f.mjs} +273 -446
  34. package/dist/.setup/{provider-session.runtime-BYlTBFD2.mjs → provider-session.runtime-BupCTZQv.mjs} +3 -3
  35. package/dist/.setup/provider.runtime-BaW_JnfU.mjs +2 -0
  36. package/dist/.setup/{realtime-session.runtime-oUd9DOcz.mjs → realtime-session.runtime-D5RSC8Mm.mjs} +6 -8
  37. package/dist/.setup/{receive-recovery-CHPOsnLc.mjs → receive-recovery-GqF2PUN_.mjs} +1 -4
  38. package/dist/.setup/{resolve-allowlist-common-DPdRggu5.mjs → resolve-allowlist-common-DUYRrrVB.mjs} +5 -9
  39. package/dist/.setup/{resolve-channels-BFPNRmVv.mjs → resolve-channels--MUatisx.mjs} +3 -3
  40. package/dist/.setup/{resolve-users-0-aBuCy3.mjs → resolve-users-CxLcDmM0.mjs} +6 -9
  41. package/dist/.setup/{retry-pz_cSha2.mjs → retry-BKzO25k4.mjs} +27 -51
  42. package/dist/.setup/{runtime-sUksZ--Q.mjs → runtime-CerRBfaa.mjs} +2 -2
  43. package/dist/.setup/{runtime-FN000lxA.mjs → runtime-CwUA0RLr.mjs} +228 -255
  44. package/dist/.setup/{runtime-doctor-migrations-CshUGl36.mjs → runtime-doctor-migrations-BPV-R4G9.mjs} +6 -0
  45. package/dist/.setup/{security-audit-Cdaegq7C.mjs → security-audit-D42cp5N7.mjs} +21 -48
  46. package/dist/.setup/{send-CrfEI6Bs.mjs → send-2X7m2Zmw.mjs} +45 -58
  47. package/dist/.setup/{send.components-DxQAMfES.mjs → send.components-RqvgmCs3.mjs} +44 -90
  48. package/dist/.setup/{send.outbound-BISKnb-a.mjs → send.outbound-B4QHSEzm.mjs} +60 -98
  49. package/dist/.setup/{send.shared-DGFkbkQR.mjs → send.shared-BQIUh6Vn.mjs} +13 -20
  50. package/dist/.setup/{sender-identity-B9X5Vb9R.mjs → sender-identity-CooeYfAn.mjs} +1 -1
  51. package/dist/.setup/{session-key-normalization-wJgsKPNF.mjs → session-key-normalization-CCHGNSQw.mjs} +3 -9
  52. package/dist/.setup/setup-plugin-api-nn_giXvZ.mjs +3 -0
  53. package/dist/.setup/{shared-B3wZ4hN-.mjs → shared-CIJn6AEC.mjs} +7 -7
  54. package/dist/.setup/{subagent-hooks-nlUE9ow7.mjs → subagent-hooks-BYlVnxzy.mjs} +4 -9
  55. package/dist/.setup/{system-events-CdeZnvPV.mjs → system-events-CQ3if_pS.mjs} +2 -2
  56. package/dist/.setup/{target-resolver-BuLapkhy.mjs → target-resolver-Dzxf80Y3.mjs} +5 -13
  57. package/dist/.setup/targets-Lf8D55w-.mjs +3 -0
  58. package/dist/.setup/{thread-bindings-D7TfgjR_.mjs → thread-bindings-yNNlcUWE.mjs} +5 -6
  59. package/dist/.setup/{thread-bindings.manager-DN-NissX.mjs → thread-bindings.manager-plk0zJAW.mjs} +14 -20
  60. package/dist/.setup/{thread-bindings.session-updates-CshfKghV.mjs → thread-bindings.session-updates-C9aKtVs6.mjs} +295 -5
  61. package/dist/.setup/{timeouts-D86uWLt_.mjs → timeouts-pun7VJ02.mjs} +2 -15
  62. package/dist/.setup/{transcripts-source-p8EV179h.mjs → transcripts-source-CNWswry-.mjs} +31 -79
  63. package/dist/.setup/typing-CNlSKY5S.mjs +11 -0
  64. package/dist/.setup/{voice-runtime-B46rcwrG.mjs → voice-runtime-Bc75quiH.mjs} +62 -110
  65. package/dist/account-inspect-api.js +1 -1
  66. package/dist/action-runtime-api.js +1 -1
  67. package/dist/activities-api.js +1 -1
  68. package/dist/api.js +18 -18
  69. package/dist/channel-config-api.js +1 -1
  70. package/dist/channel-plugin-api.js +1 -1
  71. package/dist/control-ui/2afbdab1d3aa65a789d8a3eba666f4b1ec5df07073538fe30d6cf32093a1fb2d/index.js +1 -0
  72. package/dist/directory-contract-api.js +1 -1
  73. package/dist/doctor-contract-api.js +19 -128
  74. package/dist/index.js +1 -1
  75. package/dist/runtime-api.js +20 -21
  76. package/dist/security-audit-contract-api.js +1 -1
  77. package/dist/session-key-api.js +1 -1
  78. package/dist/setup-entry.js +1 -1
  79. package/dist/setup-plugin-api.js +1 -1
  80. package/dist/src/voice/audio-worker.runtime.js +6 -8
  81. package/dist/subagent-hooks-api.js +1 -1
  82. package/dist/transcripts-source-api.js +1 -1
  83. package/node_modules/libopus-wasm/CHANGELOG.md +8 -0
  84. package/node_modules/libopus-wasm/dist/discordjs.d.ts.map +1 -1
  85. package/node_modules/libopus-wasm/dist/discordjs.js +14 -2
  86. package/node_modules/libopus-wasm/dist/generated/libopus.generated.mjs +0 -0
  87. package/node_modules/libopus-wasm/dist/index.d.ts.map +1 -1
  88. package/node_modules/libopus-wasm/dist/index.js +55 -100
  89. package/node_modules/libopus-wasm/package.json +5 -5
  90. package/node_modules/undici/README.md +10 -1
  91. package/node_modules/undici/docs/docs/api/Agent.md +8 -8
  92. package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +9 -6
  93. package/node_modules/undici/docs/docs/api/Dispatcher.md +9 -0
  94. package/node_modules/undici/docs/docs/api/Errors.md +25 -0
  95. package/node_modules/undici/docs/docs/api/Fetch.md +10 -0
  96. package/node_modules/undici/docs/docs/api/Interceptors.md +4 -3
  97. package/node_modules/undici/docs/docs/api/Pool.md +5 -6
  98. package/node_modules/undici/docs/docs/index.md +10 -1
  99. package/node_modules/undici/lib/api/readable.js +1 -2
  100. package/node_modules/undici/lib/core/request.js +23 -2
  101. package/node_modules/undici/lib/core/util.js +0 -39
  102. package/node_modules/undici/lib/dispatcher/client-h1.js +11 -4
  103. package/node_modules/undici/lib/dispatcher/client-h2.js +52 -8
  104. package/node_modules/undici/lib/dispatcher/client.js +6 -1
  105. package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +21 -6
  106. package/node_modules/undici/lib/dispatcher/pool-base.js +63 -2
  107. package/node_modules/undici/lib/dispatcher/pool.js +90 -7
  108. package/node_modules/undici/lib/dispatcher/proxy-agent.js +16 -3
  109. package/node_modules/undici/lib/handler/deduplication-handler.js +24 -11
  110. package/node_modules/undici/lib/handler/redirect-handler.js +5 -0
  111. package/node_modules/undici/lib/handler/retry-handler.js +72 -13
  112. package/node_modules/undici/lib/interceptor/cache.js +4 -1
  113. package/node_modules/undici/lib/interceptor/decompress.js +236 -69
  114. package/node_modules/undici/lib/web/cache/cache.js +17 -8
  115. package/node_modules/undici/lib/web/cache/cachestorage.js +11 -5
  116. package/node_modules/undici/lib/web/cookies/index.js +19 -7
  117. package/node_modules/undici/lib/web/cookies/util.js +3 -1
  118. package/node_modules/undici/lib/web/eventsource/eventsource.js +25 -1
  119. package/node_modules/undici/lib/web/fetch/body.js +22 -15
  120. package/node_modules/undici/lib/web/fetch/data-url.js +6 -6
  121. package/node_modules/undici/lib/web/fetch/formdata.js +30 -36
  122. package/node_modules/undici/lib/web/fetch/headers.js +34 -31
  123. package/node_modules/undici/lib/web/fetch/index.js +46 -25
  124. package/node_modules/undici/lib/web/fetch/request.js +74 -79
  125. package/node_modules/undici/lib/web/fetch/response.js +43 -44
  126. package/node_modules/undici/lib/web/fetch/util.js +7 -7
  127. package/node_modules/undici/lib/web/infra/index.js +16 -1
  128. package/node_modules/undici/lib/web/webidl/index.js +2 -14
  129. package/node_modules/undici/lib/web/websocket/connection.js +33 -12
  130. package/node_modules/undici/lib/web/websocket/events.js +43 -26
  131. package/node_modules/undici/lib/web/websocket/receiver.js +2 -0
  132. package/node_modules/undici/lib/web/websocket/stream/websocketerror.js +13 -10
  133. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +19 -4
  134. package/node_modules/undici/lib/web/websocket/websocket.js +44 -41
  135. package/node_modules/undici/package.json +1 -1
  136. package/node_modules/undici/types/diagnostics-channel.d.ts +2 -1
  137. package/node_modules/undici/types/interceptors.d.ts +1 -1
  138. package/node_modules/undici/types/webidl.d.ts +13 -7
  139. package/openclaw.plugin.json +6 -0
  140. package/package.json +12 -7
  141. package/dist/.setup/doctor-contract-CvvgwrrG.mjs +0 -409
  142. package/dist/.setup/model-picker-preference-primitives-BHT1LkR_.mjs +0 -37
  143. package/dist/.setup/provider.runtime-CUE3UxER.mjs +0 -2
  144. package/dist/.setup/setup-plugin-api-BQUBxbhe.mjs +0 -3
  145. package/dist/.setup/targets-0KUcEIYx.mjs +0 -3
  146. package/dist/.setup/thread-bindings.state-g6v9zAym.mjs +0 -331
  147. package/dist/.setup/typing-BiHCzBRu.mjs +0 -15
@@ -1,8 +1,299 @@
1
1
  import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.mjs";
2
- import { O as setBindingRecord, a as THREAD_BINDINGS_MAX_ENTRIES, b as removeBindingRecord, g as openThreadBindingsStore, l as ensureBindingsLoaded, n as MANAGERS_BY_ACCOUNT_ID, o as THREAD_BINDINGS_NAMESPACE, p as normalizePersistedBinding, r as PERSIST_BY_ACCOUNT_ID, s as THREAD_BINDINGS_STATE, t as BINDINGS_BY_THREAD_ID, u as ensureBindingsLoadedAsync, x as resolveBindingIdsForSession } from "./thread-bindings.state-g6v9zAym.mjs";
3
- import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
2
+ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
3
+ import { resolveNonNegativeIntegerOption, resolveOptionalIntegerOption } from "openclaw/plugin-sdk/number-runtime";
4
+ import { resolveGlobalSingleton } from "openclaw/plugin-sdk/global-singleton";
5
+ import { normalizeAccountId, resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing";
4
6
  import { createPluginStateErrorReporter } from "openclaw/plugin-sdk/plugin-state-runtime";
5
7
  import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
8
+ import { recordOutboundMessageIdentity } from "openclaw/plugin-sdk/outbound-echo-runtime";
9
+ import { resolveThreadBindingExpiry } from "openclaw/plugin-sdk/thread-bindings-session-runtime";
10
+ //#region extensions/discord/src/monitor/thread-bindings.state.ts
11
+ const THREAD_BINDINGS_STATE_KEY = Symbol.for("openclaw.discordThreadBindingsState");
12
+ function createThreadBindingsGlobalState() {
13
+ return {
14
+ managersByAccountId: /* @__PURE__ */ new Map(),
15
+ bindingsByThreadId: /* @__PURE__ */ new Map(),
16
+ bindingsBySessionKey: /* @__PURE__ */ new Map(),
17
+ tokensByAccountId: /* @__PURE__ */ new Map(),
18
+ reusableWebhooksByAccountChannel: /* @__PURE__ */ new Map(),
19
+ persistByAccountId: /* @__PURE__ */ new Map(),
20
+ loadedBindings: false,
21
+ loadedPersistentBindings: false,
22
+ persistenceAvailable: true,
23
+ lastPersistedAtMs: 0,
24
+ revision: 0,
25
+ mutationTail: Promise.resolve(),
26
+ accountOperationTails: /* @__PURE__ */ new WeakMap()
27
+ };
28
+ }
29
+ const THREAD_BINDINGS_STATE = resolveGlobalSingleton(THREAD_BINDINGS_STATE_KEY, createThreadBindingsGlobalState);
30
+ THREAD_BINDINGS_STATE.accountOperationTails ??= /* @__PURE__ */ new WeakMap();
31
+ const MANAGERS_BY_ACCOUNT_ID = THREAD_BINDINGS_STATE.managersByAccountId;
32
+ const BINDINGS_BY_THREAD_ID = THREAD_BINDINGS_STATE.bindingsByThreadId;
33
+ const BINDINGS_BY_SESSION_KEY = THREAD_BINDINGS_STATE.bindingsBySessionKey;
34
+ const TOKENS_BY_ACCOUNT_ID = THREAD_BINDINGS_STATE.tokensByAccountId;
35
+ const REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL = THREAD_BINDINGS_STATE.reusableWebhooksByAccountChannel;
36
+ const PERSIST_BY_ACCOUNT_ID = THREAD_BINDINGS_STATE.persistByAccountId;
37
+ const THREAD_BINDING_TOUCH_PERSIST_MIN_INTERVAL_MS = 15e3;
38
+ const THREAD_BINDINGS_NAMESPACE = "thread-bindings";
39
+ const THREAD_BINDINGS_MAX_ENTRIES = 1e4;
40
+ function rememberThreadBindingToken(params) {
41
+ const normalizedAccountId = normalizeAccountId(params.accountId);
42
+ const token = params.token?.trim();
43
+ if (!token) return;
44
+ TOKENS_BY_ACCOUNT_ID.set(normalizedAccountId, token);
45
+ }
46
+ function forgetThreadBindingToken(accountId) {
47
+ TOKENS_BY_ACCOUNT_ID.delete(normalizeAccountId(accountId));
48
+ }
49
+ function getThreadBindingToken(accountId) {
50
+ return TOKENS_BY_ACCOUNT_ID.get(normalizeAccountId(accountId));
51
+ }
52
+ function shouldDefaultPersist() {
53
+ return !(process.env.VITEST || false);
54
+ }
55
+ function openThreadBindingsStore() {
56
+ return getDiscordRuntime().state.openSyncKeyedStore({
57
+ namespace: THREAD_BINDINGS_NAMESPACE,
58
+ maxEntries: THREAD_BINDINGS_MAX_ENTRIES
59
+ });
60
+ }
61
+ function normalizeTargetKind(raw, targetSessionKey) {
62
+ if (raw === "subagent" || raw === "acp") return raw;
63
+ return targetSessionKey.includes(":subagent:") ? "subagent" : "acp";
64
+ }
65
+ function toBindingRecordKey(params) {
66
+ return `${normalizeAccountId(params.accountId)}:${params.threadId.trim()}`;
67
+ }
68
+ function resolveBindingRecordKey(params) {
69
+ const threadId = normalizeOptionalStringifiedId(params.threadId);
70
+ if (!threadId) return;
71
+ return toBindingRecordKey({
72
+ accountId: normalizeAccountId(params.accountId),
73
+ threadId
74
+ });
75
+ }
76
+ function normalizePersistedBinding(threadIdKey, raw) {
77
+ if (!raw || typeof raw !== "object") return null;
78
+ const value = raw;
79
+ const threadId = normalizeOptionalStringifiedId(value.threadId ?? threadIdKey);
80
+ const channelId = normalizeOptionalString(value.channelId) ?? "";
81
+ const targetSessionKey = normalizeOptionalString(value.targetSessionKey) ?? "";
82
+ if (!threadId || !channelId || !targetSessionKey) return null;
83
+ const accountId = normalizeAccountId(value.accountId);
84
+ const targetKind = normalizeTargetKind(value.targetKind, targetSessionKey);
85
+ const agentId = (normalizeOptionalString(value.agentId) ?? "") || resolveAgentIdFromSessionKey(targetSessionKey);
86
+ const label = normalizeOptionalString(value.label);
87
+ const webhookId = normalizeOptionalString(value.webhookId);
88
+ const webhookToken = normalizeOptionalString(value.webhookToken);
89
+ const boundBy = normalizeOptionalString(value.boundBy) ?? "system";
90
+ const boundAt = resolveOptionalIntegerOption(value.boundAt) ?? Date.now();
91
+ const lastActivityAt = resolveOptionalIntegerOption(value.lastActivityAt, { min: 0 }) ?? boundAt;
92
+ const idleTimeoutMs = resolveOptionalIntegerOption(value.idleTimeoutMs, { min: 0 });
93
+ const maxAgeMs = resolveOptionalIntegerOption(value.maxAgeMs, { min: 0 });
94
+ const metadata = value.metadata && typeof value.metadata === "object" ? { ...value.metadata } : void 0;
95
+ const record = {
96
+ accountId,
97
+ channelId,
98
+ threadId,
99
+ targetKind,
100
+ targetSessionKey,
101
+ agentId,
102
+ boundBy,
103
+ boundAt,
104
+ lastActivityAt
105
+ };
106
+ if (label !== void 0) record.label = label;
107
+ if (webhookId !== void 0) record.webhookId = webhookId;
108
+ if (webhookToken !== void 0) record.webhookToken = webhookToken;
109
+ if (idleTimeoutMs !== void 0) record.idleTimeoutMs = idleTimeoutMs;
110
+ if (maxAgeMs !== void 0) record.maxAgeMs = maxAgeMs;
111
+ if (metadata !== void 0) record.metadata = metadata;
112
+ return record;
113
+ }
114
+ function normalizeThreadBindingDurationMs(raw, defaultsTo) {
115
+ const durationMs = resolveOptionalIntegerOption(raw);
116
+ return durationMs !== void 0 && durationMs >= 0 ? durationMs : defaultsTo;
117
+ }
118
+ function resolveThreadBindingIdleTimeoutMs(params) {
119
+ return resolveNonNegativeIntegerOption(params.record.idleTimeoutMs, params.defaultIdleTimeoutMs);
120
+ }
121
+ function resolveThreadBindingMaxAgeMs(params) {
122
+ return resolveNonNegativeIntegerOption(params.record.maxAgeMs, params.defaultMaxAgeMs);
123
+ }
124
+ function resolveTimestampExpiry(timestamp, durationMs) {
125
+ if (durationMs <= 0) return;
126
+ const at = Math.floor(timestamp);
127
+ return Number.isFinite(at) && at > 0 ? at + durationMs : void 0;
128
+ }
129
+ function resolvePreparedThreadBindingLifecycle(params) {
130
+ const idleTimeoutMs = resolveThreadBindingIdleTimeoutMs({
131
+ record: params.record,
132
+ defaultIdleTimeoutMs: params.idleTimeoutMs
133
+ });
134
+ const maxAgeMs = resolveThreadBindingMaxAgeMs({
135
+ record: params.record,
136
+ defaultMaxAgeMs: params.maxAgeMs
137
+ });
138
+ return {
139
+ idleTimeoutMs,
140
+ maxAgeMs,
141
+ ...resolveThreadBindingExpiry({
142
+ inactivityExpiresAt: resolveTimestampExpiry(params.record.lastActivityAt, idleTimeoutMs),
143
+ maxAgeExpiresAt: resolveTimestampExpiry(params.record.boundAt, maxAgeMs)
144
+ })
145
+ };
146
+ }
147
+ function resolveThreadBindingInactivityExpiresAt(params) {
148
+ const idleTimeoutMs = resolveThreadBindingIdleTimeoutMs({
149
+ record: params.record,
150
+ defaultIdleTimeoutMs: params.defaultIdleTimeoutMs
151
+ });
152
+ return resolveTimestampExpiry(params.record.lastActivityAt, idleTimeoutMs);
153
+ }
154
+ function resolveThreadBindingMaxAgeExpiresAt(params) {
155
+ const maxAgeMs = resolveThreadBindingMaxAgeMs({
156
+ record: params.record,
157
+ defaultMaxAgeMs: params.defaultMaxAgeMs
158
+ });
159
+ return resolveTimestampExpiry(params.record.boundAt, maxAgeMs);
160
+ }
161
+ function linkSessionBinding(targetSessionKey, bindingKey) {
162
+ const key = targetSessionKey.trim();
163
+ if (!key) return;
164
+ const threads = BINDINGS_BY_SESSION_KEY.get(key) ?? /* @__PURE__ */ new Set();
165
+ threads.add(bindingKey);
166
+ BINDINGS_BY_SESSION_KEY.set(key, threads);
167
+ }
168
+ function unlinkSessionBinding(targetSessionKey, bindingKey) {
169
+ const key = targetSessionKey.trim();
170
+ if (!key) return;
171
+ const threads = BINDINGS_BY_SESSION_KEY.get(key);
172
+ if (!threads) return;
173
+ threads.delete(bindingKey);
174
+ if (threads.size === 0) BINDINGS_BY_SESSION_KEY.delete(key);
175
+ }
176
+ function toReusableWebhookKey(params) {
177
+ return `${normalizeLowercaseStringOrEmpty(params.accountId)}:${params.channelId.trim()}`;
178
+ }
179
+ function rememberReusableWebhook(record) {
180
+ const webhookId = record.webhookId?.trim();
181
+ const webhookToken = record.webhookToken?.trim();
182
+ if (!webhookId || !webhookToken) return;
183
+ const key = toReusableWebhookKey({
184
+ accountId: record.accountId,
185
+ channelId: record.channelId
186
+ });
187
+ REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL.set(key, {
188
+ webhookId,
189
+ webhookToken
190
+ });
191
+ }
192
+ function refreshUnboundThreadWebhookIdentity(record) {
193
+ const sourceId = record.webhookId?.trim();
194
+ if (!sourceId) return;
195
+ recordOutboundMessageIdentity({
196
+ channel: "discord",
197
+ accountId: record.accountId,
198
+ conversationId: record.threadId,
199
+ sourceId
200
+ });
201
+ }
202
+ function setBindingRecord(record) {
203
+ const bindingKey = toBindingRecordKey({
204
+ accountId: record.accountId,
205
+ threadId: record.threadId
206
+ });
207
+ const existing = BINDINGS_BY_THREAD_ID.get(bindingKey);
208
+ if (existing) unlinkSessionBinding(existing.targetSessionKey, bindingKey);
209
+ BINDINGS_BY_THREAD_ID.set(bindingKey, record);
210
+ THREAD_BINDINGS_STATE.revision += 1;
211
+ linkSessionBinding(record.targetSessionKey, bindingKey);
212
+ rememberReusableWebhook(record);
213
+ }
214
+ function removeBindingRecord(bindingKeyRaw) {
215
+ const key = bindingKeyRaw.trim();
216
+ if (!key) return null;
217
+ const existing = BINDINGS_BY_THREAD_ID.get(key);
218
+ if (!existing) return null;
219
+ BINDINGS_BY_THREAD_ID.delete(key);
220
+ THREAD_BINDINGS_STATE.revision += 1;
221
+ unlinkSessionBinding(existing.targetSessionKey, key);
222
+ return existing;
223
+ }
224
+ function beginBindingsLoad() {
225
+ THREAD_BINDINGS_STATE.loadedBindings = true;
226
+ BINDINGS_BY_THREAD_ID.clear();
227
+ THREAD_BINDINGS_STATE.revision += 1;
228
+ BINDINGS_BY_SESSION_KEY.clear();
229
+ REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL.clear();
230
+ THREAD_BINDINGS_STATE.loadedPersistentBindings = false;
231
+ }
232
+ function restoreBindings(entries) {
233
+ THREAD_BINDINGS_STATE.persistenceAvailable = true;
234
+ THREAD_BINDINGS_STATE.loadedPersistentBindings = entries.length > 0;
235
+ for (const entry of entries) {
236
+ const normalized = normalizePersistedBinding(entry.key, entry.value);
237
+ if (!normalized) continue;
238
+ setBindingRecord(normalized);
239
+ }
240
+ }
241
+ function ensureBindingsLoaded() {
242
+ if (THREAD_BINDINGS_STATE.loadedBindings) return;
243
+ beginBindingsLoad();
244
+ let entries;
245
+ try {
246
+ entries = openThreadBindingsStore().entries();
247
+ } catch {
248
+ THREAD_BINDINGS_STATE.persistenceAvailable = false;
249
+ return;
250
+ }
251
+ restoreBindings(entries);
252
+ }
253
+ async function loadBindingsAsync() {
254
+ let entries;
255
+ try {
256
+ entries = await getDiscordRuntime().state.openKeyedStore({
257
+ namespace: THREAD_BINDINGS_NAMESPACE,
258
+ maxEntries: THREAD_BINDINGS_MAX_ENTRIES
259
+ }).entries();
260
+ } catch {
261
+ if (!THREAD_BINDINGS_STATE.loadedBindings) {
262
+ beginBindingsLoad();
263
+ THREAD_BINDINGS_STATE.persistenceAvailable = false;
264
+ logVerbose("discord thread binding persistence unavailable; keeping bindings in memory");
265
+ }
266
+ return;
267
+ }
268
+ if (THREAD_BINDINGS_STATE.loadedBindings) return;
269
+ beginBindingsLoad();
270
+ restoreBindings(entries);
271
+ }
272
+ async function ensureBindingsLoadedAsync() {
273
+ if (THREAD_BINDINGS_STATE.loadedBindings) return;
274
+ const loading = THREAD_BINDINGS_STATE.loadingBindings ??= loadBindingsAsync();
275
+ try {
276
+ await loading;
277
+ } finally {
278
+ if (THREAD_BINDINGS_STATE.loadingBindings === loading) delete THREAD_BINDINGS_STATE.loadingBindings;
279
+ }
280
+ }
281
+ function resolveBindingIdsForSession(params) {
282
+ const key = params.targetSessionKey.trim();
283
+ if (!key) return [];
284
+ const ids = BINDINGS_BY_SESSION_KEY.get(key);
285
+ if (!ids) return [];
286
+ const out = [];
287
+ for (const bindingKey of ids.values()) {
288
+ const record = BINDINGS_BY_THREAD_ID.get(bindingKey);
289
+ if (!record) continue;
290
+ if (params.accountId && record.accountId !== params.accountId) continue;
291
+ if (params.targetKind && record.targetKind !== params.targetKind) continue;
292
+ out.push(bindingKey);
293
+ }
294
+ return out;
295
+ }
296
+ //#endregion
6
297
  //#region extensions/discord/src/monitor/thread-bindings.persistence.ts
7
298
  function shouldPersistAnyBindingState() {
8
299
  for (const value of PERSIST_BY_ACCOUNT_ID.values()) if (value) return true;
@@ -247,10 +538,9 @@ function resolveBindingIdsForTargetSession(params) {
247
538
  ensureBindingsLoaded();
248
539
  const targetSessionKey = params.targetSessionKey.trim();
249
540
  if (!targetSessionKey) return [];
250
- const accountId = params.accountId ? normalizeAccountId(params.accountId) : void 0;
251
541
  return resolveBindingIdsForSession({
252
542
  targetSessionKey,
253
- accountId,
543
+ accountId: params.accountId ? normalizeAccountId(params.accountId) : void 0,
254
544
  targetKind: params.targetKind
255
545
  });
256
546
  }
@@ -356,4 +646,4 @@ function setThreadBindingMaxAgeBySessionKey(params) {
356
646
  }));
357
647
  }
358
648
  //#endregion
359
- export { mutateBindingsForTargetSession as a, drainThreadBindingAccountOperations as c, runThreadBindingAccountOperation as d, runThreadBindingMutation as f, updateBindingRecordSync as h, setThreadBindingMaxAgeBySessionKeyAsync as i, drainThreadBindingMutations as l, snapshotThreadBindingJson as m, setThreadBindingIdleTimeoutBySessionKeyAsync as n, resolveBindingIdsForTargetSession as o, shouldPersistAnyBindingState as p, setThreadBindingMaxAgeBySessionKey as r, commitBindingRecord as s, setThreadBindingIdleTimeoutBySessionKey as t, removeBindingRecordSync as u };
649
+ export { resolveBindingRecordKey as A, getThreadBindingToken as C, rememberReusableWebhook as D, refreshUnboundThreadWebhookIdentity as E, resolveThreadBindingMaxAgeMs as F, shouldDefaultPersist as I, toBindingRecordKey as L, resolveThreadBindingIdleTimeoutMs as M, resolveThreadBindingInactivityExpiresAt as N, rememberThreadBindingToken as O, resolveThreadBindingMaxAgeExpiresAt as P, toReusableWebhookKey as R, forgetThreadBindingToken as S, normalizeThreadBindingDurationMs as T, MANAGERS_BY_ACCOUNT_ID as _, mutateBindingsForTargetSession as a, THREAD_BINDING_TOUCH_PERSIST_MIN_INTERVAL_MS as b, drainThreadBindingAccountOperations as c, runThreadBindingAccountOperation as d, runThreadBindingMutation as f, BINDINGS_BY_THREAD_ID as g, updateBindingRecordSync as h, setThreadBindingMaxAgeBySessionKeyAsync as i, resolvePreparedThreadBindingLifecycle as j, resolveBindingIdsForSession as k, drainThreadBindingMutations as l, snapshotThreadBindingJson as m, setThreadBindingIdleTimeoutBySessionKeyAsync as n, resolveBindingIdsForTargetSession as o, shouldPersistAnyBindingState as p, setThreadBindingMaxAgeBySessionKey as r, commitBindingRecord as s, setThreadBindingIdleTimeoutBySessionKey as t, removeBindingRecordSync as u, PERSIST_BY_ACCOUNT_ID as v, normalizeTargetKind as w, ensureBindingsLoadedAsync as x, REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL as y };
@@ -56,27 +56,14 @@ async function runDiscordTaskWithTimeout(params) {
56
56
  if (timeoutHandle) clearTimeout(timeoutHandle);
57
57
  }
58
58
  }
59
- async function raceWithTimeout(params) {
60
- const timeoutMs = resolveTimerTimeoutMs(params.timeoutMs, 1);
61
- let timeoutTimer;
62
- const timeoutPromise = new Promise((resolve) => {
63
- timeoutTimer = setTimeout(() => resolve(params.onTimeout()), timeoutMs);
64
- timeoutTimer.unref?.();
65
- });
66
- try {
67
- return await Promise.race([params.promise, timeoutPromise]);
68
- } finally {
69
- if (timeoutTimer) clearTimeout(timeoutTimer);
70
- }
71
- }
72
59
  async function withAbortTimeout(params) {
73
60
  const timeoutMs = resolveTimerTimeoutMs(params.timeoutMs, 1);
74
61
  const controller = new AbortController();
75
62
  let timeoutTimer;
76
63
  const timeoutPromise = new Promise((_, reject) => {
77
64
  timeoutTimer = setTimeout(() => {
78
- controller.abort();
79
65
  reject(params.createTimeoutError());
66
+ controller.abort();
80
67
  }, timeoutMs);
81
68
  timeoutTimer.unref?.();
82
69
  });
@@ -87,4 +74,4 @@ async function withAbortTimeout(params) {
87
74
  }
88
75
  }
89
76
  //#endregion
90
- export { isAbortError as a, raceWithTimeout as c, DISCORD_DEFAULT_LISTENER_TIMEOUT_MS as i, runDiscordTaskWithTimeout as l, DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS as n, normalizeDiscordInboundWorkerTimeoutMs as o, DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS as r, normalizeDiscordListenerTimeoutMs as s, DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS as t, withAbortTimeout as u };
77
+ export { isAbortError as a, runDiscordTaskWithTimeout as c, DISCORD_DEFAULT_LISTENER_TIMEOUT_MS as i, withAbortTimeout as l, DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS as n, normalizeDiscordInboundWorkerTimeoutMs as o, DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS as r, normalizeDiscordListenerTimeoutMs as s, DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS as t };
@@ -1,16 +1,17 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.mjs";
2
- import { _ as DiscordError, ft as editChannel, ht as getChannelMessage, lt as createThread, t as discord_exports } from "./discord-0xJYfdDD.mjs";
3
- import { D as getDiscordEndpointRuntime, f as resolveDiscordGuildEntry, i as normalizeDiscordAllowList, k as resolveDiscordEndpointMediaGuard, l as resolveDiscordChannelConfigWithFallback, n as allowListMatches, o as normalizeDiscordSlug, p as resolveDiscordMemberAccessState, r as isDiscordGroupAllowedByPolicy, t as isDiscordThreadChannelType } from "./channel-type-DRCrEMss.mjs";
4
- import { a as listEnabledDiscordAccounts, c as resolveDiscordAccount, l as resolveDiscordAccountAllowFrom } from "./accounts-ChaMcixG.mjs";
2
+ import { _ as DiscordError, ct as createThread, ft as getChannelMessage, t as discord_exports } from "./discord-J7aRzq2Q.mjs";
3
+ import { A as resolveDiscordEndpointMediaGuard, O as getDiscordEndpointRuntime, a as normalizeDiscordAllowList, i as isDiscordGroupAllowedByPolicy, m as resolveDiscordMemberAccessState, n as allowListMatches, p as resolveDiscordGuildEntry, r as hasConfiguredDiscordChannels, s as normalizeDiscordSlug, t as isDiscordThreadChannelType, u as resolveDiscordChannelConfigWithFallback } from "./channel-type-D1_b5UhU.mjs";
4
+ import { a as listEnabledDiscordAccounts, c as resolveDiscordAccount, l as resolveDiscordAccountAllowFrom } from "./accounts-DXHCL8Zm.mjs";
5
5
  import { t as resolveDiscordCommandOwnerAllowFrom } from "./command-owners-D78sAoOz.mjs";
6
- import { a as resolveDiscordChannelParentSafe, i as resolveDiscordChannelParentIdSafe, n as resolveDiscordChannelInfoSafe, r as resolveDiscordChannelNameSafe, t as resolveDiscordChannelIdSafe } from "./channel-access-C12aDZ0p.mjs";
7
- import { ComponentType, StickerFormatType } from "discord-api-types/v10";
6
+ import { a as resolveDiscordChannelParentSafe, i as resolveDiscordChannelParentIdSafe, n as resolveDiscordChannelInfoSafe, r as resolveDiscordChannelNameSafe, t as resolveDiscordChannelIdSafe } from "./channel-access-BRp3Y-rF.mjs";
7
+ import { l as withAbortTimeout } from "./timeouts-pun7VJ02.mjs";
8
+ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeOptionalStringifiedId, summarizeStringEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
9
+ import { ComponentType, Routes, StickerFormatType } from "discord-api-types/v10";
8
10
  import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
9
11
  import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime";
10
12
  import { resolveGlobalSingleton } from "openclaw/plugin-sdk/global-singleton";
11
13
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
12
14
  import { buildAgentSessionKey } from "openclaw/plugin-sdk/routing";
13
- import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeOptionalStringifiedId, summarizeStringEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
14
15
  import { getFileExtension, normalizeMimeType } from "openclaw/plugin-sdk/media-mime";
15
16
  import { createSubsystemLogger, getChildLogger, logVerbose } from "openclaw/plugin-sdk/runtime-env";
16
17
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
@@ -95,14 +96,13 @@ async function generateThreadTitle(params) {
95
96
  channelName: params.channelName,
96
97
  channelDescription: params.channelDescription
97
98
  });
98
- const timeoutMs = resolveThreadTitleTimeoutMs(params.timeoutMs);
99
99
  const generated = await generateConversationLabel({
100
100
  cfg: params.cfg,
101
101
  agentId: params.agentId,
102
102
  userMessage,
103
103
  prompt: DISCORD_THREAD_TITLE_SYSTEM_PROMPT,
104
104
  ...params.modelRef ? { modelRef: params.modelRef } : {},
105
- timeoutMs,
105
+ timeoutMs: Math.max(100, Math.floor(params.timeoutMs ?? DEFAULT_THREAD_TITLE_TIMEOUT_MS)),
106
106
  maxLength: MAX_THREAD_TITLE_SOURCE_CHARS
107
107
  });
108
108
  return generated ? normalizeGeneratedThreadTitle(generated) : null;
@@ -125,20 +125,8 @@ function truncateThreadTitleSourceText(sourceText) {
125
125
  if (sourceText.length <= MAX_THREAD_TITLE_SOURCE_CHARS) return sourceText;
126
126
  return `${truncateUtf16Safe(sourceText, MAX_THREAD_TITLE_SOURCE_CHARS)}...`;
127
127
  }
128
- function resolveThreadTitleTimeoutMs(timeoutMs) {
129
- return Math.max(100, Math.floor(timeoutMs ?? DEFAULT_THREAD_TITLE_TIMEOUT_MS));
130
- }
131
128
  function normalizeGeneratedThreadTitle(raw) {
132
- const lines = raw.replace(/\r/g, "").split("\n");
133
- let firstLine = "";
134
- for (const line of lines) {
135
- const trimmed = line.trim();
136
- if (!trimmed) continue;
137
- if (!firstLine && trimmed.startsWith("```")) continue;
138
- firstLine = trimmed;
139
- break;
140
- }
141
- return stripThreadTitleWrappers(firstLine);
129
+ return stripThreadTitleWrappers(raw.replace(/\r/g, "").split("\n").find((line) => line.trim() && !line.trim().startsWith("```")) ?? "");
142
130
  }
143
131
  function stripThreadTitleWrappers(raw) {
144
132
  let current = raw.trim();
@@ -155,11 +143,9 @@ function stripThreadTitleWrappers(raw) {
155
143
  return current;
156
144
  }
157
145
  function stripBalancedWrapper(text, marker) {
158
- if (text.length < marker.length * 2 + 1) return text;
159
- if (!text.startsWith(marker) || !text.endsWith(marker)) return text;
146
+ if (text.length < marker.length * 2 + 1 || !text.startsWith(marker) || !text.endsWith(marker)) return text;
160
147
  const inner = text.slice(marker.length, text.length - marker.length);
161
- if (!inner || inner.includes(marker)) return text;
162
- return inner;
148
+ return inner.includes(marker) ? text : inner;
163
149
  }
164
150
  function normalizeTitleContextField(raw, maxChars) {
165
151
  const value = raw?.trim();
@@ -351,41 +337,22 @@ async function resolveReferencedReplyMediaList(message, maxBytes, options) {
351
337
  const referencedReply = resolveDiscordReferencedReplyMessage(message);
352
338
  return referencedReply ? resolveMessageMedia(referencedReply, createDiscordMediaOperation(maxBytes, options), "discord: failed to download referenced reply") : [];
353
339
  }
354
- async function fetchDiscordMedia(params) {
355
- const endpointGuard = resolveDiscordEndpointMediaGuard(params.url, params.endpointRuntime);
356
- const timeoutAbortController = params.totalTimeoutMs ? new AbortController() : void 0;
357
- const signal = params.abortSignal && timeoutAbortController ? AbortSignal.any([params.abortSignal, timeoutAbortController.signal]) : params.abortSignal ?? timeoutAbortController?.signal;
358
- let timedOut = false;
359
- let timeoutHandle = null;
360
- const savePromise = saveRemoteMedia({
361
- url: params.url,
362
- filePathHint: params.filePathHint,
363
- maxBytes: params.maxBytes,
364
- fetchImpl: endpointGuard ? void 0 : params.fetchImpl,
365
- ssrfPolicy: endpointGuard?.ssrfPolicy ?? params.ssrfPolicy,
340
+ async function fetchDiscordMedia(operation, params) {
341
+ const endpointGuard = resolveDiscordEndpointMediaGuard(params.url, operation.endpointRuntime);
342
+ const save = (signal) => saveRemoteMedia({
343
+ ...params,
344
+ maxBytes: operation.maxBytes,
345
+ fetchImpl: endpointGuard ? void 0 : operation.fetchImpl,
346
+ ssrfPolicy: endpointGuard?.ssrfPolicy ?? operation.ssrfPolicy,
366
347
  ...endpointGuard ? { maxRedirects: endpointGuard.maxRedirects } : {},
367
- readIdleTimeoutMs: params.readIdleTimeoutMs,
368
- fallbackContentType: params.fallbackContentType,
369
- originalFilename: params.originalFilename,
348
+ readIdleTimeoutMs: operation.readIdleTimeoutMs,
370
349
  ...signal ? { requestInit: { signal } } : {}
371
- }).catch((error) => {
372
- if (timedOut) return new Promise(() => {});
373
- throw error;
374
350
  });
375
- try {
376
- if (!params.totalTimeoutMs) return await savePromise;
377
- const timeoutPromise = new Promise((_, reject) => {
378
- timeoutHandle = setTimeout(() => {
379
- timedOut = true;
380
- timeoutAbortController?.abort();
381
- reject(/* @__PURE__ */ new Error(`discord media download timed out after ${params.totalTimeoutMs}ms`));
382
- }, params.totalTimeoutMs);
383
- timeoutHandle.unref?.();
384
- });
385
- return await Promise.race([savePromise, timeoutPromise]);
386
- } finally {
387
- if (timeoutHandle) clearTimeout(timeoutHandle);
388
- }
351
+ return operation.totalTimeoutMs ? withAbortTimeout({
352
+ timeoutMs: operation.totalTimeoutMs,
353
+ createTimeoutError: () => /* @__PURE__ */ new Error(`discord media download timed out after ${operation.totalTimeoutMs}ms`),
354
+ run: (signal) => save(operation.abortSignal ? AbortSignal.any([operation.abortSignal, signal]) : signal)
355
+ }) : save(operation.abortSignal);
389
356
  }
390
357
  async function appendResolvedMediaFromAttachments(params) {
391
358
  const attachments = params.attachments;
@@ -398,16 +365,9 @@ async function appendResolvedMediaFromAttachments(params) {
398
365
  continue;
399
366
  }
400
367
  try {
401
- const saved = await fetchDiscordMedia({
368
+ const saved = await fetchDiscordMedia(params, {
402
369
  url: attachmentUrl,
403
370
  filePathHint: attachment.filename ?? attachmentUrl,
404
- maxBytes: params.maxBytes,
405
- fetchImpl: params.fetchImpl,
406
- ssrfPolicy: params.ssrfPolicy,
407
- readIdleTimeoutMs: params.readIdleTimeoutMs,
408
- totalTimeoutMs: params.totalTimeoutMs,
409
- abortSignal: params.abortSignal,
410
- endpointRuntime: params.endpointRuntime,
411
371
  fallbackContentType: attachment.content_type,
412
372
  originalFilename: attachment.filename
413
373
  });
@@ -423,8 +383,7 @@ async function appendResolvedMediaFromAttachments(params) {
423
383
  } catch (err) {
424
384
  const id = attachment.id ?? attachmentUrl;
425
385
  getChildLogger({ module: "discord-media" }).warn(`${params.errorPrefix} ${id}: ${String(err)}`);
426
- const classification = resolveDiscordMediaClassification({ attachment });
427
- params.out.push({ ...classification });
386
+ params.out.push(resolveDiscordMediaClassification({ attachment }));
428
387
  }
429
388
  }
430
389
  }
@@ -473,16 +432,9 @@ async function appendResolvedMediaFromStickers(params) {
473
432
  const candidates = resolveStickerAssetCandidates(sticker);
474
433
  let lastError;
475
434
  for (const candidate of candidates) try {
476
- const saved = await fetchDiscordMedia({
435
+ const saved = await fetchDiscordMedia(params, {
477
436
  url: candidate.url,
478
437
  filePathHint: candidate.fileName,
479
- maxBytes: params.maxBytes,
480
- fetchImpl: params.fetchImpl,
481
- ssrfPolicy: params.ssrfPolicy,
482
- readIdleTimeoutMs: params.readIdleTimeoutMs,
483
- totalTimeoutMs: params.totalTimeoutMs,
484
- abortSignal: params.abortSignal,
485
- endpointRuntime: params.endpointRuntime,
486
438
  fallbackContentType: inferStickerContentType(sticker),
487
439
  originalFilename: candidate.fileName
488
440
  });
@@ -499,7 +451,7 @@ async function appendResolvedMediaFromStickers(params) {
499
451
  }
500
452
  if (lastError) {
501
453
  getChildLogger({ module: "discord-media" }).warn(`${params.errorPrefix} ${sticker.id}: ${formatStickerError(lastError)}`);
502
- if (candidates[0]) params.out.push({
454
+ params.out.push({
503
455
  contentType: inferStickerContentType(sticker),
504
456
  kind: "sticker"
505
457
  });
@@ -768,7 +720,7 @@ function resolveDiscordReplyTarget(opts) {
768
720
  }
769
721
  function sanitizeDiscordThreadName(rawName, fallbackId) {
770
722
  const baseSource = rawName.replace(/<@!?\d+>/g, "").replace(/<@&\d+>/g, "").replace(/<#\d+>/g, "").replace(/\s+/g, " ").trim() || `Thread ${fallbackId}`;
771
- return truncateUtf16Safe(baseSource, 80) || `Thread ${fallbackId}`;
723
+ return truncateUtf16Safe(baseSource, 80);
772
724
  }
773
725
  function resolveDiscordReplyDeliveryPlan(params) {
774
726
  const deliverTarget = params.createdThreadId ? `channel:${params.createdThreadId}` : params.replyTarget;
@@ -936,7 +888,7 @@ async function maybeRenameDiscordAutoThread(params) {
936
888
  if (!generated) return;
937
889
  const nextName = sanitizeDiscordThreadName(generated, params.fallbackId);
938
890
  if (!nextName || nextName === params.currentName || nextName === fallbackName) return;
939
- await editChannel(params.client.rest, params.threadId, { body: { name: nextName } });
891
+ await params.client.rest.patch(Routes.channel(params.threadId), { body: { name: nextName } });
940
892
  } catch (err) {
941
893
  logVerbose(`discord: autoThread rename failed for ${params.threadId}: ${String(err)}`);
942
894
  }
@@ -1088,7 +1040,7 @@ async function authorizeDiscordVoiceIngress(initialParams) {
1088
1040
  ok: false,
1089
1041
  message: "This channel is disabled."
1090
1042
  };
1091
- const channelAllowlistConfigured = Boolean(guildInfo?.channels) && Object.keys(guildInfo?.channels ?? {}).length > 0;
1043
+ const channelAllowlistConfigured = hasConfiguredDiscordChannels(guildInfo?.channels);
1092
1044
  if (!params.channelId && groupPolicy === "allowlist" && channelAllowlistConfigured) return {
1093
1045
  ok: false,
1094
1046
  message: `${params.channelLabel ?? "This channel"} is not allowlisted for voice commands.`
@@ -0,0 +1,11 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.mjs";
2
+ import { Routes } from "discord-api-types/v10";
3
+ import { raceWithTimeout } from "openclaw/plugin-sdk/time-runtime";
4
+ //#region extensions/discord/src/monitor/typing.ts
5
+ var typing_exports = /* @__PURE__ */ __exportAll({ sendTyping: () => sendTyping });
6
+ const DISCORD_TYPING_START_TIMEOUT_MS = 5e3;
7
+ async function sendTyping(params) {
8
+ if ((await raceWithTimeout(params.rest.post(Routes.channelTyping(params.channelId)).then(() => ({ kind: "sent" })), DISCORD_TYPING_START_TIMEOUT_MS, () => ({ kind: "timeout" }), { ref: false })).kind === "timeout") throw new Error(`discord typing start timed out after ${DISCORD_TYPING_START_TIMEOUT_MS}ms`);
9
+ }
10
+ //#endregion
11
+ export { typing_exports as n, sendTyping as t };