import type { APIInteraction } from 'discord-api-types/v10' import defu from 'defu' import type { PartialDeep } from 'type-fest' import { ConfigInternals, type CordoConfig, type ParsedCordoConfig } from './files/config' import { LockfileInternals } from './files/lockfile' import { CordoGateway } from './gateway' import { RoutingFilesystem } from './routing/filesystem' import { CordoMagic } from './magic' import type { CordoInteraction } from './interaction' import { CommandInternals } from './files/command' export { type DynamicTypes } from './dynamic-types' export { type CordoConfig, defineCordoConfig } from './files/config' export { type CordoRoute, type RouteRequest, defineCordoRoute, assertCordoRequest } from './files/route' export { type CordoCommand, defineCordoCommand } from './files/command' export { type CordoErrorBoundary, defineCordoErrorBoundary } from './files/error-boundary' export { type CordoInteraction } from './interaction' // let lockfile: LockfileInternals.ParsedLockfile | null = null let config: ParsedCordoConfig | null = null async function mountCordo(configOverrides?: PartialDeep) { const fileConfig = await ConfigInternals.readAndParseConfig() config = configOverrides ? defu(configOverrides, fileConfig) as ParsedCordoConfig : fileConfig lockfile = await LockfileInternals.readOrCreateLockfile(config.paths.lockfile) await RoutingFilesystem.readFsTreeAndSyncLockfile(config.paths.routes, lockfile, config) LockfileInternals.writeLockfile(config.paths.lockfile, lockfile, config.paths.types) } function triggerInteraction(interaction: APIInteraction, opts: { httpCallback?: (payload: any) => any } = {}) { if (!lockfile || !config) throw new Error('Cordo is not mounted') CordoGateway.triggerInteraction({ interaction, httpCallback: opts.httpCallback, lockfile, config }) } /** * you can provide constants you will commonly use in your routes to cordo * cordo will then create a lookup table to more efficiently access these constants in internal routing * you should not notice any difference but it will allow you to store more data on click or submit functions */ function registerConstants(constants: readonly string[]) { if (!lockfile || !config) throw new Error('Cordo is not mounted') let changesMade = false for (const entry of constants) { if (entry.length <= LockfileInternals.Const.idLength) // too short to save any space continue if (lockfile!.lut.includes(entry)) continue lockfile.lut[lockfile.reg.lutCounter++] = entry changesMade = true } if (changesMade) return LockfileInternals.writeLockfile(config!.paths.lockfile, lockfile!, config!.paths.types) else return Promise.resolve() } // export const Cordo = { mountCordo, registerConstants, triggerInteraction, respondToRawInteraction: CordoGateway.respondTo, syncCommands: (opts?: { maxRetries?: number }) => CommandInternals.syncCommands(lockfile!.$runtime.registeredCommands, undefined, opts) } Object.freeze(Cordo) export namespace Extend { export function runInCordoContext( fn: () => any, ctx?: { invoker?: CordoInteraction lockfile?: LockfileInternals.ParsedLockfile config?: ParsedCordoConfig } ) { CordoMagic.Internals.runWithCtx(fn, { invoker: ctx?.invoker ?? null, lockfile: ctx?.lockfile ?? lockfile, config: ctx?.config ?? config, cwd: '', idCounter: 0 }) } }