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

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 (44) hide show
  1. package/dist/{AutocompleteOptions-eB87SZ4a.d.mts → AutocompleteOptions-eKhIe6Qt.d.mts} +9 -16
  2. package/dist/Plugin-C2-VHrsX.cjs +114 -0
  3. package/dist/Plugin-C2-VHrsX.cjs.map +1 -0
  4. package/dist/Plugin-CNyRKDHT.d.mts +226 -0
  5. package/dist/Plugin-PcdPjAzc.mjs +97 -0
  6. package/dist/Plugin-PcdPjAzc.mjs.map +1 -0
  7. package/dist/devChannel-CQU7hq7Q.mjs +14 -0
  8. package/dist/devChannel-CQU7hq7Q.mjs.map +1 -0
  9. package/dist/devChannel-CoCmAVDx.cjs +26 -0
  10. package/dist/devChannel-CoCmAVDx.cjs.map +1 -0
  11. package/dist/index.cjs +5 -2
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.mts +3 -2
  14. package/dist/index.mjs +4 -3
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/internal.index.cjs +7 -17
  17. package/dist/internal.index.cjs.map +1 -1
  18. package/dist/internal.index.d.mts +3 -2
  19. package/dist/internal.index.mjs +4 -15
  20. package/dist/internal.index.mjs.map +1 -1
  21. package/dist/node-internal.index.cjs +645 -0
  22. package/dist/node-internal.index.cjs.map +1 -0
  23. package/dist/node-internal.index.d.cts +1 -0
  24. package/dist/{node.index.d.mts → node-internal.index.d.mts} +104 -143
  25. package/dist/node-internal.index.mjs +636 -0
  26. package/dist/node-internal.index.mjs.map +1 -0
  27. package/dist/{permissions-DQL5ViZn.cjs → permissions-DSW_EZfN.cjs} +19 -1
  28. package/dist/{permissions-DQL5ViZn.cjs.map → permissions-DSW_EZfN.cjs.map} +1 -1
  29. package/dist/{permissions-SokZLJMj.mjs → permissions-RVCBhL2n.mjs} +14 -2
  30. package/dist/{permissions-SokZLJMj.mjs.map → permissions-RVCBhL2n.mjs.map} +1 -1
  31. package/dist/phases-BfpAG6w3.mjs +31 -0
  32. package/dist/phases-BfpAG6w3.mjs.map +1 -0
  33. package/dist/phases-C_BGNyVo.cjs +43 -0
  34. package/dist/phases-C_BGNyVo.cjs.map +1 -0
  35. package/dist/plugin.index.cjs +4 -0
  36. package/dist/plugin.index.d.cts +1 -0
  37. package/dist/plugin.index.d.mts +3 -0
  38. package/dist/plugin.index.mjs +3 -0
  39. package/package.json +24 -13
  40. package/dist/node.index.cjs +0 -521
  41. package/dist/node.index.cjs.map +0 -1
  42. package/dist/node.index.d.cts +0 -1
  43. package/dist/node.index.mjs +0 -513
  44. package/dist/node.index.mjs.map +0 -1
@@ -1,7 +1,8 @@
1
1
  import { t as IsNever } from "./is-never-Ddaba1Su.mjs";
2
+ import { f as CoreBase } from "./Plugin-CNyRKDHT.mjs";
2
3
  import { APIMessageTopLevelComponent, APIModalInteractionResponseCallbackData, ApplicationCommandType, ChannelType, Snowflake } from "discord-api-types/v10";
3
4
  import { ActionRowBuilder, ButtonBuilder, ChannelSelectMenuBuilder, CheckboxBuilder, CheckboxGroupBuilder, CheckboxGroupOptionBuilder, ContainerBuilder, ContextMenuCommandBuilder, EmbedBuilder, FileBuilder, FileUploadBuilder, LabelBuilder, MediaGalleryBuilder, MentionableSelectMenuBuilder, ModalBuilder, RadioGroupBuilder, RadioGroupOptionBuilder, RoleSelectMenuBuilder, SectionBuilder, SeparatorBuilder, SlashCommandBuilder, SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, TextDisplayBuilder, TextInputBuilder, UserSelectMenuBuilder } from "@discordjs/builders";
4
- import { Config, DeferOpts, IRateLimiter, RenderContext, ReplyResponse, SendOpts } from "@seedcord/types";
5
+ import { DeferOpts, RenderContext, ReplyResponse, SendOpts } from "@seedcord/types";
5
6
 
6
7
  //#region src/registries/SlashOptionRegistry.d.ts
7
8
  /** A slash option kind as a plain string union (`string`, `channel`, ...), keyed to the registry. */
@@ -422,24 +423,16 @@ declare enum SelectMenuKind {
422
423
  }
423
424
  type RoutableConstructor = new (...args: never[]) => unknown;
424
425
  declare function areRoutes(routes: unknown): routes is string[];
426
+ /**
427
+ * Every stored route kind and its route strings on a decorated constructor. The build's manifest
428
+ * emitter reads the same pairs.
429
+ */
430
+ declare function interactionRoutesOf(constructor: RoutableConstructor): [InteractionRoutes, string[]][];
425
431
  declare function storeInteractionRoute(route: InteractionRoutes, routes: string | readonly string[], constructor: RoutableConstructor): void;
426
432
  declare function storeComponentRoute(route: InteractionRoutes, defs: readonly AnyCustomId[], constructor: RoutableConstructor): void;
427
433
  declare function selectMenuRouteOf(kind: SelectMenuKind): InteractionRoutes;
428
434
  declare function contextMenuRouteOf(kind: ApplicationCommandType.User | ApplicationCommandType.Message): InteractionRoutes;
429
435
  //#endregion
430
- //#region src/interfaces/CoreBase.d.ts
431
- /**
432
- * The transport-agnostic slice of the running framework, what core code (gates, notices, plugins'
433
- * agnostic surface) accesses through `ctx.core`. Each transport's `Core` extends it, the gateway
434
- * adds `bot` and `bus`.
435
- */
436
- interface CoreBase {
437
- /** Transports narrow this to their own config type. */
438
- readonly config: Config;
439
- /** Sliding-window rate limiting, the `Cooldown` gate's backend and a public direct-use API. */
440
- readonly rateLimiter: IRateLimiter;
441
- }
442
- //#endregion
443
436
  //#region src/reply/AckTrace.d.ts
444
437
  /** The first ack's stack, passed as the throw cause so a double-ack points to both lines. */
445
438
  declare class AckTrace extends Error {
@@ -996,5 +989,5 @@ type Getter<Route extends keyof SlashOptionRegistry, Kind extends OptionKind, Me
996
989
  */
997
990
  type AutocompleteOptions<Route extends keyof SlashOptionRegistry> = Getter<Route, 'string', 'getString'> & Getter<Route, 'integer', 'getInteger'> & Getter<Route, 'number', 'getNumber'> & Getter<Route, 'boolean', 'getBoolean'>;
998
991
  //#endregion
999
- export { InteractionMetadataKey as $, serializeReply as A, contextMenuRouteOf as B, GuildPermissionsContext as C, BaseReplySender as D, defineGate as E, AckTrace as F, CustomId as G, storeComponentRoute as H, CoreBase as I, CustomIdField as J, decodeFor as K, RoutableConstructor as L, ReplyMethod as M, checkAckLegality as N, ModalLike as O, sendTarget as P, GatedMetadataKey as Q, SelectMenuKind as R, GateContextBase as S, defineEffectGate as T, storeInteractionRoute as U, selectMenuRouteOf as V, AnyCustomId as W, CommandMetadataKey as X, DecodedParams as Y, EventMetadataKey as Z, JoinNames as _, FocusedField as a, CommandMeta as at, EffectGate as b, RequireBotPermissions as c, BuilderComponent as ct, RequireRole as d, RowType as dt, InteractionRouteKeys as et, RequireRoleOptions as f, OptionKind as ft, IntersectRequired as g, GateFitsWith as h, EntryFor as i, WebhookUrlMetadataKey as it, AckState as j, SerializedReply as k, RequirePermissions as l, RowComponent as lt, pickNotice as m, SlashOptionRegistry as mt, AutocompleteOptions as n, MiddlewareMetadataKey as nt, PermissionNames as o, RegisterCommand as ot, GateNoticeOptions as p, SlashOption as pt, prefixOf as q, ChoiceValueOf as r, SubscribeMetadataKey as rt, PermissionScope as s, Constructor as st, AutocompletableNames as t, InteractionRoutes as tt, RequirePermissionsOptions as u, BuilderType as ut, TwoOrMore as v, RequiredOf as w, Gate as x, Notice as y, areRoutes as z };
1000
- //# sourceMappingURL=AutocompleteOptions-eB87SZ4a.d.mts.map
992
+ export { InteractionMetadataKey as $, serializeReply as A, interactionRoutesOf as B, GuildPermissionsContext as C, BaseReplySender as D, defineGate as E, AckTrace as F, CustomId as G, storeComponentRoute as H, RoutableConstructor as I, CustomIdField as J, decodeFor as K, SelectMenuKind as L, ReplyMethod as M, checkAckLegality as N, ModalLike as O, sendTarget as P, GatedMetadataKey as Q, areRoutes as R, GateContextBase as S, defineEffectGate as T, storeInteractionRoute as U, selectMenuRouteOf as V, AnyCustomId as W, CommandMetadataKey as X, DecodedParams as Y, EventMetadataKey as Z, JoinNames as _, FocusedField as a, CommandMeta as at, EffectGate as b, RequireBotPermissions as c, BuilderComponent as ct, RequireRole as d, RowType as dt, InteractionRouteKeys as et, RequireRoleOptions as f, OptionKind as ft, IntersectRequired as g, GateFitsWith as h, EntryFor as i, WebhookUrlMetadataKey as it, AckState as j, SerializedReply as k, RequirePermissions as l, RowComponent as lt, pickNotice as m, SlashOptionRegistry as mt, AutocompleteOptions as n, MiddlewareMetadataKey as nt, PermissionNames as o, RegisterCommand as ot, GateNoticeOptions as p, SlashOption as pt, prefixOf as q, ChoiceValueOf as r, SubscribeMetadataKey as rt, PermissionScope as s, Constructor as st, AutocompletableNames as t, InteractionRoutes as tt, RequirePermissionsOptions as u, BuilderType as ut, TwoOrMore as v, RequiredOf as w, Gate as x, Notice as y, contextMenuRouteOf as z };
993
+ //# sourceMappingURL=AutocompleteOptions-eKhIe6Qt.d.mts.map
@@ -0,0 +1,114 @@
1
+ const require_phases = require('./phases-C_BGNyVo.cjs');
2
+ const require_devChannel = require('./devChannel-CoCmAVDx.cjs');
3
+ let _seedcord_errors = require("@seedcord/errors");
4
+ let _seedcord_errors_internal = require("@seedcord/errors/internal");
5
+
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
+ //#region src/plugin/lifecycle.ts
22
+ const DEFAULT_INIT_TIMEOUT_MS = 15e3;
23
+ const DEFAULT_READY_TIMEOUT_MS = 15e3;
24
+ const DEFAULT_DISPOSE_TIMEOUT_MS = 1e4;
25
+ function timeoutOf(field, declared, fallback, pluginName) {
26
+ if (declared === void 0) return fallback;
27
+ if (!Number.isFinite(declared) || declared <= 0) throw new _seedcord_errors_internal.SeedcordError(_seedcord_errors.SeedcordErrorCode.PluginOptionsRejected, [pluginName, `lifecycle ${field}.timeout must be a positive number of milliseconds`]);
28
+ return declared;
29
+ }
30
+ /** @internal */
31
+ function resolveLifecycleSpec(spec, pluginName) {
32
+ return {
33
+ init: {
34
+ phase: spec?.init?.phase ?? 1,
35
+ timeout: timeoutOf("init", spec?.init?.timeout, DEFAULT_INIT_TIMEOUT_MS, pluginName)
36
+ },
37
+ ready: { timeout: timeoutOf("ready", spec?.ready?.timeout, DEFAULT_READY_TIMEOUT_MS, pluginName) },
38
+ dispose: {
39
+ phase: spec?.dispose?.phase ?? 3,
40
+ timeout: timeoutOf("dispose", spec?.dispose?.timeout, DEFAULT_DISPOSE_TIMEOUT_MS, pluginName)
41
+ }
42
+ };
43
+ }
44
+
45
+ //#endregion
46
+ //#region src/plugin/Plugin.ts
47
+ /** @internal */
48
+ const resolvedSpecSlot = Symbol("seedcord.plugin.spec");
49
+ /**
50
+ * 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`.
52
+ *
53
+ * @typeParam Opts - The plugin's declared {@link PluginOptions}.
54
+ */
55
+ var Plugin = class {
56
+ pluggable;
57
+ /** @internal */
58
+ [resolvedSpecSlot];
59
+ /** @internal */
60
+ [pluginContextSlot];
61
+ constructor(pluggable, spec) {
62
+ this.pluggable = pluggable;
63
+ this[resolvedSpecSlot] = resolveLifecycleSpec(spec, this.constructor.name);
64
+ }
65
+ /** The framework surface, available from `init()` onward. Throws if read before `attach` finalizes it. */
66
+ get ctx() {
67
+ return readPluginContext(this);
68
+ }
69
+ /**
70
+ * Rejects the plugin's constructor options with a reason. Throws a `SeedcordError` naming the
71
+ * plugin class and the reason.
72
+ *
73
+ * @param reason - Why the options are invalid.
74
+ */
75
+ rejectOptions(reason) {
76
+ throw new _seedcord_errors_internal.SeedcordError(_seedcord_errors.SeedcordErrorCode.PluginOptionsRejected, [this.constructor.name, reason]);
77
+ }
78
+ /** Override to reload plugin state on an HMR update. */
79
+ onHmr(_event) {
80
+ return Promise.resolve();
81
+ }
82
+ /**
83
+ * Registers critical file patterns that should trigger a full restart when changed in Dev HMR.
84
+ * @param patterns - Glob patterns relative to the project root
85
+ */
86
+ registerCriticalFiles(patterns) {
87
+ require_devChannel.getDevChannel()?.send("seedcord:register-critical-files", { patterns });
88
+ }
89
+ };
90
+ /** @internal */
91
+ function resolvedLifecycleSpecOf(plugin) {
92
+ return plugin[resolvedSpecSlot];
93
+ }
94
+
95
+ //#endregion
96
+ Object.defineProperty(exports, 'Plugin', {
97
+ enumerable: true,
98
+ get: function () {
99
+ return Plugin;
100
+ }
101
+ });
102
+ Object.defineProperty(exports, 'finalizePluginContext', {
103
+ enumerable: true,
104
+ get: function () {
105
+ return finalizePluginContext;
106
+ }
107
+ });
108
+ Object.defineProperty(exports, 'resolvedLifecycleSpecOf', {
109
+ enumerable: true,
110
+ get: function () {
111
+ return resolvedLifecycleSpecOf;
112
+ }
113
+ });
114
+ //# sourceMappingURL=Plugin-C2-VHrsX.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Plugin-C2-VHrsX.cjs","names":["SeedcordError","SeedcordErrorCode","SeedcordError","SeedcordErrorCode","SeedcordError","SeedcordErrorCode"],"sources":["../src/plugin/context.ts","../src/plugin/lifecycle.ts","../src/plugin/Plugin.ts"],"sourcesContent":["import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport type { PluginNeed } from './options';\nimport type { Logger } from '@seedcord/logger';\nimport type { Config, Store } from '@seedcord/types';\n\n/**\n * The type each `ctx` capability resolves to. Empty in core, each transport augments it through\n * declaration merging.\n *\n * @example\n * ```typescript\n * declare module '@seedcord/core' {\n * interface PluginCapabilityTypes {\n * client: Client;\n * rest: REST;\n * }\n * }\n * ```\n */\nexport interface PluginCapabilityTypes {}\n\ntype CapabilityType<Key extends PluginNeed, Fallback> = Key extends keyof PluginCapabilityTypes\n ? PluginCapabilityTypes[Key]\n : Fallback;\n\ntype CapabilityValue<TNeeds extends PluginNeed, Key extends PluginNeed, Value> = Key extends TNeeds ? Value : never;\n\n/**\n * The framework surface a plugin reads through `this.ctx`, typed by its declared `needs`.\n *\n * Always available: `logger`, `config`, `store`. Each capability resolves to its value only when\n * the plugin declared that key, otherwise `never`.\n *\n * @typeParam TNeeds - The plugin's declared `needs` union.\n */\nexport interface PluginContext<TNeeds extends PluginNeed = never> {\n readonly logger: Logger;\n readonly config: Config;\n readonly store: Store<'charge'>;\n readonly client: CapabilityValue<TNeeds, 'client', CapabilityType<'client', unknown>>;\n readonly token: CapabilityValue<TNeeds, 'token', string>;\n /**\n * The REST client. On http, the client has no token until the Ready phase, so a call from\n * `init()` sends without a token and returns a 401.\n */\n readonly rest: CapabilityValue<TNeeds, 'rest', CapabilityType<'rest', unknown>>;\n}\n\n// the conditional capability types make PluginContext<A> and PluginContext<B> mutually unassignable\n/** @internal */\nexport type StoredPluginContext = Pick<PluginContext, 'logger' | 'config' | 'store'> & {\n client?: unknown;\n token?: string | undefined;\n rest?: unknown;\n};\n\n/**\n * The capability arms a transport supplies from its own Bot/client. `attach` merges them into each\n * plugin's ctx.\n *\n * @internal\n */\nexport interface PluginCapabilities {\n readonly client?: unknown;\n readonly token?: string | undefined;\n readonly rest?: unknown;\n}\n\n/** @internal unset until attach installs the built ctx */\nexport const pluginContextSlot = Symbol('seedcord.plugin.ctx');\n\ninterface ContextHolder {\n [pluginContextSlot]?: StoredPluginContext;\n}\n\n/** @internal */\nexport function readPluginContext<TNeeds extends PluginNeed>(holder: ContextHolder): PluginContext<TNeeds> {\n const ctx = holder[pluginContextSlot];\n if (!ctx) throw new SeedcordError(SeedcordErrorCode.PluginContextBeforeInit, [holder.constructor.name]);\n // safe, finalizePluginContext set the ctx typed for this plugin's declared needs\n return ctx as PluginContext<TNeeds>;\n}\n\n/** @internal */\nexport function finalizePluginContext<TNeeds extends PluginNeed>(\n holder: ContextHolder,\n ctx: PluginContext<TNeeds>\n): void {\n holder[pluginContextSlot] = ctx;\n}\n","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';\n\nimport { getDevChannel } from '@hmr/devChannel';\n\nimport { pluginContextSlot, readPluginContext } from './context';\nimport { resolveLifecycleSpec } from './lifecycle';\n\nimport type { PluginContext, StoredPluginContext } from './context';\nimport type { ResolvedPluginLifecycleSpec, PluginLifecycleSpec } from './lifecycle';\nimport type { TransportOf, NeedsOf, PluginOptions, RuntimeOf } from './options';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { Logger } from '@seedcord/logger';\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.ctx`.\n *\n * @typeParam Opts - The plugin's declared {@link PluginOptions}.\n */\nexport abstract class Plugin<Opts extends PluginOptions = {}> implements Initializeable, HmrAware {\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 /** @internal */\n [pluginContextSlot]?: StoredPluginContext;\n\n public abstract logger: Logger;\n\n // subclasses redeclare the transport's own Core type on their constructor\n constructor(\n protected pluggable: CoreBase,\n spec?: PluginLifecycleSpec\n ) {\n this[resolvedSpecSlot] = resolveLifecycleSpec(spec, this.constructor.name);\n }\n\n /** The framework surface, available from `init()` onward. Throws if read before `attach` finalizes it. */\n protected get ctx(): PluginContext<NeedsOf<Opts>> {\n return readPluginContext<NeedsOf<Opts>>(this);\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 * Rejects the plugin's constructor options with a reason. Throws a `SeedcordError` naming the\n * plugin class 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: Plugin): ResolvedPluginLifecycleSpec {\n return plugin[resolvedSpecSlot];\n}\n\nexport type { PluginContext, PluginCapabilityTypes } from './context';\nexport type { PluginLifecycleSpec } from './lifecycle';\nexport type { PluginOptions } from './options';\n\n/**\n * Constructor type for plugins that can accept extra arguments after Core.\n *\n * The first parameter stays untyped here. Subclasses declare their transport's own `Core`, and a\n * `CoreBase` parameter would reject them (construct-signature params check contravariantly). The\n * `Plugin` base constructor carries the real contract, and attach call sites still infer the\n * concrete subclass tuple for the trailing args.\n *\n * @internal\n */\nexport type PluginCtor<TPlugin extends Plugin = Plugin> = new (...args: any[]) => TPlugin;\n\n/** @internal */\nexport type PluginArgs<Ctor extends PluginCtor> = Tail<ConstructorParameters<Ctor>>;\n\nexport { finalizePluginContext } from './context';\n"],"mappings":";;;;;;;AAuEA,MAAa,oBAAoB,OAAO,qBAAqB;;AAO7D,SAAgB,kBAA6C,QAA8C;CACvG,MAAM,MAAM,OAAO;CACnB,IAAI,CAAC,KAAK,MAAM,IAAIA,wCAAcC,mCAAkB,yBAAyB,CAAC,OAAO,YAAY,IAAI,CAAC;CAEtG,OAAO;AACX;;AAGA,SAAgB,sBACZ,QACA,KACI;CACJ,OAAO,qBAAqB;AAChC;;;;ACrEA,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,IAAIC,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;;;;;ACxCA,MAAM,mBAAmB,OAAO,sBAAsB;;;;;;;AAQtD,IAAsB,SAAtB,MAAkG;CAehF;;CARd,CAAU;;CAEV,CAAC;CAKD,YACI,AAAU,WACV,MACF;EAFY;EAGV,KAAK,oBAAoB,qBAAqB,MAAM,KAAK,YAAY,IAAI;CAC7E;;CAGA,IAAc,MAAoC;EAC9C,OAAO,kBAAiC,IAAI;CAChD;;;;;;;CAmBA,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,QAA6C;CACjF,OAAO,OAAO;AAClB"}
@@ -0,0 +1,226 @@
1
+ import { Logger } from "@seedcord/logger";
2
+ import { Config, HmrAware, HmrUpdateEvent, IRateLimiter, Store, Tail } from "@seedcord/types";
3
+
4
+ //#region src/interfaces/CoreBase.d.ts
5
+ /**
6
+ * The transport-agnostic slice of the running framework, what core code (gates, notices, plugins'
7
+ * agnostic surface) accesses through `ctx.core`. Each transport's `Core` extends it, the gateway
8
+ * adds `bot` and `bus`.
9
+ */
10
+ interface CoreBase {
11
+ /** Transports narrow this to their own config type. */
12
+ readonly config: Config;
13
+ /** Sliding-window rate limiting, the `Cooldown` gate's backend and a public direct-use API. */
14
+ readonly rateLimiter: IRateLimiter;
15
+ }
16
+ //#endregion
17
+ //#region src/plugin/options.d.ts
18
+ /** A capability a plugin declares through `needs`, each surfacing a typed `ctx` field. */
19
+ type PluginNeed = 'client' | 'token' | 'rest';
20
+ /**
21
+ * The options a plugin declares as its `Plugin<Opts>` type argument. Authors write unions for `needs`,
22
+ * e.g. `needs: 'token' | 'rest'`.
23
+ */
24
+ interface PluginOptions {
25
+ /**
26
+ * Which transport the plugin runs on.
27
+ * @defaultValue 'both'
28
+ */
29
+ transport?: 'gateway' | 'http' | 'both';
30
+ /**
31
+ * Which runtime the plugin runs on.
32
+ * @defaultValue 'both'
33
+ */
34
+ runtime?: 'server' | 'edge' | 'both';
35
+ /** Capabilities the plugin requests, each a typed `ctx` field. */
36
+ needs?: PluginNeed;
37
+ }
38
+ /** @internal */
39
+ type TransportOf<Opts extends PluginOptions> = undefined extends Opts['transport'] ? 'both' : NonNullable<Opts['transport']>;
40
+ /** @internal */
41
+ type RuntimeOf<Opts extends PluginOptions> = undefined extends Opts['runtime'] ? 'both' : NonNullable<Opts['runtime']>;
42
+ /** @internal */
43
+ type NeedsOf<Opts extends PluginOptions> = undefined extends Opts['needs'] ? never : NonNullable<Opts['needs']>;
44
+ //#endregion
45
+ //#region src/plugin/context.d.ts
46
+ /**
47
+ * The type each `ctx` capability resolves to. Empty in core, each transport augments it through
48
+ * declaration merging.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * declare module '@seedcord/core' {
53
+ * interface PluginCapabilityTypes {
54
+ * client: Client;
55
+ * rest: REST;
56
+ * }
57
+ * }
58
+ * ```
59
+ */
60
+ interface PluginCapabilityTypes {}
61
+ type CapabilityType<Key extends PluginNeed, Fallback> = Key extends keyof PluginCapabilityTypes ? PluginCapabilityTypes[Key] : Fallback;
62
+ type CapabilityValue<TNeeds extends PluginNeed, Key extends PluginNeed, Value> = Key extends TNeeds ? Value : never;
63
+ /**
64
+ * The framework surface a plugin reads through `this.ctx`, typed by its declared `needs`.
65
+ *
66
+ * Always available: `logger`, `config`, `store`. Each capability resolves to its value only when
67
+ * the plugin declared that key, otherwise `never`.
68
+ *
69
+ * @typeParam TNeeds - The plugin's declared `needs` union.
70
+ */
71
+ interface PluginContext<TNeeds extends PluginNeed = never> {
72
+ readonly logger: Logger;
73
+ readonly config: Config;
74
+ readonly store: Store<'charge'>;
75
+ readonly client: CapabilityValue<TNeeds, 'client', CapabilityType<'client', unknown>>;
76
+ readonly token: CapabilityValue<TNeeds, 'token', string>;
77
+ /**
78
+ * The REST client. On http, the client has no token until the Ready phase, so a call from
79
+ * `init()` sends without a token and returns a 401.
80
+ */
81
+ readonly rest: CapabilityValue<TNeeds, 'rest', CapabilityType<'rest', unknown>>;
82
+ }
83
+ /** @internal */
84
+ type StoredPluginContext = Pick<PluginContext, 'logger' | 'config' | 'store'> & {
85
+ client?: unknown;
86
+ token?: string | undefined;
87
+ rest?: unknown;
88
+ };
89
+ /**
90
+ * The capability arms a transport supplies from its own Bot/client. `attach` merges them into each
91
+ * plugin's ctx.
92
+ *
93
+ * @internal
94
+ */
95
+ interface PluginCapabilities {
96
+ readonly client?: unknown;
97
+ readonly token?: string | undefined;
98
+ readonly rest?: unknown;
99
+ }
100
+ /** @internal unset until attach installs the built ctx */
101
+ declare const pluginContextSlot: unique symbol;
102
+ //#endregion
103
+ //#region src/lifecycle/phases.d.ts
104
+ /**
105
+ * Startup phases, in run order.
106
+ */
107
+ declare enum StartupPhase {
108
+ /** Nothing connected. Plugin init runs here by default. */
109
+ Configuration = 1,
110
+ /** The gateway session opens. Empty on http. */
111
+ Login = 2,
112
+ /** Handlers are live and interactions dispatch. */
113
+ Ready = 3
114
+ }
115
+ /**
116
+ * Shutdown phases, in run order.
117
+ */
118
+ declare enum ShutdownPhase {
119
+ /** Stop taking new interactions and requests. */
120
+ Unbind = 1,
121
+ /** Waits for in-flight work to settle and stops internal services. */
122
+ Drain = 2,
123
+ /** External resources close. Plugin dispose runs here by default. */
124
+ Disconnect = 3,
125
+ /** The client disconnects last so in-flight handlers can still reference it during drain. */
126
+ Logout = 4
127
+ }
128
+ //#endregion
129
+ //#region src/plugin/lifecycle.d.ts
130
+ /**
131
+ * The lifecycle a plugin declares through `super(host, spec)`. Unset fields resolve to the base
132
+ * defaults. `ready` runs at a fixed `StartupPhase.Ready`, so it takes only a timeout.
133
+ */
134
+ interface PluginLifecycleSpec {
135
+ init?: {
136
+ phase?: StartupPhase;
137
+ timeout?: number;
138
+ };
139
+ ready?: {
140
+ timeout?: number;
141
+ };
142
+ dispose?: {
143
+ phase?: ShutdownPhase;
144
+ timeout?: number;
145
+ };
146
+ }
147
+ /** @internal */
148
+ interface ResolvedPluginLifecycleSpec {
149
+ readonly init: {
150
+ readonly phase: StartupPhase;
151
+ readonly timeout: number;
152
+ };
153
+ readonly ready: {
154
+ readonly timeout: number;
155
+ };
156
+ readonly dispose: {
157
+ readonly phase: ShutdownPhase;
158
+ readonly timeout: number;
159
+ };
160
+ }
161
+ //#endregion
162
+ //#region src/plugin/Plugin.d.ts
163
+ interface Initializeable {
164
+ init(): Promise<void>;
165
+ }
166
+ /** @internal */
167
+ declare const resolvedSpecSlot: unique symbol;
168
+ /**
169
+ * Base class for Seedcord plugins. A subclass declares its options as the `Opts` type argument,
170
+ * implements `init()`, and reads the framework surface through `this.ctx`.
171
+ *
172
+ * @typeParam Opts - The plugin's declared {@link PluginOptions}.
173
+ */
174
+ declare abstract class Plugin<Opts extends PluginOptions = {}> implements Initializeable, HmrAware {
175
+ protected pluggable: CoreBase;
176
+ /** @internal phantom, never set at runtime */
177
+ readonly __transport?: TransportOf<Opts>;
178
+ /** @internal phantom, never set at runtime */
179
+ readonly __runtime?: RuntimeOf<Opts>;
180
+ /** @internal */
181
+ readonly [resolvedSpecSlot]: ResolvedPluginLifecycleSpec;
182
+ /** @internal */
183
+ [pluginContextSlot]?: StoredPluginContext;
184
+ abstract logger: Logger;
185
+ constructor(pluggable: CoreBase, spec?: PluginLifecycleSpec);
186
+ /** The framework surface, available from `init()` onward. Throws if read before `attach` finalizes it. */
187
+ protected get ctx(): PluginContext<NeedsOf<Opts>>;
188
+ abstract init(): Promise<void>;
189
+ /**
190
+ * Runs in the startup Ready phase, after `init()`. The gateway client is logged in by this phase,
191
+ * and the http host runs its server-bind and health tasks in the same phase.
192
+ */
193
+ ready?(): Promise<void>;
194
+ /** Runs during teardown, only when `init()` resolved. */
195
+ dispose?(): Promise<void>;
196
+ /**
197
+ * Rejects the plugin's constructor options with a reason. Throws a `SeedcordError` naming the
198
+ * plugin class and the reason.
199
+ *
200
+ * @param reason - Why the options are invalid.
201
+ */
202
+ protected rejectOptions(reason: string): never;
203
+ /** Override to reload plugin state on an HMR update. */
204
+ onHmr(_event: HmrUpdateEvent): Promise<void>;
205
+ /**
206
+ * Registers critical file patterns that should trigger a full restart when changed in Dev HMR.
207
+ * @param patterns - Glob patterns relative to the project root
208
+ */
209
+ protected registerCriticalFiles(patterns: string[]): void;
210
+ }
211
+ /**
212
+ * Constructor type for plugins that can accept extra arguments after Core.
213
+ *
214
+ * The first parameter stays untyped here. Subclasses declare their transport's own `Core`, and a
215
+ * `CoreBase` parameter would reject them (construct-signature params check contravariantly). The
216
+ * `Plugin` base constructor carries the real contract, and attach call sites still infer the
217
+ * concrete subclass tuple for the trailing args.
218
+ *
219
+ * @internal
220
+ */
221
+ type PluginCtor<TPlugin extends Plugin = Plugin> = new (...args: any[]) => TPlugin;
222
+ /** @internal */
223
+ type PluginArgs<Ctor extends PluginCtor> = Tail<ConstructorParameters<Ctor>>;
224
+ //#endregion
225
+ export { PluginLifecycleSpec as a, PluginCapabilities as c, PluginOptions as d, CoreBase as f, PluginCtor as i, PluginCapabilityTypes as l, Plugin as n, ShutdownPhase as o, PluginArgs as r, StartupPhase as s, Initializeable as t, PluginContext as u };
226
+ //# sourceMappingURL=Plugin-CNyRKDHT.d.mts.map
@@ -0,0 +1,97 @@
1
+ import { n as StartupPhase, t as ShutdownPhase } from "./phases-BfpAG6w3.mjs";
2
+ import { t as getDevChannel } from "./devChannel-CQU7hq7Q.mjs";
3
+ import { SeedcordErrorCode } from "@seedcord/errors";
4
+ import { SeedcordError } from "@seedcord/errors/internal";
5
+
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 SeedcordError(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
+ //#region src/plugin/lifecycle.ts
22
+ const DEFAULT_INIT_TIMEOUT_MS = 15e3;
23
+ const DEFAULT_READY_TIMEOUT_MS = 15e3;
24
+ const DEFAULT_DISPOSE_TIMEOUT_MS = 1e4;
25
+ function timeoutOf(field, declared, fallback, pluginName) {
26
+ if (declared === void 0) return fallback;
27
+ if (!Number.isFinite(declared) || declared <= 0) throw new SeedcordError(SeedcordErrorCode.PluginOptionsRejected, [pluginName, `lifecycle ${field}.timeout must be a positive number of milliseconds`]);
28
+ return declared;
29
+ }
30
+ /** @internal */
31
+ function resolveLifecycleSpec(spec, pluginName) {
32
+ return {
33
+ init: {
34
+ phase: spec?.init?.phase ?? 1,
35
+ timeout: timeoutOf("init", spec?.init?.timeout, DEFAULT_INIT_TIMEOUT_MS, pluginName)
36
+ },
37
+ ready: { timeout: timeoutOf("ready", spec?.ready?.timeout, DEFAULT_READY_TIMEOUT_MS, pluginName) },
38
+ dispose: {
39
+ phase: spec?.dispose?.phase ?? 3,
40
+ timeout: timeoutOf("dispose", spec?.dispose?.timeout, DEFAULT_DISPOSE_TIMEOUT_MS, pluginName)
41
+ }
42
+ };
43
+ }
44
+
45
+ //#endregion
46
+ //#region src/plugin/Plugin.ts
47
+ /** @internal */
48
+ const resolvedSpecSlot = Symbol("seedcord.plugin.spec");
49
+ /**
50
+ * 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`.
52
+ *
53
+ * @typeParam Opts - The plugin's declared {@link PluginOptions}.
54
+ */
55
+ var Plugin = class {
56
+ pluggable;
57
+ /** @internal */
58
+ [resolvedSpecSlot];
59
+ /** @internal */
60
+ [pluginContextSlot];
61
+ constructor(pluggable, spec) {
62
+ this.pluggable = pluggable;
63
+ this[resolvedSpecSlot] = resolveLifecycleSpec(spec, this.constructor.name);
64
+ }
65
+ /** The framework surface, available from `init()` onward. Throws if read before `attach` finalizes it. */
66
+ get ctx() {
67
+ return readPluginContext(this);
68
+ }
69
+ /**
70
+ * Rejects the plugin's constructor options with a reason. Throws a `SeedcordError` naming the
71
+ * plugin class and the reason.
72
+ *
73
+ * @param reason - Why the options are invalid.
74
+ */
75
+ rejectOptions(reason) {
76
+ throw new SeedcordError(SeedcordErrorCode.PluginOptionsRejected, [this.constructor.name, reason]);
77
+ }
78
+ /** Override to reload plugin state on an HMR update. */
79
+ onHmr(_event) {
80
+ return Promise.resolve();
81
+ }
82
+ /**
83
+ * Registers critical file patterns that should trigger a full restart when changed in Dev HMR.
84
+ * @param patterns - Glob patterns relative to the project root
85
+ */
86
+ registerCriticalFiles(patterns) {
87
+ getDevChannel()?.send("seedcord:register-critical-files", { patterns });
88
+ }
89
+ };
90
+ /** @internal */
91
+ function resolvedLifecycleSpecOf(plugin) {
92
+ return plugin[resolvedSpecSlot];
93
+ }
94
+
95
+ //#endregion
96
+ export { resolvedLifecycleSpecOf as n, finalizePluginContext as r, Plugin as t };
97
+ //# sourceMappingURL=Plugin-PcdPjAzc.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Plugin-PcdPjAzc.mjs","names":[],"sources":["../src/plugin/context.ts","../src/plugin/lifecycle.ts","../src/plugin/Plugin.ts"],"sourcesContent":["import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport type { PluginNeed } from './options';\nimport type { Logger } from '@seedcord/logger';\nimport type { Config, Store } from '@seedcord/types';\n\n/**\n * The type each `ctx` capability resolves to. Empty in core, each transport augments it through\n * declaration merging.\n *\n * @example\n * ```typescript\n * declare module '@seedcord/core' {\n * interface PluginCapabilityTypes {\n * client: Client;\n * rest: REST;\n * }\n * }\n * ```\n */\nexport interface PluginCapabilityTypes {}\n\ntype CapabilityType<Key extends PluginNeed, Fallback> = Key extends keyof PluginCapabilityTypes\n ? PluginCapabilityTypes[Key]\n : Fallback;\n\ntype CapabilityValue<TNeeds extends PluginNeed, Key extends PluginNeed, Value> = Key extends TNeeds ? Value : never;\n\n/**\n * The framework surface a plugin reads through `this.ctx`, typed by its declared `needs`.\n *\n * Always available: `logger`, `config`, `store`. Each capability resolves to its value only when\n * the plugin declared that key, otherwise `never`.\n *\n * @typeParam TNeeds - The plugin's declared `needs` union.\n */\nexport interface PluginContext<TNeeds extends PluginNeed = never> {\n readonly logger: Logger;\n readonly config: Config;\n readonly store: Store<'charge'>;\n readonly client: CapabilityValue<TNeeds, 'client', CapabilityType<'client', unknown>>;\n readonly token: CapabilityValue<TNeeds, 'token', string>;\n /**\n * The REST client. On http, the client has no token until the Ready phase, so a call from\n * `init()` sends without a token and returns a 401.\n */\n readonly rest: CapabilityValue<TNeeds, 'rest', CapabilityType<'rest', unknown>>;\n}\n\n// the conditional capability types make PluginContext<A> and PluginContext<B> mutually unassignable\n/** @internal */\nexport type StoredPluginContext = Pick<PluginContext, 'logger' | 'config' | 'store'> & {\n client?: unknown;\n token?: string | undefined;\n rest?: unknown;\n};\n\n/**\n * The capability arms a transport supplies from its own Bot/client. `attach` merges them into each\n * plugin's ctx.\n *\n * @internal\n */\nexport interface PluginCapabilities {\n readonly client?: unknown;\n readonly token?: string | undefined;\n readonly rest?: unknown;\n}\n\n/** @internal unset until attach installs the built ctx */\nexport const pluginContextSlot = Symbol('seedcord.plugin.ctx');\n\ninterface ContextHolder {\n [pluginContextSlot]?: StoredPluginContext;\n}\n\n/** @internal */\nexport function readPluginContext<TNeeds extends PluginNeed>(holder: ContextHolder): PluginContext<TNeeds> {\n const ctx = holder[pluginContextSlot];\n if (!ctx) throw new SeedcordError(SeedcordErrorCode.PluginContextBeforeInit, [holder.constructor.name]);\n // safe, finalizePluginContext set the ctx typed for this plugin's declared needs\n return ctx as PluginContext<TNeeds>;\n}\n\n/** @internal */\nexport function finalizePluginContext<TNeeds extends PluginNeed>(\n holder: ContextHolder,\n ctx: PluginContext<TNeeds>\n): void {\n holder[pluginContextSlot] = ctx;\n}\n","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';\n\nimport { getDevChannel } from '@hmr/devChannel';\n\nimport { pluginContextSlot, readPluginContext } from './context';\nimport { resolveLifecycleSpec } from './lifecycle';\n\nimport type { PluginContext, StoredPluginContext } from './context';\nimport type { ResolvedPluginLifecycleSpec, PluginLifecycleSpec } from './lifecycle';\nimport type { TransportOf, NeedsOf, PluginOptions, RuntimeOf } from './options';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { Logger } from '@seedcord/logger';\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.ctx`.\n *\n * @typeParam Opts - The plugin's declared {@link PluginOptions}.\n */\nexport abstract class Plugin<Opts extends PluginOptions = {}> implements Initializeable, HmrAware {\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 /** @internal */\n [pluginContextSlot]?: StoredPluginContext;\n\n public abstract logger: Logger;\n\n // subclasses redeclare the transport's own Core type on their constructor\n constructor(\n protected pluggable: CoreBase,\n spec?: PluginLifecycleSpec\n ) {\n this[resolvedSpecSlot] = resolveLifecycleSpec(spec, this.constructor.name);\n }\n\n /** The framework surface, available from `init()` onward. Throws if read before `attach` finalizes it. */\n protected get ctx(): PluginContext<NeedsOf<Opts>> {\n return readPluginContext<NeedsOf<Opts>>(this);\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 * Rejects the plugin's constructor options with a reason. Throws a `SeedcordError` naming the\n * plugin class 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: Plugin): ResolvedPluginLifecycleSpec {\n return plugin[resolvedSpecSlot];\n}\n\nexport type { PluginContext, PluginCapabilityTypes } from './context';\nexport type { PluginLifecycleSpec } from './lifecycle';\nexport type { PluginOptions } from './options';\n\n/**\n * Constructor type for plugins that can accept extra arguments after Core.\n *\n * The first parameter stays untyped here. Subclasses declare their transport's own `Core`, and a\n * `CoreBase` parameter would reject them (construct-signature params check contravariantly). The\n * `Plugin` base constructor carries the real contract, and attach call sites still infer the\n * concrete subclass tuple for the trailing args.\n *\n * @internal\n */\nexport type PluginCtor<TPlugin extends Plugin = Plugin> = new (...args: any[]) => TPlugin;\n\n/** @internal */\nexport type PluginArgs<Ctor extends PluginCtor> = Tail<ConstructorParameters<Ctor>>;\n\nexport { finalizePluginContext } from './context';\n"],"mappings":";;;;;;;AAuEA,MAAa,oBAAoB,OAAO,qBAAqB;;AAO7D,SAAgB,kBAA6C,QAA8C;CACvG,MAAM,MAAM,OAAO;CACnB,IAAI,CAAC,KAAK,MAAM,IAAI,cAAc,kBAAkB,yBAAyB,CAAC,OAAO,YAAY,IAAI,CAAC;CAEtG,OAAO;AACX;;AAGA,SAAgB,sBACZ,QACA,KACI;CACJ,OAAO,qBAAqB;AAChC;;;;ACrEA,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,IAAI,cAAc,kBAAkB,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;;;;;ACxCA,MAAM,mBAAmB,OAAO,sBAAsB;;;;;;;AAQtD,IAAsB,SAAtB,MAAkG;CAehF;;CARd,CAAU;;CAEV,CAAC;CAKD,YACI,AAAU,WACV,MACF;EAFY;EAGV,KAAK,oBAAoB,qBAAqB,MAAM,KAAK,YAAY,IAAI;CAC7E;;CAGA,IAAc,MAAoC;EAC9C,OAAO,kBAAiC,IAAI;CAChD;;;;;;;CAmBA,AAAU,cAAc,QAAuB;EAC3C,MAAM,IAAI,cAAc,kBAAkB,uBAAuB,CAAC,KAAK,YAAY,MAAM,MAAM,CAAC;CACpG;;CAGA,AAAO,MAAM,QAAuC;EAChD,OAAO,QAAQ,QAAQ;CAC3B;;;;;CAMA,AAAU,sBAAsB,UAA0B;EACtD,cAAc,CAAC,EAAE,KAAK,oCAAoC,EAAE,SAAS,CAAC;CAC1E;AACJ;;AAGA,SAAgB,wBAAwB,QAA6C;CACjF,OAAO,OAAO;AAClB"}
@@ -0,0 +1,14 @@
1
+ //#region src/hmr/devChannel.ts
2
+ let channel;
3
+ /** @internal */
4
+ function setDevChannel(next) {
5
+ channel = next;
6
+ }
7
+ /** @internal */
8
+ function getDevChannel() {
9
+ return channel;
10
+ }
11
+
12
+ //#endregion
13
+ export { setDevChannel as n, getDevChannel as t };
14
+ //# sourceMappingURL=devChannel-CQU7hq7Q.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devChannel-CQU7hq7Q.mjs","names":[],"sources":["../src/hmr/devChannel.ts"],"sourcesContent":["import type { DevChannel, SeedcordCliEvents, SeedcordFrameworkEvents } from '@seedcord/types/internal';\n\n// one module instance per process, the HmrManager write and every framework read share it\nlet channel: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined;\n\n/** @internal */\nexport function setDevChannel(next: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined): void {\n channel = next;\n}\n\n/** @internal */\nexport function getDevChannel(): DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined {\n return channel;\n}\n"],"mappings":";AAGA,IAAI;;AAGJ,SAAgB,cAAc,MAAgF;CAC1G,UAAU;AACd;;AAGA,SAAgB,gBAAoF;CAChG,OAAO;AACX"}
@@ -0,0 +1,26 @@
1
+
2
+ //#region src/hmr/devChannel.ts
3
+ let channel;
4
+ /** @internal */
5
+ function setDevChannel(next) {
6
+ channel = next;
7
+ }
8
+ /** @internal */
9
+ function getDevChannel() {
10
+ return channel;
11
+ }
12
+
13
+ //#endregion
14
+ Object.defineProperty(exports, 'getDevChannel', {
15
+ enumerable: true,
16
+ get: function () {
17
+ return getDevChannel;
18
+ }
19
+ });
20
+ Object.defineProperty(exports, 'setDevChannel', {
21
+ enumerable: true,
22
+ get: function () {
23
+ return setDevChannel;
24
+ }
25
+ });
26
+ //# sourceMappingURL=devChannel-CoCmAVDx.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devChannel-CoCmAVDx.cjs","names":[],"sources":["../src/hmr/devChannel.ts"],"sourcesContent":["import type { DevChannel, SeedcordCliEvents, SeedcordFrameworkEvents } from '@seedcord/types/internal';\n\n// one module instance per process, the HmrManager write and every framework read share it\nlet channel: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined;\n\n/** @internal */\nexport function setDevChannel(next: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined): void {\n channel = next;\n}\n\n/** @internal */\nexport function getDevChannel(): DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents> | undefined {\n return channel;\n}\n"],"mappings":";;AAGA,IAAI;;AAGJ,SAAgB,cAAc,MAAgF;CAC1G,UAAU;AACd;;AAGA,SAAgB,gBAAoF;CAChG,OAAO;AACX"}
package/dist/index.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_permissions = require('./permissions-DQL5ViZn.cjs');
2
+ const require_permissions = require('./permissions-DSW_EZfN.cjs');
3
+ const require_phases = require('./phases-C_BGNyVo.cjs');
3
4
  require("reflect-metadata");
4
5
  let _seedcord_errors = require("@seedcord/errors");
5
6
  let _seedcord_errors_internal = require("@seedcord/errors/internal");
@@ -551,7 +552,7 @@ function paginate(items, page, perPage) {
551
552
  //#endregion
552
553
  //#region src/index.ts
553
554
  /** Package version */
554
- const version = "0.1.0-next.5";
555
+ const version = "0.1.0-next.6";
555
556
 
556
557
  //#endregion
557
558
  exports.AutocompleteRoute = AutocompleteRoute;
@@ -576,8 +577,10 @@ exports.RequireRole = require_permissions.RequireRole;
576
577
  exports.RowComponent = require_permissions.RowComponent;
577
578
  exports.SelectMenuKind = require_permissions.SelectMenuKind;
578
579
  exports.SelectMenuRoute = SelectMenuRoute;
580
+ exports.ShutdownPhase = require_phases.ShutdownPhase;
579
581
  exports.Silence = Silence;
580
582
  exports.SlashRoute = SlashRoute;
583
+ exports.StartupPhase = require_phases.StartupPhase;
581
584
  exports.and = and;
582
585
  exports.defineEffectGate = require_permissions.defineEffectGate;
583
586
  exports.defineGate = require_permissions.defineGate;