@seedcord/core 0.1.0-next.4 → 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.
- package/dist/{CustomId--QizzBOn.d.mts → AutocompleteOptions-eKhIe6Qt.d.mts} +496 -163
- package/dist/Plugin-C2-VHrsX.cjs +114 -0
- package/dist/Plugin-C2-VHrsX.cjs.map +1 -0
- package/dist/Plugin-CNyRKDHT.d.mts +226 -0
- package/dist/Plugin-PcdPjAzc.mjs +97 -0
- package/dist/Plugin-PcdPjAzc.mjs.map +1 -0
- package/dist/devChannel-CQU7hq7Q.mjs +14 -0
- package/dist/devChannel-CQU7hq7Q.mjs.map +1 -0
- package/dist/devChannel-CoCmAVDx.cjs +26 -0
- package/dist/devChannel-CoCmAVDx.cjs.map +1 -0
- package/dist/index.cjs +239 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +182 -25
- package/dist/index.mjs +199 -79
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.cjs +463 -57
- package/dist/internal.index.cjs.map +1 -1
- package/dist/internal.index.d.mts +146 -28
- package/dist/internal.index.mjs +415 -29
- package/dist/internal.index.mjs.map +1 -1
- package/dist/is-never-Ddaba1Su.d.mts +58 -0
- package/dist/node-internal.index.cjs +645 -0
- package/dist/node-internal.index.cjs.map +1 -0
- package/dist/node-internal.index.d.cts +1 -0
- package/dist/node-internal.index.d.mts +2352 -0
- package/dist/node-internal.index.mjs +636 -0
- package/dist/node-internal.index.mjs.map +1 -0
- package/dist/{CustomId-DV7daU7r.cjs → permissions-DSW_EZfN.cjs} +448 -89
- package/dist/permissions-DSW_EZfN.cjs.map +1 -0
- package/dist/{CustomId-epJayEGO.mjs → permissions-RVCBhL2n.mjs} +341 -90
- package/dist/permissions-RVCBhL2n.mjs.map +1 -0
- package/dist/phases-BfpAG6w3.mjs +31 -0
- package/dist/phases-BfpAG6w3.mjs.map +1 -0
- package/dist/phases-C_BGNyVo.cjs +43 -0
- package/dist/phases-C_BGNyVo.cjs.map +1 -0
- package/dist/plugin.index.cjs +4 -0
- package/dist/plugin.index.d.cts +1 -0
- package/dist/plugin.index.d.mts +3 -0
- package/dist/plugin.index.mjs +3 -0
- package/package.json +32 -10
- package/dist/CustomId-DV7daU7r.cjs.map +0 -1
- package/dist/CustomId-epJayEGO.mjs.map +0 -1
|
@@ -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"}
|