@seedcord/core 0.11.0 → 0.12.0-next.2
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/README.md +3 -3
- package/dist/Bus-VJw-QpoY.mjs +986 -0
- package/dist/Bus-VJw-QpoY.mjs.map +1 -0
- package/dist/{CoordinatedShutdown-H5YjZn8A.d.mts → CoordinatedShutdown-fPKLWjc5.d.mts} +13 -4
- package/dist/{CoordinatedStartup-CGnJrqcl.mjs → CoordinatedStartup-Zw_Lk7Zk.mjs} +22 -20
- package/dist/CoordinatedStartup-Zw_Lk7Zk.mjs.map +1 -0
- package/dist/Generated-ByC53_A2.d.mts +26 -0
- package/dist/HmrModuleHandler-Btgu8r96.mjs +165 -0
- package/dist/HmrModuleHandler-Btgu8r96.mjs.map +1 -0
- package/dist/{PluginHost-DB4j8unu.d.mts → PluginHost-DFnkIldj.d.mts} +43 -15
- package/dist/PluginHost-DTtxWRiL.mjs +552 -0
- package/dist/PluginHost-DTtxWRiL.mjs.map +1 -0
- package/dist/{PluginLifecycle-AhQ46NIr.mjs → PluginLifecycle-hx5zUc-P.mjs} +4 -4
- package/dist/PluginLifecycle-hx5zUc-P.mjs.map +1 -0
- package/dist/{ServerHost-DYeh0KTk.d.mts → ServerHost-B5o3ScCF.d.mts} +7 -6
- package/dist/{ServerHost-CtmAhEXn.mjs → ServerHost-CDaEDR4C.mjs} +17 -6
- package/dist/{ServerHost-CtmAhEXn.mjs.map → ServerHost-CDaEDR4C.mjs.map} +1 -1
- package/dist/bindViteEnv-NFzvdqlT.mjs +32 -0
- package/dist/{bindViteEnv-DWq5rftJ.mjs.map → bindViteEnv-NFzvdqlT.mjs.map} +1 -1
- package/dist/env-internal.index.mjs +1 -1
- package/dist/hmr.index.d.mts +20 -20
- package/dist/hmr.index.mjs +1 -1
- package/dist/{index-Du71Xx69.d.mts → index-DGHng1IN.d.mts} +115 -201
- package/dist/index.d.mts +321 -74
- package/dist/index.mjs +323 -102
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.d.mts +223 -83
- package/dist/internal.index.mjs +573 -74
- package/dist/internal.index.mjs.map +1 -1
- package/dist/node-internal.index.d.mts +8 -4
- package/dist/node-internal.index.mjs +19 -6
- package/dist/node-internal.index.mjs.map +1 -1
- package/dist/node.index.d.mts +3 -3
- package/dist/node.index.mjs +22 -28
- package/dist/node.index.mjs.map +1 -1
- package/dist/{phases-FTM69J3a.d.mts → phases-C2QCSqRu.d.mts} +164 -55
- package/dist/plugin.index.d.mts +3 -2
- package/dist/plugin.index.mjs +1 -1
- package/dist/subscribers-CGuVjbrg.mjs +982 -0
- package/dist/subscribers-CGuVjbrg.mjs.map +1 -0
- package/dist/{bindViteEnv-DWq5rftJ.mjs → usingCtx-Cf2cZi96.mjs} +1 -31
- package/package.json +14 -11
- package/dist/CoordinatedStartup-CGnJrqcl.mjs.map +0 -1
- package/dist/HmrModuleHandler-8ZC-UuZh.mjs +0 -162
- package/dist/HmrModuleHandler-8ZC-UuZh.mjs.map +0 -1
- package/dist/PluginHost-B8kxLOeb.mjs +0 -245
- package/dist/PluginHost-B8kxLOeb.mjs.map +0 -1
- package/dist/PluginLifecycle-AhQ46NIr.mjs.map +0 -1
- package/dist/phases-BauKJOTT.mjs +0 -31
- package/dist/phases-BauKJOTT.mjs.map +0 -1
- package/dist/publishDefault-D3dAyzZ9.mjs +0 -7
- package/dist/publishDefault-D3dAyzZ9.mjs.map +0 -1
- package/dist/subscribers-Ce3SWy23.mjs +0 -1913
- package/dist/subscribers-Ce3SWy23.mjs.map +0 -1
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
import { n as StartupPhase, t as ShutdownPhase } from "./phases-BauKJOTT.mjs";
|
|
2
|
-
import { SeedcordErrorCode } from "@seedcord/errors";
|
|
3
|
-
import { SeedcordError, SeedcordRangeError, SeedcordTypeError } from "@seedcord/errors/internal";
|
|
4
|
-
import { FRAMEWORK_CHANNELS, Logger } from "@seedcord/logger";
|
|
5
|
-
import { HostPluginKeys } from "@seedcord/types/internal";
|
|
6
|
-
|
|
7
|
-
//#region src/hmr/devChannel.ts
|
|
8
|
-
let channel;
|
|
9
|
-
/** @internal */
|
|
10
|
-
function setDevChannel(next) {
|
|
11
|
-
channel = next;
|
|
12
|
-
}
|
|
13
|
-
/** @internal */
|
|
14
|
-
function getDevChannel() {
|
|
15
|
-
return channel;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
//#endregion
|
|
19
|
-
//#region src/plugin/lifecycle.ts
|
|
20
|
-
const DEFAULT_INIT_TIMEOUT_MS = 15e3;
|
|
21
|
-
const DEFAULT_READY_TIMEOUT_MS = 15e3;
|
|
22
|
-
const DEFAULT_DISPOSE_TIMEOUT_MS = 1e4;
|
|
23
|
-
function timeoutOf(field, declared, fallback, pluginName) {
|
|
24
|
-
if (declared === void 0) return fallback;
|
|
25
|
-
if (!Number.isFinite(declared) || declared <= 0) throw new SeedcordRangeError(SeedcordErrorCode.LifecycleInvalidTimeout, [`${pluginName}'s lifecycle ${field}.timeout`, declared]);
|
|
26
|
-
return declared;
|
|
27
|
-
}
|
|
28
|
-
/** @internal */
|
|
29
|
-
function resolveLifecycleSpec(spec, pluginName) {
|
|
30
|
-
return {
|
|
31
|
-
init: {
|
|
32
|
-
phase: spec?.init?.phase ?? 1,
|
|
33
|
-
timeout: timeoutOf("init", spec?.init?.timeout, DEFAULT_INIT_TIMEOUT_MS, pluginName)
|
|
34
|
-
},
|
|
35
|
-
ready: { timeout: timeoutOf("ready", spec?.ready?.timeout, DEFAULT_READY_TIMEOUT_MS, pluginName) },
|
|
36
|
-
dispose: {
|
|
37
|
-
phase: spec?.dispose?.phase ?? 3,
|
|
38
|
-
timeout: timeoutOf("dispose", spec?.dispose?.timeout, DEFAULT_DISPOSE_TIMEOUT_MS, pluginName)
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
//#endregion
|
|
44
|
-
//#region src/plugin/Plugin.ts
|
|
45
|
-
/** @internal */
|
|
46
|
-
const resolvedSpecSlot = Symbol("seedcord:plugin:spec");
|
|
47
|
-
/** @internal */
|
|
48
|
-
const loggerSlot = Symbol("seedcord:plugin:logger");
|
|
49
|
-
/** @internal */
|
|
50
|
-
const scopeSlot = Symbol("seedcord:plugin:scope");
|
|
51
|
-
/** @internal */
|
|
52
|
-
const FixedScope = Symbol("seedcord:plugin:fixed-scope");
|
|
53
|
-
/**
|
|
54
|
-
* Base class for a seedcord plugin. Extend it and implement `init()`. `this.core` is the running
|
|
55
|
-
* bot.
|
|
56
|
-
*
|
|
57
|
-
* Your constructor takes the host first and passes it to `super()`. Add your own parameters after
|
|
58
|
-
* it. `attach()` types them at the call site.
|
|
59
|
-
*
|
|
60
|
-
* A plugin that narrows `transport` or `runtime` in `Opts` passes the same values to `super()`.
|
|
61
|
-
* `attach()` throws when either one differs from the bot's.
|
|
62
|
-
*
|
|
63
|
-
* @typeParam Opts - Where this plugin may attach.
|
|
64
|
-
* @typeParam TCore - The `Core` each transport binds `this.core` to.
|
|
65
|
-
* @typeParam Fixed - The `transport` and `runtime` values a transport's own `Plugin` base sets. Leave it out.
|
|
66
|
-
*
|
|
67
|
-
* @example
|
|
68
|
-
* ```ts
|
|
69
|
-
* class Analytics extends Plugin<{ transport: 'gateway' }> {
|
|
70
|
-
* constructor(
|
|
71
|
-
* host: CoreBase,
|
|
72
|
-
* private readonly apiKey: string
|
|
73
|
-
* ) {
|
|
74
|
-
* super(host, { transport: 'gateway', init: { phase: StartupPhase.Login } });
|
|
75
|
-
* }
|
|
76
|
-
*
|
|
77
|
-
* public async init(): Promise<void> {
|
|
78
|
-
* await this.connect(this.apiKey);
|
|
79
|
-
* }
|
|
80
|
-
* }
|
|
81
|
-
*
|
|
82
|
-
* seedcord.attach('analytics', Analytics, apiKey);
|
|
83
|
-
* ```
|
|
84
|
-
*/
|
|
85
|
-
var Plugin = class {
|
|
86
|
-
host;
|
|
87
|
-
/** @internal */
|
|
88
|
-
static [FixedScope] = {};
|
|
89
|
-
/** @internal */
|
|
90
|
-
[resolvedSpecSlot];
|
|
91
|
-
/** @internal */
|
|
92
|
-
[loggerSlot];
|
|
93
|
-
/** @internal */
|
|
94
|
-
[scopeSlot];
|
|
95
|
-
/** Logs under the plugin's class name, on the channel its attach key sets. */
|
|
96
|
-
logger;
|
|
97
|
-
constructor(host, ...[spec]) {
|
|
98
|
-
this.host = host;
|
|
99
|
-
this.logger = new Logger(this.constructor.name);
|
|
100
|
-
this[loggerSlot] = this.logger;
|
|
101
|
-
this[resolvedSpecSlot] = resolveLifecycleSpec(spec, this.constructor.name);
|
|
102
|
-
const passed = spec;
|
|
103
|
-
const fixed = new.target[FixedScope];
|
|
104
|
-
this[scopeSlot] = {
|
|
105
|
-
transport: fixed.transport ?? passed?.transport ?? "any",
|
|
106
|
-
runtime: fixed.runtime ?? passed?.runtime ?? "any"
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
/** The host, typed to the transport whose `Plugin` base this class extends. */
|
|
110
|
-
get core() {
|
|
111
|
-
return this.host;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Rejects the options this plugin got.
|
|
115
|
-
*
|
|
116
|
-
* @param reason - Why the options are invalid.
|
|
117
|
-
* @throws A **SeedcordTypeError** every time, with the plugin class name and `reason` in its message.
|
|
118
|
-
*/
|
|
119
|
-
rejectOptions(reason) {
|
|
120
|
-
throw new SeedcordTypeError(SeedcordErrorCode.PluginOptionsRejected, [this.constructor.name, reason]);
|
|
121
|
-
}
|
|
122
|
-
/** Override to reload plugin state on an HMR update. */
|
|
123
|
-
onHmr(_event) {
|
|
124
|
-
return Promise.resolve();
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Registers critical file patterns that should trigger a full restart when changed in Dev HMR.
|
|
128
|
-
* @param patterns - Glob patterns. A relative one resolves against `root` from `seedcord.config.ts`.
|
|
129
|
-
*/
|
|
130
|
-
registerCriticalFiles(patterns) {
|
|
131
|
-
getDevChannel()?.send("seedcord:register-critical-files", { patterns });
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
/** @internal */
|
|
135
|
-
function resolvedLifecycleSpecOf(plugin) {
|
|
136
|
-
return plugin[resolvedSpecSlot];
|
|
137
|
-
}
|
|
138
|
-
/** @internal */
|
|
139
|
-
function extendsThisCorePlugin(ctor) {
|
|
140
|
-
return ctor.prototype instanceof Plugin;
|
|
141
|
-
}
|
|
142
|
-
/** @internal */
|
|
143
|
-
function pluginLoggerOf(plugin) {
|
|
144
|
-
return plugin[loggerSlot];
|
|
145
|
-
}
|
|
146
|
-
/** @internal */
|
|
147
|
-
function declaredScopeOf(plugin) {
|
|
148
|
-
return plugin[scopeSlot];
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
//#endregion
|
|
152
|
-
//#region src/plugin/PluginHost.ts
|
|
153
|
-
const RESERVED_KEYS = new Set(FRAMEWORK_CHANNELS);
|
|
154
|
-
const attachmentsSlot = Symbol("seedcord:host:attachments");
|
|
155
|
-
const sealSlot = Symbol("seedcord:host:seal");
|
|
156
|
-
/** Base class for a plugin host. */
|
|
157
|
-
var PluginHost = class {
|
|
158
|
-
#sealed = false;
|
|
159
|
-
#attachments = [];
|
|
160
|
-
#groups = /* @__PURE__ */ new Map();
|
|
161
|
-
#scope;
|
|
162
|
-
constructor(transport, runtime) {
|
|
163
|
-
this.#scope = {
|
|
164
|
-
transport,
|
|
165
|
-
runtime
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
/** @internal */
|
|
169
|
-
get [attachmentsSlot]() {
|
|
170
|
-
return this.#attachments;
|
|
171
|
-
}
|
|
172
|
-
/** @internal */
|
|
173
|
-
[sealSlot]() {
|
|
174
|
-
this.#sealed = true;
|
|
175
|
-
}
|
|
176
|
-
/** @internal codegen reads this to emit the `Core` augmentation */
|
|
177
|
-
get [HostPluginKeys]() {
|
|
178
|
-
return this.#attachments.map((attachment) => attachment.key);
|
|
179
|
-
}
|
|
180
|
-
attach(key, Plugin, ...args) {
|
|
181
|
-
if (this.#sealed) throw new SeedcordError(SeedcordErrorCode.CorePluginAfterInit);
|
|
182
|
-
const dot = key.indexOf(".");
|
|
183
|
-
const head = dot === -1 ? key : key.slice(0, dot);
|
|
184
|
-
if (RESERVED_KEYS.has(head)) throw new SeedcordTypeError(SeedcordErrorCode.CorePluginReservedChannel, [head]);
|
|
185
|
-
const leaf = dot === -1 ? void 0 : key.slice(dot + 1);
|
|
186
|
-
if (head === "" || leaf === "") throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyMalformed, [key, "has an empty part."]);
|
|
187
|
-
if (leaf?.includes(".")) throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyMalformed, [key, "has more than one dot."]);
|
|
188
|
-
this.#assertFree(head, leaf, key);
|
|
189
|
-
if (!extendsThisCorePlugin(Plugin)) throw new SeedcordTypeError(SeedcordErrorCode.CorePluginFromOtherCore, [Plugin.name]);
|
|
190
|
-
const instance = new Plugin(this, ...args);
|
|
191
|
-
this.#assertScope(Plugin.name, declaredScopeOf(instance));
|
|
192
|
-
pluginLoggerOf(instance).setChannel(key);
|
|
193
|
-
this.#attachments.push({
|
|
194
|
-
key,
|
|
195
|
-
instance,
|
|
196
|
-
spec: resolvedLifecycleSpecOf(instance)
|
|
197
|
-
});
|
|
198
|
-
if (leaf === void 0) return Object.assign(this, { [key]: instance });
|
|
199
|
-
this.#groupFor(head)[leaf] = instance;
|
|
200
|
-
return this;
|
|
201
|
-
}
|
|
202
|
-
#assertFree(head, leaf, key) {
|
|
203
|
-
if (leaf === void 0) {
|
|
204
|
-
if (this.#groups.has(key)) throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyHoldsGroup, [key]);
|
|
205
|
-
if (key in this) throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyExists, [key]);
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
const group = this.#groups.get(head);
|
|
209
|
-
if (!group) {
|
|
210
|
-
if (head in this) throw new SeedcordTypeError(SeedcordErrorCode.CorePluginGroupTaken, [head, key]);
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
if (Object.hasOwn(group, leaf)) throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyExists, [key]);
|
|
214
|
-
}
|
|
215
|
-
#assertScope(pluginName, declared) {
|
|
216
|
-
for (const axis of ["transport", "runtime"]) {
|
|
217
|
-
const host = this.#scope[axis];
|
|
218
|
-
if (declared[axis] === "any" || declared[axis] === host) continue;
|
|
219
|
-
throw new SeedcordTypeError(SeedcordErrorCode.CorePluginScopeMismatch, [
|
|
220
|
-
pluginName,
|
|
221
|
-
axis,
|
|
222
|
-
declared[axis],
|
|
223
|
-
host
|
|
224
|
-
]);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
#groupFor(head) {
|
|
228
|
-
const existing = this.#groups.get(head);
|
|
229
|
-
if (existing) return existing;
|
|
230
|
-
const group = Object.create(null);
|
|
231
|
-
this.#groups.set(head, group);
|
|
232
|
-
Object.assign(this, { [head]: group });
|
|
233
|
-
return group;
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
function attachmentsOf(host) {
|
|
237
|
-
return host[attachmentsSlot];
|
|
238
|
-
}
|
|
239
|
-
function sealAttachments(host) {
|
|
240
|
-
host[sealSlot]();
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
//#endregion
|
|
244
|
-
export { Plugin as a, setDevChannel as c, FixedScope as i, attachmentsOf as n, pluginLoggerOf as o, sealAttachments as r, getDevChannel as s, PluginHost as t };
|
|
245
|
-
//# sourceMappingURL=PluginHost-B8kxLOeb.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PluginHost-B8kxLOeb.mjs","names":[],"sources":["../src/hmr/devChannel.ts","../src/plugin/lifecycle.ts","../src/plugin/Plugin.ts","../src/plugin/PluginHost.ts"],"sourcesContent":["import type { DevChannel, SeedcordCliEvents, SeedcordFrameworkEvents } from '@seedcord/types/internal';\n\nexport type CliChannel = DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents>;\n\n// one module instance per process, the HmrManager write and every framework read share it\nlet channel: CliChannel | undefined;\n\n/** @internal */\nexport function setDevChannel(next: CliChannel | undefined): void {\n channel = next;\n}\n\n/** @internal */\nexport function getDevChannel(): CliChannel | undefined {\n return channel;\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport { ShutdownPhase, StartupPhase } from '#src/lifecycle/phases';\n\n/**\n * Sets when a plugin's lifecycle methods run. Pass it as the second argument to `super()`. Omit a\n * field to keep its default.\n *\n * @see {@link StartupPhase}\n * @see {@link ShutdownPhase}\n * @example\n * ```ts\n * super(host, { init: { phase: StartupPhase.Login }, dispose: { timeout: 30_000 } });\n * ```\n */\nexport interface PluginLifecycleSpec {\n /**\n * Defaults to `StartupPhase.Configuration` and 15000ms. Set the phase to `Ready` and `init()`\n * runs ahead of every plugin's `ready()`.\n */\n init?: { phase?: StartupPhase; timeout?: number };\n /** `ready()` always runs in `StartupPhase.Ready`. Defaults to a 15000ms timeout. */\n ready?: { timeout?: number };\n /** Defaults to `ShutdownPhase.Disconnect` and 10000ms. */\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 SeedcordRangeError(SeedcordErrorCode.LifecycleInvalidTimeout, [\n `${pluginName}'s lifecycle ${field}.timeout`,\n declared\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 { SeedcordTypeError } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/logger';\n\nimport { getDevChannel } from '#hmr/devChannel';\n\nimport { RuntimeBrand, TransportBrand } from './brands';\nimport { resolveLifecycleSpec } from './lifecycle';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { ScopedSpec } from './brands';\nimport type { ResolvedPluginLifecycleSpec, PluginLifecycleSpec } from './lifecycle';\nimport type {\n DeclaredScope,\n TransportOf,\n PluginOptions,\n PluginSpecArgs,\n RuntimeOf,\n ScopeAxis,\n Runtime,\n RuntimeAssert,\n Transport,\n TransportAssert\n} from './options';\nimport type { Tail, FrameworkChannel, HmrAware, HmrUpdateEvent } from '@seedcord/types';\n\nexport interface Initializeable {\n init(): Promise<void>;\n}\n\n/** @internal */\nconst resolvedSpecSlot = Symbol('seedcord:plugin:spec');\n/** @internal */\nconst loggerSlot = Symbol('seedcord:plugin:logger');\n/** @internal */\nconst scopeSlot = Symbol('seedcord:plugin:scope');\n/** @internal */\nexport const FixedScope = Symbol('seedcord:plugin:fixed-scope');\n\n/**\n * Base class for a seedcord plugin. Extend it and implement `init()`. `this.core` is the running\n * bot.\n *\n * Your constructor takes the host first and passes it to `super()`. Add your own parameters after\n * it. `attach()` types them at the call site.\n *\n * A plugin that narrows `transport` or `runtime` in `Opts` passes the same values to `super()`.\n * `attach()` throws when either one differs from the bot's.\n *\n * @typeParam Opts - Where this plugin may attach.\n * @typeParam TCore - The `Core` each transport binds `this.core` to.\n * @typeParam Fixed - The `transport` and `runtime` values a transport's own `Plugin` base sets. Leave it out.\n *\n * @example\n * ```ts\n * class Analytics extends Plugin<{ transport: 'gateway' }> {\n * constructor(\n * host: CoreBase,\n * private readonly apiKey: string\n * ) {\n * super(host, { transport: 'gateway', init: { phase: StartupPhase.Login } });\n * }\n *\n * public async init(): Promise<void> {\n * await this.connect(this.apiKey);\n * }\n * }\n *\n * seedcord.attach('analytics', Analytics, apiKey);\n * ```\n */\nexport abstract class Plugin<\n Opts extends PluginOptions = {},\n TCore extends CoreBase = CoreBase,\n Fixed extends ScopeAxis = never\n>\n implements Initializeable, HmrAware\n{\n /** @internal */\n protected static readonly [FixedScope]: Partial<DeclaredScope> = {};\n\n // phantom, never set at runtime.\n /** @internal */\n declare readonly [TransportBrand]?: TransportOf<Opts>;\n /** @internal */\n declare readonly [RuntimeBrand]?: RuntimeOf<Opts>;\n\n /** @internal */\n readonly [resolvedSpecSlot]: ResolvedPluginLifecycleSpec;\n /** @internal */\n readonly [loggerSlot]: Logger;\n /** @internal */\n readonly [scopeSlot]: DeclaredScope;\n\n /** Logs under the plugin's class name, on the channel its attach key sets. */\n protected 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]: PluginSpecArgs<Opts, Fixed>\n ) {\n this.logger = new Logger(this.constructor.name);\n this[loggerSlot] = this.logger;\n this[resolvedSpecSlot] = resolveLifecycleSpec(spec, this.constructor.name);\n\n const passed: (PluginLifecycleSpec & Partial<DeclaredScope>) | undefined = spec;\n const fixed = new.target[FixedScope];\n this[scopeSlot] = {\n transport: fixed.transport ?? passed?.transport ?? 'any',\n runtime: fixed.runtime ?? passed?.runtime ?? 'any'\n };\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 /**\n * Runs in `StartupPhase.Configuration` by default.\n * Move it to a different phase with the {@link PluginLifecycleSpec}.\n */\n abstract init(): Promise<void>;\n\n /**\n * Runs in the Ready phase, after every attached plugin's `init()` has resolved. The other Ready\n * tasks run alongside it, including the http server binding its port.\n *\n * Override it when your work needs a logged-in client or a resolved application id.\n */\n ready?(): Promise<void>;\n\n /**\n * Runs during teardown, in `ShutdownPhase.Disconnect` by default. seedcord skips it when `init()`\n * has thrown.\n *\n * When `init()` outlasts its timeout, seedcord calls this once that `init()` resolves, outside any\n * shutdown phase. The process must still be alive for that call to happen.\n */\n dispose?(): Promise<void>;\n\n /**\n * Rejects the options this plugin got.\n *\n * @param reason - Why the options are invalid.\n * @throws A **SeedcordTypeError** every time, with the plugin class name and `reason` in its message.\n */\n protected rejectOptions(reason: string): never {\n throw new SeedcordTypeError(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. A relative one resolves against `root` from `seedcord.config.ts`.\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\n/** @internal */\nexport function extendsThisCorePlugin(ctor: PluginCtor): boolean {\n return ctor.prototype instanceof Plugin;\n}\n\n/** @internal */\nexport function pluginLoggerOf(plugin: PluginLike): Logger {\n return plugin[loggerSlot];\n}\n\n/** @internal */\nexport function declaredScopeOf(plugin: PluginLike): DeclaredScope {\n return plugin[scopeSlot];\n}\n\nexport type { PluginLifecycleSpec } from './lifecycle';\nexport type { PluginOptions } from './options';\n\n// a bound of Plugin<{}> rejects every plugin that declares an option, since Plugin<A> and Plugin<B>\n// are mutually unassignable. every member here must stay Opts-independent.\n/** @internal */\nexport type PluginLike = Pick<\n Plugin,\n 'init' | 'ready' | 'dispose' | 'onHmr' | typeof resolvedSpecSlot | typeof loggerSlot | typeof scopeSlot\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> =\n InheritsScopedConstructor<Ctor> extends true ? [] : Tail<ConstructorParameters<Ctor>>;\n\n// a narrowed plugin with no constructor of its own inherits the base one, whose spec carries ScopedSpec\ntype InheritsScopedConstructor<Ctor extends PluginCtor> =\n Tail<ConstructorParameters<Ctor>> extends [infer Spec, ...unknown[]]\n ? typeof ScopedSpec extends keyof Spec\n ? true\n : false\n : false;\n\n/** @internal */\nexport type Attached<Key extends string, Instance> = Key extends `${infer Group}.${infer Leaf}`\n ? Record<Group, Record<Leaf, Instance>>\n : Record<Key, Instance>;\n\n// attach writes the key onto the host, so a key like toString would shadow the one on Object.prototype\n// eslint-disable-next-line @typescript-eslint/no-wrapper-object-types -- lint:fix swaps this for `keyof object`, which is never\ntype HostMember<Host> = keyof Host | keyof Object;\n\n// a string argument against an object type renders only as `string is not assignable`\n/** @internal */\nexport type AttachKeyAssert<Key extends string, Host> = Key extends ''\n ? 'A plugin key needs a name.'\n : Key extends `${infer Group}.${infer Leaf}`\n ? Leaf extends `${string}.${string}`\n ? `'${Key}' has more than one dot. A plugin key takes one dot at most.`\n : '' extends Group | Leaf\n ? `'${Key}' has an empty part. Write a group and a plugin name around the dot, like 'services.users'.`\n : Group extends FrameworkChannel\n ? `'${Group}' is a channel the framework logs on. Pick another group name.`\n : Group extends keyof Host\n ? Host[Group] extends PluginLike\n ? `'${Group}' already holds a plugin, so '${Leaf}' cannot nest inside it.`\n : Host[Group] extends Record<string, PluginLike>\n ? Leaf extends keyof Host[Group]\n ? `'${Key}' is already attached.`\n : Key\n : `'${Group}' is already a member on the bot. Pick another group name.`\n : Group extends HostMember<Host>\n ? `'${Group}' is already a member on the bot. Pick another group name.`\n : Key\n : Key extends FrameworkChannel\n ? `'${Key}' is a channel the framework logs on. Pick another plugin key.`\n : Key extends keyof Host\n ? Host[Key] extends PluginLike\n ? `'${Key}' is already attached.`\n : Host[Key] extends Record<string, PluginLike>\n ? `'${Key}' already holds a group of plugins. Attach this one under a name of its own.`\n : `'${Key}' is already a member on the bot. Pick another plugin key.`\n : Key extends HostMember<Host>\n ? `'${Key}' is already a member on the bot. Pick another plugin key.`\n : Key;\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`\ntype CoreParamAssert<Ctor extends PluginCtor> = CoreBase extends ConstructorParameters<Ctor>[0]\n ? unknown\n : CoreParamTooNarrow;\n\ntype ConstructorMissing = Record<\n \"this plugin narrows its transport or runtime. Give it a constructor that passes them to super(), like super(host, { runtime: 'server' })\",\n never\n>;\n\ntype OwnConstructorAssert<Ctor extends PluginCtor> =\n InheritsScopedConstructor<Ctor> extends true ? ConstructorMissing : unknown;\n\ntype AttachAsserts<Ctor extends PluginCtor, BotT extends Transport, BotRt extends Runtime> = TransportAssert<\n InstanceType<Ctor>,\n BotT\n> &\n RuntimeAssert<InstanceType<Ctor>, BotRt> &\n CoreParamAssert<Ctor> &\n OwnConstructorAssert<Ctor>;\n\n// typescript can't infer Ctor from a generic class through `Ctor & AttachAsserts`. every assert returns unknown to pass.\n/** @internal */\nexport type AttachableCtor<Ctor extends PluginCtor, BotT extends Transport, BotRt extends Runtime> =\n unknown extends AttachAsserts<Ctor, BotT, BotRt> ? Ctor : AttachAsserts<Ctor, BotT, BotRt>;\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError, SeedcordTypeError } from '@seedcord/errors/internal';\nimport { FRAMEWORK_CHANNELS } from '@seedcord/logger';\nimport { HostPluginKeys } from '@seedcord/types/internal';\n\nimport { declaredScopeOf, extendsThisCorePlugin, pluginLoggerOf, resolvedLifecycleSpecOf } from './Plugin';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { Bus } from '#subscribers/Bus';\nimport type { ResolvedPluginLifecycleSpec } from './lifecycle';\nimport type { DeclaredScope, Runtime, Transport } from './options';\nimport type { AttachableCtor, Attached, AttachKeyAssert, PluginArgs, PluginCtor, PluginLike } from './Plugin';\nimport type { REST } from '@discordjs/rest';\nimport type { Config, IRateLimiter } from '@seedcord/types';\n\nexport interface Attachment {\n readonly key: string;\n readonly instance: PluginLike;\n readonly spec: ResolvedPluginLifecycleSpec;\n}\n\nconst RESERVED_KEYS: ReadonlySet<string> = new Set(FRAMEWORK_CHANNELS);\n\nconst attachmentsSlot = Symbol('seedcord:host:attachments');\nconst sealSlot = Symbol('seedcord:host:seal');\n\n/** Base class for a plugin host. */\nexport abstract class PluginHost<BotT extends Transport, BotRt extends Runtime> implements CoreBase {\n public abstract readonly config: Config;\n public abstract readonly rest: REST;\n public abstract readonly applicationId: string;\n public abstract readonly rateLimiter: IRateLimiter;\n public abstract readonly bus: Bus;\n\n #sealed = false;\n readonly #attachments: Attachment[] = [];\n readonly #groups = new Map<string, Record<string, PluginLike>>();\n readonly #scope: { readonly transport: BotT; readonly runtime: BotRt };\n\n constructor(transport: BotT, runtime: BotRt) {\n this.#scope = { transport, runtime };\n }\n\n /** @internal */\n public get [attachmentsSlot](): readonly Attachment[] {\n return this.#attachments;\n }\n\n /** @internal */\n public [sealSlot](): void {\n this.#sealed = true;\n }\n\n /** @internal codegen reads this to emit the `Core` augmentation */\n public get [HostPluginKeys](): readonly string[] {\n return this.#attachments.map((attachment) => attachment.key);\n }\n\n /**\n * Attaches a plugin under `key`. Read the instance back as `core[key]`. `seedcord codegen`\n * writes the `Core` augmentation that types it there.\n *\n * Put one dot in the key to nest the plugin under a group. `'services.users'` reads back as\n * `core.services.users`. Each name holds one plugin or one group.\n *\n * Startup runs each plugin's `init()` in attach order within its phase. A node bot starts in\n * `start()`. An edge bot starts on its first request.\n *\n * Attaching a plugin whose `transport` or `runtime` differs from this host fails to compile.\n * Your constructor takes `CoreBase` as its first parameter (you don't need to pass it though).\n * A narrower one fails to compile here.\n *\n * @param key - Also the channel the plugin logs on, dots included.\n * @param args - Whatever your constructor takes after the host.\n * @throws A **SeedcordError** when you attach after the bot has started.\n * @throws A **SeedcordTypeError** when `key` is taken, reserved, or malformed.\n * @throws A **SeedcordTypeError** when the plugin extends `Plugin` from another copy of `@seedcord/core`.\n * @throws A **SeedcordTypeError** when the plugin's `transport` or `runtime` differs from this host and the types were bypassed.\n * @example\n * ```ts\n * seedcord.attach('db', Mongoose, { uri: 'mongodb://...', name: 'seedcord', dir: ... });\n * ```\n */\n public attach<Key extends string, Ctor extends PluginCtor>(\n this: this,\n key: AttachKeyAssert<Key, this>,\n Plugin: AttachableCtor<Ctor, BotT, BotRt>,\n ...args: PluginArgs<Ctor>\n ): this & Attached<Key, InstanceType<Ctor>>;\n public attach<Key extends string, Ctor extends PluginCtor>(\n this: this,\n key: Key,\n Plugin: Ctor,\n ...args: PluginArgs<Ctor>\n ): this & Attached<Key, InstanceType<Ctor>> {\n if (this.#sealed) {\n throw new SeedcordError(SeedcordErrorCode.CorePluginAfterInit);\n }\n\n const dot = key.indexOf('.');\n const head = dot === -1 ? key : key.slice(0, dot);\n\n // runs before assertFree because some reserved channels are also host members\n if (RESERVED_KEYS.has(head)) {\n throw new SeedcordTypeError(SeedcordErrorCode.CorePluginReservedChannel, [head]);\n }\n\n const leaf = dot === -1 ? undefined : key.slice(dot + 1);\n if (head === '' || leaf === '') {\n throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyMalformed, [key, 'has an empty part.']);\n }\n if (leaf?.includes('.')) {\n throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyMalformed, [key, 'has more than one dot.']);\n }\n this.#assertFree(head, leaf, key);\n\n if (!extendsThisCorePlugin(Plugin)) {\n throw new SeedcordTypeError(SeedcordErrorCode.CorePluginFromOtherCore, [Plugin.name]);\n }\n\n const instance = new Plugin(this, ...args);\n this.#assertScope(Plugin.name, declaredScopeOf(instance));\n pluginLoggerOf(instance).setChannel(key);\n this.#attachments.push({ key, instance, spec: resolvedLifecycleSpecOf(instance) });\n\n if (leaf === undefined) {\n return Object.assign(this, { [key]: instance }) as this & Attached<Key, InstanceType<Ctor>>;\n }\n\n this.#groupFor(head)[leaf] = instance;\n return this as this & Attached<Key, InstanceType<Ctor>>;\n }\n\n #assertFree(head: string, leaf: string | undefined, key: string): void {\n if (leaf === undefined) {\n if (this.#groups.has(key)) throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyHoldsGroup, [key]);\n if (key in this) throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyExists, [key]);\n return;\n }\n\n const group = this.#groups.get(head);\n if (!group) {\n if (head in this) throw new SeedcordTypeError(SeedcordErrorCode.CorePluginGroupTaken, [head, key]);\n return;\n }\n if (Object.hasOwn(group, leaf)) throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyExists, [key]);\n }\n\n // the types already reject a mismatch. plain JS and casts reach this.\n #assertScope(pluginName: string, declared: DeclaredScope): void {\n for (const axis of ['transport', 'runtime'] as const) {\n const host = this.#scope[axis];\n if (declared[axis] === 'any' || declared[axis] === host) continue;\n throw new SeedcordTypeError(SeedcordErrorCode.CorePluginScopeMismatch, [\n pluginName,\n axis,\n declared[axis],\n host\n ]);\n }\n }\n\n #groupFor(head: string): Record<string, PluginLike> {\n const existing = this.#groups.get(head);\n if (existing) return existing;\n\n // a null prototype makes a leaf called __proto__ or valueOf an ordinary key\n const group = Object.create(null) as Record<string, PluginLike>;\n this.#groups.set(head, group);\n Object.assign(this, { [head]: group });\n return group;\n }\n}\n\nexport function attachmentsOf(\n host: Pick<PluginHost<Transport, Runtime>, typeof attachmentsSlot>\n): readonly Attachment[] {\n return host[attachmentsSlot];\n}\n\nexport function sealAttachments(host: Pick<PluginHost<Transport, Runtime>, typeof sealSlot>): void {\n host[sealSlot]();\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PluginLifecycle-AhQ46NIr.mjs","names":[],"sources":["../src/notices/logUnknownFault.ts","../src/lifecycle/withTimeout.ts","../src/lifecycle/PluginLifecycle.ts"],"sourcesContent":["import type { Logger } from '@seedcord/logger';\nimport type { ErrorsConfig } from '@seedcord/types';\n\nfunction causeLine(error: Error): string {\n const { cause } = error;\n if (!Error.isError(cause)) return '';\n const [first] = cause.message.split('\\n');\n return `\\ncaused by ${cause.name}: ${first ?? cause.message}`;\n}\n\nexport function logUnknownFault(logger: Logger, uuid: string, error: Error, errors: ErrorsConfig | undefined): void {\n if (errors?.errorStack ?? true) logger.error(uuid, error);\n else logger.error(`${uuid} | ${error.message}${causeLine(error)}`);\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n// calling start() in here turns its synchronous throw into a rejection\nasync function raceTimer(\n start: () => Promise<unknown>,\n timeoutMs: number,\n onTimeout: (resolve: () => void, reject: (error: unknown) => void) => void\n): Promise<void> {\n let timer: NodeJS.Timeout | undefined;\n try {\n await Promise.race([\n start(),\n new Promise<void>((resolve, reject) => {\n // node's timer can go off before performance.now() reaches timeoutMs\n const expiresAt = performance.now() + timeoutMs;\n const tick = (): void => {\n const remaining = expiresAt - performance.now();\n if (remaining > 0) {\n timer = setTimeout(tick, remaining);\n return;\n }\n onTimeout(resolve, reject);\n };\n timer = setTimeout(tick, timeoutMs);\n })\n ]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\n// rejects with a LifecycleTaskTimeout when run outlasts the bound\nexport function withTimeout(name: string, run: () => Promise<void>, timeoutMs: number): Promise<void> {\n return raceTimer(run, timeoutMs, (_, reject) => {\n reject(new SeedcordError(SeedcordErrorCode.LifecycleTaskTimeout, [name, timeoutMs]));\n });\n}\n\n// the caller does not get work's rejection\nexport function settleWithin(work: Promise<unknown>, timeoutMs: number): Promise<void> {\n return raceTimer(\n () =>\n work.then(\n () => undefined,\n () => undefined\n ),\n timeoutMs,\n (resolve) => resolve()\n );\n}\n","import { SeedcordErrorCode, isSeedcordError } from '@seedcord/errors';\nimport { throwSingleOrAggregate } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/logger';\n\nimport { StartupPhase } from '#src/lifecycle/phases';\nimport { pluginLoggerOf } from '#src/plugin/Plugin';\n\nimport { withTimeout } from './withTimeout';\n\nimport type { CoordinatedShutdown } from '#node/Lifecycle/CoordinatedShutdown';\nimport type { ShutdownPhase } from '#src/lifecycle/phases';\nimport type { Attachment } from '#src/plugin/PluginHost';\nimport type { CoordinatedStartup } from './CoordinatedStartup';\n\ninterface ReadyStep {\n readonly key: string;\n readonly run: () => Promise<void>;\n readonly timeout: number;\n}\n\nexport class PluginLifecycle {\n private readonly logger = new Logger('Plugins', { channel: 'plugins' });\n private readonly completedInits = new Set<Attachment>();\n private readonly disposePhases = new Set<ShutdownPhase>();\n private readonly timedOutInits = new Set<Promise<void>>();\n private attachments: readonly Attachment[] = [];\n private registered = false;\n\n constructor(\n private readonly startup: Pick<CoordinatedStartup, 'addTask'>,\n private readonly shutdown: Pick<CoordinatedShutdown, 'addTask'>\n ) {}\n\n // one combined task per phase keeps plugin inits sequential while the phase's other tasks run concurrently\n public register(attachments: readonly Attachment[]): void {\n if (this.registered) return;\n this.registered = true;\n this.attachments = [...attachments];\n\n const groups = Map.groupBy(this.attachments, (attachment) => attachment.spec.init.phase);\n\n for (const [phase, group] of groups) {\n // Ready inits run in the combined Ready task, before the ready hooks\n if (phase === StartupPhase.Ready) continue;\n const budget = group.reduce((sum, a) => sum + a.spec.init.timeout, 0);\n this.startup.addTask(phase, 'plugins-init', () => this.runInits(group), budget);\n }\n\n this.registerReadyTask(groups.get(StartupPhase.Ready) ?? []);\n }\n\n public async rollback(): Promise<void> {\n // log rollback dispose failures so they do not hide the startup error\n await this.disposeCompleted(undefined, (caught) => this.logger.warn('rollback dispose failed', caught));\n // prevents re-dispose when shutdown runs after rollback\n this.completedInits.clear();\n }\n\n public afterTimedOutInits(run: () => void): void {\n if (this.timedOutInits.size === 0) {\n run();\n return;\n }\n void Promise.allSettled(this.timedOutInits).then(run);\n }\n\n private async runInits(group: readonly Attachment[]): Promise<void> {\n for (const attachment of group) {\n const { key, instance, spec } = attachment;\n\n pluginLoggerOf(instance).utils.initialization(key, 'start');\n const running = instance.init();\n try {\n await withTimeout(`Plugin (${key})`, () => running, spec.init.timeout);\n } catch (caught) {\n if (isSeedcordError(caught, undefined, SeedcordErrorCode.LifecycleTaskTimeout)) {\n this.disposeWhenInitResolves(attachment, running);\n }\n throw caught;\n }\n pluginLoggerOf(instance).utils.initialization(key, 'end');\n\n this.completedInits.add(attachment);\n if (instance.dispose) this.registerDisposeTask(spec.dispose.phase);\n }\n }\n\n // disposeCompleted skips a plugin missing from completedInits\n private disposeWhenInitResolves({ key, instance, spec }: Attachment, running: Promise<void>): void {\n const dispose = instance.dispose?.bind(instance);\n\n const settled = running.then(\n async () => {\n if (!dispose) return;\n await withTimeout(`Plugin:${key}:dispose`, dispose, spec.dispose.timeout).catch((caught: unknown) =>\n this.logger.warn(`${key} dispose failed after a timed-out init`, caught)\n );\n },\n (caught: unknown) => this.logger.warn(`${key} init failed after its timeout`, caught)\n );\n this.timedOutInits.add(settled);\n void settled.finally(() => this.timedOutInits.delete(settled));\n }\n\n private registerReadyTask(readyInits: readonly Attachment[]): void {\n const steps = this.attachments.reduce<ReadyStep[]>((acc, { key, instance, spec }) => {\n const ready = instance.ready?.bind(instance);\n if (ready) acc.push({ key, run: ready, timeout: spec.ready.timeout });\n return acc;\n }, []);\n if (readyInits.length === 0 && steps.length === 0) return;\n\n const budget =\n readyInits.reduce((sum, a) => sum + a.spec.init.timeout, 0) +\n steps.reduce((sum, step) => sum + step.timeout, 0);\n this.startup.addTask(\n StartupPhase.Ready,\n 'plugins-ready',\n async () => {\n await this.runInits(readyInits);\n for (const step of steps) {\n await withTimeout(`Plugin:${step.key}:ready`, step.run, step.timeout);\n }\n },\n budget\n );\n }\n\n private registerDisposeTask(phase: ShutdownPhase): void {\n if (this.disposePhases.has(phase)) return;\n this.disposePhases.add(phase);\n\n // the budget covers every dispose in this phase because they all run in this one task\n const budget = this.attachments.reduce(\n (sum, a) => (a.instance.dispose && a.spec.dispose.phase === phase ? sum + a.spec.dispose.timeout : sum),\n 0\n );\n this.shutdown.addTask(phase, 'plugins-dispose', () => this.runDisposals(phase), budget);\n }\n\n private async runDisposals(phase: ShutdownPhase): Promise<void> {\n const failures: unknown[] = [];\n await this.disposeCompleted(phase, (caught) => failures.push(caught));\n throwSingleOrAggregate(failures, SeedcordErrorCode.PluginDisposeFailures);\n }\n\n private async disposeCompleted(\n phase: ShutdownPhase | undefined,\n onError: (caught: unknown) => void\n ): Promise<void> {\n for (const attachment of [...this.attachments].reverse()) {\n if (!this.completedInits.has(attachment)) continue;\n const { key, instance, spec } = attachment;\n const dispose = instance.dispose?.bind(instance);\n if (!dispose) continue;\n if (phase !== undefined && spec.dispose.phase !== phase) continue;\n\n try {\n await withTimeout(`Plugin:${key}:dispose`, dispose, spec.dispose.timeout);\n } catch (caught) {\n onError(caught);\n }\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/phases-BauKJOTT.mjs
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
//#region src/lifecycle/phases.ts
|
|
2
|
-
/**
|
|
3
|
-
* Startup phases, in run order.
|
|
4
|
-
*/
|
|
5
|
-
let StartupPhase = /* @__PURE__ */ function(StartupPhase) {
|
|
6
|
-
/** Nothing connected. Plugin init runs here by default. */
|
|
7
|
-
StartupPhase[StartupPhase["Configuration"] = 1] = "Configuration";
|
|
8
|
-
/** The gateway session opens, and http runs its REST-only startup work. */
|
|
9
|
-
StartupPhase[StartupPhase["Login"] = 2] = "Login";
|
|
10
|
-
/** Handlers are live and interactions dispatch. */
|
|
11
|
-
StartupPhase[StartupPhase["Ready"] = 3] = "Ready";
|
|
12
|
-
return StartupPhase;
|
|
13
|
-
}({});
|
|
14
|
-
/**
|
|
15
|
-
* Shutdown phases, in run order.
|
|
16
|
-
*/
|
|
17
|
-
let ShutdownPhase = /* @__PURE__ */ function(ShutdownPhase) {
|
|
18
|
-
/** Stop taking new interactions and requests. */
|
|
19
|
-
ShutdownPhase[ShutdownPhase["Unbind"] = 1] = "Unbind";
|
|
20
|
-
/** Waits for in-flight work to settle and stops internal services. */
|
|
21
|
-
ShutdownPhase[ShutdownPhase["Drain"] = 2] = "Drain";
|
|
22
|
-
/** External resources close. Plugin dispose runs here by default. */
|
|
23
|
-
ShutdownPhase[ShutdownPhase["Disconnect"] = 3] = "Disconnect";
|
|
24
|
-
/** The client disconnects last so in-flight handlers can still reference it during drain. */
|
|
25
|
-
ShutdownPhase[ShutdownPhase["Logout"] = 4] = "Logout";
|
|
26
|
-
return ShutdownPhase;
|
|
27
|
-
}({});
|
|
28
|
-
|
|
29
|
-
//#endregion
|
|
30
|
-
export { StartupPhase as n, ShutdownPhase as t };
|
|
31
|
-
//# sourceMappingURL=phases-BauKJOTT.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"phases-BauKJOTT.mjs","names":[],"sources":["../src/lifecycle/phases.ts"],"sourcesContent":["/**\n * Startup phases, in run order.\n */\nexport enum StartupPhase {\n /** Nothing connected. Plugin init runs here by default. */\n Configuration = 1,\n /** The gateway session opens, and http runs its REST-only startup work. */\n Login,\n /** Handlers are live and interactions dispatch. */\n Ready\n}\n\n/**\n * Shutdown phases, in run order.\n */\nexport enum ShutdownPhase {\n /** Stop taking new interactions and requests. */\n Unbind = 1,\n /** Waits for in-flight work to settle and stops internal services. */\n Drain,\n /** External resources close. Plugin dispose runs here by default. */\n Disconnect,\n /** The client disconnects last so in-flight handlers can still reference it during drain. */\n Logout\n}\n"],"mappings":";;;;AAGA,IAAY,eAAL;;CAEH;;CAEA;;CAEA;;AACJ;;;;AAKA,IAAY,gBAAL;;CAEH;;CAEA;;CAEA;;CAEA;;AACJ"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
//#region src/subscribers/publishDefault.ts
|
|
2
|
-
/** @internal PublishableKey excludes this key so publish() never emits it externally. */
|
|
3
|
-
const PublishDefault = Symbol("seedcord:bus:publish-default");
|
|
4
|
-
|
|
5
|
-
//#endregion
|
|
6
|
-
export { PublishDefault as t };
|
|
7
|
-
//# sourceMappingURL=publishDefault-D3dAyzZ9.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"publishDefault-D3dAyzZ9.mjs","names":[],"sources":["../src/subscribers/publishDefault.ts"],"sourcesContent":["/** @internal PublishableKey excludes this key so publish() never emits it externally. */\nexport const PublishDefault = Symbol('seedcord:bus:publish-default');\n"],"mappings":";;AACA,MAAa,iBAAiB,OAAO,8BAA8B"}
|