@seedcord/core 0.1.0-next.6 → 0.1.0-next.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/{AutocompleteOptions-eKhIe6Qt.d.mts → AutocompleteOptions-DLp_B8as.d.mts} +61 -112
  2. package/dist/HmrModuleHandler-3sNgKHdf.mjs +163 -0
  3. package/dist/HmrModuleHandler-3sNgKHdf.mjs.map +1 -0
  4. package/dist/HmrModuleHandler-CTBng7wV.cjs +170 -0
  5. package/dist/HmrModuleHandler-CTBng7wV.cjs.map +1 -0
  6. package/dist/Plugin-3rlH0uxH.d.mts +620 -0
  7. package/dist/{Plugin-C2-VHrsX.cjs → Plugin-Cgp1a0uQ.cjs} +13 -4
  8. package/dist/Plugin-Cgp1a0uQ.cjs.map +1 -0
  9. package/dist/{Plugin-PcdPjAzc.mjs → Plugin-j9GYdroS.mjs} +13 -4
  10. package/dist/Plugin-j9GYdroS.mjs.map +1 -0
  11. package/dist/{permissions-DSW_EZfN.cjs → Silence-DiP95iwD.cjs} +38 -307
  12. package/dist/Silence-DiP95iwD.cjs.map +1 -0
  13. package/dist/{permissions-RVCBhL2n.mjs → Silence-dbC2slOB.mjs} +35 -238
  14. package/dist/Silence-dbC2slOB.mjs.map +1 -0
  15. package/dist/basic-D7bDlgSP.d.mts +10 -0
  16. package/dist/hmr.index.cjs +2 -164
  17. package/dist/hmr.index.mjs +2 -162
  18. package/dist/index-Dueqztyy.d.mts +142 -0
  19. package/dist/index.cjs +50 -72
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.mts +7 -5
  22. package/dist/index.mjs +8 -35
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/internal.index.cjs +262 -74
  25. package/dist/internal.index.cjs.map +1 -1
  26. package/dist/internal.index.d.mts +68 -4
  27. package/dist/internal.index.mjs +216 -35
  28. package/dist/internal.index.mjs.map +1 -1
  29. package/dist/node-internal.index.cjs +123 -52
  30. package/dist/node-internal.index.cjs.map +1 -1
  31. package/dist/node-internal.index.d.mts +67 -2158
  32. package/dist/node-internal.index.mjs +124 -54
  33. package/dist/node-internal.index.mjs.map +1 -1
  34. package/dist/plugin.index.cjs +1 -1
  35. package/dist/plugin.index.d.mts +1 -1
  36. package/dist/plugin.index.mjs +1 -1
  37. package/dist/publishDefault-CCf1azzW.mjs +264 -0
  38. package/dist/publishDefault-CCf1azzW.mjs.map +1 -0
  39. package/dist/publishDefault-l0NQ-SHo.cjs +353 -0
  40. package/dist/publishDefault-l0NQ-SHo.cjs.map +1 -0
  41. package/dist/subscribers-B1G6_LlK.cjs +517 -0
  42. package/dist/subscribers-B1G6_LlK.cjs.map +1 -0
  43. package/dist/subscribers-DYqFVP1X.mjs +480 -0
  44. package/dist/subscribers-DYqFVP1X.mjs.map +1 -0
  45. package/package.json +7 -6
  46. package/dist/Plugin-C2-VHrsX.cjs.map +0 -1
  47. package/dist/Plugin-CNyRKDHT.d.mts +0 -226
  48. package/dist/Plugin-PcdPjAzc.mjs.map +0 -1
  49. package/dist/hmr.index.cjs.map +0 -1
  50. package/dist/hmr.index.mjs.map +0 -1
  51. package/dist/is-never-Ddaba1Su.d.mts +0 -58
  52. package/dist/permissions-DSW_EZfN.cjs.map +0 -1
  53. package/dist/permissions-RVCBhL2n.mjs.map +0 -1
@@ -0,0 +1,620 @@
1
+ import { FrameworkChannel, Logger } from "@seedcord/logger";
2
+ import { TypedEventEmitter } from "@seedcord/event-emitter";
3
+ import { Config, EventFrequency, HmrAware, HmrUpdateEvent, IRateLimiter, RenderContext, ReplyResponse, Store, Tail, TypedExclude } from "@seedcord/types";
4
+ import { UUID } from "node:crypto";
5
+
6
+ //#region src/metadataKeys.d.ts
7
+ declare enum InteractionRoutes {
8
+ Slash = "slash",
9
+ Button = "button",
10
+ Modal = "modal",
11
+ StringMenu = "stringMenu",
12
+ UserMenu = "userMenu",
13
+ RoleMenu = "roleMenu",
14
+ ChannelMenu = "channelMenu",
15
+ MentionableMenu = "mentionableMenu",
16
+ MessageContextMenu = "messageContextMenu",
17
+ UserContextMenu = "userContextMenu",
18
+ Autocomplete = "autocomplete"
19
+ }
20
+ declare const InteractionMetadataKey: unique symbol;
21
+ declare const InteractionRouteKeys: Record<InteractionRoutes, symbol>;
22
+ declare const MiddlewareMetadataKey: unique symbol;
23
+ declare const EventMetadataKey: unique symbol;
24
+ declare const CommandMetadataKey: unique symbol;
25
+ declare const GatedMetadataKey: unique symbol;
26
+ declare const SubscribeMetadataKey: unique symbol;
27
+ declare const WebhookUrlMetadataKey: unique symbol;
28
+ //#endregion
29
+ //#region src/subscribers/publishDefault.d.ts
30
+ /**
31
+ * The key of the Bus method that emits the framework's own subscriptions. `publish` excludes these keys
32
+ * through `PublishableKey`, and this symbol is exported only from the internal entry.
33
+ *
34
+ * @internal
35
+ */
36
+ declare const PublishDefault: unique symbol;
37
+ //#endregion
38
+ //#region src/reply/AckTrace.d.ts
39
+ /** The first ack's stack, passed as the throw cause so a double-ack points to both lines. */
40
+ declare class AckTrace extends Error {
41
+ constructor(method: ReplyMethod);
42
+ }
43
+ //#endregion
44
+ //#region src/reply/ackLegality.d.ts
45
+ type AckState = 'unacked' | 'deferred-reply' | 'deferred-update' | 'replied';
46
+ type ReplyMethod = 'reply' | 'defer' | 'deferUpdate' | 'update' | 'followUp' | 'edit' | 'delete' | 'send' | 'showModal';
47
+ /** Throws before any API call. `ackedBy` becomes the throw cause, its stack points at the first ack. */
48
+ declare function checkAckLegality(method: ReplyMethod, state: AckState, routeId: string, ackedBy?: AckTrace): void;
49
+ declare function sendTarget(state: AckState): 'reply' | 'edit' | 'followUp';
50
+ //#endregion
51
+ //#region src/reply/responseReport.d.ts
52
+ /** What `publishResponse` requires. Without it the call returns without publishing. */
53
+ interface ReplyTelemetry {
54
+ readonly bus: Bus;
55
+ readonly interactionId: string;
56
+ }
57
+ /** The reply verbs plus the autocomplete choices callback, which runs outside the ack state machine. */
58
+ type WriteMethod = ReplyMethod | 'respond';
59
+ /**
60
+ * Runs a write that returns no message and publishes whichever arm it takes.
61
+ *
62
+ * @internal
63
+ */
64
+ declare function reportedWrite<Result>(telemetry: ReplyTelemetry | undefined, routeId: string, method: WriteMethod, write: () => Promise<Result>): Promise<Result>;
65
+ //#endregion
66
+ //#region src/stops/Notice.d.ts
67
+ /**
68
+ * Base class for a user-facing refusal or a reported fault.
69
+ *
70
+ * Throw a `Notice` to stop a handler and reply to the user. The framework catches it at the controller
71
+ * boundary and renders {@link Notice.render}, which always decides what the user sees. With `report`
72
+ * false that render is all that happens. With `report` true the framework also logs the fault and
73
+ * publishes it to the `handledException` bus. A raw, non-Notice throw shows the generic message.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * import { Notice, BuilderComponent, type RenderContext, type ReplyResponse } from '@seedcord/gateway';
78
+ * import { TextDisplayBuilder } from '@discordjs/builders';
79
+ *
80
+ * // reading `.component` applies the configured bot color to the container accent
81
+ * class TooPoorCard extends BuilderComponent<'container'> {
82
+ * constructor(balance: number) {
83
+ * super('container');
84
+ * this.instance.addTextDisplayComponents(
85
+ * new TextDisplayBuilder().setContent(`### Insufficient balance\nYou need more than ${balance} coins.`)
86
+ * );
87
+ * }
88
+ * }
89
+ *
90
+ * class TooPoor extends Notice {
91
+ * constructor(private readonly balance: number) {
92
+ * super(`balance ${balance} is below the cost`);
93
+ * }
94
+ *
95
+ * render(_ctx: RenderContext): ReplyResponse {
96
+ * return { components: [new TooPoorCard(this.balance).component] };
97
+ * }
98
+ * }
99
+ *
100
+ * // in a handler, throwing stops the handler and replies with render(ctx)
101
+ * if (wallet.balance < cost) throw new TooPoor(wallet.balance);
102
+ * ```
103
+ */
104
+ declare abstract class Notice extends Error {
105
+ /**
106
+ * Whether this denial is a reported fault. True also logs it and publishes it to the `handledException`
107
+ * bus. The user always sees {@link Notice.render} either way.
108
+ *
109
+ * @defaultValue `false`
110
+ */
111
+ report: boolean;
112
+ /**
113
+ * Whether the reply is ephemeral, so only the invoking user sees it. Set it false for a refusal the
114
+ * whole channel should see.
115
+ *
116
+ * @defaultValue `true`
117
+ */
118
+ ephemeral: boolean;
119
+ /**
120
+ * A short one-line reason. When every arm of an `or` gate refuses and each refusal sets this, `or`
121
+ * lists them instead of showing a neutral message.
122
+ */
123
+ summary?: string;
124
+ protected constructor(message: string, options?: ErrorOptions);
125
+ /**
126
+ * Builds what the user sees. Called fresh each time the denial is shown, so the builders are new
127
+ * and the bot color resolves at render time rather than at construction time.
128
+ */
129
+ abstract render(ctx: RenderContext): ReplyResponse;
130
+ }
131
+ //#endregion
132
+ //#region src/subscribers/types/Subscriptions.d.ts
133
+ /**
134
+ * How a dispatch finished. The thrown value's type sets this, wherever it was thrown. A `Silence` and a
135
+ * `Notice` with `report` false are `refused`. A `Notice` with `report` true, which includes a default
136
+ * `Fault`, is `failed`, as is any other throw.
137
+ */
138
+ type DispatchOutcome = 'handled' | 'refused' | 'failed';
139
+ /** Whether a write through the reply surface reached Discord. */
140
+ type ResponseOutcome = 'sent' | 'failed';
141
+ /**
142
+ * Where a reported fault came from.
143
+ */
144
+ type FaultSource = InteractionFaultSource | EventFaultSource;
145
+ /**
146
+ * A fault that came from a discord interaction, JSON-safe for a webhook payload.
147
+ */
148
+ interface InteractionFaultSource {
149
+ kind: 'interaction';
150
+ interactionKind: 'slash' | 'context-menu' | 'button' | 'select' | 'modal';
151
+ /** Slash or context-menu command name, null for component and modal interactions. */
152
+ command: string | null;
153
+ /** Component or modal customId, null for slash and context-menu interactions. */
154
+ customId: string | null;
155
+ userId: string;
156
+ /** Guild the interaction came from, null in DMs. */
157
+ guildId: string | null;
158
+ /** Channel the interaction came from, null when unavailable. */
159
+ channelId: string | null;
160
+ interactionId: string;
161
+ /** The raw interaction, made JSON-safe at serialization with filterCirculars. */
162
+ raw: unknown;
163
+ }
164
+ /**
165
+ * A fault that came from a client event, JSON-safe for a webhook payload. The actor, guild, and channel
166
+ * are best-effort, derived from the event args, so each is nullable. The raw args carry the full detail.
167
+ */
168
+ interface EventFaultSource {
169
+ kind: 'event';
170
+ eventName: string;
171
+ handler: string;
172
+ userId: string | null;
173
+ /** Null outside a guild. */
174
+ guildId: string | null;
175
+ channelId: string | null;
176
+ /** The raw event args, made JSON-safe at serialization with filterCirculars. */
177
+ raw: unknown;
178
+ }
179
+ /**
180
+ * The framework's own subscription keys. A transport adds a key whose payload type references a type
181
+ * outside this package, through declaration merging on its own module.
182
+ *
183
+ * Every key here is publish-protected. Subscribe to them. The framework is the
184
+ * only publisher.
185
+ */
186
+ interface DefaultSubscriptions {
187
+ /** Triggered when an unhandled exception (a raw non-Notice throw) occurs. */
188
+ unknownException: {
189
+ uuid: UUID;
190
+ error: Error;
191
+ guild?: {
192
+ id: string;
193
+ name: string;
194
+ } | undefined;
195
+ user?: {
196
+ id: string;
197
+ username: string;
198
+ } | undefined;
199
+ metadata?: unknown;
200
+ };
201
+ /** Triggered when a reported Notice (`report: true`) is caught. */
202
+ handledException: {
203
+ denial: Notice;
204
+ uuid: UUID;
205
+ source: FaultSource;
206
+ };
207
+ /** Triggered when an interaction dispatch throws past the fault boundary. */
208
+ unhandledInteractionError: {
209
+ error: Error;
210
+ };
211
+ /** Triggered once per interaction dispatch, after the handler chain settles. */
212
+ interactionDispatched: {
213
+ routeId: string; /** The interaction this dispatch ran, for joining against `responseAttempted`. */
214
+ interactionId: string;
215
+ kind: `${InteractionRoutes}`;
216
+ outcome: DispatchOutcome; /** True when no route matched and the unhandled default ran. */
217
+ fallback: boolean; /** Dispatch entry until the user has a response, replies included. A clock change never affects it. */
218
+ durationMs: number;
219
+ /**
220
+ * Discord's interaction creation until dispatch entry, read from the snowflake. This covers
221
+ * network transit plus any time your bot was busy before starting, so a rise points at either
222
+ * Discord or your own backlog. It subtracts a Discord timestamp from the host clock, so a host
223
+ * running behind Discord reports a negative value.
224
+ */
225
+ queuedMs: number;
226
+ };
227
+ /**
228
+ * Triggered on every write through the reply surface, several times per interaction. A write that
229
+ * throws reports here too, with `outcome` `failed`. A write that reaches Discord and then returns an
230
+ * unexpected shape publishes nothing, since the callback succeeded and carries no message to name.
231
+ */
232
+ responseAttempted: {
233
+ routeId: string; /** The interaction this write belongs to, for joining against `interactionDispatched`. */
234
+ interactionId: string; /** `send` routes to another verb, so it reports the verb that ran. */
235
+ method: WriteMethod;
236
+ outcome: ResponseOutcome;
237
+ durationMs: number; /** Null for every ack-only or choice-only verb, and for a failed write. */
238
+ messageId: string | null; /** Present when `outcome` is `failed`. */
239
+ error?: Error;
240
+ };
241
+ }
242
+ /**
243
+ * Custom subscribers defined by the application. Augment it via declaration merging to type your
244
+ * own subscriber payloads.
245
+ *
246
+ * @example
247
+ * ```typescript
248
+ * // the transport package your bot installs, '@seedcord/gateway' or '@seedcord/http'
249
+ * declare module '@seedcord/gateway' {
250
+ * interface Subscriptions {
251
+ * 'userJoin': { userId: string; guildId: string };
252
+ * 'levelUp': { userId: string; level: number };
253
+ * }
254
+ * }
255
+ * ```
256
+ */
257
+ interface Subscriptions {}
258
+ interface AllSubscriptions extends DefaultSubscriptions, Subscriptions {}
259
+ /** All subscriber event names available to subscribe to and augment. */
260
+ type SubscriptionKey = keyof AllSubscriptions;
261
+ /**
262
+ * The keys `publish` accepts. The framework's own keys are excluded, since only the framework
263
+ * produces them.
264
+ */
265
+ type PublishableKey = TypedExclude<SubscriptionKey, keyof DefaultSubscriptions>;
266
+ /**
267
+ * The payload type for a subscriber event.
268
+ *
269
+ * @typeParam KeyOfSubscribers - The subscriber event name
270
+ */
271
+ type SubscriptionData<KeyOfSubscribers extends SubscriptionKey> = AllSubscriptions[KeyOfSubscribers];
272
+ type SubscriptionTuples = { [K in SubscriptionKey]: [AllSubscriptions[K]] };
273
+ //#endregion
274
+ //#region src/subscribers/Subscriber.d.ts
275
+ /**
276
+ * Abstract base class for handling application subscribers.
277
+ *
278
+ * Provides type-safe access to subscribers data and the core framework instance.
279
+ * Extend this class to create custom subscriber handlers.
280
+ *
281
+ * @typeParam KeyOfSubscribers - The specific subscriber type this handler processes
282
+ * @typeParam TCore - The transport's Core
283
+ */
284
+ declare abstract class Subscriber<KeyOfSubscribers extends SubscriptionKey, TCore extends CoreBase> {
285
+ protected readonly data: AllSubscriptions[KeyOfSubscribers];
286
+ protected readonly core: TCore;
287
+ protected readonly logger: Logger;
288
+ /**
289
+ * Instantiates the subscriber with event data and core.
290
+ *
291
+ * @param data - The subscriber event data
292
+ * @param core - The core framework instance
293
+ */
294
+ constructor(data: AllSubscriptions[KeyOfSubscribers], core: TCore);
295
+ /**
296
+ * Executes the subscriber handler logic.
297
+ */
298
+ abstract execute(): Promise<void>;
299
+ }
300
+ //#endregion
301
+ //#region src/subscribers/Bus.d.ts
302
+ /**
303
+ * A subscriber class as the Bus stores it. Both parameters are `never` because construct-signature
304
+ * parameters check contravariantly, and a concrete subscriber narrows each to its own payload and
305
+ * transport `Core`. One cast at dispatch restores both.
306
+ *
307
+ * @internal
308
+ */
309
+ type StoredSubscriberCtor = new (data: never, core: never) => Subscriber<SubscriptionKey, CoreBase>;
310
+ /**
311
+ * One registration. `resolve` is lazy so an edge host registers from a manifest row without
312
+ * importing the module until that key first publishes.
313
+ *
314
+ * @internal
315
+ */
316
+ interface SubscriberRegistration {
317
+ readonly keys: readonly SubscriptionKey[];
318
+ readonly frequency: EventFrequency;
319
+ readonly resolve: () => StoredSubscriberCtor | Promise<StoredSubscriberCtor>;
320
+ /** The resolved class. A server-host registration carries it from the start, a lazy one fills it on first resolve. */
321
+ ctor?: StoredSubscriberCtor | undefined;
322
+ }
323
+ /**
324
+ * Registers and dispatches subscribers. Subscribers run on a programmatic or framework publish.
325
+ * Accessed via `core.bus`. Do not construct it directly.
326
+ */
327
+ declare class Bus extends TypedEventEmitter<SubscriptionTuples> {
328
+ protected core: CoreBase;
329
+ /** @internal */
330
+ readonly logger: Logger;
331
+ private readonly subscribersMap;
332
+ private readonly executedOnce;
333
+ private readonly webhookProbes;
334
+ constructor(core: CoreBase);
335
+ /**
336
+ * Registers the two shipped webhook reporters. The host calls this during startup, keeping the
337
+ * url validation inside `start()` where a failure can still release the singleton guard.
338
+ *
339
+ * @internal
340
+ */
341
+ registerDefaults(): void;
342
+ /** @internal */
343
+ register(registration: SubscriberRegistration): void;
344
+ /** @internal */
345
+ unregister(ctor: StoredSubscriberCtor, keys?: readonly SubscriptionKey[]): void;
346
+ /** @internal */
347
+ get registeredCount(): number;
348
+ /** @internal Only eagerly registered reporters are probed, which is every server-host one. */
349
+ verifyWebhooks(): Promise<void>;
350
+ /** Returns whether the class should register. */
351
+ private probeWebhook;
352
+ /**
353
+ * Publishes an event to its subscribers and native listeners.
354
+ *
355
+ * Fire-and-forget, so subscriber handlers run asynchronously and this returns before they
356
+ * complete, and callers must not assume side effects have completed. Errors thrown by a subscriber
357
+ * or by an `on()` listener are caught and logged, never surfaced here. One throwing listener
358
+ * does not stop the others. Subscribers on one key run concurrently and carry no ordering
359
+ * guarantee. A `'once'` subscriber is marked as executed when it starts (even if it throws), so
360
+ * it never runs twice.
361
+ *
362
+ * The framework's own keys are excluded. Subscribe to those and listen with `on`. The framework
363
+ * is their only publisher.
364
+ *
365
+ * @param event - The subscription key to publish
366
+ * @param data - Payload passed to each subscriber
367
+ * @returns Whether the underlying emitter had native listeners for the event
368
+ */
369
+ publish<KeyOfSubscribers extends PublishableKey>(event: KeyOfSubscribers, data: AllSubscriptions[KeyOfSubscribers]): boolean;
370
+ /** @internal the framework's own publish path, keyed by a symbol no public entry exports */
371
+ [PublishDefault]<KeyOfSubscribers extends keyof DefaultSubscriptions>(event: KeyOfSubscribers, data: AllSubscriptions[KeyOfSubscribers]): boolean;
372
+ private dispatchKey;
373
+ protected onListenerError(error: unknown, event: string | symbol): void;
374
+ private processSubscriber;
375
+ private runSubscriber;
376
+ }
377
+ //#endregion
378
+ //#region src/interfaces/CoreBase.d.ts
379
+ /**
380
+ * The transport-agnostic slice of the running framework, what core code (gates, notices, plugins'
381
+ * agnostic surface) accesses through `ctx.core`. Each transport's `Core` extends it with its own
382
+ * members.
383
+ */
384
+ interface CoreBase {
385
+ /** Transports narrow this to their own config type. */
386
+ readonly config: Config;
387
+ /** Sliding-window rate limiting, the `Cooldown` gate's backend and a public direct-use API. */
388
+ readonly rateLimiter: IRateLimiter;
389
+ /** Publish and subscribe to framework and application events. */
390
+ readonly bus: Bus;
391
+ }
392
+ //#endregion
393
+ //#region src/plugin/options.d.ts
394
+ /** A capability a plugin declares through `needs`, each surfacing a typed `ctx` field. */
395
+ type PluginNeed = 'client' | 'token' | 'rest';
396
+ /**
397
+ * The options a plugin declares as its `Plugin<Opts>` type argument. Authors write unions for `needs`,
398
+ * e.g. `needs: 'token' | 'rest'`.
399
+ */
400
+ interface PluginOptions {
401
+ /**
402
+ * Which transport the plugin runs on. `'any'` attaches to either one.
403
+ * @defaultValue 'any'
404
+ */
405
+ transport?: 'gateway' | 'http' | 'any';
406
+ /**
407
+ * Which runtime the plugin runs on. `'any'` attaches to either one.
408
+ * @defaultValue 'any'
409
+ */
410
+ runtime?: 'server' | 'edge' | 'any';
411
+ /** Capabilities the plugin requests, each a typed `ctx` field. */
412
+ needs?: PluginNeed;
413
+ }
414
+ /** @internal */
415
+ type TransportOf<Opts extends PluginOptions> = undefined extends Opts['transport'] ? 'any' : NonNullable<Opts['transport']>;
416
+ /** @internal */
417
+ type RuntimeOf<Opts extends PluginOptions> = undefined extends Opts['runtime'] ? 'any' : NonNullable<Opts['runtime']>;
418
+ /** @internal */
419
+ type NeedsOf<Opts extends PluginOptions> = undefined extends Opts['needs'] ? never : NonNullable<Opts['needs']>;
420
+ /** @internal the transport a bot runs */
421
+ type Transport = TypedExclude<NonNullable<PluginOptions['transport']>, 'any'>;
422
+ /** @internal the runtime a bot runs */
423
+ type Runtime = TypedExclude<NonNullable<PluginOptions['runtime']>, 'any'>;
424
+ type TransportMismatch<PluginT extends string, BotT extends string> = Record<`this plugin declares transport '${PluginT}' but this bot runs '${BotT}'`, never>;
425
+ type RuntimeMismatch<PluginRt extends string, BotRt extends string> = Record<`this plugin declares runtime '${PluginRt}' but this bot runs '${BotRt}'`, never>;
426
+ type EdgePluginsUnsupported = Record<'an edge bot takes no plugins until edge support ships after v1', never>;
427
+ /** @internal */
428
+ type ChannelKeyAssert<Key extends string> = Key extends FrameworkChannel ? `'${Key}' is a channel the framework logs on. Pick another plugin key.` : Key;
429
+ type BrandTransport<Plug> = Plug extends {
430
+ readonly __transport?: infer T extends string;
431
+ } ? T : 'any';
432
+ type BrandRuntime<Plug> = Plug extends {
433
+ readonly __runtime?: infer R extends string;
434
+ } ? R : 'any';
435
+ /** @internal */
436
+ type TransportAssert<Plug, BotT extends Transport> = BrandTransport<Plug> extends 'any' | BotT ? unknown : TransportMismatch<BrandTransport<Plug>, BotT>;
437
+ /** @internal */
438
+ type RuntimeAssert<Plug, BotRt extends Runtime> = 'edge' extends BotRt ? EdgePluginsUnsupported : BrandRuntime<Plug> extends 'any' | BotRt ? unknown : RuntimeMismatch<BrandRuntime<Plug>, BotRt>;
439
+ //#endregion
440
+ //#region src/plugin/context.d.ts
441
+ /**
442
+ * The type each `ctx` capability resolves to. Empty in core, each transport augments it through
443
+ * declaration merging.
444
+ *
445
+ * @example
446
+ * ```typescript
447
+ * declare module '@seedcord/core' {
448
+ * interface PluginCapabilityTypes {
449
+ * client: Client;
450
+ * rest: REST;
451
+ * }
452
+ * }
453
+ * ```
454
+ */
455
+ interface PluginCapabilityTypes {}
456
+ type CapabilityType<Key extends PluginNeed, Fallback> = Key extends keyof PluginCapabilityTypes ? PluginCapabilityTypes[Key] : Fallback;
457
+ type CapabilityValue<TNeeds extends PluginNeed, Key extends PluginNeed, Value> = Key extends TNeeds ? Value : never;
458
+ /**
459
+ * The framework surface a plugin reads through `this.ctx`, typed by its declared `needs`.
460
+ *
461
+ * Always available: `config` and `store`. Each capability resolves to its value only when
462
+ * the plugin declared that key, otherwise `never`. The logger comes from `this.logger`.
463
+ *
464
+ * @typeParam TNeeds - The plugin's declared `needs` union.
465
+ */
466
+ interface PluginContext<TNeeds extends PluginNeed = never> {
467
+ readonly config: Config;
468
+ readonly store: Store<'charge'>;
469
+ readonly client: CapabilityValue<TNeeds, 'client', CapabilityType<'client', unknown>>;
470
+ readonly token: CapabilityValue<TNeeds, 'token', string>;
471
+ /**
472
+ * The REST client. On http, the client has no token until the Ready phase, so a call from
473
+ * `init()` sends without a token and returns a 401.
474
+ */
475
+ readonly rest: CapabilityValue<TNeeds, 'rest', CapabilityType<'rest', unknown>>;
476
+ }
477
+ /** @internal */
478
+ type StoredPluginContext = Pick<PluginContext, 'config' | 'store'> & {
479
+ client?: unknown;
480
+ token?: string | undefined;
481
+ rest?: unknown;
482
+ };
483
+ /**
484
+ * The capability arms a transport supplies from its own Bot/client. `attach` merges them into each
485
+ * plugin's ctx.
486
+ *
487
+ * @internal
488
+ */
489
+ interface PluginCapabilities {
490
+ readonly client?: unknown;
491
+ readonly token?: string | undefined;
492
+ readonly rest?: unknown;
493
+ }
494
+ /** @internal unset until attach installs the built ctx */
495
+ declare const pluginContextSlot: unique symbol;
496
+ //#endregion
497
+ //#region src/lifecycle/phases.d.ts
498
+ /**
499
+ * Startup phases, in run order.
500
+ */
501
+ declare enum StartupPhase {
502
+ /** Nothing connected. Plugin init runs here by default. */
503
+ Configuration = 1,
504
+ /** The gateway session opens. Empty on http. */
505
+ Login = 2,
506
+ /** Handlers are live and interactions dispatch. */
507
+ Ready = 3
508
+ }
509
+ /**
510
+ * Shutdown phases, in run order.
511
+ */
512
+ declare enum ShutdownPhase {
513
+ /** Stop taking new interactions and requests. */
514
+ Unbind = 1,
515
+ /** Waits for in-flight work to settle and stops internal services. */
516
+ Drain = 2,
517
+ /** External resources close. Plugin dispose runs here by default. */
518
+ Disconnect = 3,
519
+ /** The client disconnects last so in-flight handlers can still reference it during drain. */
520
+ Logout = 4
521
+ }
522
+ //#endregion
523
+ //#region src/plugin/lifecycle.d.ts
524
+ /**
525
+ * The lifecycle a plugin declares through `super(host, spec)`. Unset fields resolve to the base
526
+ * defaults. `ready` runs at a fixed `StartupPhase.Ready`, so it takes only a timeout.
527
+ */
528
+ interface PluginLifecycleSpec {
529
+ init?: {
530
+ phase?: StartupPhase;
531
+ timeout?: number;
532
+ };
533
+ ready?: {
534
+ timeout?: number;
535
+ };
536
+ dispose?: {
537
+ phase?: ShutdownPhase;
538
+ timeout?: number;
539
+ };
540
+ }
541
+ /** @internal */
542
+ interface ResolvedPluginLifecycleSpec {
543
+ readonly init: {
544
+ readonly phase: StartupPhase;
545
+ readonly timeout: number;
546
+ };
547
+ readonly ready: {
548
+ readonly timeout: number;
549
+ };
550
+ readonly dispose: {
551
+ readonly phase: ShutdownPhase;
552
+ readonly timeout: number;
553
+ };
554
+ }
555
+ //#endregion
556
+ //#region src/plugin/Plugin.d.ts
557
+ interface Initializeable {
558
+ init(): Promise<void>;
559
+ }
560
+ /** @internal */
561
+ declare const resolvedSpecSlot: unique symbol;
562
+ /**
563
+ * Base class for Seedcord plugins. A subclass declares its options as the `Opts` type argument,
564
+ * implements `init()`, and reads the framework surface through `this.ctx`.
565
+ *
566
+ * @typeParam Opts - The plugin's declared {@link PluginOptions}.
567
+ * @typeParam TCore - The host type `this.core` resolves to. Each transport binds it to its own `Core`.
568
+ */
569
+ declare abstract class Plugin<Opts extends PluginOptions = {}, TCore extends CoreBase = CoreBase> implements Initializeable, HmrAware {
570
+ private readonly host;
571
+ /** @internal phantom, never set at runtime */
572
+ readonly __transport?: TransportOf<Opts>;
573
+ /** @internal phantom, never set at runtime */
574
+ readonly __runtime?: RuntimeOf<Opts>;
575
+ /** @internal */
576
+ readonly [resolvedSpecSlot]: ResolvedPluginLifecycleSpec;
577
+ /** @internal */
578
+ [pluginContextSlot]?: StoredPluginContext;
579
+ /** Logs under the plugin's class name, on the channel its attach key names. */
580
+ readonly logger: Logger;
581
+ constructor(host: CoreBase, spec?: PluginLifecycleSpec);
582
+ /** The host, typed to the transport whose `Plugin` base this class extends. */
583
+ protected get core(): TCore;
584
+ /** The framework surface, available from `init()` onward. Throws if read before `attach` finalizes it. */
585
+ protected get ctx(): PluginContext<NeedsOf<Opts>>;
586
+ abstract init(): Promise<void>;
587
+ /**
588
+ * Runs in the startup Ready phase, after `init()`. The gateway client is logged in by this phase,
589
+ * and the http host runs its server-bind and health tasks in the same phase.
590
+ */
591
+ ready?(): Promise<void>;
592
+ /** Runs during teardown, only when `init()` resolved. */
593
+ dispose?(): Promise<void>;
594
+ /**
595
+ * Rejects the plugin's constructor options with a reason. Throws a `SeedcordError` naming the
596
+ * plugin class and the reason.
597
+ *
598
+ * @param reason - Why the options are invalid.
599
+ */
600
+ protected rejectOptions(reason: string): never;
601
+ /** Override to reload plugin state on an HMR update. */
602
+ onHmr(_event: HmrUpdateEvent): Promise<void>;
603
+ /**
604
+ * Registers critical file patterns that should trigger a full restart when changed in Dev HMR.
605
+ * @param patterns - Glob patterns relative to the project root
606
+ */
607
+ protected registerCriticalFiles(patterns: string[]): void;
608
+ }
609
+ /** @internal */
610
+ type PluginLike = Pick<Plugin, 'init' | 'ready' | 'dispose' | 'logger' | 'onHmr' | typeof resolvedSpecSlot | typeof pluginContextSlot>;
611
+ /** @internal */
612
+ type PluginCtor<TPlugin extends PluginLike = PluginLike> = new (...args: any[]) => TPlugin;
613
+ /** @internal */
614
+ type PluginArgs<Ctor extends PluginCtor> = Tail<ConstructorParameters<Ctor>>;
615
+ type CoreParamTooNarrow = Record<'this plugin constructor must take CoreBase as its first parameter and read the transport Core off this.core', never>;
616
+ /** @internal */
617
+ type CoreParamAssert<Ctor extends PluginCtor> = CoreBase extends ConstructorParameters<Ctor>[0] ? unknown : CoreParamTooNarrow;
618
+ //#endregion
619
+ export { Notice as A, EventMetadataKey as B, Subscriber as C, SubscriptionData as D, FaultSource as E, checkAckLegality as F, MiddlewareMetadataKey as G, InteractionMetadataKey as H, sendTarget as I, SubscribeMetadataKey as K, AckTrace as L, reportedWrite as M, AckState as N, SubscriptionKey as O, ReplyMethod as P, PublishDefault as R, SubscriberRegistration as S, DispatchOutcome as T, InteractionRouteKeys as U, GatedMetadataKey as V, InteractionRoutes as W, Transport as _, PluginCtor as a, Bus as b, ShutdownPhase as c, PluginCapabilityTypes as d, PluginContext as f, RuntimeAssert as g, Runtime as h, PluginArgs as i, ReplyTelemetry as j, Subscriptions as k, StartupPhase as l, PluginOptions as m, Initializeable as n, PluginLike as o, ChannelKeyAssert as p, WebhookUrlMetadataKey as q, Plugin as r, PluginLifecycleSpec as s, CoreParamAssert as t, PluginCapabilities as u, TransportAssert as v, DefaultSubscriptions as w, StoredSubscriberCtor as x, CoreBase as y, CommandMetadataKey as z };
620
+ //# sourceMappingURL=Plugin-3rlH0uxH.d.mts.map
@@ -2,6 +2,7 @@ const require_phases = require('./phases-C_BGNyVo.cjs');
2
2
  const require_devChannel = require('./devChannel-CoCmAVDx.cjs');
3
3
  let _seedcord_errors = require("@seedcord/errors");
4
4
  let _seedcord_errors_internal = require("@seedcord/errors/internal");
5
+ let _seedcord_logger = require("@seedcord/logger");
5
6
 
6
7
  //#region src/plugin/context.ts
7
8
  /** @internal unset until attach installs the built ctx */
@@ -51,17 +52,25 @@ const resolvedSpecSlot = Symbol("seedcord.plugin.spec");
51
52
  * implements `init()`, and reads the framework surface through `this.ctx`.
52
53
  *
53
54
  * @typeParam Opts - The plugin's declared {@link PluginOptions}.
55
+ * @typeParam TCore - The host type `this.core` resolves to. Each transport binds it to its own `Core`.
54
56
  */
55
57
  var Plugin = class {
56
- pluggable;
58
+ host;
57
59
  /** @internal */
58
60
  [resolvedSpecSlot];
59
61
  /** @internal */
60
62
  [pluginContextSlot];
61
- constructor(pluggable, spec) {
62
- this.pluggable = pluggable;
63
+ /** Logs under the plugin's class name, on the channel its attach key names. */
64
+ logger;
65
+ constructor(host, spec) {
66
+ this.host = host;
67
+ this.logger = new _seedcord_logger.Logger(this.constructor.name);
63
68
  this[resolvedSpecSlot] = resolveLifecycleSpec(spec, this.constructor.name);
64
69
  }
70
+ /** The host, typed to the transport whose `Plugin` base this class extends. */
71
+ get core() {
72
+ return this.host;
73
+ }
65
74
  /** The framework surface, available from `init()` onward. Throws if read before `attach` finalizes it. */
66
75
  get ctx() {
67
76
  return readPluginContext(this);
@@ -111,4 +120,4 @@ Object.defineProperty(exports, 'resolvedLifecycleSpecOf', {
111
120
  return resolvedLifecycleSpecOf;
112
121
  }
113
122
  });
114
- //# sourceMappingURL=Plugin-C2-VHrsX.cjs.map
123
+ //# sourceMappingURL=Plugin-Cgp1a0uQ.cjs.map