@seedcord/core 0.4.1 → 0.5.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 (34) hide show
  1. package/dist/{Bus-yJGE6Fs2.mjs → Bus-dGy6xq3F.mjs} +43 -40
  2. package/dist/Bus-dGy6xq3F.mjs.map +1 -0
  3. package/dist/{Pluggable-bFCmT4oB.d.mts → Pluggable-BKe2uCa0.d.mts} +3 -3
  4. package/dist/{Pluggable-BI_LQuPm.mjs → Pluggable-CtMiOP3p.mjs} +3 -3
  5. package/dist/{Pluggable-BI_LQuPm.mjs.map → Pluggable-CtMiOP3p.mjs.map} +1 -1
  6. package/dist/{Plugin-B0SRHzMX.mjs → Plugin-BJfRk0s_.mjs} +3 -3
  7. package/dist/{Plugin-B0SRHzMX.mjs.map → Plugin-BJfRk0s_.mjs.map} +1 -1
  8. package/dist/{Plugin-BW2JH2_h.d.mts → Plugin-iAaWcLaD.d.mts} +2 -2
  9. package/dist/{cursor-CO_MTgdZ.d.mts → cursor-8Y2zpF-Y.d.mts} +4 -25
  10. package/dist/{cursor-CaT051ii.mjs → cursor-BkI9lxy2.mjs} +6 -29
  11. package/dist/cursor-BkI9lxy2.mjs.map +1 -0
  12. package/dist/{index-CvneCObW.d.mts → index-CD8l15aZ.d.mts} +2 -2
  13. package/dist/index.d.mts +97 -16
  14. package/dist/index.mjs +111 -14
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/internal.index.d.mts +13 -6
  17. package/dist/internal.index.mjs +11 -11
  18. package/dist/internal.index.mjs.map +1 -1
  19. package/dist/node-internal.index.d.mts +4 -4
  20. package/dist/node-internal.index.mjs +5 -5
  21. package/dist/node.index.d.mts +1 -1
  22. package/dist/node.index.mjs +1 -1
  23. package/dist/{phases-C5Steaa2.d.mts → phases-D0a8BV9Z.d.mts} +10 -7
  24. package/dist/plugin.index.d.mts +1 -1
  25. package/dist/plugin.index.mjs +1 -1
  26. package/dist/{publishDefault-D826XXDQ.mjs → publishDefault-BuSZPbjT.mjs} +2 -2
  27. package/dist/{publishDefault-D826XXDQ.mjs.map → publishDefault-BuSZPbjT.mjs.map} +1 -1
  28. package/dist/{slashRouteLeaves-BQmbFm-S.mjs → slashRouteLeaves-C1msUE9Q.mjs} +2 -2
  29. package/dist/{slashRouteLeaves-BQmbFm-S.mjs.map → slashRouteLeaves-C1msUE9Q.mjs.map} +1 -1
  30. package/dist/{subscribers-DVa-Pr45.mjs → subscribers-A8lNU5yM.mjs} +2 -2
  31. package/dist/{subscribers-DVa-Pr45.mjs.map → subscribers-A8lNU5yM.mjs.map} +1 -1
  32. package/package.json +7 -7
  33. package/dist/Bus-yJGE6Fs2.mjs.map +0 -1
  34. package/dist/cursor-CaT051ii.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"internal.index.mjs","names":["logger"],"sources":["../src/decorators/brands.ts","../src/gates/runGates.ts","../src/gates/slowGate.ts","../src/miscellaneous/emojiConfig.ts","../src/hmr/wrapHot.ts","../src/hmr/HmrManager.ts","../src/dispatch/dispatchReport.ts"],"sourcesContent":["// A handler base declares these so a route decorator can read what the handler is for. Nothing\n// assigns them at runtime.\n\nexport const SlashRouteBrand: unique symbol = Symbol('seedcord:brand:slashRoute');\nexport const AutocompleteRouteBrand: unique symbol = Symbol('seedcord:brand:autocompleteRoute');\nexport const ContextMenuKindBrand: unique symbol = Symbol('seedcord:brand:contextMenuKind');\nexport const ContextMenuNamesBrand: unique symbol = Symbol('seedcord:brand:contextMenuNames');\nexport const ComponentKindBrand: unique symbol = Symbol('seedcord:brand:componentKind');\nexport const ComponentDefsBrand: unique symbol = Symbol('seedcord:brand:componentDefs');\n","import 'reflect-metadata';\n\nimport { GatedMetadataKey, InteractionRouteKeys } from '#src/metadataKeys';\n\nimport { discardCommits, runCheck, runCommits } from './effects';\n\nimport type { Gate, GateContextBase } from './Gate';\n\n// a combinator (`and`/`or`) reports once under its joined name.\nexport type GateObserver = (gateName: string, elapsedMs: number) => void;\n\n// the stable id a route decorator stored, e.g. slash:daily or button:confirm. null for a plain event handler.\nexport function routeIdOf(handlerCtor: object): string | null {\n for (const [kind, key] of Object.entries(InteractionRouteKeys)) {\n // justified: getMetadata returns any, this key only ever stores the route/prefix string array\n const routes = Reflect.getMetadata(key, handlerCtor) as string[] | undefined;\n if (routes?.length) return `${kind}:${routes.join(',')}`;\n }\n return null;\n}\n\nasync function timedCheck(gate: Gate<GateContextBase>, ctx: GateContextBase, observe: GateObserver): Promise<void> {\n const start = performance.now();\n // finally so a refusing gate still reports\n try {\n await runCheck(gate, ctx);\n } finally {\n observe(gate.name, performance.now() - start);\n }\n}\n\n// the first refusal throws out to the dispatcher boundary. an effect gate's commit runs once the\n// whole set passes, and observe never times the commit phase.\nexport async function runGates(\n gates: readonly Gate<GateContextBase>[],\n ctx: GateContextBase,\n observe?: GateObserver\n): Promise<void> {\n try {\n for (const gate of gates) {\n await (observe ? timedCheck(gate, ctx, observe) : runCheck(gate, ctx));\n }\n await runCommits(ctx);\n } finally {\n discardCommits(ctx);\n }\n}\n\n// dispatchers call this before execute, inside the boundary, so a refusal renders or drops. an explicit\n// routeId is for manifest-driven handlers, which carry no route metadata to derive one from.\nexport async function runHandlerGates(\n handlerCtor: object,\n ctx: GateContextBase,\n routeId?: string,\n observe?: GateObserver\n): Promise<void> {\n // justified: getMetadata returns any, and this key only ever stores the @Gated gate array\n const gates = Reflect.getMetadata(GatedMetadataKey, handlerCtor) as readonly Gate<GateContextBase>[] | undefined;\n if (!gates) return;\n await runGates(gates, { ...ctx, routeId: routeId ?? routeIdOf(handlerCtor) }, observe);\n}\n","import { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\nimport { Envapter } from 'envapt';\n\nimport type { GateObserver } from './runGates';\n\n// combined check time slower than this cuts into the 3s interaction-ack budget\nconst SLOW_GATE_MS = 750;\n\n// lazy because the logger reads the environment, which binds after this module loads\nlet gateLogger: Logger | undefined;\nfunction logger(): Logger {\n gateLogger ??= new Logger('Gates', { channel: 'gates' });\n return gateLogger;\n}\n\n/**\n * collects each gate check's elapsed time for one dispatch. `report` warns once when the checks sum\n * past the threshold, naming the total, the route, and each gate's share.\n */\nexport interface SlowGateMonitor {\n readonly observe: GateObserver;\n report(routeId: string | null): void;\n}\n\n// undefined in production, so timedCheck skips the clock there. read per call, the environment binds late\nexport function slowGateMonitor(): SlowGateMonitor | undefined {\n if (Envapter.isProduction) return undefined;\n const readings: { name: string; ms: number }[] = [];\n return {\n observe: (name, ms) => readings.push({ name, ms }),\n report(routeId) {\n const total = readings.reduce((sum, reading) => sum + reading.ms, 0);\n if (total < SLOW_GATE_MS) return;\n const shares = readings\n .toSorted((a, b) => b.ms - a.ms)\n .map((reading) => `${paint.sky.bold(reading.name)} ${paint.mute(`${Math.round(reading.ms)}ms`)}`);\n const route = routeId === null ? '' : ` for ${paint.sky.bold(routeId)}`;\n const headline = `gates${route} took ${paint.amber(`${Math.round(total)}ms`)} of the 3s ack budget`;\n logger().utils.block(headline, shares, 'warn', (text) => text);\n }\n };\n}\n","// narrows a configured emoji value to the [name, guildId] form\nexport function isEmojiTuple(value: unknown): value is readonly [string, string] {\n return Array.isArray(value) && value.length === 2 && typeof value[0] === 'string' && typeof value[1] === 'string';\n}\n","import type { DevChannel } from '@seedcord/types/internal';\n\n// the minimal raw-hot shape, satisfied by both vite's `import.meta.hot` and the CLI's `NormalizedHotChannel`.\ninterface RawHot {\n send(event: string, data?: unknown): void;\n on(event: string, cb: (data: unknown) => void): void;\n}\n\n/** @internal */\nexport function wrapHot<TSend, TRecv>(hot: RawHot): DevChannel<TSend, TRecv> {\n return {\n send: (event, data) => hot.send(event, data),\n // justified: RawHot types every payload as unknown, and the wire contract guarantees it matches TRecv[Key]\n on: (event, cb) => hot.on(event, cb as (data: unknown) => void)\n };\n}\n","// scoped here so import.meta.hot stays untyped in the rest of the package\n/// <reference types=\"vite/client\" />\nimport { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\nimport { Envapter } from 'envapt';\n\nimport { setDevChannel } from './devChannel';\nimport { wrapHot } from './wrapHot';\n\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types';\nimport type { SeedcordCliEvents, SeedcordFrameworkEvents } from '@seedcord/types/internal';\n\nexport class HmrManager {\n private readonly logger = new Logger('HMR', { channel: 'hmr' });\n private readonly listeners = new Set<HmrAware>();\n\n /** @internal */\n public init(): void {\n if (!import.meta.hot) return;\n // the only raw `import.meta.hot` read in the framework\n const channel = wrapHot<SeedcordFrameworkEvents, SeedcordCliEvents>(import.meta.hot);\n setDevChannel(channel);\n\n if (Envapter.isDevelopment || Envapter.isTest) {\n this.logger.debug('Enabled');\n channel.on('seedcord:hmr', (payload) => void this.handleUpdate(payload));\n }\n }\n\n /** @internal */\n public register(listener: HmrAware): void {\n this.listeners.add(listener);\n }\n\n private async handleUpdate(event: HmrUpdateEvent): Promise<void> {\n const promises = [...this.listeners].map(async (listener) => {\n try {\n await listener.onHmr(event);\n } catch (error) {\n this.logger.error(`Error handling HMR update in ${paint.sky.bold(listener.constructor.name)}`, error);\n }\n });\n\n await Promise.all(promises);\n }\n}\n","import { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\nimport { timestampFromSnowflake } from '@seedcord/utils';\n\nimport { Notice } from '#stops/Notice';\nimport { Silence } from '#stops/Silence';\nimport { PublishDefault } from '#subscribers/publishDefault';\n\nimport type { InteractionRoutes } from '#src/metadataKeys';\nimport type { Bus } from '#subscribers/Bus';\nimport type { DispatchOutcome } from '#subscribers/types/Subscriptions';\n\nlet dispatchLogger: Logger | undefined;\nfunction logger(): Logger {\n dispatchLogger ??= new Logger('Dispatch', { channel: 'interactions' });\n return dispatchLogger;\n}\n\n/**\n * Classifies a caught stop for `interactionDispatched` so a gate and a\n * handler label the same stop identically.\n *\n * @internal\n */\nexport function outcomeFor(caught: unknown): DispatchOutcome {\n if (caught instanceof Silence) return 'refused';\n if (caught instanceof Notice) return caught.report ? 'failed' : 'refused';\n return 'failed';\n}\n\n/** The values a dispatcher has once its handler chain settles. */\ninterface DispatchReport {\n readonly routeId: string;\n readonly interactionId: string;\n readonly kind: `${InteractionRoutes}`;\n readonly outcome: DispatchOutcome;\n /** True when no route matched and the unhandled default ran. */\n readonly fallback: boolean;\n /** `performance.now()` captured as the dispatch began. */\n readonly startedAt: number;\n /** {@link queuedMsFor} read at the same moment as `startedAt`. */\n readonly queuedMs: number;\n}\n\n/**\n * Discord's interaction creation to now, read from the snowflake. Called at dispatch entry, since\n * a later read would count the handler run into the queue time as well.\n *\n * @internal\n */\nexport function queuedMsFor(interactionId: string): number {\n // telemetry never breaks a dispatch, and BigInt() throws on a malformed id\n try {\n return Date.now() - timestampFromSnowflake(interactionId);\n } catch {\n return 0;\n }\n}\n\nexport function reportDispatch(bus: Bus, report: DispatchReport): void {\n const durationMs = performance.now() - report.startedAt;\n bus[PublishDefault]('interactionDispatched', {\n routeId: report.routeId,\n interactionId: report.interactionId,\n kind: report.kind,\n outcome: report.outcome,\n fallback: report.fallback,\n durationMs,\n queuedMs: report.queuedMs\n });\n\n // after publish so a throwing sink doesn't reach the publish above\n logger().trace(\n `${paint.sky.bold(report.routeId)} ${report.outcome} ${paint.mute('in')} ${Math.round(durationMs)}ms`\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"internal.index.mjs","names":["logger"],"sources":["../src/decorators/brands.ts","../src/gates/runGates.ts","../src/gates/slowGate.ts","../src/miscellaneous/emojiConfig.ts","../src/hmr/wrapHot.ts","../src/hmr/HmrManager.ts","../src/dispatch/dispatchReport.ts"],"sourcesContent":["// A handler base declares these so a route decorator can read what the handler is for. Nothing\n// assigns them at runtime.\n\nexport const SlashRouteBrand: unique symbol = Symbol('seedcord:brand:slash-route');\nexport const AutocompleteRouteBrand: unique symbol = Symbol('seedcord:brand:autocomplete-route');\nexport const ContextMenuKindBrand: unique symbol = Symbol('seedcord:brand:context-menu-kind');\nexport const ContextMenuNamesBrand: unique symbol = Symbol('seedcord:brand:context-menu-names');\nexport const ComponentKindBrand: unique symbol = Symbol('seedcord:brand:component-kind');\nexport const ComponentDefsBrand: unique symbol = Symbol('seedcord:brand:component-defs');\n","import 'reflect-metadata';\n\nimport { GatedMetadataKey, InteractionRouteKeys } from '#src/metadataKeys';\n\nimport { discardCommits, runCheck, runCommits } from './effects';\n\nimport type { Gate, GateContextBase } from './Gate';\n\n// a combinator (`and`/`or`) reports once under its joined name.\nexport type GateObserver = (gateName: string, elapsedMs: number) => void;\n\n// the stable id a route decorator stored, e.g. slash:daily or button:confirm. null for a plain event handler.\nexport function routeIdOf(handlerCtor: object): string | null {\n for (const [kind, key] of Object.entries(InteractionRouteKeys)) {\n // justified: getMetadata returns any, this key only ever stores the route/prefix string array\n const routes = Reflect.getMetadata(key, handlerCtor) as string[] | undefined;\n if (routes?.length) return `${kind}:${routes.join(',')}`;\n }\n return null;\n}\n\nasync function timedCheck(gate: Gate<GateContextBase>, ctx: GateContextBase, observe: GateObserver): Promise<void> {\n const start = performance.now();\n // finally so a refusing gate still reports\n try {\n await runCheck(gate, ctx);\n } finally {\n observe(gate.name, performance.now() - start);\n }\n}\n\n// the first refusal throws out to the dispatcher boundary. an effect gate's commit runs once the\n// whole set passes, and observe never times the commit phase.\nexport async function runGates(\n gates: readonly Gate<GateContextBase>[],\n ctx: GateContextBase,\n observe?: GateObserver\n): Promise<void> {\n try {\n for (const gate of gates) {\n await (observe ? timedCheck(gate, ctx, observe) : runCheck(gate, ctx));\n }\n await runCommits(ctx);\n } finally {\n discardCommits(ctx);\n }\n}\n\n// dispatchers call this before execute, inside the boundary, so a refusal renders or drops. an explicit\n// routeId is for manifest-driven handlers, which carry no route metadata to derive one from.\nexport async function runHandlerGates(\n handlerCtor: object,\n ctx: GateContextBase,\n routeId?: string,\n observe?: GateObserver\n): Promise<void> {\n // justified: getMetadata returns any, and this key only ever stores the @Gated gate array\n const gates = Reflect.getMetadata(GatedMetadataKey, handlerCtor) as readonly Gate<GateContextBase>[] | undefined;\n if (!gates) return;\n await runGates(gates, { ...ctx, routeId: routeId ?? routeIdOf(handlerCtor) }, observe);\n}\n","import { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\nimport { Envapter } from 'envapt';\n\nimport type { GateObserver } from './runGates';\n\n// combined check time slower than this cuts into the 3s interaction-ack budget\nconst SLOW_GATE_MS = 750;\n\n// lazy because the logger reads the environment, which binds after this module loads\nlet gateLogger: Logger | undefined;\nfunction logger(): Logger {\n gateLogger ??= new Logger('Gates', { channel: 'gates' });\n return gateLogger;\n}\n\n/**\n * collects each gate check's elapsed time for one dispatch. `report` warns once when the checks sum\n * past the threshold, naming the total, the route, and each gate's share.\n */\nexport interface SlowGateMonitor {\n readonly observe: GateObserver;\n report(routeId: string | null): void;\n}\n\n// undefined in production, so timedCheck skips the clock there. read per call, the environment binds late\nexport function slowGateMonitor(): SlowGateMonitor | undefined {\n if (Envapter.isProduction) return undefined;\n const readings: { name: string; ms: number }[] = [];\n return {\n observe: (name, ms) => readings.push({ name, ms }),\n report(routeId) {\n const total = readings.reduce((sum, reading) => sum + reading.ms, 0);\n if (total < SLOW_GATE_MS) return;\n const shares = readings\n .toSorted((a, b) => b.ms - a.ms)\n .map((reading) => `${paint.sky.bold(reading.name)} ${paint.mute(`${Math.round(reading.ms)}ms`)}`);\n const route = routeId === null ? '' : ` for ${paint.sky.bold(routeId)}`;\n const headline = `gates${route} took ${paint.amber(`${Math.round(total)}ms`)} of the 3s ack budget`;\n logger().utils.block(headline, shares, 'warn', (text) => text);\n }\n };\n}\n","// narrows a configured emoji value to the [name, guildId] form\nexport function isEmojiTuple(value: unknown): value is readonly [string, string] {\n return Array.isArray(value) && value.length === 2 && typeof value[0] === 'string' && typeof value[1] === 'string';\n}\n","import type { DevChannel } from '@seedcord/types/internal';\n\n// the minimal raw-hot shape, satisfied by both vite's `import.meta.hot` and the CLI's `NormalizedHotChannel`.\ninterface RawHot {\n send(event: string, data?: unknown): void;\n on(event: string, cb: (data: unknown) => void): void;\n}\n\n/** @internal */\nexport function wrapHot<TSend, TRecv>(hot: RawHot): DevChannel<TSend, TRecv> {\n return {\n send: (event, data) => hot.send(event, data),\n // justified: RawHot types every payload as unknown, and the wire contract guarantees it matches TRecv[Key]\n on: (event, cb) => hot.on(event, cb as (data: unknown) => void)\n };\n}\n","// scoped here so import.meta.hot stays untyped in the rest of the package\n/// <reference types=\"vite/client\" />\nimport { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\nimport { Envapter } from 'envapt';\n\nimport { setDevChannel } from './devChannel';\nimport { wrapHot } from './wrapHot';\n\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types';\nimport type { SeedcordCliEvents, SeedcordFrameworkEvents } from '@seedcord/types/internal';\n\nexport class HmrManager {\n private readonly logger = new Logger('HMR', { channel: 'hmr' });\n private readonly listeners = new Set<HmrAware>();\n\n /** @internal */\n public init(): void {\n if (!import.meta.hot) return;\n // the only raw `import.meta.hot` read in the framework\n const channel = wrapHot<SeedcordFrameworkEvents, SeedcordCliEvents>(import.meta.hot);\n setDevChannel(channel);\n\n if (Envapter.isDevelopment || Envapter.isTest) {\n this.logger.debug('Enabled');\n channel.on('seedcord:hmr', (payload) => void this.handleUpdate(payload));\n }\n }\n\n /** @internal */\n public register(listener: HmrAware): void {\n this.listeners.add(listener);\n }\n\n private async handleUpdate(event: HmrUpdateEvent): Promise<void> {\n const promises = [...this.listeners].map(async (listener) => {\n try {\n await listener.onHmr(event);\n } catch (error) {\n this.logger.error(`Error handling HMR update in ${paint.sky.bold(listener.constructor.name)}`, error);\n }\n });\n\n await Promise.all(promises);\n }\n}\n","import { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\nimport { timestampFromSnowflake } from '@seedcord/utils';\n\nimport { Notice } from '#stops/Notice';\nimport { Silence } from '#stops/Silence';\nimport { PublishDefault } from '#subscribers/publishDefault';\n\nimport type { InteractionKind } from '#src/metadataKeys';\nimport type { Bus } from '#subscribers/Bus';\nimport type { DispatchOutcome } from '#subscribers/types/Subscriptions';\n\nlet dispatchLogger: Logger | undefined;\nfunction logger(): Logger {\n dispatchLogger ??= new Logger('Dispatch', { channel: 'interactions' });\n return dispatchLogger;\n}\n\n/**\n * Classifies a caught stop for `interactionDispatched` so a gate and a\n * handler label the same stop identically.\n *\n * @internal\n */\nexport function outcomeFor(caught: unknown): DispatchOutcome {\n if (caught instanceof Silence) return 'refused';\n if (caught instanceof Notice) return caught.report ? 'failed' : 'refused';\n return 'failed';\n}\n\ninterface DispatchReport {\n readonly routeId: string;\n readonly interactionId: string;\n readonly kind: `${InteractionKind}`;\n readonly outcome: DispatchOutcome;\n /** True when no route matched and the unhandled default ran. */\n readonly fallback: boolean;\n /** `performance.now()` captured as the dispatch began. */\n readonly startedAt: number;\n /** {@link queuedMsFor} read at the same moment as `startedAt`. */\n readonly queuedMs: number;\n}\n\n/**\n * Discord's interaction creation to now, read from the snowflake. Called at dispatch entry, since\n * a later read would count the handler run into the queue time as well.\n *\n * @internal\n */\nexport function queuedMsFor(interactionId: string): number {\n // telemetry never breaks a dispatch, and BigInt() throws on a malformed id\n try {\n return Date.now() - timestampFromSnowflake(interactionId);\n } catch {\n return 0;\n }\n}\n\nexport function reportDispatch(bus: Bus, report: DispatchReport): void {\n const durationMs = performance.now() - report.startedAt;\n bus[PublishDefault]('interactionDispatched', {\n routeId: report.routeId,\n interactionId: report.interactionId,\n kind: report.kind,\n outcome: report.outcome,\n fallback: report.fallback,\n durationMs,\n queuedMs: report.queuedMs\n });\n\n // a throwing log sink must not stop the publish above\n logger().trace(\n `${paint.sky.bold(report.routeId)} ${report.outcome} ${paint.mute('in')} ${Math.round(durationMs)}ms`\n );\n}\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
- import { i as Bus, n as StartupPhase, r as CoreBase, t as ShutdownPhase } from "./phases-C5Steaa2.mjs";
1
+ import { i as Bus, n as StartupPhase, r as CoreBase, t as ShutdownPhase } from "./phases-D0a8BV9Z.mjs";
2
2
  import { n as CommandBuilder, r as DeployResult } from "./basic-Dng__Ena.mjs";
3
- import "./index-CvneCObW.mjs";
4
- import { n as Initializeable } from "./Plugin-BW2JH2_h.mjs";
3
+ import "./index-CD8l15aZ.mjs";
4
+ import { n as Initializeable } from "./Plugin-iAaWcLaD.mjs";
5
5
  import { t as ContextMenuLeaves } from "./contextMenuLeaves-COzDYa6c.mjs";
6
- import { a as LifecycleTask, i as CoordinatedShutdown, n as shutdownOf } from "./Pluggable-bFCmT4oB.mjs";
6
+ import { a as LifecycleTask, i as CoordinatedShutdown, n as shutdownOf } from "./Pluggable-BKe2uCa0.mjs";
7
7
  import { Logger } from "@seedcord/logger";
8
8
  import { IncomingMessage, ServerResponse } from "node:http";
9
9
  import { HealthCheckConfig, HealthCheckOption, HmrAware, HmrUpdateEvent } from "@seedcord/types";
@@ -1,11 +1,11 @@
1
- import { C as SubscribeMetadataKey, O as contextMenuLeaves, a as RegisterSubscriber, c as VerifyWebhooks, f as Subscriber, g as CommandMetadataKey, i as RegisterDefaults, n as busLoggerOf, o as RegisteredCount, r as registrationFor, s as UnregisterSubscriber } from "./Bus-yJGE6Fs2.mjs";
2
- import { t as CommandInjector } from "./subscribers-DVa-Pr45.mjs";
3
- import { t as PublishDefault } from "./publishDefault-D826XXDQ.mjs";
1
+ import { C as SubscribeMetadataKey, O as contextMenuLeaves, a as RegisterSubscriber, c as VerifyWebhooks, f as Subscriber, g as CommandMetadataKey, i as RegisterDefaults, n as busLoggerOf, o as RegisteredCount, r as registrationFor, s as UnregisterSubscriber } from "./Bus-dGy6xq3F.mjs";
2
+ import { t as CommandInjector } from "./subscribers-A8lNU5yM.mjs";
3
+ import { t as PublishDefault } from "./publishDefault-BuSZPbjT.mjs";
4
4
  import { n as StartupPhase, t as ShutdownPhase } from "./phases-BauKJOTT.mjs";
5
5
  import { t as getDevChannel } from "./devChannel-CQU7hq7Q.mjs";
6
- import { n as isCommandClass, t as slashRouteLeaves } from "./slashRouteLeaves-BQmbFm-S.mjs";
6
+ import { n as isCommandClass, t as slashRouteLeaves } from "./slashRouteLeaves-C1msUE9Q.mjs";
7
7
  import { t as HmrModuleHandler } from "./HmrModuleHandler-9AUfKXRl.mjs";
8
- import { i as settleWithin, n as shutdownOf, r as assertNodeVersion } from "./Pluggable-BI_LQuPm.mjs";
8
+ import { i as settleWithin, n as shutdownOf, r as assertNodeVersion } from "./Pluggable-CtMiOP3p.mjs";
9
9
  import { SlashCommandBuilder } from "@discordjs/builders";
10
10
  import { Routes } from "discord-api-types/v10";
11
11
  import { SeedcordErrorCode, paint } from "@seedcord/errors";
@@ -1,2 +1,2 @@
1
- import { i as CoordinatedShutdown, r as CoordinatedStartup, t as Pluggable } from "./Pluggable-bFCmT4oB.mjs";
1
+ import { i as CoordinatedShutdown, r as CoordinatedStartup, t as Pluggable } from "./Pluggable-BKe2uCa0.mjs";
2
2
  export { CoordinatedShutdown, CoordinatedStartup, Pluggable };
@@ -1,5 +1,5 @@
1
1
  import { n as StartupPhase, t as ShutdownPhase } from "./phases-BauKJOTT.mjs";
2
- import { a as withTimeout, t as Pluggable } from "./Pluggable-BI_LQuPm.mjs";
2
+ import { a as withTimeout, t as Pluggable } from "./Pluggable-CtMiOP3p.mjs";
3
3
  import { SeedcordErrorCode, paint } from "@seedcord/errors";
4
4
  import { SeedcordAggregateError, SeedcordError, SeedcordTypeError } from "@seedcord/errors/internal";
5
5
  import { Logger } from "@seedcord/logger";
@@ -72,7 +72,10 @@ declare abstract class Notice extends Error {
72
72
  }
73
73
  //#endregion
74
74
  //#region src/metadataKeys.d.ts
75
- declare enum InteractionRoutes {
75
+ /**
76
+ * Every interaction kind seedcord routes.
77
+ */
78
+ declare enum InteractionKind {
76
79
  Slash = "slash",
77
80
  Button = "button",
78
81
  Modal = "modal",
@@ -85,14 +88,14 @@ declare enum InteractionRoutes {
85
88
  UserContextMenu = "userContextMenu",
86
89
  Autocomplete = "autocomplete"
87
90
  }
91
+ declare const CommandMetadataKey: unique symbol;
88
92
  declare const InteractionMetadataKey: unique symbol;
89
- declare const InteractionRouteKeys: Record<InteractionRoutes, symbol>;
90
93
  declare const MiddlewareMetadataKey: unique symbol;
94
+ declare const SubscribeMetadataKey: unique symbol;
91
95
  declare const EventMetadataKey: unique symbol;
92
- declare const CommandMetadataKey: unique symbol;
93
96
  declare const GatedMetadataKey: unique symbol;
94
- declare const SubscribeMetadataKey: unique symbol;
95
97
  declare const WebhookUrlMetadataKey: unique symbol;
98
+ declare const InteractionRouteKeys: Record<InteractionKind, symbol>;
96
99
  //#endregion
97
100
  //#region src/subscribers/publishDefault.d.ts
98
101
  /** @internal PublishableKey excludes this key so publish() never emits it externally. */
@@ -243,7 +246,7 @@ interface DefaultSubscriptions {
243
246
  readonly routeId: string;
244
247
  /** The interaction this dispatch ran, for joining against `responseAttempted`. */
245
248
  readonly interactionId: string;
246
- readonly kind: `${InteractionRoutes}`;
249
+ readonly kind: `${InteractionKind}`;
247
250
  readonly outcome: DispatchOutcome;
248
251
  /** True when no route matched and the unhandled default ran. */
249
252
  readonly fallback: boolean;
@@ -456,5 +459,5 @@ declare enum ShutdownPhase {
456
459
  Logout = 4
457
460
  }
458
461
  //#endregion
459
- export { UnregisterSubscriber as A, SubscribeMetadataKey as B, ReplyMethod as C, RegisterDefaults as D, AckTrace as E, GatedMetadataKey as F, Notice as H, InteractionMetadataKey as I, InteractionRouteKeys as L, PublishDefault as M, CommandMetadataKey as N, RegisterSubscriber as O, EventMetadataKey as P, InteractionRoutes as R, AckState as S, sendTarget as T, WebhookUrlMetadataKey as V, SubscriptionData as _, StoredSubscriberCtor as a, ReplyTelemetry as b, Subscriber as c, DispatchOutcome as d, FaultSource as f, ResponseSent as g, ResponseOutcome as h, Bus as i, VerifyWebhooks as j, RegisteredCount as k, AttemptedWrite as l, ResponseFailed as m, StartupPhase as n, SubscriberRegistration as o, ResponseAttempt as p, CoreBase as r, busLoggerOf as s, ShutdownPhase as t, DefaultSubscriptions as u, SubscriptionKey as v, checkAckLegality as w, reportedWrite as x, Subscriptions as y, MiddlewareMetadataKey as z };
460
- //# sourceMappingURL=phases-C5Steaa2.d.mts.map
462
+ export { UnregisterSubscriber as A, SubscribeMetadataKey as B, ReplyMethod as C, RegisterDefaults as D, AckTrace as E, GatedMetadataKey as F, Notice as H, InteractionKind as I, InteractionMetadataKey as L, PublishDefault as M, CommandMetadataKey as N, RegisterSubscriber as O, EventMetadataKey as P, InteractionRouteKeys as R, AckState as S, sendTarget as T, WebhookUrlMetadataKey as V, SubscriptionData as _, StoredSubscriberCtor as a, ReplyTelemetry as b, Subscriber as c, DispatchOutcome as d, FaultSource as f, ResponseSent as g, ResponseOutcome as h, Bus as i, VerifyWebhooks as j, RegisteredCount as k, AttemptedWrite as l, ResponseFailed as m, StartupPhase as n, SubscriberRegistration as o, ResponseAttempt as p, CoreBase as r, busLoggerOf as s, ShutdownPhase as t, DefaultSubscriptions as u, SubscriptionKey as v, checkAckLegality as w, reportedWrite as x, Subscriptions as y, MiddlewareMetadataKey as z };
463
+ //# sourceMappingURL=phases-D0a8BV9Z.d.mts.map
@@ -1,3 +1,3 @@
1
- import { c as PluginOptions, p as PluginLifecycleSpec, r as Plugin } from "./Plugin-BW2JH2_h.mjs";
1
+ import { c as PluginOptions, p as PluginLifecycleSpec, r as Plugin } from "./Plugin-iAaWcLaD.mjs";
2
2
  import { HmrAware, HmrUpdateEvent } from "@seedcord/types";
3
3
  export { type HmrAware, type HmrUpdateEvent, Plugin, type PluginLifecycleSpec, type PluginOptions };
@@ -1,3 +1,3 @@
1
- import { t as Plugin } from "./Plugin-B0SRHzMX.mjs";
1
+ import { t as Plugin } from "./Plugin-BJfRk0s_.mjs";
2
2
 
3
3
  export { Plugin };
@@ -7,8 +7,8 @@ function asError(caught) {
7
7
  //#endregion
8
8
  //#region src/subscribers/publishDefault.ts
9
9
  /** @internal PublishableKey excludes this key so publish() never emits it externally. */
10
- const PublishDefault = Symbol("seedcord.publishDefault");
10
+ const PublishDefault = Symbol("seedcord:bus:publish-default");
11
11
 
12
12
  //#endregion
13
13
  export { asError as n, PublishDefault as t };
14
- //# sourceMappingURL=publishDefault-D826XXDQ.mjs.map
14
+ //# sourceMappingURL=publishDefault-BuSZPbjT.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"publishDefault-D826XXDQ.mjs","names":[],"sources":["../src/stops/asError.ts","../src/subscribers/publishDefault.ts"],"sourcesContent":["// dropping a non-Error throw would leave the user with no fault card, and every report payload declares an Error\n/** @internal */\nexport function asError(caught: unknown): Error {\n return Error.isError(caught) ? caught : new Error(String(caught), { cause: caught });\n}\n","/** @internal PublishableKey excludes this key so publish() never emits it externally. */\nexport const PublishDefault = Symbol('seedcord.publishDefault');\n"],"mappings":";;AAEA,SAAgB,QAAQ,QAAwB;CAC5C,OAAO,MAAM,QAAQ,MAAM,IAAI,SAAS,IAAI,MAAM,OAAO,MAAM,GAAG,EAAE,OAAO,OAAO,CAAC;AACvF;;;;;ACHA,MAAa,iBAAiB,OAAO,yBAAyB"}
1
+ {"version":3,"file":"publishDefault-BuSZPbjT.mjs","names":[],"sources":["../src/stops/asError.ts","../src/subscribers/publishDefault.ts"],"sourcesContent":["// dropping a non-Error throw would leave the user with no fault card, and every report payload declares an Error\n/** @internal */\nexport function asError(caught: unknown): Error {\n return Error.isError(caught) ? caught : new Error(String(caught), { cause: caught });\n}\n","/** @internal PublishableKey excludes this key so publish() never emits it externally. */\nexport const PublishDefault = Symbol('seedcord:bus:publish-default');\n"],"mappings":";;AAEA,SAAgB,QAAQ,QAAwB;CAC5C,OAAO,MAAM,QAAQ,MAAM,IAAI,SAAS,IAAI,MAAM,OAAO,MAAM,GAAG,EAAE,OAAO,OAAO,CAAC;AACvF;;;;;ACHA,MAAa,iBAAiB,OAAO,8BAA8B"}
@@ -1,4 +1,4 @@
1
- import { g as CommandMetadataKey, j as isBuilderComponentClass } from "./Bus-yJGE6Fs2.mjs";
1
+ import { g as CommandMetadataKey, j as isBuilderComponentClass } from "./Bus-dGy6xq3F.mjs";
2
2
  import { SlashCommandBuilder } from "@discordjs/builders";
3
3
  import { routeLeavesOf } from "@seedcord/utils/internal";
4
4
 
@@ -28,4 +28,4 @@ function slashRouteLeaves(commands) {
28
28
 
29
29
  //#endregion
30
30
  export { isCommandClass as n, slashRouteLeaves as t };
31
- //# sourceMappingURL=slashRouteLeaves-BQmbFm-S.mjs.map
31
+ //# sourceMappingURL=slashRouteLeaves-C1msUE9Q.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"slashRouteLeaves-BQmbFm-S.mjs","names":[],"sources":["../src/commands/isCommandClass.ts","../src/commands/slashRouteLeaves.ts"],"sourcesContent":["import { isBuilderComponentClass } from '#components/Component';\nimport { CommandMetadataKey } from '#src/metadataKeys';\n\nimport type { BuilderComponent } from '#components/Component';\n\n/** @internal */\nexport type CommandCtor = new () => BuilderComponent<'command' | 'context_menu'>;\n\n// the cli's codegen scan reads this too\n/** @internal */\nexport function isCommandClass(value: unknown): value is CommandCtor {\n return isBuilderComponentClass(value) && Reflect.hasMetadata(CommandMetadataKey, value);\n}\n","import { SlashCommandBuilder } from '@discordjs/builders';\nimport { routeLeavesOf } from '@seedcord/utils/internal';\n\nimport type { ContextMenuCommandBuilder } from '@discordjs/builders';\n\n/**\n * dedupes route keys since the same builder appears once per guild.\n * these come from the same {@link routeLeavesOf} that `seedcord codegen` reads, so the boot-time\n * check compares against the generated registry's keys.\n *\n * @internal\n */\nexport function slashRouteLeaves(commands: Iterable<SlashCommandBuilder | ContextMenuCommandBuilder>): Set<string> {\n const leaves = new Set<string>();\n for (const command of commands) {\n if (!(command instanceof SlashCommandBuilder)) continue;\n for (const leaf of routeLeavesOf(command.toJSON())) leaves.add(leaf.route);\n }\n return leaves;\n}\n"],"mappings":";;;;;;AAUA,SAAgB,eAAe,OAAsC;CACjE,OAAO,wBAAwB,KAAK,KAAK,QAAQ,YAAY,oBAAoB,KAAK;AAC1F;;;;;;;;;;;ACAA,SAAgB,iBAAiB,UAAkF;CAC/G,MAAM,yBAAS,IAAI,IAAY;CAC/B,KAAK,MAAM,WAAW,UAAU;EAC5B,IAAI,EAAE,mBAAmB,sBAAsB;EAC/C,KAAK,MAAM,QAAQ,cAAc,QAAQ,OAAO,CAAC,GAAG,OAAO,IAAI,KAAK,KAAK;CAC7E;CACA,OAAO;AACX"}
1
+ {"version":3,"file":"slashRouteLeaves-C1msUE9Q.mjs","names":[],"sources":["../src/commands/isCommandClass.ts","../src/commands/slashRouteLeaves.ts"],"sourcesContent":["import { isBuilderComponentClass } from '#components/Component';\nimport { CommandMetadataKey } from '#src/metadataKeys';\n\nimport type { BuilderComponent } from '#components/Component';\n\n/** @internal */\nexport type CommandCtor = new () => BuilderComponent<'command' | 'context_menu'>;\n\n// the cli's codegen scan reads this too\n/** @internal */\nexport function isCommandClass(value: unknown): value is CommandCtor {\n return isBuilderComponentClass(value) && Reflect.hasMetadata(CommandMetadataKey, value);\n}\n","import { SlashCommandBuilder } from '@discordjs/builders';\nimport { routeLeavesOf } from '@seedcord/utils/internal';\n\nimport type { ContextMenuCommandBuilder } from '@discordjs/builders';\n\n/**\n * dedupes route keys since the same builder appears once per guild.\n * these come from the same {@link routeLeavesOf} that `seedcord codegen` reads, so the boot-time\n * check compares against the generated registry's keys.\n *\n * @internal\n */\nexport function slashRouteLeaves(commands: Iterable<SlashCommandBuilder | ContextMenuCommandBuilder>): Set<string> {\n const leaves = new Set<string>();\n for (const command of commands) {\n if (!(command instanceof SlashCommandBuilder)) continue;\n for (const leaf of routeLeavesOf(command.toJSON())) leaves.add(leaf.route);\n }\n return leaves;\n}\n"],"mappings":";;;;;;AAUA,SAAgB,eAAe,OAAsC;CACjE,OAAO,wBAAwB,KAAK,KAAK,QAAQ,YAAY,oBAAoB,KAAK;AAC1F;;;;;;;;;;;ACAA,SAAgB,iBAAiB,UAAkF;CAC/G,MAAM,yBAAS,IAAI,IAAY;CAC/B,KAAK,MAAM,WAAW,UAAU;EAC5B,IAAI,EAAE,mBAAmB,sBAAsB;EAC/C,KAAK,MAAM,QAAQ,cAAc,QAAQ,OAAO,CAAC,GAAG,OAAO,IAAI,KAAK,KAAK;CAC7E;CACA,OAAO;AACX"}
@@ -1,4 +1,4 @@
1
- import { D as guardedAccessor, E as clearStore, O as contextMenuLeaves, T as accessorStore } from "./Bus-yJGE6Fs2.mjs";
1
+ import { D as guardedAccessor, E as clearStore, O as contextMenuLeaves, T as accessorStore } from "./Bus-dGy6xq3F.mjs";
2
2
  import { SlashCommandBuilder } from "@discordjs/builders";
3
3
  import { ApplicationCommandType } from "discord-api-types/v10";
4
4
  import { paint } from "@seedcord/errors";
@@ -136,4 +136,4 @@ var CommandInjector = class {
136
136
 
137
137
  //#endregion
138
138
  export { Commands as n, ContextMenus as r, CommandInjector as t };
139
- //# sourceMappingURL=subscribers-DVa-Pr45.mjs.map
139
+ //# sourceMappingURL=subscribers-A8lNU5yM.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"subscribers-DVa-Pr45.mjs","names":[],"sources":["../src/commands/CommandInjector.ts"],"sourcesContent":["import { SlashCommandBuilder } from '@discordjs/builders';\nimport { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\nimport { routeLeavesOf } from '@seedcord/utils/internal';\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport { contextMenuLeaves } from '#src/commands/contextMenuLeaves';\nimport { accessorStore, clearStore, guardedAccessor } from '#src/miscellaneous/guarded';\n\nimport type {\n ContextMenuKind,\n MessageContextMenuRegistry,\n UserContextMenuRegistry\n} from '#registries/ContextMenuRegistry';\nimport type { SlashRegistry } from '#registries/SlashRegistry';\nimport type { CommandBuilder, DeployResult } from '#src/commands/types';\nimport type { APIApplicationCommand, Snowflake } from 'discord-api-types/v10';\n\nconst commandStorage = accessorStore<CommandInfo>();\nconst userMenuStorage = accessorStore<ContextMenuInfo>();\nconst messageMenuStorage = accessorStore<ContextMenuInfo>();\n\n/** What {@link Commands} resolves to for one slash route. */\nexport interface CommandInfo {\n /** The clickable `</config set:id>` mention. A route whose id did not resolve falls back to `/config set`. */\n readonly mention: string;\n /** The deployed command id. Absent when the command deployed to two or more guilds. */\n readonly id?: string;\n /** The full route, e.g. `config/set`. */\n readonly route: string;\n /** The route's own description, taken from the subcommand for a nested route. */\n readonly description: string;\n}\n\n/** Each registered slash route mapped to its deployed command. */\nexport type InjectedCommandMap = {\n [K in keyof SlashRegistry]: CommandInfo;\n};\n\n/**\n * The bot's deployed slash commands, keyed by {@link SlashRegistry}. Filled by\n * {@link CommandInjector} after each deploy, and a read before that throws.\n *\n * @example\n * ```ts\n * import { Commands } from '@seedcord/gateway';\n *\n * await this.reply(`Try ${Commands['config/set'].mention}`);\n *\n * // a help listing\n * const lines = Object.values(Commands).map((c) => `${c.mention} ${c.description}`);\n * ```\n */\nexport const Commands = guardedAccessor('Commands', commandStorage) as InjectedCommandMap;\n\n/** What {@link ContextMenus} resolves to for one context-menu command. */\nexport interface ContextMenuInfo {\n /** The deployed command id. Absent when the command deployed to two or more guilds. */\n readonly id?: string;\n /** The name shown in Discord's right-click menu. */\n readonly name: string;\n readonly kind: ContextMenuKind;\n}\n\n/** Deployed context-menu commands, split by kind because Discord scopes name uniqueness per command type. */\nexport interface InjectedContextMenuMap {\n readonly user: { [K in keyof UserContextMenuRegistry]: ContextMenuInfo };\n readonly message: { [K in keyof MessageContextMenuRegistry]: ContextMenuInfo };\n}\n\n/**\n * The bot's deployed context-menu commands. Filled by {@link CommandInjector} after each deploy, and a read\n * before that throws.\n *\n * @example\n * ```ts\n * import { ContextMenus } from '@seedcord/gateway';\n *\n * const id = ContextMenus.user['View Profile'].id;\n * ```\n */\nexport const ContextMenus = {\n user: guardedAccessor('ContextMenus.user', userMenuStorage),\n message: guardedAccessor('ContextMenus.message', messageMenuStorage)\n} as InjectedContextMenuMap;\n\nconst MULTI_GUILD = Symbol('seedcord:commands:multi-guild');\n\n// Discord scopes name uniqueness per type, and a context-menu name may be all lowercase like a slash name\nfunction commandKey(type: ApplicationCommandType, name: string): string {\n return `${type}:${name}`;\n}\n\nfunction slashBuildersOf(all: readonly CommandBuilder[]): SlashCommandBuilder[] {\n const slash = all.filter((command): command is SlashCommandBuilder => command instanceof SlashCommandBuilder);\n // a guild command in N guilds is the same builder pushed once per guild\n return [...new Set(slash)];\n}\n\ninterface DeployedIds {\n readonly global: Map<string, Snowflake>;\n readonly guild: Map<string, Snowflake | typeof MULTI_GUILD>;\n readonly warned: Set<string>;\n}\n\n/** @internal */\nexport class CommandInjector {\n private readonly logger = new Logger('Commands', { channel: 'bot' });\n\n public inject(deploy: DeployResult, all: readonly CommandBuilder[]): void {\n this.clear();\n\n const ids: DeployedIds = {\n global: this.indexByKey(deploy.global),\n guild: this.indexGuilds(deploy.guilds),\n warned: new Set<string>()\n };\n let clickable = 0;\n\n for (const command of slashBuildersOf(all)) {\n const id = this.resolveId(\n ApplicationCommandType.ChatInput,\n command.name,\n ids,\n 'falling back to plain text (not clickable)'\n );\n for (const leaf of routeLeavesOf(command.toJSON())) {\n commandStorage[leaf.route] = {\n mention: id ? this.toMention(leaf.route, id) : this.toPlain(leaf.route),\n ...(id && { id }),\n route: leaf.route,\n description: leaf.description\n };\n if (id) clickable++;\n }\n }\n\n const menus = contextMenuLeaves(all);\n this.injectMenus(menus.user, ApplicationCommandType.User, userMenuStorage, ids);\n this.injectMenus(menus.message, ApplicationCommandType.Message, messageMenuStorage, ids);\n\n this.logger.utils.summary('Linked commands', {\n clickable,\n plain: Object.keys(commandStorage).length - clickable,\n 'context menus': menus.user.size + menus.message.size\n });\n }\n\n private injectMenus(\n names: ReadonlySet<string>,\n kind: ContextMenuKind,\n storage: Record<string, ContextMenuInfo>,\n ids: DeployedIds\n ): void {\n for (const name of names) {\n const id = this.resolveId(kind, name, ids, 'leaving its id unset');\n storage[name] = { ...(id && { id }), name, kind };\n }\n }\n\n private indexByKey(collection: Map<Snowflake, APIApplicationCommand>): Map<string, Snowflake> {\n const map = new Map<string, Snowflake>();\n for (const command of collection.values()) map.set(commandKey(command.type, command.name), command.id);\n return map;\n }\n\n private indexGuilds(\n guilds: Map<Snowflake, Map<Snowflake, APIApplicationCommand>>\n ): Map<string, Snowflake | typeof MULTI_GUILD> {\n const map = new Map<string, Snowflake | typeof MULTI_GUILD>();\n for (const collection of guilds.values()) {\n for (const command of collection.values()) {\n const key = commandKey(command.type, command.name);\n const existing = map.get(key);\n // Discord assigns a separate id per guild, so two ids for one name means no single mention\n if (existing === undefined) map.set(key, command.id);\n else if (existing !== command.id) map.set(key, MULTI_GUILD);\n }\n }\n return map;\n }\n\n private resolveId(\n type: ApplicationCommandType,\n name: string,\n ids: DeployedIds,\n consequence: string\n ): Snowflake | undefined {\n const key = commandKey(type, name);\n const global = ids.global.get(key);\n if (global) return global;\n\n const guild = ids.guild.get(key);\n if (guild === undefined) return undefined;\n if (guild === MULTI_GUILD) {\n if (!ids.warned.has(key)) {\n this.logger.warn(`${paint.sky.bold(name)} is deployed to multiple guilds, ${consequence}.`);\n ids.warned.add(key);\n }\n return undefined;\n }\n return guild;\n }\n\n private toMention(route: string, id: Snowflake): string {\n return `</${route.replaceAll('/', ' ')}:${id}>`;\n }\n\n private toPlain(route: string): string {\n return `/${route.replaceAll('/', ' ')}`;\n }\n\n private clear(): void {\n for (const store of [commandStorage, userMenuStorage, messageMenuStorage]) clearStore(store);\n }\n}\n"],"mappings":";;;;;;;;AAkBA,MAAM,iBAAiB,cAA2B;AAClD,MAAM,kBAAkB,cAA+B;AACvD,MAAM,qBAAqB,cAA+B;;;;;;;;;;;;;;;AAiC1D,MAAa,WAAW,gBAAgB,YAAY,cAAc;;;;;;;;;;;;AA4BlE,MAAa,eAAe;CACxB,MAAM,gBAAgB,qBAAqB,eAAe;CAC1D,SAAS,gBAAgB,wBAAwB,kBAAkB;AACvE;AAEA,MAAM,cAAc,OAAO,+BAA+B;AAG1D,SAAS,WAAW,MAA8B,MAAsB;CACpE,OAAO,GAAG,KAAK,GAAG;AACtB;AAEA,SAAS,gBAAgB,KAAuD;CAC5E,MAAM,QAAQ,IAAI,QAAQ,YAA4C,mBAAmB,mBAAmB;CAE5G,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC;AAC7B;;AASA,IAAa,kBAAb,MAA6B;CACzB,AAAiB,SAAS,IAAI,OAAO,YAAY,EAAE,SAAS,MAAM,CAAC;CAEnE,AAAO,OAAO,QAAsB,KAAsC;EACtE,KAAK,MAAM;EAEX,MAAM,MAAmB;GACrB,QAAQ,KAAK,WAAW,OAAO,MAAM;GACrC,OAAO,KAAK,YAAY,OAAO,MAAM;GACrC,wBAAQ,IAAI,IAAY;EAC5B;EACA,IAAI,YAAY;EAEhB,KAAK,MAAM,WAAW,gBAAgB,GAAG,GAAG;GACxC,MAAM,KAAK,KAAK,UACZ,uBAAuB,WACvB,QAAQ,MACR,KACA,4CACJ;GACA,KAAK,MAAM,QAAQ,cAAc,QAAQ,OAAO,CAAC,GAAG;IAChD,eAAe,KAAK,SAAS;KACzB,SAAS,KAAK,KAAK,UAAU,KAAK,OAAO,EAAE,IAAI,KAAK,QAAQ,KAAK,KAAK;KACtE,GAAI,MAAM,EAAE,GAAG;KACf,OAAO,KAAK;KACZ,aAAa,KAAK;IACtB;IACA,IAAI,IAAI;GACZ;EACJ;EAEA,MAAM,QAAQ,kBAAkB,GAAG;EACnC,KAAK,YAAY,MAAM,MAAM,uBAAuB,MAAM,iBAAiB,GAAG;EAC9E,KAAK,YAAY,MAAM,SAAS,uBAAuB,SAAS,oBAAoB,GAAG;EAEvF,KAAK,OAAO,MAAM,QAAQ,mBAAmB;GACzC;GACA,OAAO,OAAO,KAAK,cAAc,CAAC,CAAC,SAAS;GAC5C,iBAAiB,MAAM,KAAK,OAAO,MAAM,QAAQ;EACrD,CAAC;CACL;CAEA,AAAQ,YACJ,OACA,MACA,SACA,KACI;EACJ,KAAK,MAAM,QAAQ,OAAO;GACtB,MAAM,KAAK,KAAK,UAAU,MAAM,MAAM,KAAK,sBAAsB;GACjE,QAAQ,QAAQ;IAAE,GAAI,MAAM,EAAE,GAAG;IAAI;IAAM;GAAK;EACpD;CACJ;CAEA,AAAQ,WAAW,YAA2E;EAC1F,MAAM,sBAAM,IAAI,IAAuB;EACvC,KAAK,MAAM,WAAW,WAAW,OAAO,GAAG,IAAI,IAAI,WAAW,QAAQ,MAAM,QAAQ,IAAI,GAAG,QAAQ,EAAE;EACrG,OAAO;CACX;CAEA,AAAQ,YACJ,QAC2C;EAC3C,MAAM,sBAAM,IAAI,IAA4C;EAC5D,KAAK,MAAM,cAAc,OAAO,OAAO,GACnC,KAAK,MAAM,WAAW,WAAW,OAAO,GAAG;GACvC,MAAM,MAAM,WAAW,QAAQ,MAAM,QAAQ,IAAI;GACjD,MAAM,WAAW,IAAI,IAAI,GAAG;GAE5B,IAAI,aAAa,QAAW,IAAI,IAAI,KAAK,QAAQ,EAAE;QAC9C,IAAI,aAAa,QAAQ,IAAI,IAAI,IAAI,KAAK,WAAW;EAC9D;EAEJ,OAAO;CACX;CAEA,AAAQ,UACJ,MACA,MACA,KACA,aACqB;EACrB,MAAM,MAAM,WAAW,MAAM,IAAI;EACjC,MAAM,SAAS,IAAI,OAAO,IAAI,GAAG;EACjC,IAAI,QAAQ,OAAO;EAEnB,MAAM,QAAQ,IAAI,MAAM,IAAI,GAAG;EAC/B,IAAI,UAAU,QAAW,OAAO;EAChC,IAAI,UAAU,aAAa;GACvB,IAAI,CAAC,IAAI,OAAO,IAAI,GAAG,GAAG;IACtB,KAAK,OAAO,KAAK,GAAG,MAAM,IAAI,KAAK,IAAI,EAAE,mCAAmC,YAAY,EAAE;IAC1F,IAAI,OAAO,IAAI,GAAG;GACtB;GACA;EACJ;EACA,OAAO;CACX;CAEA,AAAQ,UAAU,OAAe,IAAuB;EACpD,OAAO,KAAK,MAAM,WAAW,KAAK,GAAG,EAAE,GAAG,GAAG;CACjD;CAEA,AAAQ,QAAQ,OAAuB;EACnC,OAAO,IAAI,MAAM,WAAW,KAAK,GAAG;CACxC;CAEA,AAAQ,QAAc;EAClB,KAAK,MAAM,SAAS;GAAC;GAAgB;GAAiB;EAAkB,GAAG,WAAW,KAAK;CAC/F;AACJ"}
1
+ {"version":3,"file":"subscribers-A8lNU5yM.mjs","names":[],"sources":["../src/commands/CommandInjector.ts"],"sourcesContent":["import { SlashCommandBuilder } from '@discordjs/builders';\nimport { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\nimport { routeLeavesOf } from '@seedcord/utils/internal';\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport { contextMenuLeaves } from '#src/commands/contextMenuLeaves';\nimport { accessorStore, clearStore, guardedAccessor } from '#src/miscellaneous/guarded';\n\nimport type {\n ContextMenuKind,\n MessageContextMenuRegistry,\n UserContextMenuRegistry\n} from '#registries/ContextMenuRegistry';\nimport type { SlashRegistry } from '#registries/SlashRegistry';\nimport type { CommandBuilder, DeployResult } from '#src/commands/types';\nimport type { APIApplicationCommand, Snowflake } from 'discord-api-types/v10';\n\nconst commandStorage = accessorStore<CommandInfo>();\nconst userMenuStorage = accessorStore<ContextMenuInfo>();\nconst messageMenuStorage = accessorStore<ContextMenuInfo>();\n\n/** What {@link Commands} resolves to for one slash route. */\nexport interface CommandInfo {\n /** The clickable `</config set:id>` mention. A route whose id did not resolve falls back to `/config set`. */\n readonly mention: string;\n /** The deployed command id. Absent when the command deployed to two or more guilds. */\n readonly id?: string;\n /** The full route, e.g. `config/set`. */\n readonly route: string;\n /** The route's own description, taken from the subcommand for a nested route. */\n readonly description: string;\n}\n\n/** Each registered slash route mapped to its deployed command. */\nexport type InjectedCommandMap = {\n [K in keyof SlashRegistry]: CommandInfo;\n};\n\n/**\n * The bot's deployed slash commands, keyed by {@link SlashRegistry}. Filled by\n * {@link CommandInjector} after each deploy, and a read before that throws.\n *\n * @example\n * ```ts\n * import { Commands } from '@seedcord/gateway';\n *\n * await this.reply(`Try ${Commands['config/set'].mention}`);\n *\n * // a help listing\n * const lines = Object.values(Commands).map((c) => `${c.mention} ${c.description}`);\n * ```\n */\nexport const Commands = guardedAccessor('Commands', commandStorage) as InjectedCommandMap;\n\n/** What {@link ContextMenus} resolves to for one context-menu command. */\nexport interface ContextMenuInfo {\n /** The deployed command id. Absent when the command deployed to two or more guilds. */\n readonly id?: string;\n /** The name shown in Discord's right-click menu. */\n readonly name: string;\n readonly kind: ContextMenuKind;\n}\n\n/** Deployed context-menu commands, split by kind because Discord scopes name uniqueness per command type. */\nexport interface InjectedContextMenuMap {\n readonly user: { [K in keyof UserContextMenuRegistry]: ContextMenuInfo };\n readonly message: { [K in keyof MessageContextMenuRegistry]: ContextMenuInfo };\n}\n\n/**\n * The bot's deployed context-menu commands. Filled by {@link CommandInjector} after each deploy, and a read\n * before that throws.\n *\n * @example\n * ```ts\n * import { ContextMenus } from '@seedcord/gateway';\n *\n * const id = ContextMenus.user['View Profile'].id;\n * ```\n */\nexport const ContextMenus = {\n user: guardedAccessor('ContextMenus.user', userMenuStorage),\n message: guardedAccessor('ContextMenus.message', messageMenuStorage)\n} as InjectedContextMenuMap;\n\nconst MULTI_GUILD = Symbol('seedcord:commands:multi-guild');\n\n// Discord scopes name uniqueness per type, and a context-menu name may be all lowercase like a slash name\nfunction commandKey(type: ApplicationCommandType, name: string): string {\n return `${type}:${name}`;\n}\n\nfunction slashBuildersOf(all: readonly CommandBuilder[]): SlashCommandBuilder[] {\n const slash = all.filter((command): command is SlashCommandBuilder => command instanceof SlashCommandBuilder);\n // a guild command in N guilds is the same builder pushed once per guild\n return [...new Set(slash)];\n}\n\ninterface DeployedIds {\n readonly global: Map<string, Snowflake>;\n readonly guild: Map<string, Snowflake | typeof MULTI_GUILD>;\n readonly warned: Set<string>;\n}\n\n/** @internal */\nexport class CommandInjector {\n private readonly logger = new Logger('Commands', { channel: 'bot' });\n\n public inject(deploy: DeployResult, all: readonly CommandBuilder[]): void {\n this.clear();\n\n const ids: DeployedIds = {\n global: this.indexByKey(deploy.global),\n guild: this.indexGuilds(deploy.guilds),\n warned: new Set<string>()\n };\n let clickable = 0;\n\n for (const command of slashBuildersOf(all)) {\n const id = this.resolveId(\n ApplicationCommandType.ChatInput,\n command.name,\n ids,\n 'falling back to plain text (not clickable)'\n );\n for (const leaf of routeLeavesOf(command.toJSON())) {\n commandStorage[leaf.route] = {\n mention: id ? this.toMention(leaf.route, id) : this.toPlain(leaf.route),\n ...(id && { id }),\n route: leaf.route,\n description: leaf.description\n };\n if (id) clickable++;\n }\n }\n\n const menus = contextMenuLeaves(all);\n this.injectMenus(menus.user, ApplicationCommandType.User, userMenuStorage, ids);\n this.injectMenus(menus.message, ApplicationCommandType.Message, messageMenuStorage, ids);\n\n this.logger.utils.summary('Linked commands', {\n clickable,\n plain: Object.keys(commandStorage).length - clickable,\n 'context menus': menus.user.size + menus.message.size\n });\n }\n\n private injectMenus(\n names: ReadonlySet<string>,\n kind: ContextMenuKind,\n storage: Record<string, ContextMenuInfo>,\n ids: DeployedIds\n ): void {\n for (const name of names) {\n const id = this.resolveId(kind, name, ids, 'leaving its id unset');\n storage[name] = { ...(id && { id }), name, kind };\n }\n }\n\n private indexByKey(collection: Map<Snowflake, APIApplicationCommand>): Map<string, Snowflake> {\n const map = new Map<string, Snowflake>();\n for (const command of collection.values()) map.set(commandKey(command.type, command.name), command.id);\n return map;\n }\n\n private indexGuilds(\n guilds: Map<Snowflake, Map<Snowflake, APIApplicationCommand>>\n ): Map<string, Snowflake | typeof MULTI_GUILD> {\n const map = new Map<string, Snowflake | typeof MULTI_GUILD>();\n for (const collection of guilds.values()) {\n for (const command of collection.values()) {\n const key = commandKey(command.type, command.name);\n const existing = map.get(key);\n // Discord assigns a separate id per guild, so two ids for one name means no single mention\n if (existing === undefined) map.set(key, command.id);\n else if (existing !== command.id) map.set(key, MULTI_GUILD);\n }\n }\n return map;\n }\n\n private resolveId(\n type: ApplicationCommandType,\n name: string,\n ids: DeployedIds,\n consequence: string\n ): Snowflake | undefined {\n const key = commandKey(type, name);\n const global = ids.global.get(key);\n if (global) return global;\n\n const guild = ids.guild.get(key);\n if (guild === undefined) return undefined;\n if (guild === MULTI_GUILD) {\n if (!ids.warned.has(key)) {\n this.logger.warn(`${paint.sky.bold(name)} is deployed to multiple guilds, ${consequence}.`);\n ids.warned.add(key);\n }\n return undefined;\n }\n return guild;\n }\n\n private toMention(route: string, id: Snowflake): string {\n return `</${route.replaceAll('/', ' ')}:${id}>`;\n }\n\n private toPlain(route: string): string {\n return `/${route.replaceAll('/', ' ')}`;\n }\n\n private clear(): void {\n for (const store of [commandStorage, userMenuStorage, messageMenuStorage]) clearStore(store);\n }\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.4.1",
4
+ "version": "0.5.0",
5
5
  "engines": {
6
6
  "node": ">=24.11"
7
7
  },
@@ -77,19 +77,19 @@
77
77
  "@discordjs/rest": "^2.6.3",
78
78
  "discord-api-types": "^0.38.52",
79
79
  "reflect-metadata": "^0.2.2",
80
- "@seedcord/custom-id": "^0.1.0",
81
- "@seedcord/errors": "^0.5.1",
80
+ "@seedcord/custom-id": "^0.1.1",
81
+ "@seedcord/errors": "^0.6.0",
82
82
  "@seedcord/event-emitter": "^0.1.5",
83
- "@seedcord/logger": "^0.2.2",
84
- "@seedcord/types": "^0.10.1",
85
- "@seedcord/utils": "^0.8.8"
83
+ "@seedcord/logger": "^0.3.0",
84
+ "@seedcord/types": "^0.11.0",
85
+ "@seedcord/utils": "^0.8.9"
86
86
  },
87
87
  "devDependencies": {
88
88
  "envapt": "^8.1.1",
89
89
  "type-fest": "^5.8.0",
90
90
  "vite": "^8.2.0",
91
91
  "@seedcord/eslint-config": "^2.1.0",
92
- "@seedcord/rate-limiter": "^0.1.5",
92
+ "@seedcord/rate-limiter": "^0.1.6",
93
93
  "@seedcord/tsconfig": "^2.0.3",
94
94
  "@seedcord/tsdown-config": "^2.0.1",
95
95
  "@seedcord/vitest-config": "^0.0.1"
@@ -1 +0,0 @@
1
- {"version":3,"file":"Bus-yJGE6Fs2.mjs","names":[],"sources":["../src/components/botColorHolder.ts","../src/components/builderTypes.ts","../src/components/colors.ts","../src/components/resolveColor.ts","../src/components/Component.ts","../src/commands/contextMenuLeaves.ts","../src/miscellaneous/guarded.ts","../src/metadataKeys.ts","../src/reply/flags.ts","../src/subscribers/ReportThrottle.ts","../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/slots.ts","../src/subscribers/Bus.ts"],"sourcesContent":["import type { BotColor } from '@seedcord/types';\n\n// must be 'Default' so the container guard in applyBotColor leaves the accent unset\nconst DEFAULT_COLOR: BotColor = 'Default';\n\nlet current: BotColor = DEFAULT_COLOR;\n\nexport function setBotColor(color: BotColor | undefined): void {\n current = color ?? DEFAULT_COLOR;\n}\n\nexport function getBotColor(): BotColor {\n return current;\n}\n","import {\n ActionRowBuilder,\n ButtonBuilder,\n ChannelSelectMenuBuilder,\n CheckboxBuilder,\n CheckboxGroupBuilder,\n CheckboxGroupOptionBuilder,\n ContainerBuilder,\n ContextMenuCommandBuilder,\n EmbedBuilder,\n FileBuilder,\n FileUploadBuilder,\n LabelBuilder,\n MediaGalleryBuilder,\n MentionableSelectMenuBuilder,\n ModalBuilder,\n RadioGroupBuilder,\n RadioGroupOptionBuilder,\n RoleSelectMenuBuilder,\n SectionBuilder,\n SeparatorBuilder,\n SlashCommandBuilder,\n SlashCommandSubcommandBuilder,\n SlashCommandSubcommandGroupBuilder,\n StringSelectMenuBuilder,\n StringSelectMenuOptionBuilder,\n TextDisplayBuilder,\n TextInputBuilder,\n UserSelectMenuBuilder\n} from '@discordjs/builders';\n\n/**\n * Available Discord.js builder classes for use with BuilderComponent for commands, embeds, modals, etc.\n *\n * @internal\n */\nexport const BuilderTypes = {\n // Command Components\n command: SlashCommandBuilder,\n context_menu: ContextMenuCommandBuilder,\n subcommand: SlashCommandSubcommandBuilder,\n group: SlashCommandSubcommandGroupBuilder,\n\n // Embed Components\n embed: EmbedBuilder,\n\n // Modal Components\n modal: ModalBuilder,\n label: LabelBuilder,\n text_input: TextInputBuilder,\n file_upload: FileUploadBuilder,\n checkbox: CheckboxBuilder,\n checkbox_group: CheckboxGroupBuilder,\n checkbox_group_option: CheckboxGroupOptionBuilder,\n radio_group: RadioGroupBuilder,\n radio_group_option: RadioGroupOptionBuilder,\n\n // Action Row Components\n button: ButtonBuilder,\n menu_string: StringSelectMenuBuilder,\n menu_option_string: StringSelectMenuOptionBuilder,\n menu_user: UserSelectMenuBuilder,\n menu_channel: ChannelSelectMenuBuilder,\n menu_mentionable: MentionableSelectMenuBuilder,\n menu_role: RoleSelectMenuBuilder,\n\n // ComponentsV2\n container: ContainerBuilder,\n text_display: TextDisplayBuilder,\n file: FileBuilder,\n media: MediaGalleryBuilder,\n section: SectionBuilder,\n separator: SeparatorBuilder\n};\n\n/**\n * Available Discord.js action row classes for use with RowComponent for Select Menus and Buttons\n *\n * @internal\n */\nexport const RowTypes: {\n button: typeof ActionRowBuilder<ButtonBuilder>;\n menu_string: typeof ActionRowBuilder<StringSelectMenuBuilder>;\n menu_user: typeof ActionRowBuilder<UserSelectMenuBuilder>;\n menu_channel: typeof ActionRowBuilder<ChannelSelectMenuBuilder>;\n menu_mentionable: typeof ActionRowBuilder<MentionableSelectMenuBuilder>;\n menu_role: typeof ActionRowBuilder<RoleSelectMenuBuilder>;\n} = {\n button: ActionRowBuilder<ButtonBuilder>,\n menu_string: ActionRowBuilder<StringSelectMenuBuilder>,\n menu_user: ActionRowBuilder<UserSelectMenuBuilder>,\n menu_channel: ActionRowBuilder<ChannelSelectMenuBuilder>,\n menu_mentionable: ActionRowBuilder<MentionableSelectMenuBuilder>,\n menu_role: ActionRowBuilder<RoleSelectMenuBuilder>\n};\n\n/**\n * Available Discord.js builder types for use with BuilderComponent\n */\nexport type BuilderType = keyof typeof BuilderTypes;\n\n/**\n * @internal\n */\nexport type InstantiatedBuilder<BuilderKey extends BuilderType> = InstanceType<(typeof BuilderTypes)[BuilderKey]>;\n\n/**\n * Available Discord.js action row types for use with RowComponent\n */\nexport type RowType = keyof typeof RowTypes;\n\n/**\n * @internal\n */\nexport type InstantiatedActionRow<RowKey extends RowType> = InstanceType<(typeof RowTypes)[RowKey]>;\n","import type { ColorName, TypedOmit } from '@seedcord/types';\n\n// ported verbatim from discord.js (Apache-2.0), src/util/Colors.js\nexport const Colors: TypedOmit<Record<ColorName, number>, 'Random'> = {\n Aqua: 0x1a_bc_9c,\n Blue: 0x34_98_db,\n Blurple: 0x58_65_f2,\n DarkAqua: 0x11_80_6a,\n DarkBlue: 0x20_66_94,\n DarkButNotBlack: 0x2c_2f_33,\n DarkerGrey: 0x7f_8c_8d,\n DarkGold: 0xc2_7c_0e,\n DarkGreen: 0x1f_8b_4c,\n DarkGrey: 0x97_9c_9f,\n DarkNavy: 0x2c_3e_50,\n DarkOrange: 0xa8_43_00,\n DarkPurple: 0x71_36_8a,\n DarkRed: 0x99_2d_22,\n DarkVividPink: 0xad_14_57,\n Default: 0x00_00_00,\n Fuchsia: 0xeb_45_9e,\n Gold: 0xf1_c4_0f,\n Green: 0x57_f2_87,\n Grey: 0x95_a5_a6,\n Greyple: 0x99_aa_b5,\n LightGrey: 0xbc_c0_c0,\n LuminousVividPink: 0xe9_1e_63,\n Navy: 0x34_49_5e,\n NotQuiteBlack: 0x23_27_2a,\n Orange: 0xe6_7e_22,\n Purple: 0x9b_59_b6,\n Red: 0xed_42_45,\n White: 0xff_ff_ff,\n Yellow: 0xfe_e7_5c\n} as const;\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError, SeedcordTypeError } from '@seedcord/errors/internal';\n\nimport { Colors } from './colors';\n\nimport type { BotColor } from '@seedcord/types';\n\nconst MAX_COLOR = 0xff_ff_ff;\nconst RED_SHIFT = 16;\nconst GREEN_SHIFT = 8;\n\nconst palette: Record<string, number | undefined> = Colors;\n\n/**\n * Resolves a {@link BotColor} to the integer Discord expects.\n *\n * Ported from discord.js (Apache-2.0), `resolveColor` in src/util/Util.js.\n */\nexport function resolveColor(color: BotColor): number {\n let resolved: number | undefined;\n\n if (typeof color === 'string') {\n if (color === 'Random') return Math.floor(Math.random() * (MAX_COLOR + 1));\n if (color === 'Default') return 0;\n if (/^#?[\\da-f]{6}$/i.test(color)) return Number.parseInt(color.replace('#', ''), 16);\n resolved = palette[color];\n } else if (typeof color === 'number') {\n resolved = color;\n } else {\n resolved = (color[0] << RED_SHIFT) + (color[1] << GREEN_SHIFT) + color[2];\n }\n\n if (resolved === undefined || !Number.isSafeInteger(resolved)) {\n throw new SeedcordTypeError(SeedcordErrorCode.ColorUnresolvable, [JSON.stringify(color)]);\n }\n if (resolved < 0 || resolved > MAX_COLOR) {\n throw new SeedcordRangeError(SeedcordErrorCode.ColorOutOfRange);\n }\n\n return resolved;\n}\n","import { ContainerBuilder, ContextMenuCommandBuilder, EmbedBuilder, SlashCommandBuilder } from '@discordjs/builders';\nimport { InteractionContextType } from 'discord-api-types/v10';\n\nimport { getBotColor } from './botColorHolder';\nimport { BuilderTypes, RowTypes } from './builderTypes';\nimport { resolveColor } from './resolveColor';\n\nimport type { BuilderType, InstantiatedActionRow, InstantiatedBuilder, RowType } from './builderTypes';\n\n/** @internal */\nabstract class BaseComponent<TComponent> {\n private readonly _component: TComponent;\n\n protected constructor(ComponentClass: new () => TComponent) {\n this._component = new ComponentClass();\n }\n\n /**\n * Returns the live builder, ready to send in a Discord message or nest in another component.\n *\n * Reading this can apply the bot color (see {@link BuilderComponent}), so it has a side effect.\n * @example new SomeComponent().component\n */\n public abstract get component(): InstantiatedBuilder<BuilderType> | InstantiatedActionRow<RowType>;\n\n /**\n * The wrapped builder, for calling Discord.js methods like setTitle() and setDescription() inside a subclass.\n *\n * @example this.instance.setTitle('My Modal')\n */\n protected get instance(): TComponent {\n return this._component;\n }\n}\n\n/**\n * Base class for Discord.js builder components\n *\n * Wraps Discord.js builders (SlashCommandBuilder, EmbedBuilder, etc.) with\n * Seedcord-specific defaults and helper methods.\n *\n * @typeParam BuilderKey - The type of Discord.js builder being wrapped\n */\nexport abstract class BuilderComponent<BuilderKey extends BuilderType> extends BaseComponent<\n InstantiatedBuilder<BuilderKey>\n> {\n private colorApplied = false;\n\n protected constructor(public readonly type: BuilderKey) {\n const ComponentClass = BuilderTypes[type] as unknown;\n super(ComponentClass as new () => InstantiatedBuilder<BuilderKey>);\n\n if (this.instance instanceof SlashCommandBuilder || this.instance instanceof ContextMenuCommandBuilder) {\n this.instance.setContexts(InteractionContextType.Guild);\n }\n }\n\n get component(): InstantiatedBuilder<BuilderKey> {\n this.applyBotColor();\n return this.instance;\n }\n\n // Resolving in the constructor would capture the default for a component built before setBotColor()\n // ran. The unset check keeps a color the subclass set for itself.\n private applyBotColor(): void {\n if (this.colorApplied) return;\n this.colorApplied = true;\n\n const color = getBotColor();\n if (this.instance instanceof EmbedBuilder) {\n if (this.instance.data.color === undefined) this.instance.setColor(resolveColor(color));\n } else if (this.instance instanceof ContainerBuilder) {\n const accent = this.instance.data.accent_color;\n if (accent === null || accent === undefined) {\n this.instance.setAccentColor(color === 'Default' ? undefined : resolveColor(color));\n }\n }\n }\n}\n\n// instanceof fails across the cli's separate module registry\nconst BUILDER_COMPONENT = Symbol.for('seedcord.core.builderComponent');\n\nObject.defineProperty(BuilderComponent.prototype, BUILDER_COMPONENT, { value: true });\n\n/** @internal */\nexport function isBuilderComponentClass(value: unknown): value is new () => BuilderComponent<BuilderType> {\n if (typeof value !== 'function') return false;\n const proto: unknown = (value as { prototype?: unknown }).prototype;\n return typeof proto === 'object' && proto !== null && BUILDER_COMPONENT in proto;\n}\n\n/**\n * Base class for Discord action row components\n *\n * Wraps Discord.js action row builder with Seedcord-specific defaults and helper methods.\n *\n * @typeParam RowKey - The Discord.js action row type being wrapped\n */\nexport abstract class RowComponent<RowKey extends RowType> extends BaseComponent<InstantiatedActionRow<RowKey>> {\n protected constructor(public readonly type: RowKey) {\n const ComponentClass = RowTypes[type] as unknown;\n super(ComponentClass as new () => InstantiatedActionRow<RowKey>);\n }\n\n get component(): InstantiatedActionRow<RowKey> {\n return this.instance;\n }\n}\n","import { ContextMenuCommandBuilder } from '@discordjs/builders';\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport type { SlashCommandBuilder } from '@discordjs/builders';\n\n/** @internal */\nexport interface ContextMenuLeaves {\n readonly user: Set<string>;\n readonly message: Set<string>;\n}\n\n/**\n * dedupes names across builders, since the same builder repeats once per guild.\n * a user and a message command can share a name.\n *\n * @internal\n */\nexport function contextMenuLeaves(\n commands: Iterable<SlashCommandBuilder | ContextMenuCommandBuilder>\n): ContextMenuLeaves {\n const user = new Set<string>();\n const message = new Set<string>();\n for (const command of commands) {\n if (!(command instanceof ContextMenuCommandBuilder)) continue;\n if (command.type === ApplicationCommandType.User) user.add(command.name);\n else message.add(command.name);\n }\n return { user, message };\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n// null-prototype, on a plain object a key named __proto__ sets the store's prototype and adds no entry\nexport function accessorStore<Value>(): Record<string, Value> {\n return Object.create(null) as Record<string, Value>;\n}\n\n// empties a store in place, keeping the reference the accessor's Proxy wraps\nexport function clearStore(store: Record<string, unknown>): void {\n for (const key of Object.keys(store)) Reflect.deleteProperty(store, key);\n}\n\n// handler modules import before startup fills the record, and an unguarded read there returns undefined and renders as an empty string\nexport function guardedAccessor<Value>(accessor: string, storage: Record<string, Value>): Record<string, Value> {\n return new Proxy(storage, {\n get(target, key, receiver): unknown {\n // hasOwn, since `in` walks the prototype and would read a key like `constructor` as resolved\n if (typeof key !== 'string' || Object.hasOwn(target, key)) return Reflect.get(target, key, receiver);\n throw new SeedcordError(SeedcordErrorCode.CoreAccessorUnresolved, [accessor, key]);\n }\n });\n}\n","export enum InteractionRoutes {\n Slash = 'slash',\n Button = 'button',\n Modal = 'modal',\n StringMenu = 'stringMenu',\n UserMenu = 'userMenu',\n RoleMenu = 'roleMenu',\n ChannelMenu = 'channelMenu',\n MentionableMenu = 'mentionableMenu',\n MessageContextMenu = 'messageContextMenu',\n UserContextMenu = 'userContextMenu',\n Autocomplete = 'autocomplete'\n}\n\nexport const InteractionMetadataKey = Symbol('seedcord:interaction:metadata');\n\nexport const InteractionRouteKeys: Record<InteractionRoutes, symbol> = {\n [InteractionRoutes.Slash]: Symbol('seedcord:interaction:slash'),\n [InteractionRoutes.Button]: Symbol('seedcord:interaction:button'),\n [InteractionRoutes.Modal]: Symbol('seedcord:interaction:modal'),\n [InteractionRoutes.StringMenu]: Symbol('seedcord:interaction:stringMenu'),\n [InteractionRoutes.UserMenu]: Symbol('seedcord:interaction:userMenu'),\n [InteractionRoutes.RoleMenu]: Symbol('seedcord:interaction:roleMenu'),\n [InteractionRoutes.ChannelMenu]: Symbol('seedcord:interaction:channelMenu'),\n [InteractionRoutes.MentionableMenu]: Symbol('seedcord:interaction:mentionableMenu'),\n [InteractionRoutes.MessageContextMenu]: Symbol('seedcord:interaction:messageContextMenu'),\n [InteractionRoutes.UserContextMenu]: Symbol('seedcord:interaction:userContextMenu'),\n [InteractionRoutes.Autocomplete]: Symbol('seedcord:interaction:autocomplete')\n};\n\nexport const MiddlewareMetadataKey = Symbol('seedcord:middleware:metadata');\n\nexport const EventMetadataKey = Symbol('seedcord:event:metadata');\n\n// Symbol.for so the cli's own copy of this module reads the same slot\nexport const CommandMetadataKey = Symbol.for('seedcord:command:metadata');\n\nexport const GatedMetadataKey = Symbol('seedcord:gated:metadata');\n\nexport const SubscribeMetadataKey = Symbol('seedcord:subscribe:metadata');\n\nexport const WebhookUrlMetadataKey = Symbol('seedcord:webhookUrl:metadata');\n","import { MessageFlags } from 'discord-api-types/v10';\n\nimport type { DeferOpts, SendOpts } from '@seedcord/types';\n\n// IsComponentsV2 is unconditional, since every framework reply is v2\nexport function sendFlags(opts?: SendOpts): number {\n let flags = MessageFlags.IsComponentsV2;\n if (opts?.ephemeral ?? true) flags |= MessageFlags.Ephemeral;\n if (opts?.silent) flags |= MessageFlags.SuppressNotifications;\n return flags;\n}\n\n// a deferral carries no content\nexport function deferFlags(opts?: DeferOpts): number {\n return (opts?.ephemeral ?? true) ? MessageFlags.Ephemeral : 0;\n}\n","interface ThrottleWindow {\n lastSentAt: number;\n suppressedSinceSend: number;\n}\n\nexport class ReportThrottle {\n private static readonly perCore = new WeakMap<object, ReportThrottle>();\n\n public static for(core: object): ReportThrottle {\n let throttle = ReportThrottle.perCore.get(core);\n if (!throttle) {\n throttle = new ReportThrottle();\n ReportThrottle.perCore.set(core, throttle);\n }\n return throttle;\n }\n\n private readonly windows = new Map<string, ThrottleWindow>();\n\n constructor(\n private readonly windowMs = 60_000,\n private readonly now: () => number = () => Date.now()\n ) {}\n\n // null while the window is open, otherwise how many were dropped since the last send\n public take(key: string): number | null {\n const window = this.windows.get(key);\n if (window && this.now() - window.lastSentAt < this.windowMs) {\n window.suppressedSinceSend += 1;\n return null;\n }\n\n const suppressed = window?.suppressedSinceSend ?? 0;\n this.windows.set(key, { lastSentAt: this.now(), suppressedSinceSend: 0 });\n return suppressed;\n }\n\n // gives a failed send's count to the open window, plus the one card that never went out\n public restore(key: string, suppressed: number): void {\n const window = this.windows.get(key);\n if (window) window.suppressedSinceSend += suppressed + 1;\n }\n}\n","import { Logger } from '@seedcord/logger';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { SubscriptionKey, AllSubscriptions } from './types/Subscriptions';\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 goes inside a ``` code block, so a stray ``` in the text would close it early\nexport function breakBackticks(text: string): string {\n return text.replaceAll('```', '`​`​`');\n}\n\n// discord caps a message at 2000 characters. the backticks and heading take the rest.\nconst REPORT_BUDGET = 1800;\n\n// breakBackticks grows the text by 2 chars per run\nfunction body(value: unknown): string {\n const raw = Error.isError(value) ? (value.stack ?? `${value.name}: ${value.message}`) : String(value);\n return breakBackticks(stripAnsi(raw));\n}\n\nfunction clamp(text: string, budget: number): string {\n if (text.length <= budget) return text;\n return budget > 0 ? `${text.slice(0, budget - 1)}…` : '';\n}\n\nfunction omittedLine(count: number): string {\n return `\\n\\nand ${count} more failure${count === 1 ? '' : 's'}`;\n}\n\nfunction memberReport(members: readonly unknown[], budget: number): string {\n // the dropped-count line has to fit even when every member is dropped\n const room = Math.max(budget - omittedLine(members.length).length, 0);\n const share = Math.floor(room / members.length);\n\n let report = '';\n let shown = 0;\n for (const [index, member] of members.entries()) {\n const heading = `\\n\\nFailure ${index + 1} of ${members.length}:\\n`;\n const entry = heading + clamp(body(member), Math.max(share - heading.length, 0));\n if (report.length + entry.length > room) break;\n report += entry;\n shown++;\n }\n\n const hidden = members.length - shown;\n return hidden > 0 ? report + omittedLine(hidden) : report;\n}\n\n// ansi codes are stripped because discord won't render them\nexport function errorReport(error: Error): string {\n let head = body(error);\n if (Error.isError(error.cause)) head += `\\n\\nCaused by:\\n${body(error.cause)}`;\n\n const members: unknown[] = error instanceof AggregateError ? error.errors : [];\n if (members.length === 0) return clamp(head, REPORT_BUDGET);\n\n // a long parent stack would otherwise push the dropped-count line off the end\n const report = clamp(head, REPORT_BUDGET - omittedLine(members.length).length);\n return report + memberReport(members, REPORT_BUDGET - report.length);\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 { SeedcordTypeError } 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 avatarUrl?: string | undefined;\n components: readonly { toJSON(): APIMessageTopLevelComponent }[];\n files?: readonly WebhookFile[] | undefined;\n}\n\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])\n throw new SeedcordTypeError(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, avatarUrl, 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 ...(avatarUrl && { avatar_url: avatarUrl }),\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, paint } from '@seedcord/errors';\nimport { SeedcordError, SeedcordTypeError } from '@seedcord/errors/internal';\nimport { Converters, Envapter } from 'envapt';\n\nimport { sendFlags } from '#reply/flags';\nimport { WebhookUrlMetadataKey } from '#src/metadataKeys';\n\nimport { ReportThrottle } from '../ReportThrottle';\nimport { Subscriber } from '../Subscriber';\nimport { isDiscordWebhookUrl } from './webhookHelpers';\nimport { WebhookSender } from './WebhookSender';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { WebhookFile } from './WebhookSender';\nimport type { SubscriptionKey } from '../types/Subscriptions';\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 /** Shown as the webhook message avatar. Defaults to the webhook's own. */\n avatarUrl?: 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 /**\n * Builds the message for one published event.\n *\n * @param suppressed - How many events were dropped since the last card\n */\n abstract report(suppressed: number): WebhookReport | Promise<WebhookReport>;\n\n /**\n * Events sharing this key collapse into one card per minute. Return `null` to send every event.\n */\n protected throttleKey(): string | null {\n return null;\n }\n\n async execute(): Promise<void> {\n const url = WebhookLog.urlOf(WebhookLog.envKeyOf(this.constructor));\n if (url === null) {\n // only an edge host reaches this branch, since it registers reporters lazily\n this.logger.warn(\n `${paint.sky.bold(this.constructor.name)} has no webhook url set, this reporter is disabled`\n );\n return;\n }\n\n const key = this.throttleKey();\n const throttle = ReportThrottle.for(this.core);\n const suppressed = key === null ? 0 : throttle.take(key);\n if (suppressed === null) {\n this.logger.debug(`counted a repeat into the next ${paint.sky.bold(this.constructor.name)} card`);\n return;\n }\n\n try {\n const { username, avatarUrl, components, files } = await this.report(suppressed);\n await WebhookLog.senderFor(url).send({\n flags: sendFlags({ ephemeral: false }),\n username: username ?? this.constructor.name,\n avatarUrl,\n components,\n files\n });\n } catch (error) {\n if (key !== null) throttle.restore(key, suppressed);\n this.logger.error('Webhook report failed', 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 SeedcordTypeError(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 { CoreBase } from '#interfaces/CoreBase';\nimport type { Subscriber } from '../Subscriber';\nimport type { SubscriptionKey } from '../types/Subscriptions';\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 { CoreBase } from '#interfaces/CoreBase';\nimport type { WebhookLog } from '../bases/WebhookLog';\nimport type { SubscriptionKey } from '../types/Subscriptions';\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 { breakBackticks, jsonAttachment, WebhookSeparator } from '../bases/webhookHelpers';\nimport { WebhookLog } from '../bases/WebhookLog';\nimport { Subscribe } from '../decorators/Subscribe';\nimport { WebhookUrl } from '../decorators/WebhookUrl';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { Notice } from '#stops/Notice';\nimport type { WebhookReport } from '../bases/WebhookLog';\nimport type { AllSubscriptions, FaultSource } from '../types/Subscriptions';\n\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 protected override throttleKey(): string {\n return `handledException:${this.data.routeId}:${this.data.denial.name}`;\n }\n\n report(suppressed: number): WebhookReport {\n return {\n username: 'Handled Exception',\n components: [new HandledExceptionContainer(this.data, suppressed).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'], suppressed: number) {\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\\`\\`\\`${breakBackticks(causeStack(denial))}\\`\\`\\``)\n )\n .addSeparatorComponents(new WebhookSeparator().component)\n .addTextDisplayComponents((text) => text.setContent('### Source'))\n .addFileComponents((file) => file.setURL('attachment://source.json'));\n\n this.addSuppressedCount(suppressed);\n }\n\n private addSuppressedCount(suppressed: number): void {\n if (suppressed === 0) return;\n\n this.instance.addTextDisplayComponents((text) =>\n text.setContent(`-# ${suppressed} more of these since the last report`)\n );\n }\n}\n\nfunction faultSummary(denial: Notice, source: FaultSource): string {\n // name and message carry chalk codes\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// building the report must not throw on a bigint or a 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 { CoreBase } from '#interfaces/CoreBase';\nimport type { WebhookReport } from '../bases/WebhookLog';\nimport type { AllSubscriptions } from '../types/Subscriptions';\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 protected override throttleKey(): string {\n return `unknownException:${this.data.routeId}:${nameOf(this.data.error)}`;\n }\n\n report(suppressed: number): WebhookReport {\n const { metadata } = this.data;\n return {\n username: 'Unknown Exception',\n components: [new UnhandledErrorContainer(this.data, suppressed).component],\n files: metadata\n ? [jsonAttachment('metadata.json', 'Metadata associated with the error', metadata)]\n : undefined\n };\n }\n}\n\n// discord.js puts the api code in the name, as `DiscordAPIError[10062]`\nfunction nameOf(error: Error): string {\n return error.name === 'Error' ? error.constructor.name : error.name;\n}\n\nclass UnhandledErrorContainer extends BuilderComponent<'container'> {\n constructor(data: AllSubscriptions['unknownException'], suppressed: number) {\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 this.addSuppressedCount(suppressed);\n }\n\n private addSuppressedCount(suppressed: number): void {\n if (suppressed === 0) return;\n\n this.instance.addTextDisplayComponents((text) =>\n text.setContent(`-# ${suppressed} more of these since the last report`)\n );\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","// the framework's own Bus calls. a bot author reaches the Bus through publish() and a Subscriber subclass\nexport const RegisterDefaults = Symbol('seedcord.bus.registerDefaults');\nexport const VerifyWebhooks = Symbol('seedcord.bus.verifyWebhooks');\nexport const RegisteredCount = Symbol('seedcord.bus.registeredCount');\nexport const RegisterSubscriber = Symbol('seedcord.bus.register');\nexport const UnregisterSubscriber = Symbol('seedcord.bus.unregister');\n","import { SeedcordErrorCode, paint } from '@seedcord/errors';\nimport { SeedcordError, SeedcordTypeError } from '@seedcord/errors/internal';\nimport { TypedEventEmitter } from '@seedcord/event-emitter';\nimport { Logger } from '@seedcord/logger';\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';\nimport { RegisterDefaults, RegisteredCount, RegisterSubscriber, UnregisterSubscriber, VerifyWebhooks } from './slots';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\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 { 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\nconst loggerSlot = Symbol('seedcord:bus:logger');\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 private readonly logger = new Logger('Subscribers', { channel: 'subscribers' });\n\n /** @internal */\n readonly [loggerSlot]: Logger = this.logger;\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 keep this inside start(). a bad webhook url thrown outside it never resets the singleton guard */\n public [RegisterDefaults](): void {\n this[RegisterSubscriber](registrationFor(UnknownException));\n this[RegisterSubscriber](registrationFor(HandledException));\n }\n\n /** @internal */\n public [RegisterSubscriber](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 [UnregisterSubscriber](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 a lazy edge registration never probes. every server-host reporter registers eagerly */\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(\n `could not verify webhook at ${envKeys.map((key) => paint.amber.bold(key)).join(', ')}`\n );\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(`${paint.sky.bold(ctor.name)} disabled, ${paint.amber.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 /**\n * @deprecated Always throws. Call {@link Bus.publish} to reach subscribers and listeners together.\n * @throws A **SeedcordTypeError** with `CoreBusEmitUnavailable`. `emit` reaches only the `on()` listeners.\n */\n public override emit<KeyOfSubscribers extends SubscriptionKey>(\n event: KeyOfSubscribers,\n ..._args: SubscriptionTuples[KeyOfSubscribers]\n ): never {\n throw new SeedcordTypeError(SeedcordErrorCode.CoreBusEmitUnavailable, [String(event)]);\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(\n `Error in subscriber ${paint.mute(String(subscriberName))} handler ${paint.sky.bold(name)}:`,\n err\n );\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\n/** @internal */\nexport function busLoggerOf(bus: Bus): Logger {\n return bus[loggerSlot];\n}\n"],"mappings":"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"}