@kodelyth/discord 2026.5.39 → 2026.6.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.
Files changed (126) hide show
  1. package/dist/account-inspect-Dqw-enky.js +81 -0
  2. package/dist/account-inspect-api.js +10 -0
  3. package/dist/accounts-B7OBFePq.js +224 -0
  4. package/dist/action-runtime-api.js +2 -0
  5. package/dist/agent-components.runtime-DVY_1VB4.js +4 -0
  6. package/dist/allow-list-B0s7evD7.js +354 -0
  7. package/dist/api-CXAcv9nZ.js +130 -0
  8. package/dist/api.js +23 -0
  9. package/dist/approval-handler.runtime-B9xUAF3n.js +426 -0
  10. package/dist/audit-DoiK49WO.js +24 -0
  11. package/dist/audit-core-BGrq3G7r.js +105 -0
  12. package/dist/channel-U_aeoFwW.js +795 -0
  13. package/dist/channel-actions-BxEBnEuv.js +173 -0
  14. package/dist/channel-actions.runtime-CPtpH-yl.js +263 -0
  15. package/dist/channel-api-BfjklLby.js +21 -0
  16. package/dist/channel-config-api.js +2 -0
  17. package/dist/channel-plugin-api.js +2 -0
  18. package/dist/channel.setup-BUSC0apv.js +337 -0
  19. package/dist/components-luonoe13.js +909 -0
  20. package/dist/config-api-DSYGqaLQ.js +2 -0
  21. package/dist/config-schema-DIqJBGwC.js +357 -0
  22. package/dist/configured-state.js +6 -0
  23. package/dist/contract-api.js +8 -0
  24. package/dist/conversation-identity-DXAm0_Mk.js +270 -0
  25. package/dist/directory-config-CYbuMmPS.js +49 -0
  26. package/dist/directory-contract-api.js +2 -0
  27. package/dist/directory-live-DX4dLRpJ.js +159 -0
  28. package/dist/doctor-bbKSvGVD.js +244 -0
  29. package/dist/doctor-contract-Btjt6NJD.js +383 -0
  30. package/dist/doctor-contract-api.js +2 -0
  31. package/dist/gateway-registry-BKSpa4GB.js +74 -0
  32. package/dist/handle-action.guild-admin-B5BArS2n.js +286 -0
  33. package/dist/inbound-context-WAOqhGlT.js +48 -0
  34. package/dist/inbound-event-delivery-C-1Ji3WP.js +65 -0
  35. package/dist/index.js +26 -0
  36. package/dist/manager.runtime-DXHynKE4.js +2356 -0
  37. package/dist/message-handler-mXzc3tA_.js +381 -0
  38. package/dist/message-handler.preflight-BPD1a347.js +1113 -0
  39. package/dist/message-handler.process-GUa3aV8z.js +1438 -0
  40. package/dist/message-utils-dUbem16p.js +549 -0
  41. package/dist/outbound-adapter-C18OAc1y.js +536 -0
  42. package/dist/pluralkit-D1Q2x0w5.js +22 -0
  43. package/dist/preflight-audio-CZtpWcIm.js +72 -0
  44. package/dist/preflight-audio.runtime-Brx_0_xW.js +7 -0
  45. package/dist/preview-streaming-D_slNIiO.js +8 -0
  46. package/dist/probe-D--Ca4JF.js +139 -0
  47. package/dist/probe.runtime-DQBchZzv.js +2 -0
  48. package/dist/provider-B2-31CIT.js +9565 -0
  49. package/dist/provider-session.runtime-BwzzSsrH.js +6 -0
  50. package/dist/provider.runtime-CP3oHLls.js +2 -0
  51. package/dist/resolve-allowlist-common-CqxPLcJO.js +34 -0
  52. package/dist/resolve-channels-0LX4pUbB.js +265 -0
  53. package/dist/resolve-users-CztOv0Qs.js +120 -0
  54. package/dist/runtime-DUaw66V_.js +1073 -0
  55. package/dist/runtime-api.actions.js +3 -0
  56. package/dist/runtime-api.js +30 -0
  57. package/dist/runtime-api.lookup.js +7 -0
  58. package/dist/runtime-api.monitor-CvVKvEXW.js +5 -0
  59. package/dist/runtime-api.monitor.js +8 -0
  60. package/dist/runtime-api.send.js +6 -0
  61. package/dist/runtime-api.threads.js +6 -0
  62. package/dist/runtime-fC6f4UF2.js +8 -0
  63. package/dist/runtime-setter-api.js +2 -0
  64. package/dist/secret-config-contract-B6WW5V88.js +115 -0
  65. package/dist/secret-contract-api.js +2 -0
  66. package/dist/security-audit-CnyIQKz6.js +120 -0
  67. package/dist/security-audit-contract-api.js +2 -0
  68. package/dist/security-audit.runtime-CQSkjNLu.js +2 -0
  69. package/dist/security-contract-DLvYOgLM.js +26 -0
  70. package/dist/security-contract-api.js +2 -0
  71. package/dist/security-doctor-DepqtNCI.js +18 -0
  72. package/dist/send-DCtPCHGk.js +881 -0
  73. package/dist/send.components-Bcgxvm52.js +474 -0
  74. package/dist/send.outbound-S9t0UuHc.js +330 -0
  75. package/dist/send.receipt-CDn3GBWC.js +3119 -0
  76. package/dist/send.shared-D4iBnAmn.js +669 -0
  77. package/dist/sender-identity-CxCe3_1a.js +43 -0
  78. package/dist/session-contract-Dwhw3RTY.js +6 -0
  79. package/dist/session-key-api.js +2 -0
  80. package/dist/session-key-normalization-CP8dPUid.js +23 -0
  81. package/dist/setup-entry.js +11 -0
  82. package/dist/setup-plugin-api.js +2 -0
  83. package/dist/shared-AIlvuZXt.js +171 -0
  84. package/dist/subagent-hooks-8bK-mgiU.js +120 -0
  85. package/dist/subagent-hooks-api.js +22 -0
  86. package/dist/system-events-Ba1TklaL.js +34 -0
  87. package/dist/target-resolver-BrtFQtoK.js +82 -0
  88. package/dist/targets-DWLLZE2l.js +3 -0
  89. package/dist/test-api.js +45 -0
  90. package/dist/thread-binding-api.js +4 -0
  91. package/dist/thread-bindings-9aKRmZv0.js +255 -0
  92. package/dist/thread-bindings.discord-api-ssGH5wc2.js +244 -0
  93. package/dist/thread-bindings.manager-0YBHGemk.js +534 -0
  94. package/dist/thread-bindings.session-updates-DJZGIwaU.js +54 -0
  95. package/dist/thread-bindings.state-eTFl-PqJ.js +318 -0
  96. package/dist/timeouts-CEwuGaWT.js +52 -0
  97. package/dist/timeouts.js +2 -0
  98. package/dist/typing-BmJKRpCS.js +14 -0
  99. package/package.json +19 -7
  100. package/account-inspect-api.js +0 -7
  101. package/action-runtime-api.js +0 -7
  102. package/api.js +0 -7
  103. package/channel-config-api.js +0 -7
  104. package/channel-plugin-api.js +0 -7
  105. package/configured-state.js +0 -7
  106. package/contract-api.js +0 -7
  107. package/directory-contract-api.js +0 -7
  108. package/doctor-contract-api.js +0 -7
  109. package/index.js +0 -7
  110. package/runtime-api.actions.js +0 -7
  111. package/runtime-api.js +0 -7
  112. package/runtime-api.lookup.js +0 -7
  113. package/runtime-api.monitor.js +0 -7
  114. package/runtime-api.send.js +0 -7
  115. package/runtime-api.threads.js +0 -7
  116. package/runtime-setter-api.js +0 -7
  117. package/secret-contract-api.js +0 -7
  118. package/security-audit-contract-api.js +0 -7
  119. package/security-contract-api.js +0 -7
  120. package/session-key-api.js +0 -7
  121. package/setup-entry.js +0 -7
  122. package/setup-plugin-api.js +0 -7
  123. package/subagent-hooks-api.js +0 -7
  124. package/test-api.js +0 -7
  125. package/thread-binding-api.js +0 -7
  126. package/timeouts.js +0 -7
@@ -0,0 +1,318 @@
1
+ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeOptionalStringifiedId } from "klaw/plugin-sdk/string-coerce-runtime";
2
+ import { normalizeAccountId, resolveAgentIdFromSessionKey } from "klaw/plugin-sdk/routing";
3
+ import path from "node:path";
4
+ import fs from "node:fs";
5
+ import { loadJsonFile, saveJsonFile } from "klaw/plugin-sdk/json-store";
6
+ import { resolveStateDir } from "klaw/plugin-sdk/state-paths";
7
+ //#region extensions/discord/src/monitor/thread-bindings.types.ts
8
+ const THREAD_BINDINGS_SWEEP_INTERVAL_MS = 12e4;
9
+ const DEFAULT_THREAD_BINDING_IDLE_TIMEOUT_MS = 1440 * 60 * 1e3;
10
+ const DISCORD_UNKNOWN_CHANNEL_ERROR_CODE = 10003;
11
+ const RECENT_UNBOUND_WEBHOOK_ECHO_WINDOW_MS = 3e4;
12
+ //#endregion
13
+ //#region extensions/discord/src/monitor/thread-bindings.state.ts
14
+ const THREAD_BINDINGS_STATE_KEY = Symbol.for("klaw.discordThreadBindingsState");
15
+ let threadBindingsState;
16
+ function createThreadBindingsGlobalState() {
17
+ return {
18
+ managersByAccountId: /* @__PURE__ */ new Map(),
19
+ bindingsByThreadId: /* @__PURE__ */ new Map(),
20
+ bindingsBySessionKey: /* @__PURE__ */ new Map(),
21
+ tokensByAccountId: /* @__PURE__ */ new Map(),
22
+ recentUnboundWebhookEchoesByBindingKey: /* @__PURE__ */ new Map(),
23
+ reusableWebhooksByAccountChannel: /* @__PURE__ */ new Map(),
24
+ persistByAccountId: /* @__PURE__ */ new Map(),
25
+ loadedBindings: false,
26
+ lastPersistedAtMs: 0
27
+ };
28
+ }
29
+ function resolveThreadBindingsGlobalState() {
30
+ if (!threadBindingsState) {
31
+ const globalStore = globalThis;
32
+ threadBindingsState = globalStore[THREAD_BINDINGS_STATE_KEY] ?? createThreadBindingsGlobalState();
33
+ globalStore[THREAD_BINDINGS_STATE_KEY] = threadBindingsState;
34
+ }
35
+ return threadBindingsState;
36
+ }
37
+ const THREAD_BINDINGS_STATE = resolveThreadBindingsGlobalState();
38
+ const MANAGERS_BY_ACCOUNT_ID = THREAD_BINDINGS_STATE.managersByAccountId;
39
+ const BINDINGS_BY_THREAD_ID = THREAD_BINDINGS_STATE.bindingsByThreadId;
40
+ const BINDINGS_BY_SESSION_KEY = THREAD_BINDINGS_STATE.bindingsBySessionKey;
41
+ const TOKENS_BY_ACCOUNT_ID = THREAD_BINDINGS_STATE.tokensByAccountId;
42
+ const RECENT_UNBOUND_WEBHOOK_ECHOES_BY_BINDING_KEY = THREAD_BINDINGS_STATE.recentUnboundWebhookEchoesByBindingKey;
43
+ const REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL = THREAD_BINDINGS_STATE.reusableWebhooksByAccountChannel;
44
+ const PERSIST_BY_ACCOUNT_ID = THREAD_BINDINGS_STATE.persistByAccountId;
45
+ const THREAD_BINDING_TOUCH_PERSIST_MIN_INTERVAL_MS = 15e3;
46
+ function rememberThreadBindingToken(params) {
47
+ const normalizedAccountId = normalizeAccountId(params.accountId);
48
+ const token = params.token?.trim();
49
+ if (!token) return;
50
+ TOKENS_BY_ACCOUNT_ID.set(normalizedAccountId, token);
51
+ }
52
+ function forgetThreadBindingToken(accountId) {
53
+ TOKENS_BY_ACCOUNT_ID.delete(normalizeAccountId(accountId));
54
+ }
55
+ function getThreadBindingToken(accountId) {
56
+ return TOKENS_BY_ACCOUNT_ID.get(normalizeAccountId(accountId));
57
+ }
58
+ function shouldDefaultPersist() {
59
+ return !(process.env.VITEST || false);
60
+ }
61
+ function resolveThreadBindingsPath() {
62
+ return path.join(resolveStateDir(process.env), "discord", "thread-bindings.json");
63
+ }
64
+ function normalizeTargetKind(raw, targetSessionKey) {
65
+ if (raw === "subagent" || raw === "acp") return raw;
66
+ return targetSessionKey.includes(":subagent:") ? "subagent" : "acp";
67
+ }
68
+ function normalizeThreadId(raw) {
69
+ return normalizeOptionalStringifiedId(raw);
70
+ }
71
+ function toBindingRecordKey(params) {
72
+ return `${normalizeAccountId(params.accountId)}:${params.threadId.trim()}`;
73
+ }
74
+ function resolveBindingRecordKey(params) {
75
+ const threadId = normalizeThreadId(params.threadId);
76
+ if (!threadId) return;
77
+ return toBindingRecordKey({
78
+ accountId: normalizeAccountId(params.accountId),
79
+ threadId
80
+ });
81
+ }
82
+ function normalizePersistedBinding(threadIdKey, raw) {
83
+ if (!raw || typeof raw !== "object") return null;
84
+ const value = raw;
85
+ const threadId = normalizeThreadId(value.threadId ?? threadIdKey);
86
+ const channelId = normalizeOptionalString(value.channelId) ?? "";
87
+ const targetSessionKey = normalizeOptionalString(value.targetSessionKey) ?? normalizeOptionalString(value.sessionKey) ?? "";
88
+ if (!threadId || !channelId || !targetSessionKey) return null;
89
+ const accountId = normalizeAccountId(value.accountId);
90
+ const targetKind = normalizeTargetKind(value.targetKind, targetSessionKey);
91
+ const agentId = (normalizeOptionalString(value.agentId) ?? "") || resolveAgentIdFromSessionKey(targetSessionKey);
92
+ const label = normalizeOptionalString(value.label);
93
+ const webhookId = normalizeOptionalString(value.webhookId);
94
+ const webhookToken = normalizeOptionalString(value.webhookToken);
95
+ const boundBy = normalizeOptionalString(value.boundBy) ?? "system";
96
+ const boundAt = typeof value.boundAt === "number" && Number.isFinite(value.boundAt) ? Math.floor(value.boundAt) : Date.now();
97
+ const lastActivityAt = typeof value.lastActivityAt === "number" && Number.isFinite(value.lastActivityAt) ? Math.max(0, Math.floor(value.lastActivityAt)) : boundAt;
98
+ const idleTimeoutMs = typeof value.idleTimeoutMs === "number" && Number.isFinite(value.idleTimeoutMs) ? Math.max(0, Math.floor(value.idleTimeoutMs)) : void 0;
99
+ const maxAgeMs = typeof value.maxAgeMs === "number" && Number.isFinite(value.maxAgeMs) ? Math.max(0, Math.floor(value.maxAgeMs)) : void 0;
100
+ const metadata = value.metadata && typeof value.metadata === "object" ? { ...value.metadata } : void 0;
101
+ const legacyExpiresAt = typeof value.expiresAt === "number" && Number.isFinite(value.expiresAt) ? Math.max(0, Math.floor(value.expiresAt ?? 0)) : void 0;
102
+ let migratedIdleTimeoutMs = idleTimeoutMs;
103
+ let migratedMaxAgeMs = maxAgeMs;
104
+ if (migratedIdleTimeoutMs === void 0 && migratedMaxAgeMs === void 0 && legacyExpiresAt != null) if (legacyExpiresAt <= 0) {
105
+ migratedIdleTimeoutMs = 0;
106
+ migratedMaxAgeMs = 0;
107
+ } else {
108
+ const baseBoundAt = boundAt > 0 ? boundAt : lastActivityAt;
109
+ migratedIdleTimeoutMs = 0;
110
+ migratedMaxAgeMs = Math.max(1, legacyExpiresAt - Math.max(0, baseBoundAt));
111
+ }
112
+ return {
113
+ accountId,
114
+ channelId,
115
+ threadId,
116
+ targetKind,
117
+ targetSessionKey,
118
+ agentId,
119
+ label,
120
+ webhookId,
121
+ webhookToken,
122
+ boundBy,
123
+ boundAt,
124
+ lastActivityAt,
125
+ idleTimeoutMs: migratedIdleTimeoutMs,
126
+ maxAgeMs: migratedMaxAgeMs,
127
+ metadata
128
+ };
129
+ }
130
+ function normalizeThreadBindingDurationMs(raw, defaultsTo) {
131
+ if (typeof raw !== "number" || !Number.isFinite(raw)) return defaultsTo;
132
+ const durationMs = Math.floor(raw);
133
+ if (durationMs < 0) return defaultsTo;
134
+ return durationMs;
135
+ }
136
+ function resolveThreadBindingIdleTimeoutMs(params) {
137
+ const explicit = params.record.idleTimeoutMs;
138
+ if (typeof explicit === "number" && Number.isFinite(explicit)) return Math.max(0, Math.floor(explicit));
139
+ return Math.max(0, Math.floor(params.defaultIdleTimeoutMs));
140
+ }
141
+ function resolveThreadBindingMaxAgeMs(params) {
142
+ const explicit = params.record.maxAgeMs;
143
+ if (typeof explicit === "number" && Number.isFinite(explicit)) return Math.max(0, Math.floor(explicit));
144
+ return Math.max(0, Math.floor(params.defaultMaxAgeMs));
145
+ }
146
+ function resolveThreadBindingInactivityExpiresAt(params) {
147
+ const idleTimeoutMs = resolveThreadBindingIdleTimeoutMs({
148
+ record: params.record,
149
+ defaultIdleTimeoutMs: params.defaultIdleTimeoutMs
150
+ });
151
+ if (idleTimeoutMs <= 0) return;
152
+ const lastActivityAt = Math.floor(params.record.lastActivityAt);
153
+ if (!Number.isFinite(lastActivityAt) || lastActivityAt <= 0) return;
154
+ return lastActivityAt + idleTimeoutMs;
155
+ }
156
+ function resolveThreadBindingMaxAgeExpiresAt(params) {
157
+ const maxAgeMs = resolveThreadBindingMaxAgeMs({
158
+ record: params.record,
159
+ defaultMaxAgeMs: params.defaultMaxAgeMs
160
+ });
161
+ if (maxAgeMs <= 0) return;
162
+ const boundAt = Math.floor(params.record.boundAt);
163
+ if (!Number.isFinite(boundAt) || boundAt <= 0) return;
164
+ return boundAt + maxAgeMs;
165
+ }
166
+ function linkSessionBinding(targetSessionKey, bindingKey) {
167
+ const key = targetSessionKey.trim();
168
+ if (!key) return;
169
+ const threads = BINDINGS_BY_SESSION_KEY.get(key) ?? /* @__PURE__ */ new Set();
170
+ threads.add(bindingKey);
171
+ BINDINGS_BY_SESSION_KEY.set(key, threads);
172
+ }
173
+ function unlinkSessionBinding(targetSessionKey, bindingKey) {
174
+ const key = targetSessionKey.trim();
175
+ if (!key) return;
176
+ const threads = BINDINGS_BY_SESSION_KEY.get(key);
177
+ if (!threads) return;
178
+ threads.delete(bindingKey);
179
+ if (threads.size === 0) BINDINGS_BY_SESSION_KEY.delete(key);
180
+ }
181
+ function toReusableWebhookKey(params) {
182
+ return `${normalizeLowercaseStringOrEmpty(params.accountId)}:${params.channelId.trim()}`;
183
+ }
184
+ function rememberReusableWebhook(record) {
185
+ const webhookId = record.webhookId?.trim();
186
+ const webhookToken = record.webhookToken?.trim();
187
+ if (!webhookId || !webhookToken) return;
188
+ const key = toReusableWebhookKey({
189
+ accountId: record.accountId,
190
+ channelId: record.channelId
191
+ });
192
+ REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL.set(key, {
193
+ webhookId,
194
+ webhookToken
195
+ });
196
+ }
197
+ function rememberRecentUnboundWebhookEcho(record) {
198
+ const webhookId = record.webhookId?.trim();
199
+ if (!webhookId) return;
200
+ const bindingKey = resolveBindingRecordKey({
201
+ accountId: record.accountId,
202
+ threadId: record.threadId
203
+ });
204
+ if (!bindingKey) return;
205
+ RECENT_UNBOUND_WEBHOOK_ECHOES_BY_BINDING_KEY.set(bindingKey, {
206
+ webhookId,
207
+ expiresAt: Date.now() + RECENT_UNBOUND_WEBHOOK_ECHO_WINDOW_MS
208
+ });
209
+ }
210
+ function clearRecentUnboundWebhookEcho(bindingKeyRaw) {
211
+ const key = bindingKeyRaw.trim();
212
+ if (!key) return;
213
+ RECENT_UNBOUND_WEBHOOK_ECHOES_BY_BINDING_KEY.delete(key);
214
+ }
215
+ function setBindingRecord(record) {
216
+ const bindingKey = toBindingRecordKey({
217
+ accountId: record.accountId,
218
+ threadId: record.threadId
219
+ });
220
+ const existing = BINDINGS_BY_THREAD_ID.get(bindingKey);
221
+ if (existing) unlinkSessionBinding(existing.targetSessionKey, bindingKey);
222
+ BINDINGS_BY_THREAD_ID.set(bindingKey, record);
223
+ linkSessionBinding(record.targetSessionKey, bindingKey);
224
+ clearRecentUnboundWebhookEcho(bindingKey);
225
+ rememberReusableWebhook(record);
226
+ }
227
+ function removeBindingRecord(bindingKeyRaw) {
228
+ const key = bindingKeyRaw.trim();
229
+ if (!key) return null;
230
+ const existing = BINDINGS_BY_THREAD_ID.get(key);
231
+ if (!existing) return null;
232
+ BINDINGS_BY_THREAD_ID.delete(key);
233
+ unlinkSessionBinding(existing.targetSessionKey, key);
234
+ return existing;
235
+ }
236
+ function isRecentlyUnboundThreadWebhookMessage(params) {
237
+ const webhookId = normalizeOptionalString(params.webhookId) ?? "";
238
+ if (!webhookId) return false;
239
+ const bindingKey = resolveBindingRecordKey({
240
+ accountId: params.accountId,
241
+ threadId: params.threadId
242
+ });
243
+ if (!bindingKey) return false;
244
+ const suppressed = RECENT_UNBOUND_WEBHOOK_ECHOES_BY_BINDING_KEY.get(bindingKey);
245
+ if (!suppressed) return false;
246
+ if (suppressed.expiresAt <= Date.now()) {
247
+ RECENT_UNBOUND_WEBHOOK_ECHOES_BY_BINDING_KEY.delete(bindingKey);
248
+ return false;
249
+ }
250
+ return suppressed.webhookId === webhookId;
251
+ }
252
+ function shouldPersistAnyBindingState() {
253
+ for (const value of PERSIST_BY_ACCOUNT_ID.values()) if (value) return true;
254
+ return false;
255
+ }
256
+ function shouldPersistBindingMutations() {
257
+ if (shouldPersistAnyBindingState()) return true;
258
+ return fs.existsSync(resolveThreadBindingsPath());
259
+ }
260
+ function saveBindingsToDisk(params = {}) {
261
+ if (!params.force && !shouldPersistAnyBindingState()) return;
262
+ const minIntervalMs = typeof params.minIntervalMs === "number" && Number.isFinite(params.minIntervalMs) ? Math.max(0, Math.floor(params.minIntervalMs)) : 0;
263
+ const now = Date.now();
264
+ if (!params.force && minIntervalMs > 0 && THREAD_BINDINGS_STATE.lastPersistedAtMs > 0 && now - THREAD_BINDINGS_STATE.lastPersistedAtMs < minIntervalMs) return;
265
+ const bindings = {};
266
+ for (const [bindingKey, record] of BINDINGS_BY_THREAD_ID.entries()) bindings[bindingKey] = { ...record };
267
+ const payload = {
268
+ version: 1,
269
+ bindings
270
+ };
271
+ saveJsonFile(resolveThreadBindingsPath(), payload);
272
+ THREAD_BINDINGS_STATE.lastPersistedAtMs = now;
273
+ }
274
+ function ensureBindingsLoaded() {
275
+ if (THREAD_BINDINGS_STATE.loadedBindings) return;
276
+ THREAD_BINDINGS_STATE.loadedBindings = true;
277
+ BINDINGS_BY_THREAD_ID.clear();
278
+ BINDINGS_BY_SESSION_KEY.clear();
279
+ REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL.clear();
280
+ const raw = loadJsonFile(resolveThreadBindingsPath());
281
+ if (!raw || typeof raw !== "object") return;
282
+ const payload = raw;
283
+ if (payload.version !== 1 || !payload.bindings || typeof payload.bindings !== "object") return;
284
+ for (const [threadId, entry] of Object.entries(payload.bindings)) {
285
+ const normalized = normalizePersistedBinding(threadId, entry);
286
+ if (!normalized) continue;
287
+ setBindingRecord(normalized);
288
+ }
289
+ }
290
+ function resolveBindingIdsForSession(params) {
291
+ const key = params.targetSessionKey.trim();
292
+ if (!key) return [];
293
+ const ids = BINDINGS_BY_SESSION_KEY.get(key);
294
+ if (!ids) return [];
295
+ const out = [];
296
+ for (const bindingKey of ids.values()) {
297
+ const record = BINDINGS_BY_THREAD_ID.get(bindingKey);
298
+ if (!record) continue;
299
+ if (params.accountId && record.accountId !== params.accountId) continue;
300
+ if (params.targetKind && record.targetKind !== params.targetKind) continue;
301
+ out.push(bindingKey);
302
+ }
303
+ return out;
304
+ }
305
+ function resetThreadBindingsForTests() {
306
+ for (const manager of MANAGERS_BY_ACCOUNT_ID.values()) manager.stop();
307
+ MANAGERS_BY_ACCOUNT_ID.clear();
308
+ BINDINGS_BY_THREAD_ID.clear();
309
+ BINDINGS_BY_SESSION_KEY.clear();
310
+ RECENT_UNBOUND_WEBHOOK_ECHOES_BY_BINDING_KEY.clear();
311
+ REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL.clear();
312
+ TOKENS_BY_ACCOUNT_ID.clear();
313
+ PERSIST_BY_ACCOUNT_ID.clear();
314
+ THREAD_BINDINGS_STATE.loadedBindings = false;
315
+ THREAD_BINDINGS_STATE.lastPersistedAtMs = 0;
316
+ }
317
+ //#endregion
318
+ export { DEFAULT_THREAD_BINDING_IDLE_TIMEOUT_MS as A, resolveThreadBindingMaxAgeMs as C, shouldDefaultPersist as D, setBindingRecord as E, THREAD_BINDINGS_SWEEP_INTERVAL_MS as M, shouldPersistBindingMutations as O, resolveThreadBindingMaxAgeExpiresAt as S, saveBindingsToDisk as T, resetThreadBindingsForTests as _, THREAD_BINDING_TOUCH_PERSIST_MIN_INTERVAL_MS as a, resolveThreadBindingIdleTimeoutMs as b, getThreadBindingToken as c, normalizeThreadBindingDurationMs as d, normalizeThreadId as f, removeBindingRecord as g, rememberThreadBindingToken as h, REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL as i, DISCORD_UNKNOWN_CHANNEL_ERROR_CODE as j, toReusableWebhookKey as k, isRecentlyUnboundThreadWebhookMessage as l, rememberReusableWebhook as m, MANAGERS_BY_ACCOUNT_ID as n, ensureBindingsLoaded as o, rememberRecentUnboundWebhookEcho as p, PERSIST_BY_ACCOUNT_ID as r, forgetThreadBindingToken as s, BINDINGS_BY_THREAD_ID as t, normalizeTargetKind as u, resolveBindingIdsForSession as v, resolveThreadBindingsPath as w, resolveThreadBindingInactivityExpiresAt as x, resolveBindingRecordKey as y };
@@ -0,0 +1,52 @@
1
+ //#region extensions/discord/src/monitor/timeouts.ts
2
+ const DISCORD_DEFAULT_LISTENER_TIMEOUT_MS = 12e4;
3
+ const DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS = 30 * 6e4;
4
+ const DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS = 6e4;
5
+ const DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS = 12e4;
6
+ function mergeAbortSignals(signals) {
7
+ const activeSignals = signals.filter((signal) => Boolean(signal));
8
+ if (activeSignals.length === 0) return;
9
+ if (activeSignals.length === 1) return activeSignals[0];
10
+ if (typeof AbortSignal.any === "function") return AbortSignal.any(activeSignals);
11
+ const fallbackController = new AbortController();
12
+ for (const signal of activeSignals) if (signal.aborted) {
13
+ fallbackController.abort();
14
+ return fallbackController.signal;
15
+ }
16
+ const abortFallback = () => {
17
+ fallbackController.abort();
18
+ for (const signal of activeSignals) signal.removeEventListener("abort", abortFallback);
19
+ };
20
+ for (const signal of activeSignals) signal.addEventListener("abort", abortFallback, { once: true });
21
+ return fallbackController.signal;
22
+ }
23
+ async function raceWithTimeout(params) {
24
+ let timeoutTimer;
25
+ const timeoutPromise = new Promise((resolve) => {
26
+ timeoutTimer = setTimeout(() => resolve(params.onTimeout()), Math.max(1, params.timeoutMs));
27
+ timeoutTimer.unref?.();
28
+ });
29
+ try {
30
+ return await Promise.race([params.promise, timeoutPromise]);
31
+ } finally {
32
+ if (timeoutTimer) clearTimeout(timeoutTimer);
33
+ }
34
+ }
35
+ async function withAbortTimeout(params) {
36
+ const controller = new AbortController();
37
+ let timeoutTimer;
38
+ const timeoutPromise = new Promise((_, reject) => {
39
+ timeoutTimer = setTimeout(() => {
40
+ controller.abort();
41
+ reject(params.createTimeoutError());
42
+ }, Math.max(1, params.timeoutMs));
43
+ timeoutTimer.unref?.();
44
+ });
45
+ try {
46
+ return await Promise.race([params.run(controller.signal), timeoutPromise]);
47
+ } finally {
48
+ if (timeoutTimer) clearTimeout(timeoutTimer);
49
+ }
50
+ }
51
+ //#endregion
52
+ export { mergeAbortSignals as a, DISCORD_DEFAULT_LISTENER_TIMEOUT_MS as i, DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS as n, raceWithTimeout as o, DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS as r, withAbortTimeout as s, DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS as t };
@@ -0,0 +1,2 @@
1
+ import { i as DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, r as DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-CEwuGaWT.js";
2
+ export { DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS, DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, DISCORD_DEFAULT_LISTENER_TIMEOUT_MS };
@@ -0,0 +1,14 @@
1
+ import { Wt as __exportAll, bt as sendChannelTyping } from "./send.receipt-CDn3GBWC.js";
2
+ import { o as raceWithTimeout } from "./timeouts-CEwuGaWT.js";
3
+ //#region extensions/discord/src/monitor/typing.ts
4
+ var typing_exports = /* @__PURE__ */ __exportAll({ sendTyping: () => sendTyping });
5
+ const DISCORD_TYPING_START_TIMEOUT_MS = 5e3;
6
+ async function sendTyping(params) {
7
+ if ((await raceWithTimeout({
8
+ promise: sendChannelTyping(params.rest, params.channelId).then(() => ({ kind: "sent" })),
9
+ timeoutMs: DISCORD_TYPING_START_TIMEOUT_MS,
10
+ onTimeout: () => ({ kind: "timeout" })
11
+ })).kind === "timeout") throw new Error(`discord typing start timed out after ${DISCORD_TYPING_START_TIMEOUT_MS}ms`);
12
+ }
13
+ //#endregion
14
+ export { typing_exports as n, sendTyping as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kodelyth/discord",
3
- "version": "2026.5.39",
3
+ "version": "2026.6.1",
4
4
  "description": "Klaw Discord channel plugin",
5
5
  "repository": {
6
6
  "type": "git",
@@ -18,21 +18,25 @@
18
18
  },
19
19
  "devDependencies": {
20
20
  "@kodelyth/plugin-sdk": "1.0.1",
21
- "@kodelyth/klaw": "2026.5.41"
21
+ "@kodelyth/klaw": "2026.5.42"
22
22
  },
23
23
  "peerDependencies": {
24
- "@kodelyth/klaw": ">=2026.5.19"
24
+ "@kodelyth/klaw": ">=2026.5.19",
25
+ "klaw": ">=2026.5.39"
25
26
  },
26
27
  "peerDependenciesMeta": {
27
28
  "@kodelyth/klaw": {
28
29
  "optional": true
30
+ },
31
+ "klaw": {
32
+ "optional": true
29
33
  }
30
34
  },
31
35
  "klaw": {
32
36
  "extensions": [
33
- "./index.js"
37
+ "./index.ts"
34
38
  ],
35
- "setupEntry": "./setup-entry.js",
39
+ "setupEntry": "./setup-entry.ts",
36
40
  "channel": {
37
41
  "id": "discord",
38
42
  "label": "Discord",
@@ -73,6 +77,14 @@
73
77
  "release": {
74
78
  "publishToClawHub": true,
75
79
  "publishToNpm": true
76
- }
77
- }
80
+ },
81
+ "runtimeExtensions": [
82
+ "./dist/index.js"
83
+ ],
84
+ "runtimeSetupEntry": "./dist/setup-entry.js"
85
+ },
86
+ "files": [
87
+ "dist/**",
88
+ "klaw.plugin.json"
89
+ ]
78
90
  }
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/account-inspect-api.js";
2
- import * as module from "../../../dist/extensions/discord/account-inspect-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/action-runtime-api.js";
2
- import * as module from "../../../dist/extensions/discord/action-runtime-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
package/api.js DELETED
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/api.js";
2
- import * as module from "../../../dist/extensions/discord/api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/channel-config-api.js";
2
- import * as module from "../../../dist/extensions/discord/channel-config-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/channel-plugin-api.js";
2
- import * as module from "../../../dist/extensions/discord/channel-plugin-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/configured-state.js";
2
- import * as module from "../../../dist/extensions/discord/configured-state.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
package/contract-api.js DELETED
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/contract-api.js";
2
- import * as module from "../../../dist/extensions/discord/contract-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/directory-contract-api.js";
2
- import * as module from "../../../dist/extensions/discord/directory-contract-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/doctor-contract-api.js";
2
- import * as module from "../../../dist/extensions/discord/doctor-contract-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
package/index.js DELETED
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/index.js";
2
- import defaultModule from "../../../dist/extensions/discord/index.js";
3
- let defaultExport = defaultModule;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/runtime-api.actions.js";
2
- import * as module from "../../../dist/extensions/discord/runtime-api.actions.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
package/runtime-api.js DELETED
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/runtime-api.js";
2
- import * as module from "../../../dist/extensions/discord/runtime-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/runtime-api.lookup.js";
2
- import * as module from "../../../dist/extensions/discord/runtime-api.lookup.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/runtime-api.monitor.js";
2
- import * as module from "../../../dist/extensions/discord/runtime-api.monitor.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/runtime-api.send.js";
2
- import * as module from "../../../dist/extensions/discord/runtime-api.send.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/runtime-api.threads.js";
2
- import * as module from "../../../dist/extensions/discord/runtime-api.threads.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/runtime-setter-api.js";
2
- import * as module from "../../../dist/extensions/discord/runtime-setter-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/secret-contract-api.js";
2
- import * as module from "../../../dist/extensions/discord/secret-contract-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/security-audit-contract-api.js";
2
- import * as module from "../../../dist/extensions/discord/security-audit-contract-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/security-contract-api.js";
2
- import * as module from "../../../dist/extensions/discord/security-contract-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/session-key-api.js";
2
- import * as module from "../../../dist/extensions/discord/session-key-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
package/setup-entry.js DELETED
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/setup-entry.js";
2
- import defaultModule from "../../../dist/extensions/discord/setup-entry.js";
3
- let defaultExport = defaultModule;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };
@@ -1,7 +0,0 @@
1
- export * from "../../../dist/extensions/discord/setup-plugin-api.js";
2
- import * as module from "../../../dist/extensions/discord/setup-plugin-api.js";
3
- let defaultExport = "default" in module ? module.default : module;
4
- for (let index = 0; index < 4 && defaultExport && typeof defaultExport === "object" && "default" in defaultExport; index += 1) {
5
- defaultExport = defaultExport.default;
6
- }
7
- export { defaultExport as default };