@seedcord/core 0.1.1 → 0.1.3-next.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.
Files changed (50) hide show
  1. package/dist/HmrModuleHandler-CxGOo1LT.cjs.map +1 -1
  2. package/dist/HmrModuleHandler-KxRP8lqJ.mjs.map +1 -1
  3. package/dist/Plugin-CDAV7P9l.mjs.map +1 -1
  4. package/dist/Plugin-DVNh1kvX.cjs.map +1 -1
  5. package/dist/{Plugin-BPz0obbN.d.mts → Plugin-qRc7Ch4g.d.mts} +22 -43
  6. package/dist/{basic-CeSFvbaz.d.mts → basic-Dng__Ena.d.mts} +2 -2
  7. package/dist/{contextMenuLeaves-CC3-qObq.d.mts → contextMenuLeaves-COzDYa6c.d.mts} +4 -5
  8. package/dist/{cursor-Bk-W5MTq.d.mts → cursor-C77xH5QT.d.mts} +30 -52
  9. package/dist/{cursor-Y6ct-N_8.mjs → cursor-D207VrRo.mjs} +20 -44
  10. package/dist/cursor-D207VrRo.mjs.map +1 -0
  11. package/dist/{cursor-D2iP-CCS.cjs → cursor-DFgJ70_B.cjs} +20 -44
  12. package/dist/cursor-DFgJ70_B.cjs.map +1 -0
  13. package/dist/{index-Dm0WKN37.d.mts → index-C0k7lRDi.d.mts} +3 -14
  14. package/dist/index.cjs +17 -22
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.mts +21 -24
  17. package/dist/index.mjs +17 -22
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/internal.index.cjs +10 -48
  20. package/dist/internal.index.cjs.map +1 -1
  21. package/dist/internal.index.d.mts +15 -62
  22. package/dist/internal.index.mjs +10 -48
  23. package/dist/internal.index.mjs.map +1 -1
  24. package/dist/node-internal.index.cjs +3 -76
  25. package/dist/node-internal.index.cjs.map +1 -1
  26. package/dist/node-internal.index.d.mts +4 -76
  27. package/dist/node-internal.index.mjs +3 -76
  28. package/dist/node-internal.index.mjs.map +1 -1
  29. package/dist/plugin.index.d.mts +1 -1
  30. package/dist/{publishDefault-CldnxcT2.mjs → publishDefault-BCrMG9T8.mjs} +5 -19
  31. package/dist/publishDefault-BCrMG9T8.mjs.map +1 -0
  32. package/dist/{publishDefault-CVlwYUS5.cjs → publishDefault-D52iT8mF.cjs} +5 -19
  33. package/dist/publishDefault-D52iT8mF.cjs.map +1 -0
  34. package/dist/{slashRouteLeaves-BANDtPFm.mjs → slashRouteLeaves-De1SxqnX.mjs} +4 -4
  35. package/dist/slashRouteLeaves-De1SxqnX.mjs.map +1 -0
  36. package/dist/{slashRouteLeaves-nfxOAM7Q.cjs → slashRouteLeaves-HVl6Ymr0.cjs} +4 -4
  37. package/dist/slashRouteLeaves-HVl6Ymr0.cjs.map +1 -0
  38. package/dist/{subscribers-CDbep0RH.cjs → subscribers-6x4xw39Z.cjs} +8 -26
  39. package/dist/subscribers-6x4xw39Z.cjs.map +1 -0
  40. package/dist/{subscribers-xO6DZ-70.mjs → subscribers-nEpbJj3Z.mjs} +8 -26
  41. package/dist/subscribers-nEpbJj3Z.mjs.map +1 -0
  42. package/package.json +9 -10
  43. package/dist/cursor-D2iP-CCS.cjs.map +0 -1
  44. package/dist/cursor-Y6ct-N_8.mjs.map +0 -1
  45. package/dist/publishDefault-CVlwYUS5.cjs.map +0 -1
  46. package/dist/publishDefault-CldnxcT2.mjs.map +0 -1
  47. package/dist/slashRouteLeaves-BANDtPFm.mjs.map +0 -1
  48. package/dist/slashRouteLeaves-nfxOAM7Q.cjs.map +0 -1
  49. package/dist/subscribers-CDbep0RH.cjs.map +0 -1
  50. package/dist/subscribers-xO6DZ-70.mjs.map +0 -1
@@ -25,7 +25,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
  }) : target, mod));
26
26
 
27
27
  //#endregion
28
- const require_publishDefault = require('./publishDefault-CVlwYUS5.cjs');
28
+ const require_publishDefault = require('./publishDefault-D52iT8mF.cjs');
29
29
  require("reflect-metadata");
30
30
  let _seedcord_logger = require("@seedcord/logger");
31
31
  let discord_api_types_v10 = require("discord-api-types/v10");
@@ -82,7 +82,6 @@ function jsonAttachment(name, description, data) {
82
82
  function neutralizeFences(text) {
83
83
  return text.replaceAll("```", "`​`​`");
84
84
  }
85
- /** An error's stack with its direct cause appended (one level), ANSI-stripped for the webhook payload. */
86
85
  function errorReport(error) {
87
86
  let report = error.stack ?? `${error.name}: ${error.message}`;
88
87
  if (Error.isError(error.cause)) {
@@ -103,11 +102,6 @@ var WebhookSeparator = class extends require_publishDefault.BuilderComponent {
103
102
  //#region src/subscribers/bases/WebhookSender.ts
104
103
  const HTTP_NOT_FOUND = 404;
105
104
  const HTTP_UNAUTHORIZED = 401;
106
- /**
107
- * Sends component messages to a Discord webhook through `@discordjs/rest`.
108
- *
109
- * @throws A `SeedcordError` when the url does not carry a webhook id and token.
110
- */
111
105
  var WebhookSender = class {
112
106
  rest = new _discordjs_rest.REST();
113
107
  route;
@@ -116,10 +110,6 @@ var WebhookSender = class {
116
110
  if (!match?.[1] || !match[2]) throw new _seedcord_errors_internal.SeedcordError(_seedcord_errors.SeedcordErrorCode.ConfigWebhookUrlInvalid, ["The url"]);
117
111
  this.route = discord_api_types_v10.Routes.webhook(match[1], match[2]);
118
112
  }
119
- /**
120
- * Fetches the webhook object, sending no message. Returns `missing` on a 404 or 401 from
121
- * Discord and `unreachable` on any other failure.
122
- */
123
113
  async verify() {
124
114
  try {
125
115
  await this.rest.get(this.route, { auth: false });
@@ -228,7 +218,6 @@ var WebhookLog = class WebhookLog extends Subscriber {
228
218
  * \@Subscribe('userJoin')
229
219
  * class WelcomeHandler extends Subscriber<'userJoin'> {
230
220
  * async execute() {
231
- * // Handle user join event
232
221
  * }
233
222
  * }
234
223
  * ```
@@ -377,12 +366,7 @@ var Bus = class extends _seedcord_event_emitter.TypedEventEmitter {
377
366
  super();
378
367
  this.core = core;
379
368
  }
380
- /**
381
- * Registers the two shipped webhook reporters. The host calls this during startup, keeping the
382
- * url validation inside `start()` where a failure can still release the singleton guard.
383
- *
384
- * @internal
385
- */
369
+ /** @internal the host calls this during startup, keeping the url validation inside `start()` where a failure can still release the singleton guard. */
386
370
  registerDefaults() {
387
371
  this.register(registrationFor(UnknownException));
388
372
  this.register(registrationFor(HandledException));
@@ -422,7 +406,6 @@ var Bus = class extends _seedcord_event_emitter.TypedEventEmitter {
422
406
  }));
423
407
  if (missing.length > 0) throw new _seedcord_errors_internal.SeedcordError(_seedcord_errors.SeedcordErrorCode.ConfigWebhookNotFound, [missing.join(", ")]);
424
408
  }
425
- /** Returns whether the class should register. */
426
409
  probeWebhook(ctor) {
427
410
  if (!(ctor.prototype instanceof WebhookLog)) return true;
428
411
  const envKey = WebhookLog.envKeyOf(ctor);
@@ -439,12 +422,11 @@ var Bus = class extends _seedcord_event_emitter.TypedEventEmitter {
439
422
  /**
440
423
  * Publishes an event to its subscribers and native listeners.
441
424
  *
442
- * Fire-and-forget, so subscriber handlers run asynchronously and this returns before they
443
- * complete, and callers must not assume side effects have completed. Errors thrown by a subscriber
444
- * or by an `on()` listener are caught and logged, never surfaced here. One throwing listener
445
- * does not stop the others. Subscribers on one key run concurrently and carry no ordering
446
- * guarantee. A `'once'` subscriber is marked as executed when it starts (even if it throws), so
447
- * it never runs twice.
425
+ * Fire-and-forget. Subscriber handlers run asynchronously and this returns before they finish. A
426
+ * caller cannot assume a side effect has completed. Errors thrown by a subscriber or by an `on()`
427
+ * listener are caught and logged, never surfaced here. One throwing listener does not stop the
428
+ * others. Subscribers on one key run concurrently and carry no ordering guarantee. A `'once'`
429
+ * subscriber is marked as executed when it starts, even if it throws. It never runs twice.
448
430
  *
449
431
  * The framework's own keys are excluded. Subscribe to those and listen with `on`. The framework
450
432
  * is their only publisher.
@@ -546,4 +528,4 @@ Object.defineProperty(exports, 'registrationFor', {
546
528
  return registrationFor;
547
529
  }
548
530
  });
549
- //# sourceMappingURL=subscribers-CDbep0RH.cjs.map
531
+ //# sourceMappingURL=subscribers-6x4xw39Z.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscribers-6x4xw39Z.cjs","names":["Logger","filterCirculars","stripAnsi","BuilderComponent","SeparatorSpacingSize","REST","SeedcordError","SeedcordErrorCode","Routes","DiscordAPIError","sendFlags","WebhookUrlMetadataKey","SeedcordError","SeedcordErrorCode","Envapter","Converters","SubscribeMetadataKey","WebhookUrlMetadataKey","BuilderComponent","stripAnsi","BuilderComponent","DiscordAPIError","timestampFromSnowflake","TypedEventEmitter","Logger","paint","SeedcordError","SeedcordErrorCode","PublishDefault","SubscribeMetadataKey"],"sources":["../src/subscribers/Subscriber.ts","../src/subscribers/bases/webhookHelpers.ts","../src/subscribers/bases/WebhookSender.ts","../src/subscribers/bases/WebhookLog.ts","../src/subscribers/decorators/Subscribe.ts","../src/subscribers/decorators/WebhookUrl.ts","../src/subscribers/default/HandledException.ts","../src/subscribers/default/UnknownException.ts","../src/subscribers/Bus.ts"],"sourcesContent":["import { Logger } from '@seedcord/logger';\n\nimport type { SubscriptionKey, AllSubscriptions } from './types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\n\n/**\n * Abstract base class for handling application subscribers.\n *\n * Provides type-safe access to subscribers data and the core framework instance.\n * Extend this class to create custom subscriber handlers.\n *\n * @typeParam KeyOfSubscribers - The specific subscriber type this handler processes\n * @typeParam TCore - The transport's Core\n */\nexport abstract class Subscriber<KeyOfSubscribers extends SubscriptionKey, TCore extends CoreBase> {\n protected readonly logger: Logger;\n\n /**\n * Instantiates the subscriber with event data and core.\n *\n * @param data - The subscriber event data\n * @param core - The core framework instance\n */\n constructor(\n protected readonly data: AllSubscriptions[KeyOfSubscribers],\n protected readonly core: TCore\n ) {\n this.logger = new Logger(this.constructor.name, { channel: 'subscribers' });\n }\n\n /**\n * Executes the subscriber handler logic.\n */\n abstract execute(): Promise<void>;\n}\n","import { filterCirculars, stripAnsi } from '@seedcord/utils';\nimport { SeparatorSpacingSize } from 'discord-api-types/v10';\n\nimport { BuilderComponent } from '@components/Component';\n\nimport type { WebhookFile } from './WebhookSender';\n\nconst DISCORD_WEBHOOK_REGEX = new RegExp(\n String.raw`^https?:\\/\\/(?:canary\\.|ptb\\.)?discord(?:app)?\\.com\\/api\\/webhooks\\/\\d+\\/[\\w$-]+$`\n);\n\nexport function isDiscordWebhookUrl(value: string): boolean {\n return URL.canParse(value) && DISCORD_WEBHOOK_REGEX.test(value);\n}\n\nexport function jsonAttachment(name: string, description: string, data: unknown): WebhookFile {\n const content = filterCirculars(data);\n return { name, description, data: new TextEncoder().encode(JSON.stringify(content, undefined, 2)) };\n}\n\n// the report renders inside a ``` fence, so break any triple-backtick run to keep it from closing early\nexport function neutralizeFences(text: string): string {\n return text.replaceAll('```', '`​`​`');\n}\n\n// stack plus one level of cause, ansi codes stripped since discord won't render them\nexport function errorReport(error: Error): string {\n let report = error.stack ?? `${error.name}: ${error.message}`;\n if (Error.isError(error.cause)) {\n const cause = error.cause.stack ?? `${error.cause.name}: ${error.cause.message}`;\n report += `\\n\\nCaused by:\\n${cause}`;\n }\n const stripped = neutralizeFences(stripAnsi(report));\n // eslint-disable-next-line no-magic-numbers\n return stripped.length > 1800 ? `${stripped.slice(0, 1799)}…` : stripped;\n}\n\nexport class WebhookSeparator extends BuilderComponent<'separator'> {\n constructor() {\n super('separator');\n this.instance.setSpacing(SeparatorSpacingSize.Small).setDivider(true);\n }\n}\n","import { DiscordAPIError, REST } from '@discordjs/rest';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Routes } from 'discord-api-types/v10';\n\nimport type { ReplyFile } from '@seedcord/types';\nimport type { APIMessageTopLevelComponent } from 'discord-api-types/v10';\n\nconst HTTP_NOT_FOUND = 404;\nconst HTTP_UNAUTHORIZED = 401;\n\n/** A file attached to a webhook report. */\nexport interface WebhookFile extends ReplyFile {\n readonly description: string;\n}\n\nexport interface WebhookSendOptions {\n flags: number;\n username: string;\n components: readonly { toJSON(): APIMessageTopLevelComponent }[];\n files?: readonly WebhookFile[] | undefined;\n}\n\n// throws SeedcordError when the url has no webhook id and token\nexport class WebhookSender {\n private readonly rest = new REST();\n private readonly route: `/${string}`;\n\n constructor(url: string) {\n const match = /\\/webhooks\\/(\\d+)\\/([\\w$-]+)$/.exec(url);\n if (!match?.[1] || !match[2]) throw new SeedcordError(SeedcordErrorCode.ConfigWebhookUrlInvalid, ['The url']);\n this.route = Routes.webhook(match[1], match[2]);\n }\n\n // missing means discord answered 404 or 401\n async verify(): Promise<'ok' | 'missing' | 'unreachable'> {\n try {\n await this.rest.get(this.route, { auth: false });\n return 'ok';\n } catch (error) {\n const gone =\n error instanceof DiscordAPIError &&\n (error.status === HTTP_NOT_FOUND || error.status === HTTP_UNAUTHORIZED);\n return gone ? 'missing' : 'unreachable';\n }\n }\n\n async send(options: WebhookSendOptions): Promise<void> {\n const { flags, username, components, files } = options;\n await this.rest.post(this.route, {\n auth: false,\n // with_components=true makes discord accept a components-v2 payload. wait=true makes it\n // return payload errors in the response\n query: new URLSearchParams({ with_components: 'true', wait: 'true' }),\n body: {\n flags,\n username,\n components: components.map((component) => component.toJSON()),\n ...(files?.length && {\n attachments: files.map((file, id) => ({ id, filename: file.name, description: file.description }))\n })\n },\n ...(files?.length && { files: files.map((file) => ({ name: file.name, data: file.data })) })\n });\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport chalk from 'chalk';\nimport { Converters, Envapter } from 'envapt';\n\nimport { sendFlags } from '@reply/flags';\nimport { WebhookUrlMetadataKey } from '@src/metadataKeys';\n\nimport { Subscriber } from '../Subscriber';\nimport { isDiscordWebhookUrl } from './webhookHelpers';\nimport { WebhookSender } from './WebhookSender';\n\nimport type { WebhookFile } from './WebhookSender';\nimport type { SubscriptionKey } from '../types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { APIMessageTopLevelComponent } from 'discord-api-types/v10';\n\n/**\n * The content a reporter returns from {@link WebhookLog.report}.\n */\nexport interface WebhookReport {\n /** Shown as the webhook message author. Defaults to the reporter's class name. */\n username?: string;\n components: readonly { toJSON(): APIMessageTopLevelComponent }[];\n files?: readonly WebhookFile[] | undefined;\n}\n\n/**\n * Base class for subscribers that deliver their event to a Discord webhook.\n *\n * Declare the url's environment variable with `@WebhookUrl` and implement {@link report}. Url\n * resolution, validation, sender reuse, and sending run in the base. When the variable is unset\n * the reporter is skipped at registration with a boot warning.\n *\n * @typeParam KeyOfSubscribers - The subscription key this reporter receives\n * @typeParam TCore - The transport's Core\n */\nexport abstract class WebhookLog<KeyOfSubscribers extends SubscriptionKey, TCore extends CoreBase> extends Subscriber<\n KeyOfSubscribers,\n TCore\n> {\n private static readonly senders = new Map<string, WebhookSender>();\n\n /** Builds the message for one published event. */\n abstract report(): WebhookReport | Promise<WebhookReport>;\n\n async execute(): Promise<void> {\n const url = WebhookLog.urlOf(WebhookLog.envKeyOf(this.constructor));\n if (url === null) {\n // a server host skips url-less reporters at registration, an edge host registers lazily and reaches this branch\n this.logger.warn(`${chalk.bold(this.constructor.name)} has no webhook url set, this reporter is disabled`);\n return;\n }\n\n const { username, components, files } = await this.report();\n try {\n await WebhookLog.senderFor(url).send({\n flags: sendFlags({ ephemeral: false }),\n username: username ?? this.constructor.name,\n components,\n files\n });\n } catch (error) {\n this.logger.error('Failed to send webhook report', error);\n }\n }\n\n /** @internal */\n static senderFor(url: string): WebhookSender {\n let sender = WebhookLog.senders.get(url);\n if (!sender) {\n sender = new WebhookSender(url);\n WebhookLog.senders.set(url, sender);\n }\n return sender;\n }\n\n /** @internal */\n static envKeyOf(ctor: NewableFunction): string {\n const envKey = Reflect.getMetadata(WebhookUrlMetadataKey, ctor) as string | undefined;\n if (!envKey) throw new SeedcordError(SeedcordErrorCode.DecoratorWebhookUrlMissing, [ctor.name]);\n return envKey;\n }\n\n /** @internal Returns null when the env var is unset, throws when set but malformed. */\n static urlOf(envKey: string): string | null {\n if (!Envapter.has(envKey)) return null;\n const raw = Envapter.getRequired(envKey, Converters.String).trim();\n if (raw === '') return null;\n if (!isDiscordWebhookUrl(raw)) throw new SeedcordError(SeedcordErrorCode.ConfigWebhookUrlInvalid, [envKey]);\n return raw;\n }\n}\n","// the default reporters are decorated at Bus module load, before any entry's own polyfill import runs\nimport 'reflect-metadata';\n\nimport { SubscribeMetadataKey } from '@src/metadataKeys';\n\nimport type { Subscriber } from '../Subscriber';\nimport type { SubscriptionKey } from '../types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { EventFrequency } from '@seedcord/types';\nimport type { Constructor } from 'type-fest';\n\n/**\n * Options accepted by the `@Subscribe` decorator.\n */\nexport interface SubscribeOptions {\n /**\n * Frequency: `'once'` or `'on'`.\n *\n * @defaultValue `'on'`\n */\n readonly frequency?: EventFrequency | undefined;\n}\n\n/** @internal */\nexport interface SubscribeMetadataEntry {\n readonly subscriber: SubscriptionKey;\n readonly frequency?: EventFrequency | undefined;\n}\n\n/**\n * Registers a subscriber handler class with a specific subscriber event.\n *\n * Associates the decorated class with a subscriber event type for automatic\n * registration and execution when the subscriber is emitted.\n *\n * @typeParam TSubscriber - The subscriber event name to register for\n * @param subscriber - The subscriber event name to register for\n * @param options - Options to configure the subscriber handler registration.\n * @decorator\n * @example\n * ```typescript\n * \\@Subscribe('userJoin')\n * class WelcomeHandler extends Subscriber<'userJoin'> {\n * async execute() {\n * }\n * }\n * ```\n * @example\n * ```ts\n * \\@Subscribe('userJoin', { frequency: 'once' })\n * // or\n * \\@Subscribe('userJoin')\n * ```\n */\nexport function Subscribe<TSubscriber extends SubscriptionKey>(subscriber: TSubscriber, options?: SubscribeOptions) {\n return function <HandlerCtor extends Constructor<Subscriber<TSubscriber, CoreBase>>>(\n constructor: HandlerCtor\n ): void {\n const meta: SubscribeMetadataEntry = {\n subscriber,\n frequency: options?.frequency\n };\n\n Reflect.defineMetadata(SubscribeMetadataKey, meta, constructor);\n };\n}\n","import 'reflect-metadata';\n\nimport { WebhookUrlMetadataKey } from '@src/metadataKeys';\n\nimport type { WebhookLog } from '../bases/WebhookLog';\nimport type { SubscriptionKey } from '../types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { Constructor } from 'type-fest';\n\n/**\n * Declares the environment variable a {@link WebhookLog} reporter reads its webhook url from.\n *\n * An unset variable disables the reporter with a boot warning. A set but malformed value throws\n * at boot.\n *\n * @param envKey - The environment variable name holding the webhook url\n * @decorator\n * @example\n * ```ts\n * \\@Subscribe('memberBanned')\n * \\@WebhookUrl('BAN_LOG_WEBHOOK_URL')\n * class BanLog extends WebhookLog<'memberBanned'> {\n * report() {\n * return { components: [new BanCard(this.data).component] };\n * }\n * }\n * ```\n */\nexport function WebhookUrl(envKey: string) {\n return function <HandlerCtor extends Constructor<WebhookLog<SubscriptionKey, CoreBase>>>(\n constructor: HandlerCtor\n ): void {\n Reflect.defineMetadata(WebhookUrlMetadataKey, envKey, constructor);\n };\n}\n","import { stripAnsi } from '@seedcord/utils';\n\nimport { BuilderComponent } from '@components/Component';\n\nimport { jsonAttachment, neutralizeFences, WebhookSeparator } from '../bases/webhookHelpers';\nimport { WebhookLog } from '../bases/WebhookLog';\nimport { Subscribe } from '../decorators/Subscribe';\nimport { WebhookUrl } from '../decorators/WebhookUrl';\n\nimport type { WebhookReport } from '../bases/WebhookLog';\nimport type { AllSubscriptions, FaultSource } from '../types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { Notice } from '@stops/Notice';\n\n// FaultThrottle drops repeat faults before they reach this subscriber\n// no HANDLED_EXCEPTION_WEBHOOK_URL disables the reporter with a boot warning\n@Subscribe('handledException')\n@WebhookUrl('HANDLED_EXCEPTION_WEBHOOK_URL')\nexport class HandledException extends WebhookLog<'handledException', CoreBase> {\n report(): WebhookReport {\n return {\n username: 'Handled Exception',\n components: [new HandledExceptionContainer(this.data).component],\n files: [jsonAttachment('source.json', 'The raw source the fault came from', this.data.source.raw)]\n };\n }\n}\n\nclass HandledExceptionContainer extends BuilderComponent<'container'> {\n constructor(data: AllSubscriptions['handledException']) {\n super('container');\n\n const { denial, uuid, source } = data;\n\n this.instance\n .addTextDisplayComponents((text) => text.setContent(faultSummary(denial, source)))\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) =>\n text.setContent(`### UUID \\`${uuid}\\`\\n\\`\\`\\`${neutralizeFences(causeStack(denial))}\\`\\`\\``)\n )\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) => text.setContent('### Source'))\n .addFileComponents((file) => file.setURL('attachment://source.json'));\n }\n}\n\nfunction faultSummary(denial: Notice, source: FaultSource): string {\n // name and message carry chalk codes that the webhook payload would otherwise render raw\n const head = stripAnsi(`### A handled fault was reported: \\`${denial.name}\\`\\n**Message:** ${denial.message}\\n`);\n if (source.kind === 'event') {\n return (\n `${head}**Event:** ${source.eventName}\\n` +\n `**Handler:** ${source.handler}\\n` +\n `**User ID:** \\`${source.userId ?? 'n/a'}\\`\\n` +\n `**Guild ID:** \\`${source.guildId ?? 'n/a'}\\`\\n` +\n `**Channel ID:** \\`${source.channelId ?? 'n/a'}\\``\n );\n }\n return (\n `${head}**Kind:** ${source.interactionKind}\\n` +\n `**Command:** ${source.command ?? 'n/a'}\\n` +\n `**CustomId:** ${source.customId ?? 'n/a'}\\n` +\n `**User ID:** \\`${source.userId}\\`\\n` +\n `**Guild ID:** \\`${source.guildId ?? 'n/a'}\\`\\n` +\n `**Channel ID:** \\`${source.channelId ?? 'n/a'}\\`\\n` +\n `**Interaction ID:** \\`${source.interactionId}\\``\n );\n}\n\n// every cause shape returns a string, so building the report never throws on a bigint or circular cause\nfunction causeStack(denial: Notice): string {\n const { cause } = denial;\n if (Error.isError(cause)) return stripAnsi(cause.stack ?? cause.message);\n if (typeof cause === 'string') return stripAnsi(cause);\n if (typeof cause === 'bigint' || typeof cause === 'symbol' || typeof cause === 'function') return cause.toString();\n if (cause !== undefined) {\n try {\n return JSON.stringify(cause);\n } catch {\n return '[unserializable cause]';\n }\n }\n return stripAnsi(denial.stack ?? 'No cause recorded.');\n}\n","import { DiscordAPIError } from '@discordjs/rest';\nimport { timestampFromSnowflake } from '@seedcord/utils';\n\nimport { BuilderComponent } from '@components/Component';\n\nimport { errorReport, jsonAttachment, WebhookSeparator } from '../bases/webhookHelpers';\nimport { WebhookLog } from '../bases/WebhookLog';\nimport { Subscribe } from '../decorators/Subscribe';\nimport { WebhookUrl } from '../decorators/WebhookUrl';\n\nimport type { WebhookReport } from '../bases/WebhookLog';\nimport type { AllSubscriptions } from '../types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\n\n// no UNKNOWN_EXCEPTION_WEBHOOK_URL disables the reporter with a boot warning\n@Subscribe('unknownException')\n@WebhookUrl('UNKNOWN_EXCEPTION_WEBHOOK_URL')\nexport class UnknownException extends WebhookLog<'unknownException', CoreBase> {\n report(): WebhookReport {\n const { metadata } = this.data;\n return {\n username: 'Unknown Exception',\n components: [new UnhandledErrorContainer(this.data).component],\n files: metadata\n ? [jsonAttachment('metadata.json', 'Metadata associated with the error', metadata)]\n : undefined\n };\n }\n}\n\nclass UnhandledErrorContainer extends BuilderComponent<'container'> {\n constructor(data: AllSubscriptions['unknownException']) {\n super('container');\n\n const { uuid, error, guild, user, metadata } = data;\n\n this.instance\n .addTextDisplayComponents((text) =>\n text.setContent(\n `### An unknown exception was thrown\\n` +\n `**Guild ID:** \\`${guild?.id ?? 'Not used in a guild'}\\`\\n` +\n `**Guild Name:** ${guild?.name ?? 'Not used in a guild'}\\n` +\n `**User ID:** \\`${user?.id ?? 'Missing user info'}\\`\\n` +\n `**Username:** ${user?.username ?? 'Missing user info'}\\n`\n )\n )\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) =>\n text.setContent(`### UUID \\`${uuid}\\`\\n\\`\\`\\`${errorReport(error)}\\`\\`\\``)\n );\n\n this.addTimestampsIfAvailable(error);\n this.addMetadataIfAvailable(metadata);\n }\n\n private addTimestampsIfAvailable(error: Error): void {\n if (!(error instanceof DiscordAPIError)) return;\n\n const now = Date.now();\n\n const snowflake = error.url.match(/\\/interactions\\/(\\d+)\\//)?.[1];\n if (!snowflake) return undefined;\n\n const interactionTs = timestampFromSnowflake(snowflake);\n\n const diff = now - interactionTs;\n const seconds = Math.floor(diff / 1000);\n const millis = diff % 1000;\n\n this.instance\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) =>\n text.setContent(\n `### Timestamps\\n` +\n `- **\\`Interaction sent\\` :** ${new Date(interactionTs).toISOString()} (${interactionTs})\\n` +\n `- **\\`Error logged \\` :** ${new Date(now).toISOString()} (${now})\\n` +\n `- **\\`Offset \\` :** ${seconds}s ${millis}ms`\n )\n );\n }\n\n private addMetadataIfAvailable(metadata: unknown): void {\n if (!metadata) return;\n\n this.instance\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) => text.setContent('### Metadata'))\n .addFileComponents((file) => file.setURL('attachment://metadata.json'));\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { TypedEventEmitter } from '@seedcord/event-emitter';\nimport { Logger, paint } from '@seedcord/logger';\nimport chalk from 'chalk';\n\nimport { SubscribeMetadataKey } from '@src/metadataKeys';\n\nimport { WebhookLog } from './bases/WebhookLog';\nimport { HandledException } from './default/HandledException';\nimport { UnknownException } from './default/UnknownException';\nimport { PublishDefault } from './publishDefault';\n\nimport type { SubscribeMetadataEntry } from './decorators/Subscribe';\nimport type { Subscriber } from './Subscriber';\nimport type {\n AllSubscriptions,\n DefaultSubscriptions,\n PublishableKey,\n SubscriptionKey,\n SubscriptionTuples\n} from './types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { EventFrequency } from '@seedcord/types';\n\n/**\n * Both parameters are `never` because construct-signature parameters check contravariantly, and a\n * concrete subscriber narrows each to its own payload and transport `Core`. One cast at dispatch\n * restores both.\n *\n * @internal\n */\nexport type StoredSubscriberCtor = new (data: never, core: never) => Subscriber<SubscriptionKey, CoreBase>;\n\n/**\n * `resolve` is lazy so an edge host registers from a manifest row without importing the module\n * until that key first publishes.\n *\n * @internal\n */\nexport interface SubscriberRegistration {\n readonly keys: readonly SubscriptionKey[];\n readonly frequency: EventFrequency;\n readonly resolve: () => StoredSubscriberCtor | Promise<StoredSubscriberCtor>;\n /** A server-host registration carries it from the start. A lazy one fills it on first resolve. */\n ctor?: StoredSubscriberCtor | undefined;\n}\n\n/**\n * Registers and dispatches subscribers. Subscribers run on a programmatic or framework publish.\n * Accessed via `core.bus`. Do not construct it directly.\n */\nexport class Bus extends TypedEventEmitter<SubscriptionTuples> {\n /** @internal */\n public readonly logger = new Logger('Subscribers', { channel: 'subscribers' });\n\n private readonly subscribersMap = new Map<SubscriptionKey, SubscriberRegistration[]>();\n private readonly executedOnce = new Set<SubscriberRegistration>();\n // url -> env keys, filled as reporters register and read once by verifyWebhooks\n private readonly webhookProbes = new Map<string, string[]>();\n\n constructor(protected core: CoreBase) {\n super();\n }\n\n /** @internal the host calls this during startup, keeping the url validation inside `start()` where a failure can still release the singleton guard. */\n public registerDefaults(): void {\n this.register(registrationFor(UnknownException));\n this.register(registrationFor(HandledException));\n }\n\n /** @internal */\n public register(registration: SubscriberRegistration): void {\n // a url-less reporter never registers. a publish on its key reaches nothing\n if (registration.ctor && !this.probeWebhook(registration.ctor)) return;\n\n for (const key of registration.keys) {\n let registrations = this.subscribersMap.get(key);\n if (!registrations) {\n registrations = [];\n this.subscribersMap.set(key, registrations);\n }\n registrations.push(registration);\n }\n }\n\n /** @internal */\n public unregister(ctor: StoredSubscriberCtor, keys?: readonly SubscriptionKey[]): void {\n for (const key of keys ?? [...this.subscribersMap.keys()]) {\n const registrations = this.subscribersMap.get(key);\n if (!registrations) continue;\n const index = registrations.findIndex((entry) => entry.ctor === ctor);\n if (index !== -1) registrations.splice(index, 1);\n }\n // the once state hangs off the registration identity, which is why a restored subscriber runs again\n }\n\n /** @internal */\n public get registeredCount(): number {\n return [...this.subscribersMap.values()].reduce((total, entries) => total + entries.length, 0);\n }\n\n /** @internal Only eagerly registered reporters are probed, which is every server-host one. */\n public async verifyWebhooks(): Promise<void> {\n const missing: string[] = [];\n await Promise.all(\n [...this.webhookProbes].map(async ([url, envKeys]) => {\n const result = await WebhookLog.senderFor(url).verify();\n if (result === 'missing') missing.push(...envKeys);\n else if (result === 'unreachable')\n this.logger.warn(`could not verify webhook at ${paint.sky.bold(envKeys.join(', '))}`);\n })\n );\n // collected first so the first boot names every missing webhook at once\n if (missing.length > 0) throw new SeedcordError(SeedcordErrorCode.ConfigWebhookNotFound, [missing.join(', ')]);\n }\n\n // true means the class registers\n private probeWebhook(ctor: StoredSubscriberCtor): boolean {\n if (!(ctor.prototype instanceof WebhookLog)) return true;\n\n const envKey = WebhookLog.envKeyOf(ctor);\n const url = WebhookLog.urlOf(envKey);\n if (url === null) {\n this.logger.warn(`${chalk.bold(ctor.name)} disabled, ${paint.sky.bold(envKey)} is not set`);\n return false;\n }\n const envKeys = this.webhookProbes.get(url) ?? [];\n if (!envKeys.includes(envKey)) envKeys.push(envKey);\n this.webhookProbes.set(url, envKeys);\n return true;\n }\n\n /**\n * Publishes an event to its subscribers and native listeners.\n *\n * Fire-and-forget. Subscriber handlers run asynchronously and this returns before they finish. A\n * caller cannot assume a side effect has completed. Errors thrown by a subscriber or by an `on()`\n * listener are caught and logged, never surfaced here. One throwing listener does not stop the\n * others. Subscribers on one key run concurrently and carry no ordering guarantee. A `'once'`\n * subscriber is marked as executed when it starts, even if it throws. It never runs twice.\n *\n * The framework's own keys are excluded. Subscribe to those and listen with `on`. The framework\n * is their only publisher.\n *\n * @param event - The subscription key to publish\n * @param data - Payload passed to each subscriber\n * @returns Whether the underlying emitter had native listeners for the event\n */\n public publish<KeyOfSubscribers extends PublishableKey>(\n event: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): boolean {\n return this.dispatchKey(event, data);\n }\n\n /** @internal the framework's own publish path, keyed by a symbol no public entry exports */\n public [PublishDefault]<KeyOfSubscribers extends keyof DefaultSubscriptions>(\n event: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): boolean {\n return this.dispatchKey(event, data);\n }\n\n private dispatchKey<KeyOfSubscribers extends SubscriptionKey>(\n event: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): boolean {\n void this.processSubscriber(event, data);\n // justified: a generic key can't reduce SubscriptionTuples[K], but data is this event's payload by the signature\n return this.emitSafe(event, ...([data] as SubscriptionTuples[KeyOfSubscribers]));\n }\n\n protected override onListenerError(error: unknown, event: string | symbol): void {\n this.logger.error(`listener for ${String(event)} threw`, error);\n }\n\n private async processSubscriber<KeyOfSubscribers extends SubscriptionKey>(\n subscriberName: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): Promise<void> {\n const registrations = this.subscribersMap.get(subscriberName);\n if (!registrations) return;\n\n const pending = registrations.reduce<Promise<void>[]>((acc, entry) => {\n if (entry.frequency === 'once') {\n if (this.executedOnce.has(entry)) return acc;\n // mark before awaiting, so a re-entrant publish can't run a 'once' subscriber twice mid-flight\n this.executedOnce.add(entry);\n }\n acc.push(this.runSubscriber(entry, subscriberName, data));\n return acc;\n }, []);\n\n await Promise.allSettled(pending);\n }\n\n private async runSubscriber<KeyOfSubscribers extends SubscriptionKey>(\n entry: SubscriberRegistration,\n subscriberName: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): Promise<void> {\n // named outside the try so the catch can say which subscriber threw. several run per key\n let name = '<unresolved>';\n try {\n entry.ctor ??= await entry.resolve();\n // the registration keys each subscriber to its subscriptions, so data matches this ctor's payload arm\n const Ctor = entry.ctor as new (\n data: AllSubscriptions[KeyOfSubscribers],\n core: CoreBase\n ) => Subscriber<KeyOfSubscribers, CoreBase>;\n name = Ctor.name;\n await new Ctor(data, this.core).execute();\n } catch (err) {\n this.logger.error(`Error in subscriber ${String(subscriberName)} handler ${paint.sky.bold(name)}:`, err);\n }\n }\n}\n\n// every caller has already gated on the Subscribe metadata being there\n/** @internal */\nexport function registrationFor(ctor: StoredSubscriberCtor): SubscriberRegistration {\n const meta = Reflect.getMetadata(SubscribeMetadataKey, ctor) as SubscribeMetadataEntry;\n return { keys: [meta.subscriber], frequency: meta.frequency ?? 'on', resolve: () => ctor, ctor };\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { h as WebhookUrlMetadataKey, i as BuilderComponent, m as SubscribeMetadataKey, r as sendFlags, t as PublishDefault } from "./publishDefault-CldnxcT2.mjs";
1
+ import { h as WebhookUrlMetadataKey, i as BuilderComponent, m as SubscribeMetadataKey, r as sendFlags, t as PublishDefault } from "./publishDefault-BCrMG9T8.mjs";
2
2
  import "reflect-metadata";
3
3
  import { Logger, paint } from "@seedcord/logger";
4
4
  import { Routes, SeparatorSpacingSize } from "discord-api-types/v10";
@@ -54,7 +54,6 @@ function jsonAttachment(name, description, data) {
54
54
  function neutralizeFences(text) {
55
55
  return text.replaceAll("```", "`​`​`");
56
56
  }
57
- /** An error's stack with its direct cause appended (one level), ANSI-stripped for the webhook payload. */
58
57
  function errorReport(error) {
59
58
  let report = error.stack ?? `${error.name}: ${error.message}`;
60
59
  if (Error.isError(error.cause)) {
@@ -75,11 +74,6 @@ var WebhookSeparator = class extends BuilderComponent {
75
74
  //#region src/subscribers/bases/WebhookSender.ts
76
75
  const HTTP_NOT_FOUND = 404;
77
76
  const HTTP_UNAUTHORIZED = 401;
78
- /**
79
- * Sends component messages to a Discord webhook through `@discordjs/rest`.
80
- *
81
- * @throws A `SeedcordError` when the url does not carry a webhook id and token.
82
- */
83
77
  var WebhookSender = class {
84
78
  rest = new REST();
85
79
  route;
@@ -88,10 +82,6 @@ var WebhookSender = class {
88
82
  if (!match?.[1] || !match[2]) throw new SeedcordError(SeedcordErrorCode.ConfigWebhookUrlInvalid, ["The url"]);
89
83
  this.route = Routes.webhook(match[1], match[2]);
90
84
  }
91
- /**
92
- * Fetches the webhook object, sending no message. Returns `missing` on a 404 or 401 from
93
- * Discord and `unreachable` on any other failure.
94
- */
95
85
  async verify() {
96
86
  try {
97
87
  await this.rest.get(this.route, { auth: false });
@@ -200,7 +190,6 @@ var WebhookLog = class WebhookLog extends Subscriber {
200
190
  * \@Subscribe('userJoin')
201
191
  * class WelcomeHandler extends Subscriber<'userJoin'> {
202
192
  * async execute() {
203
- * // Handle user join event
204
193
  * }
205
194
  * }
206
195
  * ```
@@ -349,12 +338,7 @@ var Bus = class extends TypedEventEmitter {
349
338
  super();
350
339
  this.core = core;
351
340
  }
352
- /**
353
- * Registers the two shipped webhook reporters. The host calls this during startup, keeping the
354
- * url validation inside `start()` where a failure can still release the singleton guard.
355
- *
356
- * @internal
357
- */
341
+ /** @internal the host calls this during startup, keeping the url validation inside `start()` where a failure can still release the singleton guard. */
358
342
  registerDefaults() {
359
343
  this.register(registrationFor(UnknownException));
360
344
  this.register(registrationFor(HandledException));
@@ -394,7 +378,6 @@ var Bus = class extends TypedEventEmitter {
394
378
  }));
395
379
  if (missing.length > 0) throw new SeedcordError(SeedcordErrorCode.ConfigWebhookNotFound, [missing.join(", ")]);
396
380
  }
397
- /** Returns whether the class should register. */
398
381
  probeWebhook(ctor) {
399
382
  if (!(ctor.prototype instanceof WebhookLog)) return true;
400
383
  const envKey = WebhookLog.envKeyOf(ctor);
@@ -411,12 +394,11 @@ var Bus = class extends TypedEventEmitter {
411
394
  /**
412
395
  * Publishes an event to its subscribers and native listeners.
413
396
  *
414
- * Fire-and-forget, so subscriber handlers run asynchronously and this returns before they
415
- * complete, and callers must not assume side effects have completed. Errors thrown by a subscriber
416
- * or by an `on()` listener are caught and logged, never surfaced here. One throwing listener
417
- * does not stop the others. Subscribers on one key run concurrently and carry no ordering
418
- * guarantee. A `'once'` subscriber is marked as executed when it starts (even if it throws), so
419
- * it never runs twice.
397
+ * Fire-and-forget. Subscriber handlers run asynchronously and this returns before they finish. A
398
+ * caller cannot assume a side effect has completed. Errors thrown by a subscriber or by an `on()`
399
+ * listener are caught and logged, never surfaced here. One throwing listener does not stop the
400
+ * others. Subscribers on one key run concurrently and carry no ordering guarantee. A `'once'`
401
+ * subscriber is marked as executed when it starts, even if it throws. It never runs twice.
420
402
  *
421
403
  * The framework's own keys are excluded. Subscribe to those and listen with `on`. The framework
422
404
  * is their only publisher.
@@ -477,4 +459,4 @@ function registrationFor(ctor) {
477
459
 
478
460
  //#endregion
479
461
  export { WebhookLog as a, Subscribe as i, registrationFor as n, Subscriber as o, WebhookUrl as r, Bus as t };
480
- //# sourceMappingURL=subscribers-xO6DZ-70.mjs.map
462
+ //# sourceMappingURL=subscribers-nEpbJj3Z.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscribers-nEpbJj3Z.mjs","names":[],"sources":["../src/subscribers/Subscriber.ts","../src/subscribers/bases/webhookHelpers.ts","../src/subscribers/bases/WebhookSender.ts","../src/subscribers/bases/WebhookLog.ts","../src/subscribers/decorators/Subscribe.ts","../src/subscribers/decorators/WebhookUrl.ts","../src/subscribers/default/HandledException.ts","../src/subscribers/default/UnknownException.ts","../src/subscribers/Bus.ts"],"sourcesContent":["import { Logger } from '@seedcord/logger';\n\nimport type { SubscriptionKey, AllSubscriptions } from './types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\n\n/**\n * Abstract base class for handling application subscribers.\n *\n * Provides type-safe access to subscribers data and the core framework instance.\n * Extend this class to create custom subscriber handlers.\n *\n * @typeParam KeyOfSubscribers - The specific subscriber type this handler processes\n * @typeParam TCore - The transport's Core\n */\nexport abstract class Subscriber<KeyOfSubscribers extends SubscriptionKey, TCore extends CoreBase> {\n protected readonly logger: Logger;\n\n /**\n * Instantiates the subscriber with event data and core.\n *\n * @param data - The subscriber event data\n * @param core - The core framework instance\n */\n constructor(\n protected readonly data: AllSubscriptions[KeyOfSubscribers],\n protected readonly core: TCore\n ) {\n this.logger = new Logger(this.constructor.name, { channel: 'subscribers' });\n }\n\n /**\n * Executes the subscriber handler logic.\n */\n abstract execute(): Promise<void>;\n}\n","import { filterCirculars, stripAnsi } from '@seedcord/utils';\nimport { SeparatorSpacingSize } from 'discord-api-types/v10';\n\nimport { BuilderComponent } from '@components/Component';\n\nimport type { WebhookFile } from './WebhookSender';\n\nconst DISCORD_WEBHOOK_REGEX = new RegExp(\n String.raw`^https?:\\/\\/(?:canary\\.|ptb\\.)?discord(?:app)?\\.com\\/api\\/webhooks\\/\\d+\\/[\\w$-]+$`\n);\n\nexport function isDiscordWebhookUrl(value: string): boolean {\n return URL.canParse(value) && DISCORD_WEBHOOK_REGEX.test(value);\n}\n\nexport function jsonAttachment(name: string, description: string, data: unknown): WebhookFile {\n const content = filterCirculars(data);\n return { name, description, data: new TextEncoder().encode(JSON.stringify(content, undefined, 2)) };\n}\n\n// the report renders inside a ``` fence, so break any triple-backtick run to keep it from closing early\nexport function neutralizeFences(text: string): string {\n return text.replaceAll('```', '`​`​`');\n}\n\n// stack plus one level of cause, ansi codes stripped since discord won't render them\nexport function errorReport(error: Error): string {\n let report = error.stack ?? `${error.name}: ${error.message}`;\n if (Error.isError(error.cause)) {\n const cause = error.cause.stack ?? `${error.cause.name}: ${error.cause.message}`;\n report += `\\n\\nCaused by:\\n${cause}`;\n }\n const stripped = neutralizeFences(stripAnsi(report));\n // eslint-disable-next-line no-magic-numbers\n return stripped.length > 1800 ? `${stripped.slice(0, 1799)}…` : stripped;\n}\n\nexport class WebhookSeparator extends BuilderComponent<'separator'> {\n constructor() {\n super('separator');\n this.instance.setSpacing(SeparatorSpacingSize.Small).setDivider(true);\n }\n}\n","import { DiscordAPIError, REST } from '@discordjs/rest';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Routes } from 'discord-api-types/v10';\n\nimport type { ReplyFile } from '@seedcord/types';\nimport type { APIMessageTopLevelComponent } from 'discord-api-types/v10';\n\nconst HTTP_NOT_FOUND = 404;\nconst HTTP_UNAUTHORIZED = 401;\n\n/** A file attached to a webhook report. */\nexport interface WebhookFile extends ReplyFile {\n readonly description: string;\n}\n\nexport interface WebhookSendOptions {\n flags: number;\n username: string;\n components: readonly { toJSON(): APIMessageTopLevelComponent }[];\n files?: readonly WebhookFile[] | undefined;\n}\n\n// throws SeedcordError when the url has no webhook id and token\nexport class WebhookSender {\n private readonly rest = new REST();\n private readonly route: `/${string}`;\n\n constructor(url: string) {\n const match = /\\/webhooks\\/(\\d+)\\/([\\w$-]+)$/.exec(url);\n if (!match?.[1] || !match[2]) throw new SeedcordError(SeedcordErrorCode.ConfigWebhookUrlInvalid, ['The url']);\n this.route = Routes.webhook(match[1], match[2]);\n }\n\n // missing means discord answered 404 or 401\n async verify(): Promise<'ok' | 'missing' | 'unreachable'> {\n try {\n await this.rest.get(this.route, { auth: false });\n return 'ok';\n } catch (error) {\n const gone =\n error instanceof DiscordAPIError &&\n (error.status === HTTP_NOT_FOUND || error.status === HTTP_UNAUTHORIZED);\n return gone ? 'missing' : 'unreachable';\n }\n }\n\n async send(options: WebhookSendOptions): Promise<void> {\n const { flags, username, components, files } = options;\n await this.rest.post(this.route, {\n auth: false,\n // with_components=true makes discord accept a components-v2 payload. wait=true makes it\n // return payload errors in the response\n query: new URLSearchParams({ with_components: 'true', wait: 'true' }),\n body: {\n flags,\n username,\n components: components.map((component) => component.toJSON()),\n ...(files?.length && {\n attachments: files.map((file, id) => ({ id, filename: file.name, description: file.description }))\n })\n },\n ...(files?.length && { files: files.map((file) => ({ name: file.name, data: file.data })) })\n });\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport chalk from 'chalk';\nimport { Converters, Envapter } from 'envapt';\n\nimport { sendFlags } from '@reply/flags';\nimport { WebhookUrlMetadataKey } from '@src/metadataKeys';\n\nimport { Subscriber } from '../Subscriber';\nimport { isDiscordWebhookUrl } from './webhookHelpers';\nimport { WebhookSender } from './WebhookSender';\n\nimport type { WebhookFile } from './WebhookSender';\nimport type { SubscriptionKey } from '../types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { APIMessageTopLevelComponent } from 'discord-api-types/v10';\n\n/**\n * The content a reporter returns from {@link WebhookLog.report}.\n */\nexport interface WebhookReport {\n /** Shown as the webhook message author. Defaults to the reporter's class name. */\n username?: string;\n components: readonly { toJSON(): APIMessageTopLevelComponent }[];\n files?: readonly WebhookFile[] | undefined;\n}\n\n/**\n * Base class for subscribers that deliver their event to a Discord webhook.\n *\n * Declare the url's environment variable with `@WebhookUrl` and implement {@link report}. Url\n * resolution, validation, sender reuse, and sending run in the base. When the variable is unset\n * the reporter is skipped at registration with a boot warning.\n *\n * @typeParam KeyOfSubscribers - The subscription key this reporter receives\n * @typeParam TCore - The transport's Core\n */\nexport abstract class WebhookLog<KeyOfSubscribers extends SubscriptionKey, TCore extends CoreBase> extends Subscriber<\n KeyOfSubscribers,\n TCore\n> {\n private static readonly senders = new Map<string, WebhookSender>();\n\n /** Builds the message for one published event. */\n abstract report(): WebhookReport | Promise<WebhookReport>;\n\n async execute(): Promise<void> {\n const url = WebhookLog.urlOf(WebhookLog.envKeyOf(this.constructor));\n if (url === null) {\n // a server host skips url-less reporters at registration, an edge host registers lazily and reaches this branch\n this.logger.warn(`${chalk.bold(this.constructor.name)} has no webhook url set, this reporter is disabled`);\n return;\n }\n\n const { username, components, files } = await this.report();\n try {\n await WebhookLog.senderFor(url).send({\n flags: sendFlags({ ephemeral: false }),\n username: username ?? this.constructor.name,\n components,\n files\n });\n } catch (error) {\n this.logger.error('Failed to send webhook report', error);\n }\n }\n\n /** @internal */\n static senderFor(url: string): WebhookSender {\n let sender = WebhookLog.senders.get(url);\n if (!sender) {\n sender = new WebhookSender(url);\n WebhookLog.senders.set(url, sender);\n }\n return sender;\n }\n\n /** @internal */\n static envKeyOf(ctor: NewableFunction): string {\n const envKey = Reflect.getMetadata(WebhookUrlMetadataKey, ctor) as string | undefined;\n if (!envKey) throw new SeedcordError(SeedcordErrorCode.DecoratorWebhookUrlMissing, [ctor.name]);\n return envKey;\n }\n\n /** @internal Returns null when the env var is unset, throws when set but malformed. */\n static urlOf(envKey: string): string | null {\n if (!Envapter.has(envKey)) return null;\n const raw = Envapter.getRequired(envKey, Converters.String).trim();\n if (raw === '') return null;\n if (!isDiscordWebhookUrl(raw)) throw new SeedcordError(SeedcordErrorCode.ConfigWebhookUrlInvalid, [envKey]);\n return raw;\n }\n}\n","// the default reporters are decorated at Bus module load, before any entry's own polyfill import runs\nimport 'reflect-metadata';\n\nimport { SubscribeMetadataKey } from '@src/metadataKeys';\n\nimport type { Subscriber } from '../Subscriber';\nimport type { SubscriptionKey } from '../types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { EventFrequency } from '@seedcord/types';\nimport type { Constructor } from 'type-fest';\n\n/**\n * Options accepted by the `@Subscribe` decorator.\n */\nexport interface SubscribeOptions {\n /**\n * Frequency: `'once'` or `'on'`.\n *\n * @defaultValue `'on'`\n */\n readonly frequency?: EventFrequency | undefined;\n}\n\n/** @internal */\nexport interface SubscribeMetadataEntry {\n readonly subscriber: SubscriptionKey;\n readonly frequency?: EventFrequency | undefined;\n}\n\n/**\n * Registers a subscriber handler class with a specific subscriber event.\n *\n * Associates the decorated class with a subscriber event type for automatic\n * registration and execution when the subscriber is emitted.\n *\n * @typeParam TSubscriber - The subscriber event name to register for\n * @param subscriber - The subscriber event name to register for\n * @param options - Options to configure the subscriber handler registration.\n * @decorator\n * @example\n * ```typescript\n * \\@Subscribe('userJoin')\n * class WelcomeHandler extends Subscriber<'userJoin'> {\n * async execute() {\n * }\n * }\n * ```\n * @example\n * ```ts\n * \\@Subscribe('userJoin', { frequency: 'once' })\n * // or\n * \\@Subscribe('userJoin')\n * ```\n */\nexport function Subscribe<TSubscriber extends SubscriptionKey>(subscriber: TSubscriber, options?: SubscribeOptions) {\n return function <HandlerCtor extends Constructor<Subscriber<TSubscriber, CoreBase>>>(\n constructor: HandlerCtor\n ): void {\n const meta: SubscribeMetadataEntry = {\n subscriber,\n frequency: options?.frequency\n };\n\n Reflect.defineMetadata(SubscribeMetadataKey, meta, constructor);\n };\n}\n","import 'reflect-metadata';\n\nimport { WebhookUrlMetadataKey } from '@src/metadataKeys';\n\nimport type { WebhookLog } from '../bases/WebhookLog';\nimport type { SubscriptionKey } from '../types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { Constructor } from 'type-fest';\n\n/**\n * Declares the environment variable a {@link WebhookLog} reporter reads its webhook url from.\n *\n * An unset variable disables the reporter with a boot warning. A set but malformed value throws\n * at boot.\n *\n * @param envKey - The environment variable name holding the webhook url\n * @decorator\n * @example\n * ```ts\n * \\@Subscribe('memberBanned')\n * \\@WebhookUrl('BAN_LOG_WEBHOOK_URL')\n * class BanLog extends WebhookLog<'memberBanned'> {\n * report() {\n * return { components: [new BanCard(this.data).component] };\n * }\n * }\n * ```\n */\nexport function WebhookUrl(envKey: string) {\n return function <HandlerCtor extends Constructor<WebhookLog<SubscriptionKey, CoreBase>>>(\n constructor: HandlerCtor\n ): void {\n Reflect.defineMetadata(WebhookUrlMetadataKey, envKey, constructor);\n };\n}\n","import { stripAnsi } from '@seedcord/utils';\n\nimport { BuilderComponent } from '@components/Component';\n\nimport { jsonAttachment, neutralizeFences, WebhookSeparator } from '../bases/webhookHelpers';\nimport { WebhookLog } from '../bases/WebhookLog';\nimport { Subscribe } from '../decorators/Subscribe';\nimport { WebhookUrl } from '../decorators/WebhookUrl';\n\nimport type { WebhookReport } from '../bases/WebhookLog';\nimport type { AllSubscriptions, FaultSource } from '../types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { Notice } from '@stops/Notice';\n\n// FaultThrottle drops repeat faults before they reach this subscriber\n// no HANDLED_EXCEPTION_WEBHOOK_URL disables the reporter with a boot warning\n@Subscribe('handledException')\n@WebhookUrl('HANDLED_EXCEPTION_WEBHOOK_URL')\nexport class HandledException extends WebhookLog<'handledException', CoreBase> {\n report(): WebhookReport {\n return {\n username: 'Handled Exception',\n components: [new HandledExceptionContainer(this.data).component],\n files: [jsonAttachment('source.json', 'The raw source the fault came from', this.data.source.raw)]\n };\n }\n}\n\nclass HandledExceptionContainer extends BuilderComponent<'container'> {\n constructor(data: AllSubscriptions['handledException']) {\n super('container');\n\n const { denial, uuid, source } = data;\n\n this.instance\n .addTextDisplayComponents((text) => text.setContent(faultSummary(denial, source)))\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) =>\n text.setContent(`### UUID \\`${uuid}\\`\\n\\`\\`\\`${neutralizeFences(causeStack(denial))}\\`\\`\\``)\n )\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) => text.setContent('### Source'))\n .addFileComponents((file) => file.setURL('attachment://source.json'));\n }\n}\n\nfunction faultSummary(denial: Notice, source: FaultSource): string {\n // name and message carry chalk codes that the webhook payload would otherwise render raw\n const head = stripAnsi(`### A handled fault was reported: \\`${denial.name}\\`\\n**Message:** ${denial.message}\\n`);\n if (source.kind === 'event') {\n return (\n `${head}**Event:** ${source.eventName}\\n` +\n `**Handler:** ${source.handler}\\n` +\n `**User ID:** \\`${source.userId ?? 'n/a'}\\`\\n` +\n `**Guild ID:** \\`${source.guildId ?? 'n/a'}\\`\\n` +\n `**Channel ID:** \\`${source.channelId ?? 'n/a'}\\``\n );\n }\n return (\n `${head}**Kind:** ${source.interactionKind}\\n` +\n `**Command:** ${source.command ?? 'n/a'}\\n` +\n `**CustomId:** ${source.customId ?? 'n/a'}\\n` +\n `**User ID:** \\`${source.userId}\\`\\n` +\n `**Guild ID:** \\`${source.guildId ?? 'n/a'}\\`\\n` +\n `**Channel ID:** \\`${source.channelId ?? 'n/a'}\\`\\n` +\n `**Interaction ID:** \\`${source.interactionId}\\``\n );\n}\n\n// every cause shape returns a string, so building the report never throws on a bigint or circular cause\nfunction causeStack(denial: Notice): string {\n const { cause } = denial;\n if (Error.isError(cause)) return stripAnsi(cause.stack ?? cause.message);\n if (typeof cause === 'string') return stripAnsi(cause);\n if (typeof cause === 'bigint' || typeof cause === 'symbol' || typeof cause === 'function') return cause.toString();\n if (cause !== undefined) {\n try {\n return JSON.stringify(cause);\n } catch {\n return '[unserializable cause]';\n }\n }\n return stripAnsi(denial.stack ?? 'No cause recorded.');\n}\n","import { DiscordAPIError } from '@discordjs/rest';\nimport { timestampFromSnowflake } from '@seedcord/utils';\n\nimport { BuilderComponent } from '@components/Component';\n\nimport { errorReport, jsonAttachment, WebhookSeparator } from '../bases/webhookHelpers';\nimport { WebhookLog } from '../bases/WebhookLog';\nimport { Subscribe } from '../decorators/Subscribe';\nimport { WebhookUrl } from '../decorators/WebhookUrl';\n\nimport type { WebhookReport } from '../bases/WebhookLog';\nimport type { AllSubscriptions } from '../types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\n\n// no UNKNOWN_EXCEPTION_WEBHOOK_URL disables the reporter with a boot warning\n@Subscribe('unknownException')\n@WebhookUrl('UNKNOWN_EXCEPTION_WEBHOOK_URL')\nexport class UnknownException extends WebhookLog<'unknownException', CoreBase> {\n report(): WebhookReport {\n const { metadata } = this.data;\n return {\n username: 'Unknown Exception',\n components: [new UnhandledErrorContainer(this.data).component],\n files: metadata\n ? [jsonAttachment('metadata.json', 'Metadata associated with the error', metadata)]\n : undefined\n };\n }\n}\n\nclass UnhandledErrorContainer extends BuilderComponent<'container'> {\n constructor(data: AllSubscriptions['unknownException']) {\n super('container');\n\n const { uuid, error, guild, user, metadata } = data;\n\n this.instance\n .addTextDisplayComponents((text) =>\n text.setContent(\n `### An unknown exception was thrown\\n` +\n `**Guild ID:** \\`${guild?.id ?? 'Not used in a guild'}\\`\\n` +\n `**Guild Name:** ${guild?.name ?? 'Not used in a guild'}\\n` +\n `**User ID:** \\`${user?.id ?? 'Missing user info'}\\`\\n` +\n `**Username:** ${user?.username ?? 'Missing user info'}\\n`\n )\n )\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) =>\n text.setContent(`### UUID \\`${uuid}\\`\\n\\`\\`\\`${errorReport(error)}\\`\\`\\``)\n );\n\n this.addTimestampsIfAvailable(error);\n this.addMetadataIfAvailable(metadata);\n }\n\n private addTimestampsIfAvailable(error: Error): void {\n if (!(error instanceof DiscordAPIError)) return;\n\n const now = Date.now();\n\n const snowflake = error.url.match(/\\/interactions\\/(\\d+)\\//)?.[1];\n if (!snowflake) return undefined;\n\n const interactionTs = timestampFromSnowflake(snowflake);\n\n const diff = now - interactionTs;\n const seconds = Math.floor(diff / 1000);\n const millis = diff % 1000;\n\n this.instance\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) =>\n text.setContent(\n `### Timestamps\\n` +\n `- **\\`Interaction sent\\` :** ${new Date(interactionTs).toISOString()} (${interactionTs})\\n` +\n `- **\\`Error logged \\` :** ${new Date(now).toISOString()} (${now})\\n` +\n `- **\\`Offset \\` :** ${seconds}s ${millis}ms`\n )\n );\n }\n\n private addMetadataIfAvailable(metadata: unknown): void {\n if (!metadata) return;\n\n this.instance\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) => text.setContent('### Metadata'))\n .addFileComponents((file) => file.setURL('attachment://metadata.json'));\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { TypedEventEmitter } from '@seedcord/event-emitter';\nimport { Logger, paint } from '@seedcord/logger';\nimport chalk from 'chalk';\n\nimport { SubscribeMetadataKey } from '@src/metadataKeys';\n\nimport { WebhookLog } from './bases/WebhookLog';\nimport { HandledException } from './default/HandledException';\nimport { UnknownException } from './default/UnknownException';\nimport { PublishDefault } from './publishDefault';\n\nimport type { SubscribeMetadataEntry } from './decorators/Subscribe';\nimport type { Subscriber } from './Subscriber';\nimport type {\n AllSubscriptions,\n DefaultSubscriptions,\n PublishableKey,\n SubscriptionKey,\n SubscriptionTuples\n} from './types/Subscriptions';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { EventFrequency } from '@seedcord/types';\n\n/**\n * Both parameters are `never` because construct-signature parameters check contravariantly, and a\n * concrete subscriber narrows each to its own payload and transport `Core`. One cast at dispatch\n * restores both.\n *\n * @internal\n */\nexport type StoredSubscriberCtor = new (data: never, core: never) => Subscriber<SubscriptionKey, CoreBase>;\n\n/**\n * `resolve` is lazy so an edge host registers from a manifest row without importing the module\n * until that key first publishes.\n *\n * @internal\n */\nexport interface SubscriberRegistration {\n readonly keys: readonly SubscriptionKey[];\n readonly frequency: EventFrequency;\n readonly resolve: () => StoredSubscriberCtor | Promise<StoredSubscriberCtor>;\n /** A server-host registration carries it from the start. A lazy one fills it on first resolve. */\n ctor?: StoredSubscriberCtor | undefined;\n}\n\n/**\n * Registers and dispatches subscribers. Subscribers run on a programmatic or framework publish.\n * Accessed via `core.bus`. Do not construct it directly.\n */\nexport class Bus extends TypedEventEmitter<SubscriptionTuples> {\n /** @internal */\n public readonly logger = new Logger('Subscribers', { channel: 'subscribers' });\n\n private readonly subscribersMap = new Map<SubscriptionKey, SubscriberRegistration[]>();\n private readonly executedOnce = new Set<SubscriberRegistration>();\n // url -> env keys, filled as reporters register and read once by verifyWebhooks\n private readonly webhookProbes = new Map<string, string[]>();\n\n constructor(protected core: CoreBase) {\n super();\n }\n\n /** @internal the host calls this during startup, keeping the url validation inside `start()` where a failure can still release the singleton guard. */\n public registerDefaults(): void {\n this.register(registrationFor(UnknownException));\n this.register(registrationFor(HandledException));\n }\n\n /** @internal */\n public register(registration: SubscriberRegistration): void {\n // a url-less reporter never registers. a publish on its key reaches nothing\n if (registration.ctor && !this.probeWebhook(registration.ctor)) return;\n\n for (const key of registration.keys) {\n let registrations = this.subscribersMap.get(key);\n if (!registrations) {\n registrations = [];\n this.subscribersMap.set(key, registrations);\n }\n registrations.push(registration);\n }\n }\n\n /** @internal */\n public unregister(ctor: StoredSubscriberCtor, keys?: readonly SubscriptionKey[]): void {\n for (const key of keys ?? [...this.subscribersMap.keys()]) {\n const registrations = this.subscribersMap.get(key);\n if (!registrations) continue;\n const index = registrations.findIndex((entry) => entry.ctor === ctor);\n if (index !== -1) registrations.splice(index, 1);\n }\n // the once state hangs off the registration identity, which is why a restored subscriber runs again\n }\n\n /** @internal */\n public get registeredCount(): number {\n return [...this.subscribersMap.values()].reduce((total, entries) => total + entries.length, 0);\n }\n\n /** @internal Only eagerly registered reporters are probed, which is every server-host one. */\n public async verifyWebhooks(): Promise<void> {\n const missing: string[] = [];\n await Promise.all(\n [...this.webhookProbes].map(async ([url, envKeys]) => {\n const result = await WebhookLog.senderFor(url).verify();\n if (result === 'missing') missing.push(...envKeys);\n else if (result === 'unreachable')\n this.logger.warn(`could not verify webhook at ${paint.sky.bold(envKeys.join(', '))}`);\n })\n );\n // collected first so the first boot names every missing webhook at once\n if (missing.length > 0) throw new SeedcordError(SeedcordErrorCode.ConfigWebhookNotFound, [missing.join(', ')]);\n }\n\n // true means the class registers\n private probeWebhook(ctor: StoredSubscriberCtor): boolean {\n if (!(ctor.prototype instanceof WebhookLog)) return true;\n\n const envKey = WebhookLog.envKeyOf(ctor);\n const url = WebhookLog.urlOf(envKey);\n if (url === null) {\n this.logger.warn(`${chalk.bold(ctor.name)} disabled, ${paint.sky.bold(envKey)} is not set`);\n return false;\n }\n const envKeys = this.webhookProbes.get(url) ?? [];\n if (!envKeys.includes(envKey)) envKeys.push(envKey);\n this.webhookProbes.set(url, envKeys);\n return true;\n }\n\n /**\n * Publishes an event to its subscribers and native listeners.\n *\n * Fire-and-forget. Subscriber handlers run asynchronously and this returns before they finish. A\n * caller cannot assume a side effect has completed. Errors thrown by a subscriber or by an `on()`\n * listener are caught and logged, never surfaced here. One throwing listener does not stop the\n * others. Subscribers on one key run concurrently and carry no ordering guarantee. A `'once'`\n * subscriber is marked as executed when it starts, even if it throws. It never runs twice.\n *\n * The framework's own keys are excluded. Subscribe to those and listen with `on`. The framework\n * is their only publisher.\n *\n * @param event - The subscription key to publish\n * @param data - Payload passed to each subscriber\n * @returns Whether the underlying emitter had native listeners for the event\n */\n public publish<KeyOfSubscribers extends PublishableKey>(\n event: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): boolean {\n return this.dispatchKey(event, data);\n }\n\n /** @internal the framework's own publish path, keyed by a symbol no public entry exports */\n public [PublishDefault]<KeyOfSubscribers extends keyof DefaultSubscriptions>(\n event: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): boolean {\n return this.dispatchKey(event, data);\n }\n\n private dispatchKey<KeyOfSubscribers extends SubscriptionKey>(\n event: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): boolean {\n void this.processSubscriber(event, data);\n // justified: a generic key can't reduce SubscriptionTuples[K], but data is this event's payload by the signature\n return this.emitSafe(event, ...([data] as SubscriptionTuples[KeyOfSubscribers]));\n }\n\n protected override onListenerError(error: unknown, event: string | symbol): void {\n this.logger.error(`listener for ${String(event)} threw`, error);\n }\n\n private async processSubscriber<KeyOfSubscribers extends SubscriptionKey>(\n subscriberName: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): Promise<void> {\n const registrations = this.subscribersMap.get(subscriberName);\n if (!registrations) return;\n\n const pending = registrations.reduce<Promise<void>[]>((acc, entry) => {\n if (entry.frequency === 'once') {\n if (this.executedOnce.has(entry)) return acc;\n // mark before awaiting, so a re-entrant publish can't run a 'once' subscriber twice mid-flight\n this.executedOnce.add(entry);\n }\n acc.push(this.runSubscriber(entry, subscriberName, data));\n return acc;\n }, []);\n\n await Promise.allSettled(pending);\n }\n\n private async runSubscriber<KeyOfSubscribers extends SubscriptionKey>(\n entry: SubscriberRegistration,\n subscriberName: KeyOfSubscribers,\n data: AllSubscriptions[KeyOfSubscribers]\n ): Promise<void> {\n // named outside the try so the catch can say which subscriber threw. several run per key\n let name = '<unresolved>';\n try {\n entry.ctor ??= await entry.resolve();\n // the registration keys each subscriber to its subscriptions, so data matches this ctor's payload arm\n const Ctor = entry.ctor as new (\n data: AllSubscriptions[KeyOfSubscribers],\n core: CoreBase\n ) => Subscriber<KeyOfSubscribers, CoreBase>;\n name = Ctor.name;\n await new Ctor(data, this.core).execute();\n } catch (err) {\n this.logger.error(`Error in subscriber ${String(subscriberName)} handler ${paint.sky.bold(name)}:`, err);\n }\n }\n}\n\n// every caller has already gated on the Subscribe metadata being there\n/** @internal */\nexport function registrationFor(ctor: StoredSubscriberCtor): SubscriberRegistration {\n const meta = Reflect.getMetadata(SubscribeMetadataKey, ctor) as SubscribeMetadataEntry;\n return { keys: [meta.subscriber], frequency: meta.frequency ?? 'on', resolve: () => ctor, ctor };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@seedcord/core",
3
3
  "type": "module",
4
- "version": "0.1.1",
4
+ "version": "0.1.3-next.0",
5
5
  "engines": {
6
6
  "node": ">=24.11"
7
7
  },
@@ -71,7 +71,6 @@
71
71
  "LICENSE"
72
72
  ],
73
73
  "peerDependencies": {
74
- "reflect-metadata": "^0.2.2",
75
74
  "typescript": "^6.0.3"
76
75
  },
77
76
  "dependencies": {
@@ -80,18 +79,18 @@
80
79
  "chalk": "^6.0.0",
81
80
  "discord-api-types": "^0.38.52",
82
81
  "envapt": "^8.1.1",
83
- "@seedcord/errors": "0.3.1",
84
- "@seedcord/event-emitter": "0.1.1",
85
- "@seedcord/logger": "0.1.1",
86
- "@seedcord/types": "0.8.1",
87
- "@seedcord/utils": "0.8.1"
82
+ "reflect-metadata": "^0.2.2",
83
+ "@seedcord/errors": "0.3.3-next.0",
84
+ "@seedcord/event-emitter": "0.1.2",
85
+ "@seedcord/logger": "0.1.3-next.0",
86
+ "@seedcord/types": "0.8.2",
87
+ "@seedcord/utils": "0.8.3-next.0"
88
88
  },
89
89
  "devDependencies": {
90
- "reflect-metadata": "^0.2.2",
91
90
  "type-fest": "^5.8.0",
92
91
  "vite": "^8.2.0",
93
- "@seedcord/eslint-config": "1.5.1",
94
- "@seedcord/rate-limiter": "0.1.1",
92
+ "@seedcord/eslint-config": "1.5.2",
93
+ "@seedcord/rate-limiter": "0.1.2",
95
94
  "@seedcord/tsconfig": "2.0.2",
96
95
  "@seedcord/tsdown-config": "2.0.1",
97
96
  "@seedcord/vitest-config": "0.0.1"