@seedcord/core 0.1.0-next.5 → 0.1.0-next.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AutocompleteOptions-eB87SZ4a.d.mts → AutocompleteOptions-DLp_B8as.d.mts} +66 -124
- package/dist/HmrModuleHandler-3sNgKHdf.mjs +163 -0
- package/dist/HmrModuleHandler-3sNgKHdf.mjs.map +1 -0
- package/dist/HmrModuleHandler-CTBng7wV.cjs +170 -0
- package/dist/HmrModuleHandler-CTBng7wV.cjs.map +1 -0
- package/dist/Plugin-3rlH0uxH.d.mts +620 -0
- package/dist/Plugin-Cgp1a0uQ.cjs +123 -0
- package/dist/Plugin-Cgp1a0uQ.cjs.map +1 -0
- package/dist/Plugin-j9GYdroS.mjs +106 -0
- package/dist/Plugin-j9GYdroS.mjs.map +1 -0
- package/dist/{permissions-DQL5ViZn.cjs → Silence-DiP95iwD.cjs} +54 -305
- package/dist/Silence-DiP95iwD.cjs.map +1 -0
- package/dist/{permissions-SokZLJMj.mjs → Silence-dbC2slOB.mjs} +47 -238
- package/dist/Silence-dbC2slOB.mjs.map +1 -0
- package/dist/basic-D7bDlgSP.d.mts +10 -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/hmr.index.cjs +2 -164
- package/dist/hmr.index.mjs +2 -162
- package/dist/index-Dueqztyy.d.mts +142 -0
- package/dist/index.cjs +53 -72
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +7 -4
- package/dist/index.mjs +9 -35
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.cjs +267 -89
- package/dist/internal.index.cjs.map +1 -1
- package/dist/internal.index.d.mts +68 -3
- package/dist/internal.index.mjs +218 -48
- package/dist/internal.index.mjs.map +1 -1
- package/dist/node-internal.index.cjs +716 -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 +261 -0
- package/dist/node-internal.index.mjs +706 -0
- package/dist/node-internal.index.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/dist/publishDefault-CCf1azzW.mjs +264 -0
- package/dist/publishDefault-CCf1azzW.mjs.map +1 -0
- package/dist/publishDefault-l0NQ-SHo.cjs +353 -0
- package/dist/publishDefault-l0NQ-SHo.cjs.map +1 -0
- package/dist/subscribers-B1G6_LlK.cjs +517 -0
- package/dist/subscribers-B1G6_LlK.cjs.map +1 -0
- package/dist/subscribers-DYqFVP1X.mjs +480 -0
- package/dist/subscribers-DYqFVP1X.mjs.map +1 -0
- package/package.json +25 -13
- package/dist/hmr.index.cjs.map +0 -1
- package/dist/hmr.index.mjs.map +0 -1
- package/dist/is-never-Ddaba1Su.d.mts +0 -58
- package/dist/node.index.cjs +0 -521
- package/dist/node.index.cjs.map +0 -1
- package/dist/node.index.d.cts +0 -1
- package/dist/node.index.d.mts +0 -2391
- package/dist/node.index.mjs +0 -513
- package/dist/node.index.mjs.map +0 -1
- package/dist/permissions-DQL5ViZn.cjs.map +0 -1
- package/dist/permissions-SokZLJMj.mjs.map +0 -1
|
@@ -0,0 +1,123 @@
|
|
|
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
|
+
let _seedcord_logger = require("@seedcord/logger");
|
|
6
|
+
|
|
7
|
+
//#region src/plugin/context.ts
|
|
8
|
+
/** @internal unset until attach installs the built ctx */
|
|
9
|
+
const pluginContextSlot = Symbol("seedcord.plugin.ctx");
|
|
10
|
+
/** @internal */
|
|
11
|
+
function readPluginContext(holder) {
|
|
12
|
+
const ctx = holder[pluginContextSlot];
|
|
13
|
+
if (!ctx) throw new _seedcord_errors_internal.SeedcordError(_seedcord_errors.SeedcordErrorCode.PluginContextBeforeInit, [holder.constructor.name]);
|
|
14
|
+
return ctx;
|
|
15
|
+
}
|
|
16
|
+
/** @internal */
|
|
17
|
+
function finalizePluginContext(holder, ctx) {
|
|
18
|
+
holder[pluginContextSlot] = ctx;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/plugin/lifecycle.ts
|
|
23
|
+
const DEFAULT_INIT_TIMEOUT_MS = 15e3;
|
|
24
|
+
const DEFAULT_READY_TIMEOUT_MS = 15e3;
|
|
25
|
+
const DEFAULT_DISPOSE_TIMEOUT_MS = 1e4;
|
|
26
|
+
function timeoutOf(field, declared, fallback, pluginName) {
|
|
27
|
+
if (declared === void 0) return fallback;
|
|
28
|
+
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`]);
|
|
29
|
+
return declared;
|
|
30
|
+
}
|
|
31
|
+
/** @internal */
|
|
32
|
+
function resolveLifecycleSpec(spec, pluginName) {
|
|
33
|
+
return {
|
|
34
|
+
init: {
|
|
35
|
+
phase: spec?.init?.phase ?? 1,
|
|
36
|
+
timeout: timeoutOf("init", spec?.init?.timeout, DEFAULT_INIT_TIMEOUT_MS, pluginName)
|
|
37
|
+
},
|
|
38
|
+
ready: { timeout: timeoutOf("ready", spec?.ready?.timeout, DEFAULT_READY_TIMEOUT_MS, pluginName) },
|
|
39
|
+
dispose: {
|
|
40
|
+
phase: spec?.dispose?.phase ?? 3,
|
|
41
|
+
timeout: timeoutOf("dispose", spec?.dispose?.timeout, DEFAULT_DISPOSE_TIMEOUT_MS, pluginName)
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/plugin/Plugin.ts
|
|
48
|
+
/** @internal */
|
|
49
|
+
const resolvedSpecSlot = Symbol("seedcord.plugin.spec");
|
|
50
|
+
/**
|
|
51
|
+
* Base class for Seedcord plugins. A subclass declares its options as the `Opts` type argument,
|
|
52
|
+
* implements `init()`, and reads the framework surface through `this.ctx`.
|
|
53
|
+
*
|
|
54
|
+
* @typeParam Opts - The plugin's declared {@link PluginOptions}.
|
|
55
|
+
* @typeParam TCore - The host type `this.core` resolves to. Each transport binds it to its own `Core`.
|
|
56
|
+
*/
|
|
57
|
+
var Plugin = class {
|
|
58
|
+
host;
|
|
59
|
+
/** @internal */
|
|
60
|
+
[resolvedSpecSlot];
|
|
61
|
+
/** @internal */
|
|
62
|
+
[pluginContextSlot];
|
|
63
|
+
/** Logs under the plugin's class name, on the channel its attach key names. */
|
|
64
|
+
logger;
|
|
65
|
+
constructor(host, spec) {
|
|
66
|
+
this.host = host;
|
|
67
|
+
this.logger = new _seedcord_logger.Logger(this.constructor.name);
|
|
68
|
+
this[resolvedSpecSlot] = resolveLifecycleSpec(spec, this.constructor.name);
|
|
69
|
+
}
|
|
70
|
+
/** The host, typed to the transport whose `Plugin` base this class extends. */
|
|
71
|
+
get core() {
|
|
72
|
+
return this.host;
|
|
73
|
+
}
|
|
74
|
+
/** The framework surface, available from `init()` onward. Throws if read before `attach` finalizes it. */
|
|
75
|
+
get ctx() {
|
|
76
|
+
return readPluginContext(this);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Rejects the plugin's constructor options with a reason. Throws a `SeedcordError` naming the
|
|
80
|
+
* plugin class and the reason.
|
|
81
|
+
*
|
|
82
|
+
* @param reason - Why the options are invalid.
|
|
83
|
+
*/
|
|
84
|
+
rejectOptions(reason) {
|
|
85
|
+
throw new _seedcord_errors_internal.SeedcordError(_seedcord_errors.SeedcordErrorCode.PluginOptionsRejected, [this.constructor.name, reason]);
|
|
86
|
+
}
|
|
87
|
+
/** Override to reload plugin state on an HMR update. */
|
|
88
|
+
onHmr(_event) {
|
|
89
|
+
return Promise.resolve();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Registers critical file patterns that should trigger a full restart when changed in Dev HMR.
|
|
93
|
+
* @param patterns - Glob patterns relative to the project root
|
|
94
|
+
*/
|
|
95
|
+
registerCriticalFiles(patterns) {
|
|
96
|
+
require_devChannel.getDevChannel()?.send("seedcord:register-critical-files", { patterns });
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
/** @internal */
|
|
100
|
+
function resolvedLifecycleSpecOf(plugin) {
|
|
101
|
+
return plugin[resolvedSpecSlot];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
//#endregion
|
|
105
|
+
Object.defineProperty(exports, 'Plugin', {
|
|
106
|
+
enumerable: true,
|
|
107
|
+
get: function () {
|
|
108
|
+
return Plugin;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
Object.defineProperty(exports, 'finalizePluginContext', {
|
|
112
|
+
enumerable: true,
|
|
113
|
+
get: function () {
|
|
114
|
+
return finalizePluginContext;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
Object.defineProperty(exports, 'resolvedLifecycleSpecOf', {
|
|
118
|
+
enumerable: true,
|
|
119
|
+
get: function () {
|
|
120
|
+
return resolvedLifecycleSpecOf;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
//# sourceMappingURL=Plugin-Cgp1a0uQ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Plugin-Cgp1a0uQ.cjs","names":["SeedcordError","SeedcordErrorCode","SeedcordError","SeedcordErrorCode","Logger","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 { 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: `config` and `store`. Each capability resolves to its value only when\n * the plugin declared that key, otherwise `never`. The logger comes from `this.logger`.\n *\n * @typeParam TNeeds - The plugin's declared `needs` union.\n */\nexport interface PluginContext<TNeeds extends PluginNeed = never> {\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, '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';\nimport { Logger } from '@seedcord/logger';\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 { 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 * @typeParam TCore - The host type `this.core` resolves to. Each transport binds it to its own `Core`.\n */\nexport abstract class Plugin<Opts extends PluginOptions = {}, TCore extends CoreBase = CoreBase>\n implements Initializeable, HmrAware\n{\n /** @internal phantom, never set at runtime */\n declare readonly __transport?: TransportOf<Opts>;\n /** @internal phantom, never set at runtime */\n declare readonly __runtime?: RuntimeOf<Opts>;\n\n /** @internal */\n readonly [resolvedSpecSlot]: ResolvedPluginLifecycleSpec;\n /** @internal */\n [pluginContextSlot]?: StoredPluginContext;\n\n /** Logs under the plugin's class name, on the channel its attach key names. */\n public readonly logger: Logger;\n\n // CoreBase here keeps the augmented Core out of ConstructorParameters, which attach reads\n constructor(\n private readonly host: CoreBase,\n spec?: PluginLifecycleSpec\n ) {\n this.logger = new Logger(this.constructor.name);\n this[resolvedSpecSlot] = resolveLifecycleSpec(spec, this.constructor.name);\n }\n\n /** The host, typed to the transport whose `Plugin` base this class extends. */\n protected get core(): TCore {\n // justified: each transport binds TCore to the Core its own host satisfies\n return this.host as TCore;\n }\n\n /** 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: PluginLike): 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// a bound of Plugin<{}> rejects every plugin that declares an option, since Plugin<A> and Plugin<B>\n// are mutually unassignable. every member here must stay Opts-independent.\n/** @internal */\nexport type PluginLike = Pick<\n Plugin,\n 'init' | 'ready' | 'dispose' | 'logger' | 'onHmr' | typeof resolvedSpecSlot | typeof pluginContextSlot\n>;\n\n// a `CoreBase` first parameter rejects a narrowing ctor on its own, and it also collapses\n// `InstanceType<Ctor>` to `PluginLike` at every attach call. CoreParamAssert checks it instead.\n/** @internal */\nexport type PluginCtor<TPlugin extends PluginLike = PluginLike> = new (...args: any[]) => TPlugin;\n\n/** @internal */\nexport type PluginArgs<Ctor extends PluginCtor> = Tail<ConstructorParameters<Ctor>>;\n\ntype CoreParamTooNarrow = Record<\n 'this plugin constructor must take CoreBase as its first parameter and read the transport Core off this.core',\n never\n>;\n\n// a narrowed first parameter fails `CoreBase extends Param`\n/** @internal */\nexport type CoreParamAssert<Ctor extends PluginCtor> = CoreBase extends ConstructorParameters<Ctor>[0]\n ? unknown\n : CoreParamTooNarrow;\n\nexport { finalizePluginContext } from './context';\n"],"mappings":";;;;;;;;AAqEA,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;;;;ACnEA,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;;;;;;;;AAStD,IAAsB,SAAtB,MAEA;CAgByB;;CATrB,CAAU;;CAEV,CAAC;;CAGD,AAAgB;CAGhB,YACI,AAAiB,MACjB,MACF;EAFmB;EAGjB,KAAK,SAAS,IAAIC,wBAAO,KAAK,YAAY,IAAI;EAC9C,KAAK,oBAAoB,qBAAqB,MAAM,KAAK,YAAY,IAAI;CAC7E;;CAGA,IAAc,OAAc;EAExB,OAAO,KAAK;CAChB;;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,QAAiD;CACrF,OAAO,OAAO;AAClB"}
|
|
@@ -0,0 +1,106 @@
|
|
|
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
|
+
import { Logger } from "@seedcord/logger";
|
|
6
|
+
|
|
7
|
+
//#region src/plugin/context.ts
|
|
8
|
+
/** @internal unset until attach installs the built ctx */
|
|
9
|
+
const pluginContextSlot = Symbol("seedcord.plugin.ctx");
|
|
10
|
+
/** @internal */
|
|
11
|
+
function readPluginContext(holder) {
|
|
12
|
+
const ctx = holder[pluginContextSlot];
|
|
13
|
+
if (!ctx) throw new SeedcordError(SeedcordErrorCode.PluginContextBeforeInit, [holder.constructor.name]);
|
|
14
|
+
return ctx;
|
|
15
|
+
}
|
|
16
|
+
/** @internal */
|
|
17
|
+
function finalizePluginContext(holder, ctx) {
|
|
18
|
+
holder[pluginContextSlot] = ctx;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/plugin/lifecycle.ts
|
|
23
|
+
const DEFAULT_INIT_TIMEOUT_MS = 15e3;
|
|
24
|
+
const DEFAULT_READY_TIMEOUT_MS = 15e3;
|
|
25
|
+
const DEFAULT_DISPOSE_TIMEOUT_MS = 1e4;
|
|
26
|
+
function timeoutOf(field, declared, fallback, pluginName) {
|
|
27
|
+
if (declared === void 0) return fallback;
|
|
28
|
+
if (!Number.isFinite(declared) || declared <= 0) throw new SeedcordError(SeedcordErrorCode.PluginOptionsRejected, [pluginName, `lifecycle ${field}.timeout must be a positive number of milliseconds`]);
|
|
29
|
+
return declared;
|
|
30
|
+
}
|
|
31
|
+
/** @internal */
|
|
32
|
+
function resolveLifecycleSpec(spec, pluginName) {
|
|
33
|
+
return {
|
|
34
|
+
init: {
|
|
35
|
+
phase: spec?.init?.phase ?? 1,
|
|
36
|
+
timeout: timeoutOf("init", spec?.init?.timeout, DEFAULT_INIT_TIMEOUT_MS, pluginName)
|
|
37
|
+
},
|
|
38
|
+
ready: { timeout: timeoutOf("ready", spec?.ready?.timeout, DEFAULT_READY_TIMEOUT_MS, pluginName) },
|
|
39
|
+
dispose: {
|
|
40
|
+
phase: spec?.dispose?.phase ?? 3,
|
|
41
|
+
timeout: timeoutOf("dispose", spec?.dispose?.timeout, DEFAULT_DISPOSE_TIMEOUT_MS, pluginName)
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/plugin/Plugin.ts
|
|
48
|
+
/** @internal */
|
|
49
|
+
const resolvedSpecSlot = Symbol("seedcord.plugin.spec");
|
|
50
|
+
/**
|
|
51
|
+
* Base class for Seedcord plugins. A subclass declares its options as the `Opts` type argument,
|
|
52
|
+
* implements `init()`, and reads the framework surface through `this.ctx`.
|
|
53
|
+
*
|
|
54
|
+
* @typeParam Opts - The plugin's declared {@link PluginOptions}.
|
|
55
|
+
* @typeParam TCore - The host type `this.core` resolves to. Each transport binds it to its own `Core`.
|
|
56
|
+
*/
|
|
57
|
+
var Plugin = class {
|
|
58
|
+
host;
|
|
59
|
+
/** @internal */
|
|
60
|
+
[resolvedSpecSlot];
|
|
61
|
+
/** @internal */
|
|
62
|
+
[pluginContextSlot];
|
|
63
|
+
/** Logs under the plugin's class name, on the channel its attach key names. */
|
|
64
|
+
logger;
|
|
65
|
+
constructor(host, spec) {
|
|
66
|
+
this.host = host;
|
|
67
|
+
this.logger = new Logger(this.constructor.name);
|
|
68
|
+
this[resolvedSpecSlot] = resolveLifecycleSpec(spec, this.constructor.name);
|
|
69
|
+
}
|
|
70
|
+
/** The host, typed to the transport whose `Plugin` base this class extends. */
|
|
71
|
+
get core() {
|
|
72
|
+
return this.host;
|
|
73
|
+
}
|
|
74
|
+
/** The framework surface, available from `init()` onward. Throws if read before `attach` finalizes it. */
|
|
75
|
+
get ctx() {
|
|
76
|
+
return readPluginContext(this);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Rejects the plugin's constructor options with a reason. Throws a `SeedcordError` naming the
|
|
80
|
+
* plugin class and the reason.
|
|
81
|
+
*
|
|
82
|
+
* @param reason - Why the options are invalid.
|
|
83
|
+
*/
|
|
84
|
+
rejectOptions(reason) {
|
|
85
|
+
throw new SeedcordError(SeedcordErrorCode.PluginOptionsRejected, [this.constructor.name, reason]);
|
|
86
|
+
}
|
|
87
|
+
/** Override to reload plugin state on an HMR update. */
|
|
88
|
+
onHmr(_event) {
|
|
89
|
+
return Promise.resolve();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Registers critical file patterns that should trigger a full restart when changed in Dev HMR.
|
|
93
|
+
* @param patterns - Glob patterns relative to the project root
|
|
94
|
+
*/
|
|
95
|
+
registerCriticalFiles(patterns) {
|
|
96
|
+
getDevChannel()?.send("seedcord:register-critical-files", { patterns });
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
/** @internal */
|
|
100
|
+
function resolvedLifecycleSpecOf(plugin) {
|
|
101
|
+
return plugin[resolvedSpecSlot];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
//#endregion
|
|
105
|
+
export { resolvedLifecycleSpecOf as n, finalizePluginContext as r, Plugin as t };
|
|
106
|
+
//# sourceMappingURL=Plugin-j9GYdroS.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Plugin-j9GYdroS.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 { 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: `config` and `store`. Each capability resolves to its value only when\n * the plugin declared that key, otherwise `never`. The logger comes from `this.logger`.\n *\n * @typeParam TNeeds - The plugin's declared `needs` union.\n */\nexport interface PluginContext<TNeeds extends PluginNeed = never> {\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, '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';\nimport { Logger } from '@seedcord/logger';\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 { 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 * @typeParam TCore - The host type `this.core` resolves to. Each transport binds it to its own `Core`.\n */\nexport abstract class Plugin<Opts extends PluginOptions = {}, TCore extends CoreBase = CoreBase>\n implements Initializeable, HmrAware\n{\n /** @internal phantom, never set at runtime */\n declare readonly __transport?: TransportOf<Opts>;\n /** @internal phantom, never set at runtime */\n declare readonly __runtime?: RuntimeOf<Opts>;\n\n /** @internal */\n readonly [resolvedSpecSlot]: ResolvedPluginLifecycleSpec;\n /** @internal */\n [pluginContextSlot]?: StoredPluginContext;\n\n /** Logs under the plugin's class name, on the channel its attach key names. */\n public readonly logger: Logger;\n\n // CoreBase here keeps the augmented Core out of ConstructorParameters, which attach reads\n constructor(\n private readonly host: CoreBase,\n spec?: PluginLifecycleSpec\n ) {\n this.logger = new Logger(this.constructor.name);\n this[resolvedSpecSlot] = resolveLifecycleSpec(spec, this.constructor.name);\n }\n\n /** The host, typed to the transport whose `Plugin` base this class extends. */\n protected get core(): TCore {\n // justified: each transport binds TCore to the Core its own host satisfies\n return this.host as TCore;\n }\n\n /** 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: PluginLike): 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// a bound of Plugin<{}> rejects every plugin that declares an option, since Plugin<A> and Plugin<B>\n// are mutually unassignable. every member here must stay Opts-independent.\n/** @internal */\nexport type PluginLike = Pick<\n Plugin,\n 'init' | 'ready' | 'dispose' | 'logger' | 'onHmr' | typeof resolvedSpecSlot | typeof pluginContextSlot\n>;\n\n// a `CoreBase` first parameter rejects a narrowing ctor on its own, and it also collapses\n// `InstanceType<Ctor>` to `PluginLike` at every attach call. CoreParamAssert checks it instead.\n/** @internal */\nexport type PluginCtor<TPlugin extends PluginLike = PluginLike> = new (...args: any[]) => TPlugin;\n\n/** @internal */\nexport type PluginArgs<Ctor extends PluginCtor> = Tail<ConstructorParameters<Ctor>>;\n\ntype CoreParamTooNarrow = Record<\n 'this plugin constructor must take CoreBase as its first parameter and read the transport Core off this.core',\n never\n>;\n\n// a narrowed first parameter fails `CoreBase extends Param`\n/** @internal */\nexport type CoreParamAssert<Ctor extends PluginCtor> = CoreBase extends ConstructorParameters<Ctor>[0]\n ? unknown\n : CoreParamTooNarrow;\n\nexport { finalizePluginContext } from './context';\n"],"mappings":";;;;;;;;AAqEA,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;;;;ACnEA,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;;;;;;;;AAStD,IAAsB,SAAtB,MAEA;CAgByB;;CATrB,CAAU;;CAEV,CAAC;;CAGD,AAAgB;CAGhB,YACI,AAAiB,MACjB,MACF;EAFmB;EAGjB,KAAK,SAAS,IAAI,OAAO,KAAK,YAAY,IAAI;EAC9C,KAAK,oBAAoB,qBAAqB,MAAM,KAAK,YAAY,IAAI;CAC7E;;CAGA,IAAc,OAAc;EAExB,OAAO,KAAK;CAChB;;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,QAAiD;CACrF,OAAO,OAAO;AAClB"}
|