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

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