@seedcord/core 0.6.0 → 0.7.0
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/{Bus-dGy6xq3F.mjs → Bus-Djm6688b.mjs} +6 -5
- package/dist/Bus-Djm6688b.mjs.map +1 -0
- package/dist/{Pluggable-C5uxmDb-.d.mts → Pluggable-CqKvMXm5.d.mts} +3 -3
- package/dist/{Pluggable-B7_EftHj.mjs → Pluggable-keys1cVr.mjs} +4 -3
- package/dist/Pluggable-keys1cVr.mjs.map +1 -0
- package/dist/{Plugin-Bnz61fs_.d.mts → Plugin-BdqfRjU0.d.mts} +2 -2
- package/dist/{cursor-8Y2zpF-Y.d.mts → cursor-BY5dmiz6.d.mts} +121 -7
- package/dist/{cursor-BkI9lxy2.mjs → cursor-CFNKLVlk.mjs} +49 -11
- package/dist/cursor-CFNKLVlk.mjs.map +1 -0
- package/dist/{index-CD8l15aZ.d.mts → index-BS1hH9Sh.d.mts} +2 -2
- package/dist/index.d.mts +16 -35
- package/dist/index.mjs +29 -17
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.d.mts +79 -8
- package/dist/internal.index.mjs +121 -16
- package/dist/internal.index.mjs.map +1 -1
- package/dist/node-internal.index.d.mts +4 -4
- package/dist/node-internal.index.mjs +4 -4
- package/dist/node.index.d.mts +1 -1
- package/dist/node.index.mjs +1 -1
- package/dist/{phases-D0a8BV9Z.d.mts → phases-DJf12l5T.d.mts} +48 -9
- package/dist/plugin.index.d.mts +1 -1
- package/dist/{slashRouteLeaves-C1msUE9Q.mjs → slashRouteLeaves-DTFHzCKN.mjs} +2 -2
- package/dist/{slashRouteLeaves-C1msUE9Q.mjs.map → slashRouteLeaves-DTFHzCKN.mjs.map} +1 -1
- package/dist/{subscribers-A8lNU5yM.mjs → subscribers-Bf4cBTvK.mjs} +2 -2
- package/dist/{subscribers-A8lNU5yM.mjs.map → subscribers-Bf4cBTvK.mjs.map} +1 -1
- package/package.json +8 -8
- package/dist/Bus-dGy6xq3F.mjs.map +0 -1
- package/dist/Pluggable-B7_EftHj.mjs.map +0 -1
- package/dist/cursor-BkI9lxy2.mjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { A as UnregisterSubscriber, B as
|
|
2
|
-
import { A as serializeReply, B as
|
|
1
|
+
import { A as UnregisterSubscriber, B as InteractionMiddlewareMetadataKey, C as ReplyMethod, D as RegisterDefaults, E as AckTrace, F as EventMetadataKey, G as Notice, H as MiddlewareKind, I as EventMiddlewareMetadataKey, L as GatedMetadataKey, M as PublishDefault, O as RegisterSubscriber, P as CommandMetadataKey, R as InteractionKind, S as AckState, T as sendTarget, U as SubscribeMetadataKey, V as InteractionRouteKeys, W as WebhookUrlMetadataKey, a as StoredSubscriberCtor, b as ReplyTelemetry, d as DispatchOutcome, i as Bus, j as VerifyWebhooks, k as RegisteredCount, o as SubscriberRegistration, s as busLoggerOf, u as DefaultSubscriptions, w as checkAckLegality, x as reportedWrite, z as InteractionMetadataKey } from "./phases-DJf12l5T.mjs";
|
|
2
|
+
import { A as serializeReply, B as AutocompleteRouteBrand, C as Gate, F as AnyMiddlewareCtor, G as MiddlewareKindsBrand, H as ComponentKindBrand, I as InteractionMiddlewareMetadata, K as SlashRouteBrand, M as EventDispatchResult, P as HandlerResult, U as ContextMenuKindBrand, V as ComponentDefsBrand, W as ContextMenuNamesBrand, X as IsNever, Y as Promisable, Z as BuilderComponent, _ as pickNotice, at as SlashRegistry, c as FocusedField, ct as MenuCacheFor, i as AutocompletableNames, it as SlashOption, j as DispatchResult, k as SerializedReply, m as PermissionNames, n as PageCursor, nt as OptionKind, o as ChoiceValueOf, ot as SlashRouteEntry, q as CommandMeta, r as pageCursor, rt as RouteCache, s as EntryFor, st as ContextMenuKind, t as PAGE_MAX, tt as CacheFor, ut as NamesFor, v as GateFitsWith, w as GateContextBase, z as interactionMiddlewareMetaOf } from "./cursor-BY5dmiz6.mjs";
|
|
3
3
|
import { n as CommandBuilder, r as DeployResult } from "./basic-Dng__Ena.mjs";
|
|
4
|
-
import { a as PluginCtor, i as PluginArgs, n as Initializeable } from "./Plugin-
|
|
4
|
+
import { a as PluginCtor, i as PluginArgs, n as Initializeable } from "./Plugin-BdqfRjU0.mjs";
|
|
5
5
|
import { n as contextMenuLeaves, t as ContextMenuLeaves } from "./contextMenuLeaves-COzDYa6c.mjs";
|
|
6
6
|
import "reflect-metadata";
|
|
7
7
|
import { AnyCustomId, DecodedParams } from "@seedcord/custom-id";
|
|
@@ -9,8 +9,54 @@ import { ContextMenuCommandBuilder, SlashCommandBuilder } from "@discordjs/build
|
|
|
9
9
|
import { ChannelType } from "discord-api-types/v10";
|
|
10
10
|
import { SeedcordErrorCode } from "@seedcord/errors";
|
|
11
11
|
import { SeedcordError } from "@seedcord/errors/internal";
|
|
12
|
+
import { Logger } from "@seedcord/logger";
|
|
12
13
|
import { DevChannel, SeedcordCliEvents, SeedcordFrameworkEvents } from "@seedcord/types/internal";
|
|
13
14
|
import { BotColor, DeferOpts, EpochMs, HmrAware, ReplyResponse, SendOpts } from "@seedcord/types";
|
|
15
|
+
//#region src/dispatch/MiddlewareRegistry.d.ts
|
|
16
|
+
/**
|
|
17
|
+
* A decorated middleware reduced to what the registry orders and filters on. An absent `keys` puts the
|
|
18
|
+
* middleware in every chain.
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
interface MiddlewareRegistration<Key extends string> {
|
|
23
|
+
readonly priority: number;
|
|
24
|
+
readonly keys?: readonly Key[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Reads a transport's decorator metadata off a class. Returns `undefined` for an undecorated one.
|
|
28
|
+
*
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
type MiddlewareRegistrationOf<Ctor, Key extends string> = (ctor: Ctor) => MiddlewareRegistration<Key> | undefined;
|
|
32
|
+
/** @internal */
|
|
33
|
+
declare function interactionMiddleware(ctor: AnyMiddlewareCtor): MiddlewareRegistration<MiddlewareKind> | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Holds the middleware a transport loaded and keeps one chain per key. An interaction keys on its kind
|
|
36
|
+
* and an event on its name. Priority and the key filter behave the same on each.
|
|
37
|
+
*
|
|
38
|
+
* @typeParam Ctor - The transport's middleware constructor type.
|
|
39
|
+
* @typeParam Key - The chain lookup key.
|
|
40
|
+
*
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
declare class MiddlewareRegistry<Ctor extends AnyMiddlewareCtor, Key extends string = MiddlewareKind> {
|
|
44
|
+
private readonly registrationOf;
|
|
45
|
+
private readonly entries;
|
|
46
|
+
private chains;
|
|
47
|
+
constructor(registrationOf: MiddlewareRegistrationOf<Ctor, Key>);
|
|
48
|
+
/**
|
|
49
|
+
* Adds a decorated middleware class and returns what it registered with. Returns `undefined` for an
|
|
50
|
+
* undecorated class or one already registered.
|
|
51
|
+
*
|
|
52
|
+
* @throws A **SeedcordError** If another class with the same name is registered.
|
|
53
|
+
*/
|
|
54
|
+
register(ctor: Ctor): MiddlewareRegistration<Key> | undefined;
|
|
55
|
+
unregister(ctor: Ctor): void;
|
|
56
|
+
chainFor(key: Key): readonly Ctor[];
|
|
57
|
+
private rebuild;
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
14
60
|
//#region src/components/botColorHolder.d.ts
|
|
15
61
|
declare function setBotColor(color: BotColor | undefined): void;
|
|
16
62
|
//#endregion
|
|
@@ -24,9 +70,8 @@ declare function contextMenuRouteOf(kind: ContextMenuKind): InteractionKind;
|
|
|
24
70
|
//#endregion
|
|
25
71
|
//#region src/gates/runGates.d.ts
|
|
26
72
|
type GateObserver = (gateName: string, elapsedMs: number) => void;
|
|
27
|
-
declare function routeIdOf(handlerCtor: object): string | null;
|
|
28
73
|
declare function runGates(gates: readonly Gate<GateContextBase>[], ctx: GateContextBase, observe?: GateObserver): Promise<void>;
|
|
29
|
-
declare function runHandlerGates(handlerCtor: object, ctx: GateContextBase,
|
|
74
|
+
declare function runHandlerGates(handlerCtor: object, ctx: GateContextBase, declaredRoute?: string, observe?: GateObserver): Promise<void>;
|
|
30
75
|
//#endregion
|
|
31
76
|
//#region src/gates/slowGate.d.ts
|
|
32
77
|
/**
|
|
@@ -35,7 +80,7 @@ declare function runHandlerGates(handlerCtor: object, ctx: GateContextBase, rout
|
|
|
35
80
|
*/
|
|
36
81
|
interface SlowGateMonitor {
|
|
37
82
|
readonly observe: GateObserver;
|
|
38
|
-
report(
|
|
83
|
+
report(declaredRoute: string | null): void;
|
|
39
84
|
}
|
|
40
85
|
declare function slowGateMonitor(): SlowGateMonitor | undefined;
|
|
41
86
|
//#endregion
|
|
@@ -253,14 +298,17 @@ declare class ReportThrottle {
|
|
|
253
298
|
*
|
|
254
299
|
* @internal
|
|
255
300
|
*/
|
|
256
|
-
declare function outcomeFor(caught: unknown): DispatchOutcome
|
|
301
|
+
declare function outcomeFor(caught: unknown): Exclude<DispatchOutcome, 'handled'>;
|
|
257
302
|
interface DispatchReport {
|
|
303
|
+
readonly dispatchId: string;
|
|
258
304
|
readonly routeId: string;
|
|
259
305
|
readonly interactionId: string;
|
|
260
306
|
readonly kind: `${InteractionKind}`;
|
|
261
307
|
readonly outcome: DispatchOutcome;
|
|
262
308
|
/** True when no route matched and the unhandled default ran. */
|
|
263
309
|
readonly fallback: boolean;
|
|
310
|
+
readonly userId: string | null;
|
|
311
|
+
readonly guildId: string | null;
|
|
264
312
|
/** `performance.now()` captured as the dispatch began. */
|
|
265
313
|
readonly startedAt: number;
|
|
266
314
|
/** {@link queuedMsFor} read at the same moment as `startedAt`. */
|
|
@@ -275,5 +323,28 @@ interface DispatchReport {
|
|
|
275
323
|
declare function queuedMsFor(interactionId: string): number;
|
|
276
324
|
declare function reportDispatch(bus: Bus, report: DispatchReport): void;
|
|
277
325
|
//#endregion
|
|
278
|
-
|
|
326
|
+
//#region src/dispatch/runAfter.d.ts
|
|
327
|
+
interface Afterable<Result> {
|
|
328
|
+
after?(result: Result): Promise<void>;
|
|
329
|
+
}
|
|
330
|
+
/** @internal */
|
|
331
|
+
declare function resultFor(caught: unknown): DispatchResult;
|
|
332
|
+
/**
|
|
333
|
+
* Builds what an event middleware's `after()` receives. `handlers` is empty exactly when the chain
|
|
334
|
+
* stopped the event.
|
|
335
|
+
*
|
|
336
|
+
* @internal
|
|
337
|
+
*/
|
|
338
|
+
declare function eventResultFor(stopped: {
|
|
339
|
+
caught: unknown;
|
|
340
|
+
} | null, handlers: readonly HandlerResult[]): EventDispatchResult;
|
|
341
|
+
/**
|
|
342
|
+
* Calls `after()` on each middleware that ran, newest first. A throw inside one is logged. Every
|
|
343
|
+
* remaining middleware still gets its call.
|
|
344
|
+
*
|
|
345
|
+
* @internal
|
|
346
|
+
*/
|
|
347
|
+
declare function runAfter<Result>(ran: readonly Afterable<Result>[], result: Result, logger: Logger): Promise<void>;
|
|
348
|
+
//#endregion
|
|
349
|
+
export { type AckState, AckTrace, type AutocompletableNames, AutocompleteRouteBrand, type CacheFor, type ChoiceValueOf, type CommandBuilder, type CommandCtor, type CommandMeta, CommandMetadataKey, ComponentDefsBrand, ComponentDefsKey, ComponentKindBrand, ContextMenuKindBrand, type ContextMenuLeaves, ContextMenuNamesBrand, type DecodedComponentRoute, type DefaultSubscriptions, type DeployResult, type EntryFor, EventMetadataKey, EventMiddlewareMetadataKey, type FocusedField, type GateFitsWith, GateNotice, type GateObserver, GatedMetadataKey, type HasComponentDefs, HasDangerousPermissions, HmrManager, type Initializeable, InteractionMetadataKey, type InteractionMiddlewareMetadata, InteractionMiddlewareMetadataKey, InteractionRouteKeys, type MatchArms, type MenuCacheFor, MiddlewareKindsBrand, type MiddlewareRegistration, type MiddlewareRegistrationOf, MiddlewareRegistry, MissingPermissions, MissingRole, type NamesFor, NeedsAny, NotAllowed, NotInDm, NotInGuild, NotOwner, NoticeCard, OnCooldown, type OptionKind, type OptionLens, PAGE_MAX, type PageCursor, PermissionNames, type PluginArgs, type PluginCtor, PublishDefault, RegisterDefaults, RegisterSubscriber, RegisteredCount, type ReplyMethod, type ReplyTelemetry, ReportThrottle, type RoutableConstructor, type RouteCache, type SerializedReply, type SingleParams, type SlashOption, type SlashOptions, SlashRouteBrand, type SlashRouteEntry, type SlowGateMonitor, type StoredSubscriberCtor, SubscribeMetadataKey, type SubscriberRegistration, UnregisterSubscriber, VerifyWebhooks, WebhookUrlMetadataKey, accessorStore, areRoutes, asError, busLoggerOf, checkAckLegality, clearStore, contextMenuLeaves, contextMenuRouteOf, decodeComponentRoute, deferFlags, eventResultFor, getDevChannel, guardedAccessor, interactionMiddleware, interactionMiddlewareMetaOf, interactionRoutesOf, isCommandClass, isEmojiTuple, outcomeFor, pageCursor, pickNotice, queuedMsFor, reportDispatch, reportedWrite, resultFor, runAfter, runGates, runHandlerGates, sendFlags, sendTarget, serializeReply, setBotColor, setDevChannel, slashRouteLeaves, slowGateMonitor, storeComponentRoute, storeInteractionRoute, translateSerializationError, wrapHot };
|
|
279
350
|
//# sourceMappingURL=internal.index.d.mts.map
|
package/dist/internal.index.mjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { A as translateSerializationError, B as
|
|
2
|
-
import { C as
|
|
1
|
+
import { A as translateSerializationError, B as contextMenuRouteOf, C as NotInDm, E as OnCooldown, F as checkAckLegality, G as decodeComponentRoute, H as storeComponentRoute, I as sendTarget, K as NoticeCard, N as reportedWrite, P as AckTrace, R as interactionMiddlewareMetaOf, S as NotAllowed, T as NotOwner, U as storeInteractionRoute, V as interactionRoutesOf, W as ComponentDefsKey, _ as GateNotice, b as MissingRole, d as pickNotice, f as discardCommits, g as runCommits, h as runCheck, k as serializeReply, n as pageCursor, q as Notice, r as Silence, s as PermissionNames, t as PAGE_MAX, v as HasDangerousPermissions, w as NotInGuild, x as NeedsAny, y as MissingPermissions, z as areRoutes } from "./cursor-CFNKLVlk.mjs";
|
|
2
|
+
import { C as InteractionRouteKeys, D as clearStore, E as accessorStore, N as setBotColor, O as guardedAccessor, S as InteractionMiddlewareMetadataKey, T as WebhookUrlMetadataKey, _ as EventMetadataKey, a as RegisterSubscriber, c as VerifyWebhooks, g as CommandMetadataKey, h as sendFlags, i as RegisterDefaults, k as contextMenuLeaves, m as deferFlags, n as busLoggerOf, o as RegisteredCount, p as ReportThrottle, s as UnregisterSubscriber, v as EventMiddlewareMetadataKey, w as SubscribeMetadataKey, x as InteractionMetadataKey, y as GatedMetadataKey } from "./Bus-Djm6688b.mjs";
|
|
3
3
|
import { n as asError, t as PublishDefault } from "./publishDefault-BuSZPbjT.mjs";
|
|
4
4
|
import { n as setDevChannel, t as getDevChannel } from "./devChannel-CQU7hq7Q.mjs";
|
|
5
|
-
import { n as isCommandClass, t as slashRouteLeaves } from "./slashRouteLeaves-
|
|
5
|
+
import { n as isCommandClass, t as slashRouteLeaves } from "./slashRouteLeaves-DTFHzCKN.mjs";
|
|
6
6
|
import "reflect-metadata";
|
|
7
|
-
import { paint } from "@seedcord/errors";
|
|
7
|
+
import { SeedcordErrorCode, paint } from "@seedcord/errors";
|
|
8
|
+
import { SeedcordError } from "@seedcord/errors/internal";
|
|
8
9
|
import { Logger } from "@seedcord/logger";
|
|
9
10
|
import { timestampFromSnowflake } from "@seedcord/utils";
|
|
10
11
|
import { Envapter } from "envapt";
|
|
@@ -16,16 +17,75 @@ const ContextMenuKindBrand = Symbol("seedcord:brand:context-menu-kind");
|
|
|
16
17
|
const ContextMenuNamesBrand = Symbol("seedcord:brand:context-menu-names");
|
|
17
18
|
const ComponentKindBrand = Symbol("seedcord:brand:component-kind");
|
|
18
19
|
const ComponentDefsBrand = Symbol("seedcord:brand:component-defs");
|
|
20
|
+
const MiddlewareKindsBrand = Symbol("seedcord:brand:middleware-kinds");
|
|
19
21
|
|
|
20
22
|
//#endregion
|
|
21
|
-
//#region src/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
//#region src/dispatch/MiddlewareRegistry.ts
|
|
24
|
+
/** @internal */
|
|
25
|
+
function interactionMiddleware(ctor) {
|
|
26
|
+
const metadata = interactionMiddlewareMetaOf(ctor);
|
|
27
|
+
if (!metadata) return void 0;
|
|
28
|
+
return {
|
|
29
|
+
priority: metadata.priority,
|
|
30
|
+
...metadata.kinds && { keys: metadata.kinds }
|
|
31
|
+
};
|
|
28
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Holds the middleware a transport loaded and keeps one chain per key. An interaction keys on its kind
|
|
35
|
+
* and an event on its name. Priority and the key filter behave the same on each.
|
|
36
|
+
*
|
|
37
|
+
* @typeParam Ctor - The transport's middleware constructor type.
|
|
38
|
+
* @typeParam Key - The chain lookup key.
|
|
39
|
+
*
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
var MiddlewareRegistry = class {
|
|
43
|
+
registrationOf;
|
|
44
|
+
entries = [];
|
|
45
|
+
chains = /* @__PURE__ */ new Map();
|
|
46
|
+
constructor(registrationOf) {
|
|
47
|
+
this.registrationOf = registrationOf;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Adds a decorated middleware class and returns what it registered with. Returns `undefined` for an
|
|
51
|
+
* undecorated class or one already registered.
|
|
52
|
+
*
|
|
53
|
+
* @throws A **SeedcordError** If another class with the same name is registered.
|
|
54
|
+
*/
|
|
55
|
+
register(ctor) {
|
|
56
|
+
const registration = this.registrationOf(ctor);
|
|
57
|
+
if (!registration) return void 0;
|
|
58
|
+
if (this.entries.some((entry) => entry.ctor === ctor)) return void 0;
|
|
59
|
+
if (this.entries.some((entry) => entry.ctor.name === ctor.name)) throw new SeedcordError(SeedcordErrorCode.DuplicateMiddleware, [ctor.name]);
|
|
60
|
+
this.entries.push({
|
|
61
|
+
ctor,
|
|
62
|
+
priority: registration.priority,
|
|
63
|
+
...registration.keys && { keys: new Set(registration.keys) }
|
|
64
|
+
});
|
|
65
|
+
this.rebuild();
|
|
66
|
+
return registration;
|
|
67
|
+
}
|
|
68
|
+
unregister(ctor) {
|
|
69
|
+
const index = this.entries.findIndex((entry) => entry.ctor === ctor);
|
|
70
|
+
if (index === -1) return;
|
|
71
|
+
this.entries.splice(index, 1);
|
|
72
|
+
this.rebuild();
|
|
73
|
+
}
|
|
74
|
+
chainFor(key) {
|
|
75
|
+
const built = this.chains.get(key);
|
|
76
|
+
if (built) return built;
|
|
77
|
+
const chain = this.entries.filter((entry) => !entry.keys || entry.keys.has(key)).map((entry) => entry.ctor);
|
|
78
|
+
this.chains.set(key, chain);
|
|
79
|
+
return chain;
|
|
80
|
+
}
|
|
81
|
+
rebuild() {
|
|
82
|
+
this.entries.sort((a, b) => a.priority - b.priority);
|
|
83
|
+
this.chains = /* @__PURE__ */ new Map();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/gates/runGates.ts
|
|
29
89
|
async function timedCheck(gate, ctx, observe) {
|
|
30
90
|
const start = performance.now();
|
|
31
91
|
try {
|
|
@@ -42,12 +102,12 @@ async function runGates(gates, ctx, observe) {
|
|
|
42
102
|
discardCommits(ctx);
|
|
43
103
|
}
|
|
44
104
|
}
|
|
45
|
-
async function runHandlerGates(handlerCtor, ctx,
|
|
105
|
+
async function runHandlerGates(handlerCtor, ctx, declaredRoute, observe) {
|
|
46
106
|
const gates = Reflect.getMetadata(GatedMetadataKey, handlerCtor);
|
|
47
107
|
if (!gates) return;
|
|
48
108
|
await runGates(gates, {
|
|
49
109
|
...ctx,
|
|
50
|
-
|
|
110
|
+
declaredRoute: declaredRoute ?? null
|
|
51
111
|
}, observe);
|
|
52
112
|
}
|
|
53
113
|
|
|
@@ -67,11 +127,11 @@ function slowGateMonitor() {
|
|
|
67
127
|
name,
|
|
68
128
|
ms
|
|
69
129
|
}),
|
|
70
|
-
report(
|
|
130
|
+
report(declaredRoute) {
|
|
71
131
|
const total = readings.reduce((sum, reading) => sum + reading.ms, 0);
|
|
72
132
|
if (total < SLOW_GATE_MS) return;
|
|
73
133
|
const shares = readings.toSorted((a, b) => b.ms - a.ms).map((reading) => `${paint.sky.bold(reading.name)} ${paint.mute(`${Math.round(reading.ms)}ms`)}`);
|
|
74
|
-
const headline = `gates${
|
|
134
|
+
const headline = `gates${declaredRoute === null ? "" : ` for ${paint.sky.bold(declaredRoute)}`} took ${paint.amber(`${Math.round(total)}ms`)} of the 3s ack budget`;
|
|
75
135
|
logger$1().utils.block(headline, shares, "warn", (text) => text);
|
|
76
136
|
}
|
|
77
137
|
};
|
|
@@ -158,11 +218,14 @@ function queuedMsFor(interactionId) {
|
|
|
158
218
|
function reportDispatch(bus, report) {
|
|
159
219
|
const durationMs = performance.now() - report.startedAt;
|
|
160
220
|
bus[PublishDefault]("interactionDispatched", {
|
|
221
|
+
dispatchId: report.dispatchId,
|
|
161
222
|
routeId: report.routeId,
|
|
162
223
|
interactionId: report.interactionId,
|
|
163
224
|
kind: report.kind,
|
|
164
225
|
outcome: report.outcome,
|
|
165
226
|
fallback: report.fallback,
|
|
227
|
+
userId: report.userId,
|
|
228
|
+
guildId: report.guildId,
|
|
166
229
|
durationMs,
|
|
167
230
|
queuedMs: report.queuedMs
|
|
168
231
|
});
|
|
@@ -170,5 +233,47 @@ function reportDispatch(bus, report) {
|
|
|
170
233
|
}
|
|
171
234
|
|
|
172
235
|
//#endregion
|
|
173
|
-
|
|
236
|
+
//#region src/dispatch/runAfter.ts
|
|
237
|
+
/** @internal */
|
|
238
|
+
function resultFor(caught) {
|
|
239
|
+
return {
|
|
240
|
+
outcome: outcomeFor(caught),
|
|
241
|
+
caught
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Builds what an event middleware's `after()` receives. `handlers` is empty exactly when the chain
|
|
246
|
+
* stopped the event.
|
|
247
|
+
*
|
|
248
|
+
* @internal
|
|
249
|
+
*/
|
|
250
|
+
function eventResultFor(stopped, handlers) {
|
|
251
|
+
if (!stopped) return {
|
|
252
|
+
outcome: "handled",
|
|
253
|
+
handlers
|
|
254
|
+
};
|
|
255
|
+
return {
|
|
256
|
+
...resultFor(stopped.caught),
|
|
257
|
+
handlers: []
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Calls `after()` on each middleware that ran, newest first. A throw inside one is logged. Every
|
|
262
|
+
* remaining middleware still gets its call.
|
|
263
|
+
*
|
|
264
|
+
* @internal
|
|
265
|
+
*/
|
|
266
|
+
async function runAfter(ran, result, logger) {
|
|
267
|
+
for (let index = ran.length - 1; index >= 0; index--) {
|
|
268
|
+
const middleware = ran[index];
|
|
269
|
+
try {
|
|
270
|
+
await middleware?.after?.(result);
|
|
271
|
+
} catch (caught) {
|
|
272
|
+
logger.error(`${middleware?.constructor.name ?? "A middleware"} threw from after()`, asError(caught));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
//#endregion
|
|
278
|
+
export { AckTrace, AutocompleteRouteBrand, CommandMetadataKey, ComponentDefsBrand, ComponentDefsKey, ComponentKindBrand, ContextMenuKindBrand, ContextMenuNamesBrand, EventMetadataKey, EventMiddlewareMetadataKey, GateNotice, GatedMetadataKey, HasDangerousPermissions, HmrManager, InteractionMetadataKey, InteractionMiddlewareMetadataKey, InteractionRouteKeys, MiddlewareKindsBrand, MiddlewareRegistry, MissingPermissions, MissingRole, NeedsAny, NotAllowed, NotInDm, NotInGuild, NotOwner, NoticeCard, OnCooldown, PAGE_MAX, PermissionNames, PublishDefault, RegisterDefaults, RegisterSubscriber, RegisteredCount, ReportThrottle, SlashRouteBrand, SubscribeMetadataKey, UnregisterSubscriber, VerifyWebhooks, WebhookUrlMetadataKey, accessorStore, areRoutes, asError, busLoggerOf, checkAckLegality, clearStore, contextMenuLeaves, contextMenuRouteOf, decodeComponentRoute, deferFlags, eventResultFor, getDevChannel, guardedAccessor, interactionMiddleware, interactionMiddlewareMetaOf, interactionRoutesOf, isCommandClass, isEmojiTuple, outcomeFor, pageCursor, pickNotice, queuedMsFor, reportDispatch, reportedWrite, resultFor, runAfter, runGates, runHandlerGates, sendFlags, sendTarget, serializeReply, setBotColor, setDevChannel, slashRouteLeaves, slowGateMonitor, storeComponentRoute, storeInteractionRoute, translateSerializationError, wrapHot };
|
|
174
279
|
//# sourceMappingURL=internal.index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal.index.mjs","names":["logger"],"sources":["../src/decorators/brands.ts","../src/gates/runGates.ts","../src/gates/slowGate.ts","../src/miscellaneous/emojiConfig.ts","../src/hmr/wrapHot.ts","../src/hmr/HmrManager.ts","../src/dispatch/dispatchReport.ts"],"sourcesContent":["// A handler base declares these so a route decorator can read what the handler is for. Nothing\n// assigns them at runtime.\n\nexport const SlashRouteBrand: unique symbol = Symbol('seedcord:brand:slash-route');\nexport const AutocompleteRouteBrand: unique symbol = Symbol('seedcord:brand:autocomplete-route');\nexport const ContextMenuKindBrand: unique symbol = Symbol('seedcord:brand:context-menu-kind');\nexport const ContextMenuNamesBrand: unique symbol = Symbol('seedcord:brand:context-menu-names');\nexport const ComponentKindBrand: unique symbol = Symbol('seedcord:brand:component-kind');\nexport const ComponentDefsBrand: unique symbol = Symbol('seedcord:brand:component-defs');\n","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// a combinator (`and`/`or`) reports once under its joined name.\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// the first refusal throws out to the dispatcher boundary. an effect gate's commit runs once the\n// whole set passes, and observe never times the commit phase.\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. an explicit\n// routeId is for manifest-driven handlers, which carry no route metadata to derive one from.\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 { paint } from '@seedcord/errors';\nimport { Logger } 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', { channel: '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)} ${paint.mute(`${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","// narrows a configured emoji value to the [name, guildId] form\nexport function isEmojiTuple(value: unknown): value is readonly [string, string] {\n return Array.isArray(value) && value.length === 2 && typeof value[0] === 'string' && typeof value[1] === 'string';\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/** @internal */\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, and 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 { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\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.debug('Enabled');\n channel.on('seedcord:hmr', (payload) => void this.handleUpdate(payload));\n }\n }\n\n /** @internal */\n public register(listener: HmrAware): void {\n this.listeners.add(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 ${paint.sky.bold(listener.constructor.name)}`, error);\n }\n });\n\n await Promise.all(promises);\n }\n}\n","import { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\nimport { timestampFromSnowflake } from '@seedcord/utils';\n\nimport { Notice } from '#stops/Notice';\nimport { Silence } from '#stops/Silence';\nimport { PublishDefault } from '#subscribers/publishDefault';\n\nimport type { InteractionKind } from '#src/metadataKeys';\nimport type { Bus } from '#subscribers/Bus';\nimport type { DispatchOutcome } from '#subscribers/types/Subscriptions';\n\nlet dispatchLogger: Logger | undefined;\nfunction logger(): Logger {\n dispatchLogger ??= new Logger('Dispatch', { channel: 'interactions' });\n return dispatchLogger;\n}\n\n/**\n * Classifies a caught stop for `interactionDispatched` so a gate and a\n * handler label the same stop identically.\n *\n * @internal\n */\nexport function outcomeFor(caught: unknown): DispatchOutcome {\n if (caught instanceof Silence) return 'refused';\n if (caught instanceof Notice) return caught.report ? 'failed' : 'refused';\n return 'failed';\n}\n\ninterface DispatchReport {\n readonly routeId: string;\n readonly interactionId: string;\n readonly kind: `${InteractionKind}`;\n readonly outcome: DispatchOutcome;\n /** True when no route matched and the unhandled default ran. */\n readonly fallback: boolean;\n /** `performance.now()` captured as the dispatch began. */\n readonly startedAt: number;\n /** {@link queuedMsFor} read at the same moment as `startedAt`. */\n readonly queuedMs: number;\n}\n\n/**\n * Discord's interaction creation to now, read from the snowflake. Called at dispatch entry, since\n * a later read would count the handler run into the queue time as well.\n *\n * @internal\n */\nexport function queuedMsFor(interactionId: string): number {\n // telemetry never breaks a dispatch, and BigInt() throws on a malformed id\n try {\n return Date.now() - timestampFromSnowflake(interactionId);\n } catch {\n return 0;\n }\n}\n\nexport function reportDispatch(bus: Bus, report: DispatchReport): void {\n const durationMs = performance.now() - report.startedAt;\n bus[PublishDefault]('interactionDispatched', {\n routeId: report.routeId,\n interactionId: report.interactionId,\n kind: report.kind,\n outcome: report.outcome,\n fallback: report.fallback,\n durationMs,\n queuedMs: report.queuedMs\n });\n\n // a throwing log sink must not stop the publish above\n logger().trace(\n `${paint.sky.bold(report.routeId)} ${report.outcome} ${paint.mute('in')} ${Math.round(durationMs)}ms`\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"internal.index.mjs","names":["logger"],"sources":["../src/decorators/brands.ts","../src/dispatch/MiddlewareRegistry.ts","../src/gates/runGates.ts","../src/gates/slowGate.ts","../src/miscellaneous/emojiConfig.ts","../src/hmr/wrapHot.ts","../src/hmr/HmrManager.ts","../src/dispatch/dispatchReport.ts","../src/dispatch/runAfter.ts"],"sourcesContent":["// phantom, nothing assigns these at runtime\n\nexport const SlashRouteBrand: unique symbol = Symbol('seedcord:brand:slash-route');\nexport const AutocompleteRouteBrand: unique symbol = Symbol('seedcord:brand:autocomplete-route');\nexport const ContextMenuKindBrand: unique symbol = Symbol('seedcord:brand:context-menu-kind');\nexport const ContextMenuNamesBrand: unique symbol = Symbol('seedcord:brand:context-menu-names');\nexport const ComponentKindBrand: unique symbol = Symbol('seedcord:brand:component-kind');\nexport const ComponentDefsBrand: unique symbol = Symbol('seedcord:brand:component-defs');\nexport const MiddlewareKindsBrand: unique symbol = Symbol('seedcord:brand:middleware-kinds');\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { interactionMiddlewareMetaOf } from '#decorators/middleware';\n\nimport type { AnyMiddlewareCtor } from '#decorators/middleware';\nimport type { MiddlewareKind } from '#src/metadataKeys';\n\n/**\n * A decorated middleware reduced to what the registry orders and filters on. An absent `keys` puts the\n * middleware in every chain.\n *\n * @internal\n */\nexport interface MiddlewareRegistration<Key extends string> {\n readonly priority: number;\n readonly keys?: readonly Key[];\n}\n\n/**\n * Reads a transport's decorator metadata off a class. Returns `undefined` for an undecorated one.\n *\n * @internal\n */\nexport type MiddlewareRegistrationOf<Ctor, Key extends string> = (\n ctor: Ctor\n) => MiddlewareRegistration<Key> | undefined;\n\n/** @internal */\nexport function interactionMiddleware(ctor: AnyMiddlewareCtor): MiddlewareRegistration<MiddlewareKind> | undefined {\n const metadata = interactionMiddlewareMetaOf(ctor);\n if (!metadata) return undefined;\n return { priority: metadata.priority, ...(metadata.kinds && { keys: metadata.kinds }) };\n}\n\ninterface Entry<Ctor, Key extends string> {\n readonly ctor: Ctor;\n readonly priority: number;\n readonly keys?: ReadonlySet<Key>;\n}\n\n/**\n * Holds the middleware a transport loaded and keeps one chain per key. An interaction keys on its kind\n * and an event on its name. Priority and the key filter behave the same on each.\n *\n * @typeParam Ctor - The transport's middleware constructor type.\n * @typeParam Key - The chain lookup key.\n *\n * @internal\n */\nexport class MiddlewareRegistry<Ctor extends AnyMiddlewareCtor, Key extends string = MiddlewareKind> {\n private readonly entries: Entry<Ctor, Key>[] = [];\n // an in-flight dispatch keeps walking the array chainFor gave it. never mutate one in place.\n private chains = new Map<Key, readonly Ctor[]>();\n\n public constructor(private readonly registrationOf: MiddlewareRegistrationOf<Ctor, Key>) {}\n\n /**\n * Adds a decorated middleware class and returns what it registered with. Returns `undefined` for an\n * undecorated class or one already registered.\n *\n * @throws A **SeedcordError** If another class with the same name is registered.\n */\n public register(ctor: Ctor): MiddlewareRegistration<Key> | undefined {\n const registration = this.registrationOf(ctor);\n if (!registration) return undefined;\n\n // a double import or an hmr re-scan registers the same class twice\n if (this.entries.some((entry) => entry.ctor === ctor)) return undefined;\n if (this.entries.some((entry) => entry.ctor.name === ctor.name)) {\n throw new SeedcordError(SeedcordErrorCode.DuplicateMiddleware, [ctor.name]);\n }\n\n this.entries.push({\n ctor,\n priority: registration.priority,\n ...(registration.keys && { keys: new Set(registration.keys) })\n });\n this.rebuild();\n return registration;\n }\n\n public unregister(ctor: Ctor): void {\n const index = this.entries.findIndex((entry) => entry.ctor === ctor);\n if (index === -1) return;\n this.entries.splice(index, 1);\n this.rebuild();\n }\n\n public chainFor(key: Key): readonly Ctor[] {\n const built = this.chains.get(key);\n if (built) return built;\n\n const chain = this.entries.filter((entry) => !entry.keys || entry.keys.has(key)).map((entry) => entry.ctor);\n this.chains.set(key, chain);\n return chain;\n }\n\n private rebuild(): void {\n // a stable sort keeps ties in registration order\n this.entries.sort((a, b) => a.priority - b.priority);\n this.chains = new Map();\n }\n}\n","import 'reflect-metadata';\n\nimport { GatedMetadataKey } from '#src/metadataKeys';\n\nimport { discardCommits, runCheck, runCommits } from './effects';\n\nimport type { Gate, GateContextBase } from './Gate';\n\n// a combinator (`and`/`or`) reports once under its joined name.\nexport type GateObserver = (gateName: string, elapsedMs: number) => void;\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// the first refusal throws out to the dispatcher boundary. an effect gate's commit runs once the\n// whole set passes, and observe never times the commit phase.\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\nexport async function runHandlerGates(\n handlerCtor: object,\n ctx: GateContextBase,\n declaredRoute?: 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, declaredRoute: declaredRoute ?? null }, observe);\n}\n","import { paint } from '@seedcord/errors';\nimport { Logger } 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', { channel: '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(declaredRoute: 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(declaredRoute) {\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)} ${paint.mute(`${Math.round(reading.ms)}ms`)}`);\n const route = declaredRoute === null ? '' : ` for ${paint.sky.bold(declaredRoute)}`;\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","// narrows a configured emoji value to the [name, guildId] form\nexport function isEmojiTuple(value: unknown): value is readonly [string, string] {\n return Array.isArray(value) && value.length === 2 && typeof value[0] === 'string' && typeof value[1] === 'string';\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/** @internal */\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, and 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 { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\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.debug('Enabled');\n channel.on('seedcord:hmr', (payload) => void this.handleUpdate(payload));\n }\n }\n\n /** @internal */\n public register(listener: HmrAware): void {\n this.listeners.add(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 ${paint.sky.bold(listener.constructor.name)}`, error);\n }\n });\n\n await Promise.all(promises);\n }\n}\n","import { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\nimport { timestampFromSnowflake } from '@seedcord/utils';\n\nimport { Notice } from '#stops/Notice';\nimport { Silence } from '#stops/Silence';\nimport { PublishDefault } from '#subscribers/publishDefault';\n\nimport type { InteractionKind } from '#src/metadataKeys';\nimport type { Bus } from '#subscribers/Bus';\nimport type { DispatchOutcome } from '#subscribers/types/Subscriptions';\n\nlet dispatchLogger: Logger | undefined;\nfunction logger(): Logger {\n dispatchLogger ??= new Logger('Dispatch', { channel: 'interactions' });\n return dispatchLogger;\n}\n\n/**\n * Classifies a caught stop for `interactionDispatched` so a gate and a\n * handler label the same stop identically.\n *\n * @internal\n */\nexport function outcomeFor(caught: unknown): Exclude<DispatchOutcome, 'handled'> {\n if (caught instanceof Silence) return 'refused';\n if (caught instanceof Notice) return caught.report ? 'failed' : 'refused';\n return 'failed';\n}\n\ninterface DispatchReport {\n readonly dispatchId: string;\n readonly routeId: string;\n readonly interactionId: string;\n readonly kind: `${InteractionKind}`;\n readonly outcome: DispatchOutcome;\n /** True when no route matched and the unhandled default ran. */\n readonly fallback: boolean;\n readonly userId: string | null;\n readonly guildId: string | null;\n /** `performance.now()` captured as the dispatch began. */\n readonly startedAt: number;\n /** {@link queuedMsFor} read at the same moment as `startedAt`. */\n readonly queuedMs: number;\n}\n\n/**\n * Discord's interaction creation to now, read from the snowflake. Called at dispatch entry, since\n * a later read would count the handler run into the queue time as well.\n *\n * @internal\n */\nexport function queuedMsFor(interactionId: string): number {\n // timestampFromSnowflake throws on a malformed id\n try {\n return Date.now() - timestampFromSnowflake(interactionId);\n } catch {\n return 0;\n }\n}\n\nexport function reportDispatch(bus: Bus, report: DispatchReport): void {\n const durationMs = performance.now() - report.startedAt;\n bus[PublishDefault]('interactionDispatched', {\n dispatchId: report.dispatchId,\n routeId: report.routeId,\n interactionId: report.interactionId,\n kind: report.kind,\n outcome: report.outcome,\n fallback: report.fallback,\n userId: report.userId,\n guildId: report.guildId,\n durationMs,\n queuedMs: report.queuedMs\n });\n\n // a throwing log sink must not stop the publish above\n logger().trace(\n `${paint.sky.bold(report.routeId)} ${report.outcome} ${paint.mute('in')} ${Math.round(durationMs)}ms`\n );\n}\n","import { asError } from '#stops/asError';\n\nimport { outcomeFor } from './dispatchReport';\n\nimport type { DispatchResult, EventDispatchResult, HandlerResult } from './dispatchResult';\nimport type { Logger } from '@seedcord/logger';\n\ninterface Afterable<Result> {\n after?(result: Result): Promise<void>;\n}\n\n/** @internal */\nexport function resultFor(caught: unknown): DispatchResult {\n return { outcome: outcomeFor(caught), caught };\n}\n\n/**\n * Builds what an event middleware's `after()` receives. `handlers` is empty exactly when the chain\n * stopped the event.\n *\n * @internal\n */\nexport function eventResultFor(\n stopped: { caught: unknown } | null,\n handlers: readonly HandlerResult[]\n): EventDispatchResult {\n if (!stopped) return { outcome: 'handled', handlers };\n return { ...resultFor(stopped.caught), handlers: [] };\n}\n\n/**\n * Calls `after()` on each middleware that ran, newest first. A throw inside one is logged. Every\n * remaining middleware still gets its call.\n *\n * @internal\n */\nexport async function runAfter<Result>(\n ran: readonly Afterable<Result>[],\n result: Result,\n logger: Logger\n): Promise<void> {\n for (let index = ran.length - 1; index >= 0; index--) {\n const middleware = ran[index];\n try {\n await middleware?.after?.(result);\n } catch (caught) {\n logger.error(`${middleware?.constructor.name ?? 'A middleware'} threw from after()`, asError(caught));\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { i as Bus, n as StartupPhase, r as CoreBase, t as ShutdownPhase } from "./phases-
|
|
1
|
+
import { i as Bus, n as StartupPhase, r as CoreBase, t as ShutdownPhase } from "./phases-DJf12l5T.mjs";
|
|
2
2
|
import { n as CommandBuilder, r as DeployResult } from "./basic-Dng__Ena.mjs";
|
|
3
|
-
import "./index-
|
|
4
|
-
import { n as Initializeable } from "./Plugin-
|
|
3
|
+
import "./index-BS1hH9Sh.mjs";
|
|
4
|
+
import { n as Initializeable } from "./Plugin-BdqfRjU0.mjs";
|
|
5
5
|
import { t as ContextMenuLeaves } from "./contextMenuLeaves-COzDYa6c.mjs";
|
|
6
|
-
import { a as LifecycleTask, i as CoordinatedShutdown, n as shutdownOf } from "./Pluggable-
|
|
6
|
+
import { a as LifecycleTask, i as CoordinatedShutdown, n as shutdownOf } from "./Pluggable-CqKvMXm5.mjs";
|
|
7
7
|
import { Logger } from "@seedcord/logger";
|
|
8
8
|
import { IncomingMessage, ServerResponse } from "node:http";
|
|
9
9
|
import { HealthCheckConfig, HealthCheckOption, HmrAware, HmrUpdateEvent } from "@seedcord/types";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as CommandInjector } from "./subscribers-
|
|
1
|
+
import { a as RegisterSubscriber, c as VerifyWebhooks, f as Subscriber, g as CommandMetadataKey, i as RegisterDefaults, k as contextMenuLeaves, n as busLoggerOf, o as RegisteredCount, r as registrationFor, s as UnregisterSubscriber, w as SubscribeMetadataKey } from "./Bus-Djm6688b.mjs";
|
|
2
|
+
import { t as CommandInjector } from "./subscribers-Bf4cBTvK.mjs";
|
|
3
3
|
import { t as PublishDefault } from "./publishDefault-BuSZPbjT.mjs";
|
|
4
4
|
import { n as StartupPhase, t as ShutdownPhase } from "./phases-BauKJOTT.mjs";
|
|
5
5
|
import { t as getDevChannel } from "./devChannel-CQU7hq7Q.mjs";
|
|
6
|
-
import { n as isCommandClass, t as slashRouteLeaves } from "./slashRouteLeaves-
|
|
6
|
+
import { n as isCommandClass, t as slashRouteLeaves } from "./slashRouteLeaves-DTFHzCKN.mjs";
|
|
7
7
|
import { t as HmrModuleHandler } from "./HmrModuleHandler-9AUfKXRl.mjs";
|
|
8
|
-
import { i as settleWithin, n as shutdownOf, r as assertNodeVersion } from "./Pluggable-
|
|
8
|
+
import { i as settleWithin, n as shutdownOf, r as assertNodeVersion } from "./Pluggable-keys1cVr.mjs";
|
|
9
9
|
import { SlashCommandBuilder } from "@discordjs/builders";
|
|
10
10
|
import { Routes } from "discord-api-types/v10";
|
|
11
11
|
import { SeedcordErrorCode, paint } from "@seedcord/errors";
|
package/dist/node.index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as CoordinatedShutdown, r as CoordinatedStartup, t as Pluggable } from "./Pluggable-
|
|
1
|
+
import { i as CoordinatedShutdown, r as CoordinatedStartup, t as Pluggable } from "./Pluggable-CqKvMXm5.mjs";
|
|
2
2
|
export { CoordinatedShutdown, CoordinatedStartup, Pluggable };
|
package/dist/node.index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as StartupPhase, t as ShutdownPhase } from "./phases-BauKJOTT.mjs";
|
|
2
|
-
import { a as withTimeout, i as settleWithin, t as Pluggable } from "./Pluggable-
|
|
2
|
+
import { a as withTimeout, i as settleWithin, t as Pluggable } from "./Pluggable-keys1cVr.mjs";
|
|
3
3
|
import { SeedcordErrorCode, paint } from "@seedcord/errors";
|
|
4
4
|
import { SeedcordAggregateError, SeedcordError, SeedcordRangeError, SeedcordTypeError } from "@seedcord/errors/internal";
|
|
5
5
|
import { Logger } from "@seedcord/logger";
|
|
@@ -2,8 +2,8 @@ import { APIApplicationCommand } from "discord-api-types/v10";
|
|
|
2
2
|
import { Logger } from "@seedcord/logger";
|
|
3
3
|
import { TypedEventEmitter } from "@seedcord/event-emitter";
|
|
4
4
|
import { REST } from "@discordjs/rest";
|
|
5
|
-
import { UUID } from "
|
|
6
|
-
import { Config, EventFrequency, IRateLimiter, RenderContext, ReplyResponse, TypedExclude } from "@seedcord/types";
|
|
5
|
+
import { UUID } from "@seedcord/types/internal";
|
|
6
|
+
import { Config, DispatchBag, DispatchState, EventFrequency, IRateLimiter, RenderContext, ReplyResponse, TypedExclude } from "@seedcord/types";
|
|
7
7
|
//#region src/stops/Notice.d.ts
|
|
8
8
|
/**
|
|
9
9
|
* Base class for a user-facing refusal or a reported fault.
|
|
@@ -88,15 +88,41 @@ declare enum InteractionKind {
|
|
|
88
88
|
UserContextMenu = "userContextMenu",
|
|
89
89
|
Autocomplete = "autocomplete"
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* The interaction kinds a middleware can filter on. Autocomplete carries no reply target.
|
|
93
|
+
*/
|
|
94
|
+
type MiddlewareKind = TypedExclude<InteractionKind, InteractionKind.Autocomplete>;
|
|
91
95
|
declare const CommandMetadataKey: unique symbol;
|
|
92
96
|
declare const InteractionMetadataKey: unique symbol;
|
|
93
|
-
declare const
|
|
97
|
+
declare const InteractionMiddlewareMetadataKey: unique symbol;
|
|
98
|
+
declare const EventMiddlewareMetadataKey: unique symbol;
|
|
94
99
|
declare const SubscribeMetadataKey: unique symbol;
|
|
95
100
|
declare const EventMetadataKey: unique symbol;
|
|
96
101
|
declare const GatedMetadataKey: unique symbol;
|
|
97
102
|
declare const WebhookUrlMetadataKey: unique symbol;
|
|
98
103
|
declare const InteractionRouteKeys: Record<InteractionKind, symbol>;
|
|
99
104
|
//#endregion
|
|
105
|
+
//#region src/dispatch/DispatchContext.d.ts
|
|
106
|
+
/**
|
|
107
|
+
* A typed bag allocated once per interaction dispatch and handed to the handler. The middleware and i18n
|
|
108
|
+
* work reads and writes it through {@link DispatchState}. Today the bag is empty, so it only carries the
|
|
109
|
+
* dispatched `routeId`.
|
|
110
|
+
*/
|
|
111
|
+
declare class DispatchContext implements DispatchBag {
|
|
112
|
+
readonly routeId: string;
|
|
113
|
+
private readonly state;
|
|
114
|
+
readonly id: `${string}-${string}-${string}-${string}-${string}`;
|
|
115
|
+
constructor(routeId: string);
|
|
116
|
+
set<Key extends keyof DispatchState>(key: Key, value: DispatchState[Key]): void;
|
|
117
|
+
get<Key extends keyof DispatchState>(key: Key): DispatchState[Key] | undefined;
|
|
118
|
+
/**
|
|
119
|
+
* Read a key that must be present, with `undefined` stripped from the result.
|
|
120
|
+
*
|
|
121
|
+
* @throws A **SeedcordError** If nothing set the key on this dispatch.
|
|
122
|
+
*/
|
|
123
|
+
require<Key extends keyof DispatchState>(key: Key): Exclude<DispatchState[Key], undefined>;
|
|
124
|
+
}
|
|
125
|
+
//#endregion
|
|
100
126
|
//#region src/subscribers/publishDefault.d.ts
|
|
101
127
|
/** @internal PublishableKey excludes this key so publish() never emits it externally. */
|
|
102
128
|
declare const PublishDefault: unique symbol;
|
|
@@ -122,10 +148,11 @@ declare function sendTarget(state: AckState): 'reply' | 'edit' | 'followUp';
|
|
|
122
148
|
//#region src/reply/responseReport.d.ts
|
|
123
149
|
interface ReplyTelemetry {
|
|
124
150
|
readonly bus: Bus;
|
|
151
|
+
readonly dispatch: DispatchContext;
|
|
125
152
|
readonly interactionId: string;
|
|
126
153
|
}
|
|
127
154
|
type WriteMethod = ReplyMethod | 'respond';
|
|
128
|
-
declare function reportedWrite<Result>(telemetry: ReplyTelemetry,
|
|
155
|
+
declare function reportedWrite<Result>(telemetry: ReplyTelemetry, method: WriteMethod, write: () => Promise<Result>): Promise<Result>;
|
|
129
156
|
//#endregion
|
|
130
157
|
//#region src/subscribers/types/Subscriptions.d.ts
|
|
131
158
|
/**
|
|
@@ -176,6 +203,8 @@ interface EventFaultSource {
|
|
|
176
203
|
* The fields both `responseAttempted` arms carry.
|
|
177
204
|
*/
|
|
178
205
|
interface AttemptedWrite {
|
|
206
|
+
/** The dispatch this write belongs to, for joining against every other key it published. */
|
|
207
|
+
readonly dispatchId: string;
|
|
179
208
|
readonly routeId: string;
|
|
180
209
|
/** The interaction this write belongs to, for joining against `interactionDispatched`. */
|
|
181
210
|
readonly interactionId: string;
|
|
@@ -216,9 +245,11 @@ interface DefaultSubscriptions {
|
|
|
216
245
|
/** Triggered when an unhandled exception (a raw non-Notice throw) occurs. */
|
|
217
246
|
readonly unknownException: {
|
|
218
247
|
readonly uuid: UUID;
|
|
248
|
+
/** The dispatch that raised it. Null on a process-level throw, which has no dispatch behind it. */
|
|
249
|
+
readonly dispatchId: string | null;
|
|
219
250
|
readonly error: Error;
|
|
220
251
|
/** Where the throw came from, `slash:ban` for an interaction and `event:name:handler` for an event. */
|
|
221
|
-
readonly
|
|
252
|
+
readonly origin: string;
|
|
222
253
|
readonly guild?: {
|
|
223
254
|
readonly id: string;
|
|
224
255
|
readonly name: string;
|
|
@@ -233,8 +264,10 @@ interface DefaultSubscriptions {
|
|
|
233
264
|
readonly handledException: {
|
|
234
265
|
readonly denial: Notice;
|
|
235
266
|
readonly uuid: UUID;
|
|
236
|
-
/** The
|
|
237
|
-
readonly
|
|
267
|
+
/** The dispatch that reported it. */
|
|
268
|
+
readonly dispatchId: string;
|
|
269
|
+
/** Where the reported Notice came from, the same shape `unknownException.origin` carries. */
|
|
270
|
+
readonly origin: string;
|
|
238
271
|
readonly source: FaultSource;
|
|
239
272
|
};
|
|
240
273
|
/** Triggered when an interaction dispatch throws past the fault boundary. */
|
|
@@ -243,6 +276,8 @@ interface DefaultSubscriptions {
|
|
|
243
276
|
};
|
|
244
277
|
/** Triggered once per interaction dispatch, after the handler chain settles. */
|
|
245
278
|
readonly interactionDispatched: {
|
|
279
|
+
/** This dispatch, for joining against every other key it published. */
|
|
280
|
+
readonly dispatchId: string;
|
|
246
281
|
readonly routeId: string;
|
|
247
282
|
/** The interaction this dispatch ran, for joining against `responseAttempted`. */
|
|
248
283
|
readonly interactionId: string;
|
|
@@ -250,6 +285,10 @@ interface DefaultSubscriptions {
|
|
|
250
285
|
readonly outcome: DispatchOutcome;
|
|
251
286
|
/** True when no route matched and the unhandled default ran. */
|
|
252
287
|
readonly fallback: boolean;
|
|
288
|
+
/** Who ran the route. Null when the payload carried no user. */
|
|
289
|
+
readonly userId: string | null;
|
|
290
|
+
/** Guild the interaction came from, null in DMs. */
|
|
291
|
+
readonly guildId: string | null;
|
|
253
292
|
/** Dispatch entry until the user has a response, replies included. A clock change never affects it. */
|
|
254
293
|
readonly durationMs: number;
|
|
255
294
|
/**
|
|
@@ -459,5 +498,5 @@ declare enum ShutdownPhase {
|
|
|
459
498
|
Logout = 4
|
|
460
499
|
}
|
|
461
500
|
//#endregion
|
|
462
|
-
export { UnregisterSubscriber as A,
|
|
463
|
-
//# sourceMappingURL=phases-
|
|
501
|
+
export { UnregisterSubscriber as A, InteractionMiddlewareMetadataKey as B, ReplyMethod as C, RegisterDefaults as D, AckTrace as E, EventMetadataKey as F, Notice as G, MiddlewareKind as H, EventMiddlewareMetadataKey as I, GatedMetadataKey as L, PublishDefault as M, DispatchContext as N, RegisterSubscriber as O, CommandMetadataKey as P, InteractionKind as R, AckState as S, sendTarget as T, SubscribeMetadataKey as U, InteractionRouteKeys as V, WebhookUrlMetadataKey as W, SubscriptionData as _, StoredSubscriberCtor as a, ReplyTelemetry as b, Subscriber as c, DispatchOutcome as d, FaultSource as f, ResponseSent as g, ResponseOutcome as h, Bus as i, VerifyWebhooks as j, RegisteredCount as k, AttemptedWrite as l, ResponseFailed as m, StartupPhase as n, SubscriberRegistration as o, ResponseAttempt as p, CoreBase as r, busLoggerOf as s, ShutdownPhase as t, DefaultSubscriptions as u, SubscriptionKey as v, checkAckLegality as w, reportedWrite as x, Subscriptions as y, InteractionMetadataKey as z };
|
|
502
|
+
//# sourceMappingURL=phases-DJf12l5T.d.mts.map
|
package/dist/plugin.index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { c as PluginOptions, p as PluginLifecycleSpec, r as Plugin } from "./Plugin-
|
|
1
|
+
import { c as PluginOptions, p as PluginLifecycleSpec, r as Plugin } from "./Plugin-BdqfRjU0.mjs";
|
|
2
2
|
import { HmrAware, HmrUpdateEvent } from "@seedcord/types";
|
|
3
3
|
export { type HmrAware, type HmrUpdateEvent, Plugin, type PluginLifecycleSpec, type PluginOptions };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { M as isBuilderComponentClass, g as CommandMetadataKey } from "./Bus-Djm6688b.mjs";
|
|
2
2
|
import { SlashCommandBuilder } from "@discordjs/builders";
|
|
3
3
|
import { routeLeavesOf } from "@seedcord/utils/internal";
|
|
4
4
|
|
|
@@ -28,4 +28,4 @@ function slashRouteLeaves(commands) {
|
|
|
28
28
|
|
|
29
29
|
//#endregion
|
|
30
30
|
export { isCommandClass as n, slashRouteLeaves as t };
|
|
31
|
-
//# sourceMappingURL=slashRouteLeaves-
|
|
31
|
+
//# sourceMappingURL=slashRouteLeaves-DTFHzCKN.mjs.map
|