@seedcord/core 0.1.4 → 0.2.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 (60) hide show
  1. package/README.md +35 -5
  2. package/dist/{subscribers-nEpbJj3Z.mjs → Bus-DcuUtOEL.mjs} +401 -31
  3. package/dist/Bus-DcuUtOEL.mjs.map +1 -0
  4. package/dist/{HmrModuleHandler-KxRP8lqJ.mjs → HmrModuleHandler-9AUfKXRl.mjs} +2 -2
  5. package/dist/{HmrModuleHandler-KxRP8lqJ.mjs.map → HmrModuleHandler-9AUfKXRl.mjs.map} +1 -1
  6. package/dist/{Plugin-CDAV7P9l.mjs → Plugin-Bkeqcjy6.mjs} +12 -3
  7. package/dist/Plugin-Bkeqcjy6.mjs.map +1 -0
  8. package/dist/{Plugin-qRc7Ch4g.d.mts → Plugin-Cl5P7-PO.d.mts} +19 -7
  9. package/dist/{cursor-D207VrRo.mjs → cursor-B07ArwDz.mjs} +4 -4
  10. package/dist/cursor-B07ArwDz.mjs.map +1 -0
  11. package/dist/{cursor-C77xH5QT.d.mts → cursor-__0_F4rW.d.mts} +10 -3
  12. package/dist/hmr.index.mjs +1 -1
  13. package/dist/{index-C0k7lRDi.d.mts → index-TYnQ-ztr.d.mts} +15 -4
  14. package/dist/index.d.mts +24 -11
  15. package/dist/index.mjs +26 -6
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/internal.index.d.mts +13 -18
  18. package/dist/internal.index.mjs +16 -48
  19. package/dist/internal.index.mjs.map +1 -1
  20. package/dist/node-internal.index.d.mts +6 -5
  21. package/dist/node-internal.index.mjs +54 -49
  22. package/dist/node-internal.index.mjs.map +1 -1
  23. package/dist/plugin.index.d.mts +1 -1
  24. package/dist/plugin.index.mjs +1 -1
  25. package/dist/subscribers-DuHg-bGT.mjs +3 -0
  26. package/package.json +25 -34
  27. package/dist/HmrModuleHandler-CxGOo1LT.cjs +0 -182
  28. package/dist/HmrModuleHandler-CxGOo1LT.cjs.map +0 -1
  29. package/dist/Plugin-CDAV7P9l.mjs.map +0 -1
  30. package/dist/Plugin-DVNh1kvX.cjs +0 -95
  31. package/dist/Plugin-DVNh1kvX.cjs.map +0 -1
  32. package/dist/cursor-D207VrRo.mjs.map +0 -1
  33. package/dist/cursor-DFgJ70_B.cjs +0 -1339
  34. package/dist/cursor-DFgJ70_B.cjs.map +0 -1
  35. package/dist/devChannel-Cdnmz6hd.cjs +0 -25
  36. package/dist/devChannel-Cdnmz6hd.cjs.map +0 -1
  37. package/dist/hmr.index.cjs +0 -4
  38. package/dist/hmr.index.d.cts +0 -1
  39. package/dist/index.cjs +0 -889
  40. package/dist/index.cjs.map +0 -1
  41. package/dist/index.d.cts +0 -1
  42. package/dist/internal.index.cjs +0 -717
  43. package/dist/internal.index.cjs.map +0 -1
  44. package/dist/internal.index.d.cts +0 -1
  45. package/dist/node-internal.index.cjs +0 -799
  46. package/dist/node-internal.index.cjs.map +0 -1
  47. package/dist/node-internal.index.d.cts +0 -1
  48. package/dist/phases-8qiiLKjS.cjs +0 -42
  49. package/dist/phases-8qiiLKjS.cjs.map +0 -1
  50. package/dist/plugin.index.cjs +0 -4
  51. package/dist/plugin.index.d.cts +0 -1
  52. package/dist/publishDefault-BCrMG9T8.mjs +0 -273
  53. package/dist/publishDefault-BCrMG9T8.mjs.map +0 -1
  54. package/dist/publishDefault-D52iT8mF.cjs +0 -368
  55. package/dist/publishDefault-D52iT8mF.cjs.map +0 -1
  56. package/dist/slashRouteLeaves-HVl6Ymr0.cjs +0 -28
  57. package/dist/slashRouteLeaves-HVl6Ymr0.cjs.map +0 -1
  58. package/dist/subscribers-6x4xw39Z.cjs +0 -531
  59. package/dist/subscribers-6x4xw39Z.cjs.map +0 -1
  60. package/dist/subscribers-nEpbJj3Z.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"internal.index.mjs","names":["logger","logger"],"sources":["../src/gates/runGates.ts","../src/gates/slowGate.ts","../src/miscellaneous/emojiConfig.ts","../src/hmr/wrapHot.ts","../src/hmr/HmrManager.ts","../src/stops/asError.ts","../src/reply/ackLegality.ts","../src/reply/AckTrace.ts","../src/reply/responseReport.ts","../src/reply/translateSerialization.ts","../src/reply/serializeReply.ts","../src/reply/BaseReplySender.ts","../src/subscribers/FaultThrottle.ts","../src/dispatch/dispatchReport.ts"],"sourcesContent":["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 { Logger, paint } 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)} ${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 { Logger, paint } 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 /** @internal */\n public unregister(listener: HmrAware): void {\n this.listeners.delete(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","// 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","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport type { AckTrace } from './AckTrace';\n\nexport type AckState = 'unacked' | 'deferred-reply' | 'deferred-update' | 'replied';\n\nexport type ReplyMethod =\n 'reply' | 'defer' | 'deferUpdate' | 'update' | 'followUp' | 'edit' | 'delete' | 'send' | 'showModal';\n\ninterface Illegal {\n // spliced into the message after \"was called when\"\n readonly reason: string;\n readonly alternative: string;\n}\n\nconst showModalReason: Illegal = {\n reason: 'this interaction was already acknowledged',\n alternative: 'showModal() must be the initial response.'\n};\n\nfunction deferReason(what: string): Illegal {\n return {\n reason: `this interaction was already acknowledged with ${what}`,\n alternative: 'A deferral can only be the initial response.'\n };\n}\n\n// a missing entry means legal in that state\nconst ILLEGAL: Record<Exclude<ReplyMethod, 'send'>, Partial<Record<AckState, Illegal>>> = {\n reply: {\n 'deferred-reply': {\n reason: 'this interaction was already deferred',\n alternative: 'Use edit() to fill the deferred reply or followUp() for a new message.'\n },\n 'deferred-update': {\n reason: 'this interaction was already acknowledged with a deferred update',\n alternative: 'Use followUp() for a new message.'\n },\n replied: {\n reason: 'this interaction was already replied to',\n alternative: 'Use followUp() for a new message or edit() to rewrite the reply.'\n }\n },\n defer: {\n 'deferred-reply': deferReason('a deferred reply'),\n 'deferred-update': deferReason('a deferred update'),\n replied: deferReason('a reply')\n },\n deferUpdate: {\n 'deferred-reply': deferReason('a deferred reply'),\n 'deferred-update': deferReason('a deferred update'),\n replied: deferReason('a reply')\n },\n update: {\n 'deferred-reply': {\n reason: 'this interaction was deferred as a reply',\n alternative: 'The placeholder is yours via edit(). update() rewrites a source message.'\n },\n replied: {\n reason: 'this interaction was already replied to',\n alternative: 'update() rewrites a source message. Use edit() or followUp() instead.'\n }\n },\n followUp: {\n unacked: {\n reason: 'this interaction has not been acknowledged yet',\n alternative: 'Ack first with reply() or defer().'\n }\n },\n edit: {\n unacked: {\n reason: 'nothing has been sent yet',\n alternative: 'Send with reply() or defer() first, then edit() rewrites it.'\n }\n },\n delete: {\n unacked: {\n reason: 'nothing has been sent yet',\n alternative: 'Acknowledge first with reply() or defer(), then delete() removes it.'\n }\n },\n showModal: {\n 'deferred-reply': showModalReason,\n 'deferred-update': showModalReason,\n replied: showModalReason\n }\n};\n\nconst SEND_TARGET: Record<AckState, 'reply' | 'edit' | 'followUp'> = {\n unacked: 'reply',\n 'deferred-reply': 'edit',\n 'deferred-update': 'followUp',\n replied: 'followUp'\n};\n\n// throws before any API call, and ackedBy becomes the throw cause with its stack pointing at the first ack\nexport function checkAckLegality(method: ReplyMethod, state: AckState, routeId: string, ackedBy?: AckTrace): void {\n if (method === 'send') return;\n const illegal = ILLEGAL[method][state];\n if (!illegal) return;\n throw new SeedcordError(\n SeedcordErrorCode.ReplyIllegalAckState,\n [method, illegal.reason, illegal.alternative, routeId],\n { cause: ackedBy }\n );\n}\n\nexport function sendTarget(state: AckState): 'reply' | 'edit' | 'followUp' {\n return SEND_TARGET[state];\n}\n","import type { ReplyMethod } from './ackLegality';\n\n// the first ack's stack, passed as the throw cause so a double-ack points to both lines\nexport class AckTrace extends Error {\n public constructor(method: ReplyMethod) {\n super(`${method}() acknowledged this interaction`);\n this.name = 'AckTrace';\n }\n}\n","import { Logger, paint } from '@seedcord/logger';\n\nimport { asError } from '@stops/asError';\nimport { PublishDefault } from '@subscribers/publishDefault';\n\nimport type { ReplyMethod } from './ackLegality';\nimport type { Bus } from '@subscribers/Bus';\nimport type { ResponseOutcome } from '@subscribers/types/Subscriptions';\n\nlet replyLogger: Logger | undefined;\nfunction logger(): Logger {\n replyLogger ??= new Logger('Reply', { channel: 'interactions' });\n return replyLogger;\n}\n\nexport interface ReplyTelemetry {\n readonly bus: Bus;\n readonly interactionId: string;\n}\n\n// the reply verbs plus the autocomplete choices callback, which runs outside the ack state machine\nexport type WriteMethod = ReplyMethod | 'respond';\n\nexport interface ResponseReport {\n readonly routeId: string;\n readonly method: WriteMethod;\n // performance.now() captured before the write began\n readonly startedAt: number;\n readonly outcome: ResponseOutcome;\n readonly messageId: string | null;\n readonly error?: Error;\n}\n\n/** @internal */\nexport function publishResponse(telemetry: ReplyTelemetry, report: ResponseReport): void {\n const durationMs = performance.now() - report.startedAt;\n telemetry.bus[PublishDefault]('responseAttempted', {\n routeId: report.routeId,\n interactionId: telemetry.interactionId,\n method: report.method,\n outcome: report.outcome,\n durationMs,\n messageId: report.messageId,\n ...(report.error && { error: report.error })\n });\n\n // after publish so a throwing sink doesn't reach the publish above\n logger().trace(\n `${paint.mint.bold(report.routeId)} ${report.method} ${report.outcome} ${paint.mute('in')} ${Math.round(durationMs)}ms`\n );\n}\n\nexport async function reportedWrite<Result>(\n telemetry: ReplyTelemetry,\n routeId: string,\n method: WriteMethod,\n write: () => Promise<Result>\n): Promise<Result> {\n const startedAt = performance.now();\n const result = await attemptWrite(telemetry, routeId, method, startedAt, write);\n publishResponse(telemetry, { routeId, method, startedAt, outcome: 'sent', messageId: null });\n return result;\n}\n\n// publishes the failed arm when write() throws, since the caller's success report sits after the write and a throw skips it\nexport async function attemptWrite<Result>(\n telemetry: ReplyTelemetry,\n routeId: string,\n method: WriteMethod,\n startedAt: number,\n write: () => Promise<Result>\n): Promise<Result> {\n try {\n return await write();\n } catch (caught) {\n const error = asError(caught);\n publishResponse(telemetry, { routeId, method, startedAt, outcome: 'failed', messageId: null, error });\n // rethrown raw\n throw caught;\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n// shapeshift aggregate errors nest, so the cap bounds the recursion\nconst MAX_DEPTH = 8;\n\ninterface ShapeshiftLike {\n readonly message?: unknown;\n readonly errors?: unknown;\n readonly constraint?: unknown;\n readonly validator?: unknown;\n readonly expected?: unknown;\n readonly given?: unknown;\n}\n\nconst OPERATOR_WORD: Record<string, string> = {\n '<=': 'at most',\n '>=': 'at least',\n '<': 'fewer than',\n '>': 'more than'\n};\n\nconst KIND_WORD: Record<string, string> = {\n string: 'a string',\n number: 'a number',\n boolean: 'a boolean',\n bigint: 'a bigint',\n array: 'a list',\n tuple: 'a list',\n date: 'a date',\n object: 'an object'\n};\n\nfunction asRecord(value: unknown): ShapeshiftLike | null {\n return typeof value === 'object' && value !== null ? value : null;\n}\n\nfunction firstLine(message: unknown): string {\n if (typeof message !== 'string') return 'unknown validation failure';\n return message.split('\\n')[0] ?? message;\n}\n\n// strings over this limit render as a character count\nconst GIVEN_PREVIEW_LIMIT = 40;\n\nfunction gotPhrase(given: unknown): string {\n if (given === undefined) return 'nothing';\n if (given === null) return 'null';\n if (typeof given === 'string') {\n if (given.length === 0) return 'an empty string';\n if (given.length > GIVEN_PREVIEW_LIMIT) return `${given.length} characters`;\n return JSON.stringify(given);\n }\n if (Array.isArray(given)) return given.length === 0 ? 'an empty list' : `${given.length} items`;\n if (typeof given === 'number' || typeof given === 'bigint' || typeof given === 'boolean') return String(given);\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a null-prototype value has no constructor at runtime\n if (typeof given === 'object') return given.constructor?.name ?? 'an object';\n return typeof given;\n}\n\n// shapeshift constraint strings take the form 'expected.length >= 1' or 'expected <= 16777215'\nfunction needPhrase(expected: string, given: unknown): string | null {\n const bounds = [...expected.matchAll(/expected(\\.length)?\\s*(<=|>=|<|>)\\s*(\\d+)/g)];\n if (bounds.length === 0) return null;\n const phrases = bounds.map(([, lengthPart, operator, limit]) => {\n const word = OPERATOR_WORD[operator ?? ''] ?? operator ?? '';\n if (!lengthPart) return `${word} ${limit}`;\n const unit = typeof given === 'string' ? 'character' : 'item';\n return `${word} ${limit} ${Number(limit) === 1 ? unit : `${unit}s`}`;\n });\n return phrases.join(' and ');\n}\n\nfunction instanceName(expected: unknown): string {\n if (typeof expected === 'function' && expected.name) return expected.name;\n return 'specific class instance';\n}\n\nfunction describeLeaf(record: ShapeshiftLike): string {\n if (typeof record.constraint === 'string') {\n const need = typeof record.expected === 'string' ? needPhrase(record.expected, record.given) : null;\n if (need) return `need ${need}, got ${gotPhrase(record.given)}`;\n return `${firstLine(record.message)}${'given' in record ? ` (got ${gotPhrase(record.given)})` : ''}`;\n }\n if (typeof record.expected === 'function') {\n return `need a ${instanceName(record.expected)}, got ${gotPhrase(record.given)}`;\n }\n if (typeof record.validator === 'string') {\n const kind = KIND_WORD[record.validator.replace(/^s\\./, '').replace(/\\(.*$/, '')];\n if (kind) return `need ${kind}, got ${gotPhrase(record.given)}`;\n return `${firstLine(record.message)}, got ${gotPhrase(record.given)}`;\n }\n return firstLine(record.message);\n}\n\nfunction describeUnion(branches: unknown[], depth: number): string {\n const records: ShapeshiftLike[] = [];\n for (const branch of branches) {\n const record = asRecord(branch);\n if (record) records.push(record);\n }\n const bounded = records.find((record) => typeof record.constraint === 'string');\n if (bounded) return describeLeaf(bounded);\n\n const names: string[] = [];\n let allInstances = records.length > 0;\n for (const record of records) {\n if (typeof record.expected === 'function') names.push(instanceName(record.expected));\n else allInstances = false;\n }\n if (allInstances) {\n return `need a ${[...new Set(names)].join(' or ')}, got ${gotPhrase(records[0]?.given)}`;\n }\n return detailOf(branches[0], depth + 1);\n}\n\n// shapeshift nests errors as [key, inner] tuples\nfunction detailOf(value: unknown, depth: number): string {\n const record = asRecord(value);\n if (!record || depth >= MAX_DEPTH) return firstLine(record?.message);\n\n if (Array.isArray(record.errors) && record.errors.length > 0) {\n const errors = record.errors as unknown[];\n const [first] = errors;\n if (Array.isArray(first)) {\n const [key, inner] = first as [unknown, unknown];\n return `${String(key)}: ${detailOf(inner, depth + 1)}`;\n }\n return describeUnion(errors, depth);\n }\n\n return describeLeaf(record);\n}\n\n// a shapeshift throw becomes an actionable message with the cause kept, while anything else contributes its own message as the detail\nexport function translateSerializationError(\n error: unknown,\n componentClass: string,\n index: number,\n routeId: string\n): SeedcordError<SeedcordErrorCode.ReplyComponentSerialization> {\n const detail = detailOf(error, 0);\n return new SeedcordError(SeedcordErrorCode.ReplyComponentSerialization, [componentClass, index, detail, routeId], {\n cause: error\n });\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { translateSerializationError } from './translateSerialization';\n\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { APIMessageTopLevelComponent } from 'discord-api-types/v10';\n\nexport interface SerializedReply<TNative = never> {\n readonly components: APIMessageTopLevelComponent[];\n readonly allowedMentions?: ReplyResponse['allowedMentions'];\n readonly files?: ReplyResponse<TNative>['files'];\n}\n\nexport function serializeReply<TNative>(\n response: ReplyResponse<TNative> | string,\n routeId: string\n): SerializedReply<TNative> {\n if (typeof response === 'string') {\n try {\n return { components: [new TextDisplayBuilder().setContent(response).toJSON()] };\n } catch (error) {\n throw translateSerializationError(error, 'TextDisplayBuilder', 0, routeId);\n }\n }\n\n const components = response.components.map((component, index) => {\n try {\n return component.toJSON();\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a null-prototype value has no constructor at runtime\n const name = component.constructor?.name;\n throw translateSerializationError(error, !name || name === 'Object' ? 'component' : name, index, routeId);\n }\n });\n\n return {\n components,\n ...(response.allowedMentions && { allowedMentions: response.allowedMentions }),\n ...(response.files && { files: response.files })\n };\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { checkAckLegality, sendTarget } from './ackLegality';\nimport { AckTrace } from './AckTrace';\nimport { attemptWrite, publishResponse } from './responseReport';\nimport { serializeReply } from './serializeReply';\nimport { translateSerializationError } from './translateSerialization';\n\nimport type { AckState, ReplyMethod } from './ackLegality';\nimport type { ReplyTelemetry } from './responseReport';\nimport type { SerializedReply } from './serializeReply';\nimport type { DeferOpts, ReplyResponse, SendOpts } from '@seedcord/types';\nimport type { ResponseOutcome } from '@subscribers/types/Subscriptions';\nimport type { APIModalInteractionResponseCallbackData } from 'discord-api-types/v10';\n\n/** The shape djs modal builders emit from `toJSON()`. */\nexport interface ModalLike {\n toJSON(): APIModalInteractionResponseCallbackData;\n}\n\n/**\n * Tracks acknowledgement state and throws a translated `SeedcordError` on an illegal verb before any\n * transport call. Every verb runs the legality check, calls the transport's wire writer, then updates\n * the state and the ack trace. Each transport binds `TMessage` to its own created-message type and\n * supplies the writers.\n */\nexport abstract class BaseReplySender<TMessage extends { id: string }, TNative = never> {\n private state: AckState;\n // the only ids a targeted edit accepts\n private readonly sent = new Set<string>();\n // the cause carries the first ack's stack so a double-ack reports both lines\n private ackedBy?: AckTrace;\n\n protected constructor(\n protected readonly routeId: string,\n private readonly telemetry: ReplyTelemetry,\n initialState: AckState = 'unacked'\n ) {\n this.state = initialState;\n }\n\n private report(method: ReplyMethod, startedAt: number, outcome: ResponseOutcome, messageId: string | null): void {\n publishResponse(this.telemetry, { routeId: this.routeId, method, startedAt, outcome, messageId });\n }\n\n private async attempt<Result>(\n method: ReplyMethod,\n startedAt: number,\n write: () => Promise<Result>\n ): Promise<Result> {\n return await attemptWrite(this.telemetry, this.routeId, method, startedAt, write);\n }\n\n public async reply(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n this.checkLegality('reply');\n const startedAt = performance.now();\n const created = await this.attempt('reply', startedAt, () => this.writeReply(response, opts));\n // the callback already acked discord, so record replied before the message guard can throw\n this.transition('reply', 'replied');\n const message = this.remember(this.requireMessage(created, 'reply'));\n this.report('reply', startedAt, 'sent', message.id);\n return message;\n }\n\n public async defer(opts?: DeferOpts): Promise<void> {\n this.checkLegality('defer');\n const startedAt = performance.now();\n await this.attempt('defer', startedAt, () => this.writeDefer(opts));\n this.transition('defer', 'deferred-reply');\n this.report('defer', startedAt, 'sent', null);\n }\n\n public async deferUpdate(): Promise<void> {\n this.checkLegality('deferUpdate');\n const startedAt = performance.now();\n await this.attempt('deferUpdate', startedAt, () => this.writeDeferUpdate());\n this.transition('deferUpdate', 'deferred-update');\n this.report('deferUpdate', startedAt, 'sent', null);\n }\n\n /**\n * After a deferUpdate the state stays deferred-update. Calling this again rewrites. The returned message\n * is the source message, editable only through a bare `update` or `edit`. A targeted `edit` or `delete`\n * of it throws the foreign-target error.\n */\n public async update(response: ReplyResponse<TNative> | string): Promise<TMessage> {\n this.checkLegality('update');\n const startedAt = performance.now();\n // in deferred-update the source message is @original and the ack-legality check above already passed\n if (this.state === 'deferred-update') {\n const edited = await this.attempt('update', startedAt, () => this.editOriginal(response));\n this.report('update', startedAt, 'sent', edited.id);\n return edited;\n }\n const created = await this.attempt('update', startedAt, () => this.writeUpdate(response));\n this.transition('update', 'replied');\n const message = this.remember(this.requireMessage(created, 'update'));\n this.report('update', startedAt, 'sent', message.id);\n return message;\n }\n\n public async followUp(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n this.checkLegality('followUp');\n const startedAt = performance.now();\n const created = await this.attempt('followUp', startedAt, () => this.writeFollowUp(response, opts));\n const message = this.remember(created);\n this.report('followUp', startedAt, 'sent', message.id);\n return message;\n }\n\n public edit(response: ReplyResponse<TNative> | string): Promise<TMessage>;\n public edit(target: TMessage, response: ReplyResponse<TNative> | string): Promise<TMessage>;\n public async edit(\n targetOrResponse: TMessage | ReplyResponse<TNative> | string,\n maybeResponse?: ReplyResponse<TNative> | string\n ): Promise<TMessage> {\n this.checkLegality('edit');\n const startedAt = performance.now();\n if (maybeResponse === undefined) {\n // justified: the overloads narrow targetOrResponse to a response once maybeResponse is absent\n const edited = await this.attempt('edit', startedAt, () =>\n this.editOriginal(targetOrResponse as ReplyResponse<TNative> | string)\n );\n this.report('edit', startedAt, 'sent', edited.id);\n return edited;\n }\n // justified: the overloads narrow targetOrResponse to a target message once maybeResponse is defined\n const target = targetOrResponse as TMessage;\n if (!this.sent.has(target.id)) {\n throw new SeedcordError(SeedcordErrorCode.ReplyForeignEditTarget, ['edit', target.id, this.routeId]);\n }\n const written = await this.attempt('edit', startedAt, () => this.writeEditTarget(target.id, maybeResponse));\n const message = this.remember(written);\n this.report('edit', startedAt, 'sent', message.id);\n return message;\n }\n\n public delete(): Promise<void>;\n public delete(target: TMessage): Promise<void>;\n public async delete(target?: TMessage): Promise<void> {\n this.checkLegality('delete');\n const startedAt = performance.now();\n if (target === undefined) {\n await this.attempt('delete', startedAt, () => this.writeDeleteOriginal());\n this.report('delete', startedAt, 'sent', null);\n return;\n }\n if (!this.sent.has(target.id)) {\n throw new SeedcordError(SeedcordErrorCode.ReplyForeignEditTarget, ['delete', target.id, this.routeId]);\n }\n await this.attempt('delete', startedAt, () => this.writeDeleteTarget(target.id));\n // evict so a later targeted edit of this id throws foreign\n this.sent.delete(target.id);\n this.report('delete', startedAt, 'sent', null);\n }\n\n /** Routes to the verb the current ack state permits. Every state has a route, so the illegal-ack throw is unreachable. */\n public async send(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n const target = sendTarget(this.state);\n if (target === 'reply') return await this.reply(response, opts);\n if (target === 'edit') return await this.edit(response);\n return await this.followUp(response, opts);\n }\n\n /** Must be the initial response. */\n public async showModal(modal: ModalLike): Promise<void> {\n this.checkLegality('showModal');\n this.guardModalSource();\n let data: APIModalInteractionResponseCallbackData;\n try {\n data = modal.toJSON();\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a null-prototype modal has no constructor at runtime\n const name = modal.constructor?.name;\n throw translateSerializationError(error, !name || name === 'Object' ? 'modal' : name, 0, this.routeId);\n }\n const startedAt = performance.now();\n await this.attempt('showModal', startedAt, () => this.writeModal(data));\n this.transition('showModal', 'replied');\n this.report('showModal', startedAt, 'sent', null);\n }\n\n protected serialize(response: ReplyResponse<TNative> | string): SerializedReply<TNative> {\n return serializeReply(response, this.routeId);\n }\n\n protected remember(created: TMessage): TMessage {\n this.sent.add(created.id);\n return created;\n }\n\n // a with_response callback always returns the created message. this only trips if the wire says otherwise\n private requireMessage(created: TMessage | undefined, method: 'reply' | 'update'): TMessage {\n if (!created) throw new SeedcordError(SeedcordErrorCode.ReplyCallbackMissingMessage, [method, this.routeId]);\n return created;\n }\n\n private async editOriginal(response: ReplyResponse<TNative> | string): Promise<TMessage> {\n const edited = await this.writeEditOriginal(response);\n // after a deferUpdate the source message is @original, which this interaction did not send\n if (this.state !== 'deferred-update') this.remember(edited);\n return edited;\n }\n\n private checkLegality(method: ReplyMethod): void {\n checkAckLegality(method, this.state, this.routeId, this.ackedBy);\n }\n\n private transition(method: ReplyMethod, state: AckState): void {\n this.state = state;\n this.ackedBy = new AckTrace(method);\n }\n\n // gateway overrides this to reject a modal-submit source\n protected guardModalSource(): void {}\n\n protected abstract writeReply(\n response: ReplyResponse<TNative> | string,\n opts?: SendOpts\n ): Promise<TMessage | undefined>;\n protected abstract writeDefer(opts?: DeferOpts): Promise<void>;\n protected abstract writeDeferUpdate(): Promise<void>;\n protected abstract writeUpdate(response: ReplyResponse<TNative> | string): Promise<TMessage | undefined>;\n protected abstract writeFollowUp(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage>;\n protected abstract writeEditOriginal(response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected abstract writeEditTarget(targetId: string, response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected abstract writeDeleteOriginal(): Promise<void>;\n protected abstract writeDeleteTarget(targetId: string): Promise<void>;\n protected abstract writeModal(data: APIModalInteractionResponseCallbackData): Promise<void>;\n}\n","/** @internal */\nexport class FaultThrottle {\n // keyed by core so each bot gets its own window, and the entry is collected with the core\n private static readonly perCore = new WeakMap<object, FaultThrottle>();\n\n /** @internal */\n public static for(core: object): FaultThrottle {\n let throttle = FaultThrottle.perCore.get(core);\n if (!throttle) {\n throttle = new FaultThrottle();\n FaultThrottle.perCore.set(core, throttle);\n }\n return throttle;\n }\n\n private readonly lastReportedAt = new Map<string, number>();\n\n constructor(\n private readonly windowMs = 60_000,\n private readonly now: () => number = () => Date.now()\n ) {}\n\n public shouldReport(key: string): boolean {\n const last = this.lastReportedAt.get(key);\n if (last === undefined) return true;\n if (this.now() - last < this.windowMs) return false;\n\n this.lastReportedAt.delete(key);\n return true;\n }\n\n public markReported(key: string): void {\n this.lastReportedAt.set(key, this.now());\n }\n\n public clear(): void {\n this.lastReportedAt.clear();\n }\n}\n","import { Logger, paint } 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.mint.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","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/stops/asError.ts","../src/reply/ackLegality.ts","../src/reply/AckTrace.ts","../src/reply/responseReport.ts","../src/reply/translateSerialization.ts","../src/reply/serializeReply.ts","../src/reply/BaseReplySender.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 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","// 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","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport type { AckTrace } from './AckTrace';\n\nexport type AckState = 'unacked' | 'deferred-reply' | 'deferred-update' | 'replied';\n\nexport type ReplyMethod =\n 'reply' | 'defer' | 'deferUpdate' | 'update' | 'followUp' | 'edit' | 'delete' | 'send' | 'showModal';\n\ninterface Illegal {\n // spliced into the message after \"was called when\"\n readonly reason: string;\n readonly alternative: string;\n}\n\nconst showModalReason: Illegal = {\n reason: 'this interaction was already acknowledged',\n alternative: 'showModal() must be the initial response.'\n};\n\nfunction deferReason(what: string): Illegal {\n return {\n reason: `this interaction was already acknowledged with ${what}`,\n alternative: 'A deferral can only be the initial response.'\n };\n}\n\n// a missing entry means legal in that state\nconst ILLEGAL: Record<Exclude<ReplyMethod, 'send'>, Partial<Record<AckState, Illegal>>> = {\n reply: {\n 'deferred-reply': {\n reason: 'this interaction was already deferred',\n alternative: 'Use edit() to fill the deferred reply or followUp() for a new message.'\n },\n 'deferred-update': {\n reason: 'this interaction was already acknowledged with a deferred update',\n alternative: 'Use followUp() for a new message.'\n },\n replied: {\n reason: 'this interaction was already replied to',\n alternative: 'Use followUp() for a new message or edit() to rewrite the reply.'\n }\n },\n defer: {\n 'deferred-reply': deferReason('a deferred reply'),\n 'deferred-update': deferReason('a deferred update'),\n replied: deferReason('a reply')\n },\n deferUpdate: {\n 'deferred-reply': deferReason('a deferred reply'),\n 'deferred-update': deferReason('a deferred update'),\n replied: deferReason('a reply')\n },\n update: {\n 'deferred-reply': {\n reason: 'this interaction was deferred as a reply',\n alternative: 'The placeholder is yours via edit(). update() rewrites a source message.'\n },\n replied: {\n reason: 'this interaction was already replied to',\n alternative: 'update() rewrites a source message. Use edit() or followUp() instead.'\n }\n },\n followUp: {\n unacked: {\n reason: 'this interaction has not been acknowledged yet',\n alternative: 'Ack first with reply() or defer().'\n }\n },\n edit: {\n unacked: {\n reason: 'nothing has been sent yet',\n alternative: 'Send with reply() or defer() first, then edit() rewrites it.'\n }\n },\n delete: {\n unacked: {\n reason: 'nothing has been sent yet',\n alternative: 'Acknowledge first with reply() or defer(), then delete() removes it.'\n }\n },\n showModal: {\n 'deferred-reply': showModalReason,\n 'deferred-update': showModalReason,\n replied: showModalReason\n }\n};\n\nconst SEND_TARGET: Record<AckState, 'reply' | 'edit' | 'followUp'> = {\n unacked: 'reply',\n 'deferred-reply': 'edit',\n 'deferred-update': 'followUp',\n replied: 'followUp'\n};\n\n// throws before any API call, and ackedBy becomes the throw cause with its stack pointing at the first ack\nexport function checkAckLegality(method: ReplyMethod, state: AckState, routeId: string, ackedBy?: AckTrace): void {\n if (method === 'send') return;\n const illegal = ILLEGAL[method][state];\n if (!illegal) return;\n throw new SeedcordError(\n SeedcordErrorCode.ReplyIllegalAckState,\n [method, illegal.reason, illegal.alternative, routeId],\n { cause: ackedBy }\n );\n}\n\nexport function sendTarget(state: AckState): 'reply' | 'edit' | 'followUp' {\n return SEND_TARGET[state];\n}\n","import type { ReplyMethod } from './ackLegality';\n\n// the first ack's stack, passed as the throw cause so a double-ack points to both lines\nexport class AckTrace extends Error {\n public constructor(method: ReplyMethod) {\n super(`${method}() acknowledged this interaction`);\n this.name = 'AckTrace';\n }\n}\n","import { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\n\nimport { asError } from '#stops/asError';\nimport { PublishDefault } from '#subscribers/publishDefault';\n\nimport type { Bus } from '#subscribers/Bus';\nimport type { ResponseOutcome } from '#subscribers/types/Subscriptions';\nimport type { ReplyMethod } from './ackLegality';\n\nlet replyLogger: Logger | undefined;\nfunction logger(): Logger {\n replyLogger ??= new Logger('Reply', { channel: 'interactions' });\n return replyLogger;\n}\n\nexport interface ReplyTelemetry {\n readonly bus: Bus;\n readonly interactionId: string;\n}\n\n// the reply verbs plus the autocomplete choices callback, which runs outside the ack state machine\nexport type WriteMethod = ReplyMethod | 'respond';\n\nexport interface ResponseReport {\n readonly routeId: string;\n readonly method: WriteMethod;\n // performance.now() captured before the write began\n readonly startedAt: number;\n readonly outcome: ResponseOutcome;\n readonly messageId: string | null;\n readonly error?: Error;\n}\n\n/** @internal */\nexport function publishResponse(telemetry: ReplyTelemetry, report: ResponseReport): void {\n const durationMs = performance.now() - report.startedAt;\n telemetry.bus[PublishDefault]('responseAttempted', {\n routeId: report.routeId,\n interactionId: telemetry.interactionId,\n method: report.method,\n outcome: report.outcome,\n durationMs,\n messageId: report.messageId,\n ...(report.error && { error: report.error })\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.method} ${report.outcome} ${paint.mute('in')} ${Math.round(durationMs)}ms`\n );\n}\n\nexport async function reportedWrite<Result>(\n telemetry: ReplyTelemetry,\n routeId: string,\n method: WriteMethod,\n write: () => Promise<Result>\n): Promise<Result> {\n const startedAt = performance.now();\n const result = await attemptWrite(telemetry, routeId, method, startedAt, write);\n publishResponse(telemetry, { routeId, method, startedAt, outcome: 'sent', messageId: null });\n return result;\n}\n\n// publishes the failed arm when write() throws, since the caller's success report sits after the write and a throw skips it\nexport async function attemptWrite<Result>(\n telemetry: ReplyTelemetry,\n routeId: string,\n method: WriteMethod,\n startedAt: number,\n write: () => Promise<Result>\n): Promise<Result> {\n try {\n return await write();\n } catch (caught) {\n const error = asError(caught);\n publishResponse(telemetry, { routeId, method, startedAt, outcome: 'failed', messageId: null, error });\n // rethrown raw\n throw caught;\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n// shapeshift aggregate errors nest, so the cap bounds the recursion\nconst MAX_DEPTH = 8;\n\ninterface ShapeshiftLike {\n readonly message?: unknown;\n readonly errors?: unknown;\n readonly constraint?: unknown;\n readonly validator?: unknown;\n readonly expected?: unknown;\n readonly given?: unknown;\n}\n\nconst OPERATOR_WORD: Record<string, string> = {\n '<=': 'at most',\n '>=': 'at least',\n '<': 'fewer than',\n '>': 'more than'\n};\n\nconst KIND_WORD: Record<string, string> = {\n string: 'a string',\n number: 'a number',\n boolean: 'a boolean',\n bigint: 'a bigint',\n array: 'a list',\n tuple: 'a list',\n date: 'a date',\n object: 'an object'\n};\n\nfunction asRecord(value: unknown): ShapeshiftLike | null {\n return typeof value === 'object' && value !== null ? value : null;\n}\n\nfunction firstLine(message: unknown): string {\n if (typeof message !== 'string') return 'unknown validation failure';\n return message.split('\\n')[0] ?? message;\n}\n\n// strings over this limit render as a character count\nconst GIVEN_PREVIEW_LIMIT = 40;\n\nfunction gotPhrase(given: unknown): string {\n if (given === undefined) return 'nothing';\n if (given === null) return 'null';\n if (typeof given === 'string') {\n if (given.length === 0) return 'an empty string';\n if (given.length > GIVEN_PREVIEW_LIMIT) return `${given.length} characters`;\n return JSON.stringify(given);\n }\n if (Array.isArray(given)) return given.length === 0 ? 'an empty list' : `${given.length} items`;\n if (typeof given === 'number' || typeof given === 'bigint' || typeof given === 'boolean') return String(given);\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a null-prototype value has no constructor at runtime\n if (typeof given === 'object') return given.constructor?.name ?? 'an object';\n return typeof given;\n}\n\n// shapeshift constraint strings take the form 'expected.length >= 1' or 'expected <= 16777215'\nfunction needPhrase(expected: string, given: unknown): string | null {\n const bounds = [...expected.matchAll(/expected(\\.length)?\\s*(<=|>=|<|>)\\s*(\\d+)/g)];\n if (bounds.length === 0) return null;\n const phrases = bounds.map(([, lengthPart, operator, limit]) => {\n const word = OPERATOR_WORD[operator ?? ''] ?? operator ?? '';\n if (!lengthPart) return `${word} ${limit}`;\n const unit = typeof given === 'string' ? 'character' : 'item';\n return `${word} ${limit} ${Number(limit) === 1 ? unit : `${unit}s`}`;\n });\n return phrases.join(' and ');\n}\n\nfunction instanceName(expected: unknown): string {\n if (typeof expected === 'function' && expected.name) return expected.name;\n return 'specific class instance';\n}\n\nfunction describeLeaf(record: ShapeshiftLike): string {\n if (typeof record.constraint === 'string') {\n const need = typeof record.expected === 'string' ? needPhrase(record.expected, record.given) : null;\n if (need) return `need ${need}, got ${gotPhrase(record.given)}`;\n return `${firstLine(record.message)}${'given' in record ? ` (got ${gotPhrase(record.given)})` : ''}`;\n }\n if (typeof record.expected === 'function') {\n return `need a ${instanceName(record.expected)}, got ${gotPhrase(record.given)}`;\n }\n if (typeof record.validator === 'string') {\n const kind = KIND_WORD[record.validator.replace(/^s\\./, '').replace(/\\(.*$/, '')];\n if (kind) return `need ${kind}, got ${gotPhrase(record.given)}`;\n return `${firstLine(record.message)}, got ${gotPhrase(record.given)}`;\n }\n return firstLine(record.message);\n}\n\nfunction describeUnion(branches: unknown[], depth: number): string {\n const records: ShapeshiftLike[] = [];\n for (const branch of branches) {\n const record = asRecord(branch);\n if (record) records.push(record);\n }\n const bounded = records.find((record) => typeof record.constraint === 'string');\n if (bounded) return describeLeaf(bounded);\n\n const names: string[] = [];\n let allInstances = records.length > 0;\n for (const record of records) {\n if (typeof record.expected === 'function') names.push(instanceName(record.expected));\n else allInstances = false;\n }\n if (allInstances) {\n return `need a ${[...new Set(names)].join(' or ')}, got ${gotPhrase(records[0]?.given)}`;\n }\n return detailOf(branches[0], depth + 1);\n}\n\n// shapeshift nests errors as [key, inner] tuples\nfunction detailOf(value: unknown, depth: number): string {\n const record = asRecord(value);\n if (!record || depth >= MAX_DEPTH) return firstLine(record?.message);\n\n if (Array.isArray(record.errors) && record.errors.length > 0) {\n const errors = record.errors as unknown[];\n const [first] = errors;\n if (Array.isArray(first)) {\n const [key, inner] = first as [unknown, unknown];\n return `${String(key)}: ${detailOf(inner, depth + 1)}`;\n }\n return describeUnion(errors, depth);\n }\n\n return describeLeaf(record);\n}\n\n// a shapeshift throw becomes an actionable message with the cause kept, while anything else contributes its own message as the detail\nexport function translateSerializationError(\n error: unknown,\n componentClass: string,\n index: number,\n routeId: string\n): SeedcordError<SeedcordErrorCode.ReplyComponentSerialization> {\n const detail = detailOf(error, 0);\n return new SeedcordError(SeedcordErrorCode.ReplyComponentSerialization, [componentClass, index, detail, routeId], {\n cause: error\n });\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { translateSerializationError } from './translateSerialization';\n\nimport type { ReplyResponse } from '@seedcord/types';\nimport type { APIMessageTopLevelComponent } from 'discord-api-types/v10';\n\nexport interface SerializedReply<TNative = never> {\n readonly components: APIMessageTopLevelComponent[];\n readonly allowedMentions?: ReplyResponse['allowedMentions'];\n readonly files?: ReplyResponse<TNative>['files'];\n}\n\nexport function serializeReply<TNative>(\n response: ReplyResponse<TNative> | string,\n routeId: string\n): SerializedReply<TNative> {\n if (typeof response === 'string') {\n try {\n return { components: [new TextDisplayBuilder().setContent(response).toJSON()] };\n } catch (error) {\n throw translateSerializationError(error, 'TextDisplayBuilder', 0, routeId);\n }\n }\n\n const components = response.components.map((component, index) => {\n try {\n return component.toJSON();\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a null-prototype value has no constructor at runtime\n const name = component.constructor?.name;\n throw translateSerializationError(error, !name || name === 'Object' ? 'component' : name, index, routeId);\n }\n });\n\n return {\n components,\n ...(response.allowedMentions && { allowedMentions: response.allowedMentions }),\n ...(response.files && { files: response.files })\n };\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { checkAckLegality, sendTarget } from './ackLegality';\nimport { AckTrace } from './AckTrace';\nimport { attemptWrite, publishResponse } from './responseReport';\nimport { serializeReply } from './serializeReply';\nimport { translateSerializationError } from './translateSerialization';\n\nimport type { ResponseOutcome } from '#subscribers/types/Subscriptions';\nimport type { AckState, ReplyMethod } from './ackLegality';\nimport type { ReplyTelemetry } from './responseReport';\nimport type { SerializedReply } from './serializeReply';\nimport type { DeferOpts, ReplyResponse, SendOpts } from '@seedcord/types';\nimport type { APIModalInteractionResponseCallbackData } from 'discord-api-types/v10';\n\n/** The shape djs modal builders emit from `toJSON()`. */\nexport interface ModalLike {\n toJSON(): APIModalInteractionResponseCallbackData;\n}\n\n/**\n * Tracks acknowledgement state and throws a translated `SeedcordError` on an illegal verb before any\n * transport call. Every verb runs the legality check, calls the transport's wire writer, then updates\n * the state and the ack trace. Each transport binds `TMessage` to its own created-message type and\n * supplies the writers.\n */\nexport abstract class BaseReplySender<TMessage extends { id: string }, TNative = never> {\n private state: AckState;\n // the only ids a targeted edit accepts\n private readonly sent = new Set<string>();\n // the cause carries the first ack's stack so a double-ack reports both lines\n private ackedBy?: AckTrace;\n\n protected constructor(\n protected readonly routeId: string,\n private readonly telemetry: ReplyTelemetry,\n initialState: AckState = 'unacked'\n ) {\n this.state = initialState;\n }\n\n private report(method: ReplyMethod, startedAt: number, outcome: ResponseOutcome, messageId: string | null): void {\n publishResponse(this.telemetry, { routeId: this.routeId, method, startedAt, outcome, messageId });\n }\n\n private async attempt<Result>(\n method: ReplyMethod,\n startedAt: number,\n write: () => Promise<Result>\n ): Promise<Result> {\n return await attemptWrite(this.telemetry, this.routeId, method, startedAt, write);\n }\n\n public async reply(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n this.checkLegality('reply');\n const startedAt = performance.now();\n const created = await this.attempt('reply', startedAt, () => this.writeReply(response, opts));\n // the callback already acked discord, so record replied before the message guard can throw\n this.transition('reply', 'replied');\n const message = this.remember(this.requireMessage(created, 'reply'));\n this.report('reply', startedAt, 'sent', message.id);\n return message;\n }\n\n public async defer(opts?: DeferOpts): Promise<void> {\n this.checkLegality('defer');\n const startedAt = performance.now();\n await this.attempt('defer', startedAt, () => this.writeDefer(opts));\n this.transition('defer', 'deferred-reply');\n this.report('defer', startedAt, 'sent', null);\n }\n\n public async deferUpdate(): Promise<void> {\n this.checkLegality('deferUpdate');\n const startedAt = performance.now();\n await this.attempt('deferUpdate', startedAt, () => this.writeDeferUpdate());\n this.transition('deferUpdate', 'deferred-update');\n this.report('deferUpdate', startedAt, 'sent', null);\n }\n\n /**\n * After a deferUpdate the state stays deferred-update. Calling this again rewrites. The returned message\n * is the source message, editable only through a bare `update` or `edit`. A targeted `edit` or `delete`\n * of it throws the foreign-target error.\n */\n public async update(response: ReplyResponse<TNative> | string): Promise<TMessage> {\n this.checkLegality('update');\n const startedAt = performance.now();\n // in deferred-update the source message is @original and the ack-legality check above already passed\n if (this.state === 'deferred-update') {\n const edited = await this.attempt('update', startedAt, () => this.editOriginal(response));\n this.report('update', startedAt, 'sent', edited.id);\n return edited;\n }\n const created = await this.attempt('update', startedAt, () => this.writeUpdate(response));\n this.transition('update', 'replied');\n const message = this.remember(this.requireMessage(created, 'update'));\n this.report('update', startedAt, 'sent', message.id);\n return message;\n }\n\n public async followUp(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n this.checkLegality('followUp');\n const startedAt = performance.now();\n const created = await this.attempt('followUp', startedAt, () => this.writeFollowUp(response, opts));\n const message = this.remember(created);\n this.report('followUp', startedAt, 'sent', message.id);\n return message;\n }\n\n public edit(response: ReplyResponse<TNative> | string): Promise<TMessage>;\n public edit(target: TMessage, response: ReplyResponse<TNative> | string): Promise<TMessage>;\n public async edit(\n targetOrResponse: TMessage | ReplyResponse<TNative> | string,\n maybeResponse?: ReplyResponse<TNative> | string\n ): Promise<TMessage> {\n this.checkLegality('edit');\n const startedAt = performance.now();\n if (maybeResponse === undefined) {\n // justified: the overloads narrow targetOrResponse to a response once maybeResponse is absent\n const edited = await this.attempt('edit', startedAt, () =>\n this.editOriginal(targetOrResponse as ReplyResponse<TNative> | string)\n );\n this.report('edit', startedAt, 'sent', edited.id);\n return edited;\n }\n // justified: the overloads narrow targetOrResponse to a target message once maybeResponse is defined\n const target = targetOrResponse as TMessage;\n if (!this.sent.has(target.id)) {\n throw new SeedcordError(SeedcordErrorCode.ReplyForeignEditTarget, ['edit', target.id, this.routeId]);\n }\n const written = await this.attempt('edit', startedAt, () => this.writeEditTarget(target.id, maybeResponse));\n const message = this.remember(written);\n this.report('edit', startedAt, 'sent', message.id);\n return message;\n }\n\n public delete(): Promise<void>;\n public delete(target: TMessage): Promise<void>;\n public async delete(target?: TMessage): Promise<void> {\n this.checkLegality('delete');\n const startedAt = performance.now();\n if (target === undefined) {\n await this.attempt('delete', startedAt, () => this.writeDeleteOriginal());\n this.report('delete', startedAt, 'sent', null);\n return;\n }\n if (!this.sent.has(target.id)) {\n throw new SeedcordError(SeedcordErrorCode.ReplyForeignEditTarget, ['delete', target.id, this.routeId]);\n }\n await this.attempt('delete', startedAt, () => this.writeDeleteTarget(target.id));\n // evict so a later targeted edit of this id throws foreign\n this.sent.delete(target.id);\n this.report('delete', startedAt, 'sent', null);\n }\n\n /** Routes to the verb the current ack state permits. Every state has a route, so the illegal-ack throw is unreachable. */\n public async send(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n const target = sendTarget(this.state);\n if (target === 'reply') return await this.reply(response, opts);\n if (target === 'edit') return await this.edit(response);\n return await this.followUp(response, opts);\n }\n\n /** Must be the initial response. */\n public async showModal(modal: ModalLike): Promise<void> {\n this.checkLegality('showModal');\n this.guardModalSource();\n let data: APIModalInteractionResponseCallbackData;\n try {\n data = modal.toJSON();\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a null-prototype modal has no constructor at runtime\n const name = modal.constructor?.name;\n throw translateSerializationError(error, !name || name === 'Object' ? 'modal' : name, 0, this.routeId);\n }\n const startedAt = performance.now();\n await this.attempt('showModal', startedAt, () => this.writeModal(data));\n this.transition('showModal', 'replied');\n this.report('showModal', startedAt, 'sent', null);\n }\n\n protected serialize(response: ReplyResponse<TNative> | string): SerializedReply<TNative> {\n return serializeReply(response, this.routeId);\n }\n\n protected remember(created: TMessage): TMessage {\n this.sent.add(created.id);\n return created;\n }\n\n // a with_response callback always returns the created message. this only trips if the wire says otherwise\n private requireMessage(created: TMessage | undefined, method: 'reply' | 'update'): TMessage {\n if (!created) throw new SeedcordError(SeedcordErrorCode.ReplyCallbackMissingMessage, [method, this.routeId]);\n return created;\n }\n\n private async editOriginal(response: ReplyResponse<TNative> | string): Promise<TMessage> {\n const edited = await this.writeEditOriginal(response);\n // after a deferUpdate the source message is @original, which this interaction did not send\n if (this.state !== 'deferred-update') this.remember(edited);\n return edited;\n }\n\n private checkLegality(method: ReplyMethod): void {\n checkAckLegality(method, this.state, this.routeId, this.ackedBy);\n }\n\n private transition(method: ReplyMethod, state: AckState): void {\n this.state = state;\n this.ackedBy = new AckTrace(method);\n }\n\n // gateway overrides this to reject a modal-submit source\n protected guardModalSource(): void {}\n\n protected abstract writeReply(\n response: ReplyResponse<TNative> | string,\n opts?: SendOpts\n ): Promise<TMessage | undefined>;\n protected abstract writeDefer(opts?: DeferOpts): Promise<void>;\n protected abstract writeDeferUpdate(): Promise<void>;\n protected abstract writeUpdate(response: ReplyResponse<TNative> | string): Promise<TMessage | undefined>;\n protected abstract writeFollowUp(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage>;\n protected abstract writeEditOriginal(response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected abstract writeEditTarget(targetId: string, response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected abstract writeDeleteOriginal(): Promise<void>;\n protected abstract writeDeleteTarget(targetId: string): Promise<void>;\n protected abstract writeModal(data: APIModalInteractionResponseCallbackData): Promise<void>;\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,6 +1,6 @@
1
1
  import { n as CommandBuilder, r as DeployResult } from "./basic-Dng__Ena.mjs";
2
- import { _ as Bus, a as PluginCtor, d as Transport, f as TransportAssert, g as CoreBase, h as StartupPhase, i as PluginArgs, l as Runtime, m as ShutdownPhase, n as Initializeable, o as PluginLike, s as ChannelKeyAssert, t as CoreParamAssert, u as RuntimeAssert } from "./Plugin-qRc7Ch4g.mjs";
3
- import "./index-C0k7lRDi.mjs";
2
+ import { _ as Bus, a as PluginCtor, d as Transport, f as TransportAssert, g as CoreBase, h as StartupPhase, i as PluginArgs, l as Runtime, m as ShutdownPhase, n as Initializeable, o as PluginLike, s as ChannelKeyAssert, t as CoreParamAssert, u as RuntimeAssert } from "./Plugin-Cl5P7-PO.mjs";
3
+ import "./index-TYnQ-ztr.mjs";
4
4
  import { t as ContextMenuLeaves } from "./contextMenuLeaves-COzDYa6c.mjs";
5
5
  import { Logger } from "@seedcord/logger";
6
6
  import { REST } from "@discordjs/rest";
@@ -68,17 +68,18 @@ declare class CoordinatedStartup extends CoordinatedLifecycle<StartupPhase> {
68
68
  protected isAborted(): boolean;
69
69
  abort(): void;
70
70
  get isReady(): boolean;
71
- get isRunning(): boolean;
72
71
  }
73
72
  //#endregion
74
73
  //#region src/node/HealthCheck.d.ts
75
74
  declare class HealthCheck {
76
75
  readonly logger: Logger;
77
- readonly port: number;
78
- readonly host: string | undefined;
76
+ private readonly _port;
77
+ private readonly _host;
79
78
  private readonly responder;
80
79
  private server?;
81
80
  constructor(shutdown: CoordinatedShutdown, options?: HealthCheckConfig);
81
+ get port(): number;
82
+ get host(): string | undefined;
82
83
  get path(): string;
83
84
  static fromOption(shutdown: CoordinatedShutdown, option?: HealthCheckOption): HealthCheck | undefined;
84
85
  init(): Promise<void>;
@@ -1,17 +1,16 @@
1
- import { g as contextMenuLeaves, i as BuilderComponent, m as SubscribeMetadataKey, s as CommandMetadataKey } from "./publishDefault-BCrMG9T8.mjs";
1
+ import { S as SubscribeMetadataKey, c as Subscriber, f as BuilderComponent, h as CommandMetadataKey, n as busLoggerOf, r as registrationFor, w as contextMenuLeaves } from "./Bus-DcuUtOEL.mjs";
2
2
  import { n as StartupPhase, t as ShutdownPhase } from "./phases-BauKJOTT.mjs";
3
- import { n as registrationFor, o as Subscriber } from "./subscribers-nEpbJj3Z.mjs";
3
+ import "./subscribers-DuHg-bGT.mjs";
4
4
  import { t as getDevChannel } from "./devChannel-CQU7hq7Q.mjs";
5
- import { n as resolvedLifecycleSpecOf } from "./Plugin-CDAV7P9l.mjs";
5
+ import { n as pluginLoggerOf, r as resolvedLifecycleSpecOf } from "./Plugin-Bkeqcjy6.mjs";
6
6
  import { t as slashRouteLeaves } from "./slashRouteLeaves-De1SxqnX.mjs";
7
- import { t as HmrModuleHandler } from "./HmrModuleHandler-KxRP8lqJ.mjs";
7
+ import { t as HmrModuleHandler } from "./HmrModuleHandler-9AUfKXRl.mjs";
8
8
  import { SlashCommandBuilder } from "@discordjs/builders";
9
- import { FRAMEWORK_CHANNELS, Logger, paint } from "@seedcord/logger";
9
+ import { SeedcordErrorCode, paint } from "@seedcord/errors";
10
+ import { FRAMEWORK_CHANNELS, Logger } from "@seedcord/logger";
10
11
  import { Routes } from "discord-api-types/v10";
11
- import { SeedcordErrorCode } from "@seedcord/errors";
12
- import { SeedcordError } from "@seedcord/errors/internal";
12
+ import { SeedcordAggregateError, SeedcordError } from "@seedcord/errors/internal";
13
13
  import { formatFilePath } from "@seedcord/utils";
14
- import chalk from "chalk";
15
14
  import { Envapter } from "envapt";
16
15
  import { resolve } from "node:path";
17
16
  import { createServer } from "node:http";
@@ -59,7 +58,7 @@ var CoordinatedLifecycle = class {
59
58
  task,
60
59
  timeout: timeoutMs
61
60
  });
62
- this.logger.debug(`${chalk.italic("Added")} ${this.getTaskType()} task ${paint.sky.bold(taskName)} to phase ${paint.iris.bold(this.phaseEnum[phase])}`);
61
+ this.logger.debug(`${paint.italic("Added")} ${this.getTaskType()} task ${paint.sky.bold(taskName)} to phase ${paint.iris.bold(this.phaseEnum[phase])}`);
63
62
  }
64
63
  removeTask(phase, taskName) {
65
64
  if (!this.canRemoveTask()) return false;
@@ -69,7 +68,7 @@ var CoordinatedLifecycle = class {
69
68
  const filteredTasks = tasks.filter((task) => task.name !== taskName);
70
69
  this.tasksMap.set(phase, filteredTasks);
71
70
  const removed = initialLength !== filteredTasks.length;
72
- if (removed) this.logger.debug(`${chalk.italic("Removed")} ${this.getTaskType()} task ${paint.sky.bold(taskName)} from phase ${paint.iris.bold(this.phaseEnum[phase])}`);
71
+ if (removed) this.logger.debug(`${paint.italic("Removed")} ${this.getTaskType()} task ${paint.sky.bold(taskName)} from phase ${paint.iris.bold(this.phaseEnum[phase])}`);
73
72
  return removed;
74
73
  }
75
74
  async runPhase(phase) {
@@ -79,18 +78,21 @@ var CoordinatedLifecycle = class {
79
78
  return;
80
79
  }
81
80
  this.logger.debug(`${paint.amber.bold("Running")} ${this.getTaskType()} phase ${paint.iris.bold(this.phaseEnum[phase])} with ${paint.sky.bold(String(tasks.length))} tasks`);
82
- const failures = (await this.executeTasksInPhase(phase, tasks)).filter((r) => r.status === "rejected").length;
83
- if (failures > 0) throw new SeedcordError(SeedcordErrorCode.LifecyclePhaseFailures, [this.phaseEnum[phase], failures]);
81
+ const reasons = (await this.executeTasksInPhase(phase, tasks)).reduce((rejected, result) => {
82
+ if (result.status === "rejected") rejected.push(result.reason);
83
+ return rejected;
84
+ }, []);
85
+ if (reasons.length > 0) throw new SeedcordAggregateError(SeedcordErrorCode.LifecyclePhaseFailures, reasons, [this.phaseEnum[phase], reasons.length]);
84
86
  this.logger.debug(`Phase ${paint.iris.bold(this.phaseEnum[phase])} ${paint.mint.bold("completed successfully")}`);
85
87
  }
86
88
  async runTaskWithTimeout(phase, task) {
87
- this.logger.trace(`${chalk.italic("Starting")} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}`);
89
+ this.logger.trace(`${paint.italic("Starting")} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}`);
88
90
  try {
89
91
  await withTimeout(task.name, task.task, task.timeout);
90
- this.logger.trace(`${chalk.italic("Completed")} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}`);
92
+ this.logger.trace(`${paint.italic("Completed")} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}`);
91
93
  } catch (error) {
92
94
  if (this.isAborted()) return;
93
- this.logger.error(`${chalk.italic("Failed")} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}:`, error);
95
+ this.logger.error(`${paint.italic("Failed")} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}:`, error);
94
96
  throw error;
95
97
  }
96
98
  }
@@ -134,11 +136,11 @@ var CoordinatedShutdown = class extends CoordinatedLifecycle {
134
136
  }
135
137
  registerSignalHandlers() {
136
138
  this.onSigTerm = () => {
137
- this.logger.info(`Received ${chalk.yellow.bold("SIGTERM")} signal`);
139
+ this.logger.info(`Received ${paint.amber.bold("SIGTERM")} signal`);
138
140
  this.run(0);
139
141
  };
140
142
  this.onSigInt = () => {
141
- this.logger.info(`Received ${chalk.yellow.bold("SIGINT")} signal`);
143
+ this.logger.info(`Received ${paint.amber.bold("SIGINT")} signal`);
142
144
  this.run(0);
143
145
  };
144
146
  process.on("SIGTERM", this.onSigTerm);
@@ -173,7 +175,7 @@ var CoordinatedShutdown = class extends CoordinatedLifecycle {
173
175
  }
174
176
  this.isShuttingDown = true;
175
177
  this.exitCode = exitCode;
176
- this.logger.info(`${chalk.bold.yellow("Starting")} coordinated shutdown with exit code ${chalk.bold.cyan(exitCode)}`);
178
+ this.logger.info(`${paint.amber.bold("Starting")} coordinated shutdown with exit code ${paint.sky.bold(exitCode)}`);
177
179
  try {
178
180
  if (this.startupGate) await this.startupGate;
179
181
  const failures = [];
@@ -182,17 +184,17 @@ var CoordinatedShutdown = class extends CoordinatedLifecycle {
182
184
  } catch (error) {
183
185
  failures.push(error);
184
186
  }
185
- if (failures.length > 0) this.logger.error(`${chalk.bold.red("Coordinated shutdown failed")}`, ...failures);
186
- else this.logger.info(`${chalk.bold.green("Coordinated shutdown completed")} successfully`);
187
+ if (failures.length > 0) this.logger.error(`${paint.coral.bold("Coordinated shutdown failed")}`, ...failures);
188
+ else this.logger.info(`${paint.mint.bold("Coordinated shutdown completed")} successfully`);
187
189
  } finally {
188
190
  this.hasShutdown = true;
189
191
  if (exitProcess) {
190
- this.logger.debug(`${chalk.bold.red("Exiting")} process with code ${chalk.bold.cyan(this.exitCode)}`);
192
+ this.logger.debug(`${paint.coral.bold("Exiting")} process with code ${paint.sky.bold(this.exitCode)}`);
191
193
  setTimeout(() => {
192
194
  process.exit(this.exitCode);
193
195
  }, LOG_FLUSH_DELAY_MS);
194
196
  } else {
195
- this.logger.debug(`${chalk.bold.yellow("Skipping")} process exit (dev mode)`);
197
+ this.logger.debug(`${paint.amber.bold("Skipping")} process exit (dev mode)`);
196
198
  this.isShuttingDown = false;
197
199
  }
198
200
  }
@@ -241,7 +243,7 @@ var CoordinatedStartup = class extends CoordinatedLifecycle {
241
243
  return;
242
244
  }
243
245
  this.isStartingUp = true;
244
- this.logger.info(`${chalk.bold.green("Starting")} coordinated startup sequence`);
246
+ this.logger.info(`${paint.mint.bold("Starting")} coordinated startup sequence`);
245
247
  try {
246
248
  for (const phase of PHASE_ORDER) {
247
249
  if (!this.isStartingUp) {
@@ -251,13 +253,13 @@ var CoordinatedStartup = class extends CoordinatedLifecycle {
251
253
  await this.runPhase(phase);
252
254
  }
253
255
  this.hasStarted = true;
254
- this.logger.info(`${chalk.bold.green("Coordinated startup completed")} successfully`);
256
+ this.logger.info(`${paint.mint.bold("Coordinated startup completed")} successfully`);
255
257
  } catch (error) {
256
258
  if (!this.isStartingUp) {
257
259
  this.logger.warn("Startup sequence aborted during error handling");
258
260
  return;
259
261
  }
260
- this.logger.error(`${chalk.bold.red("Coordinated startup failed")}`);
262
+ this.logger.error(`${paint.coral.bold("Coordinated startup failed")}`);
261
263
  throw error;
262
264
  } finally {
263
265
  this.isStartingUp = false;
@@ -274,9 +276,6 @@ var CoordinatedStartup = class extends CoordinatedLifecycle {
274
276
  get isReady() {
275
277
  return this.hasStarted;
276
278
  }
277
- get isRunning() {
278
- return this.isStartingUp;
279
- }
280
279
  };
281
280
 
282
281
  //#endregion
@@ -305,16 +304,22 @@ const HTTP_NOT_FOUND = 404;
305
304
  const DEFAULT_HEALTH_CHECK_PORT = 6967;
306
305
  var HealthCheck = class HealthCheck {
307
306
  logger = new Logger("HealthCheck", { channel: "health" });
308
- port;
309
- host;
307
+ _port;
308
+ _host;
310
309
  responder;
311
310
  server;
312
311
  constructor(shutdown, options) {
313
- this.port = options?.port ?? DEFAULT_HEALTH_CHECK_PORT;
314
- this.host = options?.host;
312
+ this._port = options?.port ?? DEFAULT_HEALTH_CHECK_PORT;
313
+ this._host = options?.host;
315
314
  this.responder = new HealthResponder(options?.path);
316
315
  shutdown.addTask(2, "stop-healthcheck-server", () => this.stop());
317
316
  }
317
+ get port() {
318
+ return this._port;
319
+ }
320
+ get host() {
321
+ return this._host;
322
+ }
318
323
  get path() {
319
324
  return this.responder.path;
320
325
  }
@@ -335,16 +340,16 @@ var HealthCheck = class HealthCheck {
335
340
  server.once("listening", () => {
336
341
  server.removeListener("error", onListenError);
337
342
  server.on("error", (err) => this.logger.error("Health check server error", err));
338
- const address = this.host ?? "localhost";
339
- this.logger.info(`${paint.mint.bold("✔︎")} Health check server listening on ${paint.sky(`http://${address}:${this.port}${this.path}`)}`);
343
+ const address = this._host ?? "localhost";
344
+ this.logger.info(`${paint.mint.bold("✔︎")} Health check server listening on ${paint.sky.bold(`http://${address}:${this._port}${this.path}`)}`);
340
345
  resolve();
341
346
  });
342
- if (this.host) {
343
- this.logger.debug(`Binding health check server to ${this.host}`);
344
- server.listen(this.port, this.host);
347
+ if (this._host) {
348
+ this.logger.debug(`Binding health check server to ${this._host}`);
349
+ server.listen(this._port, this._host);
345
350
  } else {
346
351
  this.logger.debug("Binding health check server to all interfaces");
347
- server.listen(this.port);
352
+ server.listen(this._port);
348
353
  }
349
354
  });
350
355
  }
@@ -454,7 +459,7 @@ var Pluggable = class Pluggable {
454
459
  if (RESERVED_KEYS.has(key)) throw new SeedcordError(SeedcordErrorCode.CorePluginReservedChannel, [key]);
455
460
  if (key in this) throw new SeedcordError(SeedcordErrorCode.CorePluginKeyExists, [key]);
456
461
  const instance = new Plugin(this, ...args);
457
- instance.logger.setChannel(key);
462
+ pluginLoggerOf(instance).setChannel(key);
458
463
  this.plugins.push(instance);
459
464
  this.attachments.push({
460
465
  key,
@@ -483,9 +488,9 @@ var Pluggable = class Pluggable {
483
488
  for (const attachment of group) {
484
489
  const { key, instance } = attachment;
485
490
  const spec = resolvedLifecycleSpecOf(instance);
486
- instance.logger.utils.initialization(key, "start");
491
+ pluginLoggerOf(instance).utils.initialization(key, "start");
487
492
  await withTimeout(`Plugin (${key})`, () => instance.init(), spec.init.timeout);
488
- instance.logger.utils.initialization(key, "end");
493
+ pluginLoggerOf(instance).utils.initialization(key, "end");
489
494
  this.completedInits.add(attachment);
490
495
  if (instance.dispose) this.registerDisposeTask(spec.dispose.phase);
491
496
  }
@@ -520,7 +525,7 @@ var Pluggable = class Pluggable {
520
525
  const failures = [];
521
526
  await this.disposeCompleted(phase, (caught) => failures.push(caught));
522
527
  if (failures.length === 1) throw failures[0];
523
- if (failures.length > 1) throw new AggregateError(failures, "plugin dispose failures");
528
+ if (failures.length > 1) throw new SeedcordAggregateError(SeedcordErrorCode.PluginDisposeFailures, failures, [failures.length]);
524
529
  }
525
530
  async disposeCompleted(phase, onError) {
526
531
  for (const attachment of [...this.attachments].reverse()) {
@@ -561,7 +566,7 @@ var SubscriberLoader = class {
561
566
  registerHandler: this.registerSubscriber.bind(this),
562
567
  unregisterHandler: this.unregisterSubscriber.bind(this),
563
568
  getArtifacts: this.getArtifacts.bind(this),
564
- logger: this.bus.logger
569
+ logger: busLoggerOf(this.bus)
565
570
  });
566
571
  }
567
572
  /** @internal */
@@ -571,9 +576,9 @@ var SubscriberLoader = class {
571
576
  this.bus.registerDefaults();
572
577
  const { directory } = this;
573
578
  if (directory) {
574
- this.bus.logger.debug(chalk.bold(directory));
579
+ busLoggerOf(this.bus).debug(paint.mute(directory));
575
580
  await this.load(directory);
576
- this.bus.logger.utils.list([`${chalk.bold.magenta(this.bus.registeredCount)} subscribers`], chalk.bold.green("Loaded"), "debug");
581
+ busLoggerOf(this.bus).utils.list([`${paint.iris.bold(this.bus.registeredCount)} subscribers`], paint.mint.bold("Loaded"), "debug");
577
582
  }
578
583
  if (!Envapter.isTest) await this.bus.verifyWebhooks();
579
584
  }
@@ -588,7 +593,7 @@ var SubscriberLoader = class {
588
593
  if (!this.isSubscriber(value)) continue;
589
594
  this.registerSubscriber(value);
590
595
  this.hmrHandler?.trackHandler(fullPath, value);
591
- this.bus.logger.utils.registration(value.name, relativePath, void 0, "trace");
596
+ busLoggerOf(this.bus).utils.registration(value.name, relativePath, void 0, "trace");
592
597
  }
593
598
  });
594
599
  }
@@ -678,11 +683,11 @@ var CommandRegistry = class {
678
683
  /** @internal */
679
684
  async refresh(shouldRefresh = true) {
680
685
  if (!shouldRefresh) {
681
- this.logger.debug(chalk.italic("Command refresh cancelled."));
686
+ this.logger.debug(paint.italic("Command refresh cancelled."));
682
687
  this.pendingEvents.clear();
683
688
  return;
684
689
  }
685
- this.logger.debug(chalk.italic("Refreshing commands..."));
690
+ this.logger.debug(paint.italic("Refreshing commands..."));
686
691
  for (const event of this.pendingEvents.values()) await this.hmrHandler?.handle(event);
687
692
  this.pendingEvents.clear();
688
693
  await this.setCommands();
@@ -760,7 +765,7 @@ var CommandRegistry = class {
760
765
  const deployed = await this.put(Routes.applicationGuildCommands(appId, guildId), commands);
761
766
  result.guilds.set(guildId, indexById(deployed));
762
767
  const tag = commands.length === 1 ? "command" : "commands";
763
- this.logger.utils.block(`Deployed ${commands.length} ${tag} to ${paint.amber.bold(guildId)}`, this.logger.utils.wrap(commands.map((command) => command.name)), "info");
768
+ this.logger.utils.block(`Deployed ${paint.iris.bold(commands.length)} ${tag} to ${paint.sky.bold(guildId)}`, this.logger.utils.wrap(commands.map((command) => command.name)), "info");
764
769
  }
765
770
  this.options.onDeployed?.(result);
766
771
  return result;