@seedcord/core 0.1.0-next.3 → 0.1.0-next.5
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/{CustomId--QizzBOn.d.mts → AutocompleteOptions-eB87SZ4a.d.mts} +494 -154
- package/dist/hmr.index.cjs +166 -0
- package/dist/hmr.index.cjs.map +1 -0
- package/dist/hmr.index.d.cts +1 -0
- package/dist/hmr.index.d.mts +44 -0
- package/dist/hmr.index.mjs +163 -0
- package/dist/hmr.index.mjs.map +1 -0
- package/dist/index.cjs +236 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +181 -25
- package/dist/index.mjs +198 -79
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.cjs +529 -37
- package/dist/internal.index.cjs.map +1 -1
- package/dist/internal.index.d.mts +177 -28
- package/dist/internal.index.mjs +479 -12
- package/dist/internal.index.mjs.map +1 -1
- package/dist/is-never-Ddaba1Su.d.mts +58 -0
- package/dist/node.index.cjs +521 -0
- package/dist/node.index.cjs.map +1 -0
- package/dist/node.index.d.cts +1 -0
- package/dist/node.index.d.mts +2391 -0
- package/dist/node.index.mjs +513 -0
- package/dist/node.index.mjs.map +1 -0
- package/dist/{CustomId-DV7daU7r.cjs → permissions-DQL5ViZn.cjs} +430 -89
- package/dist/permissions-DQL5ViZn.cjs.map +1 -0
- package/dist/{CustomId-epJayEGO.mjs → permissions-SokZLJMj.mjs} +329 -90
- package/dist/permissions-SokZLJMj.mjs.map +1 -0
- package/dist/rolldown-runtime-C_NdSu1c.cjs +34 -0
- package/package.json +32 -7
- package/dist/CustomId-DV7daU7r.cjs.map +0 -1
- package/dist/CustomId-epJayEGO.mjs.map +0 -1
package/dist/internal.index.mjs
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { A as CustomId, B as GatedMetadataKey, C as areRoutes, D as storeInteractionRoute, E as storeComponentRoute, G as SubscribeMetadataKey, H as InteractionRouteKeys, I as setBotColor, K as WebhookUrlMetadataKey, M as prefixOf, N as NoticeCard, O as ComponentDefsKey, R as CommandMetadataKey, T as selectMenuRouteOf, U as InteractionRoutes, V as InteractionMetadataKey, W as MiddlewareMetadataKey, _ as NotInGuild, a as pickNotice, d as GateNotice, f as MissingPermissions, g as NotInDm, h as NotAllowed, j as decodeFor, k as decodeComponentRoute, l as runCheck, m as NeedsAny, o as discardCommits, p as MissingRole, t as PermissionNames, u as runCommits, v as NotOwner, w as contextMenuRouteOf, y as OnCooldown, z as EventMetadataKey } from "./permissions-SokZLJMj.mjs";
|
|
2
|
+
import "reflect-metadata";
|
|
3
|
+
import { SeedcordErrorCode } from "@seedcord/errors";
|
|
4
|
+
import { SeedcordError } from "@seedcord/errors/internal";
|
|
5
|
+
import { MessageFlags } from "discord-api-types/v10";
|
|
6
|
+
import { TextDisplayBuilder } from "@discordjs/builders";
|
|
7
|
+
import { Logger, paint } from "@seedcord/logger";
|
|
8
|
+
import { formatFilePath } from "@seedcord/utils";
|
|
9
|
+
import { Envapter } from "envapt";
|
|
10
|
+
import chalk from "chalk";
|
|
2
11
|
|
|
3
12
|
//#region src/gates/runGates.ts
|
|
4
13
|
function routeIdOf(handlerCtor) {
|
|
@@ -8,36 +17,127 @@ function routeIdOf(handlerCtor) {
|
|
|
8
17
|
}
|
|
9
18
|
return null;
|
|
10
19
|
}
|
|
20
|
+
async function timedCheck(gate, ctx, observe) {
|
|
21
|
+
const start = performance.now();
|
|
22
|
+
try {
|
|
23
|
+
await runCheck(gate, ctx);
|
|
24
|
+
} finally {
|
|
25
|
+
observe(gate.name, performance.now() - start);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
11
28
|
/**
|
|
12
29
|
* Runs each gate's check in order, so the first refusal propagates to the dispatcher boundary. An effect
|
|
13
|
-
* gate's commit runs once the whole set passes.
|
|
30
|
+
* gate's commit runs once the whole set passes. When `observe` is given, each check is timed and reported,
|
|
31
|
+
* commits excluded.
|
|
14
32
|
*/
|
|
15
|
-
async function runGates(gates, ctx) {
|
|
33
|
+
async function runGates(gates, ctx, observe) {
|
|
16
34
|
try {
|
|
17
|
-
for (const gate of gates) await runCheck(gate, ctx);
|
|
35
|
+
for (const gate of gates) await (observe ? timedCheck(gate, ctx, observe) : runCheck(gate, ctx));
|
|
18
36
|
await runCommits(ctx);
|
|
19
37
|
} finally {
|
|
20
38
|
discardCommits(ctx);
|
|
21
39
|
}
|
|
22
40
|
}
|
|
23
|
-
async function runHandlerGates(handlerCtor, ctx) {
|
|
41
|
+
async function runHandlerGates(handlerCtor, ctx, routeId, observe) {
|
|
24
42
|
const gates = Reflect.getMetadata(GatedMetadataKey, handlerCtor);
|
|
25
43
|
if (!gates) return;
|
|
26
44
|
await runGates(gates, {
|
|
27
45
|
...ctx,
|
|
28
|
-
routeId: routeIdOf(handlerCtor)
|
|
29
|
-
});
|
|
46
|
+
routeId: routeId ?? routeIdOf(handlerCtor)
|
|
47
|
+
}, observe);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/gates/slowGate.ts
|
|
52
|
+
const SLOW_GATE_MS = 750;
|
|
53
|
+
let gateLogger;
|
|
54
|
+
function logger() {
|
|
55
|
+
gateLogger ??= new Logger("Gates");
|
|
56
|
+
return gateLogger;
|
|
57
|
+
}
|
|
58
|
+
function slowGateMonitor() {
|
|
59
|
+
if (Envapter.isProduction) return void 0;
|
|
60
|
+
const readings = [];
|
|
61
|
+
return {
|
|
62
|
+
observe: (name, ms) => readings.push({
|
|
63
|
+
name,
|
|
64
|
+
ms
|
|
65
|
+
}),
|
|
66
|
+
report(routeId) {
|
|
67
|
+
const total = readings.reduce((sum, reading) => sum + reading.ms, 0);
|
|
68
|
+
if (total < SLOW_GATE_MS) return;
|
|
69
|
+
const shares = readings.toSorted((a, b) => b.ms - a.ms).map((reading) => `${paint.sky.bold(reading.name)} ${Math.round(reading.ms)}ms`);
|
|
70
|
+
const headline = `gates${routeId === null ? "" : ` for ${paint.sky.bold(routeId)}`} took ${paint.amber(`${Math.round(total)}ms`)} of the 3s ack budget`;
|
|
71
|
+
logger().utils.block(headline, shares, "warn", (text) => text);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
30
74
|
}
|
|
31
75
|
|
|
32
76
|
//#endregion
|
|
33
|
-
//#region src/
|
|
77
|
+
//#region src/hmr/devChannel.ts
|
|
78
|
+
let channel;
|
|
79
|
+
/** @internal */
|
|
80
|
+
function setDevChannel(next) {
|
|
81
|
+
channel = next;
|
|
82
|
+
}
|
|
83
|
+
/** @internal */
|
|
84
|
+
function getDevChannel() {
|
|
85
|
+
return channel;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/hmr/wrapHot.ts
|
|
34
90
|
/**
|
|
35
|
-
*
|
|
36
|
-
* against them at runtime.
|
|
91
|
+
* Wraps a raw vite hot object as a typed {@link DevChannel}.
|
|
37
92
|
*
|
|
38
93
|
* @internal
|
|
39
94
|
*/
|
|
40
|
-
|
|
95
|
+
function wrapHot(hot) {
|
|
96
|
+
return {
|
|
97
|
+
send: (event, data) => hot.send(event, data),
|
|
98
|
+
on: (event, cb) => hot.on(event, cb)
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/hmr/HmrManager.ts
|
|
104
|
+
var HmrManager = class {
|
|
105
|
+
logger = new Logger("HMR", { channel: "hmr" });
|
|
106
|
+
listeners = /* @__PURE__ */ new Set();
|
|
107
|
+
/** @internal */
|
|
108
|
+
init() {
|
|
109
|
+
if (!import.meta.hot) return;
|
|
110
|
+
const channel = wrapHot(import.meta.hot);
|
|
111
|
+
setDevChannel(channel);
|
|
112
|
+
if (Envapter.isDevelopment || Envapter.isTest) {
|
|
113
|
+
this.logger.info("Enabled");
|
|
114
|
+
channel.on("seedcord:hmr", (payload) => {
|
|
115
|
+
const affected = payload.affectedModules?.length ?? 0;
|
|
116
|
+
this.logger.info(`${chalk.bold("1")} module changed, ${chalk.bold(affected)} affected modules`);
|
|
117
|
+
if (payload.affectedModules) this.logger.utils.list(payload.affectedModules.map((mod) => formatFilePath(mod)), "Affected modules: ");
|
|
118
|
+
this.handleUpdate(payload);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** @internal */
|
|
123
|
+
register(listener) {
|
|
124
|
+
this.listeners.add(listener);
|
|
125
|
+
}
|
|
126
|
+
/** @internal */
|
|
127
|
+
unregister(listener) {
|
|
128
|
+
this.listeners.delete(listener);
|
|
129
|
+
}
|
|
130
|
+
async handleUpdate(event) {
|
|
131
|
+
const promises = [...this.listeners].map(async (listener) => {
|
|
132
|
+
try {
|
|
133
|
+
await listener.onHmr(event);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
this.logger.error(`Error handling HMR update in ${chalk.bold(listener.name)}: `, error);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
await Promise.all(promises);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
41
141
|
|
|
42
142
|
//#endregion
|
|
43
143
|
//#region src/pagination/cursor.ts
|
|
@@ -49,5 +149,372 @@ function pageCursor(prefix) {
|
|
|
49
149
|
}
|
|
50
150
|
|
|
51
151
|
//#endregion
|
|
52
|
-
|
|
152
|
+
//#region src/reply/flags.ts
|
|
153
|
+
/** IsComponentsV2 is unconditional, every framework reply is v2. */
|
|
154
|
+
function sendFlags(opts) {
|
|
155
|
+
let flags = MessageFlags.IsComponentsV2;
|
|
156
|
+
if (opts?.ephemeral ?? true) flags |= MessageFlags.Ephemeral;
|
|
157
|
+
if (opts?.silent) flags |= MessageFlags.SuppressNotifications;
|
|
158
|
+
return flags;
|
|
159
|
+
}
|
|
160
|
+
/** A deferral carries no content, so only Ephemeral applies. */
|
|
161
|
+
function deferFlags(opts) {
|
|
162
|
+
return opts?.ephemeral ?? true ? MessageFlags.Ephemeral : 0;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region src/reply/ackLegality.ts
|
|
167
|
+
const showModalReason = {
|
|
168
|
+
reason: "this interaction was already acknowledged",
|
|
169
|
+
alternative: "showModal() must be the initial response."
|
|
170
|
+
};
|
|
171
|
+
function deferReason(what) {
|
|
172
|
+
return {
|
|
173
|
+
reason: `this interaction was already acknowledged with ${what}`,
|
|
174
|
+
alternative: "A deferral can only be the initial response."
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
const ILLEGAL = {
|
|
178
|
+
reply: {
|
|
179
|
+
"deferred-reply": {
|
|
180
|
+
reason: "this interaction was already deferred",
|
|
181
|
+
alternative: "Use edit() to fill the deferred reply or followUp() for a new message."
|
|
182
|
+
},
|
|
183
|
+
"deferred-update": {
|
|
184
|
+
reason: "this interaction was already acknowledged with a deferred update",
|
|
185
|
+
alternative: "Use followUp() for a new message."
|
|
186
|
+
},
|
|
187
|
+
replied: {
|
|
188
|
+
reason: "this interaction was already replied to",
|
|
189
|
+
alternative: "Use followUp() for a new message or edit() to rewrite the reply."
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
defer: {
|
|
193
|
+
"deferred-reply": deferReason("a deferred reply"),
|
|
194
|
+
"deferred-update": deferReason("a deferred update"),
|
|
195
|
+
replied: deferReason("a reply")
|
|
196
|
+
},
|
|
197
|
+
deferUpdate: {
|
|
198
|
+
"deferred-reply": deferReason("a deferred reply"),
|
|
199
|
+
"deferred-update": deferReason("a deferred update"),
|
|
200
|
+
replied: deferReason("a reply")
|
|
201
|
+
},
|
|
202
|
+
update: {
|
|
203
|
+
"deferred-reply": {
|
|
204
|
+
reason: "this interaction was deferred as a reply",
|
|
205
|
+
alternative: "The placeholder is yours via edit(). update() rewrites a source message."
|
|
206
|
+
},
|
|
207
|
+
replied: {
|
|
208
|
+
reason: "this interaction was already replied to",
|
|
209
|
+
alternative: "update() rewrites a source message. Use edit() or followUp() instead."
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
followUp: { unacked: {
|
|
213
|
+
reason: "this interaction has not been acknowledged yet",
|
|
214
|
+
alternative: "Ack first with reply() or defer()."
|
|
215
|
+
} },
|
|
216
|
+
edit: { unacked: {
|
|
217
|
+
reason: "nothing has been sent yet",
|
|
218
|
+
alternative: "Send with reply() or defer() first, then edit() rewrites it."
|
|
219
|
+
} },
|
|
220
|
+
delete: { unacked: {
|
|
221
|
+
reason: "nothing has been sent yet",
|
|
222
|
+
alternative: "Acknowledge first with reply() or defer(), then delete() removes it."
|
|
223
|
+
} },
|
|
224
|
+
showModal: {
|
|
225
|
+
"deferred-reply": showModalReason,
|
|
226
|
+
"deferred-update": showModalReason,
|
|
227
|
+
replied: showModalReason
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
const SEND_TARGET = {
|
|
231
|
+
unacked: "reply",
|
|
232
|
+
"deferred-reply": "edit",
|
|
233
|
+
"deferred-update": "followUp",
|
|
234
|
+
replied: "followUp"
|
|
235
|
+
};
|
|
236
|
+
/** Throws before any API call. `ackedBy` becomes the throw cause, its stack points at the first ack. */
|
|
237
|
+
function checkAckLegality(method, state, routeId, ackedBy) {
|
|
238
|
+
if (method === "send") return;
|
|
239
|
+
const illegal = ILLEGAL[method][state];
|
|
240
|
+
if (!illegal) return;
|
|
241
|
+
throw new SeedcordError(SeedcordErrorCode.ReplyIllegalAckState, [
|
|
242
|
+
method,
|
|
243
|
+
illegal.reason,
|
|
244
|
+
illegal.alternative,
|
|
245
|
+
routeId
|
|
246
|
+
], { cause: ackedBy });
|
|
247
|
+
}
|
|
248
|
+
function sendTarget(state) {
|
|
249
|
+
return SEND_TARGET[state];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
//#endregion
|
|
253
|
+
//#region src/reply/AckTrace.ts
|
|
254
|
+
/** The first ack's stack, passed as the throw cause so a double-ack points to both lines. */
|
|
255
|
+
var AckTrace = class extends Error {
|
|
256
|
+
constructor(method) {
|
|
257
|
+
super(`${method}() acknowledged this interaction`);
|
|
258
|
+
this.name = "AckTrace";
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
//#endregion
|
|
263
|
+
//#region src/reply/translateSerialization.ts
|
|
264
|
+
const MAX_DEPTH = 8;
|
|
265
|
+
const OPERATOR_WORD = {
|
|
266
|
+
"<=": "at most",
|
|
267
|
+
">=": "at least",
|
|
268
|
+
"<": "fewer than",
|
|
269
|
+
">": "more than"
|
|
270
|
+
};
|
|
271
|
+
const KIND_WORD = {
|
|
272
|
+
string: "a string",
|
|
273
|
+
number: "a number",
|
|
274
|
+
boolean: "a boolean",
|
|
275
|
+
bigint: "a bigint",
|
|
276
|
+
array: "a list",
|
|
277
|
+
tuple: "a list",
|
|
278
|
+
date: "a date",
|
|
279
|
+
object: "an object"
|
|
280
|
+
};
|
|
281
|
+
function asRecord(value) {
|
|
282
|
+
return typeof value === "object" && value !== null ? value : null;
|
|
283
|
+
}
|
|
284
|
+
function firstLine(message) {
|
|
285
|
+
if (typeof message !== "string") return "unknown validation failure";
|
|
286
|
+
return message.split("\n")[0] ?? message;
|
|
287
|
+
}
|
|
288
|
+
const GIVEN_PREVIEW_LIMIT = 40;
|
|
289
|
+
function gotPhrase(given) {
|
|
290
|
+
if (given === void 0) return "nothing";
|
|
291
|
+
if (given === null) return "null";
|
|
292
|
+
if (typeof given === "string") {
|
|
293
|
+
if (given.length === 0) return "an empty string";
|
|
294
|
+
if (given.length > GIVEN_PREVIEW_LIMIT) return `${given.length} characters`;
|
|
295
|
+
return JSON.stringify(given);
|
|
296
|
+
}
|
|
297
|
+
if (Array.isArray(given)) return given.length === 0 ? "an empty list" : `${given.length} items`;
|
|
298
|
+
if (typeof given === "number" || typeof given === "bigint" || typeof given === "boolean") return String(given);
|
|
299
|
+
if (typeof given === "object") return given.constructor?.name ?? "an object";
|
|
300
|
+
return typeof given;
|
|
301
|
+
}
|
|
302
|
+
function needPhrase(expected, given) {
|
|
303
|
+
const bounds = [...expected.matchAll(/expected(\.length)?\s*(<=|>=|<|>)\s*(\d+)/g)];
|
|
304
|
+
if (bounds.length === 0) return null;
|
|
305
|
+
return bounds.map(([, lengthPart, operator, limit]) => {
|
|
306
|
+
const word = OPERATOR_WORD[operator ?? ""] ?? operator ?? "";
|
|
307
|
+
if (!lengthPart) return `${word} ${limit}`;
|
|
308
|
+
const unit = typeof given === "string" ? "character" : "item";
|
|
309
|
+
return `${word} ${limit} ${Number(limit) === 1 ? unit : `${unit}s`}`;
|
|
310
|
+
}).join(" and ");
|
|
311
|
+
}
|
|
312
|
+
function instanceName(expected) {
|
|
313
|
+
if (typeof expected === "function" && expected.name) return expected.name;
|
|
314
|
+
return "specific class instance";
|
|
315
|
+
}
|
|
316
|
+
function describeLeaf(record) {
|
|
317
|
+
if (typeof record.constraint === "string") {
|
|
318
|
+
const need = typeof record.expected === "string" ? needPhrase(record.expected, record.given) : null;
|
|
319
|
+
if (need) return `need ${need}, got ${gotPhrase(record.given)}`;
|
|
320
|
+
return `${firstLine(record.message)}${"given" in record ? ` (got ${gotPhrase(record.given)})` : ""}`;
|
|
321
|
+
}
|
|
322
|
+
if (typeof record.expected === "function") return `need a ${instanceName(record.expected)}, got ${gotPhrase(record.given)}`;
|
|
323
|
+
if (typeof record.validator === "string") {
|
|
324
|
+
const kind = KIND_WORD[record.validator.replace(/^s\./, "").replace(/\(.*$/, "")];
|
|
325
|
+
if (kind) return `need ${kind}, got ${gotPhrase(record.given)}`;
|
|
326
|
+
return `${firstLine(record.message)}, got ${gotPhrase(record.given)}`;
|
|
327
|
+
}
|
|
328
|
+
return firstLine(record.message);
|
|
329
|
+
}
|
|
330
|
+
function describeUnion(branches, depth) {
|
|
331
|
+
const records = [];
|
|
332
|
+
for (const branch of branches) {
|
|
333
|
+
const record = asRecord(branch);
|
|
334
|
+
if (record) records.push(record);
|
|
335
|
+
}
|
|
336
|
+
const bounded = records.find((record) => typeof record.constraint === "string");
|
|
337
|
+
if (bounded) return describeLeaf(bounded);
|
|
338
|
+
const names = [];
|
|
339
|
+
let allInstances = records.length > 0;
|
|
340
|
+
for (const record of records) if (typeof record.expected === "function") names.push(instanceName(record.expected));
|
|
341
|
+
else allInstances = false;
|
|
342
|
+
if (allInstances) return `need a ${[...new Set(names)].join(" or ")}, got ${gotPhrase(records[0]?.given)}`;
|
|
343
|
+
return detailOf(branches[0], depth + 1);
|
|
344
|
+
}
|
|
345
|
+
function detailOf(value, depth) {
|
|
346
|
+
const record = asRecord(value);
|
|
347
|
+
if (!record || depth >= MAX_DEPTH) return firstLine(record?.message);
|
|
348
|
+
if (Array.isArray(record.errors) && record.errors.length > 0) {
|
|
349
|
+
const errors = record.errors;
|
|
350
|
+
const [first] = errors;
|
|
351
|
+
if (Array.isArray(first)) {
|
|
352
|
+
const [key, inner] = first;
|
|
353
|
+
return `${String(key)}: ${detailOf(inner, depth + 1)}`;
|
|
354
|
+
}
|
|
355
|
+
return describeUnion(errors, depth);
|
|
356
|
+
}
|
|
357
|
+
return describeLeaf(record);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Translates a shapeshift throw into an actionable message, keeping the original as `cause`. Any other
|
|
361
|
+
* throw contributes its message as the detail.
|
|
362
|
+
*/
|
|
363
|
+
function translateSerializationError(error, componentClass, index, routeId) {
|
|
364
|
+
const detail = detailOf(error, 0);
|
|
365
|
+
return new SeedcordError(SeedcordErrorCode.ReplyComponentSerialization, [
|
|
366
|
+
componentClass,
|
|
367
|
+
index,
|
|
368
|
+
detail,
|
|
369
|
+
routeId
|
|
370
|
+
], { cause: error });
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
//#endregion
|
|
374
|
+
//#region src/reply/serializeReply.ts
|
|
375
|
+
/** Wraps a string in a TextDisplay component. */
|
|
376
|
+
function serializeReply(response, routeId) {
|
|
377
|
+
if (typeof response === "string") try {
|
|
378
|
+
return { components: [new TextDisplayBuilder().setContent(response).toJSON()] };
|
|
379
|
+
} catch (error) {
|
|
380
|
+
throw translateSerializationError(error, "TextDisplayBuilder", 0, routeId);
|
|
381
|
+
}
|
|
382
|
+
return {
|
|
383
|
+
components: response.components.map((component, index) => {
|
|
384
|
+
try {
|
|
385
|
+
return component.toJSON();
|
|
386
|
+
} catch (error) {
|
|
387
|
+
const name = component.constructor?.name;
|
|
388
|
+
throw translateSerializationError(error, !name || name === "Object" ? "component" : name, index, routeId);
|
|
389
|
+
}
|
|
390
|
+
}),
|
|
391
|
+
...response.allowedMentions && { allowedMentions: response.allowedMentions },
|
|
392
|
+
...response.files && { files: response.files }
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
//#endregion
|
|
397
|
+
//#region src/reply/BaseReplySender.ts
|
|
398
|
+
/**
|
|
399
|
+
* Tracks acknowledgement state and throws a translated `SeedcordError` on an illegal verb before any
|
|
400
|
+
* transport call. Verbs execute the legality check, control the transport wire writer, then update the
|
|
401
|
+
* state and ack trace. Each transport binds `TMessage` to its created-message lens and supplies the
|
|
402
|
+
* writers.
|
|
403
|
+
*/
|
|
404
|
+
var BaseReplySender = class {
|
|
405
|
+
routeId;
|
|
406
|
+
state;
|
|
407
|
+
sent = /* @__PURE__ */ new Set();
|
|
408
|
+
ackedBy;
|
|
409
|
+
constructor(routeId, initialState = "unacked") {
|
|
410
|
+
this.routeId = routeId;
|
|
411
|
+
this.state = initialState;
|
|
412
|
+
}
|
|
413
|
+
async reply(response, opts) {
|
|
414
|
+
this.checkLegality("reply");
|
|
415
|
+
const created = await this.writeReply(response, opts);
|
|
416
|
+
this.transition("reply", "replied");
|
|
417
|
+
return this.remember(this.requireMessage(created, "reply"));
|
|
418
|
+
}
|
|
419
|
+
async defer(opts) {
|
|
420
|
+
this.checkLegality("defer");
|
|
421
|
+
await this.writeDefer(opts);
|
|
422
|
+
this.transition("defer", "deferred-reply");
|
|
423
|
+
}
|
|
424
|
+
async deferUpdate() {
|
|
425
|
+
this.checkLegality("deferUpdate");
|
|
426
|
+
await this.writeDeferUpdate();
|
|
427
|
+
this.transition("deferUpdate", "deferred-update");
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* After a deferUpdate the state stays deferred-update, so the rewrite repeats. The returned message
|
|
431
|
+
* is the source message, editable only through a bare `update` or `edit`. A targeted `edit` or `delete`
|
|
432
|
+
* of it throws the foreign-target error.
|
|
433
|
+
*/
|
|
434
|
+
async update(response) {
|
|
435
|
+
this.checkLegality("update");
|
|
436
|
+
if (this.state === "deferred-update") return await this.editOriginal(response);
|
|
437
|
+
const created = await this.writeUpdate(response);
|
|
438
|
+
this.transition("update", "replied");
|
|
439
|
+
return this.remember(this.requireMessage(created, "update"));
|
|
440
|
+
}
|
|
441
|
+
async followUp(response, opts) {
|
|
442
|
+
this.checkLegality("followUp");
|
|
443
|
+
const created = await this.writeFollowUp(response, opts);
|
|
444
|
+
return this.remember(created);
|
|
445
|
+
}
|
|
446
|
+
async edit(targetOrResponse, maybeResponse) {
|
|
447
|
+
this.checkLegality("edit");
|
|
448
|
+
if (maybeResponse === void 0) return await this.editOriginal(targetOrResponse);
|
|
449
|
+
const target = targetOrResponse;
|
|
450
|
+
if (!this.sent.has(target.id)) throw new SeedcordError(SeedcordErrorCode.ReplyForeignEditTarget, [
|
|
451
|
+
"edit",
|
|
452
|
+
target.id,
|
|
453
|
+
this.routeId
|
|
454
|
+
]);
|
|
455
|
+
return this.remember(await this.writeEditTarget(target.id, maybeResponse));
|
|
456
|
+
}
|
|
457
|
+
async delete(target) {
|
|
458
|
+
this.checkLegality("delete");
|
|
459
|
+
if (target === void 0) {
|
|
460
|
+
await this.writeDeleteOriginal();
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
if (!this.sent.has(target.id)) throw new SeedcordError(SeedcordErrorCode.ReplyForeignEditTarget, [
|
|
464
|
+
"delete",
|
|
465
|
+
target.id,
|
|
466
|
+
this.routeId
|
|
467
|
+
]);
|
|
468
|
+
await this.writeDeleteTarget(target.id);
|
|
469
|
+
this.sent.delete(target.id);
|
|
470
|
+
}
|
|
471
|
+
/** Routes to the verb the current ack state permits. Every state has a route, so the illegal-ack throw is unreachable. */
|
|
472
|
+
async send(response, opts) {
|
|
473
|
+
const target = sendTarget(this.state);
|
|
474
|
+
if (target === "reply") return await this.reply(response, opts);
|
|
475
|
+
if (target === "edit") return await this.edit(response);
|
|
476
|
+
return await this.followUp(response, opts);
|
|
477
|
+
}
|
|
478
|
+
/** Must be the initial response. */
|
|
479
|
+
async showModal(modal) {
|
|
480
|
+
this.checkLegality("showModal");
|
|
481
|
+
this.guardModalSource();
|
|
482
|
+
let data;
|
|
483
|
+
try {
|
|
484
|
+
data = modal.toJSON();
|
|
485
|
+
} catch (error) {
|
|
486
|
+
const name = modal.constructor?.name;
|
|
487
|
+
throw translateSerializationError(error, !name || name === "Object" ? "modal" : name, 0, this.routeId);
|
|
488
|
+
}
|
|
489
|
+
await this.writeModal(data);
|
|
490
|
+
this.transition("showModal", "replied");
|
|
491
|
+
}
|
|
492
|
+
serialize(response) {
|
|
493
|
+
return serializeReply(response, this.routeId);
|
|
494
|
+
}
|
|
495
|
+
remember(created) {
|
|
496
|
+
this.sent.add(created.id);
|
|
497
|
+
return created;
|
|
498
|
+
}
|
|
499
|
+
requireMessage(created, method) {
|
|
500
|
+
if (!created) throw new SeedcordError(SeedcordErrorCode.ReplyCallbackMissingMessage, [method, this.routeId]);
|
|
501
|
+
return created;
|
|
502
|
+
}
|
|
503
|
+
async editOriginal(response) {
|
|
504
|
+
const edited = await this.writeEditOriginal(response);
|
|
505
|
+
if (this.state !== "deferred-update") this.remember(edited);
|
|
506
|
+
return edited;
|
|
507
|
+
}
|
|
508
|
+
checkLegality(method) {
|
|
509
|
+
checkAckLegality(method, this.state, this.routeId, this.ackedBy);
|
|
510
|
+
}
|
|
511
|
+
transition(method, state) {
|
|
512
|
+
this.state = state;
|
|
513
|
+
this.ackedBy = new AckTrace(method);
|
|
514
|
+
}
|
|
515
|
+
guardModalSource() {}
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
//#endregion
|
|
519
|
+
export { AckTrace, BaseReplySender, CommandMetadataKey, ComponentDefsKey, EventMetadataKey, GateNotice, GatedMetadataKey, HmrManager, InteractionMetadataKey, InteractionRouteKeys, InteractionRoutes, MiddlewareMetadataKey, MissingPermissions, MissingRole, NeedsAny, NotAllowed, NotInDm, NotInGuild, NotOwner, NoticeCard, OnCooldown, PAGE_MAX, PermissionNames, SubscribeMetadataKey, WebhookUrlMetadataKey, areRoutes, checkAckLegality, contextMenuRouteOf, decodeComponentRoute, decodeFor, deferFlags, getDevChannel, pageCursor, pickNotice, prefixOf, routeIdOf, runGates, runHandlerGates, selectMenuRouteOf, sendFlags, sendTarget, serializeReply, setBotColor, setDevChannel, slowGateMonitor, storeComponentRoute, storeInteractionRoute, translateSerializationError, wrapHot };
|
|
53
520
|
//# sourceMappingURL=internal.index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal.index.mjs","names":[],"sources":["../src/gates/runGates.ts","../src/customId/routing.ts","../src/pagination/cursor.ts"],"sourcesContent":["import { GatedMetadataKey, InteractionRouteKeys } from '@src/metadataKeys';\n\nimport { discardCommits, runCheck, runCommits } from './effects';\n\nimport type { Gate, GateContextBase } from './Gate';\n\n// the stable id a route decorator stored, e.g. slash:daily or button:confirm. null for a plain event handler.\nexport function routeIdOf(handlerCtor: object): string | null {\n for (const [kind, key] of Object.entries(InteractionRouteKeys)) {\n // justified: getMetadata returns any, this key only ever stores the route/prefix string array\n const routes = Reflect.getMetadata(key, handlerCtor) as string[] | undefined;\n if (routes?.length) return `${kind}:${routes.join(',')}`;\n }\n return null;\n}\n\n/**\n * Runs each gate's check in order, so the first refusal propagates to the dispatcher boundary. An effect\n * gate's commit runs once the whole set passes.\n */\nexport async function runGates(gates: readonly Gate<GateContextBase>[], ctx: GateContextBase): Promise<void> {\n try {\n for (const gate of gates) {\n await runCheck(gate, ctx);\n }\n await runCommits(ctx);\n } finally {\n discardCommits(ctx);\n }\n}\n\n// dispatchers call this before execute, inside the boundary, so a refusal renders or drops\nexport async function runHandlerGates(handlerCtor: object, ctx: GateContextBase): Promise<void> {\n // justified: getMetadata returns any, and this key only ever stores the @Gated gate array\n const gates = Reflect.getMetadata(GatedMetadataKey, handlerCtor) as readonly Gate<GateContextBase>[] | undefined;\n if (!gates) return;\n await runGates(gates, { ...ctx, routeId: routeIdOf(handlerCtor) });\n}\n","import type { AnyCustomId } from './CustomId';\n\n/**\n * The route decorators store a handler's customId definitions here so the component base can decode\n * against them at runtime.\n *\n * @internal\n */\nexport const ComponentDefsKey = Symbol('seedcord:customId:componentDefs');\n\n/**\n * The phantom a component handler base carries. A route decorator constrains its argument to this, so\n * passing different definitions to the decorator and the handler's generic is a compile error. Never set at runtime.\n *\n * @internal\n */\nexport interface HasComponentDefs<Defs extends readonly AnyCustomId[]> {\n readonly __componentDefs?: Defs;\n}\n","import { CustomId } from '@customId/CustomId';\n\nimport type { CustomIdField } from '@customId/Field';\n\n// Included in the layout hash so it is fixed per prefix. Reducing it marks every active button as StaleCustomId.\n// @internal\nexport const PAGE_MAX = 1_000_000;\n\n// Discord rejects a message with duplicate custom_ids, and two controls can target the same page (first and\n// prev both hit 0), so each control uses a distinct slot.\n// @internal\nconst SLOT_MAX = 4;\n\n/** Page cursor for a paginator. */\nexport type PageCursor<Prefix extends string> = CustomId<\n Prefix,\n { page: CustomIdField<number>; slot: CustomIdField<number> }\n>;\n\n/** Build the page cursor for a paginator. */\nexport function pageCursor<Prefix extends string>(prefix: Prefix): PageCursor<Prefix> {\n return new CustomId(prefix).int('page', 0, PAGE_MAX).int('slot', 0, SLOT_MAX);\n}\n"],"mappings":";;;AAOA,SAAgB,UAAU,aAAoC;CAC1D,KAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,oBAAoB,GAAG;EAE5D,MAAM,SAAS,QAAQ,YAAY,KAAK,WAAW;EACnD,IAAI,QAAQ,QAAQ,OAAO,GAAG,KAAK,GAAG,OAAO,KAAK,GAAG;CACzD;CACA,OAAO;AACX;;;;;AAMA,eAAsB,SAAS,OAAyC,KAAqC;CACzG,IAAI;EACA,KAAK,MAAM,QAAQ,OACf,MAAM,SAAS,MAAM,GAAG;EAE5B,MAAM,WAAW,GAAG;CACxB,UAAU;EACN,eAAe,GAAG;CACtB;AACJ;AAGA,eAAsB,gBAAgB,aAAqB,KAAqC;CAE5F,MAAM,QAAQ,QAAQ,YAAY,kBAAkB,WAAW;CAC/D,IAAI,CAAC,OAAO;CACZ,MAAM,SAAS,OAAO;EAAE,GAAG;EAAK,SAAS,UAAU,WAAW;CAAE,CAAC;AACrE;;;;;;;;;;AC7BA,MAAa,mBAAmB,OAAO,iCAAiC;;;;ACFxE,MAAa,WAAW;AAKxB,MAAM,WAAW;;AASjB,SAAgB,WAAkC,QAAoC;CAClF,OAAO,IAAI,SAAS,MAAM,CAAC,CAAC,IAAI,QAAQ,GAAG,QAAQ,CAAC,CAAC,IAAI,QAAQ,GAAG,QAAQ;AAChF"}
|
|
1
|
+
{"version":3,"file":"internal.index.mjs","names":[],"sources":["../src/gates/runGates.ts","../src/gates/slowGate.ts","../src/hmr/devChannel.ts","../src/hmr/wrapHot.ts","../src/hmr/HmrManager.ts","../src/pagination/cursor.ts","../src/reply/flags.ts","../src/reply/ackLegality.ts","../src/reply/AckTrace.ts","../src/reply/translateSerialization.ts","../src/reply/serializeReply.ts","../src/reply/BaseReplySender.ts"],"sourcesContent":["import 'reflect-metadata';\n\nimport { GatedMetadataKey, InteractionRouteKeys } from '@src/metadataKeys';\n\nimport { discardCommits, runCheck, runCommits } from './effects';\n\nimport type { Gate, GateContextBase } from './Gate';\n\n/**\n * Receives each gate's name and how long its check ran, in ms. A combinator (`and`/`or`) reports once\n * under its joined name.\n */\nexport type GateObserver = (gateName: string, elapsedMs: number) => void;\n\n// the stable id a route decorator stored, e.g. slash:daily or button:confirm. null for a plain event handler.\nexport function routeIdOf(handlerCtor: object): string | null {\n for (const [kind, key] of Object.entries(InteractionRouteKeys)) {\n // justified: getMetadata returns any, this key only ever stores the route/prefix string array\n const routes = Reflect.getMetadata(key, handlerCtor) as string[] | undefined;\n if (routes?.length) return `${kind}:${routes.join(',')}`;\n }\n return null;\n}\n\nasync function timedCheck(gate: Gate<GateContextBase>, ctx: GateContextBase, observe: GateObserver): Promise<void> {\n const start = performance.now();\n // finally so a refusing gate still reports\n try {\n await runCheck(gate, ctx);\n } finally {\n observe(gate.name, performance.now() - start);\n }\n}\n\n/**\n * Runs each gate's check in order, so the first refusal propagates to the dispatcher boundary. An effect\n * gate's commit runs once the whole set passes. When `observe` is given, each check is timed and reported,\n * commits excluded.\n */\nexport async function runGates(\n gates: readonly Gate<GateContextBase>[],\n ctx: GateContextBase,\n observe?: GateObserver\n): Promise<void> {\n try {\n for (const gate of gates) {\n await (observe ? timedCheck(gate, ctx, observe) : runCheck(gate, ctx));\n }\n await runCommits(ctx);\n } finally {\n discardCommits(ctx);\n }\n}\n\n// dispatchers call this before execute, inside the boundary, so a refusal renders or drops. the\n// explicit routeId overrides the ctor-derived id for manifest-driven handlers with no route metadata.\nexport async function runHandlerGates(\n handlerCtor: object,\n ctx: GateContextBase,\n routeId?: string,\n observe?: GateObserver\n): Promise<void> {\n // justified: getMetadata returns any, and this key only ever stores the @Gated gate array\n const gates = Reflect.getMetadata(GatedMetadataKey, handlerCtor) as readonly Gate<GateContextBase>[] | undefined;\n if (!gates) return;\n await runGates(gates, { ...ctx, routeId: routeId ?? routeIdOf(handlerCtor) }, observe);\n}\n","import { Logger, paint } from '@seedcord/logger';\nimport { Envapter } from 'envapt';\n\nimport type { GateObserver } from './runGates';\n\n// combined check time slower than this cuts into the 3s interaction-ack budget\nconst SLOW_GATE_MS = 750;\n\n// lazy because the logger reads the environment, which binds after this module loads\nlet gateLogger: Logger | undefined;\nfunction logger(): Logger {\n gateLogger ??= new Logger('Gates');\n return gateLogger;\n}\n\n/**\n * Collects each gate check's elapsed time for one dispatch. `report` warns once when the checks sum\n * past the threshold, naming the total, the route, and each gate's share.\n */\nexport interface SlowGateMonitor {\n readonly observe: GateObserver;\n report(routeId: string | null): void;\n}\n\n// undefined in production, so timedCheck skips the clock there. read per call, the environment binds late\nexport function slowGateMonitor(): SlowGateMonitor | undefined {\n if (Envapter.isProduction) return undefined;\n const readings: { name: string; ms: number }[] = [];\n return {\n observe: (name, ms) => readings.push({ name, ms }),\n report(routeId) {\n const total = readings.reduce((sum, reading) => sum + reading.ms, 0);\n if (total < SLOW_GATE_MS) return;\n const shares = readings\n .toSorted((a, b) => b.ms - a.ms)\n .map((reading) => `${paint.sky.bold(reading.name)} ${Math.round(reading.ms)}ms`);\n const route = routeId === null ? '' : ` for ${paint.sky.bold(routeId)}`;\n const headline = `gates${route} took ${paint.amber(`${Math.round(total)}ms`)} of the 3s ack budget`;\n logger().utils.block(headline, shares, 'warn', (text) => text);\n }\n };\n}\n","import type { DevChannel, SeedcordCliEvents, SeedcordFrameworkEvents } from '@seedcord/types/internal';\n\n// one module instance per process, the HmrManager write and every framework read share it\nlet channel: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined;\n\n/** @internal */\nexport function setDevChannel(next: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined): void {\n channel = next;\n}\n\n/** @internal */\nexport function getDevChannel(): DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined {\n return channel;\n}\n","import type { DevChannel } from '@seedcord/types/internal';\n\n// the minimal raw-hot shape, satisfied by both vite's `import.meta.hot` and the CLI's `NormalizedHotChannel`.\ninterface RawHot {\n send(event: string, data?: unknown): void;\n on(event: string, cb: (data: unknown) => void): void;\n}\n\n/**\n * Wraps a raw vite hot object as a typed {@link DevChannel}.\n *\n * @internal\n */\nexport function wrapHot<TSend, TRecv>(hot: RawHot): DevChannel<TSend, TRecv> {\n return {\n send: (event, data) => hot.send(event, data),\n // justified: RawHot types every payload as unknown, the wire contract guarantees it matches TRecv[Key]\n on: (event, cb) => hot.on(event, cb as (data: unknown) => void)\n };\n}\n","// scoped here so import.meta.hot stays untyped in the rest of the package\n/// <reference types=\"vite/client\" />\nimport { Logger } from '@seedcord/logger';\nimport { formatFilePath } from '@seedcord/utils';\nimport chalk from 'chalk';\nimport { Envapter } from 'envapt';\n\nimport { setDevChannel } from './devChannel';\nimport { wrapHot } from './wrapHot';\n\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types';\nimport type { SeedcordCliEvents, SeedcordFrameworkEvents } from '@seedcord/types/internal';\n\nexport class HmrManager {\n private readonly logger = new Logger('HMR', { channel: 'hmr' });\n private readonly listeners = new Set<HmrAware>();\n\n /** @internal */\n public init(): void {\n if (!import.meta.hot) return;\n // the only raw `import.meta.hot` read in the framework\n const channel = wrapHot<SeedcordFrameworkEvents, SeedcordCliEvents>(import.meta.hot);\n setDevChannel(channel);\n\n if (Envapter.isDevelopment || Envapter.isTest) {\n this.logger.info('Enabled');\n\n channel.on('seedcord:hmr', (payload) => {\n const affected = payload.affectedModules?.length ?? 0;\n this.logger.info(`${chalk.bold('1')} module changed, ${chalk.bold(affected)} affected modules`);\n\n if (payload.affectedModules) {\n this.logger.utils.list(\n payload.affectedModules.map((mod) => formatFilePath(mod)),\n 'Affected modules: '\n );\n }\n\n void this.handleUpdate(payload);\n });\n }\n }\n\n /** @internal */\n public register(listener: HmrAware): void {\n this.listeners.add(listener);\n }\n\n /** @internal */\n public unregister(listener: HmrAware): void {\n this.listeners.delete(listener);\n }\n\n private async handleUpdate(event: HmrUpdateEvent): Promise<void> {\n const promises = [...this.listeners].map(async (listener) => {\n try {\n await listener.onHmr(event);\n } catch (error) {\n this.logger.error(`Error handling HMR update in ${chalk.bold(listener.name)}: `, error);\n }\n });\n\n await Promise.all(promises);\n }\n}\n","import { CustomId } from '@customId/CustomId';\n\nimport type { CustomIdField } from '@customId/Field';\n\n// Included in the layout hash so it is fixed per prefix. Reducing it marks every active button as StaleCustomId.\n// @internal\nexport const PAGE_MAX = 1_000_000;\n\n// Discord rejects a message with duplicate custom_ids, and two controls can target the same page (first and\n// prev both hit 0), so each control uses a distinct slot.\n// @internal\nconst SLOT_MAX = 4;\n\n/** Page cursor for a paginator. */\nexport type PageCursor<Prefix extends string> = CustomId<\n Prefix,\n { page: CustomIdField<number>; slot: CustomIdField<number> }\n>;\n\n/** Build the page cursor for a paginator. */\nexport function pageCursor<Prefix extends string>(prefix: Prefix): PageCursor<Prefix> {\n return new CustomId(prefix).int('page', 0, PAGE_MAX).int('slot', 0, SLOT_MAX);\n}\n","import { MessageFlags } from 'discord-api-types/v10';\n\nimport type { DeferOpts, SendOpts } from '@seedcord/types';\n\n/** IsComponentsV2 is unconditional, every framework reply is v2. */\nexport function sendFlags(opts?: SendOpts): number {\n let flags = MessageFlags.IsComponentsV2;\n if (opts?.ephemeral ?? true) flags |= MessageFlags.Ephemeral;\n if (opts?.silent) flags |= MessageFlags.SuppressNotifications;\n return flags;\n}\n\n/** A deferral carries no content, so only Ephemeral applies. */\nexport function deferFlags(opts?: DeferOpts): number {\n return (opts?.ephemeral ?? true) ? MessageFlags.Ephemeral : 0;\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport type { AckTrace } from './AckTrace';\n\nexport type AckState = 'unacked' | 'deferred-reply' | 'deferred-update' | 'replied';\n\nexport type ReplyMethod =\n | 'reply'\n | 'defer'\n | 'deferUpdate'\n | 'update'\n | 'followUp'\n | 'edit'\n | 'delete'\n | 'send'\n | 'showModal';\n\ninterface Illegal {\n // spliced into the message after \"was called when\"\n readonly reason: string;\n readonly alternative: string;\n}\n\nconst showModalReason: Illegal = {\n reason: 'this interaction was already acknowledged',\n alternative: 'showModal() must be the initial response.'\n};\n\nfunction deferReason(what: string): Illegal {\n return {\n reason: `this interaction was already acknowledged with ${what}`,\n alternative: 'A deferral can only be the initial response.'\n };\n}\n\n// a missing entry means legal in that state\nconst ILLEGAL: Record<Exclude<ReplyMethod, 'send'>, Partial<Record<AckState, Illegal>>> = {\n reply: {\n 'deferred-reply': {\n reason: 'this interaction was already deferred',\n alternative: 'Use edit() to fill the deferred reply or followUp() for a new message.'\n },\n 'deferred-update': {\n reason: 'this interaction was already acknowledged with a deferred update',\n alternative: 'Use followUp() for a new message.'\n },\n replied: {\n reason: 'this interaction was already replied to',\n alternative: 'Use followUp() for a new message or edit() to rewrite the reply.'\n }\n },\n defer: {\n 'deferred-reply': deferReason('a deferred reply'),\n 'deferred-update': deferReason('a deferred update'),\n replied: deferReason('a reply')\n },\n deferUpdate: {\n 'deferred-reply': deferReason('a deferred reply'),\n 'deferred-update': deferReason('a deferred update'),\n replied: deferReason('a reply')\n },\n update: {\n 'deferred-reply': {\n reason: 'this interaction was deferred as a reply',\n alternative: 'The placeholder is yours via edit(). update() rewrites a source message.'\n },\n replied: {\n reason: 'this interaction was already replied to',\n alternative: 'update() rewrites a source message. Use edit() or followUp() instead.'\n }\n },\n followUp: {\n unacked: {\n reason: 'this interaction has not been acknowledged yet',\n alternative: 'Ack first with reply() or defer().'\n }\n },\n edit: {\n unacked: {\n reason: 'nothing has been sent yet',\n alternative: 'Send with reply() or defer() first, then edit() rewrites it.'\n }\n },\n delete: {\n unacked: {\n reason: 'nothing has been sent yet',\n alternative: 'Acknowledge first with reply() or defer(), then delete() removes it.'\n }\n },\n showModal: {\n 'deferred-reply': showModalReason,\n 'deferred-update': showModalReason,\n replied: showModalReason\n }\n};\n\nconst SEND_TARGET: Record<AckState, 'reply' | 'edit' | 'followUp'> = {\n unacked: 'reply',\n 'deferred-reply': 'edit',\n 'deferred-update': 'followUp',\n replied: 'followUp'\n};\n\n/** Throws before any API call. `ackedBy` becomes the throw cause, its stack points at the first ack. */\nexport function checkAckLegality(method: ReplyMethod, state: AckState, routeId: string, ackedBy?: AckTrace): void {\n if (method === 'send') return;\n const illegal = ILLEGAL[method][state];\n if (!illegal) return;\n throw new SeedcordError(\n SeedcordErrorCode.ReplyIllegalAckState,\n [method, illegal.reason, illegal.alternative, routeId],\n { cause: ackedBy }\n );\n}\n\nexport function sendTarget(state: AckState): 'reply' | 'edit' | 'followUp' {\n return SEND_TARGET[state];\n}\n","import type { ReplyMethod } from './ackLegality';\n\n/** The first ack's stack, passed as the throw cause so a double-ack points to both lines. */\nexport class AckTrace extends Error {\n public constructor(method: ReplyMethod) {\n super(`${method}() acknowledged this interaction`);\n this.name = 'AckTrace';\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n// shapeshift aggregate errors nest, the cap bounds the recursion\nconst MAX_DEPTH = 8;\n\ninterface ShapeshiftLike {\n readonly message?: unknown;\n readonly errors?: unknown;\n readonly constraint?: unknown;\n readonly validator?: unknown;\n readonly expected?: unknown;\n readonly given?: unknown;\n}\n\nconst OPERATOR_WORD: Record<string, string> = {\n '<=': 'at most',\n '>=': 'at least',\n '<': 'fewer than',\n '>': 'more than'\n};\n\nconst KIND_WORD: Record<string, string> = {\n string: 'a string',\n number: 'a number',\n boolean: 'a boolean',\n bigint: 'a bigint',\n array: 'a list',\n tuple: 'a list',\n date: 'a date',\n object: 'an object'\n};\n\nfunction asRecord(value: unknown): ShapeshiftLike | null {\n return typeof value === 'object' && value !== null ? value : null;\n}\n\nfunction firstLine(message: unknown): string {\n if (typeof message !== 'string') return 'unknown validation failure';\n return message.split('\\n')[0] ?? message;\n}\n\n// strings over this limit render as a character count\nconst GIVEN_PREVIEW_LIMIT = 40;\n\nfunction gotPhrase(given: unknown): string {\n if (given === undefined) return 'nothing';\n if (given === null) return 'null';\n if (typeof given === 'string') {\n if (given.length === 0) return 'an empty string';\n if (given.length > GIVEN_PREVIEW_LIMIT) return `${given.length} characters`;\n return JSON.stringify(given);\n }\n if (Array.isArray(given)) return given.length === 0 ? 'an empty list' : `${given.length} items`;\n if (typeof given === 'number' || typeof given === 'bigint' || typeof given === 'boolean') return String(given);\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a null-prototype value has no constructor at runtime\n if (typeof given === 'object') return given.constructor?.name ?? 'an object';\n return typeof given;\n}\n\n// shapeshift constraint strings take the form 'expected.length >= 1' or 'expected <= 16777215'\nfunction needPhrase(expected: string, given: unknown): string | null {\n const bounds = [...expected.matchAll(/expected(\\.length)?\\s*(<=|>=|<|>)\\s*(\\d+)/g)];\n if (bounds.length === 0) return null;\n const phrases = bounds.map(([, lengthPart, operator, limit]) => {\n const word = OPERATOR_WORD[operator ?? ''] ?? operator ?? '';\n if (!lengthPart) return `${word} ${limit}`;\n const unit = typeof given === 'string' ? 'character' : 'item';\n return `${word} ${limit} ${Number(limit) === 1 ? unit : `${unit}s`}`;\n });\n return phrases.join(' and ');\n}\n\nfunction instanceName(expected: unknown): string {\n if (typeof expected === 'function' && expected.name) return expected.name;\n return 'specific class instance';\n}\n\nfunction describeLeaf(record: ShapeshiftLike): string {\n if (typeof record.constraint === 'string') {\n const need = typeof record.expected === 'string' ? needPhrase(record.expected, record.given) : null;\n if (need) return `need ${need}, got ${gotPhrase(record.given)}`;\n return `${firstLine(record.message)}${'given' in record ? ` (got ${gotPhrase(record.given)})` : ''}`;\n }\n if (typeof record.expected === 'function') {\n return `need a ${instanceName(record.expected)}, got ${gotPhrase(record.given)}`;\n }\n if (typeof record.validator === 'string') {\n const kind = KIND_WORD[record.validator.replace(/^s\\./, '').replace(/\\(.*$/, '')];\n if (kind) return `need ${kind}, got ${gotPhrase(record.given)}`;\n return `${firstLine(record.message)}, got ${gotPhrase(record.given)}`;\n }\n return firstLine(record.message);\n}\n\n// a concrete bound is picked first, then accepted instance classes, then the first branch\nfunction describeUnion(branches: unknown[], depth: number): string {\n const records: ShapeshiftLike[] = [];\n for (const branch of branches) {\n const record = asRecord(branch);\n if (record) records.push(record);\n }\n const bounded = records.find((record) => typeof record.constraint === 'string');\n if (bounded) return describeLeaf(bounded);\n\n const names: string[] = [];\n let allInstances = records.length > 0;\n for (const record of records) {\n if (typeof record.expected === 'function') names.push(instanceName(record.expected));\n else allInstances = false;\n }\n if (allInstances) {\n return `need a ${[...new Set(names)].join(' or ')}, got ${gotPhrase(records[0]?.given)}`;\n }\n return detailOf(branches[0], depth + 1);\n}\n\n// shapeshift nests errors as [key, inner] tuples\nfunction detailOf(value: unknown, depth: number): string {\n const record = asRecord(value);\n if (!record || depth >= MAX_DEPTH) return firstLine(record?.message);\n\n if (Array.isArray(record.errors) && record.errors.length > 0) {\n const errors = record.errors as unknown[];\n const [first] = errors;\n if (Array.isArray(first)) {\n const [key, inner] = first as [unknown, unknown];\n return `${String(key)}: ${detailOf(inner, depth + 1)}`;\n }\n return describeUnion(errors, depth);\n }\n\n return describeLeaf(record);\n}\n\n/**\n * Translates a shapeshift throw into an actionable message, keeping the original as `cause`. Any other\n * throw contributes its message as the detail.\n */\nexport function translateSerializationError(\n error: unknown,\n componentClass: string,\n index: number,\n routeId: string\n): SeedcordError<SeedcordErrorCode.ReplyComponentSerialization> {\n const detail = detailOf(error, 0);\n return new SeedcordError(SeedcordErrorCode.ReplyComponentSerialization, [componentClass, index, detail, routeId], {\n cause: error\n });\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { translateSerializationError } from './translateSerialization';\n\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { APIMessageTopLevelComponent } from 'discord-api-types/v10';\n\n/** Serialized message data the transport wire writers consume. */\nexport interface SerializedReply {\n readonly components: APIMessageTopLevelComponent[];\n readonly allowedMentions?: ReplyResponse['allowedMentions'];\n readonly files?: ReplyResponse['files'];\n}\n\n/** Wraps a string in a TextDisplay component. */\nexport function serializeReply(response: ReplyResponse | string, routeId: string): SerializedReply {\n if (typeof response === 'string') {\n try {\n return { components: [new TextDisplayBuilder().setContent(response).toJSON()] };\n } catch (error) {\n throw translateSerializationError(error, 'TextDisplayBuilder', 0, routeId);\n }\n }\n\n const components = response.components.map((component, index) => {\n try {\n return component.toJSON();\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a null-prototype value has no constructor at runtime\n const name = component.constructor?.name;\n throw translateSerializationError(error, !name || name === 'Object' ? 'component' : name, index, routeId);\n }\n });\n\n return {\n components,\n ...(response.allowedMentions && { allowedMentions: response.allowedMentions }),\n ...(response.files && { files: response.files })\n };\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { checkAckLegality, sendTarget } from './ackLegality';\nimport { AckTrace } from './AckTrace';\nimport { serializeReply } from './serializeReply';\nimport { translateSerializationError } from './translateSerialization';\n\nimport type { AckState, ReplyMethod } from './ackLegality';\nimport type { SerializedReply } from './serializeReply';\nimport type { DeferOpts, ReplyResponse, SendOpts } from '@seedcord/types';\nimport type { APIModalInteractionResponseCallbackData } from 'discord-api-types/v10';\n\n/** The shape djs modal builders emit from `toJSON()`. */\nexport interface ModalLike {\n toJSON(): APIModalInteractionResponseCallbackData;\n}\n\n/**\n * Tracks acknowledgement state and throws a translated `SeedcordError` on an illegal verb before any\n * transport call. Verbs execute the legality check, control the transport wire writer, then update the\n * state and ack trace. Each transport binds `TMessage` to its created-message lens and supplies the\n * writers.\n */\nexport abstract class BaseReplySender<TMessage extends { id: string }> {\n private state: AckState;\n // the only ids a targeted edit accepts\n private readonly sent = new Set<string>();\n // the cause carries the first ack's stack so a double-ack names both lines\n private ackedBy?: AckTrace;\n\n protected constructor(\n protected readonly routeId: string,\n initialState: AckState = 'unacked'\n ) {\n this.state = initialState;\n }\n\n public async reply(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n this.checkLegality('reply');\n const created = await this.writeReply(response, opts);\n // the callback already acked discord, so record replied before the message guard can throw\n this.transition('reply', 'replied');\n return this.remember(this.requireMessage(created, 'reply'));\n }\n\n public async defer(opts?: DeferOpts): Promise<void> {\n this.checkLegality('defer');\n await this.writeDefer(opts);\n this.transition('defer', 'deferred-reply');\n }\n\n public async deferUpdate(): Promise<void> {\n this.checkLegality('deferUpdate');\n await this.writeDeferUpdate();\n this.transition('deferUpdate', 'deferred-update');\n }\n\n /**\n * After a deferUpdate the state stays deferred-update, so the rewrite repeats. The returned message\n * is the source message, editable only through a bare `update` or `edit`. A targeted `edit` or `delete`\n * of it throws the foreign-target error.\n */\n public async update(response: ReplyResponse | string): Promise<TMessage> {\n this.checkLegality('update');\n // in deferred-update the source message is @original and the ack-legality check above already passed\n if (this.state === 'deferred-update') return await this.editOriginal(response);\n const created = await this.writeUpdate(response);\n this.transition('update', 'replied');\n return this.remember(this.requireMessage(created, 'update'));\n }\n\n public async followUp(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n this.checkLegality('followUp');\n const created = await this.writeFollowUp(response, opts);\n return this.remember(created);\n }\n\n public edit(response: ReplyResponse | string): Promise<TMessage>;\n public edit(target: TMessage, response: ReplyResponse | string): Promise<TMessage>;\n public async edit(\n targetOrResponse: TMessage | ReplyResponse | string,\n maybeResponse?: ReplyResponse | string\n ): Promise<TMessage> {\n this.checkLegality('edit');\n if (maybeResponse === undefined) {\n // justified: the overloads narrow targetOrResponse to a response once maybeResponse is absent\n return await this.editOriginal(targetOrResponse as ReplyResponse | string);\n }\n // justified: the overloads narrow targetOrResponse to a target message once maybeResponse is defined\n const target = targetOrResponse as TMessage;\n if (!this.sent.has(target.id)) {\n throw new SeedcordError(SeedcordErrorCode.ReplyForeignEditTarget, ['edit', target.id, this.routeId]);\n }\n return this.remember(await this.writeEditTarget(target.id, maybeResponse));\n }\n\n public delete(): Promise<void>;\n public delete(target: TMessage): Promise<void>;\n public async delete(target?: TMessage): Promise<void> {\n this.checkLegality('delete');\n if (target === undefined) {\n await this.writeDeleteOriginal();\n return;\n }\n if (!this.sent.has(target.id)) {\n throw new SeedcordError(SeedcordErrorCode.ReplyForeignEditTarget, ['delete', target.id, this.routeId]);\n }\n await this.writeDeleteTarget(target.id);\n // evict so a later targeted edit of this id throws foreign\n this.sent.delete(target.id);\n }\n\n /** Routes to the verb the current ack state permits. Every state has a route, so the illegal-ack throw is unreachable. */\n public async send(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage> {\n const target = sendTarget(this.state);\n if (target === 'reply') return await this.reply(response, opts);\n if (target === 'edit') return await this.edit(response);\n return await this.followUp(response, opts);\n }\n\n /** Must be the initial response. */\n public async showModal(modal: ModalLike): Promise<void> {\n this.checkLegality('showModal');\n this.guardModalSource();\n let data: APIModalInteractionResponseCallbackData;\n try {\n data = modal.toJSON();\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a null-prototype modal has no constructor at runtime\n const name = modal.constructor?.name;\n throw translateSerializationError(error, !name || name === 'Object' ? 'modal' : name, 0, this.routeId);\n }\n await this.writeModal(data);\n this.transition('showModal', 'replied');\n }\n\n protected serialize(response: ReplyResponse | string): SerializedReply {\n return serializeReply(response, this.routeId);\n }\n\n protected remember(created: TMessage): TMessage {\n this.sent.add(created.id);\n return created;\n }\n\n // a with_response callback always returns the created message, this guards a wire-contract gap\n private requireMessage(created: TMessage | undefined, method: 'reply' | 'update'): TMessage {\n if (!created) throw new SeedcordError(SeedcordErrorCode.ReplyCallbackMissingMessage, [method, this.routeId]);\n return created;\n }\n\n private async editOriginal(response: ReplyResponse | string): Promise<TMessage> {\n const edited = await this.writeEditOriginal(response);\n // after a deferUpdate the source message is @original, which this interaction did not send\n if (this.state !== 'deferred-update') this.remember(edited);\n return edited;\n }\n\n private checkLegality(method: ReplyMethod): void {\n checkAckLegality(method, this.state, this.routeId, this.ackedBy);\n }\n\n private transition(method: ReplyMethod, state: AckState): void {\n this.state = state;\n this.ackedBy = new AckTrace(method);\n }\n\n // the modal-submit backstop, gateway overrides, the base call is a no-op elsewhere\n protected guardModalSource(): void {}\n\n protected abstract writeReply(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage | undefined>;\n protected abstract writeDefer(opts?: DeferOpts): Promise<void>;\n protected abstract writeDeferUpdate(): Promise<void>;\n protected abstract writeUpdate(response: ReplyResponse | string): Promise<TMessage | undefined>;\n protected abstract writeFollowUp(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage>;\n protected abstract writeEditOriginal(response: ReplyResponse | string): Promise<TMessage>;\n protected abstract writeEditTarget(targetId: string, response: ReplyResponse | string): Promise<TMessage>;\n protected abstract writeDeleteOriginal(): Promise<void>;\n protected abstract writeDeleteTarget(targetId: string): Promise<void>;\n protected abstract writeModal(data: APIModalInteractionResponseCallbackData): Promise<void>;\n}\n"],"mappings":"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"}
|