@seedcord/core 0.7.0 → 0.9.0
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/{Pluggable-keys1cVr.mjs → Pluggable-BShEwGw9.mjs} +37 -5
- package/dist/Pluggable-BShEwGw9.mjs.map +1 -0
- package/dist/{Pluggable-CqKvMXm5.d.mts → Pluggable-CAteNmfy.d.mts} +10 -4
- package/dist/Plugin-BJfRk0s_.mjs.map +1 -1
- package/dist/{Plugin-BdqfRjU0.d.mts → Plugin-D3wIj0xX.d.mts} +7 -4
- package/dist/{cursor-BY5dmiz6.d.mts → cursor-BPaPFTic.d.mts} +67 -9
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +3 -23
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.d.mts +2 -2
- package/dist/node-internal.index.d.mts +4 -2
- package/dist/node-internal.index.mjs +36 -12
- package/dist/node-internal.index.mjs.map +1 -1
- package/dist/node.index.d.mts +1 -1
- package/dist/node.index.mjs +1 -1
- package/dist/plugin.index.d.mts +1 -1
- package/dist/{subscribers-Bf4cBTvK.mjs → subscribers-kAQQt_YP.mjs} +32 -4
- package/dist/subscribers-kAQQt_YP.mjs.map +1 -0
- package/package.json +13 -13
- package/dist/Pluggable-keys1cVr.mjs.map +0 -1
- package/dist/subscribers-Bf4cBTvK.mjs.map +0 -1
|
@@ -105,6 +105,7 @@ var Pluggable = class Pluggable {
|
|
|
105
105
|
isInitialized = false;
|
|
106
106
|
startFailed = false;
|
|
107
107
|
plugins = [];
|
|
108
|
+
groups = /* @__PURE__ */ new Map();
|
|
108
109
|
pluginLogger = new Logger("Plugins", { channel: "plugins" });
|
|
109
110
|
attachments = [];
|
|
110
111
|
completedInits = /* @__PURE__ */ new Set();
|
|
@@ -174,13 +175,16 @@ var Pluggable = class Pluggable {
|
|
|
174
175
|
* Attaches a plugin under `key`. Read the instance back as `core[key]`. `seedcord codegen`
|
|
175
176
|
* writes the `Core` augmentation that types it there.
|
|
176
177
|
*
|
|
178
|
+
* Put one dot in the key to nest the plugin under a group, so `'services.users'` reads back as
|
|
179
|
+
* `core.services.users`. Each name holds one plugin or one group.
|
|
180
|
+
*
|
|
177
181
|
* Startup runs each plugin's `init()` in attach order within its phase.
|
|
178
182
|
*
|
|
179
183
|
* Attaching a plugin whose `transport` or `runtime` differs from this host fails to compile.
|
|
180
184
|
* Your constructor takes `CoreBase` as its first parameter (you don't need to pass it though).
|
|
181
185
|
* A narrower one fails to compile here.
|
|
182
186
|
*
|
|
183
|
-
* @param key - Also the channel the plugin logs on. Reserved channel names throw.
|
|
187
|
+
* @param key - Also the channel the plugin logs on, dots included. Reserved channel names throw.
|
|
184
188
|
* @param args - Whatever your constructor takes after the host.
|
|
185
189
|
* @throws A **SeedcordError** if you attach after the bot has started. A taken or reserved key throws too.
|
|
186
190
|
* @example
|
|
@@ -190,8 +194,13 @@ var Pluggable = class Pluggable {
|
|
|
190
194
|
*/
|
|
191
195
|
attach(key, Plugin, ...args) {
|
|
192
196
|
if (this.isInitialized) throw new SeedcordError(SeedcordErrorCode.CorePluginAfterInit);
|
|
193
|
-
|
|
194
|
-
|
|
197
|
+
const dot = key.indexOf(".");
|
|
198
|
+
const head = dot === -1 ? key : key.slice(0, dot);
|
|
199
|
+
if (RESERVED_KEYS.has(head)) throw new SeedcordTypeError(SeedcordErrorCode.CorePluginReservedChannel, [head]);
|
|
200
|
+
const leaf = dot === -1 ? void 0 : key.slice(dot + 1);
|
|
201
|
+
if (head === "" || leaf === "") throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyMalformed, [key, "has an empty part."]);
|
|
202
|
+
if (leaf?.includes(".")) throw new SeedcordTypeError(SeedcordErrorCode.CorePluginKeyMalformed, [key, "has more than one dot."]);
|
|
203
|
+
this.assertFree(head, leaf, key);
|
|
195
204
|
const instance = new Plugin(this, ...args);
|
|
196
205
|
pluginLoggerOf(instance).setChannel(key);
|
|
197
206
|
this.plugins.push(instance);
|
|
@@ -199,7 +208,30 @@ var Pluggable = class Pluggable {
|
|
|
199
208
|
key,
|
|
200
209
|
instance
|
|
201
210
|
});
|
|
202
|
-
return Object.assign(this, { [key]: instance });
|
|
211
|
+
if (leaf === void 0) return Object.assign(this, { [key]: instance });
|
|
212
|
+
this.groupFor(head)[leaf] = instance;
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
assertFree(head, leaf, key) {
|
|
216
|
+
if (leaf === void 0) {
|
|
217
|
+
if (this.groups.has(key)) throw new SeedcordError(SeedcordErrorCode.CorePluginKeyHoldsGroup, [key]);
|
|
218
|
+
if (key in this) throw new SeedcordError(SeedcordErrorCode.CorePluginKeyExists, [key]);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const group = this.groups.get(head);
|
|
222
|
+
if (!group) {
|
|
223
|
+
if (head in this) throw new SeedcordError(SeedcordErrorCode.CorePluginGroupTaken, [head, key]);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (Object.hasOwn(group, leaf)) throw new SeedcordError(SeedcordErrorCode.CorePluginKeyExists, [key]);
|
|
227
|
+
}
|
|
228
|
+
groupFor(head) {
|
|
229
|
+
const existing = this.groups.get(head);
|
|
230
|
+
if (existing) return existing;
|
|
231
|
+
const group = Object.create(null);
|
|
232
|
+
this.groups.set(head, group);
|
|
233
|
+
Object.assign(this, { [head]: group });
|
|
234
|
+
return group;
|
|
203
235
|
}
|
|
204
236
|
registerPluginTasks() {
|
|
205
237
|
if (this.pluginTasksRegistered) return;
|
|
@@ -301,4 +333,4 @@ function shutdownOf(host) {
|
|
|
301
333
|
|
|
302
334
|
//#endregion
|
|
303
335
|
export { withTimeout as a, settleWithin as i, shutdownOf as n, assertNodeVersion as r, Pluggable as t };
|
|
304
|
-
//# sourceMappingURL=Pluggable-
|
|
336
|
+
//# sourceMappingURL=Pluggable-BShEwGw9.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Pluggable-BShEwGw9.mjs","names":[],"sources":["../src/node/Lifecycle/withTimeout.ts","../src/node/assertNodeVersion.ts","../src/node/processErrors.ts","../src/node/Pluggable.ts"],"sourcesContent":["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 } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n// every seedcord package declares engines.node as `>=major` or `>=major.minor`\nconst RANGE = new RegExp(String.raw`^>=(\\d+)(?:\\.(\\d+))?`);\nconst VERSION = /^v?(\\d+)\\.(\\d+)/;\nconst SPACES = /\\s/g;\n\n/** @internal */\nexport function assertNodeVersion(range: string, running: string): void {\n const required = RANGE.exec(range.replaceAll(SPACES, ''));\n const current = VERSION.exec(running);\n if (!required || !current) return;\n\n const [, requiredMajor, requiredMinor = '0'] = required;\n const [, currentMajor, currentMinor] = current;\n\n const meetsRange =\n Number(currentMajor) > Number(requiredMajor) ||\n (Number(currentMajor) === Number(requiredMajor) && Number(currentMinor) >= Number(requiredMinor));\n if (meetsRange) return;\n\n throw new SeedcordError(SeedcordErrorCode.UnsupportedNodeVersion, [range, running]);\n}\n","import crypto from 'node:crypto';\n\nimport { Logger } from '@seedcord/logger';\n\nimport { asError } from '#stops/asError';\nimport { PublishDefault } from '#subscribers/publishDefault';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { CoordinatedShutdown } from '#node/Lifecycle/CoordinatedShutdown';\n\nconst logger = new Logger('Faults', { channel: 'errors' });\n\n/** @internal */\nexport function registerProcessErrors(core: CoreBase, shutdown: CoordinatedShutdown): () => void {\n function report(caught: unknown, origin: string): void {\n const error = asError(caught);\n const uuid = crypto.randomUUID();\n\n if (core.config.errors?.errorStack ?? false) logger.error(uuid, error);\n else logger.error(`${uuid} | ${error.message}`);\n\n core.bus[PublishDefault]('unknownException', { uuid, dispatchId: null, error, origin });\n }\n\n const onRejection = (reason: unknown): void => {\n report(reason, 'process:unhandledRejection');\n };\n\n const onException = (caught: unknown): void => {\n report(caught, 'process:uncaughtException');\n // node does not exit on its own once a listener is registered\n void shutdown.run(1);\n };\n\n process.on('unhandledRejection', onRejection);\n process.on('uncaughtException', onException);\n\n return () => {\n process.off('unhandledRejection', onRejection);\n process.off('uncaughtException', onException);\n };\n}\n","import { SeedcordErrorCode, isSeedcordError } from '@seedcord/errors';\nimport { SeedcordAggregateError, SeedcordError, SeedcordTypeError } from '@seedcord/errors/internal';\nimport { FRAMEWORK_CHANNELS, Logger } from '@seedcord/logger';\nimport { HostPluginKeys, HostShutdown, HostStartup } from '@seedcord/types/internal';\n\nimport { assertNodeVersion } from '#node/assertNodeVersion';\nimport { StartupPhase } from '#src/lifecycle/phases';\nimport { pluginLoggerOf, resolvedLifecycleSpecOf } from '#src/plugin/Plugin';\n\nimport { withTimeout } from './Lifecycle/withTimeout';\nimport { registerProcessErrors } from './processErrors';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { CoordinatedShutdown } from '#node/Lifecycle/CoordinatedShutdown';\nimport type { CoordinatedStartup } from '#node/Lifecycle/CoordinatedStartup';\nimport type { ShutdownPhase } from '#src/lifecycle/phases';\nimport type { Runtime, RuntimeAssert, Transport, TransportAssert } from '#src/plugin/options';\nimport type {\n Attached,\n AttachKeyAssert,\n CoreParamAssert,\n PluginArgs,\n PluginCtor,\n PluginLike\n} from '#src/plugin/Plugin';\nimport type { Bus } from '#subscribers/Bus';\nimport type { REST } from '@discordjs/rest';\nimport type { Config, IRateLimiter } from '@seedcord/types';\n\ninterface Attachment {\n readonly key: string;\n readonly instance: PluginLike;\n}\n\nconst RESERVED_KEYS: ReadonlySet<string> = new Set(FRAMEWORK_CHANNELS);\n\n/**\n * Base class for a plugin host, a transport `Seedcord` class.\n *\n * You attach plugins while configuring the bot. Within one startup phase, their `init()` calls run\n * one after another in attach order.\n */\n// BotRt has no default because RuntimeAssert rejects every plugin once 'edge' is in the union\nexport abstract class Pluggable<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 /** @internal */\n readonly [HostShutdown]: CoordinatedShutdown;\n /** @internal */\n readonly [HostStartup]: CoordinatedStartup;\n\n /** Add a task that runs while the bot shuts down. */\n public readonly shutdown: Pick<CoordinatedShutdown, 'addTask'>;\n\n /** Add a task that runs while the bot starts. */\n public readonly startup: Pick<CoordinatedStartup, 'addTask'>;\n\n protected isInitialized = false;\n protected startFailed = false;\n protected readonly plugins: PluginLike[] = [];\n private readonly groups = new Map<string, Record<string, PluginLike>>();\n\n private readonly pluginLogger = new Logger('Plugins', { channel: 'plugins' });\n\n private readonly attachments: Attachment[] = [];\n private readonly completedInits = new Set<Attachment>();\n private readonly disposePhases = new Set<ShutdownPhase>();\n private pluginTasksRegistered = false;\n private initPromise?: Promise<this> | undefined;\n\n private static isInstantiated = false;\n private static liveHost?: object | undefined;\n private static liveShutdown?: CoordinatedShutdown | undefined;\n private static liveProcessErrors?: (() => void) | undefined;\n\n constructor(shutdown: CoordinatedShutdown, startup: CoordinatedStartup) {\n // a `sideEffects: false` build would drop the same call in the node entry\n assertNodeVersion(process.env.PACKAGE_NODE_RANGE ?? '', process.version);\n\n if (Pluggable.isInstantiated) {\n // signal handlers from the caller's shutdown stay on the process unless dropped here\n shutdown.removeSignalHandlers();\n throw new SeedcordError(SeedcordErrorCode.CoreSingletonViolation);\n }\n\n Pluggable.isInstantiated = true;\n Pluggable.liveHost = this;\n Pluggable.liveShutdown = shutdown;\n this[HostShutdown] = shutdown;\n this[HostStartup] = startup;\n // a getter returning the slot would expose run() and the signal handlers too\n this.shutdown = { addTask: shutdown.addTask.bind(shutdown) };\n this.startup = { addTask: startup.addTask.bind(startup) };\n }\n\n /** @internal */\n protected init(): Promise<this> {\n // clearing the slot on a rejection means a later retry throws its own error\n this.initPromise ??= this.runInit().catch((caught: unknown) => {\n this.initPromise = undefined;\n throw caught;\n });\n return this.initPromise;\n }\n\n private async runInit(): Promise<this> {\n if (this.isInitialized) return this;\n // a rerun after a failed startup would re-init the rolled-back plugins\n if (this.startFailed) throw new SeedcordError(SeedcordErrorCode.LifecycleRestartAfterFailure);\n\n this.registerPluginTasks();\n\n if (this.config.errors?.catchProcessErrors ?? true) {\n Pluggable.liveProcessErrors = registerProcessErrors(this, this[HostShutdown]);\n }\n\n const startupSettled: PromiseWithResolvers<void> = Promise.withResolvers();\n this[HostShutdown].gateOnStartup(startupSettled.promise);\n\n try {\n await this[HostStartup].run();\n } catch (caught) {\n await this.rollback();\n throw caught;\n } finally {\n startupSettled.resolve();\n }\n\n this.isInitialized = true;\n return this;\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 /** @internal */\n protected static reset(host?: object): boolean {\n if (host !== undefined && Pluggable.liveHost !== host) return false;\n\n Pluggable.liveShutdown?.removeSignalHandlers();\n Pluggable.liveShutdown = undefined;\n Pluggable.liveProcessErrors?.();\n Pluggable.liveProcessErrors = undefined;\n Pluggable.liveHost = undefined;\n Pluggable.isInstantiated = false;\n return true;\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, so `'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.\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. Reserved channel names throw.\n * @param args - Whatever your constructor takes after the host.\n * @throws A **SeedcordError** if you attach after the bot has started. A taken or reserved key throws too.\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: Ctor &\n TransportAssert<InstanceType<Ctor>, BotT> &\n RuntimeAssert<InstanceType<Ctor>, BotRt> &\n CoreParamAssert<Ctor>,\n ...args: PluginArgs<Ctor>\n ): this & Attached<Key, InstanceType<Ctor>> {\n if (this.isInitialized) {\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 // several reserved channels are also members on a host, which the next check would report first\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 const instance = new Plugin(this, ...args);\n pluginLoggerOf(instance).setChannel(key);\n this.plugins.push(instance);\n this.attachments.push({ key, 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 private assertFree(head: string, leaf: string | undefined, key: string): void {\n if (leaf === undefined) {\n if (this.groups.has(key)) throw new SeedcordError(SeedcordErrorCode.CorePluginKeyHoldsGroup, [key]);\n if (key in this) throw new SeedcordError(SeedcordErrorCode.CorePluginKeyExists, [key]);\n return;\n }\n\n const group = this.groups.get(head);\n if (!group) {\n if (head in this) throw new SeedcordError(SeedcordErrorCode.CorePluginGroupTaken, [head, key]);\n return;\n }\n if (Object.hasOwn(group, leaf)) throw new SeedcordError(SeedcordErrorCode.CorePluginKeyExists, [key]);\n }\n\n private 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 // one combined task per phase keeps plugin inits sequential while the phase's other tasks run concurrently\n private registerPluginTasks(): void {\n if (this.pluginTasksRegistered) return;\n this.pluginTasksRegistered = true;\n\n const groups = new Map<StartupPhase, Attachment[]>();\n for (const attachment of this.attachments) {\n const phase = resolvedLifecycleSpecOf(attachment.instance).init.phase;\n const group = groups.get(phase) ?? [];\n group.push(attachment);\n groups.set(phase, group);\n }\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 + resolvedLifecycleSpecOf(a.instance).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 private async runInits(group: readonly Attachment[]): Promise<void> {\n for (const attachment of group) {\n const { key, instance } = attachment;\n const spec = resolvedLifecycleSpecOf(instance);\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(attachment: Attachment, running: Promise<void>): void {\n const dispose = attachment.instance.dispose?.bind(attachment.instance);\n const spec = resolvedLifecycleSpecOf(attachment.instance);\n\n void running.then(\n async () => {\n if (!dispose) return;\n await withTimeout(`Plugin:${attachment.key}:dispose`, dispose, spec.dispose.timeout).catch(\n (caught: unknown) =>\n this.pluginLogger.warn(`${attachment.key} dispose failed after a timed-out init`, caught)\n );\n },\n (caught: unknown) => this.pluginLogger.warn(`${attachment.key} init failed after its timeout`, caught)\n );\n }\n\n private registerReadyTask(readyInits: readonly Attachment[]): void {\n const steps = this.attachments.reduce<{ key: string; run: () => Promise<void>; timeout: number }[]>(\n (acc, a) => {\n const ready = a.instance.ready?.bind(a.instance);\n if (ready) {\n acc.push({\n key: a.key,\n run: ready,\n timeout: resolvedLifecycleSpecOf(a.instance).ready.timeout\n });\n }\n return acc;\n },\n []\n );\n if (readyInits.length === 0 && steps.length === 0) return;\n\n const budget =\n readyInits.reduce((sum, a) => sum + resolvedLifecycleSpecOf(a.instance).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((sum, a) => {\n const spec = resolvedLifecycleSpecOf(a.instance);\n return a.instance.dispose && spec.dispose.phase === phase ? sum + spec.dispose.timeout : sum;\n }, 0);\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 if (failures.length === 1) throw failures[0];\n if (failures.length > 1) {\n throw new SeedcordAggregateError(SeedcordErrorCode.PluginDisposeFailures, failures, [failures.length]);\n }\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 dispose = attachment.instance.dispose?.bind(attachment.instance);\n if (!dispose) continue;\n const spec = resolvedLifecycleSpecOf(attachment.instance);\n if (phase !== undefined && spec.dispose.phase !== phase) continue;\n\n try {\n await withTimeout(`Plugin:${attachment.key}:dispose`, dispose, spec.dispose.timeout);\n } catch (caught) {\n onError(caught);\n }\n }\n }\n\n private async rollback(): Promise<void> {\n this.startFailed = true;\n // log rollback dispose failures so they do not hide the startup error\n await this.disposeCompleted(undefined, (caught) => this.pluginLogger.warn('rollback dispose failed', caught));\n // prevents re-dispose when shutdown runs after rollback\n this.completedInits.clear();\n }\n}\n\n// the public `shutdown` field carries addTask alone\nexport function shutdownOf(host: Pick<Pluggable<Transport, Runtime>, typeof HostShutdown>): CoordinatedShutdown {\n return host[HostShutdown];\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as Bus, n as StartupPhase, r as CoreBase, t as ShutdownPhase } from "./phases-DJf12l5T.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { c as PluginLike, d as RuntimeAssert, f as Transport, n as Attached, o as PluginArgs, p as TransportAssert, r as CoreParamAssert, s as PluginCtor, t as AttachKeyAssert, u as Runtime } from "./Plugin-D3wIj0xX.mjs";
|
|
3
3
|
import { Logger } from "@seedcord/logger";
|
|
4
4
|
import { REST } from "@discordjs/rest";
|
|
5
5
|
import { HostPluginKeys, HostShutdown, HostStartup } from "@seedcord/types/internal";
|
|
@@ -103,6 +103,7 @@ declare abstract class Pluggable<BotT extends Transport, BotRt extends Runtime>
|
|
|
103
103
|
protected isInitialized: boolean;
|
|
104
104
|
protected startFailed: boolean;
|
|
105
105
|
protected readonly plugins: PluginLike[];
|
|
106
|
+
private readonly groups;
|
|
106
107
|
private readonly pluginLogger;
|
|
107
108
|
private readonly attachments;
|
|
108
109
|
private readonly completedInits;
|
|
@@ -125,13 +126,16 @@ declare abstract class Pluggable<BotT extends Transport, BotRt extends Runtime>
|
|
|
125
126
|
* Attaches a plugin under `key`. Read the instance back as `core[key]`. `seedcord codegen`
|
|
126
127
|
* writes the `Core` augmentation that types it there.
|
|
127
128
|
*
|
|
129
|
+
* Put one dot in the key to nest the plugin under a group, so `'services.users'` reads back as
|
|
130
|
+
* `core.services.users`. Each name holds one plugin or one group.
|
|
131
|
+
*
|
|
128
132
|
* Startup runs each plugin's `init()` in attach order within its phase.
|
|
129
133
|
*
|
|
130
134
|
* Attaching a plugin whose `transport` or `runtime` differs from this host fails to compile.
|
|
131
135
|
* Your constructor takes `CoreBase` as its first parameter (you don't need to pass it though).
|
|
132
136
|
* A narrower one fails to compile here.
|
|
133
137
|
*
|
|
134
|
-
* @param key - Also the channel the plugin logs on. Reserved channel names throw.
|
|
138
|
+
* @param key - Also the channel the plugin logs on, dots included. Reserved channel names throw.
|
|
135
139
|
* @param args - Whatever your constructor takes after the host.
|
|
136
140
|
* @throws A **SeedcordError** if you attach after the bot has started. A taken or reserved key throws too.
|
|
137
141
|
* @example
|
|
@@ -139,7 +143,9 @@ declare abstract class Pluggable<BotT extends Transport, BotRt extends Runtime>
|
|
|
139
143
|
* seedcord.attach('db', Mongoose, { uri: 'mongodb://...', name: 'seedcord', dir: ... });
|
|
140
144
|
* ```
|
|
141
145
|
*/
|
|
142
|
-
attach<Key extends string, Ctor extends PluginCtor>(this: this, key:
|
|
146
|
+
attach<Key extends string, Ctor extends PluginCtor>(this: this, key: AttachKeyAssert<Key, this>, Plugin: Ctor & TransportAssert<InstanceType<Ctor>, BotT> & RuntimeAssert<InstanceType<Ctor>, BotRt> & CoreParamAssert<Ctor>, ...args: PluginArgs<Ctor>): this & Attached<Key, InstanceType<Ctor>>;
|
|
147
|
+
private assertFree;
|
|
148
|
+
private groupFor;
|
|
143
149
|
private registerPluginTasks;
|
|
144
150
|
private runInits;
|
|
145
151
|
private disposeWhenInitResolves;
|
|
@@ -152,4 +158,4 @@ declare abstract class Pluggable<BotT extends Transport, BotRt extends Runtime>
|
|
|
152
158
|
declare function shutdownOf(host: Pick<Pluggable<Transport, Runtime>, typeof HostShutdown>): CoordinatedShutdown;
|
|
153
159
|
//#endregion
|
|
154
160
|
export { LifecycleTask as a, CoordinatedShutdown as i, shutdownOf as n, CoordinatedStartup as r, Pluggable as t };
|
|
155
|
-
//# sourceMappingURL=Pluggable-
|
|
161
|
+
//# sourceMappingURL=Pluggable-CAteNmfy.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Plugin-BJfRk0s_.mjs","names":[],"sources":["../src/plugin/lifecycle.ts","../src/plugin/Plugin.ts"],"sourcesContent":["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.PluginInvalidLifecycleTimeout, [pluginName, field, declared]);\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 { RuntimeBrand, TransportBrand } from './brands';\nimport { resolveLifecycleSpec } from './lifecycle';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { ResolvedPluginLifecycleSpec, PluginLifecycleSpec } from './lifecycle';\nimport type { TransportOf, PluginOptions, RuntimeOf } from './options';\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/** @internal */\nconst loggerSlot = Symbol('seedcord:plugin:logger');\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 * @typeParam Opts - Where this plugin may attach, checked only at compile time.\n * @typeParam TCore - The `Core` each transport binds `this.core` to.\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, { 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<Opts extends PluginOptions = {}, TCore extends CoreBase = CoreBase>\n implements Initializeable, HmrAware\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\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?: PluginLifecycleSpec\n ) {\n this.logger = new Logger(this.constructor.name);\n this[loggerSlot] = this.logger;\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 /**\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 * Throws a `SeedcordError` that contains the plugin class name and the reason.\n *\n * @param reason - Why the options are invalid.\n */\n protected rejectOptions(reason: string): never {\n throw new SeedcordError(SeedcordErrorCode.PluginOptionsRejected, [this.constructor.name, reason]);\n }\n\n /** Override to reload plugin state on an HMR update. */\n public onHmr(_event: HmrUpdateEvent): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Registers critical file patterns that should trigger a full restart when changed in Dev HMR.\n * @param patterns - Glob patterns relative to the project root\n */\n protected registerCriticalFiles(patterns: string[]): void {\n getDevChannel()?.send('seedcord:register-critical-files', { patterns });\n }\n}\n\n/** @internal */\nexport function resolvedLifecycleSpecOf(plugin: PluginLike): ResolvedPluginLifecycleSpec {\n return plugin[resolvedSpecSlot];\n}\n\n/** @internal */\nexport function pluginLoggerOf(plugin: PluginLike): Logger {\n return plugin[loggerSlot];\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\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"],"mappings":";;;;;;;AAmCA,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,mBAAmB,kBAAkB,+BAA+B;EAAC;EAAY;EAAO;CAAQ,CAAC;CAE/G,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;;;;;ACnDA,MAAM,mBAAmB,OAAO,sBAAsB;;AAEtD,MAAM,aAAa,OAAO,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BlD,IAAsB,SAAtB,MAEA;CAiByB;;CATrB,CAAU;;CAEV,CAAU;;CAGV,AAAmB;CAGnB,YACI,AAAiB,MACjB,MACF;EAFmB;EAGjB,KAAK,SAAS,IAAI,OAAO,KAAK,YAAY,IAAI;EAC9C,KAAK,cAAc,KAAK;EACxB,KAAK,oBAAoB,qBAAqB,MAAM,KAAK,YAAY,IAAI;CAC7E;;CAGA,IAAc,OAAc;EAExB,OAAO,KAAK;CAChB;;;;;;CA8BA,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;;AAGA,SAAgB,eAAe,QAA4B;CACvD,OAAO,OAAO;AAClB"}
|
|
1
|
+
{"version":3,"file":"Plugin-BJfRk0s_.mjs","names":[],"sources":["../src/plugin/lifecycle.ts","../src/plugin/Plugin.ts"],"sourcesContent":["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.PluginInvalidLifecycleTimeout, [pluginName, field, declared]);\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 { RuntimeBrand, TransportBrand } from './brands';\nimport { resolveLifecycleSpec } from './lifecycle';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { ResolvedPluginLifecycleSpec, PluginLifecycleSpec } from './lifecycle';\nimport type { TransportOf, PluginOptions, RuntimeOf } 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\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 * @typeParam Opts - Where this plugin may attach, checked only at compile time.\n * @typeParam TCore - The `Core` each transport binds `this.core` to.\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, { 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<Opts extends PluginOptions = {}, TCore extends CoreBase = CoreBase>\n implements Initializeable, HmrAware\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\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?: PluginLifecycleSpec\n ) {\n this.logger = new Logger(this.constructor.name);\n this[loggerSlot] = this.logger;\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 /**\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 * Throws a `SeedcordError` that contains the plugin class name and the reason.\n *\n * @param reason - Why the options are invalid.\n */\n protected rejectOptions(reason: string): never {\n throw new SeedcordError(SeedcordErrorCode.PluginOptionsRejected, [this.constructor.name, reason]);\n }\n\n /** Override to reload plugin state on an HMR update. */\n public onHmr(_event: HmrUpdateEvent): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Registers critical file patterns that should trigger a full restart when changed in Dev HMR.\n * @param patterns - Glob patterns relative to the project root\n */\n protected registerCriticalFiles(patterns: string[]): void {\n getDevChannel()?.send('seedcord:register-critical-files', { patterns });\n }\n}\n\n/** @internal */\nexport function resolvedLifecycleSpecOf(plugin: PluginLike): ResolvedPluginLifecycleSpec {\n return plugin[resolvedSpecSlot];\n}\n\n/** @internal */\nexport function pluginLoggerOf(plugin: PluginLike): Logger {\n return plugin[loggerSlot];\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\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\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`\n/** @internal */\nexport type CoreParamAssert<Ctor extends PluginCtor> = CoreBase extends ConstructorParameters<Ctor>[0]\n ? unknown\n : CoreParamTooNarrow;\n"],"mappings":";;;;;;;AAmCA,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,mBAAmB,kBAAkB,+BAA+B;EAAC;EAAY;EAAO;CAAQ,CAAC;CAE/G,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;;;;;ACnDA,MAAM,mBAAmB,OAAO,sBAAsB;;AAEtD,MAAM,aAAa,OAAO,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BlD,IAAsB,SAAtB,MAEA;CAiByB;;CATrB,CAAU;;CAEV,CAAU;;CAGV,AAAmB;CAGnB,YACI,AAAiB,MACjB,MACF;EAFmB;EAGjB,KAAK,SAAS,IAAI,OAAO,KAAK,YAAY,IAAI;EAC9C,KAAK,cAAc,KAAK;EACxB,KAAK,oBAAoB,qBAAqB,MAAM,KAAK,YAAY,IAAI;CAC7E;;CAGA,IAAc,OAAc;EAExB,OAAO,KAAK;CAChB;;;;;;CA8BA,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;;AAGA,SAAgB,eAAe,QAA4B;CACvD,OAAO,OAAO;AAClB"}
|
|
@@ -87,8 +87,6 @@ type Runtime = TypedExclude<NonNullable<PluginOptions['runtime']>, 'any'>;
|
|
|
87
87
|
type TransportMismatch<PluginT extends string, BotT extends string> = Record<`this plugin declares transport '${PluginT}' but this bot runs '${BotT}'`, never>;
|
|
88
88
|
type RuntimeMismatch<PluginRt extends string, BotRt extends string> = Record<`this plugin declares runtime '${PluginRt}' but this bot runs '${BotRt}'`, never>;
|
|
89
89
|
type EdgePluginsUnsupported = Record<'an edge bot takes no plugins until edge support ships after v1', never>;
|
|
90
|
-
/** @internal */
|
|
91
|
-
type ChannelKeyAssert<Key extends string> = Key extends FrameworkChannel ? `'${Key}' is a channel the framework logs on. Pick another plugin key.` : Key;
|
|
92
90
|
type BrandTransport<Plug> = Plug extends {
|
|
93
91
|
readonly [TransportBrand]?: infer T extends string;
|
|
94
92
|
} ? T : 'any';
|
|
@@ -191,9 +189,14 @@ type PluginLike = Pick<Plugin, 'init' | 'ready' | 'dispose' | 'onHmr' | typeof r
|
|
|
191
189
|
type PluginCtor<TPlugin extends PluginLike = PluginLike> = new (...args: any[]) => TPlugin;
|
|
192
190
|
/** @internal */
|
|
193
191
|
type PluginArgs<Ctor extends PluginCtor> = Tail<ConstructorParameters<Ctor>>;
|
|
192
|
+
/** @internal */
|
|
193
|
+
type Attached<Key extends string, Instance> = Key extends `${infer Group}.${infer Leaf}` ? Record<Group, Record<Leaf, Instance>> : Record<Key, Instance>;
|
|
194
|
+
type HostMember<Host> = keyof Host | keyof Object;
|
|
195
|
+
/** @internal */
|
|
196
|
+
type AttachKeyAssert<Key extends string, Host> = Key extends '' ? 'A plugin key needs a name.' : Key extends `${infer Group}.${infer Leaf}` ? Leaf extends `${string}.${string}` ? `'${Key}' has more than one dot. A plugin key takes one dot at most.` : '' extends Group | Leaf ? `'${Key}' has an empty part. Write a group and a plugin name around the dot, like 'services.users'.` : Group extends FrameworkChannel ? `'${Group}' is a channel the framework logs on. Pick another group name.` : Group extends keyof Host ? Host[Group] extends PluginLike ? `'${Group}' already holds a plugin, so '${Leaf}' cannot nest inside it.` : Host[Group] extends Record<string, PluginLike> ? Leaf extends keyof Host[Group] ? `'${Key}' is already attached.` : Key : `'${Group}' is already a member on the bot. Pick another group name.` : Group extends HostMember<Host> ? `'${Group}' is already a member on the bot. Pick another group name.` : Key : Key extends FrameworkChannel ? `'${Key}' is a channel the framework logs on. Pick another plugin key.` : Key extends keyof Host ? Host[Key] extends PluginLike ? `'${Key}' is already attached.` : Host[Key] extends Record<string, PluginLike> ? `'${Key}' already holds a group of plugins. Attach this one under a name of its own.` : `'${Key}' is already a member on the bot. Pick another plugin key.` : Key extends HostMember<Host> ? `'${Key}' is already a member on the bot. Pick another plugin key.` : Key;
|
|
194
197
|
type CoreParamTooNarrow = Record<'this plugin constructor must take CoreBase as its first parameter and read the transport Core off this.core', never>;
|
|
195
198
|
/** @internal */
|
|
196
199
|
type CoreParamAssert<Ctor extends PluginCtor> = CoreBase extends ConstructorParameters<Ctor>[0] ? unknown : CoreParamTooNarrow;
|
|
197
200
|
//#endregion
|
|
198
|
-
export {
|
|
199
|
-
//# sourceMappingURL=Plugin-
|
|
201
|
+
export { Plugin as a, PluginLike as c, RuntimeAssert as d, Transport as f, Initializeable as i, PluginOptions as l, PluginLifecycleSpec as m, Attached as n, PluginArgs as o, TransportAssert as p, CoreParamAssert as r, PluginCtor as s, AttachKeyAssert as t, Runtime as u };
|
|
202
|
+
//# sourceMappingURL=Plugin-D3wIj0xX.d.mts.map
|
|
@@ -208,6 +208,14 @@ declare abstract class RowComponent<RowKey extends RowType> extends BaseComponen
|
|
|
208
208
|
get component(): InstantiatedActionRow<RowKey>;
|
|
209
209
|
}
|
|
210
210
|
//#endregion
|
|
211
|
+
//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/primitive.d.ts
|
|
212
|
+
/**
|
|
213
|
+
Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
|
|
214
|
+
|
|
215
|
+
@category Type
|
|
216
|
+
*/
|
|
217
|
+
type Primitive = null | undefined | string | number | boolean | symbol | bigint;
|
|
218
|
+
//#endregion
|
|
211
219
|
//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/is-never.d.ts
|
|
212
220
|
/**
|
|
213
221
|
Returns a boolean for whether the given type is `never`.
|
|
@@ -288,6 +296,38 @@ sum();
|
|
|
288
296
|
*/
|
|
289
297
|
type NonEmptyTuple<T = unknown> = readonly [T, ...T[]];
|
|
290
298
|
//#endregion
|
|
299
|
+
//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/literal-union.d.ts
|
|
300
|
+
/**
|
|
301
|
+
Create a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union.
|
|
302
|
+
|
|
303
|
+
Currently, when a union type of a primitive type is combined with literal types, TypeScript loses all information about the combined literals. Thus, when such type is used in an IDE with autocompletion, no suggestions are made for the declared literals.
|
|
304
|
+
|
|
305
|
+
This type is a workaround for [Microsoft/TypeScript#29729](https://github.com/Microsoft/TypeScript/issues/29729). It will be removed as soon as it's not needed anymore.
|
|
306
|
+
|
|
307
|
+
@example
|
|
308
|
+
```
|
|
309
|
+
import type {LiteralUnion} from 'type-fest';
|
|
310
|
+
|
|
311
|
+
// Before
|
|
312
|
+
|
|
313
|
+
type Pet = 'dog' | 'cat' | string;
|
|
314
|
+
|
|
315
|
+
const petWithoutAutocomplete: Pet = '';
|
|
316
|
+
// Start typing in your TypeScript-enabled IDE.
|
|
317
|
+
// You **will not** get auto-completion for `dog` and `cat` literals.
|
|
318
|
+
|
|
319
|
+
// After
|
|
320
|
+
|
|
321
|
+
type Pet2 = LiteralUnion<'dog' | 'cat', string>;
|
|
322
|
+
|
|
323
|
+
const petWithAutoComplete: Pet2 = '';
|
|
324
|
+
// You **will** get auto-completion for `dog` and `cat` literals.
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
@category Type
|
|
328
|
+
*/
|
|
329
|
+
type LiteralUnion<LiteralType, BaseType extends Primitive> = LiteralType | (BaseType & Record<never, never>);
|
|
330
|
+
//#endregion
|
|
291
331
|
//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/promisable.d.ts
|
|
292
332
|
/**
|
|
293
333
|
Create a type that represents either the value or the value wrapped in `PromiseLike`.
|
|
@@ -317,16 +357,34 @@ type Promisable<T> = T | PromiseLike<T>;
|
|
|
317
357
|
//#endregion
|
|
318
358
|
//#region src/decorators/Command.d.ts
|
|
319
359
|
type CommandCtor = Constructor<BuilderComponent<'command' | 'context_menu'>>;
|
|
360
|
+
declare const ConfigGuilds = "config";
|
|
361
|
+
/** A guild id, or `'config'` for every id in `commands.guilds`. */
|
|
362
|
+
type GuildTarget = LiteralUnion<typeof ConfigGuilds, string>;
|
|
320
363
|
interface GlobalMeta {
|
|
321
364
|
scope: 'global';
|
|
322
365
|
}
|
|
323
366
|
interface GuildMeta {
|
|
324
367
|
scope: 'guild';
|
|
325
|
-
guilds:
|
|
368
|
+
guilds: GuildTarget[];
|
|
369
|
+
}
|
|
370
|
+
interface ConfigMeta {
|
|
371
|
+
scope: 'config';
|
|
326
372
|
}
|
|
327
|
-
type CommandMeta = GlobalMeta | GuildMeta;
|
|
373
|
+
type CommandMeta = GlobalMeta | GuildMeta | ConfigMeta;
|
|
374
|
+
/**
|
|
375
|
+
* Registers a command in the guilds listed under `commands.guilds`. With no ids listed there, the
|
|
376
|
+
* command deploys globally.
|
|
377
|
+
*
|
|
378
|
+
* @decorator
|
|
379
|
+
* @example
|
|
380
|
+
* ```typescript
|
|
381
|
+
* \@RegisterCommand()
|
|
382
|
+
* class PingCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>
|
|
383
|
+
* ```
|
|
384
|
+
*/
|
|
385
|
+
declare function RegisterCommand(): (ctor: CommandCtor) => void;
|
|
328
386
|
/**
|
|
329
|
-
*
|
|
387
|
+
* Registers a command globally, ignoring `commands.guilds`.
|
|
330
388
|
*
|
|
331
389
|
* @decorator
|
|
332
390
|
* @example
|
|
@@ -337,17 +395,17 @@ type CommandMeta = GlobalMeta | GuildMeta;
|
|
|
337
395
|
*/
|
|
338
396
|
declare function RegisterCommand(scope: 'global'): (ctor: CommandCtor) => void;
|
|
339
397
|
/**
|
|
340
|
-
* Registers a command
|
|
398
|
+
* Registers a command in the guilds you pass. These ids replace `commands.guilds`. Include
|
|
399
|
+
* `'config'` among them to keep that list too.
|
|
341
400
|
*
|
|
342
|
-
* @param guilds - Array of guild IDs where the command should be registered
|
|
343
401
|
* @decorator
|
|
344
402
|
* @example
|
|
345
403
|
* ```typescript
|
|
346
|
-
* \@RegisterCommand('guild', ['123456789'])
|
|
404
|
+
* \@RegisterCommand('guild', ['config', '123456789'])
|
|
347
405
|
* class AdminCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>
|
|
348
406
|
* ```
|
|
349
407
|
*/
|
|
350
|
-
declare function RegisterCommand(scope: 'guild', guilds:
|
|
408
|
+
declare function RegisterCommand(scope: 'guild', guilds: GuildTarget[]): (ctor: CommandCtor) => void;
|
|
351
409
|
//#endregion
|
|
352
410
|
//#region src/decorators/brands.d.ts
|
|
353
411
|
declare const SlashRouteBrand: unique symbol;
|
|
@@ -878,5 +936,5 @@ type PageCursor<Prefix extends string> = CustomId<Prefix, {
|
|
|
878
936
|
/** Build the page cursor for a paginator. */
|
|
879
937
|
declare function pageCursor<Prefix extends string>(prefix: Prefix): PageCursor<Prefix>;
|
|
880
938
|
//#endregion
|
|
881
|
-
export {
|
|
882
|
-
//# sourceMappingURL=cursor-
|
|
939
|
+
export { RowComponent as $, serializeReply as A, AutocompleteRouteBrand as B, Gate as C, defineEffectGate as D, RequiredOf as E, AnyMiddlewareCtor as F, MiddlewareKindsBrand as G, ComponentKindBrand as H, InteractionMiddlewareMetadata as I, GuildTarget as J, SlashRouteBrand as K, InteractionMiddlewareOptions as L, EventDispatchResult as M, HandlerOutcome as N, defineGate as O, HandlerResult as P, BuilderComponent as Q, RegisterInteractionMiddleware as R, EffectGate as S, GuildPermissionsContext as T, ContextMenuKindBrand as U, ComponentDefsBrand as V, ContextMenuNamesBrand as W, Promisable as X, RegisterCommand as Y, IsNever as Z, pickNotice as _, AutocompleteOptions as a, SlashOption as at, JoinNames as b, FocusedField as c, ContextMenuKind as ct, RequirePermissionsOptions as d, NamesFor as dt, BuilderType as et, RequireRole as f, UserContextMenuRegistry as ft, GateNoticeOptions as g, PermissionScope as h, AutocompletableNames as i, RouteCache as it, DispatchResult as j, SerializedReply as k, RequireBotPermissions as l, MenuCacheFor as lt, PermissionNames as m, PageCursor as n, CacheFor as nt, ChoiceValueOf as o, SlashRegistry as ot, RequireRoleOptions as p, CommandMeta as q, pageCursor as r, OptionKind as rt, EntryFor as s, SlashRouteEntry as st, PAGE_MAX as t, RowType as tt, RequirePermissions as u, MessageContextMenuRegistry as ut, GateFitsWith as v, GateContextBase as w, TwoOrMore as x, IntersectRequired as y, interactionMiddlewareMetaOf as z };
|
|
940
|
+
//# sourceMappingURL=cursor-BPaPFTic.d.mts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { G as Notice, H as MiddlewareKind, N as DispatchContext, R as InteractionKind, S as AckState, _ as SubscriptionData, b as ReplyTelemetry, c as Subscriber, d as DispatchOutcome, f as FaultSource, g as ResponseSent, h as ResponseOutcome, i as Bus, l as AttemptedWrite, m as ResponseFailed, n as StartupPhase, p as ResponseAttempt, r as CoreBase, t as ShutdownPhase, v as SubscriptionKey, y as Subscriptions } from "./phases-DJf12l5T.mjs";
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as RowComponent, B as AutocompleteRouteBrand, C as Gate, D as defineEffectGate, E as RequiredOf, H as ComponentKindBrand, J as GuildTarget, K as SlashRouteBrand, L as InteractionMiddlewareOptions, M as EventDispatchResult, N as HandlerOutcome, O as defineGate, P as HandlerResult, Q as BuilderComponent, R as RegisterInteractionMiddleware, S as EffectGate, T as GuildPermissionsContext, U as ContextMenuKindBrand, V as ComponentDefsBrand, W as ContextMenuNamesBrand, X as Promisable, Y as RegisterCommand, a as AutocompleteOptions, b as JoinNames, ct as ContextMenuKind, d as RequirePermissionsOptions, dt as NamesFor, et as BuilderType, f as RequireRole, ft as UserContextMenuRegistry, g as GateNoticeOptions, h as PermissionScope, j as DispatchResult, k as SerializedReply, l as RequireBotPermissions, n as PageCursor, ot as SlashRegistry, p as RequireRoleOptions, tt as RowType, u as RequirePermissions, ut as MessageContextMenuRegistry, w as GateContextBase, x as TwoOrMore, y as IntersectRequired } from "./cursor-BPaPFTic.mjs";
|
|
3
3
|
import { t as Constructor } from "./basic-Dng__Ena.mjs";
|
|
4
4
|
import { a as Subscribe, i as WebhookFile, n as WebhookLog, o as SubscribeOptions, r as WebhookReport, t as WebhookUrl } from "./index-BS1hH9Sh.mjs";
|
|
5
5
|
import "reflect-metadata";
|
|
@@ -963,5 +963,5 @@ declare abstract class PaginatorBase<Item, Prefix extends string, Ctx> {
|
|
|
963
963
|
/** Package version */
|
|
964
964
|
declare const version: string;
|
|
965
965
|
//#endregion
|
|
966
|
-
export { type AnyCustomId, ArraySourceBase, type AttemptedWrite, type AutocompleteOptions, AutocompleteRoute, BaseHandler, BaseReplySender, BuilderComponent, type BuilderType, Bus, ButtonRoute, ChannelMenuRoute, type CommandInfo, Commands, type ContextMenuInfo, ContextMenus, type ControlCosmetics, type ControlKey, Cooldown, type CooldownOptions, type CoreBase, CursorSourceBase, CustomId, type CustomIdField, type CustomIdShape, type DecodedParams, type DecodedRoute, DispatchContext, type DispatchOutcome, type DispatchResult, DmOnly, type EffectGate, type EventDispatchResult, Fault, type FaultSource, type FieldOptions, type Gate, type GateContextBase, type GateNoticeOptions, GuildOnly, type GuildPermissionsContext, type HandlerOutcome, type HandlerResult, type InjectedCommandMap, type InjectedContextMenuMap, InteractionKind, type InteractionMiddlewareOptions, type ItemRender, MentionableMenuRoute, type MessageContextMenuRegistry, MessageContextMenuRoute, type MiddlewareKind, type ModalLike, ModalRoute, Notice, OwnerOnly, type PageRender, type PageSourceBase, type PageView, PaginatorBase, type PaginatorConfig, type PaginatorControls, type PermissionAssertion, type PermissionNoticeOverrides, type PermissionScope, RegisterCommand, RegisterInteractionMiddleware, RepliableHandler, RequireBotPermissions, RequirePermissions, type RequirePermissionsOptions, RequireRole, type RequireRoleOptions, type RequiredOf, ResolvedEmoji, type ResponseAttempt, type ResponseFailed, type ResponseOutcome, type ResponseSent, RoleMenuRoute, RowComponent, type RowType, ShutdownPhase, Silence, type SlashRegistry, SlashRoute, StartupPhase, StringMenuRoute, Subscribe, type SubscribeOptions, Subscriber, type SubscriptionData, type SubscriptionKey, type Subscriptions, type UserContextMenuRegistry, UserContextMenuRoute, UserMenuRoute, type WebhookFile, WebhookLog, type WebhookReport, WebhookUrl, and, assertPermissions, decodeFor, defineEffectGate, defineGate, mergeRoles, or, paginate, prefixOf, setCustomIdErrors, version };
|
|
966
|
+
export { type AnyCustomId, ArraySourceBase, type AttemptedWrite, type AutocompleteOptions, AutocompleteRoute, BaseHandler, BaseReplySender, BuilderComponent, type BuilderType, Bus, ButtonRoute, ChannelMenuRoute, type CommandInfo, Commands, type ContextMenuInfo, ContextMenus, type ControlCosmetics, type ControlKey, Cooldown, type CooldownOptions, type CoreBase, CursorSourceBase, CustomId, type CustomIdField, type CustomIdShape, type DecodedParams, type DecodedRoute, DispatchContext, type DispatchOutcome, type DispatchResult, DmOnly, type EffectGate, type EventDispatchResult, Fault, type FaultSource, type FieldOptions, type Gate, type GateContextBase, type GateNoticeOptions, GuildOnly, type GuildPermissionsContext, type GuildTarget, type HandlerOutcome, type HandlerResult, type InjectedCommandMap, type InjectedContextMenuMap, InteractionKind, type InteractionMiddlewareOptions, type ItemRender, MentionableMenuRoute, type MessageContextMenuRegistry, MessageContextMenuRoute, type MiddlewareKind, type ModalLike, ModalRoute, Notice, OwnerOnly, type PageRender, type PageSourceBase, type PageView, PaginatorBase, type PaginatorConfig, type PaginatorControls, type PermissionAssertion, type PermissionNoticeOverrides, type PermissionScope, RegisterCommand, RegisterInteractionMiddleware, RepliableHandler, RequireBotPermissions, RequirePermissions, type RequirePermissionsOptions, RequireRole, type RequireRoleOptions, type RequiredOf, ResolvedEmoji, type ResponseAttempt, type ResponseFailed, type ResponseOutcome, type ResponseSent, RoleMenuRoute, RowComponent, type RowType, ShutdownPhase, Silence, type SlashRegistry, SlashRoute, StartupPhase, StringMenuRoute, Subscribe, type SubscribeOptions, Subscriber, type SubscriptionData, type SubscriptionKey, type Subscriptions, type UserContextMenuRegistry, UserContextMenuRoute, UserMenuRoute, type WebhookFile, WebhookLog, type WebhookReport, WebhookUrl, and, assertPermissions, decodeFor, defineEffectGate, defineGate, mergeRoles, or, paginate, prefixOf, setCustomIdErrors, version };
|
|
967
967
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { A as translateSerializationError, B as contextMenuRouteOf, C as NotInDm, D as defineEffectGate, E as OnCooldown, F as checkAckLegality, H as storeComponentRoute, I as sendTarget, K as NoticeCard, L as RegisterInteractionMiddleware, M as publishResponse, O as defineGate, P as AckTrace, S as NotAllowed, T as NotOwner, U as storeInteractionRoute, a as RequirePermissions, c as hasAll, d as pickNotice, h as runCheck, i as RequireBotPermissions, j as attemptWrite, k as serializeReply, l as missingNames, m as rollbackCommits, n as pageCursor, o as RequireRole, p as markCommits, q as Notice, r as Silence, t as PAGE_MAX, u as presentNames, v as HasDangerousPermissions, w as NotInGuild, x as NeedsAny, y as MissingPermissions } from "./cursor-CFNKLVlk.mjs";
|
|
2
|
-
import { A as BuilderComponent, b as InteractionKind, d as WebhookLog, f as Subscriber,
|
|
3
|
-
import {
|
|
2
|
+
import { A as BuilderComponent, b as InteractionKind, d as WebhookLog, f as Subscriber, j as RowComponent, l as WebhookUrl, t as Bus, u as Subscribe } from "./Bus-Djm6688b.mjs";
|
|
3
|
+
import { a as ContextMenus, i as Commands, n as RegisterCommand } from "./subscribers-kAQQt_YP.mjs";
|
|
4
4
|
import { n as StartupPhase, t as ShutdownPhase } from "./phases-BauKJOTT.mjs";
|
|
5
5
|
import "reflect-metadata";
|
|
6
6
|
import { CustomId, decodeFor, prefixOf, setCustomIdErrors, setCustomIdErrors as setCustomIdErrors$1 } from "@seedcord/custom-id";
|
|
@@ -44,26 +44,6 @@ setCustomIdErrors$1({
|
|
|
44
44
|
invalid: (detail) => new InvalidCustomId(detail)
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region src/decorators/Command.ts
|
|
49
|
-
function RegisterCommand(scope, guilds = []) {
|
|
50
|
-
return (ctor) => {
|
|
51
|
-
const existingMeta = Reflect.getOwnMetadata(CommandMetadataKey, ctor);
|
|
52
|
-
if (existingMeta) throw new SeedcordError(SeedcordErrorCode.DecoratorCommandAlreadyRegistered, [
|
|
53
|
-
ctor.name,
|
|
54
|
-
existingMeta.scope,
|
|
55
|
-
scope
|
|
56
|
-
]);
|
|
57
|
-
if (scope === "global" && guilds.length > 0) throw new SeedcordTypeError(SeedcordErrorCode.DecoratorCommandGlobalWithGuilds);
|
|
58
|
-
if (scope === "guild" && (!Array.isArray(guilds) || guilds.length === 0)) throw new SeedcordTypeError(SeedcordErrorCode.DecoratorCommandGuildWithoutGuilds);
|
|
59
|
-
const meta = scope === "global" ? { scope } : {
|
|
60
|
-
scope,
|
|
61
|
-
guilds
|
|
62
|
-
};
|
|
63
|
-
Reflect.defineMetadata(CommandMetadataKey, meta, ctor);
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
47
|
//#endregion
|
|
68
48
|
//#region src/decorators/routes.ts
|
|
69
49
|
/**
|
|
@@ -1189,7 +1169,7 @@ var CursorSourceBase = class {
|
|
|
1189
1169
|
//#endregion
|
|
1190
1170
|
//#region src/index.ts
|
|
1191
1171
|
/** Package version */
|
|
1192
|
-
const version = "0.
|
|
1172
|
+
const version = "0.9.0";
|
|
1193
1173
|
|
|
1194
1174
|
//#endregion
|
|
1195
1175
|
export { ArraySourceBase, AutocompleteRoute, BaseHandler, BaseReplySender, BuilderComponent, Bus, ButtonRoute, ChannelMenuRoute, Commands, ContextMenus, Cooldown, CursorSourceBase, CustomId, DispatchContext, DmOnly, Fault, GuildOnly, InteractionKind, MentionableMenuRoute, MessageContextMenuRoute, ModalRoute, Notice, OwnerOnly, PaginatorBase, RegisterCommand, RegisterInteractionMiddleware, RepliableHandler, RequireBotPermissions, RequirePermissions, RequireRole, ResolvedEmoji, RoleMenuRoute, RowComponent, ShutdownPhase, Silence, SlashRoute, StartupPhase, StringMenuRoute, Subscribe, Subscriber, UserContextMenuRoute, UserMenuRoute, WebhookLog, WebhookUrl, and, assertPermissions, decodeFor, defineEffectGate, defineGate, mergeRoles, or, paginate, prefixOf, setCustomIdErrors, version };
|