@usebridger/core 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -0
- package/dist/adapter.d.mts +1 -1
- package/dist/index.d.mts +58 -39
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +344 -44
- package/dist/index.mjs.map +1 -1
- package/dist/{reconnection-BGpkqq4C.d.mts → reconnection-COfwSj9L.d.mts} +91 -52
- package/dist/reconnection-COfwSj9L.d.mts.map +1 -0
- package/package.json +1 -1
- package/dist/reconnection-BGpkqq4C.d.mts.map +0 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["isThenable","SEPARATORS","isThenable","validTimeout","isThenable","join","isThenable"],"sources":["../src/text/format.ts","../src/actions/actions.ts","../src/commands/catalog.ts","../src/commands/prefixes.ts","../src/commands/command.ts","../src/commands/registry.ts","../src/deadline.ts","../src/commands/roles.ts","../src/commands/args.ts","../src/commands/router.ts","../src/config/owners.ts","../src/logger/logger.ts","../src/config/schema.ts","../src/config/env.ts","../src/config/errors.ts","../src/config/plugin-configs.ts","../src/conversations/conversations.ts","../src/events/bus.ts","../src/groups/groups.ts","../src/http/server.ts","../src/logger/deferred.ts","../src/logger/secrets.ts","../src/middleware/chat-filter.ts","../src/middleware/ignore-bots.ts","../src/middleware/ignore-self.ts","../src/middleware/pipeline.ts","../src/middleware/rate-limit.ts","../src/middleware/sanitize.ts","../src/text/split.ts","../src/outbound/text.ts","../src/outbound/actions.ts","../src/outbound/album.ts","../src/outbound/queue.ts","../src/events/names.ts","../src/plugin/semver.ts","../src/plugin/define.ts","../src/version.ts","../src/plugin/declared.ts","../src/plugin/order.ts","../src/plugin/report.ts","../src/plugin/host.ts","../src/plugin/sources.ts","../src/queue/inbound.ts","../src/tenant/scope.ts","../src/scheduler/service.ts","../src/services/registry.ts","../src/storage/memory.ts","../src/unsafe/access.ts","../src/outbound/reply.ts","../src/bot/message-context.ts","../src/storage/tenant.ts","../src/bot/plugin-context.ts","../src/bot/reconnect.ts","../src/bot/session.ts","../src/bot/session-lease.ts","../src/bot/stop-hooks.ts","../src/bot/bot.ts"],"sourcesContent":["// Texto formatado neutro (ADR 0061). O plugin monta uma árvore mínima com os helpers, e o\n// transport a traduz para a marcação da plataforma, com o escape dela. Texto cru (string) continua\n// valendo e vai ao transport como veio.\n\nimport type { Contact } from '#message/types.ts';\n\n/** O que uma menção precisa para virar `@número`, `<@id>` ou `text_mention` no transport. */\nexport type MentionTarget = Pick<Contact, 'id' | 'name' | 'phone' | 'username'>;\n\n/** Nó da árvore de `FormattedText`. Uma string é texto literal, que o transport escapa. */\nexport type TextNode =\n | string\n | { readonly type: 'bold' | 'italic'; readonly children: readonly TextNode[] }\n | { readonly type: 'code'; readonly text: string }\n | { readonly type: 'link'; readonly url: string; readonly children: readonly TextNode[] }\n | { readonly type: 'mention'; readonly contact: MentionTarget };\n\n/** Texto formatado neutro, congelado. Monte com `fmt`, `bold`, `italic`, `code`, `link` e `mention`. */\nexport interface FormattedText {\n readonly type: 'formatted';\n readonly nodes: readonly TextNode[];\n}\n\n/** Texto que o plugin envia: cru (a marcação da plataforma, sem escape) ou formatado neutro. */\nexport type MessageText = string | FormattedText;\n\n/** Parte que os helpers aceitam: texto literal ou outro trecho formatado. */\nexport type TextPart = string | FormattedText;\n\n/** Monta o `FormattedText`; os nós já vêm validados e congelados. */\nexport function formatted(nodes: readonly TextNode[]): FormattedText {\n return Object.freeze({ type: 'formatted', nodes: Object.freeze([...nodes]) });\n}\n\n/** Nós de `parts`, sem string vazia; lança `TypeError` para o que não é texto (JS sem tipos). */\nfunction nodesOf(parts: readonly unknown[], where: string): TextNode[] {\n const nodes: TextNode[] = [];\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') nodes.push(part);\n } else if (isFormatted(part)) {\n nodes.push(...part.nodes);\n } else {\n throw new TypeError(`${where}: esperava string ou texto formatado, recebeu ${typeof part}`);\n }\n }\n return nodes;\n}\n\nexport function isFormatted(value: unknown): value is FormattedText {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { type?: unknown }).type === 'formatted' &&\n Array.isArray((value as { nodes?: unknown }).nodes)\n );\n}\n\n// Um estilo sem conteúdo some: `****` no Discord e entity vazia no Telegram dão erro ou lixo.\nfunction style(type: 'bold' | 'italic', parts: readonly TextPart[]): FormattedText {\n const children = nodesOf(parts, type);\n if (children.length === 0) return formatted([]);\n return formatted([Object.freeze({ type, children: Object.freeze(children) })]);\n}\n\nexport function bold(...parts: TextPart[]): FormattedText {\n return style('bold', parts);\n}\n\nexport function italic(...parts: TextPart[]): FormattedText {\n return style('italic', parts);\n}\n\n/** Código em linha. O conteúdo é sempre literal: não aceita outra formatação dentro. */\nexport function code(text: string): FormattedText {\n if (typeof text !== 'string') throw new TypeError('code: esperava string');\n if (text === '') return formatted([]);\n return formatted([Object.freeze({ type: 'code', text })]);\n}\n\n/**\n * Link com rótulo; sem rótulo, mostra a URL. Só `http:` e `https:`: no web a URL vira `href`, e\n * `javascript:` seria XSS.\n */\nexport function link(url: string, label?: TextPart): FormattedText {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch (error) {\n throw new TypeError(`link: URL inválida: ${String(url)}`, { cause: error });\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new TypeError(`link: só http e https são aceitos: ${url}`);\n }\n const children = nodesOf([label ?? url], 'link');\n return formatted([\n Object.freeze({\n type: 'link',\n url,\n children: Object.freeze(children.length ? children : [url]),\n }),\n ]);\n}\n\n/**\n * Menção portátil. O transport põe a sintaxe da plataforma e notifica o contato. Guarda só os\n * campos de que precisa, para não levar os `claims` do contato ao conteúdo enviado.\n */\nexport function mention(contact: MentionTarget): FormattedText {\n if (typeof contact?.id !== 'string' || contact.id === '') {\n throw new TypeError('mention: o contato precisa de um `id`');\n }\n const target: MentionTarget = Object.freeze({\n id: contact.id,\n name: contact.name ?? null,\n phone: contact.phone ?? null,\n ...(contact.username !== undefined && { username: contact.username }),\n });\n return formatted([Object.freeze({ type: 'mention', contact: target })]);\n}\n\n/**\n * Tag que compõe o texto: `` fmt`Notas de ${bold(aluno)}: ${nota}` ``. Valores interpolados são\n * literais, então o texto do usuário nunca vira marcação.\n */\nexport function fmt(\n strings: TemplateStringsArray,\n ...values: readonly (TextPart | number)[]\n): FormattedText {\n const parts: unknown[] = [];\n strings.forEach((literal, index) => {\n parts.push(literal);\n if (index < values.length) {\n const value = values[index];\n parts.push(typeof value === 'number' ? String(value) : value);\n }\n });\n return formatted(nodesOf(parts, 'fmt'));\n}\n\n/**\n * Texto visível, sem marcação: o que a pessoa lê. Uma menção vira `@` mais o usuário, o nome, o\n * telefone ou o ID, nessa ordem. A string crua volta como está.\n */\nexport function plainText(text: MessageText): string {\n if (typeof text === 'string') return text;\n let out = '';\n const walk = (nodes: readonly TextNode[]): void => {\n for (const node of nodes) {\n if (typeof node === 'string') out += node;\n else if (node.type === 'code') out += node.text;\n else if (node.type === 'mention') out += `@${mentionLabel(node.contact)}`;\n else walk(node.children);\n }\n };\n walk(text.nodes);\n return out;\n}\n\nfunction mentionLabel(contact: MentionTarget): string {\n return contact.username ?? contact.name ?? contact.phone ?? contact.id;\n}\n","// Ações (ADR 0062): o botão leva só um ID opaco, e o kernel guarda o que o clique roda. O\n// cliente (Telegram, web) não forja um clique com outro comando ou outros argumentos, e o ID cabe\n// nos 64 bytes do `callback_data` do Telegram.\n\nimport { randomBytes } from 'node:crypto';\nimport type { JsonValue } from '#storage/types.ts';\nimport { fmt, type MessageText } from '#text/format.ts';\n\n/** Botão que roda um comando registrado (de qualquer plugin), como se a pessoa o digitasse. */\nexport interface CommandAction {\n /** Texto do botão. */\n readonly label: string;\n /** Nome ou alias do comando, sem o prefixo. */\n readonly command: string;\n /** Argumentos, entregues como vieram em `ctx.args`; o `rawArgs` é a junção por espaços. */\n readonly args?: readonly string[];\n}\n\n/** Botão que roda um passo de conversa do próprio plugin (ADR 0060), com o `data` da ação. */\nexport interface StepAction {\n /** Texto do botão. */\n readonly label: string;\n /** Passo definido com `ctx.conversations.define`. */\n readonly step: string;\n /** Entregue ao passo em `ctx.data`. Padrão: `null`. */\n readonly data?: JsonValue;\n}\n\n/** Ação anexada a uma resposta (`ctx.reply(text, { actions })`). */\nexport type MessageAction = CommandAction | StepAction;\n\n/**\n * O que o clique roda, guardado pelo kernel sob o ID do botão. O `label` vira o texto da mensagem\n * do clique.\n */\nexport type ActionTarget =\n | {\n readonly kind: 'command';\n readonly label: string;\n readonly command: string;\n readonly args: readonly string[];\n }\n | {\n readonly kind: 'step';\n readonly label: string;\n readonly plugin: string;\n readonly step: string;\n readonly data: JsonValue;\n };\n\n/** Validade de um botão: 24 horas. */\nexport const ACTION_TTL_MS: number = 24 * 60 * 60_000;\n\n/** Máximo de botões guardados; acima disso, saem os mais antigos. */\nexport const MAX_STORED_ACTIONS = 10_000;\n\ninterface StoredAction {\n readonly chatId: string;\n readonly target: ActionTarget;\n readonly expiresAt: number;\n}\n\n/**\n * Alvos dos botões de um bot (estado no closure do bot, ADR 0004). Sem timer: o vencido sai ao\n * ser consultado e quando entram IDs novos, e nada sobrevive ao `stop()`.\n */\nexport class ActionRegistry {\n // O `Map` guarda a ordem de inserção, que é a de vencimento: a poda olha só o começo.\n readonly #actions = new Map<string, StoredAction>();\n readonly #now: () => number;\n\n constructor(now: () => number = Date.now) {\n this.#now = now;\n }\n\n /** Guarda o alvo, preso ao chat, e devolve o ID do botão. */\n register(chatId: string, target: ActionTarget): string {\n const now = this.#now();\n this.#prune(now);\n // 12 bytes viram 16 caracteres base64url: imprevisível e dentro dos 64 bytes do Telegram.\n const id = randomBytes(12).toString('base64url');\n this.#actions.set(id, { chatId, target, expiresAt: now + ACTION_TTL_MS });\n return id;\n }\n\n /** O alvo do botão clicado no chat, ou `undefined` se vencido, desconhecido ou de outro chat. */\n resolve(id: string, chatId: string): ActionTarget | undefined {\n const stored = this.#actions.get(id);\n if (stored === undefined) return undefined;\n if (stored.expiresAt <= this.#now()) {\n this.#actions.delete(id);\n return undefined;\n }\n return stored.chatId === chatId ? stored.target : undefined;\n }\n\n /** Descarta tudo (shutdown). */\n clear(): void {\n this.#actions.clear();\n }\n\n get size(): number {\n return this.#actions.size;\n }\n\n #prune(now: number): void {\n for (const [id, stored] of this.#actions) {\n if (stored.expiresAt > now && this.#actions.size < MAX_STORED_ACTIONS) return;\n this.#actions.delete(id);\n }\n }\n}\n\n/** O texto com o menu numerado (`1. rótulo`) no fim, para o transport sem botões. */\nexport function numberedMenu(text: MessageText, labels: readonly string[]): MessageText {\n const menu = labels.map((label, index) => `${index + 1}. ${label}`).join('\\n');\n // Na árvore, o rótulo entra como texto literal: não vira marcação.\n return typeof text === 'string' ? `${text}\\n\\n${menu}` : fmt`${text}\\n\\n${menu}`;\n}\n\nconst CHOICE = /^\\d{1,3}$/;\n\n/** Índice (a partir de 0) da opção que o texto escolhe, ou `null` se ele não é um número dela. */\nexport function pickChoice(text: string | null, count: number): number | null {\n const trimmed = text?.trim();\n if (trimmed === undefined || !CHOICE.test(trimmed)) return null;\n const choice = Number(trimmed);\n return choice >= 1 && choice <= count ? choice - 1 : null;\n}\n","import type { TransportCommands } from '#transport/types.ts';\nimport type { CommandInfo } from './command.ts';\nimport type { RegisteredCommand } from './registry.ts';\n\n/** Comando como os plugins e o transport o veem: os dados da definição, sem `run` nem `onReject`. */\nexport function commandInfo({ plugin, definition }: RegisteredCommand): CommandInfo {\n return {\n plugin,\n name: definition.name,\n aliases: [...(definition.aliases ?? [])],\n description: definition.description ?? null,\n role: definition.role ?? 'everyone',\n };\n}\n\nexport interface CommandCatalogOptions {\n /** Comandos registrados agora. */\n readonly list: () => readonly RegisteredCommand[];\n /** Destino do erro de um listener de `onChange`, que lançou ou rejeitou. */\n readonly onError: (error: unknown) => void;\n}\n\n/** A lista de comandos que o transport lê e assina (ADR 0064), com os avisos em lote. */\nexport interface CommandCatalog {\n readonly commands: TransportCommands;\n /** O registro mudou. O aviso sai no fim do tick ou, dentro de um `batch`, no fim dele. */\n changed(): void;\n /** Liga os avisos. Antes disso (o boot, que termina antes do `connect()`), nada avisa. */\n open(): void;\n /** Desliga os avisos de vez: o `teardown` do shutdown apagaria o menu da plataforma. */\n close(): void;\n /** Roda `work` segurando os avisos; ao fim, um aviso só, se a lista mudou. */\n batch<T>(work: () => Promise<T>): Promise<T>;\n}\n\ntype Listener = () => void | Promise<void>;\n\nexport function createCommandCatalog(options: CommandCatalogOptions): CommandCatalog {\n let phase: 'boot' | 'open' | 'closed' = 'boot';\n // Lotes em andamento; o reload em cascata pode aninhar.\n let holds = 0;\n let dirty = false;\n let scheduled = false;\n const listeners = new Set<Listener>();\n\n function notify(listener: Listener): void {\n try {\n const result = listener();\n if (result instanceof Promise) result.catch(options.onError);\n } catch (error) {\n options.onError(error);\n }\n }\n\n function flush(): void {\n scheduled = false;\n // Um lote aberto depois da mudança, no mesmo tick, avisa quando terminar.\n if (phase !== 'open' || holds > 0 || !dirty) return;\n dirty = false;\n for (const listener of [...listeners]) notify(listener);\n }\n\n function schedule(): void {\n if (scheduled) return;\n scheduled = true;\n // Microtask, não timer: vários `add` seguidos viram um aviso, e nada sobrevive ao `stop()`.\n queueMicrotask(flush);\n }\n\n return {\n commands: {\n list: () => options.list().map(commandInfo),\n onChange(listener) {\n // Depois do `close()`, a assinatura fica sem efeito: o `flush` não roda mais.\n if (phase !== 'closed') listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n },\n\n changed() {\n if (phase !== 'open') return;\n dirty = true;\n if (holds === 0) schedule();\n },\n\n open() {\n if (phase === 'boot') phase = 'open';\n },\n\n close() {\n phase = 'closed';\n listeners.clear();\n },\n\n async batch(work) {\n holds++;\n try {\n return await work();\n } finally {\n holds--;\n if (holds === 0 && dirty) schedule();\n }\n },\n };\n}\n","// Prefixo de comando por tipo de chat e por chat (ADR 0063). O padrão vem da config, e o override\n// de um chat fica no storage do kernel. O override é lido inteiro no boot: o roteador consulta\n// o prefixo a cada mensagem, e o caminho quente não pode ir ao storage (plano §7).\n\nimport type { Chat } from '#message/types.ts';\nimport { kernelStorage } from '#storage/namespace.ts';\nimport type { Collection, StoragePort } from '#storage/types.ts';\n\nexport const DEFAULT_PREFIX = '!';\n\n/**\n * Prefixo da config: um texto para todo chat, ou um por tipo de chat. `group` vale para todo\n * chat que não é `dm` (grupo, canal, thread). Tipo omitido: `'!'`. Vazio é permitido.\n */\nexport type PrefixConfig = string | { readonly dm?: string; readonly group?: string };\n\n/** Prefixos vistos pelo plugin (`ctx.prefixes`). */\nexport interface Prefixes {\n /** Prefixo em vigor no chat: o override dele ou o padrão do tipo de chat. */\n get(chat: Pick<Chat, 'id' | 'isGroup'>): string;\n /** Grava o override do chat. Vazio é permitido; começado por espaço em branco lança. */\n set(chatId: string, prefix: string): Promise<void>;\n /** Apaga o override, e o chat volta ao padrão do tipo. `true` se havia override. */\n reset(chatId: string): Promise<boolean>;\n}\n\nexport interface PrefixStore extends Prefixes {\n /** Lê os overrides do storage. O bot chama no boot, antes do `setup` dos plugins. */\n load(): Promise<void>;\n}\n\ntype PrefixDocument = { chat: string; prefix: string };\n\nconst LEADING_WHITESPACE = /^\\s/;\n\n/**\n * Valida um prefixo. O texto da mensagem perde os espaços iniciais antes do match, então um\n * prefixo começado por espaço em branco nunca casaria.\n */\nexport function validatePrefix(prefix: unknown, label: string): string {\n if (typeof prefix !== 'string') throw new TypeError(`${label}: o prefixo deve ser texto`);\n if (LEADING_WHITESPACE.test(prefix)) {\n throw new TypeError(`${label}: o prefixo não pode começar com espaço em branco`);\n }\n return prefix;\n}\n\nexport function createPrefixStore(\n config: PrefixConfig | undefined,\n port: StoragePort,\n): PrefixStore {\n const split = typeof config === 'object' ? config : { dm: config, group: config };\n const dm = validatePrefix(split.dm ?? DEFAULT_PREFIX, 'prefix.dm').toLowerCase();\n const group = validatePrefix(split.group ?? DEFAULT_PREFIX, 'prefix.group').toLowerCase();\n const overrides = new Map<string, string>();\n // A coleção só é aberta no primeiro uso: o `createBot` não faz I/O.\n let chats: Collection<PrefixDocument> | undefined;\n const collection = (): Collection<PrefixDocument> => {\n chats ??= kernelStorage(port, 'prefixes').collection<PrefixDocument>('chats', {\n indexes: ['chat'],\n });\n return chats;\n };\n // Escritas em fila: duas trocas seguidas no mesmo chat terminam na ordem em que foram pedidas,\n // no storage e no Map.\n let queue: Promise<unknown> = Promise.resolve();\n const enqueue = <T>(task: () => Promise<T>): Promise<T> => {\n const run = queue.then(task);\n queue = run.catch(() => undefined);\n return run;\n };\n\n return {\n async load() {\n for (const { chat, prefix } of await collection().find()) overrides.set(chat, prefix);\n },\n\n get(chat) {\n return overrides.get(chat.id) ?? (chat.isGroup ? group : dm);\n },\n\n set(chatId, prefix) {\n const value = validatePrefix(prefix, 'prefixes.set').toLowerCase();\n return enqueue(async () => {\n // Storage primeiro: se a escrita falha, o Map continua igual ao que está gravado.\n const updated = await collection().update({ chat: chatId }, { prefix: value });\n if (updated === 0) await collection().insert({ chat: chatId, prefix: value });\n overrides.set(chatId, value);\n });\n },\n\n reset(chatId) {\n return enqueue(async () => {\n const removed = await collection().delete({ chat: chatId });\n overrides.delete(chatId);\n return removed > 0;\n });\n },\n };\n}\n","import type { BotMessageContext } from '#context.ts';\nimport type { ExpectReply } from '#conversations/conversations.ts';\nimport type { Media, Message, MessageType } from '#message/types.ts';\nimport type { RoleName } from './roles.ts';\n\n/**\n * Quem pode rodar o comando: os embutidos (ADR 0024) ou um papel custom que um plugin define com\n * `ctx.roles.define` e declara em `Roles` (ADR 0035).\n */\nexport type CommandRole = 'owner' | 'group-admin' | 'everyone' | RoleName;\n\n/**\n * O que o comando aceita: o tipo da própria mensagem (`'image'`) ou da mensagem citada\n * (`'quoted:image'`).\n */\nexport type AcceptSpec = MessageType | `quoted:${MessageType}`;\n\n/** Entrada de `accepts` que casou e a mensagem (própria ou citada) a que ela se refere. */\nexport interface AcceptedMessage {\n readonly spec: AcceptSpec;\n readonly message: Message;\n}\n\n/**\n * Contexto que o `run` recebe: o da mensagem (`text`, `reply`, `log`, montados pelo `Bot`) mais\n * o que o roteador resolveu. Quem usa o roteador fora do `Bot` fornece `reply`/`log` no\n * contexto passado a `dispatch`; o roteador só herda o que recebeu.\n */\nexport interface CommandContext extends BotMessageContext {\n /** Nome canônico do comando casado (não o alias digitado). */\n readonly command: string;\n /** Token digitado, já em minúsculas: o nome ou um dos aliases. */\n readonly invokedAs: string;\n /** Argumentos após o comando, com aspas resolvidas (ver `parseArgs`). */\n readonly args: readonly string[];\n /** Texto após o comando, sem o espaço inicial e com quebras de linha preservadas. */\n readonly rawArgs: string;\n /**\n * Aborta quando o `run` (ou o `onReject`) estoura o prazo (`timeoutMs` do comando ou\n * `timeouts.commandMs`), com\n * `reason` = `CommandTimeoutError`. Repasse a `fetch`/SDKs para parar o trabalho a tempo (ADR 0033);\n * depois do prazo, o `reply` deste contexto rejeita com `ContextExpiredError`. Montado pelo\n * `Bot`: quem usa o roteador solto o fornece no contexto passado a `dispatch`.\n */\n readonly signal: AbortSignal;\n /**\n * Faz a próxima mensagem do remetente, neste chat, ir para um passo de conversa do plugin\n * (ADR 0060). O `run` pergunta, registra a espera e termina, sem segurar o chat. Montado pelo\n * `Bot`, como o `signal`.\n */\n readonly expectReply: ExpectReply;\n /** Entrada de `accepts` que casou; `null` se o comando não declara `accepts`. */\n readonly accepted: AcceptedMessage | null;\n /**\n * Mídia da mensagem que casou com `accepts` (própria ou citada). Sem `accepts`, a da\n * própria mensagem ou, na falta dela, a da citada. `null` se nenhuma tiver mídia.\n */\n readonly media: Media | null;\n}\n\n/** Por que o roteador recusou rodar o comando. */\nexport type CommandRejection =\n | { readonly reason: 'role'; readonly required: CommandRole }\n | { readonly reason: 'accepts'; readonly accepts: readonly AcceptSpec[] };\n\n/**\n * Contexto de `onReject`: ainda não há mídia resolvida nem `accepted`. No bot, o `onReject` tem\n * o mesmo prazo do `run`, e o `signal` aborta quando ele estoura.\n */\nexport type RejectContext = Omit<CommandContext, 'accepted' | 'media'>;\n\nexport interface CommandDefinition {\n /** Nome sem o prefixo (`'sticker'`, não `'!sticker'`). Casado sem diferenciar caixa. */\n readonly name: string;\n readonly aliases?: readonly string[];\n readonly description?: string;\n /** Padrão: `'everyone'`. */\n readonly role?: CommandRole;\n /** A primeira entrada que casar, na ordem declarada, define `ctx.media`. */\n readonly accepts?: readonly AcceptSpec[];\n /**\n * Texto de resposta quando o comando é recusado (papel ou `accepts`). Sem `onReject`, ou\n * retornando `null`/`undefined`, a recusa é silenciosa.\n */\n readonly onReject?: (\n ctx: RejectContext,\n rejection: CommandRejection,\n ) => string | null | undefined | Promise<string | null | undefined>;\n /**\n * No bot, devolver texto (string ou `fmt`) responde citando a mensagem, como terminar com\n * `await ctx.reply(texto)` (ADR 0079). Outro valor é ignorado. O tipo segue `unknown` para\n * `run: (c) => c.reply('x')` continuar valendo.\n */\n readonly run: (ctx: CommandContext) => unknown;\n /**\n * Prazo do `run` e do `onReject` no bot, em ms. Padrão: `timeouts.commandMs` do bot. Para o\n * comando que legitimamente demora (download, conversão): enquanto roda, ele segura o chat\n * (ADR 0042), então o prazo maior vale só para ele.\n */\n readonly timeoutMs?: number;\n}\n\n/** Comando como os plugins o veem em `ctx.commands.list()` (ADR 0040): sem `run` nem `onReject`. */\nexport interface CommandInfo {\n /** Plugin que registrou o comando. */\n readonly plugin: string;\n readonly name: string;\n readonly aliases: readonly string[];\n readonly description: string | null;\n readonly role: CommandRole;\n}\n\nconst TOKEN = /^\\S+$/;\n\nfunction assertToken(token: string, what: string): void {\n if (!TOKEN.test(token)) {\n throw new TypeError(\n `${what} de comando inválido: ${JSON.stringify(token)} (vazio ou com espaço)`,\n );\n }\n}\n\n/**\n * Lança `TypeError` se o nome ou algum alias for vazio ou tiver espaço (nunca casaria) e\n * `RangeError` se `timeoutMs` não for finito e > 0 (o `setTimeout` trataria `Infinity`/`NaN`\n * como 1 ms e o comando estouraria na hora).\n */\nexport function assertCommandDefinition(definition: CommandDefinition): void {\n assertToken(definition.name, 'Nome');\n for (const alias of definition.aliases ?? []) assertToken(alias, 'Alias');\n const { timeoutMs } = definition;\n if (timeoutMs !== undefined && !(Number.isFinite(timeoutMs) && timeoutMs > 0)) {\n throw new RangeError(`Prazo do comando \"${definition.name}\" inválido: ${timeoutMs}`);\n }\n}\n\n/**\n * Define um comando. Valida nome, aliases e prazo na definição, para o erro apontar o plugin que\n * declarou e não aparecer só quando alguém digitar o comando.\n */\nexport function command(definition: CommandDefinition): CommandDefinition {\n assertCommandDefinition(definition);\n return definition;\n}\n","import { assertCommandDefinition, type CommandDefinition } from './command.ts';\n\n/** Comando registrado com o plugin que o declarou. */\nexport interface RegisteredCommand {\n readonly plugin: string;\n readonly definition: CommandDefinition;\n}\n\n/** Dois comandos disputam o mesmo token (nome ou alias). Lançado no registro, isto é, no boot. */\nexport class CommandConflictError extends Error {\n override readonly name = 'CommandConflictError';\n /** Token disputado, em minúsculas. */\n readonly token: string;\n readonly existing: RegisteredCommand;\n readonly incoming: RegisteredCommand;\n\n constructor(token: string, existing: RegisteredCommand, incoming: RegisteredCommand) {\n super(\n `Conflito de comando \"${token}\": \"${incoming.definition.name}\" do plugin ` +\n `\"${incoming.plugin}\" colide com \"${existing.definition.name}\" do plugin ` +\n `\"${existing.plugin}\". Renomeie o comando ou o alias em um dos dois.`,\n );\n this.token = token;\n this.existing = existing;\n this.incoming = incoming;\n }\n}\n\nexport interface CommandRegistry {\n /**\n * Registra o comando em nome do plugin. Lança `TypeError` se o nome ou algum alias for\n * inválido (como `command()`) e `CommandConflictError` se algum já pertencer a outro comando\n * (de qualquer plugin, inclusive o mesmo); nos dois casos nada do comando é registrado.\n */\n add(plugin: string, definition: CommandDefinition): void;\n /** Remove todos os comandos do plugin (teardown e reload). */\n removePlugin(plugin: string): void;\n /** Busca pelo token já sem prefixo; não diferencia caixa. */\n find(token: string): RegisteredCommand | undefined;\n list(): RegisteredCommand[];\n}\n\n/** Tokens de um comando em minúsculas e sem repetição (alias igual ao nome é inofensivo). */\nfunction tokensOf(definition: CommandDefinition): Set<string> {\n const tokens = new Set([definition.name.toLowerCase()]);\n for (const alias of definition.aliases ?? []) tokens.add(alias.toLowerCase());\n return tokens;\n}\n\nexport interface CommandRegistryOptions {\n /** Chamado a cada comando que entra ou sai (o aviso do `TransportDeps.commands`, ADR 0064). */\n readonly onChange?: () => void;\n}\n\nexport function createCommandRegistry(options: CommandRegistryOptions = {}): CommandRegistry {\n // Um Map por token deixa o match O(1), independente de quantos comandos existem.\n const byToken = new Map<string, RegisteredCommand>();\n const commands = new Set<RegisteredCommand>();\n\n return {\n add(plugin, definition) {\n // Quem registra sem passar por `command()` (o `ctx.commands.add` aceita a definição\n // literal) também falha no boot, e não com um comando que nunca casa.\n assertCommandDefinition(definition);\n const entry: RegisteredCommand = { plugin, definition };\n const tokens = tokensOf(definition);\n // Valida tudo antes de gravar: um conflito no 2º alias não pode deixar o 1º registrado.\n for (const token of tokens) {\n const existing = byToken.get(token);\n if (existing) throw new CommandConflictError(token, existing, entry);\n }\n for (const token of tokens) byToken.set(token, entry);\n commands.add(entry);\n options.onChange?.();\n },\n\n removePlugin(plugin) {\n let removed = false;\n for (const entry of commands) {\n if (entry.plugin !== plugin) continue;\n commands.delete(entry);\n for (const token of tokensOf(entry.definition)) byToken.delete(token);\n removed = true;\n }\n // Plugin sem comandos não muda a lista: o transport não precisa conferir nada.\n if (removed) options.onChange?.();\n },\n\n find(token) {\n return byToken.get(token.toLowerCase());\n },\n\n list() {\n return [...commands];\n },\n };\n}\n","// Cancelamento cooperativo (ADR 0033). O JS não mata uma promise: quando o código de um plugin\n// estoura o prazo, o kernel só consegue avisá-lo (`signal`) e recusar o que ele tentar fazer\n// pelo contexto expirado. `Deadline` guarda esse estado para uma execução — um comando, um\n// listener, um job ou o contexto inteiro do plugin.\n\n/**\n * Prazo de uma execução de código de plugin. Quem expira é o dono do timer (o barramento, o\n * roteador, o scheduler, o host); o timer de `armTimer` só conta o tempo, sem expirar sozinho.\n *\n * Com `parent` (o `Deadline` de vida do plugin), a execução expira também quando o pai expira:\n * o descarte do plugin alcança os comandos, listeners e jobs dele ainda em andamento (ADR 0033).\n * O pai não guarda os filhos: `expired` e `reason` consultam o pai na leitura, e o `signal` só o\n * escuta quando alguém o lê — o caminho quente não paga nada a mais.\n */\nexport class Deadline {\n readonly #parent: Deadline | undefined;\n #expired = false;\n #reason: unknown;\n // Criado só quando alguém lê `signal`: a maioria das execuções nem olha para ele, e o\n // `AbortController` é a parte cara (EventTarget) no caminho quente de cada mensagem.\n #controller: AbortController | undefined;\n #signal: AbortSignal | undefined;\n // Envios da execução aguardando a fila de saída: enquanto houver um, o prazo não corre (ADR 0047).\n #holds = 0;\n #onHold: ((held: boolean) => void) | undefined;\n\n constructor(parent?: Deadline) {\n this.#parent = parent;\n }\n\n /** O prazo estourou (ou o contexto foi descartado). */\n get expired(): boolean {\n return this.#expired || this.#parent?.expired === true;\n }\n\n /** Motivo da expiração (o erro de timeout ou do descarte); `undefined` enquanto no prazo. */\n get reason(): unknown {\n return this.#expired ? this.#reason : this.#parent?.reason;\n }\n\n /** Aborta quando o prazo estoura (ou o pai expira), com `reason` = o motivo. */\n get signal(): AbortSignal {\n if (this.#signal === undefined) {\n this.#controller = new AbortController();\n if (this.#expired) this.#controller.abort(this.#reason);\n const own = this.#controller.signal;\n // `any` guarda o filho por referência fraca no pai: execuções que terminam não se\n // acumulam no `signal` do plugin.\n this.#signal = this.#parent === undefined ? own : AbortSignal.any([own, this.#parent.signal]);\n }\n return this.#signal;\n }\n\n /**\n * Pausa o prazo enquanto `operation` (um envio pela fila de saída) não assenta: a espera pela\n * taxa anti-ban, o \"digitando\" e as re-tentativas são do kernel, não do plugin, e a fila tem\n * tetos próprios (ADR 0047). Devolve uma promise nova, que assenta como `operation`: uma\n * rejeição que o plugin ignore continua não tratada, como sem a pausa.\n */\n hold<T>(operation: Promise<T>): Promise<T> {\n if (this.#holds++ === 0) this.#onHold?.(true);\n const release = (): void => {\n if (--this.#holds === 0) this.#onHold?.(false);\n };\n return operation.then(\n (value) => {\n release();\n return value;\n },\n (error: unknown) => {\n release();\n throw error;\n },\n );\n }\n\n /**\n * Arma o timer do prazo: `fire` corre depois de `timeoutMs` contados só fora das pausas de\n * `hold`. Um timer por execução. Devolve o desarme.\n */\n armTimer(timeoutMs: number, fire: () => void): () => void {\n let remaining = timeoutMs;\n let startedAt = 0;\n let timer: NodeJS.Timeout | undefined;\n const start = (): void => {\n startedAt = performance.now();\n timer = setTimeout(\n () => {\n this.#onHold = undefined;\n fire();\n },\n Math.max(0, remaining),\n );\n };\n this.#onHold = (held) => {\n if (held) {\n clearTimeout(timer);\n timer = undefined;\n remaining -= performance.now() - startedAt;\n } else {\n start();\n }\n };\n // O handler pode ter enviado antes de o timer armar (envio síncrono no início do `run`).\n if (this.#holds === 0) start();\n return () => {\n clearTimeout(timer);\n this.#onHold = undefined;\n };\n }\n\n /** Marca como expirado e aborta o `signal`. Só a primeira expiração vale, a do pai inclusive. */\n expire(reason: unknown): void {\n if (this.expired) return;\n this.#expired = true;\n this.#reason = reason;\n this.#controller?.abort(reason);\n }\n}\n\n/**\n * Uma execução com prazo (comando, listener ou job) estourou o tempo. É o `reason` do `signal`\n * abortado: o plugin distingue timeout de outro motivo com `instanceof` (ADR 0033).\n */\nexport class ExecutionTimeoutError extends Error {\n override readonly name: string = 'ExecutionTimeoutError';\n readonly plugin: string;\n readonly timeoutMs: number;\n\n constructor(plugin: string, what: string, timeoutMs: number) {\n super(`${what} do plugin \"${plugin}\" excedeu ${timeoutMs} ms`);\n this.plugin = plugin;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/** Um listener estourou o prazo. Vai em `plugin.error` com `timedOut: true`. */\nexport class ListenerTimeoutError extends ExecutionTimeoutError {\n override readonly name: string = 'ListenerTimeoutError';\n readonly event: string;\n\n constructor(plugin: string, event: string, timeoutMs: number) {\n super(plugin, `listener em \"${event}\"`, timeoutMs);\n this.event = event;\n }\n}\n\n/** O handler de um job estourou o prazo. Vai em `plugin.error` com `timedOut: true`. */\nexport class JobTimeoutError extends ExecutionTimeoutError {\n override readonly name: string = 'JobTimeoutError';\n readonly job: string;\n\n constructor(plugin: string, job: string, timeoutMs: number) {\n super(plugin, `job \"${job}\"`, timeoutMs);\n this.job = job;\n }\n}\n\n/**\n * Operação de um contexto expirado: `reply` de um comando ou listener que estourou o prazo, ou\n * `send`/`storage`/`scheduler` de um contexto de plugin descartado. A operação não executa;\n * `cause` é o motivo da expiração (o erro de timeout ou do descarte).\n */\nexport class ContextExpiredError extends Error {\n override readonly name = 'ContextExpiredError';\n readonly plugin: string;\n /** O que foi recusado: `'reply'`, `'reply.image'`, `'send'`, `'storage.kv.set'`… */\n readonly operation: string;\n /** Dono do contexto: `'comando \"ping\"'`, `'listener de \"message\"'`, `'contexto do plugin'`. */\n readonly scope: string;\n\n constructor(plugin: string, operation: string, scope: string, cause: unknown) {\n super(\n `plugin \"${plugin}\": ${operation} recusado — ${scope} já expirou (prazo estourado ou ` +\n 'contexto descartado). Repasse ctx.signal ao trabalho assíncrono para pará-lo a tempo.',\n { cause },\n );\n this.plugin = plugin;\n this.operation = operation;\n this.scope = scope;\n }\n}\n\n/**\n * Chave do `Deadline` de uma execução no objeto de contexto. Simbólica, não `#privada`: as\n * visões por plugin derivam o contexto por `Object.create`, e a chave precisa ser alcançável\n * pela cadeia de protótipos.\n */\nexport const DEADLINE: unique symbol = Symbol('bridger.deadline');\n\nexport interface WithDeadline {\n readonly [DEADLINE]?: Deadline;\n}\n\n/** `Deadline` da execução dona do contexto, se houver. */\nexport function deadlineOf(ctx: object): Deadline | undefined {\n return (ctx as WithDeadline)[DEADLINE];\n}\n\nexport function isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n value !== null &&\n (typeof value === 'object' || typeof value === 'function') &&\n typeof (value as PromiseLike<unknown>).then === 'function'\n );\n}\n\n/**\n * Prazos armados de um bot, cada um pela função que o desarma. O JS não mata o handler preso,\n * mas o timer do prazo dele não pode sobreviver ao `stop()`: o shutdown chama `disarmAll`.\n */\nexport class ArmedTimers {\n readonly #disarms = new Set<() => void>();\n\n add(disarm: () => void): void {\n this.#disarms.add(disarm);\n }\n\n delete(disarm: () => void): void {\n this.#disarms.delete(disarm);\n }\n\n /**\n * Desarma todos. A execução abandonada não assenta: rejeitar viraria `plugin.error` e novos\n * listeners com prazo no meio do shutdown, e ninguém mais espera por ela (a fila de entrada já\n * foi abandonada). O `Deadline` dela já expirou com o descarte do plugin.\n */\n disarmAll(): void {\n for (const disarm of this.#disarms) disarm();\n this.#disarms.clear();\n }\n}\n\n/**\n * Corre `result` contra um prazo de `timeoutMs`. Estourado, rejeita com o erro de `onTimeout`\n * (que também é a hora de expirar o `Deadline` da execução); o trabalho não tem como ser\n * cancelado e segue em segundo plano, e uma rejeição dele depois do prazo vai para `onLate`,\n * nunca vira rejeição não tratada. Resultado síncrono passa direto, sem timer: o caminho quente\n * não paga nada (plano §7). O timer fica em `armed` enquanto corre, para o shutdown desarmá-lo.\n * Com `deadline`, o prazo pausa enquanto a execução aguarda a fila de saída (`Deadline.hold`).\n */\nexport function settleWithin(\n result: unknown,\n timeoutMs: number,\n onTimeout: () => Error,\n onLate: (error: unknown) => void,\n armed: ArmedTimers,\n deadline?: Deadline,\n): unknown {\n if (!isThenable(result)) return result;\n return new Promise((resolve, reject) => {\n let settled = false;\n const disarm = (): void => {\n settled = true;\n cancel();\n armed.delete(disarm);\n };\n const fire = (): void => {\n disarm();\n reject(onTimeout());\n };\n let cancel: () => void;\n if (deadline === undefined) {\n const timer = setTimeout(fire, timeoutMs);\n cancel = () => clearTimeout(timer);\n } else {\n cancel = deadline.armTimer(timeoutMs, fire);\n }\n armed.add(disarm);\n result.then(\n (value) => {\n if (settled) return;\n disarm();\n resolve(value);\n },\n (error: unknown) => {\n if (settled) {\n onLate(error);\n return;\n }\n disarm();\n reject(error);\n },\n );\n });\n}\n","// Papéis custom nomeados (ADR 0035): um plugin define o papel, qualquer plugin o exige no comando\n// e o roteador o avalia, como faz com os embutidos.\n\nimport { ExecutionTimeoutError } from '#deadline.ts';\nimport type { Logger } from '#logger/types.ts';\nimport type { Message } from '#message/types.ts';\n\n/**\n * Papéis custom, preenchidos por declaration merging no plugin que os define:\n *\n * ```ts\n * declare module '@usebridger/core' {\n * interface Roles { moderador: true }\n * }\n * ```\n */\n// biome-ignore lint/suspicious/noEmptyInterface: vazio de propósito; plugins estendem por declaration merging.\nexport interface Roles {}\n\n/** Nomes declarados em `Roles`; só strings, porque viram chave de mapa e texto de erro. */\nexport type RoleName = Extract<keyof Roles, string>;\n\n/** Papéis que o roteador resolve sozinho; nenhum plugin pode redefini-los. */\nexport const RESERVED_ROLES: ReadonlySet<string> = new Set(['owner', 'group-admin', 'everyone']);\n\n/** O que a checagem de um papel recebe: a mensagem e o comando que exige o papel. */\nexport interface RoleContext {\n readonly message: Message;\n /** Texto de trabalho (`ctx.text`). */\n readonly text: string | null;\n /** Nome canônico do comando que exige o papel. */\n readonly command: string;\n /** Logger do plugin dono do papel, com `chatId`. */\n readonly log: Logger;\n /**\n * Aborta quando a checagem estoura o prazo (`timeouts.commandMs`), com `reason` =\n * `RoleTimeoutError`. Repasse a consultas externas (ADR 0033).\n */\n readonly signal: AbortSignal;\n}\n\n/**\n * Concede o papel só com `true`. Lançar, rejeitar, estourar o prazo ou devolver qualquer outra\n * coisa recusa o comando (fail-closed).\n */\nexport type RoleCheck = (ctx: RoleContext) => boolean | Promise<boolean>;\n\n/** Papel registrado com o plugin que o definiu. */\nexport interface RegisteredRole {\n readonly plugin: string;\n readonly name: string;\n readonly check: RoleCheck;\n}\n\n/** Dois plugins (ou o mesmo, duas vezes) definem o mesmo papel. Lançado no `setup`. */\nexport class RoleConflictError extends Error {\n override readonly name = 'RoleConflictError';\n readonly role: string;\n readonly existing: string;\n readonly incoming: string;\n\n constructor(role: string, existing: string, incoming: string) {\n super(\n existing === incoming\n ? `Papel \"${role}\" definido duas vezes pelo plugin \"${incoming}\". Cada papel é definido ` +\n 'uma vez por setup; para trocar a checagem, recarregue o plugin.'\n : `Conflito de papel \"${role}\": o plugin \"${incoming}\" tenta definir um papel que o ` +\n `plugin \"${existing}\" já define. Use o papel do plugin \"${existing}\" (declarando ` +\n 'dependsOn nele) ou renomeie o seu.',\n );\n this.role = role;\n this.existing = existing;\n this.incoming = incoming;\n }\n}\n\nexport interface RoleRegistry {\n /**\n * Registra o papel em nome do plugin. Lança `TypeError` para nome vazio, com espaço ou\n * reservado (`owner`, `group-admin`, `everyone`) e `RoleConflictError` se o nome já tem dono.\n */\n define(plugin: string, name: string, check: RoleCheck): void;\n /** Remove os papéis do plugin (teardown e reload). */\n removePlugin(plugin: string): void;\n find(name: string): RegisteredRole | undefined;\n}\n\nconst ROLE_NAME = /^\\S+$/;\n\nexport function createRoleRegistry(): RoleRegistry {\n const byName = new Map<string, RegisteredRole>();\n return {\n define(plugin, name, check) {\n if (!ROLE_NAME.test(name)) {\n throw new TypeError(\n `Nome de papel inválido: ${JSON.stringify(name)} (vazio ou com espaço)`,\n );\n }\n if (RESERVED_ROLES.has(name)) {\n throw new TypeError(\n `Papel \"${name}\" é reservado (owner, group-admin, everyone): o plugin \"${plugin}\" ` +\n 'precisa de outro nome.',\n );\n }\n const existing = byName.get(name);\n if (existing) throw new RoleConflictError(name, existing.plugin, plugin);\n byName.set(name, { plugin, name, check });\n },\n\n removePlugin(plugin) {\n for (const [name, role] of byName) {\n if (role.plugin === plugin) byName.delete(name);\n }\n },\n\n find: (name) => byName.get(name),\n };\n}\n\n/** A checagem de um papel custom estourou o prazo: o comando é recusado e sai `plugin.error`. */\nexport class RoleTimeoutError extends ExecutionTimeoutError {\n override readonly name: string = 'RoleTimeoutError';\n readonly role: string;\n\n constructor(plugin: string, role: string, timeoutMs: number) {\n super(plugin, `checagem do papel \"${role}\"`, timeoutMs);\n this.role = role;\n }\n}\n","// Aspas de abertura → fechamento aceitas. As tipográficas entram porque o teclado do celular\n// (iOS principalmente) troca `\"` por `“ ”` sozinho. Aspas simples ficam de fora: o apóstrofo\n// aparece em texto comum (\"d'água\") e quebraria o argumento.\nconst QUOTES: ReadonlyMap<string, string> = new Map([\n ['\"', '\"'],\n ['“', '”'],\n]);\n\nconst WHITESPACE = /\\s/;\n\n/**\n * Quebra o texto em argumentos por espaço em branco, respeitando trechos entre aspas\n * (`\"a b\"` vira um argumento só, sem as aspas). Aspa sem fechamento estende o argumento até o\n * fim do texto: é o que o usuário quis dizer na maioria das vezes, e não há como responder\n * \"erro de sintaxe\" de forma útil num chat.\n */\nexport function parseArgs(input: string): string[] {\n const args: string[] = [];\n let current = '';\n // Distingue \"nenhum argumento em curso\" de argumento vazio vindo de `\"\"`.\n let inArg = false;\n let closing: string | null = null;\n\n for (const char of input) {\n if (closing !== null) {\n if (char === closing) closing = null;\n else current += char;\n continue;\n }\n const close = QUOTES.get(char);\n if (close !== undefined) {\n closing = close;\n inArg = true;\n continue;\n }\n if (WHITESPACE.test(char)) {\n if (inArg) {\n args.push(current);\n current = '';\n inArg = false;\n }\n continue;\n }\n current += char;\n inArg = true;\n }\n if (inArg) args.push(current);\n return args;\n}\n","import type { BotOwner } from '#config/owners.ts';\nimport type { BotMessageContext, MessageContext } from '#context.ts';\nimport type { Chat, Contact, Media, Message } from '#message/types.ts';\nimport { parseArgs } from './args.ts';\nimport type {\n AcceptedMessage,\n AcceptSpec,\n CommandContext,\n CommandDefinition,\n CommandRejection,\n CommandRole,\n RejectContext,\n} from './command.ts';\nimport { DEFAULT_PREFIX, validatePrefix } from './prefixes.ts';\nimport { type CommandRegistry, createCommandRegistry, type RegisteredCommand } from './registry.ts';\nimport { createRoleRegistry, type RoleContext, type RoleRegistry } from './roles.ts';\n\n/**\n * Porta para consultar admins de grupo. Vem do transport (`isChatAdmin` ou capability `groups`,\n * ADR 0059); o core não importa transport, então quem compõe o bot injeta. Recebe o chat\n * inteiro, porque no Discord o admin é do servidor (`parentId`), e o contato inteiro, porque o id\n * do remetente e o do participante podem vir em espaços diferentes (no WhatsApp, LID e JID de\n * telefone), e o telefone é o que os liga (ADR 0046).\n */\nexport type IsGroupAdmin = (chat: Chat, sender: Contact) => boolean | Promise<boolean>;\n\nexport interface CommandRouterOptions {\n /**\n * Padrão: `'!'`. Comparado sem diferenciar caixa; vazio faz a primeira palavra ser o token. Uma\n * função resolve o prefixo pelo chat da mensagem (no bot, o override do chat ou o padrão do\n * tipo, ADR 0063) e deve devolver o texto já validado e em minúsculas.\n */\n readonly prefix?: string | ((chat: Chat) => string);\n /**\n * `@usuario` da própria sessão, sem o `@`. Com ele, `cmd@usuario` vira o token `cmd`: é como o\n * Telegram endereça um comando ao bot num grupo. Lido a cada mensagem, porque só existe depois\n * da conexão.\n */\n readonly selfUsername?: () => string | undefined;\n /**\n * Donos do bot, já normalizados (`normalizeOwners`): telefone só com dígitos e DDI, comparado\n * com `message.sender.phone`, ou `{ id }`, comparado com `message.sender.id`.\n */\n readonly owners?: readonly BotOwner[];\n /** Sem a porta, `role: 'group-admin'` recusa todo mundo exceto owners (fail-closed). */\n readonly isGroupAdmin?: IsGroupAdmin;\n /** Registro a usar; padrão: um novo. */\n readonly registry?: CommandRegistry;\n /** Papéis custom (ADR 0035); padrão: um registro novo, vazio. */\n readonly roles?: RoleRegistry;\n /**\n * Comando exige um papel custom que nenhum plugin carregado define. O comando é recusado\n * (fail-closed) de todo jeito; aqui quem compõe o roteador registra o erro de configuração.\n */\n readonly onUnknownRole?: (role: string, command: MatchedCommand) => void;\n}\n\n/** Comando casado, para quem chamou o roteador saber o que rodou. */\nexport interface MatchedCommand {\n readonly plugin: string;\n readonly name: string;\n readonly invokedAs: string;\n}\n\n/**\n * Resultado de `dispatch`. `consumed` diz se a mensagem para aqui (não vai aos listeners):\n * basta o token casar, mesmo que o comando seja recusado ou falhe.\n */\nexport type DispatchResult =\n | { readonly consumed: false; readonly status: 'no-match' }\n | { readonly consumed: true; readonly status: 'ran'; readonly command: MatchedCommand }\n | {\n readonly consumed: true;\n readonly status: 'rejected';\n readonly command: MatchedCommand;\n readonly rejection: CommandRejection;\n /** Texto de `onReject` a enviar ao chat; `null` = recusa silenciosa. */\n readonly reply: string | null;\n }\n | {\n readonly consumed: true;\n readonly status: 'failed';\n readonly command: MatchedCommand;\n /**\n * Erro de `run`, `onReject` ou `isGroupAdmin` (no bot, também o prazo estourado de cada\n * um); quem chamou registra/reporta.\n */\n readonly error: unknown;\n };\n\nexport interface CommandRouter {\n readonly registry: CommandRegistry;\n readonly roles: RoleRegistry;\n /**\n * Comando que a mensagem invoca, sem validar papel nem `accepts`. `text` é o texto de\n * trabalho (`ctx.text`); padrão: `message.text`.\n */\n match(message: Message, text?: string | null): CommandMatch | null;\n /**\n * Casa, valida papel e `accepts` e roda. Nunca rejeita: erros vêm em `status: 'failed'`. Com\n * `invocation`, roda o comando dado sem casar o texto (o clique num botão, ADR 0062, ou o\n * comando nativo da plataforma, ADR 0064).\n */\n dispatch(ctx: MessageContext, invocation?: CommandInvocation): Promise<DispatchResult>;\n}\n\n/**\n * Comando a rodar sem casar o texto: com `args` já separados (botão) ou com o texto livre em\n * `rawArgs` (comando nativo), interpretado como o texto depois do comando digitado.\n */\nexport type CommandInvocation =\n | {\n /** Nome ou alias, sem o prefixo. */\n readonly command: string;\n /** Vão como vieram em `ctx.args`; o `rawArgs` é a junção por espaços. */\n readonly args: readonly string[];\n readonly rawArgs?: never;\n }\n | {\n /** Nome ou alias, sem o prefixo. */\n readonly command: string;\n readonly rawArgs: string;\n readonly args?: never;\n };\n\nexport interface CommandMatch {\n readonly entry: RegisteredCommand;\n readonly invokedAs: string;\n readonly rawArgs: string;\n}\n\nconst FIRST_WHITESPACE = /\\s/;\n\n/**\n * O contexto recebido, com o `signal` e o `expectReply` que o Bot (ou quem chama `dispatch`)\n * fornece.\n */\ntype SignalContext = BotMessageContext & Pick<RejectContext, 'signal' | 'expectReply'>;\n\nfunction mediaOf(message: Message | null): Media | null {\n return message !== null && 'media' in message ? message.media : null;\n}\n\n/** Primeira entrada de `accepts` que casa, na ordem declarada. */\nfunction resolveAccepts(message: Message, accepts: readonly AcceptSpec[]): AcceptedMessage | null {\n for (const spec of accepts) {\n const quoted = spec.startsWith('quoted:');\n const target = quoted ? message.quoted : message;\n const type = quoted ? spec.slice('quoted:'.length) : spec;\n if (target !== null && target.type === type) return { spec, message: target };\n }\n return null;\n}\n\nexport function createCommandRouter(options: CommandRouterOptions = {}): CommandRouter {\n const option = options.prefix ?? DEFAULT_PREFIX;\n let prefixOf: (chat: Chat) => string;\n if (typeof option === 'function') {\n prefixOf = option;\n } else {\n const fixed = validatePrefix(option, 'prefix').toLowerCase();\n prefixOf = () => fixed;\n }\n // Dois conjuntos, um por espaço: um ID com texto de telefone não casa com o telefone de\n // ninguém, e vice-versa (ADR 0056).\n const ownerPhones = new Set<string>();\n const ownerIds = new Set<string>();\n for (const owner of options.owners ?? []) {\n if (typeof owner === 'string') ownerPhones.add(owner);\n else ownerIds.add(owner.id);\n }\n const isGroupAdmin = options.isGroupAdmin;\n const registry = options.registry ?? createCommandRegistry();\n const roles = options.roles ?? createRoleRegistry();\n\n function match(message: Message, workingText = message.text): CommandMatch | null {\n const text = workingText?.trimStart();\n if (!text) return null;\n const prefix = prefixOf(message.chat);\n if (text.slice(0, prefix.length).toLowerCase() !== prefix) return null;\n\n // Token = do fim do prefixo até o primeiro espaço em branco. Match exato no Map: o\n // `includes()` do legacy fazia \"!s\" casar dentro de \"vou mandar !sticker depois\".\n const rest = text.slice(prefix.length);\n const end = rest.search(FIRST_WHITESPACE);\n let token = (end === -1 ? rest : rest.slice(0, end)).toLowerCase();\n // Só o @ da própria sessão sai: `cmd@OutroBot` é de outro bot e não casa.\n const self = options.selfUsername?.();\n if (self !== undefined && token.endsWith(`@${self.toLowerCase()}`)) {\n token = token.slice(0, -(self.length + 1));\n }\n if (token.length === 0) return null;\n\n const entry = registry.find(token);\n if (!entry) return null;\n const rawArgs = end === -1 ? '' : rest.slice(end).trimStart();\n return { entry, invokedAs: token, rawArgs };\n }\n\n function invoke(invocation: CommandInvocation): CommandMatch | null {\n const token = invocation.command.toLowerCase();\n const entry = registry.find(token);\n if (!entry) return null;\n const rawArgs =\n invocation.args === undefined ? invocation.rawArgs.trimStart() : invocation.args.join(' ');\n return { entry, invokedAs: token, rawArgs };\n }\n\n async function hasRole(\n role: CommandRole,\n ctx: RoleContext,\n command: MatchedCommand,\n ): Promise<boolean> {\n if (role === 'everyone') return true;\n const { message } = ctx;\n // Dono é superusuário: passa também em `group-admin`. Owner por telefone compara com\n // `sender.phone`, não com o `sender.id`: o ID é opaco e nem sempre carrega o número (no\n // WhatsApp, um LID; M1-16.4). Owner `{ id }` compara com o `sender.id`, para quem não tem\n // telefone.\n const { id, phone } = message.sender;\n if (ownerIds.has(id) || (phone !== null && ownerPhones.has(phone))) return true;\n if (role === 'owner') return false;\n if (role !== 'group-admin') {\n // Papel custom: sem dono carregado (plugin desligado, ignorado ou recarregando), recusa.\n const custom = roles.find(role);\n if (!custom) {\n options.onUnknownRole?.(role, command);\n return false;\n }\n // Só `true` concede: o `check` embrulhado pelo bot já recusa em erro e no prazo.\n return (await custom.check(ctx)) === true;\n }\n // `group-admin` fora de grupo não tem a quem se referir: recusa.\n if (!message.chat.isGroup || !isGroupAdmin) return false;\n return isGroupAdmin(message.chat, message.sender);\n }\n\n async function reject(\n definition: CommandDefinition,\n ctx: RejectContext,\n rejection: CommandRejection,\n ): Promise<string | null> {\n return (await definition.onReject?.(ctx, rejection)) ?? null;\n }\n\n return {\n registry,\n roles,\n match,\n\n async dispatch(ctx, invocation) {\n // O texto de trabalho (M1-16.2) vem do contexto: um middleware pode tê-lo reescrito.\n const text = ctx.text === undefined ? ctx.message.text : ctx.text;\n const found = invocation === undefined ? match(ctx.message, text) : invoke(invocation);\n if (!found) return { consumed: false, status: 'no-match' };\n\n const { entry, invokedAs, rawArgs } = found;\n // Os argumentos do botão vão como o plugin os deu: reparseá-los partiria um com espaço.\n const args = invocation?.args === undefined ? parseArgs(rawArgs) : [...invocation.args];\n const { definition } = entry;\n const command: MatchedCommand = { plugin: entry.plugin, name: definition.name, invokedAs };\n const message = ctx.message;\n\n try {\n // Herda do contexto recebido em vez de copiar: preserva métodos e getters que os\n // estágios anteriores (ou o Bot) tenham colocado nele.\n // `reply`/`log` vêm do contexto do Bot pela cadeia de protótipos, e o `signal`, da visão\n // que o Bot monta para `run` e `onReject` (ver `CommandContext`).\n const base: RejectContext = Object.assign(Object.create(ctx) as SignalContext, {\n text,\n command: definition.name,\n invokedAs,\n args,\n rawArgs,\n });\n\n const role = definition.role ?? 'everyone';\n if (!(await hasRole(role, base, command))) {\n const rejection: CommandRejection = { reason: 'role', required: role };\n const reply = await reject(definition, base, rejection);\n return { consumed: true, status: 'rejected', command, rejection, reply };\n }\n\n let accepted: AcceptedMessage | null = null;\n let media: Media | null;\n if (definition.accepts) {\n accepted = resolveAccepts(message, definition.accepts);\n if (!accepted) {\n const rejection: CommandRejection = { reason: 'accepts', accepts: definition.accepts };\n const reply = await reject(definition, base, rejection);\n return { consumed: true, status: 'rejected', command, rejection, reply };\n }\n media = mediaOf(accepted.message);\n } else {\n media = mediaOf(message) ?? mediaOf(message.quoted);\n }\n\n // `signal` vem do Bot, na visão do comando (ADR 0033); solto, do contexto recebido.\n const commandCtx = Object.assign(base, { accepted, media }) as CommandContext;\n await definition.run(commandCtx);\n return { consumed: true, status: 'ran', command };\n } catch (error) {\n return { consumed: true, status: 'failed', command, error };\n }\n },\n };\n}\n","// `owners` da config do bot. Uma string é telefone, comparado com `Contact.phone`, que o transport\n// entrega só com dígitos (M1-16). Normalizar aqui deixa o operador escrever o número como está\n// acostumado (`+55 (11) 99999-9999`) sem que a comparação dependa da formatação. `{ id }` é o ID\n// nativo do contato (`Contact.id`), para plataformas sem telefone (ADR 0056).\n\n// Pontuação comum em telefone escrito à mão. Qualquer outra coisa (letra, `@` de JID) é erro:\n// melhor recusar no boot do que nunca reconhecer o dono.\nconst SEPARATORS = /[\\s+().-]/g;\n// E.164 tem no máximo 15 dígitos; menos de 8 não é número internacional completo.\nconst PHONE = /^\\d{8,15}$/;\n\n/** Dono reconhecido pelo ID nativo do contato (`Contact.id`), comparado sem normalizar. */\nexport interface OwnerId {\n readonly id: string;\n}\n\n/** Entrada de `owners`: telefone (com ou sem pontuação) ou `{ id }`. */\nexport type BotOwner = string | OwnerId;\n\n/** Config do bot inválida (ex.: `owners` com telefone malformado). */\nexport class BotConfigError extends Error {\n override readonly name = 'BotConfigError';\n}\n\n/**\n * Telefone só com dígitos, com DDI: `'+55 11 99999-9999'` → `'5511999999999'`. Lança\n * `BotConfigError` se sobrar algo além de dígitos ou se o tamanho não for de um telefone.\n */\nexport function normalizePhone(value: string, label = 'telefone'): string {\n const digits = value.replace(SEPARATORS, '');\n if (!PHONE.test(digits)) {\n throw new BotConfigError(\n `${label}: \"${value}\" não é um telefone válido. Use só o número com DDI e DDD ` +\n '(ex.: \"5511999999999\" ou \"+55 11 99999-9999\"); para um ID de contato (JID, ID do ' +\n 'Discord ou do Telegram), use { id: \"...\" }.',\n );\n }\n return digits;\n}\n\nfunction ownerId(owner: unknown, label: string): OwnerId {\n const id = typeof owner === 'object' && owner !== null ? (owner as { id?: unknown }).id : owner;\n // O ID é comparado por igualdade exata: espaço nas pontas é engano de config, e número perde\n // precisão (um snowflake do Discord passa de 2^53). Recusar no boot em vez de nunca casar.\n if (typeof id !== 'string' || id === '' || id.trim() !== id) {\n throw new BotConfigError(\n `${label}: esperava um telefone ou { id: \"...\" } com o ID em texto, não vazio e sem ` +\n `espaço nas pontas; recebido ${JSON.stringify(owner)}.`,\n );\n }\n return { id };\n}\n\n/**\n * Normaliza `owners`: telefones por `normalizePhone`, `{ id }` validado e mantido como está. Sem\n * repetidos, na ordem dada. Telefone e ID com o mesmo texto não se fundem: são espaços diferentes.\n */\nexport function normalizeOwners(owners: readonly BotOwner[]): BotOwner[] {\n const unique = new Map<string, BotOwner>();\n owners.forEach((owner, index) => {\n const label = `owners[${index}]`;\n if (typeof owner === 'string') {\n const phone = normalizePhone(owner, label);\n unique.set(`phone:${phone}`, phone);\n } else {\n const normalized = ownerId(owner, label);\n unique.set(`id:${normalized.id}`, normalized);\n }\n });\n return [...unique.values()];\n}\n","// Implementação do `Logger` sobre pino (M1-14). O pino fica só aqui dentro: a API pública fala\n// `Logger`/`LoggerOptions`, para trocar a implementação sem quebrar plugins.\n\nimport { type Logger as PinoLogger, pino, stdSerializers } from 'pino';\nimport type { SecretSource } from './secrets.ts';\nimport type { LogFields, Logger, LogLevel } from './types.ts';\n\n/** Para onde vão as linhas JSON (uma por chamada, terminada em `\\n`). */\nexport interface LogDestination {\n write(line: string): void;\n}\n\nexport interface LoggerOptions {\n /** Nível mínimo emitido. Padrão: `'info'`. */\n readonly level?: LogLevel;\n /** Destino das linhas. Padrão: stdout do processo. */\n readonly destination?: LogDestination;\n /** Campos presentes em toda linha deste logger e dos filhos (ex.: `{ app: 'meu-bot' }`). */\n readonly bindings?: LogFields;\n /**\n * Caminhos de campos trocados por `[REDACTED]`, na sintaxe de redação do pino\n * (`'password'`, `'config.apiKey'`, `'*.token'`). Pega o campo pelo nome, onde quer que o\n * valor esteja.\n */\n readonly redact?: readonly string[];\n /**\n * Valores secretos (ex.: campos `secret` da config) trocados por `[REDACTED]` em qualquer\n * lugar da linha: mensagem, campos, bindings, `err.message`/`err.stack`. Pega o valor, sob\n * qualquer nome de campo. Valores com menos de `MIN_SECRET_LENGTH` caracteres são ignorados.\n * Uma `SecretSource` (ex.: `createSecretSet()`) é consultada a cada linha: segredos descobertos\n * depois da criação do logger — como os da config de plugin, resolvida no setup e no reload —\n * também são censurados.\n */\n readonly secrets?: readonly string[] | SecretSource;\n}\n\nconst CENSOR = '[REDACTED]';\n\n/**\n * Tamanho mínimo de um segredo para ser censurado no log. A censura troca o valor onde ele\n * aparecer na linha: um segredo de 1 a 3 caracteres (`\"1\"`, `\"on\"`) apagaria pedaços de todo\n * log, e um valor tão curto não protege nada de qualquer forma.\n */\nexport const MIN_SECRET_LENGTH = 4;\n\n/**\n * Logger estruturado em JSON. `child({ plugin })` e `child({ chatId })` acumulam contexto; o\n * campo `err` é serializado com `message`, `stack` e `cause`.\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const destination = withSecretsCensored(options.destination, options.secrets);\n const root = pino(\n {\n level: options.level ?? 'info',\n // `errWithCause` mantém a `cause` como objeto estruturado (com stack própria), em vez de\n // concatená-la na mensagem como o serializer padrão.\n serializers: { err: stdSerializers.errWithCause },\n ...(options.redact && options.redact.length > 0\n ? { redact: { paths: [...options.redact], censor: CENSOR } }\n : {}),\n },\n destination,\n );\n return wrap(options.bindings ? root.child(options.bindings) : root);\n}\n\n// Censura por valor no texto já serializado: pega o segredo onde quer que ele apareça, o que a\n// redação por caminho não garante (ex.: token interpolado na mensagem ou no `err.message`).\n// Custo só em linha emitida, e só quando há segredo configurado.\nfunction withSecretsCensored(\n destination: LogDestination | undefined,\n secrets: readonly string[] | SecretSource | undefined,\n): LogDestination | undefined {\n if (secrets === undefined) return destination;\n let source: SecretSource | undefined;\n let needles: string[] = [];\n if ('version' in secrets) source = secrets;\n else needles = toNeedles(secrets);\n // Lista fixa e vazia: nada a censurar, nem precisa embrulhar o destino. Com fonte viva, sempre\n // embrulha, porque um segredo pode aparecer depois.\n if (!source && needles.length === 0) return destination;\n let seen = -1;\n // Sem destino explícito, o padrão é o mesmo do pino: stdout.\n const target = destination ?? pino.destination(1);\n return {\n write(line: string): void {\n if (source && source.version !== seen) {\n seen = source.version;\n needles = toNeedles(source.values());\n }\n let censored = line;\n for (const needle of needles) censored = censored.replaceAll(needle, CENSOR);\n target.write(censored);\n },\n };\n}\n\n// O segredo aparece na linha na forma escapada do JSON; o mais longo primeiro, para um segredo\n// que contém outro ser trocado inteiro.\nfunction toNeedles(secrets: readonly string[]): string[] {\n return secrets\n .filter((secret) => secret.length >= MIN_SECRET_LENGTH)\n .map((secret) => JSON.stringify(secret).slice(1, -1))\n .sort((a, b) => b.length - a.length);\n}\n\nfunction wrap(log: PinoLogger): Logger {\n // Sem campos, chama o pino só com a mensagem: evita alocar um objeto vazio por linha. Em nível\n // desabilitado o método do pino já é um no-op, então nada é serializado.\n return {\n get level(): LogLevel {\n return log.level as LogLevel;\n },\n trace: (message, fields) => (fields ? log.trace(fields, message) : log.trace(message)),\n debug: (message, fields) => (fields ? log.debug(fields, message) : log.debug(message)),\n info: (message, fields) => (fields ? log.info(fields, message) : log.info(message)),\n warn: (message, fields) => (fields ? log.warn(fields, message) : log.warn(message)),\n error: (message, fields) => (fields ? log.error(fields, message) : log.error(message)),\n fatal: (message, fields) => (fields ? log.fatal(fields, message) : log.fatal(message)),\n child: (bindings) => wrap(log.child(bindings)),\n };\n}\n\n// Descarta a linha: é o propósito do logger no-op.\nconst noop = (): void => {\n return;\n};\n\n// Objeto congelado e sem recurso: compartilhá-lo não cria estado global mutável.\nconst NOOP_LOGGER: Logger = Object.freeze({\n level: 'silent',\n trace: noop,\n debug: noop,\n info: noop,\n warn: noop,\n error: noop,\n fatal: noop,\n child: (): Logger => NOOP_LOGGER,\n});\n\n/** Logger que descarta tudo, sem custo: para testes e como padrão quando ninguém configurou. */\nexport function createNoopLogger(): Logger {\n return NOOP_LOGGER;\n}\n","// Leitura estrutural de schemas Zod: achar o tipo \"de verdade\" atrás de optional/default/pipe,\n// percorrer campos de objeto e saber se um campo é secreto. Olha `_zod.def.type` (string) em vez\n// de `instanceof`, para funcionar mesmo se o plugin trouxer outra cópia do Zod. O core importa\n// o Zod só como tipo: carregar o módulo cria globais (`__zod_globalRegistry`), e importar o core\n// não pode ter side effect (ADR 0004). Por isso tudo passa por métodos do próprio schema\n// (`meta()`, `toJSONSchema()`), que já vêm do Zod que o plugin carregou.\n\nimport type { z } from 'zod';\n\n/** Texto que substitui um valor secreto em qualquer exibição (dashboard, `describe`). */\nexport const SECRET_MASK = '********';\n\ninterface Def {\n readonly type: string;\n readonly innerType?: z.ZodType;\n readonly in?: z.ZodType;\n readonly shape?: Readonly<Record<string, z.ZodType>>;\n readonly values?: readonly unknown[];\n}\n\n// Embrulhos que não mudam o formato do valor de entrada.\nconst WRAPPERS = new Set([\n 'optional',\n 'nullable',\n 'default',\n 'prefault',\n 'readonly',\n 'catch',\n 'nonoptional',\n]);\n\nconst defOf = (schema: z.ZodType): Def => schema._zod.def as unknown as Def;\n\n/** Próximo nível do embrulho, ou `undefined` se `schema` já é o tipo base. */\nfunction innerOf(schema: z.ZodType): z.ZodType | undefined {\n const def = defOf(schema);\n if (WRAPPERS.has(def.type)) return def.innerType;\n // Num pipe (transform, coerce), a entrada é o lado `in`.\n if (def.type === 'pipe') return def.in;\n return undefined;\n}\n\n/** O schema base atrás de optional/default/nullable/pipe. */\nexport function unwrapSchema(schema: z.ZodType): z.ZodType {\n let current = schema;\n for (let inner = innerOf(current); inner; inner = innerOf(current)) current = inner;\n return current;\n}\n\n/** Tipo base do schema (`'string'`, `'number'`, `'object'`...). */\nexport const baseType = (schema: z.ZodType): string => defOf(unwrapSchema(schema)).type;\n\n/** Valores aceitos por um `z.literal` (vazio para outros tipos). */\nexport const literalValues = (schema: z.ZodType): readonly unknown[] =>\n defOf(unwrapSchema(schema)).values ?? [];\n\n/** Campos do objeto, se o schema base for `z.object`. */\nexport function objectShape(schema: z.ZodType): Readonly<Record<string, z.ZodType>> | undefined {\n const def = defOf(unwrapSchema(schema));\n return def.type === 'object' ? def.shape : undefined;\n}\n\n/**\n * Marca um campo como secreto: o valor é censurado no log, mascarado em `describe` e o JSON\n * Schema exportado sai com `secret: true` e `writeOnly: true`. Vale em qualquer nível de objeto\n * e sobrevive a `.optional()`/`.default()` aplicados depois.\n *\n * ```ts\n * config: z.object({ apiKey: secret(z.string().min(1)) })\n * ```\n */\nexport function secret<T extends z.ZodType>(schema: T): T {\n // `meta` clona e registra no registro global do Zod, que o `toJSONSchema` lê; a descrição e\n // outros metadados do schema original são herdados pelo clone.\n return schema.meta({ secret: true, writeOnly: true }) as T;\n}\n\n// Os `checks` (`.min()`, `.refine()`) também têm `_zod`, mas não são schemas: não têm `meta`.\nconst isSchema = (value: unknown): value is z.ZodType =>\n typeof value === 'object' &&\n value !== null &&\n '_zod' in value &&\n typeof (value as { meta?: unknown }).meta === 'function';\n\n/** Sub-schemas guardados na definição (`element`, `options`, `keyType`, `items`...). */\nfunction childrenOf(def: Def): z.ZodType[] {\n const children: z.ZodType[] = [];\n for (const value of Object.values(def)) {\n if (isSchema(value)) children.push(value);\n else if (Array.isArray(value)) children.push(...value.filter(isSchema));\n }\n return children;\n}\n\n/**\n * Caminhos de `secret()` fora de campo de `z.object` (dentro de array, record, union...). A config\n * só acha segredo seguindo objetos — para censurar no log, mascarar e recusar no override —, então\n * um segredo noutro lugar passaria sem nenhuma dessas proteções. `[*]` marca o nível que não é\n * objeto. `z.lazy` não é percorrido.\n */\nexport function misplacedSecrets(schema: z.ZodType): string[] {\n const found: string[] = [];\n const visited = new Set<z.ZodType>();\n const walk = (node: z.ZodType, path: string, nested: boolean): void => {\n if (visited.has(node)) return;\n visited.add(node);\n if (node.meta()?.['secret'] === true) {\n // Num campo de objeto, o valor inteiro é segredo: o que houver dentro já está coberto.\n if (nested) found.push(path);\n return;\n }\n const def = defOf(node);\n if (def.type === 'object') {\n for (const [key, field] of Object.entries(def.shape ?? {})) {\n walk(field, path === '' ? key : `${path}.${key}`, nested);\n }\n return;\n }\n // Embrulhos e pipes não mudam o nível; qualquer outro contêiner tira do caminho de objetos.\n const transparent = WRAPPERS.has(def.type) || def.type === 'pipe';\n for (const child of childrenOf(def)) {\n walk(child, transparent ? path : `${path}[*]`, nested || !transparent);\n }\n };\n walk(schema, '', false);\n return found;\n}\n\n/** `true` se o campo foi marcado com `secret()` (em qualquer nível do embrulho). */\nexport function isSecretSchema(schema: z.ZodType): boolean {\n for (let current: z.ZodType | undefined = schema; current; current = innerOf(current)) {\n if (current.meta()?.['secret'] === true) return true;\n }\n return false;\n}\n","// Camada de variáveis de ambiente da config de plugin. Este é o único lugar do core que lê\n// `process.env` (regra do Biome), e só como padrão quando quem cria a config não injeta um\n// ambiente — testes sempre injetam.\n\nimport type { z } from 'zod';\nimport { baseType, literalValues, objectShape } from './schema.ts';\n\n/** Ambiente consultado: nome → valor. `process.env` tem esse formato. */\nexport type ConfigEnv = Readonly<Record<string, string | undefined>>;\n\nconst ENV_PREFIX = 'BRIDGER';\n\n/** O ambiente do processo. Lido na chamada, nunca no import. */\nexport const processEnv = (): ConfigEnv => process.env;\n\n/** `apiKey` → `API_KEY`, `user-names` → `USER_NAMES`, `openAIKey` → `OPEN_AI_KEY`. */\nexport function toEnvSegment(name: string): string {\n return name\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1_$2')\n .replace(/-/g, '_')\n .toUpperCase();\n}\n\n/**\n * Nome da variável de um campo: `BRIDGER_<PLUGIN>__<CAMPO>[__<SUBCAMPO>...]`. O `__` separa\n * níveis, então `user-names` + `apiKey` vira `BRIDGER_USER_NAMES__API_KEY`.\n */\nexport function envName(plugin: string, path: readonly string[]): string {\n return [`${ENV_PREFIX}_${toEnvSegment(plugin)}`, ...path.map(toEnvSegment)].join('__');\n}\n\nconst TRUE = new Set(['true', '1', 'yes', 'on']);\nconst FALSE = new Set(['false', '0', 'no', 'off']);\n\n/**\n * Converte o texto da variável para o tipo que o schema espera. Se não der, devolve o texto\n * como veio: o Zod rejeita com a mensagem dele e o erro aponta a variável como fonte.\n */\nexport function coerceEnvValue(raw: string, schema: z.ZodType): unknown {\n switch (baseType(schema)) {\n case 'string':\n case 'enum':\n case 'template_literal':\n return raw;\n case 'number': {\n const value = Number(raw);\n return raw.trim() === '' || Number.isNaN(value) ? raw : value;\n }\n case 'boolean': {\n const lower = raw.trim().toLowerCase();\n if (TRUE.has(lower)) return true;\n if (FALSE.has(lower)) return false;\n return raw;\n }\n case 'literal':\n return literalValues(schema).find((value) => String(value) === raw) ?? raw;\n default:\n // Arrays, records, uniões: a variável traz JSON (`[\"a\",\"b\"]`). Texto que não é JSON\n // segue cru, e o Zod decide se uma string serve.\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return raw;\n }\n }\n}\n\n/**\n * Variáveis de ambiente que dois caminhos da config produzem iguais: `openAIKey` e `openAiKey`\n * viram ambos `OPEN_AI_KEY`, e uma variável preencheria os dois campos. Devolve, por variável,\n * os caminhos em conflito. `messages` entra como `messages.<chave>`.\n */\nexport function envCollisions(\n plugin: string,\n shape: Readonly<Record<string, z.ZodType>> | undefined,\n messageKeys: readonly string[],\n): Map<string, string[]> {\n const byName = new Map<string, string[]>();\n const add = (path: readonly string[]): void => {\n const name = envName(plugin, path);\n byName.set(name, [...(byName.get(name) ?? []), path.join('.')]);\n };\n const walk = (fields: Readonly<Record<string, z.ZodType>>, prefix: readonly string[]): void => {\n for (const [key, field] of Object.entries(fields)) {\n const nested = objectShape(field);\n if (nested) walk(nested, [...prefix, key]);\n else add([...prefix, key]);\n }\n };\n if (shape) walk(shape, []);\n for (const key of messageKeys) add(['messages', key]);\n for (const [name, paths] of byName) if (paths.length < 2) byName.delete(name);\n return byName;\n}\n\n/** Um valor lido do ambiente: caminho no objeto de config e a variável de onde veio. */\nexport interface EnvEntry {\n readonly path: readonly string[];\n readonly name: string;\n readonly value: unknown;\n}\n\n/**\n * Valores do ambiente para os campos do schema, percorrendo objetos aninhados. Só campos\n * declarados no schema são procurados — o ambiente não cria chave nova.\n */\nexport function readEnvFields(\n plugin: string,\n shape: Readonly<Record<string, z.ZodType>>,\n env: ConfigEnv,\n prefix: readonly string[] = [],\n): EnvEntry[] {\n const found: EnvEntry[] = [];\n for (const [key, field] of Object.entries(shape)) {\n const path = [...prefix, key];\n const nested = objectShape(field);\n if (nested) {\n found.push(...readEnvFields(plugin, nested, env, path));\n continue;\n }\n const name = envName(plugin, path);\n const raw = env[name];\n if (raw !== undefined) found.push({ path, name, value: coerceEnvValue(raw, field) });\n }\n return found;\n}\n","/** De onde veio o valor de um campo, em ordem crescente de precedência. */\nexport type ConfigSource = 'default' | 'override' | 'file' | 'env';\n\nexport interface PluginConfigIssue {\n /** Caminho do campo (`quality`, `openai.apiKey`, `messages.needMedia`); vazio = o objeto todo. */\n readonly path: string;\n /** O que está errado. Nunca contém o valor recebido (pode ser secreto). */\n readonly message: string;\n /** Camada que forneceu o valor rejeitado; `default` = nenhuma (valor ausente). */\n readonly source: ConfigSource;\n /** Variável de ambiente, quando `source` é `env`. */\n readonly env?: string;\n}\n\nconst describeSource = (plugin: string, issue: PluginConfigIssue): string => {\n switch (issue.source) {\n case 'env':\n return `env ${issue.env}`;\n case 'file': {\n const path = issue.path === '' ? '' : `.${issue.path}`;\n return `arquivo pluginConfig[\"${plugin}\"]${path}`;\n }\n case 'override':\n return 'override salvo no storage';\n case 'default':\n return 'ausente, sem default no schema';\n }\n};\n\n/**\n * Config de plugin rejeitada: lista todos os problemas, cada um com campo e fonte. No boot, a\n * fábrica de contexto que lança este erro faz o plugin ser ignorado (motivo na tabela); numa\n * mudança de config, a mudança é recusada e o plugin segue com a config anterior.\n */\nexport class PluginConfigError extends Error {\n override readonly name = 'PluginConfigError';\n readonly plugin: string;\n readonly issues: readonly PluginConfigIssue[];\n\n constructor(plugin: string, issues: readonly PluginConfigIssue[]) {\n const lines = issues.map(\n (issue) =>\n `${issue.path === '' ? '(config)' : issue.path}: ${issue.message} (fonte: ${describeSource(plugin, issue)})`,\n );\n super(`config inválida do plugin \"${plugin}\":\\n- ${lines.join('\\n- ')}`);\n this.plugin = plugin;\n this.issues = issues;\n }\n}\n","// Config por plugin (M1-13, ADRs 0017 e 0025). Junta as camadas — default do schema < override\n// salvo no storage (dashboard) < arquivo (config do app) < env —, valida com o schema Zod do\n// plugin, mescla os `messages` sobrescritos e mantém os valores secretos no `SecretSet` que o\n// logger consulta. Quem monta o `PluginContext` (M1-16) chama `resolve` a cada setup; uma\n// mudança de override é validada antes de salvar e dispara o reload do plugin. Campo `secret` não\n// entra por override: o storage guarda em texto puro (ADR 0032).\n\nimport type { z } from 'zod';\nimport { createNoopLogger, MIN_SECRET_LENGTH } from '#logger/logger.ts';\nimport type { SecretSet } from '#logger/secrets.ts';\nimport type { Logger } from '#logger/types.ts';\nimport type { PluginReloadResult } from '#plugin/host.ts';\nimport type { PluginDefinition, PluginMessages } from '#plugin/types.ts';\nimport { kernelStorage } from '#storage/namespace.ts';\nimport type { JsonObject, StoragePort } from '#storage/types.ts';\nimport {\n type ConfigEnv,\n type EnvEntry,\n envCollisions,\n envName,\n processEnv,\n readEnvFields,\n} from './env.ts';\nimport { type ConfigSource, PluginConfigError, type PluginConfigIssue } from './errors.ts';\nimport { isSecretSchema, misplacedSecrets, objectShape, SECRET_MASK } from './schema.ts';\n\n/**\n * Config de um plugin vinda do app ou do storage: os campos do schema e, opcionalmente,\n * `messages` com textos a sobrescrever (ADR 0025). `messages` é chave reservada.\n */\nexport type PluginConfigEntry = Readonly<Record<string, unknown>>;\n\n/** \"Arquivo\" de config: nome do plugin → entrada. É o `pluginConfig` da config do bot. */\nexport type PluginConfigFile = Readonly<Record<string, PluginConfigEntry>>;\n\n/** O que o contexto do plugin recebe: `ctx.config` e `ctx.plugin.messages`. */\nexport interface ResolvedPluginConfig {\n /** Saída do schema (defaults aplicados); `undefined` se o plugin não declara `config`. */\n readonly config: unknown;\n /** `messages` do manifesto com as sobrescritas aplicadas. */\n readonly messages: PluginMessages;\n}\n\n/** Config para exibição (dashboard, diagnóstico): campos `secret` trocados por `SECRET_MASK`. */\nexport interface PluginConfigView {\n readonly config: unknown;\n readonly messages: PluginMessages;\n /**\n * Fonte de cada folha da config (`\"openai.token\"`) e de cada mensagem (`\"messages.done\"`).\n * Mostra ao dashboard quando um override não vale porque o arquivo ou o env decide o campo.\n */\n readonly sources: Readonly<Record<string, ConfigSource>>;\n}\n\n/**\n * JSON Schema (draft 2020-12) da entrada da config; campos secretos com `secret: true`,\n * `writeOnly: true` e `x-bridger-override: false` (não editáveis por override).\n */\nexport type PluginConfigJsonSchema = Readonly<Record<string, unknown>>;\n\nexport interface PluginConfigsOptions {\n /** Plugins conhecidos (os mesmos passados ao host). */\n readonly plugins: readonly PluginDefinition[];\n /** Config do app por plugin. */\n readonly file?: PluginConfigFile;\n /** Overrides ficam em `kernelStorage(storage, 'config').kv`, chave = nome do plugin. */\n readonly storage: StoragePort;\n /** Ambiente lido. Padrão: `process.env` (testes injetam o seu). */\n readonly env?: ConfigEnv;\n /** Recebe os valores dos campos `secret` de cada plugin resolvido (compartilhe com o logger). */\n readonly secrets?: SecretSet;\n /** Chamado depois de salvar um override válido; normalmente `(name) => host.reload(name)`. */\n readonly reload?: (plugin: string) => Promise<PluginReloadResult>;\n /** Avisos de configuração (ex.: `pluginConfig` citando plugin inexistente). */\n readonly log?: Logger;\n}\n\nexport interface PluginConfigs {\n /**\n * Config atual do plugin, validada, e `messages` mesclado. Lança `PluginConfigError` se\n * alguma camada tiver valor inválido. Registra os segredos no `SecretSet`.\n */\n resolve(plugin: string): Promise<ResolvedPluginConfig>;\n /**\n * Substitui os overrides do plugin (`{}` remove). Campo `secret` (em qualquer nível) é\n * recusado com `PluginConfigError` (fonte `override`): segredo vem de env ou do arquivo.\n * Valida a config resultante antes de salvar:\n * se inválida, rejeita com `PluginConfigError` e nada muda — o plugin segue rodando. Se\n * válida, salva e chama `reload` (devolve o resultado dele; `undefined` sem `reload`).\n * Campo do override que o arquivo ou o env já definem não tem efeito: é salvo mesmo assim\n * (vale se a camada de cima sair) e gera um aviso no log com os caminhos sombreados.\n */\n setOverrides(plugin: string, overrides: JsonObject): Promise<PluginReloadResult | undefined>;\n /** Config atual com os segredos mascarados. Lança `PluginConfigError` se inválida. */\n describe(plugin: string): Promise<PluginConfigView>;\n /** JSON Schema da config para gerar formulário; `undefined` se o plugin não declara `config`. */\n jsonSchema(plugin: string): PluginConfigJsonSchema | undefined;\n}\n\nconst MESSAGES_KEY = 'messages';\nconst SECRETS_OWNER = (plugin: string): string => `plugin:${plugin}`;\n\ntype PlainObject = Record<string, unknown>;\n\nconst isPlainObject = (value: unknown): value is PlainObject => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n};\n\n/** `top` sobre `base`: objetos mesclam recursivamente; o resto (arrays inclusive) substitui. */\nfunction deepMerge(base: PlainObject, top: PlainObject): PlainObject {\n const merged: PlainObject = { ...base };\n for (const [key, value] of Object.entries(top)) {\n // `undefined` é ausência: não apaga o que veio de camada mais baixa.\n if (value === undefined) continue;\n const current = merged[key];\n merged[key] =\n isPlainObject(current) && isPlainObject(value) ? deepMerge(current, value) : value;\n }\n return merged;\n}\n\nfunction setIn(target: PlainObject, path: readonly string[], value: unknown): void {\n let node = target;\n for (const key of path.slice(0, -1)) {\n const next = node[key];\n if (isPlainObject(next)) node = next;\n else {\n const created: PlainObject = {};\n node[key] = created;\n node = created;\n }\n }\n node[path.at(-1) as string] = value;\n}\n\n/** `true` se a camada forneceu algum valor no caminho. */\nfunction provides(layer: PlainObject, path: readonly PropertyKey[]): boolean {\n let node: unknown = layer;\n for (const key of path) {\n if (typeof node !== 'object' || node === null) return true;\n if (!(key in node)) return false;\n node = (node as Record<PropertyKey, unknown>)[key];\n }\n return node !== undefined;\n}\n\n/** Caminhos das folhas: objetos simples abrem; o resto (arrays inclusive) é folha. */\nfunction leafPaths(value: PlainObject, prefix: readonly string[] = []): string[][] {\n return Object.entries(value).flatMap(([key, child]) => {\n if (child === undefined) return [];\n const path = [...prefix, key];\n return isPlainObject(child) && Object.keys(child).length > 0 ? leafPaths(child, path) : [path];\n });\n}\n\nconst startsWith = (path: readonly PropertyKey[], prefix: readonly string[]): boolean =>\n prefix.every((key, index) => String(path[index]) === key);\n\n/**\n * Copia `value` trocando cada campo `secret` por `onSecret(valor)`. Percorre só objetos\n * declarados no schema; o que o schema não descreve passa intacto.\n */\nfunction mapSecrets(\n schema: z.ZodType,\n value: unknown,\n onSecret: (value: unknown) => unknown,\n): unknown {\n const shape = objectShape(schema);\n if (!shape || !isPlainObject(value)) return value;\n const copy: PlainObject = { ...value };\n for (const [key, field] of Object.entries(shape)) {\n if (copy[key] === undefined) continue;\n copy[key] = isSecretSchema(field)\n ? onSecret(copy[key])\n : mapSecrets(field, copy[key], onSecret);\n }\n return copy;\n}\n\n/**\n * Caminhos dos campos `secret` presentes em `value`, seguindo o schema. Mesmo critério de\n * `mapSecrets`: só objetos declarados; `undefined` é ausência.\n */\nfunction secretPaths(\n schema: z.ZodType,\n value: unknown,\n prefix: readonly string[] = [],\n): string[][] {\n const shape = objectShape(schema);\n if (!shape || !isPlainObject(value)) return [];\n return Object.entries(shape).flatMap(([key, field]) => {\n if (value[key] === undefined) return [];\n const path = [...prefix, key];\n return isSecretSchema(field) ? [path] : secretPaths(field, value[key], path);\n });\n}\n\n/** Valor no caminho de objetos `path` (`undefined` se algum nível faltar). */\nfunction valueAt(value: unknown, path: readonly string[]): unknown {\n let node = value;\n for (const key of path) node = isPlainObject(node) ? node[key] : undefined;\n return node;\n}\n\n/** Cópia de `value` sem o campo em `path` (os objetos do caminho são copiados, não alterados). */\nfunction withoutPath(value: PlainObject, path: readonly string[]): PlainObject {\n const [key, ...rest] = path as [string, ...string[]];\n const copy: PlainObject = { ...value };\n const next = copy[key];\n if (rest.length === 0) delete copy[key];\n else if (isPlainObject(next)) copy[key] = withoutPath(next, rest);\n return copy;\n}\n\n/** Valores de um campo secreto como texto, para o logger achá-los na linha. */\nfunction secretStrings(value: unknown, into: string[]): void {\n if (typeof value === 'string') into.push(value);\n else if (typeof value === 'number' || typeof value === 'bigint') into.push(String(value));\n else if (Array.isArray(value)) for (const item of value) secretStrings(item, into);\n else if (isPlainObject(value)) for (const item of Object.values(value)) secretStrings(item, into);\n}\n\n/** Anotação do JSON Schema que diz ao dashboard que o campo não aceita override. */\nconst OVERRIDE_ANNOTATION = 'x-bridger-override';\n\n/**\n * No JSON Schema exportado, marca campo secreto como não editável por override e troca o\n * `default` dele pela máscara. `x-bridger-override` em vez de `readOnly`: o campo já é\n * `writeOnly`, e `readOnly` + `writeOnly` juntos se contradizem no JSON Schema.\n */\nfunction markSecrets(node: unknown): void {\n if (Array.isArray(node)) {\n for (const item of node) markSecrets(item);\n return;\n }\n if (typeof node !== 'object' || node === null) return;\n const record = node as PlainObject;\n if (record['secret'] === true) {\n record[OVERRIDE_ANNOTATION] = false;\n if ('default' in record) record['default'] = SECRET_MASK;\n }\n for (const value of Object.values(record)) markSecrets(value);\n}\n\ninterface Layer {\n readonly source: Exclude<ConfigSource, 'default' | 'env'>;\n readonly fields: PlainObject;\n readonly messages: PlainObject;\n}\n\ntype Computed =\n | {\n ok: true;\n resolved: ResolvedPluginConfig;\n secrets: string[];\n sources: Record<string, ConfigSource>;\n }\n | { ok: false; error: PluginConfigError };\n\n/** Cria a config dos plugins. Não lê storage nem ambiente até a primeira chamada. */\nexport function createPluginConfigs(options: PluginConfigsOptions): PluginConfigs {\n const env = options.env ?? processEnv();\n const kv = kernelStorage(options.storage, 'config').kv;\n const log = options.log ?? createNoopLogger();\n const file = options.file ?? {};\n const byName = new Map(options.plugins.map((plugin) => [plugin.name, plugin]));\n\n for (const name of Object.keys(file)) {\n if (!byName.has(name)) {\n log.warn(`pluginConfig cita \"${name}\", que não existe entre os plugins`, { plugin: name });\n }\n }\n\n let queue: Promise<unknown> = Promise.resolve();\n // Avisa uma vez por campo: `resolve` roda a cada setup/reload/describe.\n const warnedLegacy = new Set<string>();\n const warnedShort = new Set<string>();\n\n function definitionOf(name: string): PluginDefinition {\n const definition = byName.get(name);\n if (!definition) throw new RangeError(`config: plugin desconhecido \"${name}\"`);\n return definition;\n }\n\n /** Separa campos e `messages` de uma entrada; formato errado vira problema da fonte. */\n function toLayer(\n source: Layer['source'],\n raw: unknown,\n issues: PluginConfigIssue[],\n ): Layer | undefined {\n if (raw === undefined) return undefined;\n if (!isPlainObject(raw)) {\n issues.push({ path: '', message: 'a config do plugin deve ser um objeto', source });\n return undefined;\n }\n const { [MESSAGES_KEY]: messages, ...fields } = raw;\n if (messages !== undefined && !isPlainObject(messages)) {\n issues.push({ path: MESSAGES_KEY, message: 'deve ser um objeto chave → texto', source });\n return { source, fields, messages: {} };\n }\n return { source, fields, messages: messages ?? {} };\n }\n\n function compute(definition: PluginDefinition, override: unknown): Computed {\n const { name } = definition;\n const schema = definition.config;\n const shape = schema ? objectShape(schema) : undefined;\n // Erros do autor do plugin, não da config: mensagem direta, sem fonte.\n if (schema && !shape) {\n throw new TypeError(`plugin \"${name}\": o schema de config deve ser um z.object(...)`);\n }\n if (shape && MESSAGES_KEY in shape) {\n throw new TypeError(\n `plugin \"${name}\": \"${MESSAGES_KEY}\" é reservado para sobrescrever textos (ADR 0025) ` +\n 'e não pode ser campo do schema de config',\n );\n }\n const misplaced = schema ? misplacedSecrets(schema) : [];\n if (misplaced.length > 0) {\n throw new TypeError(\n `plugin \"${name}\": secret() só vale em campo de z.object (em qualquer nível de objetos); ` +\n `dentro de array, record ou union ele não seria censurado nem protegido (ADR 0032): ` +\n misplaced.map((path) => `\"${path}\"`).join(', '),\n );\n }\n const collisions = envCollisions(name, shape, Object.keys(definition.messages ?? {}));\n if (collisions.size > 0) {\n const list = [...collisions].map(([env, paths]) => `${env} (${paths.join(', ')})`);\n throw new TypeError(\n `plugin \"${name}\": campos diferentes geram a mesma variável de ambiente; renomeie um ` +\n `deles: ${list.join('; ')}`,\n );\n }\n\n const issues: PluginConfigIssue[] = [];\n // Da menor para a maior precedência.\n const layers = [\n toLayer('override', override, issues),\n toLayer('file', file[name], issues),\n ].filter((layer) => layer !== undefined);\n const envFields = shape ? readEnvFields(name, shape, env) : [];\n const envMessages: EnvEntry[] = Object.keys(definition.messages ?? {}).flatMap((key) => {\n const variable = envName(name, [MESSAGES_KEY, key]);\n const value = env[variable];\n return value === undefined ? [] : [{ path: [key], name: variable, value }];\n });\n\n let fields: PlainObject = {};\n for (const layer of layers) fields = deepMerge(fields, layer.fields);\n const envLayer: PlainObject = {};\n for (const entry of envFields) setIn(envLayer, entry.path, entry.value);\n fields = deepMerge(fields, envLayer);\n\n const sourceOf = (path: readonly PropertyKey[]): Omit<PluginConfigIssue, 'message'> => {\n const label = path.map(String).join('.');\n const fromEnv = envFields.find((entry) => startsWith(path, entry.path));\n if (fromEnv) return { path: label, source: 'env', env: fromEnv.name };\n for (const layer of layers.toReversed()) {\n if (provides(layer.fields, path)) return { path: label, source: layer.source };\n }\n return { path: label, source: 'default' };\n };\n\n let config: unknown;\n if (!schema) {\n for (const layer of layers) {\n for (const key of Object.keys(layer.fields)) {\n issues.push({\n path: key,\n message: 'o plugin não declara config; o campo não tem para onde ir',\n source: layer.source,\n });\n }\n }\n } else {\n const parsed = schema.safeParse(fields);\n if (parsed.success) config = parsed.data;\n else {\n // Só a mensagem do Zod: ela não inclui o valor recebido, que pode ser secreto.\n for (const issue of parsed.error.issues) {\n issues.push({ ...sourceOf(issue.path), message: issue.message });\n }\n }\n }\n\n const base = definition.messages ?? {};\n const messages: Record<string, string> = { ...base };\n const messageSources: Record<string, ConfigSource> = Object.fromEntries(\n Object.keys(base).map((key) => [`${MESSAGES_KEY}.${key}`, 'default' as const]),\n );\n const messageLayers = [\n ...layers.map((layer) => ({\n entries: Object.entries(layer.messages),\n sourceOf: (): Omit<PluginConfigIssue, 'message' | 'path'> => ({ source: layer.source }),\n })),\n {\n entries: envMessages.map((entry) => [entry.path[0] as string, entry.value] as const),\n sourceOf: (key: string): Omit<PluginConfigIssue, 'message' | 'path'> => ({\n source: 'env',\n env: envName(name, [MESSAGES_KEY, key]),\n }),\n },\n ];\n for (const layer of messageLayers) {\n for (const [key, text] of layer.entries) {\n const at = { path: `${MESSAGES_KEY}.${key}`, ...layer.sourceOf(key) };\n if (!Object.hasOwn(base, key)) {\n const known = Object.keys(base);\n issues.push({\n ...at,\n message:\n `mensagem desconhecida; o plugin declara ` +\n (known.length === 0 ? 'nenhuma' : known.map((k) => `\"${k}\"`).join(', ')),\n });\n } else if (typeof text !== 'string') {\n issues.push({ ...at, message: 'deve ser texto' });\n } else {\n messages[key] = text;\n messageSources[at.path] = at.source;\n }\n }\n }\n\n if (issues.length > 0) return { ok: false, error: new PluginConfigError(name, issues) };\n const secrets: string[] = [];\n if (schema) {\n mapSecrets(schema, config, (value) => {\n secretStrings(value, secrets);\n return value;\n });\n }\n // Pelos caminhos da saída: é o que o plugin recebe, defaults inclusive.\n const sources: Record<string, ConfigSource> = {};\n if (isPlainObject(config)) {\n for (const path of leafPaths(config)) sources[path.join('.')] = sourceOf(path).source;\n }\n return {\n ok: true,\n resolved: { config, messages: Object.freeze(messages) },\n secrets,\n sources: { ...sources, ...messageSources },\n };\n }\n\n /**\n * Override salvo antes da regra de segredos (ou escrito direto no banco) pode ter campo\n * `secret`. O valor é ignorado com aviso em vez de falhar a config: um dado legado não deve\n * desligar o plugin, e o segredo de verdade continua vindo de env ou do arquivo.\n */\n function dropLegacySecrets(definition: PluginDefinition, stored: unknown): unknown {\n if (!definition.config || !isPlainObject(stored)) return stored;\n let clean = stored;\n for (const path of secretPaths(definition.config, stored)) {\n clean = withoutPath(clean, path);\n const label = path.join('.');\n const key = `${definition.name}:${label}`;\n if (warnedLegacy.has(key)) continue;\n warnedLegacy.add(key);\n // Só o caminho: o valor é segredo e ainda não está no `SecretSet`.\n log.warn(\n `override do plugin \"${definition.name}\" tem o campo secreto \"${label}\", ignorado; ` +\n `defina pela env ${envName(definition.name, path)} ou pelo arquivo`,\n { plugin: definition.name, field: label },\n );\n }\n return clean;\n }\n\n /**\n * Avisa (uma vez por campo, sem o valor) do segredo curto demais para a censura do log\n * (`MIN_SECRET_LENGTH`): o logger não o censura, e ele sai no log como qualquer texto.\n */\n function warnShortSecrets(definition: PluginDefinition, config: unknown): void {\n if (!definition.config) return;\n for (const path of secretPaths(definition.config, config)) {\n const values: string[] = [];\n secretStrings(valueAt(config, path), values);\n if (!values.some((value) => value.length < MIN_SECRET_LENGTH)) continue;\n const label = path.join('.');\n const key = `${definition.name}:${label}`;\n if (warnedShort.has(key)) continue;\n warnedShort.add(key);\n log.warn(\n `campo secreto \"${label}\" do plugin \"${definition.name}\" tem menos de ` +\n `${MIN_SECRET_LENGTH} caracteres e não é censurado no log`,\n { plugin: definition.name, field: label },\n );\n }\n }\n\n /** Grava os segredos da config resolvida no `SecretSet` e avisa dos curtos demais. */\n function trackSecrets(definition: PluginDefinition, result: Computed & { ok: true }): void {\n warnShortSecrets(definition, result.resolved.config);\n options.secrets?.set(SECRETS_OWNER(definition.name), result.secrets);\n }\n\n async function current(name: string): Promise<Computed & { ok: true }> {\n const definition = definitionOf(name);\n const result = compute(definition, dropLegacySecrets(definition, await kv.get(name)));\n if (!result.ok) throw result.error;\n trackSecrets(definition, result);\n return result;\n }\n\n /**\n * O dashboard diria \"salvo\" para um campo que o arquivo ou o env decidem (precedência do\n * ADR 0017/0032). Avisa com caminho e fonte; o valor fica de fora (pode ser sensível).\n */\n function warnShadowed(\n name: string,\n overrides: JsonObject,\n sources: Readonly<Record<string, ConfigSource>>,\n ): void {\n const fields = leafPaths(overrides).flatMap((path) => {\n const label = path.join('.');\n // Folha do override que virou objeto mais em cima: vale a fonte das folhas de baixo.\n const below = Object.entries(sources).filter(\n ([key]) => key === label || key.startsWith(`${label}.`),\n );\n const [first] = below;\n if (!first || below.some(([, source]) => source === 'override')) return [];\n return [{ path: label, source: first[1] }];\n });\n if (fields.length === 0) return;\n log.warn(\n `override do plugin \"${name}\" sem efeito em ` +\n `${fields.map((field) => `\"${field.path}\" (vale ${field.source})`).join(', ')}`,\n { plugin: name, fields },\n );\n }\n\n async function runSetOverrides(\n name: string,\n overrides: JsonObject,\n ): Promise<PluginReloadResult | undefined> {\n const definition = definitionOf(name);\n // O storage guarda o override em texto puro (banco, backups): segredo não entra (ADR 0032).\n const secretIssues: PluginConfigIssue[] = definition.config\n ? secretPaths(definition.config, overrides).map((path) => ({\n path: path.join('.'),\n message:\n 'campo secreto não pode ser definido por override (o storage guarda em texto ' +\n `puro); defina pela env ${envName(name, path)} ou pelo arquivo ` +\n `pluginConfig[\"${name}\"].${path.join('.')}`,\n source: 'override',\n }))\n : [];\n if (secretIssues.length > 0) throw new PluginConfigError(name, secretIssues);\n const result = compute(definition, overrides);\n if (!result.ok) throw result.error;\n warnShadowed(name, overrides, result.sources);\n // Antes de salvar e de recarregar: o reload loga, e o segredo novo já precisa sair censurado.\n trackSecrets(definition, result);\n if (Object.keys(overrides).length === 0) await kv.delete(name);\n else await kv.set(name, overrides);\n return options.reload ? options.reload(name) : undefined;\n }\n\n return {\n resolve: async (name) => (await current(name)).resolved,\n\n setOverrides(name: string, overrides: JsonObject): Promise<PluginReloadResult | undefined> {\n // Uma mudança por vez: duas gravações concorrentes reordenariam save e reload.\n const result = queue.then(() => runSetOverrides(name, overrides));\n queue = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n },\n\n async describe(name: string): Promise<PluginConfigView> {\n const definition = definitionOf(name);\n const { resolved, sources } = await current(name);\n const { config, messages } = resolved;\n const masked = definition.config\n ? mapSecrets(definition.config, config, () => SECRET_MASK)\n : config;\n return { config: masked, messages, sources };\n },\n\n jsonSchema(name: string): PluginConfigJsonSchema | undefined {\n const schema = definitionOf(name).config;\n if (!schema) return undefined;\n // `input`: o formulário preenche a entrada (campos com default são opcionais). Transform\n // não tem JSON Schema; vira `{}` em vez de lançar.\n const json = schema.toJSONSchema({ io: 'input', unrepresentable: 'any' });\n markSecrets(json);\n return json as PluginConfigJsonSchema;\n },\n };\n}\n","// Resposta esperada (ADR 0060): o handler pergunta, registra qual passo trata a próxima mensagem\n// daquela pessoa naquele chat e termina, sem segurar o chat na fila de entrada (ADR 0042). O\n// estado fica em memória; o passo é nomeado e o `data` é JSON para que uma espera possa ir ao\n// storage depois sem mudar a API.\n\nimport type { BotMessageContext } from '#context.ts';\nimport { ExecutionTimeoutError } from '#deadline.ts';\nimport type { JsonValue } from '#storage/types.ts';\n\n/** Validade padrão de uma espera: 5 minutos. */\nexport const DEFAULT_REPLY_TTL_MS: number = 5 * 60_000;\n\n/** Maior atraso que o `setTimeout` aceita; acima disso ele dispara na hora. */\nconst MAX_TTL_MS = 2_147_483_647;\n\nexport interface ExpectReplyOptions {\n /** Estado do fluxo, entregue ao passo em `ctx.data`. Padrão: `null`. */\n readonly data?: JsonValue;\n /** Validade da espera em ms. Padrão: 5 minutos. Expirada, some sem aviso. */\n readonly ttlMs?: number;\n}\n\n/**\n * Registra que a próxima mensagem do remetente, neste chat, vai para o passo `step` deste plugin.\n * Uma espera por (chat, remetente): registrar de novo, deste plugin ou de outro, troca a\n * anterior. Lança `TypeError` se o plugin não definiu o passo e `RangeError` com `ttlMs`\n * inválido.\n */\nexport type ExpectReply = (step: string, options?: ExpectReplyOptions) => void;\n\n/** Contexto do passo: o da mensagem que respondeu, com o estado guardado na espera. */\nexport interface StepContext extends BotMessageContext {\n /** Nome do passo que está rodando. */\n readonly step: string;\n /** O `data` da espera; `null` se ela não trouxe nenhum. */\n readonly data: JsonValue;\n /**\n * Aborta quando o passo estoura o prazo (`timeouts.commandMs`), com `reason` =\n * `StepTimeoutError`, como o `signal` do comando.\n */\n readonly signal: AbortSignal;\n /** Encadeia a pergunta seguinte do fluxo (ver `ExpectReply`). */\n readonly expectReply: ExpectReply;\n}\n\nexport type StepHandler = (ctx: StepContext) => unknown;\n\n/** Passos de conversa do plugin (`ctx.conversations`). */\nexport interface Conversations {\n /**\n * Define o passo `step`, que trata a resposta registrada com `expectReply(step)`. Nome vazio ou\n * repetido no mesmo plugin lança `TypeError`. O passo e as esperas dele saem no\n * teardown/reload.\n */\n define(step: string, handler: StepHandler): void;\n}\n\n/** O passo estourou o prazo. Vai em `plugin.error` com `phase: 'step'` e `timedOut: true`. */\nexport class StepTimeoutError extends ExecutionTimeoutError {\n override readonly name: string = 'StepTimeoutError';\n readonly step: string;\n\n constructor(plugin: string, step: string, timeoutMs: number) {\n super(plugin, `passo \"${step}\"`, timeoutMs);\n this.step = step;\n }\n}\n\n/** Passo como o kernel o roda: já com prazo e visão do plugin, montados por quem o define. */\nexport type KernelStep<C> = (ctx: C, data: JsonValue) => unknown;\n\n/** Espera consumida por `take`: o que o bot precisa para rodar o passo. */\nexport interface PendingReply<C> {\n readonly plugin: string;\n readonly step: string;\n readonly data: JsonValue;\n readonly run: KernelStep<C>;\n}\n\ninterface Wait {\n readonly plugin: string;\n readonly step: string;\n readonly data: JsonValue;\n readonly timer: ReturnType<typeof setTimeout>;\n}\n\n/** Esperas e passos de todos os plugins de um bot (estado no closure do bot, ADR 0004). */\nexport class ConversationRegistry<C> {\n readonly #steps = new Map<string, Map<string, KernelStep<C>>>();\n readonly #waits = new Map<string, Wait>();\n #closed = false;\n\n define(plugin: string, step: string, run: KernelStep<C>): void {\n if (typeof step !== 'string' || step.length === 0) {\n throw new TypeError(`plugin \"${plugin}\": nome de passo vazio`);\n }\n let steps = this.#steps.get(plugin);\n if (steps === undefined) {\n steps = new Map();\n this.#steps.set(plugin, steps);\n }\n if (steps.has(step)) throw new TypeError(`plugin \"${plugin}\": passo \"${step}\" já definido`);\n steps.set(step, run);\n }\n\n expect(\n plugin: string,\n chatId: string,\n senderId: string,\n step: string,\n options: ExpectReplyOptions = {},\n ): void {\n if (!this.#steps.get(plugin)?.has(step)) {\n throw new TypeError(\n `plugin \"${plugin}\": expectReply(\"${step}\") sem o passo; defina-o com ` +\n 'ctx.conversations.define',\n );\n }\n const ttlMs = options.ttlMs ?? DEFAULT_REPLY_TTL_MS;\n if (!(Number.isFinite(ttlMs) && ttlMs > 0 && ttlMs <= MAX_TTL_MS)) {\n throw new RangeError(`plugin \"${plugin}\": ttlMs de expectReply inválido: ${ttlMs}`);\n }\n // Depois do shutdown não há quem responda, e o timer sobreviveria ao `stop()`.\n if (this.#closed) return;\n const key = waitKey(chatId, senderId);\n this.#drop(key);\n const timer = setTimeout(() => {\n if (this.#waits.get(key)?.timer === timer) this.#waits.delete(key);\n }, ttlMs);\n // A espera não mantém o processo vivo: ela só importa se chegar mensagem.\n timer.unref?.();\n this.#waits.set(key, { plugin, step, data: options.data ?? null, timer });\n }\n\n /**\n * Retira a espera do remetente no chat, se houver. Quem chama decide se roda o passo ou, com um\n * comando digitado, só a descarta. O mapa vazio sai sem montar a chave: o caminho de cada\n * mensagem não paga nada sem conversa aberta.\n */\n take(chatId: string, senderId: string): PendingReply<C> | undefined {\n if (this.#waits.size === 0) return undefined;\n const key = waitKey(chatId, senderId);\n const wait = this.#waits.get(key);\n if (wait === undefined) return undefined;\n this.#drop(key);\n // O passo existe: o `removePlugin` tira passos e esperas juntos.\n const run = this.#steps.get(wait.plugin)?.get(wait.step) as KernelStep<C>;\n return { plugin: wait.plugin, step: wait.step, data: wait.data, run };\n }\n\n /** O passo do plugin, para rodar sem espera (o clique num botão, ADR 0062). */\n find(plugin: string, step: string): KernelStep<C> | undefined {\n return this.#steps.get(plugin)?.get(step);\n }\n\n /** Tira os passos e as esperas do plugin (teardown/reload), com os timers. */\n removePlugin(plugin: string): void {\n this.#steps.delete(plugin);\n for (const [key, wait] of this.#waits) {\n if (wait.plugin === plugin) this.#drop(key);\n }\n }\n\n /** Descarta tudo e recusa esperas novas: nenhum timer sobrevive ao shutdown. */\n close(): void {\n this.#closed = true;\n for (const key of [...this.#waits.keys()]) this.#drop(key);\n this.#steps.clear();\n }\n\n #drop(key: string): void {\n const wait = this.#waits.get(key);\n if (wait === undefined) return;\n clearTimeout(wait.timer);\n this.#waits.delete(key);\n }\n}\n\n// NUL não aparece em ID de chat nem de contato de nenhuma plataforma: a chave não colide.\nconst waitKey = (chatId: string, senderId: string): string => `${chatId}\\u0000${senderId}`;\n","import {\n ArmedTimers,\n ContextExpiredError,\n DEADLINE,\n Deadline,\n deadlineOf,\n ListenerTimeoutError,\n} from '#deadline.ts';\nimport type { Message, MessageType } from '#message/types.ts';\nimport type { Unsubscribe } from '#transport/types.ts';\nimport type {\n BotEventName,\n BotEvents,\n EventSubscriber,\n ListenerContext,\n ListenerExtras,\n MessageFilter,\n MessageTypeEvents,\n PluginErrorEvent,\n SubscribeOptions,\n} from './types.ts';\n\n/** Eventos que se emitem diretamente. `message:<type>` não entra: o bus o deriva de `message`. */\nexport type EmittableEventName = Exclude<BotEventName, keyof MessageTypeEvents>;\n\n/**\n * Extras do contexto. Opcionais para o barramento: ele só os copia, sem conferir. Nos eventos de\n * mensagem o `ListenerContext` declara `MessageListenerFields`, e quem garante que eles chegam é\n * o `Bot`, que monta o contexto de cada plugin (M1-16); quem usa o barramento solto e emite\n * mensagem sem extras entrega listeners sem esses campos.\n */\nexport type EmitExtras<E extends BotEventName> = [extras?: ListenerExtras<E>];\n\nexport interface EmitResult {\n /** Listeners que rodaram (os barrados pelo filtro não contam). */\n readonly listeners: number;\n /** Algum listener chamou `claim()`, antes ou depois do primeiro `await`. */\n readonly claimed: boolean;\n /** Listeners que lançaram, rejeitaram ou estouraram o prazo. */\n readonly failed: number;\n}\n\nexport interface EventBusOptions {\n /** Prazo padrão de cada listener em ms; `ListenerOptions.timeoutMs` sobrescreve. Padrão: 30000. */\n readonly listenerTimeoutMs?: number;\n /**\n * Destino garantido de toda falha de listener (o log do kernel). Recebe também as falhas que\n * não viram evento: as dos listeners de `plugin.error` e as rejeições que chegam depois do\n * prazo. Não deve lançar.\n */\n readonly onError: (error: PluginErrorEvent) => void;\n /** Onde ficam os prazos armados dos listeners, para o shutdown do `Bot` desarmá-los. */\n readonly armed?: ArmedTimers;\n}\n\n/** Deriva o contexto que um listener recebe a partir do contexto da emissão. */\nexport type ListenerView = <C extends object>(ctx: C) => C;\n\nexport interface PluginSubscriberOptions {\n /**\n * Visão por listener para os listeners deste plugin no `event` assinado; `undefined` usa a\n * padrão (`Object.create(ctx)`). A visão precisa herdar do contexto recebido. O `Bot` a usa\n * para pôr `message`/`text`/`reply`/`log` do plugin nos eventos de mensagem sem uma segunda\n * camada de protótipo no caminho quente.\n */\n readonly view?: (event: BotEventName) => ListenerView | undefined;\n /**\n * `Deadline` de vida do plugin: o de cada listener é filho dele, então o descarte do plugin\n * aborta o `signal` e recusa o `reply` dos listeners ainda em andamento.\n */\n readonly lifetime?: Deadline;\n}\n\nexport interface EventBus {\n /** Assinatura em nome do plugin: falhas saem com o nome dele e `removePlugin` as desfaz. */\n forPlugin(plugin: string, options?: PluginSubscriberOptions): EventSubscriber;\n /** Remove todos os listeners do plugin (teardown e reload). */\n removePlugin(plugin: string): void;\n /**\n * Inicia todos os listeners do evento, em ordem de prioridade decrescente, sem esperar um\n * pelo outro. `message` alcança também os listeners de `message:<tipo da mensagem>`, numa\n * única ordem e com o mesmo `claim()`. Resolve quando todos assentam (ou estouram o prazo);\n * nunca rejeita, porque cada falha já foi entregue a `plugin.error` e ao `onError`.\n */\n emit<E extends EmittableEventName>(\n event: E,\n payload: BotEvents[E],\n ...extras: EmitExtras<E>\n ): Promise<EmitResult>;\n listenerCount(event: BotEventName): number;\n /** Nenhum listener assíncrono em andamento (os que estouraram o prazo já não contam). */\n readonly idle: boolean;\n /** Resolve quando `idle`. Não impede novas emissões. */\n onIdle(): Promise<void>;\n}\n\nexport const DEFAULT_LISTENER_TIMEOUT_MS = 30_000;\n\ntype AnyContext = ListenerContext<BotEventName>;\ntype AnyListener = (ctx: AnyContext) => unknown;\n\ninterface Entry {\n readonly plugin: string;\n readonly listener: AnyListener;\n readonly priority: number;\n readonly timeoutMs: number;\n /** Ordem de registro, para desempatar prioridades iguais de forma estável entre eventos. */\n readonly seq: number;\n /** Tipos aceitos em `quoted`; `null` sem filtro. */\n readonly quoted: ReadonlySet<MessageType> | null;\n readonly view: ListenerView | undefined;\n readonly lifetime: Deadline | undefined;\n}\n\nconst NO_ENTRIES: readonly Entry[] = [];\nconst NO_LISTENERS: Promise<EmitResult> = Promise.resolve({\n listeners: 0,\n claimed: false,\n failed: 0,\n});\n\nfunction compare(a: Entry, b: Entry): number {\n return b.priority - a.priority || a.seq - b.seq;\n}\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n value !== null &&\n (typeof value === 'object' || typeof value === 'function') &&\n typeof (value as PromiseLike<unknown>).then === 'function'\n );\n}\n\nfunction quotedSet(filter: MessageFilter['quoted']): ReadonlySet<MessageType> | null {\n if (filter === undefined) return null;\n return new Set(typeof filter === 'string' ? [filter] : filter);\n}\n\nfunction validTimeout(value: number): number {\n // setTimeout trata Infinity/NaN como 1 ms: o listener estouraria na hora.\n if (!Number.isFinite(value) || value <= 0) throw new RangeError(`Prazo inválido: ${value}`);\n return value;\n}\n\nexport function createEventBus(options: EventBusOptions): EventBus {\n const defaultTimeoutMs = validTimeout(options.listenerTimeoutMs ?? DEFAULT_LISTENER_TIMEOUT_MS);\n const onError = options.onError;\n const armed = options.armed ?? new ArmedTimers();\n // Arrays imutáveis (copy-on-write): a emissão percorre o array da vez sem copiar, e quem\n // (des)assina durante uma emissão não afeta a rodada em andamento.\n const byEvent = new Map<string, readonly Entry[]>();\n // `message` + `message:<tipo>` já mesclados por tipo; refeito só quando as assinaturas mudam.\n const messageEntries = new Map<MessageType, readonly Entry[]>();\n let seq = 0;\n // Listeners assíncronos em andamento, para o `bot.settled()`: eventos diretos e `plugin.error`\n // são emitidos sem ninguém esperar, então só o barramento sabe que ainda há trabalho.\n let running = 0;\n let idleWaiters: (() => void)[] = [];\n\n function settle(): void {\n running--;\n if (running > 0 || idleWaiters.length === 0) return;\n const waiters = idleWaiters;\n idleWaiters = [];\n for (const resolve of waiters) resolve();\n }\n\n function changed(event: string, entries: readonly Entry[]): void {\n if (entries.length === 0) byEvent.delete(event);\n else byEvent.set(event, entries);\n messageEntries.clear();\n }\n\n function entriesForMessage(type: MessageType): readonly Entry[] {\n let merged = messageEntries.get(type);\n if (merged === undefined) {\n const base = byEvent.get('message') ?? NO_ENTRIES;\n const typed = byEvent.get(`message:${type}`) ?? NO_ENTRIES;\n if (typed.length === 0) merged = base;\n else if (base.length === 0) merged = typed;\n else merged = [...base, ...typed].sort(compare);\n messageEntries.set(type, merged);\n }\n return merged;\n }\n\n function subscribe(\n plugin: string,\n options: PluginSubscriberOptions | undefined,\n event: BotEventName,\n first: unknown,\n second: unknown,\n ): Unsubscribe {\n const [listener, opts] = (typeof first === 'function' ? [first, second] : [second, first]) as [\n unknown,\n (SubscribeOptions<'message'> & SubscribeOptions<BotEventName>) | undefined,\n ];\n if (typeof listener !== 'function') throw new TypeError(`Listener de \"${event}\" não é função`);\n const priority = opts?.priority ?? 0;\n // NaN quebraria a comparação do sort e embaralharia a ordem do evento inteiro.\n if (!Number.isFinite(priority)) throw new RangeError(`Prioridade inválida: ${priority}`);\n const entry: Entry = {\n plugin,\n listener: listener as AnyListener,\n priority,\n timeoutMs: opts?.timeoutMs === undefined ? defaultTimeoutMs : validTimeout(opts.timeoutMs),\n seq: seq++,\n quoted: quotedSet(opts?.quoted),\n view: options?.view?.(event),\n lifetime: options?.lifetime,\n };\n changed(event, [...(byEvent.get(event) ?? NO_ENTRIES), entry].sort(compare));\n return () => {\n const current = byEvent.get(event);\n if (!current?.includes(entry)) return;\n changed(\n event,\n current.filter((e) => e !== entry),\n );\n };\n }\n\n function fail(entry: Entry, event: BotEventName, error: unknown, timedOut: boolean): void {\n const report: PluginErrorEvent = {\n plugin: entry.plugin,\n phase: 'listener',\n event,\n error,\n timedOut,\n };\n onError(report);\n // Falha de um listener de `plugin.error` viraria outro `plugin.error`, em loop: fica só no\n // onError.\n if (event !== 'plugin.error') void emit('plugin.error', report);\n }\n\n /**\n * Corre a promise do listener contra o prazo; resolve `true` se ele falhou. Estourado o prazo,\n * expira o `Deadline` do listener: o `ctx.signal` dele aborta (ADR 0033).\n */\n function watch(\n entry: Entry,\n event: BotEventName,\n result: PromiseLike<unknown>,\n deadline: Deadline,\n ): Promise<boolean> {\n running++;\n return new Promise<boolean>((resolve) => {\n let settled = false;\n const disarm = (): void => {\n settled = true;\n cancel();\n armed.delete(disarm);\n settle();\n };\n // Pausa enquanto o `reply` do listener aguarda a fila de saída (ADR 0047).\n const cancel = deadline.armTimer(entry.timeoutMs, () => {\n disarm();\n const error = new ListenerTimeoutError(entry.plugin, event, entry.timeoutMs);\n deadline.expire(error);\n fail(entry, event, error, true);\n resolve(true);\n });\n armed.add(disarm);\n result.then(\n () => {\n if (settled) return;\n disarm();\n resolve(false);\n },\n (error: unknown) => {\n if (settled) {\n // Já reportado como timeout; o erro tardio só vai para o log. A recusa de um\n // contexto expirado já foi logada quando aconteceu (ADR 0033): não repete.\n if (!(error instanceof ContextExpiredError)) {\n onError({ plugin: entry.plugin, phase: 'listener', event, error, timedOut: false });\n }\n return;\n }\n disarm();\n fail(entry, event, error, false);\n resolve(true);\n },\n );\n });\n }\n\n function emit<E extends EmittableEventName>(\n event: E,\n payload: BotEvents[E],\n ...[extras]: EmitExtras<E>\n ): Promise<EmitResult> {\n const entries =\n event === 'message'\n ? entriesForMessage((payload as Message).type)\n : (byEvent.get(event) ?? NO_ENTRIES);\n if (entries.length === 0) return NO_LISTENERS;\n\n // Um contexto por emissão, compartilhado: é o que torna o claim() visível aos demais. Cada\n // listener recebe uma visão derivada dele com o próprio `Deadline`: o prazo é por listener,\n // e um lento expirar não pode abortar o `signal` de outro que está no prazo.\n let claimed = false;\n const ctx = {\n event,\n payload,\n get claimed() {\n return claimed;\n },\n claim() {\n claimed = true;\n },\n get signal(): AbortSignal {\n // `this` é a visão do listener (ou uma derivada dela); o `Deadline` está nela.\n return (deadlineOf(this) as Deadline).signal;\n },\n };\n if (extras !== undefined) Object.assign(ctx, extras);\n\n let listeners = 0;\n let failed = 0;\n let pending: Promise<boolean>[] | undefined;\n for (const entry of entries) {\n if (entry.quoted !== null) {\n const quoted = (payload as Message).quoted;\n if (!quoted || !entry.quoted.has(quoted.type)) continue;\n }\n listeners++;\n const deadline = new Deadline(entry.lifetime);\n const view: { [DEADLINE]?: Deadline } =\n entry.view === undefined ? Object.create(ctx) : entry.view(ctx);\n view[DEADLINE] = deadline;\n let result: unknown;\n try {\n result = entry.listener(view as unknown as AnyContext);\n } catch (error) {\n failed++;\n fail(entry, event, error, false);\n continue;\n }\n if (isThenable(result)) {\n pending ??= [];\n pending.push(watch(entry, event, result, deadline));\n }\n }\n\n if (pending === undefined) return Promise.resolve({ listeners, claimed, failed });\n return Promise.all(pending).then((results) => {\n for (const listenerFailed of results) if (listenerFailed) failed++;\n return { listeners, claimed, failed };\n });\n }\n\n return {\n forPlugin(plugin, options) {\n return {\n on(event: BotEventName, first: unknown, second?: unknown): Unsubscribe {\n return subscribe(plugin, options, event, first, second);\n },\n } as EventSubscriber;\n },\n\n removePlugin(plugin) {\n for (const [event, entries] of byEvent) {\n const kept = entries.filter((e) => e.plugin !== plugin);\n if (kept.length !== entries.length) changed(event, kept);\n }\n },\n\n emit,\n\n listenerCount(event) {\n return byEvent.get(event)?.length ?? 0;\n },\n\n get idle() {\n return running === 0;\n },\n\n onIdle() {\n if (running === 0) return Promise.resolve();\n return new Promise((resolve) => idleWaiters.push(resolve));\n },\n };\n}\n","// `ctx.groups` (ADR 0040): leitura dos metadados direto no transport; alteração de participantes\n// é tráfego e passa pela fila de saída, como as ações de `ctx.send`.\n\nimport type { EnqueueAction } from '#outbound/actions.ts';\nimport type { ActionOptions } from '#outbound/types.ts';\nimport { assertCapability, groupActionCapability } from '#transport/capabilities.ts';\nimport type { GroupMetadata, GroupParticipantAction, Transport } from '#transport/types.ts';\n\nexport interface Groups {\n /**\n * Nome, descrição e participantes do grupo (capability `groups`). `participants` fica ausente\n * onde a plataforma não lista membros (ADR 0059). Sem cache: cada chamada consulta o transport.\n */\n metadata(groupId: string): Promise<GroupMetadata>;\n /**\n * Adiciona, remove, promove ou rebaixa participantes, pela fila de saída. Cada ação exige a\n * sua capability: `groups.add`, `groups.remove` ou `groups.promote` (que vale também para\n * `demote`); o bot precisa ser admin do grupo.\n */\n updateParticipants(\n groupId: string,\n participantIds: readonly string[],\n action: GroupParticipantAction,\n options?: ActionOptions,\n ): Promise<void>;\n}\n\nexport function createGroups(\n transport: Pick<\n Transport,\n 'name' | 'capabilities' | 'getGroupMetadata' | 'updateGroupParticipants'\n >,\n action: EnqueueAction,\n): Groups {\n return {\n async metadata(groupId) {\n assertCapability(transport, 'groups');\n return transport.getGroupMetadata(groupId);\n },\n updateParticipants: (groupId, participantIds, change, options) =>\n action(\n groupActionCapability(change),\n groupId,\n () => transport.updateGroupParticipants(groupId, participantIds, change),\n options,\n ),\n };\n}\n","// Servidor HTTP do processo (ADR 0020, 0076). Um por processo, dividido pelos bots como o\n// storage: cada bot publica a própria tabela de rotas (`SessionHttp`) ao subir e a retira ao\n// parar. O router do Hono não remove rota, então o app é remontado da tabela a cada mudança,\n// que só acontece no boot, no reload e no stop. Hono, adapter do Node e `ws` carregam só ao\n// abrir a porta: bot sem rota não paga a memória deles.\n\nimport type { Server } from 'node:http';\nimport type { upgradeWebSocket as UpgradeWebSocket } from '@hono/node-server';\nimport type { Context, Hono } from 'hono';\nimport type { WSContext, WSEvents } from 'hono/ws';\nimport type { WebSocketServer } from 'ws';\nimport { BotConfigError } from '#config/owners.ts';\nimport type { Logger } from '#logger/types.ts';\nimport { DEFAULT_SESSION } from '#storage/namespace.ts';\nimport type {\n HttpHandler,\n HttpMethod,\n HttpOptions,\n HttpRequestInfo,\n HttpRoutes,\n HttpServer,\n HttpSocket,\n HttpSocketAccept,\n HttpSocketHandlers,\n} from './types.ts';\n\nconst METHODS: ReadonlySet<string> = new Set<HttpMethod>([\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n]);\n\n/** Código de fechamento \"going away\": a rota sumiu (reload, teardown ou stop). */\nconst GOING_AWAY = 1001;\n\n/** O mesmo método e caminho registrados duas vezes pelo mesmo dono. */\nexport class HttpRouteConflictError extends Error {\n override readonly name = 'HttpRouteConflictError';\n readonly method: HttpMethod;\n readonly path: string;\n\n constructor(method: HttpMethod, path: string) {\n super(`rota ${method} ${path} já registrada`);\n this.method = method;\n this.path = path;\n }\n}\n\n/** Módulos do servidor, carregados na primeira abertura da porta. */\ninterface ServerLib {\n readonly Hono: typeof Hono;\n readonly upgradeWebSocket: typeof UpgradeWebSocket;\n}\n\ninterface RouteEntry {\n readonly owner: string;\n readonly method: HttpMethod;\n /** Caminho relativo, normalizado (sem barra final). */\n readonly path: string;\n /** Resolvido ao montar o app: o nome do transport só existe depois da fábrica. */\n readonly base: () => string;\n readonly target: HttpHandler | { readonly ws: HttpSocketAccept };\n readonly onError: (error: unknown) => void;\n /** Conexões abertas, fechadas quando a rota sai. */\n readonly sockets: Set<WSContext>;\n}\n\n// O `HttpServer` público só expõe a porta; o resto é do kernel.\nconst hubs = new WeakMap<HttpServer, HttpHub>();\n\n/**\n * Servidor HTTP para `BotConfig.http`, o mesmo para todos os bots do processo. Nada abre aqui:\n * a porta abre no `start()` do primeiro bot que tiver rota (ver docs/http.md).\n */\nexport function createHttp(options: HttpOptions): HttpServer {\n const { port } = options;\n if (!(Number.isInteger(port) && port >= 0 && port <= 65_535)) {\n throw new RangeError(`http: port deve ser inteiro entre 0 e 65535 (recebido: ${port})`);\n }\n const hub = new HttpHub(options);\n const server: HttpServer = {\n get port() {\n return hub.port;\n },\n };\n hubs.set(server, hub);\n return server;\n}\n\n/** Tabela de rotas de uma sessão nesse servidor; sem efeito até o `attach`. */\nexport function sessionHttp(server: HttpServer, session: string, log: () => Logger): SessionHttp {\n const hub = hubs.get(server);\n if (hub === undefined) {\n throw new BotConfigError('http: passe o servidor criado por `createHttp({ port })`');\n }\n return new SessionHttp(hub, session, log);\n}\n\n/** Prefixo das rotas da sessão: nenhum na `default`, para a URL não mudar quando entra outro bot. */\nfunction sessionPrefix(session: string): string {\n return session === DEFAULT_SESSION ? '' : `/sessions/${session}`;\n}\n\nfunction normalizePath(path: string): string {\n if (typeof path !== 'string' || !path.startsWith('/')) {\n throw new TypeError(`http: o caminho deve começar com \"/\" (recebido: ${String(path)})`);\n }\n return path.length > 1 && path.endsWith('/') ? path.slice(0, -1) : path;\n}\n\n/** Rotas de um bot no servidor. Publicadas no `attach` (start) e retiradas no `detach` (stop). */\nexport class SessionHttp {\n readonly session: string;\n readonly log: () => Logger;\n readonly #hub: HttpHub;\n readonly #prefix: string;\n readonly #entries = new Map<string, RouteEntry>();\n #state: () => string = () => 'idle';\n #attached = false;\n\n constructor(hub: HttpHub, session: string, log: () => Logger) {\n this.#hub = hub;\n this.session = session;\n this.log = log;\n this.#prefix = sessionPrefix(session);\n }\n\n /**\n * Rotas de um dono (um plugin, ou o transport) sob `prefixo + segment()`. `onError` recebe a\n * falha de um handler com a rota (`POST /webhook`).\n */\n scope(\n owner: string,\n segment: () => string,\n onError: (error: unknown, route: string) => void,\n ): HttpRoutes {\n const base = (): string => this.#prefix + segment();\n const add = (method: HttpMethod, rawPath: string, target: RouteEntry['target']): void => {\n const path = normalizePath(rawPath);\n const key = `${owner} ${method} ${path}`;\n if (this.#entries.has(key)) throw new HttpRouteConflictError(method, path);\n this.#entries.set(key, {\n owner,\n method,\n path,\n base,\n target,\n onError: (error) => onError(error, `${method} ${path}`),\n sockets: new Set(),\n });\n if (this.#attached) this.#hub.changed();\n };\n return {\n get basePath() {\n return base();\n },\n route(method, path, handler) {\n if (!METHODS.has(method)) {\n throw new TypeError(`http: método não suportado: ${String(method)}`);\n }\n add(method, path, handler);\n },\n ws(path, accept) {\n add('GET', path, { ws: accept });\n },\n };\n }\n\n entries(): Iterable<RouteEntry> {\n return this.#entries.values();\n }\n\n get hasRoutes(): boolean {\n return this.#entries.size > 0;\n }\n\n state(): string {\n return this.#state();\n }\n\n /** Tira as rotas de um dono (teardown ou reload do plugin) e fecha as conexões delas. */\n removeOwner(owner: string): void {\n let removed = false;\n for (const [key, entry] of this.#entries) {\n if (entry.owner !== owner) continue;\n this.#entries.delete(key);\n closeSockets(entry);\n removed = true;\n }\n if (removed && this.#attached) this.#hub.changed();\n }\n\n /** Publica as rotas no servidor; sessão repetida no mesmo servidor é erro de config. */\n attach(state: () => string): void {\n this.#hub.attach(this);\n this.#state = state;\n this.#attached = true;\n }\n\n /** Abre a porta se alguma sessão tiver rota (e, daqui em diante, quando a primeira chegar). */\n listen(): Promise<void> {\n return this.#hub.listen();\n }\n\n /** Retira as rotas; o último bot a sair fecha a porta. */\n async detach(): Promise<void> {\n if (!this.#attached) return;\n this.#attached = false;\n for (const entry of this.#entries.values()) closeSockets(entry);\n this.#entries.clear();\n await this.#hub.detach(this);\n }\n}\n\nclass HttpHub {\n readonly #options: HttpOptions;\n readonly #sessions = new Map<string, SessionHttp>();\n #app: Hono | undefined;\n #lib: ServerLib | undefined;\n #server: Server | undefined;\n #wss: WebSocketServer | undefined;\n #listening: Promise<void> | undefined;\n #closing: Promise<void> = Promise.resolve();\n // Algum bot terminou o boot: rota que chegar depois (reload) abre a porta na hora.\n #armed = false;\n\n constructor(options: HttpOptions) {\n this.#options = options;\n }\n\n get port(): number | undefined {\n const address = this.#server?.address();\n return address !== null && typeof address === 'object' ? address.port : undefined;\n }\n\n attach(session: SessionHttp): void {\n if (this.#sessions.has(session.session)) {\n throw new BotConfigError(\n `http: a sessão \"${session.session}\" já está ligada a este servidor; cada bot precisa ` +\n 'de um `session` diferente',\n );\n }\n this.#sessions.set(session.session, session);\n this.changed();\n }\n\n async detach(session: SessionHttp): Promise<void> {\n if (this.#sessions.get(session.session) !== session) return;\n this.#sessions.delete(session.session);\n this.changed();\n if (this.#sessions.size === 0) await this.#close();\n }\n\n changed(): void {\n this.#app = undefined;\n if (this.#armed && this.#listening === undefined && this.#hasRoutes()) {\n this.#listen().catch((error: unknown) =>\n this.#log()?.error('http: falha ao abrir a porta', {\n err: error,\n port: this.#options.port,\n }),\n );\n }\n }\n\n listen(): Promise<void> {\n this.#armed = true;\n return this.#hasRoutes() ? this.#listen() : Promise.resolve();\n }\n\n #hasRoutes(): boolean {\n for (const session of this.#sessions.values()) if (session.hasRoutes) return true;\n return false;\n }\n\n #log(): Logger | undefined {\n for (const session of this.#sessions.values()) return session.log();\n return undefined;\n }\n\n #listen(): Promise<void> {\n if (this.#listening === undefined) {\n // Um fechamento em curso libera a porta antes de abrir de novo.\n const opening = this.#closing.then(() => this.#open());\n this.#listening = opening;\n // Falhou (porta ocupada): a próxima chamada tenta de novo. O erro segue para quem esperou.\n opening.catch(() => {\n if (this.#listening === opening) this.#listening = undefined;\n });\n }\n return this.#listening;\n }\n\n async #open(): Promise<void> {\n const [{ createAdaptorServer, upgradeWebSocket }, { Hono }, { WebSocketServer }] =\n await Promise.all([import('@hono/node-server'), import('hono'), import('ws')]);\n this.#lib = { Hono, upgradeWebSocket };\n const wss = new WebSocketServer({ noServer: true });\n const server = createAdaptorServer({\n fetch: (request, env) => this.#currentApp().fetch(request, env),\n websocket: { server: wss },\n }) as Server;\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(this.#options.port, this.#options.hostname, () => {\n server.off('error', reject);\n resolve();\n });\n });\n server.on('error', (error) => this.#log()?.error('http: erro no servidor', { err: error }));\n this.#server = server;\n this.#wss = wss;\n }\n\n async #close(): Promise<void> {\n this.#armed = false;\n const listening = this.#listening;\n if (listening === undefined) return;\n this.#listening = undefined;\n // Abertura que falhou não deixou nada para fechar.\n const closing = listening.then(\n () => this.#shut(),\n () => undefined,\n );\n this.#closing = closing.catch(() => undefined);\n await closing;\n }\n\n #shut(): Promise<void> {\n const server = this.#server;\n const wss = this.#wss;\n this.#server = undefined;\n this.#wss = undefined;\n if (server === undefined) return Promise.resolve();\n for (const client of wss?.clients ?? []) client.terminate();\n return new Promise<void>((resolve, reject) => {\n server.close((error) => (error ? reject(error) : resolve()));\n // Os bots já pararam: requisição em curso (ou keep-alive) não segura o encerramento.\n server.closeAllConnections();\n });\n }\n\n #currentApp(): Hono {\n // Só há requisição com a porta aberta, e a abertura carregou a lib.\n const lib = this.#lib as ServerLib;\n this.#app ??= this.#build(lib);\n return this.#app;\n }\n\n #build(lib: ServerLib): Hono {\n const app = new lib.Hono({ strict: false });\n app.get('/health', (c) => {\n const sessions: Record<string, string> = {};\n for (const [name, session] of this.#sessions) sessions[name] = session.state();\n const ok = Object.values(sessions).every((state) => state === 'running');\n return c.json({ status: ok ? 'ok' : 'degraded', sessions }, ok ? 200 : 503);\n });\n for (const session of this.#sessions.values()) {\n for (const entry of session.entries()) mount(app, entry, lib.upgradeWebSocket);\n }\n app.onError((error, c) => {\n this.#log()?.error('http: erro fora de um handler', { err: error });\n return c.text('Internal Server Error', 500);\n });\n return app;\n }\n}\n\nfunction mount(app: Hono, entry: RouteEntry, upgradeWebSocket: typeof UpgradeWebSocket): void {\n const base = entry.base();\n const path = entry.path === '/' ? base : base + entry.path;\n const info = (c: Context): HttpRequestInfo => ({ params: c.req.param() });\n const { target } = entry;\n if (typeof target === 'function') {\n app.on(entry.method, path, async (c) => {\n try {\n const response = await target(c.req.raw, info(c));\n if (response instanceof Response) return response;\n throw new TypeError(`o handler de ${entry.method} ${entry.path} não devolveu um Response`);\n } catch (error) {\n entry.onError(error);\n return c.text('Internal Server Error', 500);\n }\n });\n return;\n }\n app.get(path, async (c, next) => {\n if (c.req.header('upgrade')?.toLowerCase() !== 'websocket') {\n return c.text('Upgrade Required', 426);\n }\n let decided: HttpSocketHandlers | Response;\n try {\n decided = await target.ws(c.req.raw, info(c));\n } catch (error) {\n entry.onError(error);\n return c.text('Internal Server Error', 500);\n }\n if (decided instanceof Response) return decided;\n const handlers = decided;\n const upgrade = upgradeWebSocket(() => socketEvents(entry, handlers), {\n onError: (error) => entry.onError(error),\n });\n return (await upgrade(c, next)) ?? c.text('Internal Server Error', 500);\n });\n}\n\n/** Callbacks do Hono ligados aos do autor, com cada conexão registrada na rota. */\nfunction socketEvents(entry: RouteEntry, handlers: HttpSocketHandlers): WSEvents {\n let socket: HttpSocket | undefined;\n const wrap = (ws: WSContext): HttpSocket => {\n socket ??= {\n // O `ws` do Node aceita qualquer `Uint8Array` (Buffer incluso); o tipo do Hono pede o de\n // `ArrayBuffer` só.\n send: (data) => ws.send(data as string | ArrayBuffer),\n close: (code, reason) => ws.close(code, reason),\n };\n return socket;\n };\n const run = (callback: () => void | Promise<void>): void => {\n try {\n Promise.resolve(callback()).catch(entry.onError);\n } catch (error) {\n entry.onError(error);\n }\n };\n return {\n onOpen(_event, ws) {\n entry.sockets.add(ws);\n run(() => handlers.onOpen?.(wrap(ws)));\n },\n onMessage(event, ws) {\n run(() => handlers.onMessage?.(wrap(ws), event.data as string | ArrayBuffer));\n },\n onClose(event, ws) {\n entry.sockets.delete(ws);\n run(() => handlers.onClose?.(wrap(ws), event.code, event.reason));\n },\n };\n}\n\nfunction closeSockets(entry: RouteEntry): void {\n for (const ws of entry.sockets) ws.close(GOING_AWAY, 'rota removida');\n entry.sockets.clear();\n}\n","// Logger que resolve o destino a cada linha (M1-21). O `createBot` entrega um logger à fábrica\n// do transport antes de existir o logger real, que só nasce no `start()` (criá-lo antes seria\n// efeito colateral, ADR 0004). Este repassa cada chamada ao logger que valer no momento.\n\nimport type { LogFields, Logger, LogLevel } from './types.ts';\n\n/** Logger que delega cada chamada a `resolve()`; `child` acumula os bindings sobre o destino. */\nexport function createDeferredLogger(resolve: () => Logger): Logger {\n return {\n get level(): LogLevel {\n return resolve().level;\n },\n trace: (message, fields) => resolve().trace(message, fields),\n debug: (message, fields) => resolve().debug(message, fields),\n info: (message, fields) => resolve().info(message, fields),\n warn: (message, fields) => resolve().warn(message, fields),\n error: (message, fields) => resolve().error(message, fields),\n fatal: (message, fields) => resolve().fatal(message, fields),\n child: (bindings) => createDeferredLogger(childOf(resolve, bindings)),\n };\n}\n\n/** Filho do destino atual, recriado só quando o destino muda: não aloca um logger por linha. */\nfunction childOf(resolve: () => Logger, bindings: LogFields): () => Logger {\n let parent: Logger | undefined;\n let child: Logger | undefined;\n return () => {\n const current = resolve();\n if (current !== parent || child === undefined) {\n parent = current;\n child = current.child(bindings);\n }\n return child;\n };\n}\n","// Fonte viva de segredos para o logger. A lista fixa de `createLogger({ secrets })` não basta\n// para a config de plugin: ela é resolvida depois que o logger existe e muda no reload. Quem\n// cria o bot compartilha um `SecretSet` entre o logger e a config; o logger relê os valores só\n// quando `version` muda, então o custo por linha é uma comparação de número.\n\n/** O que o logger consulta: os valores atuais e um contador que muda junto com eles. */\nexport interface SecretSource {\n /** Muda sempre que o conjunto de valores muda. */\n readonly version: number;\n values(): readonly string[];\n}\n\n/** Segredos agrupados por dono (ex.: `plugin:ai`), para trocar os de um sem tocar nos outros. */\nexport interface SecretSet extends SecretSource {\n /** Substitui os segredos do dono. Lista vazia equivale a `delete`. */\n set(owner: string, values: readonly string[]): void;\n delete(owner: string): void;\n}\n\nexport function createSecretSet(): SecretSet {\n const byOwner = new Map<string, readonly string[]>();\n let version = 0;\n let cached: readonly string[] | undefined;\n\n const changed = (): void => {\n version += 1;\n cached = undefined;\n };\n\n return {\n get version(): number {\n return version;\n },\n values(): readonly string[] {\n cached ??= [...new Set([...byOwner.values()].flat())];\n return cached;\n },\n set(owner: string, values: readonly string[]): void {\n const kept = values.filter((value) => value.length > 0);\n if (kept.length === 0) {\n if (byOwner.delete(owner)) changed();\n return;\n }\n byOwner.set(owner, [...kept]);\n changed();\n },\n delete(owner: string): void {\n if (byOwner.delete(owner)) changed();\n },\n };\n}\n","import type { MessageContext } from '#context.ts';\nimport type { Chat } from '#message/types.ts';\nimport type { Middleware } from './pipeline.ts';\n\nexport interface ChatFilterOptions {\n /**\n * Se informado, só esses chats passam. Vale o ID do chat ou o do espaço (`parentId`): liberar\n * um servidor libera todos os canais dele.\n */\n readonly allow?: Iterable<string>;\n /**\n * Chats que nunca passam, pelo ID do chat ou do espaço. Vence a `allow`: um canal bloqueado\n * fica de fora mesmo com o servidor dele liberado.\n */\n readonly block?: Iterable<string>;\n}\n\n/** Allow/blocklist de chats (ADR 0024). As listas são copiadas na criação. */\nexport function chatFilter(options: ChatFilterOptions): Middleware<MessageContext> {\n const allowed = chatAllowed(options);\n return (ctx, next) => (allowed(ctx.message.chat) ? next() : undefined);\n}\n\n/**\n * A regra do `chatFilter` sem o middleware: o bot a aplica também aos eventos que não são\n * mensagem (ADR 0038). As listas são copiadas na criação.\n */\nexport function chatAllowed(\n options: ChatFilterOptions,\n): (chat: Pick<Chat, 'id' | 'parentId'>) => boolean {\n const allow = options.allow === undefined ? null : new Set(options.allow);\n const block = new Set(options.block);\n return ({ id, parentId }) => {\n const inParent = (list: Set<string>) => parentId !== undefined && list.has(parentId);\n if (block.has(id) || inParent(block)) return false;\n return allow === null || allow.has(id) || inParent(allow);\n };\n}\n","import type { MessageContext } from '#context.ts';\nimport type { Middleware } from './pipeline.ts';\n\n/**\n * Descarta mensagens de outros bots (`sender.isBot`): no Discord e no Telegram, dois bots que\n * respondem um ao outro entram em loop (ADR 0057). Remetente sem `isBot` conta como pessoa.\n */\nexport function ignoreBots(): Middleware<MessageContext> {\n return (ctx, next) => (ctx.message.sender.isBot === true ? undefined : next());\n}\n","import type { MessageContext } from '#context.ts';\nimport type { Middleware } from './pipeline.ts';\n\n/** Descarta mensagens enviadas pela própria sessão do bot, evitando que ele responda a si mesmo. */\nexport function ignoreSelf(): Middleware<MessageContext> {\n return (ctx, next) => (ctx.message.fromMe ? undefined : next());\n}\n","import type { MessageContext } from '#context.ts';\nimport { isThenable } from '#deadline.ts';\n\n/** Avança para o próximo middleware (ou para o fim do pipeline). Chamar duas vezes é erro. */\nexport type Next = () => Promise<void>;\n\n/**\n * Estágio do pipeline em onion (estilo Koa). Para interromper, não chame `next()`. O código\n * depois de `await next()` roda na volta, depois dos middlewares internos.\n */\nexport type Middleware<C extends MessageContext = MessageContext> = (ctx: C, next: Next) => unknown;\n\nexport interface MiddlewareOptions {\n /** Maior prioridade roda antes (mais por fora). Empate: ordem de registro. Padrão `0`. */\n readonly priority?: number;\n}\n\nexport interface MiddlewarePipelineOptions {\n /**\n * Prazo de cada middleware, contado só no tempo dele: o que passa dentro do `next()` (os\n * middlewares internos, comando e listeners) não conta, porque cada um tem o próprio prazo.\n * Sem ele, middleware não tem prazo.\n */\n readonly timeoutMs?: number;\n /** Rejeição de um middleware que já estourou o prazo (o `run` já rejeitou por ele). */\n readonly onLateError?: (error: unknown) => void;\n}\n\n/** Um middleware estourou o prazo. A mensagem é descartada (o `run` rejeita com este erro). */\nexport class MiddlewareTimeoutError extends Error {\n override readonly name = 'MiddlewareTimeoutError';\n readonly timeoutMs: number;\n\n constructor(timeoutMs: number) {\n super(`middleware excedeu ${timeoutMs} ms`);\n this.timeoutMs = timeoutMs;\n }\n}\n\n/** O pipeline foi encerrado (`close`) com o middleware ainda em andamento. */\nexport class MiddlewareAbandonedError extends Error {\n override readonly name = 'MiddlewareAbandonedError';\n\n constructor() {\n super('middleware abandonado: o pipeline foi encerrado');\n }\n}\n\ninterface Entry<C extends MessageContext> {\n readonly middleware: Middleware<C>;\n readonly priority: number;\n}\n\nconst RESOLVED: Promise<void> = Promise.resolve();\nconst NOOP = (): void => undefined;\n\n/**\n * Primeiro estágio do fluxo de mensagem (ADR 0012). A ordem é calculada em `use`/remoção,\n * não a cada mensagem: `run` só percorre um array pronto.\n */\nexport class MiddlewarePipeline<C extends MessageContext = MessageContext> {\n #entries: Entry<C>[] = [];\n #chain: readonly Middleware<C>[] = [];\n readonly #timeoutMs: number | undefined;\n readonly #onLateError: (error: unknown) => void;\n // Abandono dos estágios com timer armado, para o `close` não deixar timer vivo.\n readonly #active = new Set<() => void>();\n\n constructor(options: MiddlewarePipelineOptions = {}) {\n const { timeoutMs } = options;\n // setTimeout trata Infinity/NaN como 1 ms: todo middleware assíncrono estouraria na hora.\n if (timeoutMs !== undefined && (!Number.isFinite(timeoutMs) || timeoutMs <= 0)) {\n throw new RangeError(`Prazo inválido: ${timeoutMs}`);\n }\n this.#timeoutMs = timeoutMs;\n this.#onLateError = options.onLateError ?? NOOP;\n }\n\n /** Registra um middleware; devolve a função que o remove (idempotente). */\n use(middleware: Middleware<C>, options: MiddlewareOptions = {}): () => void {\n const priority = options.priority ?? 0;\n // NaN quebraria a comparação do sort e embaralharia a cadeia inteira.\n if (!Number.isFinite(priority)) throw new RangeError(`Prioridade inválida: ${priority}`);\n const entry: Entry<C> = { middleware, priority };\n this.#entries.push(entry);\n this.#rebuild();\n return () => {\n const index = this.#entries.indexOf(entry);\n if (index === -1) return;\n this.#entries.splice(index, 1);\n this.#rebuild();\n };\n }\n\n get size(): number {\n return this.#chain.length;\n }\n\n /**\n * Passa o contexto pela cadeia. Resolve `true` se a mensagem atravessou até o fim (todos\n * chamaram `next()`) e `false` se algum middleware a interrompeu. Erros de middleware\n * rejeitam a promise: o destino deles é de quem executa o pipeline.\n *\n * `terminal` é o estágio mais interno: roda quando o último middleware chama `next()`, e a\n * volta da cebola espera por ele. É onde o kernel põe comando e listeners (ADR 0012).\n *\n * Com `timeoutMs`, um middleware que estoura o prazo rejeita o `run` com\n * `MiddlewareTimeoutError`, e a mensagem para ali: um `next()` chamado depois disso rejeita\n * com o mesmo erro, sem rodar o resto da cadeia.\n */\n run(ctx: C, terminal?: (ctx: C) => Promise<void>): Promise<boolean> {\n // Snapshot: registrar/remover durante a execução não afeta a mensagem em andamento.\n const chain = this.#chain;\n const length = chain.length;\n if (length === 0) {\n return terminal === undefined ? Promise.resolve(true) : terminal(ctx).then(() => true);\n }\n\n let index = -1;\n let completed = false;\n let expired: MiddlewareTimeoutError | undefined;\n const expire = (error: MiddlewareTimeoutError): void => {\n expired = error;\n };\n const dispatch = (i: number): Promise<void> => {\n if (expired !== undefined) return Promise.reject(expired);\n if (i <= index) return Promise.reject(new Error('next() chamado mais de uma vez'));\n index = i;\n if (i === length) {\n completed = true;\n return terminal === undefined ? RESOLVED : terminal(ctx);\n }\n // biome-ignore lint/style/noNonNullAssertion: 0 <= i < length\n const middleware = chain[i]!;\n const next = (): Promise<void> => dispatch(i + 1);\n if (this.#timeoutMs !== undefined) return this.#timed(middleware, ctx, next, expire);\n try {\n // O valor devolvido pelo middleware é ignorado; o cast evita um `.then` por estágio.\n return Promise.resolve(middleware(ctx, next)) as Promise<void>;\n } catch (error) {\n // Middleware síncrono que lança vira rejeição, como no caso assíncrono.\n return Promise.reject(error);\n }\n };\n return dispatch(0).then(() => completed);\n }\n\n /**\n * Abandona os middlewares ainda em andamento (rejeitam com `MiddlewareAbandonedError`) e\n * desarma os timers deles. É o fim do shutdown: depois dele nenhum timer do pipeline fica vivo.\n */\n close(): void {\n for (const abandon of [...this.#active]) abandon();\n }\n\n /**\n * Roda um estágio com prazo. O relógio só corre fora do `next()`: para ao chamá-lo e volta,\n * com o que sobrou, quando ele termina. Middleware síncrono, ou que só devolve o `next()`,\n * não arma timer: o caminho quente não paga nada (plano §7).\n */\n #timed(\n middleware: Middleware<C>,\n ctx: C,\n next: () => Promise<void>,\n expire: (error: MiddlewareTimeoutError) => void,\n ): Promise<void> {\n // biome-ignore lint/style/noNonNullAssertion: só é chamado com prazo\n const timeoutMs = this.#timeoutMs!;\n let settled = false;\n let async = false;\n let inside = false;\n let lastNext: Promise<void> | undefined;\n let remaining = timeoutMs;\n let startedAt = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let fail: (error: unknown) => void = NOOP;\n\n const pause = (): void => {\n if (timer === undefined) return;\n clearTimeout(timer);\n timer = undefined;\n remaining -= performance.now() - startedAt;\n };\n const finish = (): void => {\n settled = true;\n pause();\n this.#active.delete(abandon);\n };\n const resume = (): void => {\n startedAt = performance.now();\n timer = setTimeout(\n () => {\n timer = undefined;\n const error = new MiddlewareTimeoutError(timeoutMs);\n expire(error);\n finish();\n fail(error);\n },\n Math.max(0, remaining),\n );\n };\n const abandon = (): void => {\n if (settled) return;\n finish();\n fail(new MiddlewareAbandonedError());\n };\n const back = (): void => {\n inside = false;\n if (async && !settled) resume();\n };\n const timedNext = (): Promise<void> => {\n const pending = next();\n if (settled) return pending;\n pause();\n inside = true;\n lastNext = pending;\n // `back` não lança: esta derivada nunca rejeita. O erro do `next()` é de quem o chamou.\n pending.then(back, back);\n return pending;\n };\n\n let result: unknown;\n try {\n result = middleware(ctx, timedNext);\n } catch (error) {\n settled = true;\n return Promise.reject(error);\n }\n // Síncrono, ou devolveu o próprio `next()`: não sobra tempo do middleware para medir.\n if (!isThenable(result) || result === lastNext) {\n settled = true;\n return Promise.resolve(result) as Promise<void>;\n }\n async = true;\n if (!inside) resume();\n this.#active.add(abandon);\n const promise = result;\n return new Promise<void>((resolve, reject) => {\n fail = reject;\n promise.then(\n () => {\n if (settled) return;\n finish();\n resolve();\n },\n (error: unknown) => {\n if (settled) {\n this.#onLateError(error);\n return;\n }\n finish();\n reject(error);\n },\n );\n });\n }\n\n #rebuild(): void {\n // Maior prioridade primeiro. O sort é estável e a entrada nova chega no fim do array já\n // ordenado, então o empate preserva a ordem de registro.\n this.#entries.sort((a, b) => b.priority - a.priority);\n this.#chain = this.#entries.map((entry) => entry.middleware);\n }\n}\n","import type { MessageContext } from '#context.ts';\nimport type { Middleware } from './pipeline.ts';\n\nexport interface RateLimiterOptions {\n /** Máximo de ocorrências por chave dentro de uma janela. */\n readonly max: number;\n /** Duração da janela fixa, em ms. */\n readonly windowMs: number;\n /** Relógio em ms. Padrão `performance.now` (monotônico: não volta com ajuste de hora). */\n readonly clock?: () => number;\n}\n\ninterface Window {\n readonly start: number;\n count: number;\n}\n\n/**\n * Contador de janela fixa por chave. As janelas vencidas são removidas a cada `hit`, então a\n * memória fica limitada às chaves ativas na última janela — o `rateLimiter` do LumaBot nunca\n * limpava o `Map` e crescia com cada contato visto (débito #7 do plano).\n */\nexport class RateLimiter {\n readonly #max: number;\n readonly #windowMs: number;\n readonly #clock: () => number;\n // Ordem de inserção = ordem de início da janela: uma janela vencida sai do Map antes de a\n // chave abrir outra, então a varredura para na primeira janela ainda válida.\n readonly #windows = new Map<string, Window>();\n\n constructor(options: RateLimiterOptions) {\n if (!Number.isInteger(options.max) || options.max < 1) {\n throw new RangeError(`max deve ser um inteiro >= 1: ${options.max}`);\n }\n if (!(options.windowMs > 0)) {\n throw new RangeError(`windowMs deve ser > 0: ${options.windowMs}`);\n }\n this.#max = options.max;\n this.#windowMs = options.windowMs;\n this.#clock = options.clock ?? (() => performance.now());\n }\n\n /** Conta uma ocorrência da chave; `false` se ela estourou o limite da janela atual. */\n hit(key: string): boolean {\n const now = this.#clock();\n this.#sweep(now);\n const window = this.#windows.get(key);\n if (window === undefined) {\n this.#windows.set(key, { start: now, count: 1 });\n return true;\n }\n window.count++;\n return window.count <= this.#max;\n }\n\n /** Chaves com janela aberta. */\n get size(): number {\n return this.#windows.size;\n }\n\n #sweep(now: number): void {\n for (const [key, window] of this.#windows) {\n if (now - window.start < this.#windowMs) return;\n this.#windows.delete(key);\n }\n }\n}\n\n/** Por quem a mensagem é contada: remetente (em qualquer chat), chat, ou remetente em cada chat. */\nexport type RateLimitScope = 'sender' | 'chat' | 'sender-in-chat';\n\nexport interface RateLimitOptions extends RateLimiterOptions {\n /** Padrão `'sender'`. */\n readonly by?: RateLimitScope;\n /** Chamado quando uma mensagem é barrada (ex.: para registrar). Erro aqui propaga ao pipeline. */\n readonly onLimited?: (ctx: MessageContext) => void;\n}\n\nconst KEYS: Record<RateLimitScope, (ctx: MessageContext) => string> = {\n sender: (ctx) => ctx.message.sender.id,\n chat: (ctx) => ctx.message.chat.id,\n // NUL não aparece em IDs de transport, então não há colisão entre pares diferentes.\n 'sender-in-chat': (ctx) => `${ctx.message.chat.id}\\u0000${ctx.message.sender.id}`,\n};\n\n/** Rate limit de entrada: barra a mensagem quando a chave estoura `max` dentro da janela. */\nexport function rateLimit(options: RateLimitOptions): Middleware<MessageContext> {\n const limiter = new RateLimiter(options);\n const keyOf = KEYS[options.by ?? 'sender'];\n const onLimited = options.onLimited;\n return (ctx, next) => {\n if (limiter.hit(keyOf(ctx))) return next();\n onLimited?.(ctx);\n return undefined;\n };\n}\n","import type { MessageContext } from '#context.ts';\nimport type { Middleware } from './pipeline.ts';\n\n/** Campos do remetente/texto já limitados pelo middleware `sanitize`. */\nexport interface SanitizedFields {\n readonly text: string | null;\n readonly senderName: string | null;\n}\n\n/**\n * Contexto com o resultado de `sanitize`. `ctx.message` é imutável (contrato compartilhado),\n * então o texto limpo fica ao lado dele: em `ctx.text`, o texto de trabalho que o roteador e os\n * listeners leem (M1-16.2), e em `sanitized`, junto do nome do remetente. Sem o middleware,\n * `sanitized` fica ausente.\n */\nexport interface SanitizedContext extends MessageContext {\n sanitized?: SanitizedFields;\n}\n\nexport interface SanitizeOptions {\n /** Padrão `4096`, o limite do LumaBot. */\n readonly maxTextLength?: number;\n /** Padrão `100`. */\n readonly maxSenderNameLength?: number;\n}\n\n/**\n * Trunca texto/legenda e nome do remetente: um texto gigante custa CPU em todo estágio\n * seguinte (parse de comando, regex de listeners, prompt de IA) e um nome gigante polui logs.\n */\nexport function sanitize(options: SanitizeOptions = {}): Middleware<SanitizedContext> {\n const maxText = options.maxTextLength ?? 4096;\n const maxName = options.maxSenderNameLength ?? 100;\n for (const [name, value] of [\n ['maxTextLength', maxText],\n ['maxSenderNameLength', maxName],\n ] as const) {\n if (!Number.isInteger(value) || value < 1) {\n throw new RangeError(`${name} deve ser um inteiro >= 1: ${value}`);\n }\n }\n return (ctx, next) => {\n const { message } = ctx;\n // Trunca o texto de trabalho, não o original: um middleware anterior pode tê-lo reescrito.\n const text = truncate(ctx.text === undefined ? message.text : ctx.text, maxText);\n ctx.text = text;\n ctx.sanitized = { text, senderName: truncate(message.sender.name, maxName) };\n return next();\n };\n}\n\nfunction truncate(value: string | null, max: number): string | null {\n if (value === null || value.length <= max) return value;\n // Não corta um par surrogate ao meio (emoji etc.): sobraria um caractere inválido.\n const code = value.charCodeAt(max - 1);\n const end = code >= 0xd800 && code <= 0xdbff ? max - 1 : max;\n return value.slice(0, end);\n}\n","// Divisão de texto longo em partes que cabem no limite do transport (ADR 0061). Corta num\n// parágrafo, depois numa linha, num espaço e, por último, num caractere; um nó partido continua\n// formatado nas duas partes.\n\nimport { formatted, type MessageText, type TextNode } from './format.ts';\n\ntype Wrapper = Extract<TextNode, { readonly children: readonly TextNode[] }>;\ntype Leaf = Extract<TextNode, { readonly type: 'code' | 'mention' }>;\n\n/** Trecho achatado: texto (de string ou de `code`) ou menção, com os estilos que o envolvem. */\ninterface Segment {\n /** Estilos e links de fora para dentro; a identidade do nó junta os pedaços de volta. */\n readonly wrap: readonly Wrapper[];\n /** Vazio na menção, que nunca é cortada. */\n readonly text: string;\n /** O `code` de origem ou a menção; `null` no texto literal. */\n readonly leaf: Leaf | null;\n}\n\nexport interface SplitLimits {\n /** Limite da primeira parte (a legenda, quando a primeira parte é a mídia). */\n readonly first: number;\n /** Limite das outras partes. */\n readonly rest: number;\n}\n\nconst SEPARATORS = ['\\n\\n', '\\n', ' ', ''] as const;\n\n/**\n * Divide `text` em partes com `measure(parte)` dentro do limite. Um texto que cabe volta sozinho,\n * sem cópia. Um caractere ou uma menção maior que o limite sai sozinho numa parte: não há como\n * cortar menos, e o transport rejeita.\n */\nexport function splitText(\n text: MessageText,\n limits: SplitLimits,\n measure: (text: MessageText) => number,\n): MessageText[] {\n if (measure(text) <= limits.first) return [text];\n const raw = typeof text === 'string';\n const build = (segments: readonly Segment[]): MessageText =>\n raw ? segments.map((s) => s.text).join('') : formatted(rebuild(segments, 0));\n const chunks: Segment[][] = [];\n // Mede a parte já sem o espaço das pontas, como ela sai: o separador fica no fim do pedaço.\n const fits = (segments: readonly Segment[]): boolean =>\n measure(build(trim(segments))) <= (chunks.length === 0 ? limits.first : limits.rest);\n\n const pack = (segments: readonly Segment[], level: number): void => {\n const pieces = cut(segments, SEPARATORS[level] ?? '');\n let i = 0;\n while (i < pieces.length) {\n if (!fits(pieces[i] ?? [])) {\n if (level < SEPARATORS.length - 1) pack(pieces[i] ?? [], level + 1);\n else chunks.push(pieces[i] ?? []);\n i++;\n continue;\n }\n // Busca galopante: dobra até não caber e refina por bisseção. Cada medida custa no máximo\n // o dobro do limite, e o total fica em O(n log n).\n let ok = 1;\n let bad = 2;\n while (i + bad <= pieces.length && fits(join(pieces, i, bad))) {\n ok = bad;\n bad *= 2;\n }\n bad = Math.min(bad, pieces.length - i + 1);\n while (bad - ok > 1) {\n const mid = (ok + bad) >> 1;\n if (fits(join(pieces, i, mid))) ok = mid;\n else bad = mid;\n }\n chunks.push(join(pieces, i, ok));\n i += ok;\n }\n };\n pack(flatten(text), 0);\n\n const out: MessageText[] = [];\n for (const chunk of chunks) {\n const trimmed = trim(chunk);\n if (trimmed.length > 0) out.push(build(trimmed));\n }\n return out;\n}\n\nfunction join(pieces: readonly Segment[][], start: number, count: number): Segment[] {\n return pieces.slice(start, start + count).flat();\n}\n\nfunction flatten(text: MessageText): Segment[] {\n if (typeof text === 'string') return [{ wrap: [], text, leaf: null }];\n const out: Segment[] = [];\n const walk = (nodes: readonly TextNode[], wrap: readonly Wrapper[]): void => {\n for (const node of nodes) {\n if (typeof node === 'string') out.push({ wrap, text: node, leaf: null });\n else if (node.type === 'code') out.push({ wrap, text: node.text, leaf: node });\n else if (node.type === 'mention') out.push({ wrap, text: '', leaf: node });\n else walk(node.children, [...wrap, node]);\n }\n };\n walk(text.nodes, []);\n return out;\n}\n\n/** Corta logo depois de cada `separator` (ou entre code points, com `''`); a menção não corta. */\nfunction cut(segments: readonly Segment[], separator: string): Segment[][] {\n const pieces: Segment[][] = [];\n let current: Segment[] = [];\n for (const segment of segments) {\n if (segment.leaf?.type === 'mention') {\n current.push(segment);\n continue;\n }\n let start = 0;\n for (const end of cutPoints(segment.text, separator)) {\n current.push({ ...segment, text: segment.text.slice(start, end) });\n pieces.push(current);\n current = [];\n start = end;\n }\n if (start < segment.text.length) current.push({ ...segment, text: segment.text.slice(start) });\n }\n if (current.length > 0) pieces.push(current);\n return pieces;\n}\n\nfunction* cutPoints(text: string, separator: string): Generator<number> {\n if (separator === '') {\n // Por code point: partir um par surrogate deixaria um caractere inválido em cada parte.\n let index = 0;\n for (const char of text) {\n index += char.length;\n yield index;\n }\n return;\n }\n // Inclusive no fim do trecho: o separador pode ser o último caractere antes de um estilo.\n for (let at = text.indexOf(separator); at !== -1; at = text.indexOf(separator, at)) {\n at += separator.length;\n yield at;\n }\n}\n\n/** Tira o espaço em branco das pontas da parte (fora de `code`) e os trechos que ficam vazios. */\nfunction trim(chunk: readonly Segment[]): Segment[] {\n const out = [...chunk];\n const edge = (index: number, re: RegExp): void => {\n const segment = out[index];\n if (segment === undefined || segment.leaf !== null) return;\n out[index] = { ...segment, text: segment.text.replace(re, '') };\n };\n while (out.length > 0) {\n edge(0, /^\\s+/);\n if (out[0]?.leaf === null && out[0].text === '') out.shift();\n else break;\n }\n while (out.length > 0) {\n edge(out.length - 1, /\\s+$/);\n if (out.at(-1)?.leaf === null && out.at(-1)?.text === '') out.pop();\n else break;\n }\n return out;\n}\n\n/** Remonta a árvore: trechos seguidos com o mesmo nó de estilo voltam para um nó só. */\nfunction rebuild(segments: readonly Segment[], depth: number): TextNode[] {\n const out: TextNode[] = [];\n let i = 0;\n while (i < segments.length) {\n const segment = segments[i] as Segment;\n const wrapper = segment.wrap[depth];\n if (wrapper !== undefined) {\n let j = i + 1;\n while (j < segments.length && segments[j]?.wrap[depth] === wrapper) j++;\n const children = rebuild(segments.slice(i, j), depth + 1);\n out.push(\n Object.freeze(\n wrapper.type === 'link'\n ? { type: 'link', url: wrapper.url, children: Object.freeze(children) }\n : { type: wrapper.type, children: Object.freeze(children) },\n ),\n );\n i = j;\n continue;\n }\n const { leaf } = segment;\n if (leaf?.type === 'mention') {\n out.push(leaf);\n i++;\n continue;\n }\n let j = i + 1;\n let text = segment.text;\n while (\n j < segments.length &&\n segments[j]?.wrap.length === depth &&\n segments[j]?.leaf === leaf\n ) {\n text += segments[j]?.text ?? '';\n j++;\n }\n if (text !== '') out.push(leaf === null ? text : Object.freeze({ type: 'code', text }));\n i = j;\n }\n return out;\n}\n","// Texto do envio (ADR 0061): a árvore neutra vira o par `text` visível + `formatted`, e o texto\n// acima do limite do transport vira várias partes, antes de entrar na fila de saída.\n\nimport { type FormattedText, isFormatted, type MessageText, plainText } from '#text/format.ts';\nimport { splitText } from '#text/split.ts';\nimport type { OutgoingContent, SendOptions, TextLimits, Transport } from '#transport/types.ts';\n\n/** Uma parte do envio: o conteúdo e as opções com que vai ao transport. */\nexport interface SendPart {\n readonly content: OutgoingContent;\n readonly options: SendOptions | undefined;\n}\n\n/** Conteúdo de texto com o `text` visível e, para a árvore, o `formatted`. */\nexport function textContent(text: MessageText): OutgoingContent {\n return typeof text === 'string'\n ? { type: 'text', text }\n : { type: 'text', text: plainText(text), formatted: text };\n}\n\n/** Campos da legenda no conteúdo, ou nada, para não mandar `undefined` explícito ao transport. */\nexport function captionFields(caption: MessageText | undefined): {\n caption?: string;\n formattedCaption?: FormattedText;\n} {\n if (caption === undefined) return {};\n return typeof caption === 'string'\n ? { caption }\n : { caption: plainText(caption), formattedCaption: caption };\n}\n\n/** O que o `send` aceita: o conteúdo ou, como atalho, só o texto. */\nexport function toContent(input: OutgoingContent | MessageText): OutgoingContent {\n if (typeof input === 'string' || isFormatted(input)) return textContent(input);\n // O texto visível sai sempre da árvore: o transport que não a conhece envia o mesmo texto.\n if (input.type === 'text' && input.formatted !== undefined) return textContent(input.formatted);\n if ('formattedCaption' in input && input.formattedCaption !== undefined) {\n return { ...input, caption: plainText(input.formattedCaption) };\n }\n return input;\n}\n\nfunction measureVisible(text: MessageText): number {\n return typeof text === 'string' ? text.length : plainText(text).length;\n}\n\n/** O limite do transport validado; ausente vira `Infinity`. */\nexport function positiveLimit(name: string, value: number | undefined): number {\n if (value === undefined) return Number.POSITIVE_INFINITY;\n if (!(Number.isInteger(value) && value >= 1)) {\n throw new RangeError(`limits.${name} do transport deve ser inteiro >= 1 (recebido: ${value})`);\n }\n return value;\n}\n\n/** Os limites do transport, validados uma vez: são fixos na vida da instância. */\nexport class TextLimiter {\n readonly #text: number;\n readonly #caption: number;\n readonly #measure: (text: MessageText) => number;\n /** Sem limite nenhum, o envio passa direto, sem medir. */\n readonly #unlimited: boolean;\n\n constructor(transport: Pick<Transport, 'limits'>) {\n const limits: TextLimits = transport.limits ?? {};\n this.#text = positiveLimit('text', limits.text);\n this.#caption = positiveLimit('caption', limits.caption);\n const custom = limits.measure;\n this.#measure = custom === undefined ? measureVisible : (text) => custom.call(limits, text);\n this.#unlimited =\n this.#text === Number.POSITIVE_INFINITY && this.#caption === Number.POSITIVE_INFINITY;\n }\n\n /**\n * As partes do envio, na ordem. Só a primeira cita a mensagem, e só a última leva os botões; as\n * menções vão em todas. Uma legenda longa fica com o começo na mídia, e o resto vira texto.\n */\n split(content: OutgoingContent, options: SendOptions | undefined): SendPart[] {\n if (this.#unlimited) return [{ content, options }];\n let first: OutgoingContent;\n let rest: MessageText[];\n if (content.type === 'text') {\n const parts = this.#split(content.formatted ?? content.text, this.#text);\n if (parts.length <= 1) return [{ content, options }];\n first = textContent(parts[0] as MessageText);\n rest = parts.slice(1);\n } else if (\n (content.type === 'image' ||\n content.type === 'video' ||\n content.type === 'document' ||\n content.type === 'album') &&\n content.caption !== undefined\n ) {\n const parts = this.#split(content.formattedCaption ?? content.caption, this.#caption);\n if (parts.length <= 1) return [{ content, options }];\n const { caption: _caption, formattedCaption: _formatted, ...media } = content;\n first = { ...media, ...captionFields(parts[0]) };\n rest = parts.slice(1);\n } else {\n return [{ content, options }];\n }\n let firstOptions = options;\n let restOptions: SendOptions | undefined;\n let lastOptions: SendOptions | undefined;\n if (options !== undefined) {\n // Os botões vão onde a leitura termina, na última parte (ADR 0062).\n const { quoted: _quoted, actions, ...others } = options;\n restOptions = others;\n lastOptions = actions === undefined ? others : { ...others, actions };\n if (actions !== undefined) {\n const { actions: _actions, ...withoutActions } = options;\n firstOptions = withoutActions;\n }\n }\n const last = rest.length - 1;\n return [\n { content: first, options: firstOptions },\n ...rest.map((text, index) => ({\n content: textContent(text),\n options: index === last ? lastOptions : restOptions,\n })),\n ];\n }\n\n /** Afirma que o texto da edição cabe; a edição não se divide. */\n assertEditFits(text: MessageText): void {\n if (this.#text === Number.POSITIVE_INFINITY) return;\n const size = this.#measure(text);\n if (size > this.#text) {\n throw new RangeError(\n `texto da edição com ${size} caracteres passa do limite do transport (${this.#text})`,\n );\n }\n }\n\n #split(text: MessageText, limit: number): MessageText[] {\n if (limit === Number.POSITIVE_INFINITY) return [text];\n // A primeira parte de uma legenda segue o limite da legenda; as outras viram texto.\n const rest = Number.isFinite(this.#text) ? this.#text : limit;\n return splitText(text, { first: limit, rest }, this.#measure);\n }\n}\n","// `ctx.send` (ADR 0040): o envio e as ações sobre mensagens e chats, todos pela fila de saída. A\n// fila não conhece as ações; aqui cada uma confere a capability e vira uma chamada enfileirada.\n\nimport { plainText } from '#text/format.ts';\nimport { assertCapability, type Capability } from '#transport/capabilities.ts';\nimport type { Transport } from '#transport/types.ts';\nimport type { OutboundQueue } from './queue.ts';\nimport { TextLimiter } from './text.ts';\nimport type { ActionOptions, Outbound } from './types.ts';\n\n/** O que as ações usam do transport. */\nexport type ActionTransport = Pick<\n Transport,\n 'name' | 'capabilities' | 'react' | 'edit' | 'delete' | 'sendTyping' | 'limits'\n>;\n\n/** Enfileira `run` no chat se o transport tem a capability; sem ela, rejeita já. */\nexport type EnqueueAction = (\n capability: Capability,\n chatId: string,\n run: () => Promise<void>,\n options?: ActionOptions,\n) => Promise<void>;\n\nexport function enqueueAction(\n queue: Pick<OutboundQueue, 'enqueue'>,\n transport: Pick<Transport, 'name' | 'capabilities'>,\n): EnqueueAction {\n return (capability, chatId, run, options) => {\n try {\n // Capability ausente nunca vira tentativa, como no envio.\n assertCapability(transport, capability);\n } catch (error) {\n return Promise.reject(error);\n }\n return queue.enqueue(chatId, run, options);\n };\n}\n\nexport function createOutbound(\n queue: Pick<OutboundQueue, 'send' | 'enqueue'>,\n transport: ActionTransport,\n): Outbound {\n const action = enqueueAction(queue, transport);\n const limiter = new TextLimiter(transport);\n return {\n send: (chatId, content, options) => queue.send(chatId, content, options),\n react: (key, emoji, options) =>\n action('reactions', key.chatId, () => transport.react(key, emoji), options),\n edit: (key, text, options) => {\n try {\n limiter.assertEditFits(text);\n } catch (error) {\n return Promise.reject(error);\n }\n // A árvore vai junto do texto visível, como no envio (ADR 0061).\n if (typeof text === 'string') {\n return action('message.edit', key.chatId, () => transport.edit(key, text), options);\n }\n const visible = plainText(text);\n return action('message.edit', key.chatId, () => transport.edit(key, visible, text), options);\n },\n delete: (key, options) =>\n action('message.delete', key.chatId, () => transport.delete(key), options),\n typing: (chatId, kind, options) =>\n action('typing', chatId, () => transport.sendTyping(chatId, kind), options),\n };\n}\n","// Álbum do envio (ADR 0065): com a capability `send.album`, vai em lotes de até `limits.album`\n// itens; sem ela, item a item. Roda antes da divisão da legenda (ADR 0061), na entrada da fila.\n\nimport type { OutgoingContent, SendOptions, Transport } from '#transport/types.ts';\nimport { positiveLimit, type SendPart } from './text.ts';\n\ntype AlbumContent = Extract<OutgoingContent, { readonly type: 'album' }>;\n\n/** A capability e o limite do transport, lidos uma vez: são fixos na vida da instância. */\nexport class AlbumSplitter {\n /** Itens por mensagem: `limits.album` com a capability, um sem ela. */\n readonly #size: number;\n\n constructor(transport: Pick<Transport, 'capabilities' | 'limits'>) {\n const max = positiveLimit('album', transport.limits?.album);\n this.#size = transport.capabilities.has('send.album') ? max : 1;\n }\n\n /**\n * As mensagens do álbum, na ordem, com a legenda na primeira. Um lote de um item sai como\n * mensagem comum, porque o Telegram não aceita álbum de um. As opções seguem a regra das partes\n * do texto: só a primeira cita, só a última leva os botões, as menções vão em todas. Lança\n * `TypeError` com o álbum vazio.\n */\n split(content: AlbumContent, options: SendOptions | undefined): SendPart[] {\n const { items } = content;\n if (items.length === 0) throw new TypeError('álbum sem itens');\n const contents: OutgoingContent[] = [];\n for (let start = 0; start < items.length; start += this.#size) {\n const lot = items.slice(start, start + this.#size);\n const caption = start === 0 ? captionOf(content) : {};\n contents.push(\n lot.length === 1\n ? ({ ...lot[0], ...caption } as OutgoingContent)\n : { type: 'album', items: lot, ...caption },\n );\n }\n return distribute(contents, options);\n }\n}\n\n/** Legenda do álbum, só com os campos definidos: o transport não recebe `undefined` explícito. */\nfunction captionOf(content: AlbumContent): Pick<AlbumContent, 'caption' | 'formattedCaption'> {\n return {\n ...(content.caption === undefined ? null : { caption: content.caption }),\n ...(content.formattedCaption === undefined\n ? null\n : { formattedCaption: content.formattedCaption }),\n };\n}\n\nfunction distribute(contents: OutgoingContent[], options: SendOptions | undefined): SendPart[] {\n if (options === undefined || contents.length === 1) {\n return contents.map((content) => ({ content, options }));\n }\n const { quoted, actions, ...others } = options;\n const last = contents.length - 1;\n return contents.map((content, index) => ({\n content,\n options: {\n ...others,\n ...(index === 0 && quoted !== undefined ? { quoted } : null),\n ...(index === last && actions !== undefined ? { actions } : null),\n },\n }));\n}\n","// Fila de saída anti-ban (ADR 0019). Todo envio do bot passa por aqui: intervalo mínimo global\n// e por chat, prioridade (comando > broadcast), retry com backoff (ou na janela que a plataforma\n// informou, ADR 0067) e humanização opcional.\n\nimport type { MessageText } from '#text/format.ts';\nimport { assertCanSend, hasCapability, UnsupportedError } from '#transport/capabilities.ts';\nimport type {\n MessageKey,\n OutgoingContent,\n SendOptions,\n Transport,\n TransportPacing,\n TypingKind,\n} from '#transport/types.ts';\nimport { AlbumSplitter } from './album.ts';\nimport { type SendPart, TextLimiter, toContent } from './text.ts';\nimport type { ActionOptions, OutboundSendOptions, Sender, SendPriority } from './types.ts';\n\n/** O que a fila usa do transport. */\nexport type OutboundTransport = Pick<\n Transport,\n 'name' | 'capabilities' | 'send' | 'sendTyping' | 'limits' | 'pacing'\n>;\n\nexport interface RetryOptions {\n /** Tentativas no total, contando a primeira. Padrão: 3. `1` desliga o retry. */\n readonly maxAttempts?: number;\n /** Espera antes da primeira re-tentativa, em ms; dobra a cada falha. Padrão: 1000. */\n readonly baseDelayMs?: number;\n /**\n * Teto da espera, em ms. Padrão: 30000. Um erro com `retryAfterMs` acima dele não re-tenta: a\n * resposta já sairia fora de contexto (ADR 0067).\n */\n readonly maxDelayMs?: number;\n /**\n * Decide se a falha é transitória. Padrão: tudo, exceto `UnsupportedError` e erros com\n * `retryable: false` (convenção para o transport marcar falha permanente).\n */\n readonly isRetryable?: (error: unknown) => boolean;\n}\n\nexport interface HumanizeOptions {\n /** Tempo \"digitando\" por caractere do texto, em ms. Padrão: 50. */\n readonly msPerChar?: number;\n /** Piso do tempo de \"digitando\", em ms. Padrão: 500. */\n readonly minMs?: number;\n /** Teto do tempo de \"digitando\", em ms; voz usa o teto. Padrão: 3000. */\n readonly maxMs?: number;\n}\n\nexport interface OutboundQueueOptions {\n readonly transport: OutboundTransport;\n /**\n * Intervalo mínimo entre dois envios quaisquer, em ms. Padrão: o `transport.pacing`, ou 300.\n */\n readonly globalIntervalMs?: number;\n /**\n * Intervalo mínimo entre dois envios ao mesmo chat, em ms. Padrão: o `transport.pacing`, ou\n * 1000.\n */\n readonly chatIntervalMs?: number;\n /**\n * Máximo de mensagens aguardando em cada prioridade, somando os chats. Padrão: 1000.\n * `Infinity` desliga. Por prioridade para um broadcast que encheu a fila não recusar respostas.\n */\n readonly maxPending?: number;\n readonly retry?: RetryOptions;\n /**\n * \"Digitando\" (`text`) antes de texto e \"gravando\" (`voice`) antes de voz, se o transport tiver a\n * capability `typing`. Padrão: desligada.\n */\n readonly humanize?: boolean | HumanizeOptions;\n /**\n * Destino das falhas do \"digitando\", que não impedem o envio. Sem ele, a falha é descartada:\n * o indicador é cosmético e quem chamou `send` só se importa com a mensagem.\n */\n readonly onTypingError?: (error: unknown, chatId: string) => void;\n /**\n * Quanto o que aguarda pode esperar com a fila pausada (conexão caída), em ms. Estourado, rejeita\n * com `OutboundQueueError` `'disconnected'`, e envios novos rejeitam na hora até o `resume()`.\n * Padrão: 60000 (cobre o ciclo de reconexão padrão, 5 + 10 + 15 s). `Infinity` desliga.\n */\n readonly maxPauseMs?: number;\n /**\n * Prazo de cada chamada ao transport (\"digitando\" e envio), em ms. Estourado, o envio rejeita com\n * `OutboundQueueError` `'timeout'`, sem re-tentar, e libera o chat. Padrão: 30000. `Infinity`\n * desliga.\n */\n readonly sendTimeoutMs?: number;\n /** Relógio em ms. Padrão: `performance.now` (monotônico). */\n readonly clock?: () => number;\n /** Fonte do jitter do backoff, em [0, 1). Padrão: `Math.random`. */\n readonly random?: () => number;\n}\n\nexport interface OutboundQueueStats {\n /** Mensagens aguardando, inclusive as em espera de re-tentativa. */\n readonly pending: { readonly high: number; readonly normal: number; readonly low: number };\n /** Envios em andamento (\"digitando\" + transport). */\n readonly inFlight: number;\n /** Chats com mensagem aguardando ou em andamento. */\n readonly activeChats: number;\n readonly sent: number;\n /** Envios que rejeitaram com o erro final. */\n readonly failed: number;\n readonly retries: number;\n /** Recusadas (fila cheia, fechada ou desconectada) ou descartadas sem envio. */\n readonly dropped: number;\n /** Despacho pausado pela conexão caída. */\n readonly paused: boolean;\n}\n\nexport interface OutboundCloseOptions {\n /**\n * `true` (padrão): envia tudo o que já foi aceito antes de resolver. `false`: rejeita o que\n * aguarda e só espera os envios em andamento.\n */\n readonly drain?: boolean;\n}\n\nexport type OutboundQueueErrorReason = 'full' | 'closed' | 'disconnected' | 'timeout';\n\n/**\n * Envio recusado ou abandonado pela fila: backlog cheio, fila fechada, conexão caída além de\n * `maxPauseMs` ou transport sem resposta em `sendTimeoutMs`.\n */\nexport class OutboundQueueError extends Error {\n override readonly name = 'OutboundQueueError';\n readonly reason: OutboundQueueErrorReason;\n\n constructor(reason: OutboundQueueErrorReason, message: string) {\n super(message);\n this.reason = reason;\n }\n}\n\n/** Índice nas estruturas por prioridade: 0 é a mais alta. */\ntype PriorityIndex = 0 | 1 | 2;\n\n// Map e não objeto: prioridade vinda de JS sem tipos (ex.: `'toString'`) não casa por engano.\nconst PRIORITY_INDEX: ReadonlyMap<string, PriorityIndex> = new Map<SendPriority, PriorityIndex>([\n ['high', 0],\n ['normal', 1],\n ['low', 2],\n]);\n\nconst DEFAULTS = {\n globalIntervalMs: 300,\n chatIntervalMs: 1000,\n maxPending: 1000,\n maxAttempts: 3,\n baseDelayMs: 1000,\n maxDelayMs: 30_000,\n maxPauseMs: 60_000,\n sendTimeoutMs: 30_000,\n msPerChar: 50,\n minMs: 500,\n maxMs: 3000,\n} as const;\n\n/** FIFO com remoção O(1) na frente; `Array.shift` é O(n) e o backlog pode ter milhares. */\nclass Fifo<T> {\n #items: (T | undefined)[] = [];\n #head = 0;\n\n get size(): number {\n return this.#items.length - this.#head;\n }\n\n push(item: T): void {\n this.#items.push(item);\n }\n\n peek(): T | undefined {\n return this.#items[this.#head];\n }\n\n shift(): T | undefined {\n if (this.#head >= this.#items.length) return undefined;\n const item = this.#items[this.#head];\n this.#items[this.#head] = undefined;\n this.#head++;\n if (this.#head === this.#items.length) {\n this.#items = [];\n this.#head = 0;\n } else if (this.#head >= 1024 && this.#head * 2 >= this.#items.length) {\n // Compacta só quando a parte consumida domina: custo amortizado O(1).\n this.#items = this.#items.slice(this.#head);\n this.#head = 0;\n }\n return item;\n }\n\n clear(): void {\n this.#items = [];\n this.#head = 0;\n }\n}\n\n/** Uma chamada ao transport e o conteúdo dela, para a humanização (`null` nas ações). */\ninterface JobPart {\n readonly run: () => Promise<unknown>;\n readonly content: OutgoingContent | null;\n}\n\ninterface Job extends JobPart {\n /**\n * Partes seguintes de um texto dividido (ADR 0061). Cada uma sai logo depois da anterior, na\n * frente do chat, para outro envio não se intrometer.\n */\n readonly rest: readonly JobPart[];\n /** Resultado da primeira parte, com que a última resolve; ausente até ela sair. */\n readonly first?: { readonly value: unknown };\n /** O que é a chamada, para a mensagem do prazo estourado. */\n readonly what: string;\n readonly priority: PriorityIndex;\n /** Tentativas já feitas. */\n attempts: number;\n readonly resolve: (value: unknown) => void;\n readonly reject: (error: unknown) => void;\n}\n\ninterface ChatState {\n readonly id: string;\n readonly jobs: readonly [Fifo<Job>, Fifo<Job>, Fifo<Job>];\n /**\n * Mensagem em espera de re-tentativa ou parte seguinte de um texto dividido: sai antes das\n * outras do chat, para não embaralhar.\n */\n head: Job | null;\n pending: number;\n busy: boolean;\n /** Antes disso o chat não envia (intervalo por chat ou backoff). */\n readyAt: number;\n /** Senha da entrada válida numa lista de prontos; 0 = fora das listas. */\n ticket: number;\n listedPriority: PriorityIndex | -1;\n timer: NodeJS.Timeout | undefined;\n}\n\ninterface ReadyEntry {\n readonly chat: ChatState;\n readonly ticket: number;\n}\n\n/**\n * Fila de saída de uma instância do bot. Chats diferentes enviam em paralelo, limitados só\n * pelo intervalo global; dentro do chat, uma mensagem por vez, em ordem por prioridade.\n */\nexport class OutboundQueue implements Sender {\n readonly #transport: OutboundTransport;\n readonly #text: TextLimiter;\n readonly #album: AlbumSplitter;\n readonly #globalIntervalMs: number;\n readonly #chatIntervalMs: number;\n readonly #maxPending: number;\n readonly #maxAttempts: number;\n readonly #baseDelayMs: number;\n readonly #maxDelayMs: number;\n readonly #isRetryable: (error: unknown) => boolean;\n readonly #humanize: Required<HumanizeOptions> | null;\n readonly #onTypingError: ((error: unknown, chatId: string) => void) | undefined;\n readonly #maxPauseMs: number;\n readonly #sendTimeoutMs: number;\n readonly #clock: () => number;\n readonly #random: () => number;\n\n // Só chats com mensagem aguardando ou em andamento: ao esvaziar, saem (o vazamento do\n // rateLimiter do legacy).\n readonly #chats = new Map<string, ChatState>();\n // Fim do intervalo por chat, em ordem de envio. Como o intervalo é fixo, a ordem de inserção\n // é a de vencimento e a limpeza para na primeira entrada válida.\n readonly #cooldowns = new Map<string, number>();\n // Chats prontos para enviar, um FIFO por prioridade. Remoção preguiçosa: entradas cujo\n // ticket não bate mais são descartadas ao chegar na frente.\n readonly #ready: readonly [Fifo<ReadyEntry>, Fifo<ReadyEntry>, Fifo<ReadyEntry>] = [\n new Fifo(),\n new Fifo(),\n new Fifo(),\n ];\n readonly #pendingBy: Record<PriorityIndex, number> = [0, 0, 0];\n #nextTicket = 1;\n #globalReadyAt = Number.NEGATIVE_INFINITY;\n #globalTimer: NodeJS.Timeout | undefined;\n #pumping = false;\n #idleWaiters: (() => void)[] = [];\n #closed = false;\n #discarding = false;\n #paused = false;\n // Pausada além do teto: o que chega rejeita na hora, em vez de acumular sem previsão de saída.\n #offline = false;\n #pauseTimer: NodeJS.Timeout | undefined;\n // Esperas de humanização em curso: o descarte as encerra para o envio não sair depois do close.\n readonly #sleepers = new Set<() => void>();\n #inFlight = 0;\n #sent = 0;\n #failed = 0;\n #retries = 0;\n #dropped = 0;\n\n constructor(options: OutboundQueueOptions) {\n const retry = options.retry ?? {};\n this.#transport = options.transport;\n this.#text = new TextLimiter(options.transport);\n this.#album = new AlbumSplitter(options.transport);\n // O ritmo é da plataforma (ADR 0067): a config do bot sobrescreve o do transport, e sem\n // nenhum dos dois vale o padrão anti-ban do WhatsApp (ADR 0019).\n const pacing = options.transport.pacing;\n this.#globalIntervalMs = pace('globalIntervalMs', options.globalIntervalMs, pacing);\n this.#chatIntervalMs = pace('chatIntervalMs', options.chatIntervalMs, pacing);\n const maxPending = options.maxPending ?? DEFAULTS.maxPending;\n if (\n !(\n maxPending === Number.POSITIVE_INFINITY ||\n (Number.isInteger(maxPending) && maxPending >= 0)\n )\n ) {\n throw new RangeError(\n `maxPending deve ser inteiro >= 0 ou Infinity (recebido: ${maxPending})`,\n );\n }\n this.#maxPending = maxPending;\n const maxAttempts = retry.maxAttempts ?? DEFAULTS.maxAttempts;\n if (!(Number.isInteger(maxAttempts) && maxAttempts >= 1)) {\n throw new RangeError(`retry.maxAttempts deve ser inteiro >= 1 (recebido: ${maxAttempts})`);\n }\n this.#maxAttempts = maxAttempts;\n this.#baseDelayMs = nonNegative('retry.baseDelayMs', retry.baseDelayMs ?? DEFAULTS.baseDelayMs);\n this.#maxDelayMs = nonNegative('retry.maxDelayMs', retry.maxDelayMs ?? DEFAULTS.maxDelayMs);\n this.#isRetryable = retry.isRetryable ?? isTransient;\n this.#humanize = resolveHumanize(options.humanize, options.transport);\n this.#onTypingError = options.onTypingError;\n const maxPauseMs = options.maxPauseMs ?? DEFAULTS.maxPauseMs;\n if (!(maxPauseMs >= 0)) {\n throw new RangeError(`maxPauseMs deve ser >= 0 ou Infinity (recebido: ${maxPauseMs})`);\n }\n this.#maxPauseMs = maxPauseMs;\n const sendTimeoutMs = options.sendTimeoutMs ?? DEFAULTS.sendTimeoutMs;\n if (!(sendTimeoutMs > 0)) {\n throw new RangeError(`sendTimeoutMs deve ser > 0 ou Infinity (recebido: ${sendTimeoutMs})`);\n }\n this.#sendTimeoutMs = sendTimeoutMs;\n this.#clock = options.clock ?? (() => performance.now());\n this.#random = options.random ?? Math.random;\n }\n\n /**\n * Enfileira o envio. Resolve com a chave da mensagem criada ou rejeita com o erro final\n * (capability ausente, fila cheia/fechada ou falha do transport após as re-tentativas). Um\n * texto acima do limite do transport sai em partes, e a chave é a da primeira (ADR 0061).\n */\n send(\n chatId: string,\n input: OutgoingContent | MessageText,\n options?: OutboundSendOptions,\n ): Promise<MessageKey> {\n let sendOptions: SendOptions | undefined;\n if (options !== undefined) {\n const { priority: _priority, ...rest } = options;\n sendOptions = rest;\n }\n let parts: SendPart[];\n try {\n const content = toContent(input);\n parts =\n content.type === 'album'\n ? this.#album\n .split(content, sendOptions)\n .flatMap((part) => this.#text.split(part.content, part.options))\n : this.#text.split(content, sendOptions);\n } catch (error) {\n return Promise.reject(error);\n }\n const [head, ...rest] = parts.map(\n ({ content, options: partOptions }): JobPart => ({\n run: () => this.#transport.send(chatId, content, partOptions),\n content,\n }),\n );\n return this.#push(chatId, options?.priority, {\n ...(head as JobPart),\n rest,\n what: `envio para ${chatId}`,\n // Capability ausente nunca vira tentativa: falha já, sem ocupar a fila. Uma legenda\n // dividida também exige `send.text`.\n check: () => {\n for (const part of parts) assertCanSend(this.#transport, part.content, part.options);\n },\n }) as Promise<MessageKey>;\n }\n\n /**\n * Enfileira uma ação que gera tráfego sem ser envio (reação, edição, \"digitando\", participantes de\n * grupo; ADR 0040), com as mesmas regras do envio: intervalos, prioridade, retry, pausa e prazo.\n * Sem humanização. Quem chama confere a capability antes: a fila não conhece a ação.\n */\n enqueue<T>(chatId: string, action: () => Promise<T>, options?: ActionOptions): Promise<T> {\n return this.#push(chatId, options?.priority, {\n run: action,\n content: null,\n rest: [],\n what: `ação em ${chatId}`,\n }) as Promise<T>;\n }\n\n #push(\n chatId: string,\n requested: SendPriority | undefined,\n spec: Pick<Job, 'run' | 'content' | 'rest' | 'what'> & { readonly check?: () => void },\n ): Promise<unknown> {\n if (this.#closed) {\n this.#dropped++;\n return Promise.reject(\n new OutboundQueueError('closed', `fila de saída fechada: ${spec.what} recusado`),\n );\n }\n if (this.#offline) {\n this.#dropped++;\n return Promise.reject(\n new OutboundQueueError(\n 'disconnected',\n `conexão caída há mais de ${this.#maxPauseMs} ms: ${spec.what} recusado`,\n ),\n );\n }\n const priority = PRIORITY_INDEX.get(requested ?? 'normal');\n if (priority === undefined) {\n return Promise.reject(new TypeError(`prioridade inválida: ${String(requested)}`));\n }\n try {\n spec.check?.();\n } catch (error) {\n return Promise.reject(error);\n }\n // Limite por prioridade: `low`/`normal` acumulados nunca tiram a vaga de uma `high`.\n if (this.#pendingBy[priority] >= this.#maxPending) {\n this.#dropped++;\n return Promise.reject(\n new OutboundQueueError(\n 'full',\n `fila de saída cheia (${this.#maxPending} aguardando com prioridade ${requested ?? 'normal'}): ${spec.what} recusado`,\n ),\n );\n }\n\n return new Promise<unknown>((resolve, reject) => {\n const job: Job = {\n run: spec.run,\n content: spec.content,\n rest: spec.rest,\n what: spec.what,\n priority,\n attempts: 0,\n resolve,\n reject,\n };\n const chat = this.#chatFor(chatId);\n chat.jobs[priority].push(job);\n chat.pending++;\n this.#pendingBy[priority]++;\n this.#wake(chat, this.#clock());\n this.#pump();\n });\n }\n\n stats(): OutboundQueueStats {\n return {\n pending: {\n high: this.#pendingBy[0],\n normal: this.#pendingBy[1],\n low: this.#pendingBy[2],\n },\n inFlight: this.#inFlight,\n activeChats: this.#chats.size,\n sent: this.#sent,\n failed: this.#failed,\n retries: this.#retries,\n dropped: this.#dropped,\n paused: this.#paused,\n };\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n\n get paused(): boolean {\n return this.#paused;\n }\n\n /**\n * Para de despachar (a conexão caiu): o que aguarda e o que chegar esperam o `resume()`, até\n * `maxPauseMs`. Envios em andamento terminam; se falharem, a re-tentativa também espera.\n */\n pause(): void {\n if (this.#paused) return;\n this.#paused = true;\n if (this.#maxPauseMs === Number.POSITIVE_INFINITY) return;\n this.#pauseTimer = setTimeout(() => {\n this.#pauseTimer = undefined;\n this.#offline = true;\n this.#rejectWaiting(\n () =>\n new OutboundQueueError(\n 'disconnected',\n `conexão caída há mais de ${this.#maxPauseMs} ms: envio descartado`,\n ),\n );\n }, this.#maxPauseMs);\n }\n\n /** Volta a despachar (a conexão abriu), inclusive depois de estourado o `maxPauseMs`. */\n resume(): void {\n if (!this.#paused) return;\n this.#paused = false;\n this.#offline = false;\n clearTimeout(this.#pauseTimer);\n this.#pauseTimer = undefined;\n this.#pump();\n }\n\n /** Resolve quando não há mensagem aguardando nem em andamento. Não impede novos envios. */\n onIdle(): Promise<void> {\n if (this.#chats.size === 0) return Promise.resolve();\n return new Promise((resolve) => this.#idleWaiters.push(resolve));\n }\n\n /**\n * Para de aceitar envios (novos rejeitam com `OutboundQueueError` `'closed'`) e resolve quando\n * a fila esvaziar. Pode ser chamado de novo com `drain: false` para abortar uma drenagem.\n */\n close(options: OutboundCloseOptions = {}): Promise<void> {\n this.#closed = true;\n if (options.drain === false) this.#discard();\n return this.onIdle();\n }\n\n #chatFor(chatId: string): ChatState {\n const existing = this.#chats.get(chatId);\n if (existing !== undefined) return existing;\n const chat: ChatState = {\n id: chatId,\n jobs: [new Fifo(), new Fifo(), new Fifo()],\n head: null,\n pending: 0,\n busy: false,\n readyAt: this.#cooldowns.get(chatId) ?? Number.NEGATIVE_INFINITY,\n ticket: 0,\n listedPriority: -1,\n timer: undefined,\n };\n this.#chats.set(chatId, chat);\n return chat;\n }\n\n /** Coloca o chat na lista de prontos ou agenda quando ele ficará pronto. */\n #wake(chat: ChatState, now: number): void {\n if (chat.busy || chat.pending === 0) return;\n if (now < chat.readyAt) {\n chat.timer ??= setTimeout(() => {\n chat.timer = undefined;\n this.#wake(chat, this.#clock());\n this.#pump();\n }, chat.readyAt - now);\n return;\n }\n const priority = chat.head !== null ? chat.head.priority : firstNonEmpty(chat.jobs);\n if (priority === -1 || (chat.ticket !== 0 && chat.listedPriority === priority)) return;\n // Nova senha invalida a entrada antiga (ex.: chegou mensagem de prioridade maior).\n chat.ticket = this.#nextTicket++;\n chat.listedPriority = priority;\n this.#ready[priority].push({ chat, ticket: chat.ticket });\n }\n\n #pump(): void {\n if (this.#pumping || this.#paused) return;\n this.#pumping = true;\n try {\n for (;;) {\n const list = this.#peekReady();\n if (list === undefined) return;\n const now = this.#clock();\n if (now < this.#globalReadyAt) {\n this.#globalTimer ??= setTimeout(() => {\n this.#globalTimer = undefined;\n this.#pump();\n }, this.#globalReadyAt - now);\n return;\n }\n const entry = list.shift();\n if (entry !== undefined) this.#dispatch(entry.chat, now);\n }\n } finally {\n this.#pumping = false;\n }\n }\n\n /** Lista de maior prioridade com entrada válida na frente; descarta as obsoletas. */\n #peekReady(): Fifo<ReadyEntry> | undefined {\n for (const list of this.#ready) {\n for (let entry = list.peek(); entry !== undefined; entry = list.peek()) {\n if (entry.ticket === entry.chat.ticket) return list;\n list.shift();\n }\n }\n return undefined;\n }\n\n #dispatch(chat: ChatState, now: number): void {\n let job = chat.head;\n if (job !== null) {\n chat.head = null;\n } else {\n const priority = firstNonEmpty(chat.jobs);\n job = priority === -1 ? null : (chat.jobs[priority].shift() ?? null);\n // Inalcançável: só chat com mensagem entra na lista de prontos.\n if (job === null) return;\n }\n chat.ticket = 0;\n chat.busy = true;\n chat.pending--;\n this.#pendingBy[job.priority]--;\n this.#inFlight++;\n this.#globalReadyAt = now + this.#globalIntervalMs;\n chat.readyAt = now + this.#chatIntervalMs;\n this.#rememberCooldown(chat.id, chat.readyAt, now);\n void this.#execute(chat, job);\n }\n\n #rememberCooldown(chatId: string, readyAt: number, now: number): void {\n for (const [id, until] of this.#cooldowns) {\n if (until > now) break;\n this.#cooldowns.delete(id);\n }\n this.#cooldowns.delete(chatId);\n this.#cooldowns.set(chatId, readyAt);\n }\n\n async #execute(chat: ChatState, job: Job): Promise<void> {\n job.attempts++;\n try {\n if (this.#humanize !== null && job.content !== null) {\n await this.#simulate(chat.id, job.content, this.#humanize);\n }\n // Descartada durante o \"digitando\": o envio não chegou ao transport e não sai.\n if (this.#discarding) {\n this.#dropped++;\n job.reject(\n new OutboundQueueError('closed', 'fila de saída fechada sem drenar: envio descartado'),\n );\n } else {\n const result = await this.#withTimeout(job.run(), job.what);\n this.#sent++;\n this.#settle(chat, job, result);\n }\n } catch (error) {\n this.#handleFailure(chat, job, error);\n }\n this.#inFlight--;\n chat.busy = false;\n if (chat.pending === 0) {\n clearTimeout(chat.timer);\n this.#chats.delete(chat.id);\n this.#notifyIdle();\n } else {\n this.#wake(chat, this.#clock());\n }\n this.#pump();\n }\n\n /** Resolve o envio ou, num texto dividido, põe a parte seguinte na frente do chat. */\n #settle(chat: ChatState, job: Job, result: unknown): void {\n const first = job.first ?? { value: result };\n const [next, ...rest] = job.rest;\n if (next === undefined) {\n job.resolve(first.value);\n return;\n }\n if (this.#discarding) {\n this.#dropped++;\n job.reject(\n new OutboundQueueError('closed', 'fila de saída fechada sem drenar: envio descartado'),\n );\n return;\n }\n chat.head = { ...job, ...next, rest, first, attempts: 0 };\n chat.pending++;\n this.#pendingBy[job.priority]++;\n }\n\n #handleFailure(chat: ChatState, job: Job, error: unknown): void {\n const now = this.#clock();\n const hint = this.#discarding ? undefined : retryAfter(error);\n // Janela global (429 global): nenhum chat envia antes dela, nem quando este envio não\n // re-tenta. Mandar antes só gastaria requisições recusadas, que a plataforma também pune.\n if (hint?.global === true) {\n this.#globalReadyAt = Math.max(this.#globalReadyAt, now + hint.ms);\n }\n let retryable: boolean;\n try {\n // Prazo estourado não re-tenta: o transport pode ainda entregar, e reenviar duplicaria.\n // Pausada além do teto, a re-tentativa ficaria parada sem previsão. Janela acima do teto\n // de espera também não: a resposta sairia fora de contexto.\n retryable =\n !this.#discarding &&\n !this.#offline &&\n !(error instanceof OutboundQueueError) &&\n job.attempts < this.#maxAttempts &&\n (hint === undefined || hint.ms <= this.#maxDelayMs) &&\n this.#isRetryable(error);\n } catch (hookError) {\n this.#failed++;\n job.reject(new AggregateError([hookError, error], 'retry.isRetryable lançou'));\n return;\n }\n if (!retryable) {\n this.#failed++;\n job.reject(error);\n return;\n }\n this.#retries++;\n chat.head = job;\n chat.pending++;\n this.#pendingBy[job.priority]++;\n // A janela informada pela plataforma é exata: sem jitter, e no lugar do backoff, que\n // tentaria cedo demais e gastaria as tentativas antes de ela abrir.\n const delay = hint === undefined ? this.#backoff(job.attempts) : hint.ms;\n chat.readyAt = Math.max(chat.readyAt, now + delay);\n }\n\n /**\n * Corre `operation` contra `sendTimeoutMs`. O resultado tardio é ignorado de propósito: quem\n * chamou `send` já recebeu o `'timeout'`, e o `race` mantém um handler na promise original.\n */\n #withTimeout<T>(operation: Promise<T>, what: string): Promise<T> {\n if (this.#sendTimeoutMs === Number.POSITIVE_INFINITY) return operation;\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n const message = `${what}: transport sem resposta em ${this.#sendTimeoutMs} ms`;\n reject(new OutboundQueueError('timeout', message));\n }, this.#sendTimeoutMs);\n });\n return Promise.race([operation, timeout]).finally(() => clearTimeout(timer));\n }\n\n /** Exponencial com teto e jitter \"igual\": metade fixa, metade aleatória. */\n #backoff(failures: number): number {\n const capped = Math.min(this.#maxDelayMs, this.#baseDelayMs * 2 ** (failures - 1));\n return capped / 2 + (capped / 2) * this.#random();\n }\n\n async #simulate(\n chatId: string,\n content: OutgoingContent,\n humanize: Required<HumanizeOptions>,\n ): Promise<void> {\n let kind: TypingKind;\n let ms: number;\n if (content.type === 'text') {\n kind = 'text';\n ms = Math.min(\n humanize.maxMs,\n Math.max(humanize.minMs, content.text.length * humanize.msPerChar),\n );\n } else if (content.type === 'voice') {\n kind = 'voice';\n ms = humanize.maxMs;\n } else {\n return;\n }\n try {\n await this.#withTimeout(this.#transport.sendTyping(chatId, kind), `\"digitando\" em ${chatId}`);\n } catch (error) {\n // O indicador é cosmético: a falha vai para o destino configurado e o envio segue já.\n this.#onTypingError?.(error, chatId);\n return;\n }\n if (ms > 0 && !this.#discarding) await this.#sleep(ms);\n }\n\n /** Espera `ms`, ou menos se a fila for descartada antes. */\n #sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const done = (): void => {\n clearTimeout(timer);\n this.#sleepers.delete(done);\n resolve();\n };\n const timer = setTimeout(done, ms);\n this.#sleepers.add(done);\n });\n }\n\n #discard(): void {\n this.#discarding = true;\n clearTimeout(this.#pauseTimer);\n this.#pauseTimer = undefined;\n for (const done of this.#sleepers) done();\n this.#rejectWaiting(\n () => new OutboundQueueError('closed', 'fila de saída fechada sem drenar: envio descartado'),\n );\n }\n\n /** Rejeita tudo o que aguarda, inclusive re-tentativas; os envios em andamento seguem. */\n #rejectWaiting(error: () => OutboundQueueError): void {\n for (const chat of this.#chats.values()) {\n const waiting: Job[] = chat.head === null ? [] : [chat.head];\n for (const fifo of chat.jobs) {\n for (let job = fifo.shift(); job !== undefined; job = fifo.shift()) waiting.push(job);\n }\n for (const job of waiting) {\n this.#dropped++;\n job.reject(error());\n }\n chat.head = null;\n chat.pending = 0;\n chat.ticket = 0;\n clearTimeout(chat.timer);\n chat.timer = undefined;\n if (!chat.busy) this.#chats.delete(chat.id);\n }\n this.#pendingBy[0] = 0;\n this.#pendingBy[1] = 0;\n this.#pendingBy[2] = 0;\n for (const list of this.#ready) list.clear();\n clearTimeout(this.#globalTimer);\n this.#globalTimer = undefined;\n this.#notifyIdle();\n }\n\n #notifyIdle(): void {\n if (this.#chats.size > 0 || this.#idleWaiters.length === 0) return;\n const waiters = this.#idleWaiters;\n this.#idleWaiters = [];\n for (const resolve of waiters) resolve();\n }\n}\n\nfunction firstNonEmpty(jobs: ChatState['jobs']): PriorityIndex | -1 {\n if (jobs[0].size > 0) return 0;\n if (jobs[1].size > 0) return 1;\n return jobs[2].size > 0 ? 2 : -1;\n}\n\nfunction nonNegative(name: string, value: number): number {\n if (!(Number.isFinite(value) && value >= 0)) {\n throw new RangeError(`${name} deve ser um número finito >= 0 (recebido: ${value})`);\n }\n return value;\n}\n\nfunction pace(\n name: keyof TransportPacing,\n configured: number | undefined,\n pacing: TransportPacing | undefined,\n): number {\n if (configured !== undefined) return nonNegative(name, configured);\n const fromTransport = pacing?.[name];\n if (fromTransport !== undefined) return nonNegative(`transport.pacing.${name}`, fromTransport);\n return DEFAULTS[name];\n}\n\n/**\n * Janela que a plataforma informou num erro do transport (ADR 0067): `retryAfterMs` finito e\n * >= 0, e `retryAfterScope: 'global'` quando ela vale para todos os chats. Duck typing, como o\n * `retryable`: o transport não precisa de classe do core para lançar o erro nativo enriquecido.\n */\nfunction retryAfter(error: unknown): { readonly ms: number; readonly global: boolean } | undefined {\n if (typeof error !== 'object' || error === null || !('retryAfterMs' in error)) return undefined;\n const ms = error.retryAfterMs;\n if (typeof ms !== 'number' || !(Number.isFinite(ms) && ms >= 0)) return undefined;\n return { ms, global: 'retryAfterScope' in error && error.retryAfterScope === 'global' };\n}\n\nfunction isTransient(error: unknown): boolean {\n if (error instanceof UnsupportedError) return false;\n return !(\n typeof error === 'object' &&\n error !== null &&\n 'retryable' in error &&\n error.retryable === false\n );\n}\n\nfunction resolveHumanize(\n option: boolean | HumanizeOptions | undefined,\n transport: OutboundTransport,\n): Required<HumanizeOptions> | null {\n // Capabilities são fixas na vida do transport: decide uma vez, não a cada envio.\n if (option === undefined || option === false || !hasCapability(transport, 'typing')) {\n return null;\n }\n const custom = option === true ? {} : option;\n return {\n msPerChar: nonNegative('humanize.msPerChar', custom.msPerChar ?? DEFAULTS.msPerChar),\n minMs: nonNegative('humanize.minMs', custom.minMs ?? DEFAULTS.minMs),\n maxMs: nonNegative('humanize.maxMs', custom.maxMs ?? DEFAULTS.maxMs),\n };\n}\n","import type { BotEventName } from './types.ts';\n\n// Objeto mapeado em vez de array: o compilador barra evento faltando e evento a mais, então a\n// lista de runtime não descola de `BotEvents`.\nconst names: { readonly [E in BotEventName]: true } = {\n message: true,\n 'message.edited': true,\n 'message.deleted': true,\n reaction: true,\n 'poll.vote': true,\n 'group.joined': true,\n 'group.left': true,\n 'group.participants': true,\n 'group.updated': true,\n 'contact.updated': true,\n 'connection.status': true,\n 'connection.qr': true,\n 'connection.pairing-code': true,\n 'message:text': true,\n 'message:image': true,\n 'message:video': true,\n 'message:audio': true,\n 'message:voice': true,\n 'message:sticker': true,\n 'message:document': true,\n 'message:location': true,\n 'message:contact': true,\n 'message:poll': true,\n 'message:unknown': true,\n command: true,\n 'plugin.error': true,\n};\n\n/**\n * Valida nomes de evento vindos de fora do sistema de tipos (o `on` de um manifesto em JS): um\n * nome com erro de digitação nunca dispararia, sem aviso nenhum.\n */\nexport function isBotEventName(value: string): value is BotEventName {\n return Object.hasOwn(names, value);\n}\n","// Subconjunto de semver suficiente para `engine` e `dependsOn` (ADR 0016): versões\n// `M.m.p[-pre][+build]` e faixas com `^`, `~`, `>=`, `>`, `<=`, `<`, `=`, curingas (`x`, `X`,\n// `*`, versão parcial), comparadores separados por espaço (E) e `||` (OU). Faixas com hífen\n// (`1.0.0 - 2.0.0`) ficam de fora. Implementado aqui em vez do pacote `semver` para o core não\n// carregar dependência de runtime por ~100 linhas; a semântica segue a do npm, inclusive a\n// regra de pré-release (ver `satisfies`).\n\nexport interface SemVer {\n readonly major: number;\n readonly minor: number;\n readonly patch: number;\n readonly prerelease: readonly (string | number)[];\n}\n\ntype Operator = '<' | '<=' | '>' | '>=' | '=';\n\ninterface Comparator {\n readonly operator: Operator;\n readonly version: SemVer;\n}\n\nconst NUMBER = '0|[1-9]\\\\d*';\nconst IDENTIFIER = '[0-9A-Za-z-]+';\nconst PRERELEASE = `${IDENTIFIER}(?:\\\\.${IDENTIFIER})*`;\nconst VERSION = new RegExp(\n `^(${NUMBER})\\\\.(${NUMBER})\\\\.(${NUMBER})(?:-(${PRERELEASE}))?(?:\\\\+${PRERELEASE})?$`,\n);\nconst PART = `${NUMBER}|x|X|\\\\*`;\nconst PARTIAL = new RegExp(\n `^(\\\\^|~|>=|<=|>|<|=)?(${PART})(?:\\\\.(${PART})(?:\\\\.(${PART})(?:-(${PRERELEASE}))?(?:\\\\+${PRERELEASE})?)?)?$`,\n);\n\nfunction parsePrerelease(raw: string | undefined): (string | number)[] {\n if (raw === undefined) return [];\n return raw.split('.').map((id) => (/^\\d+$/.test(id) ? Number(id) : id));\n}\n\n/** Versão exata (`1.2.3`, `1.0.0-beta.1`); `undefined` se não for semver válido. */\nexport function parseVersion(value: string): SemVer | undefined {\n const match = VERSION.exec(value.trim());\n if (!match) return undefined;\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n prerelease: parsePrerelease(match[4]),\n };\n}\n\nfunction compareIdentifiers(a: string | number, b: string | number): number {\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n // Identificador numérico tem precedência menor que alfanumérico.\n if (typeof a === 'number') return -1;\n if (typeof b === 'number') return 1;\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\n/** Negativo, zero ou positivo, como em `Array#sort`. `+build` não conta. */\nexport function compareVersions(a: SemVer, b: SemVer): number {\n const core = a.major - b.major || a.minor - b.minor || a.patch - b.patch;\n if (core !== 0) return core;\n // Sem pré-release é maior que com: 1.0.0 > 1.0.0-rc.1.\n if (a.prerelease.length === 0 || b.prerelease.length === 0) {\n return b.prerelease.length - a.prerelease.length;\n }\n const length = Math.max(a.prerelease.length, b.prerelease.length);\n for (let i = 0; i < length; i++) {\n const x = a.prerelease[i];\n const y = b.prerelease[i];\n if (x === undefined) return -1;\n if (y === undefined) return 1;\n const diff = compareIdentifiers(x, y);\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\nconst version = (\n major: number,\n minor: number,\n patch: number,\n prerelease: (string | number)[] = [],\n): SemVer => ({ major, minor, patch, prerelease });\n\nconst comparator = (operator: Operator, v: SemVer): Comparator => ({ operator, version: v });\n\n// Nada é menor que 0.0.0-0: um comparador que nenhuma versão satisfaz (ex.: `<*`).\nconst NOTHING: Comparator[] = [comparator('<', version(0, 0, 0, [0]))];\n\nfunction parsePart(raw: string | undefined): number | undefined {\n if (raw === undefined || raw === 'x' || raw === 'X' || raw === '*') return undefined;\n return Number(raw);\n}\n\n/** Converte um termo da faixa (`^1.2`, `>=1.0.0`, `1.x`) em comparadores; `undefined` se inválido. */\nfunction desugar(term: string): Comparator[] | undefined {\n const match = PARTIAL.exec(term);\n if (!match) return undefined;\n const operator = match[1] ?? '=';\n const major = parsePart(match[2]);\n const minor = parsePart(match[3]);\n const patch = parsePart(match[4]);\n // Curinga só no fim: `1.x.3` não é faixa.\n if (\n (major === undefined && match[3] !== undefined) ||\n (minor === undefined && match[4] !== undefined)\n ) {\n return undefined;\n }\n const pre = parsePrerelease(match[5]);\n if (major === undefined) return operator === '<' || operator === '>' ? NOTHING : [];\n const low = version(major, minor ?? 0, patch ?? 0, pre);\n\n switch (operator) {\n case '=':\n if (minor === undefined)\n return [comparator('>=', low), comparator('<', version(major + 1, 0, 0))];\n if (patch === undefined) {\n return [comparator('>=', low), comparator('<', version(major, minor + 1, 0))];\n }\n return [comparator('=', low)];\n case '^': {\n let high: SemVer;\n if (major > 0 || minor === undefined) high = version(major + 1, 0, 0);\n else if (minor > 0 || patch === undefined) high = version(0, minor + 1, 0);\n else high = version(0, 0, patch + 1);\n return [comparator('>=', low), comparator('<', high)];\n }\n case '~': {\n const high = minor === undefined ? version(major + 1, 0, 0) : version(major, minor + 1, 0);\n return [comparator('>=', low), comparator('<', high)];\n }\n case '>':\n if (minor === undefined) return [comparator('>=', version(major + 1, 0, 0))];\n if (patch === undefined) return [comparator('>=', version(major, minor + 1, 0))];\n return [comparator('>', low)];\n case '<=':\n if (minor === undefined) return [comparator('<', version(major + 1, 0, 0))];\n if (patch === undefined) return [comparator('<', version(major, minor + 1, 0))];\n return [comparator('<=', low)];\n default:\n // `>=` e `<` com versão parcial completam com zeros.\n return [comparator(operator as Operator, low)];\n }\n}\n\n/** Conjuntos de comparadores (OU entre conjuntos, E dentro de cada um); `undefined` se inválida. */\nfunction parseRange(range: string): Comparator[][] | undefined {\n const sets: Comparator[][] = [];\n for (const raw of range.split('||')) {\n // `>= 1.2.3` vale como `>=1.2.3`.\n const terms = raw\n .trim()\n .replace(/(\\^|~|>=|<=|>|<|=)\\s+/g, '$1')\n .split(/\\s+/)\n .filter((term) => term.length > 0);\n const set: Comparator[] = [];\n for (const term of terms) {\n const comparators = desugar(term);\n if (!comparators) return undefined;\n set.push(...comparators);\n }\n sets.push(set);\n }\n return sets;\n}\n\n/** `true` se `range` é uma faixa que este subconjunto entende. */\nexport function isValidRange(range: string): boolean {\n return parseRange(range) !== undefined;\n}\n\nfunction test(v: SemVer, { operator, version: other }: Comparator): boolean {\n const diff = compareVersions(v, other);\n switch (operator) {\n case '<':\n return diff < 0;\n case '<=':\n return diff <= 0;\n case '>':\n return diff > 0;\n case '>=':\n return diff >= 0;\n default:\n return diff === 0;\n }\n}\n\n/**\n * `version` está dentro de `range`? Lança `RangeError` se algum dos dois for inválido.\n *\n * Como no npm, uma versão de pré-release só satisfaz a faixa se algum comparador do mesmo\n * conjunto citar pré-release da mesma `M.m.p`: `^1.0.0` não aceita `1.1.0-beta`, mas\n * `^1.1.0-alpha` aceita. Isso evita que um plugin estável carregue em core instável por acaso.\n */\nexport function satisfies(versionText: string, range: string): boolean {\n const v = parseVersion(versionText);\n if (!v) throw new RangeError(`Versão semver inválida: \"${versionText}\"`);\n const sets = parseRange(range);\n if (!sets) throw new RangeError(`Faixa semver inválida: \"${range}\"`);\n return sets.some((set) => {\n if (!set.every((c) => test(v, c))) return false;\n if (v.prerelease.length === 0) return true;\n return set.some(\n ({ version: c }) =>\n c.prerelease.length > 0 &&\n c.major === v.major &&\n c.minor === v.minor &&\n c.patch === v.patch,\n );\n });\n}\n","import type { z } from 'zod';\nimport { assertCommandDefinition, type CommandDefinition } from '#commands/command.ts';\nimport { isBotEventName } from '#events/names.ts';\nimport { isCapability } from '#transport/capabilities.ts';\nimport { isValidRange, parseVersion } from './semver.ts';\nimport type { PluginDefinition, PluginMessages } from './types.ts';\n\n/**\n * Nome de plugin: kebab-case minúsculo, começando por letra. É estável porque vira chave de\n * `disabledPlugins`, namespace de storage e prefixo de rota HTTP (`/plugins/<name>/…`).\n */\nexport const PLUGIN_NAME_PATTERN: RegExp = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;\nconst MAX_NAME_LENGTH = 64;\n\n/** Manifesto malformado: erro de quem escreveu o plugin, então derruba o boot. */\nexport class PluginManifestError extends Error {\n override readonly name = 'PluginManifestError';\n /** `name` declarado, se havia um string. */\n readonly plugin: string | undefined;\n /** De onde o plugin veio (`config` ou caminho do módulo), quando conhecido. */\n readonly origin: string | undefined;\n readonly issues: readonly string[];\n\n constructor(plugin: string | undefined, issues: readonly string[], origin?: string) {\n const who = plugin === undefined ? 'plugin sem nome' : `plugin \"${plugin}\"`;\n const where = origin === undefined ? '' : ` (${origin})`;\n super(`Manifesto inválido no ${who}${where}:\\n- ${issues.join('\\n- ')}`);\n this.plugin = plugin;\n this.origin = origin;\n this.issues = issues;\n }\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nfunction checkName(value: unknown, label: string, issues: string[]): void {\n if (typeof value !== 'string' || !PLUGIN_NAME_PATTERN.test(value)) {\n issues.push(\n `${label} deve ser kebab-case minúsculo (ex.: \"user-names\"); recebido ${show(value)}`,\n );\n } else if (value.length > MAX_NAME_LENGTH) {\n issues.push(`${label} passa de ${MAX_NAME_LENGTH} caracteres`);\n }\n}\n\nconst show = (value: unknown): string =>\n typeof value === 'string' ? `\"${value}\"` : value === undefined ? 'nada' : typeof value;\n\nfunction checkNames(value: unknown, label: string, self: unknown, issues: string[]): void {\n if (value === undefined) return;\n if (!Array.isArray(value)) {\n issues.push(`${label} deve ser uma lista de nomes de plugin`);\n return;\n }\n for (const name of value) {\n checkName(name, `${label}: item`, issues);\n if (name === self) issues.push(`${label} não pode citar o próprio plugin`);\n }\n}\n\n/**\n * `commands` do manifesto (ADR 0079). Confere aqui o que o `ctx.commands.add` só descobriria no\n * boot, para o erro sair no `definePlugin`, que aponta a linha do plugin.\n */\nfunction checkCommands(value: unknown, issues: string[]): void {\n if (value === undefined) return;\n if (!isRecord(value)) {\n issues.push('commands deve ser um objeto nome → comando');\n return;\n }\n for (const [name, declared] of Object.entries(value)) {\n const label = `commands[\"${name}\"]`;\n if (!isRecord(declared)) {\n issues.push(`${label} deve ser um objeto com run`);\n continue;\n }\n if (declared['name'] !== undefined) {\n issues.push(`${label}: o nome vem da chave; tire o campo name`);\n }\n if (typeof declared['run'] !== 'function') issues.push(`${label}.run deve ser uma função`);\n const { aliases, description, onReject } = declared;\n if (aliases !== undefined && !(Array.isArray(aliases) && aliases.every(isString))) {\n issues.push(`${label}.aliases deve ser uma lista de textos`);\n continue;\n }\n if (description !== undefined && typeof description !== 'string') {\n issues.push(`${label}.description deve ser um texto`);\n }\n if (onReject !== undefined && typeof onReject !== 'function') {\n issues.push(`${label}.onReject, se presente, deve ser uma função`);\n }\n try {\n assertCommandDefinition({ ...declared, name } as unknown as CommandDefinition);\n } catch (error) {\n issues.push(`${label}: ${(error as Error).message}`);\n }\n }\n}\n\nfunction checkListeners(value: unknown, issues: string[]): void {\n if (value === undefined) return;\n if (!isRecord(value)) {\n issues.push('on deve ser um objeto evento → listener');\n return;\n }\n for (const [event, listener] of Object.entries(value)) {\n if (!isBotEventName(event)) issues.push(`on: evento desconhecido \"${event}\"`);\n else if (typeof listener !== 'function') issues.push(`on[\"${event}\"] deve ser uma função`);\n }\n}\n\nconst isString = (value: unknown): value is string => typeof value === 'string';\n\n/** Problemas do manifesto, um por linha; lista vazia = válido. Não olha compatibilidade. */\nexport function manifestIssues(value: unknown): string[] {\n if (!isRecord(value)) return ['o plugin deve ser um objeto (use definePlugin)'];\n const issues: string[] = [];\n const { name } = value;\n checkName(name, 'name', issues);\n\n if (typeof value['version'] !== 'string' || !parseVersion(value['version'])) {\n issues.push(`version deve ser semver (ex.: \"1.2.0\"); recebido ${show(value['version'])}`);\n }\n if (typeof value['engine'] !== 'string' || !isValidRange(value['engine'])) {\n issues.push(\n `engine é obrigatório e deve ser uma faixa semver do core (ex.: \"^1.0.0\"); recebido ${show(value['engine'])}`,\n );\n }\n\n const requires = value['requires'];\n if (requires !== undefined) {\n if (!Array.isArray(requires)) issues.push('requires deve ser uma lista de capabilities');\n else {\n for (const capability of requires) {\n if (typeof capability !== 'string' || !isCapability(capability)) {\n issues.push(`requires: capability desconhecida ${show(capability)}`);\n }\n }\n }\n }\n\n const transports = value['transports'];\n if (transports !== undefined) {\n if (\n !Array.isArray(transports) ||\n transports.length === 0 ||\n !transports.every((t) => typeof t === 'string' && t.length > 0)\n ) {\n issues.push('transports, se presente, deve ser uma lista não vazia de nomes de transport');\n }\n }\n\n const dependsOn = value['dependsOn'];\n if (dependsOn !== undefined) {\n if (!isRecord(dependsOn)) issues.push('dependsOn deve ser um objeto nome → faixa semver');\n else {\n for (const [dependency, range] of Object.entries(dependsOn)) {\n checkName(dependency, 'dependsOn: nome', issues);\n if (dependency === name) issues.push('dependsOn não pode citar o próprio plugin');\n if (typeof range !== 'string' || !isValidRange(range)) {\n issues.push(\n `dependsOn[\"${dependency}\"] deve ser uma faixa semver; recebido ${show(range)}`,\n );\n }\n }\n }\n }\n\n checkNames(value['after'], 'after', name, issues);\n\n const priority = value['priority'];\n if (priority !== undefined && (typeof priority !== 'number' || !Number.isFinite(priority))) {\n issues.push('priority deve ser um número finito');\n }\n\n const config = value['config'];\n if (config !== undefined && !(isRecord(config) && typeof config['safeParse'] === 'function')) {\n issues.push('config deve ser um schema Zod');\n }\n\n const messages = value['messages'];\n if (\n messages !== undefined &&\n !(isRecord(messages) && Object.values(messages).every((text) => typeof text === 'string'))\n ) {\n issues.push('messages deve ser um objeto chave → texto');\n }\n\n checkCommands(value['commands'], issues);\n checkListeners(value['on'], issues);\n\n // Sem `commands` nem `on`, o `setup` é o único jeito de o plugin fazer algo.\n const declares = value['commands'] !== undefined || value['on'] !== undefined;\n if (typeof value['setup'] !== 'function' && (value['setup'] !== undefined || !declares)) {\n issues.push('setup deve ser uma função (opcional quando o plugin declara commands ou on)');\n }\n if (value['teardown'] !== undefined && typeof value['teardown'] !== 'function') {\n issues.push('teardown, se presente, deve ser uma função');\n }\n return issues;\n}\n\n/** Lança `PluginManifestError` se `value` não for um plugin bem formado. */\nexport function assertPluginDefinition(\n value: unknown,\n origin?: string,\n): asserts value is PluginDefinition {\n const issues = manifestIssues(value);\n if (issues.length === 0) return;\n const name = isRecord(value) && typeof value['name'] === 'string' ? value['name'] : undefined;\n throw new PluginManifestError(name, issues, origin);\n}\n\n/**\n * Declara um plugin. Valida o manifesto na hora (lança `PluginManifestError`) e devolve a\n * própria definição, tipada: o `ctx.config` de `setup`/`teardown` sai de `z.output` do schema\n * em `config`, e `ctx.plugin.messages` tem as chaves de `messages`.\n */\nexport function definePlugin<\n TSchema extends z.ZodType = z.ZodType,\n TMessages extends PluginMessages = PluginMessages,\n>(definition: PluginDefinition<TSchema, TMessages>): PluginDefinition<TSchema, TMessages> {\n assertPluginDefinition(definition);\n return definition;\n}\n","/**\n * Versão do `@usebridger/core`, contra a qual o loader confere o `engine` dos plugins. Fica numa\n * constante (e não lida do `package.json` em runtime) para valer igual no fonte e no bundle.\n * Não edite à mão: `pnpm version-packages` roda o `changeset version` e reescreve esta linha\n * (`scripts/sync-version.ts`); o `version.test.ts` falha se ela divergir do `package.json`.\n */\nexport const CORE_VERSION = '0.2.0';\n","// Açúcar do manifesto (ADR 0079): `commands` e `on` viram as chamadas que o `setup` faria à mão.\n// Não há segundo caminho de execução: o comando passa pelo mesmo `ctx.commands.add`, com prazo,\n// recusa e teardown iguais aos da forma longa.\n\nimport type { BotEventName, Listener } from '#events/types.ts';\nimport type { Capability } from '#transport/capabilities.ts';\nimport type { PluginContext, PluginDefinition, PluginListener } from './types.ts';\n\n/** Registra os `commands` e o `on` do manifesto. Chamado pelo host antes do `setup`. */\nexport function installDeclared(definition: PluginDefinition, ctx: PluginContext): void {\n for (const [name, declared] of Object.entries(definition.commands ?? {})) {\n const { run, ...rest } = declared;\n ctx.commands.add({ ...rest, name, run: (c) => run.call(declared, c, ctx) });\n }\n for (const [event, listener] of Object.entries(definition.on ?? {}) as [\n BotEventName,\n PluginListener<BotEventName>,\n ][]) {\n const subscribed: Listener<BotEventName> = (e) => listener(e, ctx);\n ctx.events.on(event, subscribed);\n }\n}\n\n/**\n * `requires` declarado mais o que o manifesto implica: comando declarado pode responder texto\n * devolvendo-o, então exige `send.text` sem o autor precisar repeti-lo.\n */\nexport function requiredCapabilities(definition: PluginDefinition): readonly Capability[] {\n const declared = definition.requires ?? [];\n const hasCommands = Object.keys(definition.commands ?? {}).length > 0;\n return hasCommands && !declared.includes('send.text') ? [...declared, 'send.text'] : declared;\n}\n","import type { PluginManifest } from './types.ts';\n\n/** O que a ordenação lê do manifesto. */\nexport type OrderableManifest = Pick<PluginManifest, 'name' | 'priority' | 'after' | 'dependsOn'>;\n\n/** `dependsOn`/`after` formam um ciclo: não existe ordem de carga possível. Erro no boot. */\nexport class PluginCycleError extends Error {\n override readonly name = 'PluginCycleError';\n /** Caminho do ciclo, fechando no primeiro: `['a', 'b', 'a']` = a depende de b, b de a. */\n readonly cycle: readonly string[];\n\n constructor(cycle: readonly string[]) {\n super(\n `Ciclo na ordem de carga dos plugins: ${cycle.join(' → ')} ` +\n '(→ = depende de / carrega depois de). Remova um dos dependsOn/after.',\n );\n this.cycle = cycle;\n }\n}\n\n/**\n * Ordem de carga (ADR 0007): toposort em que `dependsOn` e `after` são arestas (a dependência\n * vem antes) e, entre os prontos, desempata `priority` maior e depois a ordem recebida. Nomes\n * citados que não estão na lista não criam aresta — dependência ausente é motivo de \"ignorado\",\n * não de ordem. Lança `PluginCycleError` com o caminho do ciclo.\n */\nexport function sortPlugins<T extends OrderableManifest>(plugins: readonly T[]): T[] {\n const index = new Map(plugins.map((plugin, i) => [plugin.name, i]));\n // predecessors[i]: índices que precisam carregar antes de i.\n const predecessors = plugins.map((plugin) => {\n const before = new Set<number>();\n for (const name of [...Object.keys(plugin.dependsOn ?? {}), ...(plugin.after ?? [])]) {\n const j = index.get(name);\n if (j !== undefined) before.add(j);\n }\n return before;\n });\n const pending = predecessors.map((before) => before.size);\n const done = new Set<number>();\n const result: T[] = [];\n\n // O(n²) de propósito: são dezenas de plugins, e a escolha explícita do melhor pronto deixa a\n // regra de desempate óbvia.\n while (result.length < plugins.length) {\n let best: number | undefined;\n for (let i = 0; i < plugins.length; i++) {\n if (done.has(i) || pending[i] !== 0) continue;\n if (best === undefined || priorityOf(plugins, i) > priorityOf(plugins, best)) best = i;\n }\n if (best === undefined) throw new PluginCycleError(findCycle(plugins, predecessors, done));\n done.add(best);\n result.push(plugins[best] as T);\n predecessors.forEach((before, i) => {\n if (before.has(best)) pending[i] = (pending[i] ?? 0) - 1;\n });\n }\n return result;\n}\n\nconst priorityOf = (plugins: readonly OrderableManifest[], i: number): number =>\n plugins[i]?.priority ?? 0;\n\n/**\n * Todo nó que sobrou tem um predecessor que também sobrou; andando de predecessor em\n * predecessor, uma hora repete — o trecho desde a repetição é o ciclo.\n */\nfunction findCycle(\n plugins: readonly OrderableManifest[],\n predecessors: readonly Set<number>[],\n done: ReadonlySet<number>,\n): string[] {\n const path: number[] = [];\n let current = plugins.findIndex((_, i) => !done.has(i));\n while (!path.includes(current)) {\n path.push(current);\n const before = [...(predecessors[current] ?? [])]\n .filter((j) => !done.has(j))\n .sort((a, b) => a - b);\n current = before[0] ?? current;\n }\n const cycle = path.slice(path.indexOf(current));\n cycle.push(current);\n return cycle.map((i) => plugins[i]?.name ?? '?');\n}\n","import type { Capability } from '#transport/capabilities.ts';\n\n/** Fase do lifecycle em que um plugin falhou. `context` = a fábrica do contexto lançou. */\nexport type PluginPhase = 'context' | 'setup' | 'teardown' | 'dispose';\n\n/** Falha de um plugin numa fase do lifecycle; o erro original fica em `cause`. */\nexport class PluginLifecycleError extends Error {\n override readonly name = 'PluginLifecycleError';\n readonly plugin: string;\n readonly phase: PluginPhase;\n /** `true` quando a fase estourou o prazo. */\n readonly timedOut: boolean;\n /** O que aconteceu, sem o prefixo do plugin (ex.: `excedeu 5000 ms`). */\n readonly detail: string;\n\n constructor(\n plugin: string,\n phase: PluginPhase,\n detail: string,\n timedOut: boolean,\n cause?: unknown,\n ) {\n super(`plugin \"${plugin}\" (${phase}): ${detail}`, { cause });\n this.plugin = plugin;\n this.phase = phase;\n this.timedOut = timedOut;\n this.detail = detail;\n }\n}\n\n/** Por que um plugin não está carregado. */\nexport type PluginSkipReason =\n | { readonly kind: 'disabled' }\n | { readonly kind: 'engine'; readonly range: string; readonly coreVersion: string }\n | { readonly kind: 'capabilities'; readonly missing: readonly Capability[] }\n | { readonly kind: 'transport'; readonly expected: readonly string[]; readonly actual: string }\n | { readonly kind: 'dependency-missing'; readonly dependency: string }\n | { readonly kind: 'dependency-skipped'; readonly dependency: string }\n | {\n readonly kind: 'dependency-version';\n readonly dependency: string;\n readonly range: string;\n readonly version: string;\n }\n | { readonly kind: 'setup-failed'; readonly error: PluginLifecycleError };\n\ninterface ReportBase {\n readonly name: string;\n readonly version: string;\n /** `'config'` ou caminho do módulo (ver `PluginEntry`). */\n readonly origin: string;\n}\n\n/** Uma linha da tabela de boot. A tabela segue a ordem de carga. */\nexport type PluginReportEntry =\n | (ReportBase & { readonly status: 'loaded' })\n | (ReportBase & { readonly status: 'skipped'; readonly reason: PluginSkipReason });\n\n/** Motivo em texto curto, como aparece na tabela de boot. */\nexport function describeSkipReason(reason: PluginSkipReason): string {\n switch (reason.kind) {\n case 'disabled':\n return 'desabilitado em disabledPlugins';\n case 'engine':\n return `engine incompatível: exige core ${reason.range}, versão atual ${reason.coreVersion}`;\n case 'capabilities':\n return `capability ausente no transport: ${reason.missing.join(', ')}`;\n case 'transport':\n return `transport diferente: exige ${reason.expected.join(' ou ')}, atual ${reason.actual}`;\n case 'dependency-missing':\n return `dependência ausente: ${reason.dependency}`;\n case 'dependency-skipped':\n return `dependência ignorada: ${reason.dependency}`;\n case 'dependency-version':\n return `dependência com versão incompatível: ${reason.dependency}@${reason.version} não satisfaz ${reason.range}`;\n case 'setup-failed': {\n const { error } = reason;\n const phase = error.phase === 'context' ? 'na criação do contexto' : 'no setup';\n const detail =\n error.timedOut || error.cause === undefined\n ? error.detail\n : error.cause instanceof Error\n ? error.cause.message\n : String(error.cause);\n return `falha ${phase}: ${detail}`;\n }\n }\n}\n\n/**\n * Tabela de boot para log, uma linha por plugin, alinhada em colunas:\n *\n * ```\n * Plugins: 1 carregado(s), 1 ignorado(s)\n * sticker 1.2.0 carregado\n * ai 1.0.0 ignorado (capability ausente no transport: polls)\n * ```\n */\nexport function formatBootTable(entries: readonly PluginReportEntry[]): string {\n const loaded = entries.filter((entry) => entry.status === 'loaded').length;\n const header = `Plugins: ${loaded} carregado(s), ${entries.length - loaded} ignorado(s)`;\n const nameWidth = Math.max(0, ...entries.map((entry) => entry.name.length));\n const versionWidth = Math.max(0, ...entries.map((entry) => entry.version.length));\n const lines = entries.map((entry) => {\n const status =\n entry.status === 'loaded' ? 'carregado' : `ignorado (${describeSkipReason(entry.reason)})`;\n return ` ${entry.name.padEnd(nameWidth)} ${entry.version.padEnd(versionWidth)} ${status}`;\n });\n return [header, ...lines].join('\\n');\n}\n","import type { Logger } from '#logger/types.ts';\nimport { type CapabilityHolder, missingCapabilities } from '#transport/capabilities.ts';\nimport { CORE_VERSION } from '#version.ts';\nimport { installDeclared, requiredCapabilities } from './declared.ts';\nimport { assertPluginDefinition } from './define.ts';\nimport { sortPlugins } from './order.ts';\nimport {\n describeSkipReason,\n formatBootTable,\n PluginLifecycleError,\n type PluginPhase,\n type PluginReportEntry,\n type PluginSkipReason,\n} from './report.ts';\nimport { parseVersion, satisfies } from './semver.ts';\nimport type { PluginEntry } from './sources.ts';\nimport type { PluginContext, PluginDefinition } from './types.ts';\n\n/**\n * Contexto de um plugin montado pelo `Bot`. `dispose` desfaz tudo o que o plugin registrou\n * por esse contexto (comandos, listeners, serviços, jobs) e roda sempre depois do `teardown` —\n * ou no lugar dele, quando o `setup` falhou no meio. `reason` é a falha do `setup` (o erro de\n * timeout, se ele estourou o prazo), que vira o motivo do `ctx.signal` abortado (ADR 0033).\n */\nexport interface PluginContextHandle {\n readonly context: PluginContext;\n dispose(reason?: unknown): void | Promise<void>;\n}\n\n/** Monta o contexto de um plugin. O loader não conhece os serviços concretos (M1-16 fornece). */\nexport type PluginContextFactory = (\n plugin: PluginDefinition,\n) => PluginContextHandle | Promise<PluginContextHandle>;\n\nexport interface PluginHostOptions {\n /** Plugins já coletados (ver `collectPlugins`), em ordem de declaração. */\n readonly plugins: readonly PluginEntry[];\n /** Nome e capabilities do transport ativo, conferidos contra `transports` e `requires`. */\n readonly transport: CapabilityHolder;\n readonly createContext: PluginContextFactory;\n readonly log: Logger;\n /** Nomes de plugin que não carregam. */\n readonly disabledPlugins?: readonly string[];\n /** Prazo de criação do contexto e de `setup` em ms. Padrão: 10000. */\n readonly setupTimeoutMs?: number;\n /** Prazo de `teardown` e de `dispose` em ms. Padrão: 5000. */\n readonly teardownTimeoutMs?: number;\n /** Versão conferida contra `engine`. Padrão: `CORE_VERSION`; existe para testes. */\n readonly coreVersion?: string;\n}\n\n/** `idle → starting → running → stopping → stopped`; `stopped` é terminal. */\nexport type PluginHostState = 'idle' | 'starting' | 'running' | 'stopping' | 'stopped';\n\nexport interface PluginReloadResult {\n /** Linha nova do plugin na tabela: `loaded`, ou `skipped` se o `setup` novo falhou. */\n readonly entry: PluginReportEntry;\n /**\n * Linhas novas de quem depende dele (`dependsOn`, transitivo), recarregados em cascata, na\n * ordem de carga. `dependency-skipped` se o plugin recarregado não subiu.\n */\n readonly dependents: readonly PluginReportEntry[];\n /**\n * Falhas do `teardown`/`dispose` das instâncias anteriores, do plugin e dos dependentes (já\n * registradas no log). Falha do `setup` novo fica na `entry` de cada um.\n */\n readonly errors: readonly PluginLifecycleError[];\n}\n\nexport interface PluginHost {\n readonly state: PluginHostState;\n /**\n * Valida, ordena e roda o `setup` de cada plugin compatível, em ordem topológica. Devolve a\n * tabela de boot (também logada). Rejeita — sem rodar nenhum `setup` — com\n * `PluginManifestError`, `PluginConflictError` ou `PluginCycleError`. Falha de um `setup`\n * não rejeita: o plugin e quem depende dele viram \"ignorado\".\n */\n start(): Promise<PluginReportEntry[]>;\n /**\n * `teardown` e `dispose` dos carregados, na ordem inversa da carga. Nunca rejeita por falha\n * de plugin: devolve as falhas (também logadas), e uma não impede o resto. Abortado o\n * `signal`, o `teardown` em curso é abandonado e os seguintes não rodam (cada um vira falha\n * com `timedOut`), mas o `dispose` de todos roda: o kernel desfaz o que o plugin registrou.\n * Idempotente: só o `signal` da primeira chamada vale.\n */\n stop(signal?: AbortSignal): Promise<PluginLifecycleError[]>;\n /**\n * Derruba e sobe de novo um plugin (`teardown` → `dispose` → novo contexto → `setup`) e, em\n * cascata, quem depende dele por `dependsOn` (ADR 0041): os dependentes descem antes (ordem\n * inversa) e sobem depois (ordem de carga), reavaliados como no boot. É a primitiva do reload\n * por mudança de config (ADR 0017): o contexto novo sai da fábrica, que já lê a config\n * atualizada. Vale para plugin carregado ou cujo `setup` falhou.\n */\n reload(name: string): Promise<PluginReloadResult>;\n /** Tabela atual, na ordem de carga (reflete reloads). */\n report(): PluginReportEntry[];\n}\n\n/** Dois plugins com o mesmo `name` (ADR 0007). Erro no boot. */\nexport class PluginConflictError extends Error {\n override readonly name = 'PluginConflictError';\n readonly plugin: string;\n readonly origins: readonly string[];\n\n constructor(plugin: string, origins: readonly string[]) {\n super(\n `Dois plugins se chamam \"${plugin}\" (${origins.join(' e ')}). ` +\n 'O nome identifica o plugin em config, storage e rotas: renomeie um deles.',\n );\n this.plugin = plugin;\n this.origins = origins;\n }\n}\n\n/** Operação incompatível com o estado do host ou do plugin. */\nexport class PluginHostStateError extends Error {\n override readonly name = 'PluginHostStateError';\n}\n\nexport const DEFAULT_SETUP_TIMEOUT_MS = 10_000;\nexport const DEFAULT_TEARDOWN_TIMEOUT_MS = 5000;\n\ninterface Slot {\n readonly entry: PluginEntry;\n report: PluginReportEntry;\n handle: PluginContextHandle | undefined;\n}\n\n/**\n * Roda `fn` com prazo e devolve a falha em vez de lançar. A promise de `fn` sempre ganha um\n * handler, então um `setup` que rejeita depois do timeout não vira rejeição não tratada.\n * Abortado o `signal`, desiste na hora, como num timeout.\n */\nasync function runPhase<T>(\n plugin: string,\n phase: PluginPhase,\n timeoutMs: number,\n fn: () => T | Promise<T>,\n signal?: AbortSignal,\n): Promise<{ ok: true; value: T } | { ok: false; error: PluginLifecycleError }> {\n let timer: NodeJS.Timeout | undefined;\n let onAbort: (() => void) | undefined;\n type Outcome = { ok: true; value: T } | { ok: false; error: PluginLifecycleError };\n const timeout = new Promise<Outcome>((resolve) => {\n const give = (message: string) => () =>\n resolve({ ok: false, error: new PluginLifecycleError(plugin, phase, message, true) });\n timer = setTimeout(give(`excedeu ${timeoutMs} ms`), timeoutMs);\n onAbort = give('abandonado: prazo de parada do bot esgotado');\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n // `then` captura também o throw síncrono.\n const run = Promise.resolve()\n .then(fn)\n .then(\n (value): Outcome => ({ ok: true, value }),\n (cause: unknown): Outcome => ({\n ok: false,\n error: new PluginLifecycleError(plugin, phase, 'falhou', false, cause),\n }),\n );\n try {\n return await Promise.race([run, timeout]);\n } finally {\n clearTimeout(timer);\n if (onAbort) signal?.removeEventListener('abort', onAbort);\n }\n}\n\nconst reportBase = ({ definition, origin }: PluginEntry) => ({\n name: definition.name,\n version: definition.version,\n origin,\n});\n\n/** Cria o host de plugins. Não roda nada até `start()`. */\nexport function createPluginHost(options: PluginHostOptions): PluginHost {\n const { transport, createContext, log } = options;\n const coreVersion = options.coreVersion ?? CORE_VERSION;\n if (!parseVersion(coreVersion)) throw new RangeError(`coreVersion inválida: \"${coreVersion}\"`);\n const setupTimeoutMs = options.setupTimeoutMs ?? DEFAULT_SETUP_TIMEOUT_MS;\n const teardownTimeoutMs = options.teardownTimeoutMs ?? DEFAULT_TEARDOWN_TIMEOUT_MS;\n const disabled = new Set(options.disabledPlugins ?? []);\n\n let state: PluginHostState = 'idle';\n let slots: Slot[] = [];\n const byName = new Map<string, Slot>();\n let stopPromise: Promise<PluginLifecycleError[]> | undefined;\n // start, stop e reload rodam um de cada vez: um reload no meio do stop deixaria contexto órfão.\n let queue: Promise<unknown> = Promise.resolve();\n\n function enqueue<T>(task: () => Promise<T>): Promise<T> {\n const result = queue.then(task);\n // A fila só precisa saber que a tarefa acabou; o erro chega a quem chamou por `result`.\n queue = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n }\n\n /** Motivo estático para não carregar, na ordem em que a tabela mostra. */\n function incompatibility(definition: PluginDefinition): PluginSkipReason | undefined {\n if (disabled.has(definition.name)) return { kind: 'disabled' };\n if (!satisfies(coreVersion, definition.engine)) {\n return { kind: 'engine', range: definition.engine, coreVersion };\n }\n if (definition.transports && !definition.transports.includes(transport.name)) {\n return { kind: 'transport', expected: definition.transports, actual: transport.name };\n }\n const missing = missingCapabilities(transport, requiredCapabilities(definition));\n if (missing.length > 0) return { kind: 'capabilities', missing };\n for (const [dependency, range] of Object.entries(definition.dependsOn ?? {})) {\n const slot = byName.get(dependency);\n if (!slot) return { kind: 'dependency-missing', dependency };\n const { version } = slot.entry.definition;\n if (!satisfies(version, range)) {\n return { kind: 'dependency-version', dependency, range, version };\n }\n // A ordem topológica garante que a dependência já foi decidida.\n if (slot.report.status !== 'loaded') return { kind: 'dependency-skipped', dependency };\n }\n return undefined;\n }\n\n /** Contexto + `setup`. Em falha, desfaz o que o plugin registrou e devolve o motivo. */\n async function bringUp(slot: Slot): Promise<PluginReportEntry> {\n const { definition } = slot.entry;\n const base = reportBase(slot.entry);\n const created = await runPhase(definition.name, 'context', setupTimeoutMs, () =>\n createContext(definition),\n );\n if (!created.ok) return fail(base, created.error);\n const handle = created.value;\n // O declarado entra na fase do `setup`: um conflito de nome falha e desfaz como na forma longa.\n const setup = await runPhase(definition.name, 'setup', setupTimeoutMs, () => {\n installDeclared(definition, handle.context);\n return definition.setup?.(handle.context);\n });\n if (!setup.ok) {\n // Sem teardown: ele pareia com um setup que terminou. O dispose limpa o registro parcial.\n const disposed = await runPhase(definition.name, 'dispose', teardownTimeoutMs, () =>\n handle.dispose(setup.error),\n );\n if (!disposed.ok) logLifecycleError(disposed.error);\n return fail(base, setup.error);\n }\n slot.handle = handle;\n return { ...base, status: 'loaded' };\n }\n\n function fail(\n base: ReturnType<typeof reportBase>,\n error: PluginLifecycleError,\n ): PluginReportEntry {\n logLifecycleError(error);\n return { ...base, status: 'skipped', reason: { kind: 'setup-failed', error } };\n }\n\n /** `teardown` (se houver) e `dispose`, sempre os dois; devolve as falhas. */\n async function bringDown(slot: Slot, signal?: AbortSignal): Promise<PluginLifecycleError[]> {\n const { handle } = slot;\n if (!handle) return [];\n slot.handle = undefined;\n const { definition } = slot.entry;\n const errors: PluginLifecycleError[] = [];\n if (definition.teardown && signal?.aborted) {\n errors.push(\n new PluginLifecycleError(\n definition.name,\n 'teardown',\n 'não executado: prazo de parada do bot esgotado',\n true,\n ),\n );\n } else if (definition.teardown) {\n const teardown = definition.teardown.bind(definition);\n const result = await runPhase(\n definition.name,\n 'teardown',\n teardownTimeoutMs,\n () => teardown(handle.context),\n signal,\n );\n if (!result.ok) errors.push(result.error);\n }\n const disposed = await runPhase(definition.name, 'dispose', teardownTimeoutMs, () =>\n handle.dispose(),\n );\n if (!disposed.ok) errors.push(disposed.error);\n for (const error of errors) logLifecycleError(error);\n return errors;\n }\n\n function logLifecycleError(error: PluginLifecycleError): void {\n log.error(error.message, {\n plugin: error.plugin,\n phase: error.phase,\n timedOut: error.timedOut,\n err: error.cause ?? error,\n });\n }\n\n function logTable(entries: PluginReportEntry[]): void {\n const fields = {\n plugins: entries.map((entry) => ({\n name: entry.name,\n version: entry.version,\n origin: entry.origin,\n status: entry.status,\n ...(entry.status === 'skipped' ? { reason: describeSkipReason(entry.reason) } : {}),\n })),\n };\n const anySkipped = entries.some((entry) => entry.status === 'skipped');\n // Plugin ignorado é configuração a revisar: warn chama atenção sem ser falha do bot.\n if (anySkipped) log.warn(formatBootTable(entries), fields);\n else log.info(formatBootTable(entries), fields);\n }\n\n /** Erros de boot: manifesto, nome repetido e ciclo. Lança antes de qualquer setup. */\n function plan(): Slot[] {\n const origins = new Map<string, string[]>();\n for (const { definition, origin } of options.plugins) {\n assertPluginDefinition(definition, origin);\n origins.set(definition.name, [...(origins.get(definition.name) ?? []), origin]);\n }\n for (const [name, found] of origins) {\n if (found.length > 1) throw new PluginConflictError(name, found);\n }\n const order = sortPlugins(options.plugins.map((entry) => entry.definition));\n const entryOf = new Map(options.plugins.map((entry) => [entry.definition, entry]));\n return order.map((definition) => {\n const entry = entryOf.get(definition) as PluginEntry;\n return { entry, report: { ...reportBase(entry), status: 'loaded' }, handle: undefined };\n });\n }\n\n async function runStart(): Promise<PluginReportEntry[]> {\n try {\n slots = plan();\n } catch (error) {\n state = 'stopped';\n throw error;\n }\n for (const slot of slots) byName.set(slot.entry.definition.name, slot);\n for (const name of disabled) {\n if (!byName.has(name)) {\n log.warn(`disabledPlugins cita \"${name}\", que não existe entre os plugins`, {\n plugin: name,\n });\n }\n }\n for (const slot of slots) {\n const reason = incompatibility(slot.entry.definition);\n slot.report = reason\n ? { ...reportBase(slot.entry), status: 'skipped', reason }\n : await bringUp(slot);\n }\n const table = slots.map((slot) => slot.report);\n logTable(table);\n if (state === 'starting') state = 'running';\n return table;\n }\n\n async function runStop(signal?: AbortSignal): Promise<PluginLifecycleError[]> {\n state = 'stopping';\n const errors: PluginLifecycleError[] = [];\n // Ordem inversa: quem subiu depois pode usar serviços de quem subiu antes.\n for (const slot of slots.toReversed()) errors.push(...(await bringDown(slot, signal)));\n state = 'stopped';\n return errors;\n }\n\n async function runReload(name: string): Promise<PluginReloadResult> {\n if (state !== 'running') {\n throw new PluginHostStateError(`reload(\"${name}\"): host em \"${state}\"`);\n }\n const slot = byName.get(name);\n if (!slot) throw new PluginHostStateError(`reload(\"${name}\"): plugin desconhecido`);\n const { report } = slot;\n if (report.status === 'skipped' && report.reason.kind !== 'setup-failed') {\n throw new PluginHostStateError(\n `reload(\"${name}\"): plugin ignorado (${describeSkipReason(report.reason)}); ` +\n 'só recarrega plugin carregado ou cujo setup falhou',\n );\n }\n // Quem guardou um serviço do plugin no `setup` ficaria com a instância do contexto\n // descartado: o subgrafo de dependentes desce e sobe junto (ADR 0041).\n const affected = withDependents(slot);\n const errors: PluginLifecycleError[] = [];\n for (const each of affected.toReversed()) errors.push(...(await bringDown(each)));\n for (const each of affected) {\n // O próprio plugin não passa por `incompatibility`: o motivo estático dele não muda, e\n // um `setup-failed` anterior precisa de uma nova tentativa.\n const reason = each === slot ? undefined : incompatibility(each.entry.definition);\n each.report = reason\n ? { ...reportBase(each.entry), status: 'skipped', reason }\n : await bringUp(each);\n }\n const dependents = affected.slice(1).map((each) => each.report);\n log.info(\n `plugin \"${name}\" recarregado: ${slot.report.status === 'loaded' ? 'carregado' : 'ignorado'}`,\n {\n plugin: name,\n status: slot.report.status,\n ...(dependents.length > 0 && {\n dependents: dependents.map((entry) => ({ name: entry.name, status: entry.status })),\n }),\n },\n );\n return { entry: slot.report, dependents, errors };\n }\n\n /**\n * O slot e quem depende dele por `dependsOn`, direta ou transitivamente, na ordem de carga.\n * `after` só ordena: quem o usa não pega nada do outro plugin, então não entra.\n */\n function withDependents(root: Slot): Slot[] {\n const names = new Set([root.entry.definition.name]);\n // Na ordem topológica, toda dependência aparece antes do dependente: uma passada basta.\n return slots.filter((each) => {\n if (each === root) return true;\n const dependsOn = Object.keys(each.entry.definition.dependsOn ?? {});\n if (!dependsOn.some((dependency) => names.has(dependency))) return false;\n names.add(each.entry.definition.name);\n return true;\n });\n }\n\n return {\n get state(): PluginHostState {\n return state;\n },\n\n start(): Promise<PluginReportEntry[]> {\n if (state !== 'idle') {\n return Promise.reject(new PluginHostStateError(`start(): host em \"${state}\"`));\n }\n state = 'starting';\n return enqueue(runStart);\n },\n\n stop(signal?: AbortSignal): Promise<PluginLifecycleError[]> {\n if (state === 'idle') {\n state = 'stopped';\n stopPromise = Promise.resolve([]);\n }\n stopPromise ??= enqueue(() => runStop(signal));\n return stopPromise;\n },\n\n reload(name: string): Promise<PluginReloadResult> {\n return enqueue(() => runReload(name));\n },\n\n report(): PluginReportEntry[] {\n return slots.map((slot) => slot.report);\n },\n };\n}\n","import { existsSync } from 'node:fs';\nimport { readdir } from 'node:fs/promises';\nimport { extname, join, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { PluginDefinition } from './types.ts';\n\n/**\n * Plugin a carregar e de onde veio. As duas fontes (ADR 0007) produzem a mesma `definition`;\n * `origin` só serve para mensagens de erro e para a tabela de boot.\n */\nexport interface PluginEntry {\n readonly definition: PluginDefinition;\n /** `'config'` para a lista da config; caminho absoluto do módulo para `pluginDirs`. */\n readonly origin: string;\n}\n\n/** Falha ao ler uma pasta de plugins ou importar um módulo dela. Erro no boot. */\nexport class PluginDiscoveryError extends Error {\n override readonly name = 'PluginDiscoveryError';\n readonly path: string;\n\n constructor(path: string, message: string, cause?: unknown) {\n super(`pluginDirs: ${message} (${path})`, { cause });\n this.path = path;\n }\n}\n\nconst MODULE_EXTENSIONS = ['.ts', '.mts', '.js', '.mjs'];\n\n/** Arquivos que convivem na pasta sem serem plugin: testes, tipos e helpers com `_`/`.`. */\nfunction isIgnored(name: string): boolean {\n return (\n name.startsWith('.') ||\n name.startsWith('_') ||\n name.endsWith('.d.ts') ||\n name.endsWith('.d.mts') ||\n /\\.(test|spec)\\.[cm]?[jt]s$/.test(name)\n );\n}\n\n/**\n * Duck typing de propósito: o core instalado no app pode ser outra cópia que a do plugin.\n * `commands` ou `on` contam como o `setup`: o plugin só declarativo não tem `setup` (ADR 0079).\n */\nconst looksLikePlugin = (value: unknown): value is PluginDefinition => {\n if (typeof value !== 'object' || value === null) return false;\n const { name, setup, commands, on } = value as Record<string, unknown>;\n return (\n typeof name === 'string' && (typeof setup === 'function' || isObject(commands) || isObject(on))\n );\n};\n\nconst isObject = (value: unknown): boolean => typeof value === 'object' && value !== null;\n\n/** Módulo da entrada da pasta: o próprio arquivo, ou o `index.*` de uma subpasta. */\nasync function moduleOf(dir: string, entry: { name: string; isDirectory(): boolean }) {\n const path = join(dir, entry.name);\n if (entry.isDirectory()) {\n const index = MODULE_EXTENSIONS.map((ext) => join(path, `index${ext}`)).find((candidate) =>\n existsSync(candidate),\n );\n if (index === undefined) {\n throw new PluginDiscoveryError(\n path,\n 'subpasta sem index.ts/index.js; para a pasta não ser lida como plugin, prefixe com \"_\"',\n );\n }\n return index;\n }\n return MODULE_EXTENSIONS.includes(extname(entry.name)) ? path : undefined;\n}\n\n/**\n * Descobre os plugins de uma pasta. Convenção: cada arquivo `.ts`/`.mts`/`.js`/`.mjs` e cada\n * subpasta com `index.*` é um módulo que exporta (export nomeado) um ou mais plugins; todo\n * export com `name` string e `setup` função (ou `commands`/`on`) entra. Ficam de fora nomes\n * começando com `_` ou `.`, testes e `.d.ts`. A ordem é a alfabética dos nomes — nunca a do\n * sistema de arquivos — e um módulo sem plugin é erro, porque quase sempre é engano.\n */\nexport async function discoverPlugins(dir: string): Promise<PluginEntry[]> {\n let entries: { name: string; isDirectory(): boolean }[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (cause) {\n throw new PluginDiscoveryError(dir, 'não foi possível ler a pasta', cause);\n }\n entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));\n\n const found: PluginEntry[] = [];\n for (const entry of entries) {\n if (isIgnored(entry.name)) continue;\n const path = await moduleOf(dir, entry);\n if (path === undefined) continue;\n let namespace: Record<string, unknown>;\n try {\n namespace = (await import(pathToFileURL(path).href)) as Record<string, unknown>;\n } catch (cause) {\n throw new PluginDiscoveryError(path, 'falha ao importar o módulo', cause);\n }\n // O mesmo plugin pode sair por dois exports (ex.: nomeado e default): conta uma vez.\n const plugins = new Set(Object.values(namespace).filter(looksLikePlugin));\n if (plugins.size === 0) {\n throw new PluginDiscoveryError(path, 'o módulo não exporta nenhum plugin (definePlugin)');\n }\n for (const definition of plugins) found.push({ definition, origin: path });\n }\n return found;\n}\n\nexport interface CollectPluginsOptions {\n /** Plugins instanciados na config (ex.: pacotes npm que o app importa). */\n readonly plugins?: readonly PluginDefinition[];\n /** Pastas varridas por `discoverPlugins`, relativas a `cwd`. */\n readonly pluginDirs?: readonly string[];\n /** Base dos caminhos relativos de `pluginDirs`. Padrão: `process.cwd()`. */\n readonly cwd?: string;\n}\n\n/** Junta as duas fontes: primeiro a lista da config, depois cada pasta na ordem dada. */\nexport async function collectPlugins(options: CollectPluginsOptions): Promise<PluginEntry[]> {\n const entries: PluginEntry[] = (options.plugins ?? []).map((definition) => ({\n definition,\n origin: 'config',\n }));\n const cwd = options.cwd ?? process.cwd();\n for (const dir of options.pluginDirs ?? []) {\n entries.push(...(await discoverPlugins(resolve(cwd, dir))));\n }\n return entries;\n}\n","// Fila de entrada por chat (veio da fila por chat do legacy). Mesmo chat em série — sem race no\n// histórico/estado da conversa —, chats distintos em paralelo, sem bloqueio global.\n\n/** Trabalho de uma mensagem. Pode ser síncrono ou assíncrono. */\nexport type InboundTask = () => unknown;\n\n/**\n * Resultado de `enqueue`. `'queued'`: aceita (iniciada ou na fila). `'full'`: o backlog do chat\n * está no limite e a tarefa foi descartada. `'closed'`: a fila foi fechada (shutdown).\n */\nexport type EnqueueResult = 'queued' | 'full' | 'closed';\n\nexport interface InboundQueueOptions {\n /** Destino de todo erro lançado por uma tarefa. A fila segue para a próxima tarefa do chat. */\n readonly onError: (error: unknown, chatId: string) => void;\n /**\n * Máximo de tarefas aguardando por chat, sem contar a que está rodando. Ao exceder, a nova\n * tarefa é rejeitada (`'full'`). Padrão: 100. `Infinity` desliga o limite.\n */\n readonly maxPendingPerChat?: number;\n}\n\n/** Fotografia das métricas da fila. Leitura O(1): os contadores são mantidos incrementalmente. */\nexport interface InboundQueueStats {\n /** Chats com tarefa rodando (e possivelmente outras aguardando). */\n readonly activeChats: number;\n /** Tarefas aguardando em todos os chats, sem contar as que estão rodando. */\n readonly pending: number;\n /** Tarefas concluídas, com sucesso ou erro. */\n readonly processed: number;\n /** Tarefas rejeitadas (`'full'` ou `'closed'`), nunca executadas. */\n readonly dropped: number;\n /** Tarefas que lançaram erro (subconjunto de `processed`). */\n readonly errors: number;\n}\n\nconst DEFAULT_MAX_PENDING_PER_CHAT = 100;\n\nexport class InboundQueue {\n readonly #onError: (error: unknown, chatId: string) => void;\n readonly #maxPending: number;\n // Um chat só tem entrada enquanto há tarefa rodando; o runner a remove ao esvaziar, então o\n // Map nunca acumula chats ociosos (o vazamento do rateLimiter do legacy).\n readonly #chats = new Map<string, InboundTask[]>();\n #idleWaiters: (() => void)[] = [];\n #closed = false;\n #pending = 0;\n #processed = 0;\n #dropped = 0;\n #errors = 0;\n\n constructor(options: InboundQueueOptions) {\n const max = options.maxPendingPerChat ?? DEFAULT_MAX_PENDING_PER_CHAT;\n if (!(max === Number.POSITIVE_INFINITY || (Number.isInteger(max) && max >= 0))) {\n throw new RangeError(\n `maxPendingPerChat deve ser inteiro >= 0 ou Infinity (recebido: ${max})`,\n );\n }\n this.#onError = options.onError;\n this.#maxPending = max;\n }\n\n /**\n * Agenda `task` no chat. Se o chat está ocioso, a tarefa começa já, de forma síncrona; senão\n * aguarda as anteriores. Nunca lança nem rejeita: erros da tarefa vão para `onError`.\n */\n enqueue(chatId: string, task: InboundTask): EnqueueResult {\n if (this.#closed) {\n this.#dropped++;\n return 'closed';\n }\n const waiting = this.#chats.get(chatId);\n if (waiting === undefined) {\n const fresh: InboundTask[] = [];\n this.#chats.set(chatId, fresh);\n void this.#run(chatId, fresh, task);\n return 'queued';\n }\n if (waiting.length >= this.#maxPending) {\n this.#dropped++;\n return 'full';\n }\n waiting.push(task);\n this.#pending++;\n return 'queued';\n }\n\n /** Tarefas aguardando no chat, sem contar a que está rodando. */\n pendingFor(chatId: string): number {\n return this.#chats.get(chatId)?.length ?? 0;\n }\n\n stats(): InboundQueueStats {\n return {\n activeChats: this.#chats.size,\n pending: this.#pending,\n processed: this.#processed,\n dropped: this.#dropped,\n errors: this.#errors,\n };\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n\n /** Resolve quando não há tarefa rodando nem aguardando. Não impede novas tarefas. */\n onIdle(): Promise<void> {\n if (this.#chats.size === 0) return Promise.resolve();\n return new Promise((resolve) => this.#idleWaiters.push(resolve));\n }\n\n /**\n * Shutdown gracioso: para de aceitar tarefas (novas viram `'closed'`) e resolve quando as já\n * aceitas terminarem. Com `drain: false`, descarta as que aguardam (contam em `dropped`); as\n * que já rodam terminam. Pode ser chamado de novo com `drain: false` para abortar uma drenagem.\n */\n close(options: { readonly drain?: boolean } = {}): Promise<void> {\n this.#closed = true;\n if (options.drain === false) {\n for (const waiting of this.#chats.values()) {\n this.#dropped += waiting.length;\n this.#pending -= waiting.length;\n waiting.length = 0;\n }\n }\n return this.onIdle();\n }\n\n async #run(chatId: string, waiting: InboundTask[], first: InboundTask): Promise<void> {\n let task: InboundTask | undefined = first;\n while (task !== undefined) {\n try {\n await task();\n } catch (error) {\n this.#errors++;\n this.#report(error, chatId);\n }\n this.#processed++;\n task = waiting.shift();\n if (task !== undefined) this.#pending--;\n }\n this.#chats.delete(chatId);\n if (this.#chats.size === 0 && this.#idleWaiters.length > 0) {\n const waiters = this.#idleWaiters;\n this.#idleWaiters = [];\n for (const resolve of waiters) resolve();\n }\n }\n\n #report(error: unknown, chatId: string): void {\n try {\n this.#onError(error, chatId);\n } catch (handlerError) {\n // Bug no próprio onError: não há outro destino seguro sem logger, então vira exceção não\n // capturada (fora do runner, para não travar a fila do chat) em vez de sumir.\n queueMicrotask(() => {\n throw new AggregateError(\n [handlerError, error],\n `onError da InboundQueue lançou (chat ${chatId})`,\n );\n });\n }\n }\n}\n","// Escopo de tenant do bot (ADR 0072). O kernel roda cada mensagem e evento cujo chat tem\n// `tenantId` dentro deste escopo, e o storage do plugin lê dele o tenant corrente. Assim o mesmo\n// `ctx.storage` serve ao handler, à closure do `setup`, ao service de outro plugin e ao timer\n// disparado no handler, sem o plugin repassar nada: o isolamento não depende da disciplina dele.\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\n/** Um por bot (ADR 0004: nada global); dois bots no processo não veem o tenant um do outro. */\nexport class TenantScope {\n readonly #store = new AsyncLocalStorage<string | undefined>();\n\n /** Tenant do trabalho corrente, ou `undefined` fora de um (setup, timer solto, sem tenant). */\n get current(): string | undefined {\n return this.#store.getStore();\n }\n\n /**\n * Roda `fn` no escopo de `tenant`; `undefined` sai de qualquer escopo, para o trabalho sem\n * tenant não herdar o de quem o disparou (o loop do scheduler acordado por um handler, por\n * exemplo). Sem troca de escopo, chama direto: a mensagem sem tenant não paga nada.\n */\n run<R>(tenant: string | undefined, fn: () => R): R {\n if (this.#store.getStore() === tenant) return fn();\n return this.#store.run(tenant, fn);\n }\n}\n","// Scheduler do bot (M1-11, plano §6.8). Um serviço por bot: os jobs de todos os plugins ficam\n// numa única coleção do namespace do kernel (`$scheduler`), e um único timer fica armado para o\n// próximo horário. Nada de polling: sem job futuro, nenhum timer existe.\n//\n// Entrega \"pelo menos uma vez\": o documento só sai do storage depois que o handler termina.\n// Se o processo cair no meio, o job continua lá e dispara de novo ao subir.\n\nimport { ContextExpiredError, Deadline, JobTimeoutError } from '#deadline.ts';\nimport type { PluginErrorEvent } from '#events/types.ts';\nimport { kernelStorage } from '#storage/namespace.ts';\nimport type { Collection, JsonValue, StoragePort, Where, WithId } from '#storage/types.ts';\nimport { TenantScope } from '#tenant/scope.ts';\nimport type { Unsubscribe } from '#transport/types.ts';\nimport type { JobContext, JobHandler, Scheduler } from './types.ts';\n\nexport const DEFAULT_JOB_TIMEOUT_MS = 30_000;\nexport const DEFAULT_STORAGE_RETRY_MS = 5000;\nexport const DEFAULT_MAX_CONCURRENT_JOBS = 10;\n\n/** Vencidos lidos por consulta: a leitura é paginada, nunca a coleção inteira na memória. */\nconst DUE_PAGE_SIZE = 100;\n\n/**\n * Maior atraso que o `setTimeout` aceita (~24,8 dias). Acima disso o Node dispara em 1 ms; job\n * mais distante arma o teto e, ao acordar, o loop só recalcula e rearma.\n */\nconst MAX_TIMER_DELAY_MS = 2_147_483_647;\n\n/** Documento de um agendamento. `type` (não `interface`) para casar com o JSON da coleção. */\ntype JobDocument = {\n plugin: string;\n job: string;\n /** Epoch ms. Indexado: é por ele que o loop consulta. */\n fireAt: number;\n payload: JsonValue;\n /** Tenant de quem agendou (ADR 0072); o handler roda no escopo dele. Ausente: sem tenant. */\n tenant?: string;\n};\n\ntype StoredJob = WithId<JobDocument>;\n\ninterface RegisteredHandler {\n readonly handler: JobHandler;\n /** `Deadline` de vida do plugin: pai do `Deadline` de cada execução do handler. */\n readonly lifetime: Deadline | undefined;\n}\n\nexport interface SchedulerServiceOptions {\n /** Storage do bot; os jobs ficam em `kernelStorage(storage, 'scheduler')`. */\n readonly storage: StoragePort;\n /**\n * Destino de toda falha de handler (lançou, rejeitou ou estourou o prazo), com\n * `phase: 'scheduler'` e o nome do job em `event`. Não deve lançar.\n */\n readonly onError: (error: PluginErrorEvent) => void;\n /**\n * Destino da rejeição de um handler que chegou depois do prazo, já reportado como timeout\n * pelo `onError`: normalmente só o log, para não virar um segundo `plugin.error`. Padrão:\n * `onError`. Não deve lançar.\n */\n readonly onLateError?: (error: PluginErrorEvent) => void;\n /**\n * Destino das falhas do próprio storage (consulta do loop, remoção depois do handler). O loop\n * não morre: tenta de novo após `storageRetryMs`. Não deve lançar.\n */\n readonly onStorageError: (error: unknown) => void;\n /**\n * Escopo de tenant do bot (ADR 0072): `at` guarda o tenant corrente no job, e o handler roda\n * no escopo dele. Padrão: um escopo próprio, sem tenant.\n */\n readonly tenants?: TenantScope;\n /** Prazo de cada handler em ms. Padrão: 30000. */\n readonly jobTimeoutMs?: number;\n /** Espera antes de reconsultar o storage depois de uma falha, em ms. Padrão: 5000. */\n readonly storageRetryMs?: number;\n /**\n * Máximo de handlers rodando ao mesmo tempo, somando todos os plugins. Os vencidos além dele\n * esperam vaga, em ordem de `fireAt` (depois de um downtime longo, nada de milhares de handlers\n * de uma vez). Padrão: 10.\n */\n readonly maxConcurrentJobs?: number;\n}\n\nexport interface SchedulerService {\n /**\n * Scheduler em nome do plugin (`ctx.scheduler`): jobs e handlers no namespace dele. Com\n * `lifetime` (o `Deadline` de vida do plugin), o descarte do plugin aborta o `signal` dos jobs\n * dele ainda em andamento.\n */\n forPlugin(plugin: string, lifetime?: Deadline): Scheduler;\n /**\n * Remove os handlers do plugin (teardown e reload). Os jobs persistidos ficam: disparam\n * quando o plugin registrar o handler de novo.\n */\n removePlugin(plugin: string): void;\n /** Liga o loop: dispara o que venceu (inclusive durante o downtime) e arma o próximo. */\n start(): void;\n /**\n * Desarma o timer e espera os handlers em andamento (cada um limitado pelo prazo de job).\n * Abortado o `signal`, abandona os que ainda rodam: o `signal` do job aborta, o prazo dele é\n * desarmado e o documento fica no storage, para disparar de novo na próxima subida. Depois\n * dele não sobra timer vivo. Idempotente.\n */\n stop(signal?: AbortSignal): Promise<void>;\n}\n\n/** Dois handlers para o mesmo job do mesmo plugin: o job seria consumido por um só. */\nexport class JobHandlerConflictError extends Error {\n override readonly name = 'JobHandlerConflictError';\n readonly plugin: string;\n readonly job: string;\n\n constructor(plugin: string, job: string) {\n super(\n `O plugin \"${plugin}\" já registrou um handler para o job \"${job}\". Cada job tem um ` +\n 'handler; cancele o anterior (a função devolvida por on) antes de registrar outro.',\n );\n this.plugin = plugin;\n this.job = job;\n }\n}\n\nfunction validTimeout(name: string, value: number): number {\n // setTimeout trata Infinity/NaN como 1 ms: tudo estouraria na hora.\n if (!Number.isFinite(value) || value <= 0) throw new RangeError(`${name} inválido: ${value}`);\n return value;\n}\n\nfunction toEpoch(when: Date | number): number {\n const ms = when instanceof Date ? when.getTime() : when;\n if (typeof ms !== 'number' || !Number.isFinite(ms)) {\n throw new TypeError(`Horário inválido para o job: ${String(when)}. Use Date ou epoch ms.`);\n }\n return ms;\n}\n\nfunction assertJobName(job: unknown): asserts job is string {\n if (typeof job !== 'string' || job === '') {\n throw new TypeError('Nome de job deve ser texto não vazio.');\n }\n}\n\n/**\n * Recusa o que o JSON perderia ou alteraria em silêncio (`undefined`, `NaN`, `Date`, `Map`,\n * classes, ciclos): o handler tem de receber exatamente o payload agendado.\n */\nfunction assertJsonValue(value: unknown, path: string, seen: Set<object>): void {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return;\n if (typeof value === 'number') {\n if (Number.isFinite(value)) return;\n throw new TypeError(`Payload inválido em ${path}: ${value} não é JSON.`);\n }\n if (typeof value !== 'object') {\n throw new TypeError(`Payload inválido em ${path}: ${typeof value} não é JSON.`);\n }\n if (seen.has(value)) throw new TypeError(`Payload inválido em ${path}: referência circular.`);\n seen.add(value);\n if (Array.isArray(value)) {\n value.forEach((item, i) => {\n assertJsonValue(item, `${path}[${i}]`, seen);\n });\n } else {\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) {\n throw new TypeError(`Payload inválido em ${path}: só objetos simples são JSON.`);\n }\n for (const [key, item] of Object.entries(value)) assertJsonValue(item, `${path}.${key}`, seen);\n }\n seen.delete(value);\n}\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n value !== null &&\n (typeof value === 'object' || typeof value === 'function') &&\n typeof (value as PromiseLike<unknown>).then === 'function'\n );\n}\n\nexport function createSchedulerService(options: SchedulerServiceOptions): SchedulerService {\n const { onError, onStorageError } = options;\n const onLateError = options.onLateError ?? onError;\n const tenants = options.tenants ?? new TenantScope();\n const jobTimeoutMs = validTimeout('jobTimeoutMs', options.jobTimeoutMs ?? DEFAULT_JOB_TIMEOUT_MS);\n const retryMs = validTimeout(\n 'storageRetryMs',\n options.storageRetryMs ?? DEFAULT_STORAGE_RETRY_MS,\n );\n const maxConcurrent = options.maxConcurrentJobs ?? DEFAULT_MAX_CONCURRENT_JOBS;\n if (!Number.isInteger(maxConcurrent) || maxConcurrent < 1) {\n throw new RangeError(`maxConcurrentJobs inválido: ${maxConcurrent}`);\n }\n const jobs: Collection<JobDocument> = kernelStorage(options.storage, 'scheduler').collection(\n 'jobs',\n { indexes: ['fireAt'] },\n );\n\n // plugin → job → handler (com o `Deadline` de vida do plugin que o registrou).\n const handlers = new Map<string, Map<string, RegisteredHandler>>();\n // id → handler em andamento (resolve quando o job saiu do storage). Impede entrega dupla\n // enquanto o handler roda e responde ao `cancel` de job já disparado.\n const inFlight = new Map<string, Promise<void>>();\n // id → abandono do handler em andamento, usado pelo `stop` abortado.\n const abandons = new Map<string, (reason: unknown) => void>();\n\n let started = false;\n let timer: NodeJS.Timeout | undefined;\n let armedAt: number | undefined;\n // Volta do loop em andamento; `rerun` pede outra volta quando algo mudou durante a atual.\n let loop: Promise<void> | undefined;\n let rerun = false;\n // A última volta parou por falta de vaga: quando um handler termina, o loop roda de novo.\n let backlog = false;\n // Uma remoção falhou: a volta nesse horário reentrega o job (pelo menos uma vez).\n let retryAt: number | undefined;\n\n // Exclusão mútua entre \"ler os vencidos e despachar\" e `cancel`: sem ela, um `cancel` poderia\n // apagar o job depois da leitura e antes do despacho, devolver `true` e o job disparar mesmo\n // assim.\n let lock: Promise<unknown> = Promise.resolve();\n function exclusive<T>(fn: () => Promise<T>): Promise<T> {\n const result = lock.then(fn);\n lock = result.catch(() => undefined);\n return result;\n }\n\n function disarm(): void {\n clearTimeout(timer);\n timer = undefined;\n armedAt = undefined;\n }\n\n function arm(at: number): void {\n disarm();\n const delay = Math.min(Math.max(at - Date.now(), 0), MAX_TIMER_DELAY_MS);\n armedAt = at;\n timer = setTimeout(() => {\n timer = undefined;\n armedAt = undefined;\n wake();\n }, delay);\n }\n\n /** Pede uma volta do loop; se já há uma rodando, ela repete ao terminar. */\n function wake(): void {\n if (!started) return;\n if (loop !== undefined) {\n rerun = true;\n return;\n }\n disarm();\n loop = (async () => {\n do {\n rerun = false;\n await tick();\n } while (rerun && started);\n })().finally(() => {\n loop = undefined;\n });\n }\n\n /**\n * Filtro dos jobs que têm handler, ou `undefined` sem nenhum. Sem ele, os órfãos (plugin\n * desligado, job renomeado) seriam relidos do storage a cada volta, e o custo de cada disparo\n * cresceria com o lixo acumulado (#228). Como `Where` só combina campos com E, o filtro é o\n * produto `plugin × job`: um órfão só passa se outro plugin tiver handler com o mesmo nome de\n * job, e o `dispatch` o pula.\n */\n function withHandler(): Where<JobDocument> | undefined {\n if (handlers.size === 0) return undefined;\n const names = new Set<string>();\n for (const byJob of handlers.values()) for (const job of byJob.keys()) names.add(job);\n return { plugin: { in: [...handlers.keys()] }, job: { in: [...names] } };\n }\n\n async function tick(): Promise<void> {\n const now = Date.now();\n // Esta volta já reentrega o que a remoção não tirou do storage.\n retryAt = undefined;\n let next: number | undefined;\n try {\n await exclusive(() => dispatchDue(now));\n // Job sem handler não arma timer: espera o `on` do plugin, que acorda o loop.\n const filter = withHandler();\n const [upcoming] =\n filter === undefined\n ? []\n : await jobs.find({\n where: { ...filter, fireAt: { gt: now } },\n orderBy: 'fireAt',\n limit: 1,\n });\n next = upcoming?.fireAt;\n } catch (error) {\n onStorageError(error);\n next = Date.now() + retryMs;\n }\n if (retryAt !== undefined && (next === undefined || retryAt < next)) next = retryAt;\n if (started && !rerun && next !== undefined) arm(next);\n }\n\n /**\n * Despacha os vencidos com handler em ordem de `fireAt` até acabarem as vagas, lendo uma\n * página por vez. Os que estão em andamento não ocupam vaga e são pulados pelo `offset`, para\n * não travarem os de trás (no máximo `maxConcurrent` deles). Se um handler terminar no meio da varredura e o `offset` pular um\n * vencido, a volta extra que esse término pede (`wake`) o encontra.\n */\n async function dispatchDue(now: number): Promise<void> {\n backlog = false;\n const filter = withHandler();\n if (filter === undefined) return;\n for (let offset = 0; started; offset += DUE_PAGE_SIZE) {\n const page = await jobs.find({\n where: { ...filter, fireAt: { lte: now } },\n orderBy: 'fireAt',\n limit: DUE_PAGE_SIZE,\n offset,\n });\n for (const doc of page) {\n if (!started) return;\n if (inFlight.size >= maxConcurrent) {\n backlog = true;\n return;\n }\n dispatch(doc);\n }\n if (page.length < DUE_PAGE_SIZE) return;\n }\n }\n\n function dispatch(doc: StoredJob): void {\n if (inFlight.has(doc.id)) return;\n const registered = handlers.get(doc.plugin)?.get(doc.job);\n // Órfão que passou pelo filtro (ver `withHandler`): fica pendente no storage.\n if (registered === undefined) return;\n const done = run(doc, registered)\n // Abandonado no shutdown, o job não terminou: fica no storage para a próxima subida.\n .then(async (finished) => {\n if (finished) await jobs.delete(doc.id);\n return finished;\n })\n .then(\n (removed) => removed,\n (error: unknown) => {\n onStorageError(error);\n // O job ficou no storage: uma volta depois do retry o entrega de novo, mesmo sem outro\n // evento que acorde o loop. Uma volta em curso também respeita `retryAt` ao rearmar.\n const at = Date.now() + retryMs;\n retryAt = Math.min(retryAt ?? at, at);\n if (started && (armedAt === undefined || at < armedAt)) arm(at);\n return false;\n },\n )\n .then((removed) => {\n inFlight.delete(doc.id);\n // Vaga liberada com vencidos esperando, ou varredura em curso que pode ter pulado um\n // (o `offset` anda, e a remoção puxou a fila uma posição).\n if (removed && (backlog || loop !== undefined)) wake();\n });\n inFlight.set(doc.id, done);\n }\n\n function fail(doc: StoredJob, error: unknown, timedOut: boolean): void {\n onError({ plugin: doc.plugin, phase: 'scheduler', event: doc.job, error, timedOut });\n }\n\n /**\n * Roda o handler contra o prazo e resolve `false` só se ele foi abandonado no `stop`. Nunca\n * rejeita: toda falha já foi entregue ao `onError`. Estourado o prazo (ou abandonado), o\n * `signal` do job aborta (ADR 0033).\n */\n function run(doc: StoredJob, { handler, lifetime }: RegisteredHandler): Promise<boolean> {\n const deadline = new Deadline(lifetime);\n const job: JobContext = {\n get signal(): AbortSignal {\n return deadline.signal;\n },\n };\n let result: unknown;\n try {\n // O job sem tenant sai de qualquer escopo: o loop pode ter sido acordado no handler de um.\n result = tenants.run(doc.tenant, () => handler(doc.payload, job));\n } catch (error) {\n fail(doc, error, false);\n return Promise.resolve(true);\n }\n if (!isThenable(result)) return Promise.resolve(true);\n return new Promise<boolean>((resolve) => {\n let settled = false;\n const settle = (finished: boolean): void => {\n settled = true;\n clearTimeout(timeout);\n abandons.delete(doc.id);\n resolve(finished);\n };\n const timeout = setTimeout(() => {\n const error = new JobTimeoutError(doc.plugin, doc.job, jobTimeoutMs);\n settle(true);\n deadline.expire(error);\n fail(doc, error, true);\n }, jobTimeoutMs);\n abandons.set(doc.id, (reason) => {\n settle(false);\n deadline.expire(reason);\n });\n result.then(\n () => {\n if (!settled) settle(true);\n },\n (error: unknown) => {\n if (!settled) {\n settle(true);\n fail(doc, error, false);\n return;\n }\n // Rejeição depois do prazo: já reportado como timeout; o erro tardio vai só ao\n // `onLateError`. A recusa de um contexto expirado já foi logada (ADR 0033).\n if (error instanceof ContextExpiredError) return;\n onLateError({\n plugin: doc.plugin,\n phase: 'scheduler',\n event: doc.job,\n error,\n timedOut: false,\n });\n },\n );\n });\n }\n\n function forPlugin(plugin: string, lifetime?: Deadline): Scheduler {\n return {\n async at(when, job, payload = null) {\n const fireAt = toEpoch(when);\n assertJobName(job);\n assertJsonValue(payload, 'payload', new Set());\n const tenant = tenants.current;\n const id = await jobs.insert({\n plugin,\n job,\n fireAt,\n payload,\n ...(tenant !== undefined && { tenant }),\n });\n if (started) {\n if (loop !== undefined) rerun = true;\n else if (armedAt === undefined || fireAt < armedAt) arm(fireAt);\n }\n return id;\n },\n\n cancel(id) {\n return exclusive(async () => {\n // Já disparou: o handler está rodando e o job sai do storage quando ele terminar.\n if (inFlight.has(id)) return false;\n return (await jobs.delete({ id, plugin })) > 0;\n });\n },\n\n on(job, handler): Unsubscribe {\n assertJobName(job);\n if (typeof handler !== 'function') throw new TypeError(`Handler de \"${job}\" não é função`);\n let byJob = handlers.get(plugin);\n if (byJob === undefined) {\n byJob = new Map();\n handlers.set(plugin, byJob);\n }\n if (byJob.has(job)) throw new JobHandlerConflictError(plugin, job);\n const registered: RegisteredHandler = { handler, lifetime };\n byJob.set(job, registered);\n // Pode haver jobs vencidos esperando por este handler.\n wake();\n return () => {\n const current = handlers.get(plugin);\n if (current?.get(job) !== registered) return;\n current.delete(job);\n if (current.size === 0) handlers.delete(plugin);\n };\n },\n };\n }\n\n return {\n forPlugin,\n\n removePlugin(plugin) {\n handlers.delete(plugin);\n },\n\n start() {\n if (started) return;\n started = true;\n wake();\n },\n\n async stop(signal) {\n started = false;\n disarm();\n const abandon = (): void => {\n for (const fn of abandons.values()) fn(signal?.reason);\n };\n if (signal?.aborted) abandon();\n else signal?.addEventListener('abort', abandon, { once: true });\n await loop;\n // Um `at` pode ter rearmado enquanto o loop terminava; nada pode sobrar vivo.\n disarm();\n await Promise.all(inFlight.values());\n },\n };\n}\n","import type { ServiceAccess, ServiceName, Services } from './types.ts';\n\n/** Serviço registrado com o plugin que o proveu. */\nexport interface ProvidedService {\n readonly plugin: string;\n readonly name: string;\n readonly service: unknown;\n}\n\n/** `get` de um serviço que nenhum plugin carregado provê. */\nexport class ServiceNotFoundError extends Error {\n override readonly name = 'ServiceNotFoundError';\n readonly service: string;\n /** Plugin que pediu o serviço. */\n readonly requestedBy: string;\n\n constructor(service: string, requestedBy: string) {\n super(\n `Serviço \"${service}\" não encontrado (pedido pelo plugin \"${requestedBy}\"): nenhum ` +\n `plugin carregado o provê. Declare em \"${requestedBy}\" o \\`dependsOn\\` do plugin que ` +\n `provê \"${service}\", para que ele carregue (e chame \\`provide\\`) antes.`,\n );\n this.service = service;\n this.requestedBy = requestedBy;\n }\n}\n\n/** Dois `provide` com o mesmo nome. Lançado no `setup`, isto é, no boot. */\nexport class ServiceConflictError extends Error {\n override readonly name = 'ServiceConflictError';\n readonly service: string;\n readonly existing: string;\n readonly incoming: string;\n\n constructor(service: string, existing: string, incoming: string) {\n super(\n existing === incoming\n ? `Serviço \"${service}\" provido duas vezes pelo plugin \"${incoming}\". Cada serviço é ` +\n `provido uma vez por setup; para trocar a implementação, recarregue o plugin.`\n : `Conflito de serviço \"${service}\": o plugin \"${incoming}\" tenta prover um serviço ` +\n `que o plugin \"${existing}\" já provê. Desabilite um dos dois ou renomeie o serviço.`,\n );\n this.service = service;\n this.existing = existing;\n this.incoming = incoming;\n }\n}\n\nexport interface ServiceRegistry {\n /** O `ctx.services` do plugin: `provide` atribui a ele, e os erros o citam. */\n forPlugin(plugin: string): ServiceAccess;\n /** Remove os serviços que o plugin proveu (teardown e reload). */\n removePlugin(plugin: string): void;\n list(): ProvidedService[];\n}\n\n/** Um registry por bot: nada global, então dois bots no mesmo processo não se enxergam. */\nexport function createServiceRegistry(): ServiceRegistry {\n // Chave string: em runtime o core não conhece os nomes, que só existem no type-level.\n const byName = new Map<string, ProvidedService>();\n\n return {\n forPlugin(plugin) {\n return {\n provide<K extends ServiceName>(name: K, service: Services[K]): void {\n const existing = byName.get(name);\n // Re-prover é erro mesmo no próprio plugin: quem já fez `get` guardaria a instância\n // antiga sem saber. Trocar a implementação passa por teardown + setup (reload).\n if (existing) throw new ServiceConflictError(name, existing.plugin, plugin);\n byName.set(name, { plugin, name, service });\n },\n\n get<K extends ServiceName>(name: K): Services[K] {\n const entry = byName.get(name);\n if (!entry) throw new ServiceNotFoundError(name, plugin);\n // O tipo foi garantido no `provide`, que só aceita `Services[K]` para o nome K.\n return entry.service as Services[K];\n },\n\n has(name) {\n return byName.has(name);\n },\n };\n },\n\n removePlugin(plugin) {\n for (const [name, entry] of byName) {\n if (entry.plugin === plugin) byName.delete(name);\n }\n },\n\n list() {\n return [...byName.values()];\n },\n };\n}\n","// Adapter em memória do StoragePort: referência executável da semântica do contrato, usado em\n// testes e no M1-16. Guarda tudo como texto JSON — como os adapters reais —, então o que entra\n// e o que sai são sempre cópias, sem aliasing com objetos do plugin. Cada chamada de\n// `createMemoryStorage` tem dados próprios (nenhum estado de módulo).\n\nimport { randomUUID } from 'node:crypto';\nimport { StorageClosedError } from './errors.ts';\nimport {\n type NormalizedCondition,\n type NormalizedSort,\n normalizeDocument,\n normalizeIndexes,\n normalizeQuery,\n normalizeWhere,\n} from './query.ts';\nimport type {\n AuthKeyData,\n AuthStateStore,\n Collection,\n FindQuery,\n JsonObject,\n JsonValue,\n KeyValueStore,\n Patch,\n PluginStorage,\n Scalar,\n StoragePort,\n Target,\n WithId,\n} from './types.ts';\n\n// id → documento em JSON. A ordem de inserção do Map é a ordem de desempate do contrato, e\n// `Map.set` numa chave existente (update) não muda a posição.\ntype Documents = Map<string, string>;\n\ninterface NamespaceData {\n readonly kv: Map<string, string>;\n readonly collections: Map<string, Documents>;\n}\n\ninterface SessionData {\n creds: string | undefined;\n readonly keys: Map<string, Map<string, string>>;\n}\n\ninterface Row {\n readonly id: string;\n readonly doc: JsonObject;\n}\n\nfunction serialize(value: unknown): string {\n const text = JSON.stringify(value);\n if (text === undefined) throw new TypeError('Valor não serializável em JSON.');\n return text;\n}\n\nfunction parse<T>(text: string): T {\n return JSON.parse(text) as T;\n}\n\nfunction fieldValue(row: Row, field: string): JsonValue {\n if (field === 'id') return row.id;\n // Campo ausente vale null, igual ao `json_extract`/`->>` dos adapters SQL.\n return Object.hasOwn(row.doc, field) ? (row.doc[field] as JsonValue) : null;\n}\n\n// Igualdade estrita de tipo e valor: o adapter SQLite precisa conferir `json_type`, porque\n// `json_extract` devolve `true` como 1.\nfunction equals(value: JsonValue, operand: Scalar): boolean {\n if (operand === null) return value === null;\n return typeof value === typeof operand && value === operand;\n}\n\n// Ordem de code point (= ordem de bytes UTF-8, a do SQLite BINARY e do Postgres COLLATE \"C\").\n// O `<` do JS compara unidades UTF-16 e erra quando um lado é surrogate.\nfunction compareStrings(a: string, b: string): number {\n if (a === b) return 0;\n const length = Math.min(a.length, b.length);\n for (let i = 0; i < length; i++) {\n if (a.charCodeAt(i) !== b.charCodeAt(i)) {\n return (a.codePointAt(i) as number) - (b.codePointAt(i) as number);\n }\n }\n return a.length - b.length;\n}\n\nfunction compareOrdered(value: JsonValue, operand: string | number): number | undefined {\n if (typeof value === 'number' && typeof operand === 'number') return value - operand;\n if (typeof value === 'string' && typeof operand === 'string') {\n return compareStrings(value, operand);\n }\n return undefined;\n}\n\nfunction matches(row: Row, conditions: readonly NormalizedCondition[]): boolean {\n return conditions.every((condition) => {\n const value = fieldValue(row, condition.field);\n switch (condition.op) {\n case 'eq':\n return equals(value, condition.value);\n case 'ne':\n return !equals(value, condition.value);\n case 'in':\n return condition.value.some((operand) => equals(value, operand));\n default: {\n const diff = compareOrdered(value, condition.value);\n if (diff === undefined) return false;\n if (condition.op === 'gt') return diff > 0;\n if (condition.op === 'gte') return diff >= 0;\n if (condition.op === 'lt') return diff < 0;\n return diff <= 0;\n }\n }\n });\n}\n\n// null/ausente < booleano < número < texto < array/objeto (iguais entre si).\nfunction typeRank(value: JsonValue): number {\n if (value === null) return 0;\n if (typeof value === 'boolean') return 1;\n if (typeof value === 'number') return 2;\n if (typeof value === 'string') return 3;\n return 4;\n}\n\nfunction compareValues(a: JsonValue, b: JsonValue): number {\n const rank = typeRank(a) - typeRank(b);\n if (rank !== 0) return rank;\n if (typeof a === 'boolean') return Number(a) - Number(b);\n if (typeof a === 'number') return a - (b as number);\n if (typeof a === 'string') return compareStrings(a, b as string);\n return 0;\n}\n\nfunction sortRows(rows: Row[], sorts: readonly NormalizedSort[]): Row[] {\n if (sorts.length === 0) return rows;\n // `Array.prototype.sort` é estável: empates mantêm a ordem de inserção.\n return rows.sort((a, b) => {\n for (const { field, direction } of sorts) {\n const diff = compareValues(fieldValue(a, field), fieldValue(b, field));\n if (diff !== 0) return direction === 'asc' ? diff : -diff;\n }\n return 0;\n });\n}\n\n/** Cria um StoragePort em memória, com dados próprios e descartados no `close()`. */\nexport function createMemoryStorage(): StoragePort {\n const namespaces = new Map<string, NamespaceData>();\n const sessions = new Map<string, SessionData>();\n let closed = false;\n\n function ensureOpen(): void {\n if (closed) throw new StorageClosedError();\n }\n\n function namespaceData(namespace: string): NamespaceData {\n let data = namespaces.get(namespace);\n if (data === undefined) {\n data = { kv: new Map(), collections: new Map() };\n namespaces.set(namespace, data);\n }\n return data;\n }\n\n function documents(namespace: string, name: string): Documents {\n const { collections } = namespaceData(namespace);\n let docs = collections.get(name);\n if (docs === undefined) {\n docs = new Map();\n collections.set(name, docs);\n }\n return docs;\n }\n\n function sessionData(session: string): SessionData {\n let data = sessions.get(session);\n if (data === undefined) {\n data = { creds: undefined, keys: new Map() };\n sessions.set(session, data);\n }\n return data;\n }\n\n function createKv(namespace: string): KeyValueStore {\n return {\n async get<T extends JsonValue = JsonValue>(key: string): Promise<T | undefined> {\n ensureOpen();\n const text = namespaceData(namespace).kv.get(key);\n return text === undefined ? undefined : parse<T>(text);\n },\n async set(key: string, value: JsonValue): Promise<void> {\n ensureOpen();\n namespaceData(namespace).kv.set(key, serialize(value));\n },\n async delete(key: string): Promise<boolean> {\n ensureOpen();\n return namespaceData(namespace).kv.delete(key);\n },\n };\n }\n\n function createCollection<T extends { readonly [key: string]: JsonValue }>(\n namespace: string,\n name: string,\n ): Collection<T> {\n function rows(): Row[] {\n return [...documents(namespace, name)].map(([id, text]) => ({ id, doc: parse(text) }));\n }\n\n function targetRows(target: Target<T>): Row[] {\n if (typeof target === 'string') {\n const text = documents(namespace, name).get(target);\n return text === undefined ? [] : [{ id: target, doc: parse(text) }];\n }\n const conditions = normalizeWhere(target);\n return rows().filter((row) => matches(row, conditions));\n }\n\n return {\n async insert(document: T): Promise<string> {\n ensureOpen();\n const text = serialize(normalizeDocument(document));\n const id = randomUUID();\n documents(namespace, name).set(id, text);\n return id;\n },\n async get(id: string): Promise<WithId<T> | undefined> {\n ensureOpen();\n const text = documents(namespace, name).get(id);\n return text === undefined ? undefined : { ...parse<T>(text), id };\n },\n async find(query?: FindQuery<T>): Promise<WithId<T>[]> {\n ensureOpen();\n const { where, orderBy, limit, offset } = normalizeQuery(query);\n const found = sortRows(\n rows().filter((row) => matches(row, where)),\n orderBy,\n );\n const end = limit === undefined ? undefined : offset + limit;\n return found.slice(offset, end).map((row) => ({ ...(row.doc as T), id: row.id }));\n },\n async update(target: Target<T>, patch: Patch<T>): Promise<number> {\n ensureOpen();\n const changes = normalizeDocument(patch);\n const docs = documents(namespace, name);\n const targets = targetRows(target);\n for (const row of targets) docs.set(row.id, serialize({ ...row.doc, ...changes }));\n return targets.length;\n },\n async delete(target: Target<T>): Promise<number> {\n ensureOpen();\n const docs = documents(namespace, name);\n const targets = targetRows(target);\n for (const row of targets) docs.delete(row.id);\n return targets.length;\n },\n };\n }\n\n function createPluginStorage(namespace: string): PluginStorage {\n return {\n kv: createKv(namespace),\n collection<T extends { readonly [key: string]: JsonValue }>(\n name: string,\n options?: Parameters<PluginStorage['collection']>[1],\n ): Collection<T> {\n // Índice não muda o resultado em memória; validar mantém o erro igual ao dos outros\n // adapters, que criam o índice de verdade.\n normalizeIndexes(options);\n return createCollection<T>(namespace, name);\n },\n };\n }\n\n function createAuthState(session: string): AuthStateStore {\n return {\n async getCreds(): Promise<JsonValue | undefined> {\n ensureOpen();\n const text = sessionData(session).creds;\n return text === undefined ? undefined : parse(text);\n },\n async setCreds(creds: JsonValue): Promise<void> {\n ensureOpen();\n sessionData(session).creds = serialize(creds);\n },\n async getKeys(type: string, ids: readonly string[]): Promise<Record<string, JsonValue>> {\n ensureOpen();\n const stored = sessionData(session).keys.get(type);\n const result: Record<string, JsonValue> = {};\n if (stored === undefined) return result;\n for (const id of ids) {\n const text = stored.get(id);\n if (text !== undefined) result[id] = parse(text);\n }\n return result;\n },\n async setKeys(data: AuthKeyData): Promise<void> {\n ensureOpen();\n // Serializa o lote inteiro antes de aplicar: um valor inválido no meio não deixa o\n // lote pela metade (o equivalente da transação dos adapters SQL).\n const batch = Object.entries(data).map(\n ([type, entries]) =>\n [\n type,\n Object.entries(entries).map(\n ([id, value]) => [id, value === null ? null : serialize(value)] as const,\n ),\n ] as const,\n );\n const { keys } = sessionData(session);\n for (const [type, entries] of batch) {\n let stored = keys.get(type);\n if (stored === undefined) {\n stored = new Map();\n keys.set(type, stored);\n }\n for (const [id, text] of entries) {\n if (text === null) stored.delete(id);\n else stored.set(id, text);\n }\n }\n },\n async clear(): Promise<void> {\n ensureOpen();\n sessions.delete(session);\n },\n };\n }\n\n return {\n forNamespace(namespace: string): PluginStorage {\n return createPluginStorage(namespace);\n },\n authState(session: string): AuthStateStore {\n return createAuthState(session);\n },\n async close(): Promise<void> {\n closed = true;\n namespaces.clear();\n sessions.clear();\n },\n };\n}\n","// Fábrica do escape hatch `ctx.unsafe` (M1-15, ADR 0011; `raw` no ADR 0066).\n\nimport type { Logger } from '#logger/types.ts';\nimport type { Message } from '#message/types.ts';\nimport type { PluginManifest } from '#plugin/types.ts';\nimport type { Interaction, Transport } from '#transport/types.ts';\nimport type { Unsafe } from './types.ts';\n\nexport interface UnsafeAccessOptions {\n /**\n * Só `name` (vai no aviso), `native` (lido a cada acesso) e `raw` (consultado a cada chamada)\n * são usados.\n */\n readonly transport: Pick<Transport, 'name' | 'native' | 'raw'>;\n readonly log: Logger;\n /**\n * A interação de onde o kernel montou a mensagem (clique ou comando nativo). O transport nunca\n * viu essa `Message`, então o `raw` pergunta a ele pela interação. Ausente: nenhuma mensagem\n * vem de interação.\n */\n readonly interactionOf?: (message: Message) => Interaction | undefined;\n}\n\n/** Fábrica de `Unsafe` de um bot; guarda quais plugins já foram avisados. */\nexport interface UnsafeAccess {\n /**\n * `Unsafe` do plugin. Pode ser chamado várias vezes para o mesmo plugin (ex.: um por\n * contexto de mensagem): o aviso continua saindo uma vez só por plugin.\n */\n forPlugin(manifest: Pick<PluginManifest, 'name' | 'transports'>): Unsafe;\n}\n\n/** O que o plugin acessou; cada um avisa uma vez, para o log medir os dois usos (ADR 0011). */\ntype Accessor = 'native' | 'raw';\n\n/**\n * Uma por instância de bot. O registro de \"já avisou\" mora aqui, e não em cada `Unsafe` nem em\n * escopo de módulo: assim o aviso sai uma vez por plugin mesmo com vários `Unsafe` do mesmo\n * plugin, e dois bots no mesmo processo não silenciam um ao outro.\n */\nexport function createUnsafeAccess(options: UnsafeAccessOptions): UnsafeAccess {\n const { transport, log, interactionOf } = options;\n const warned = new Set<string>();\n\n function warnOnce(manifest: Pick<PluginManifest, 'name' | 'transports'>, what: Accessor): void {\n const id = `${what}:${manifest.name}`;\n if (warned.has(id)) return;\n warned.add(id);\n const fields = { plugin: manifest.name, transport: transport.name };\n const access = what === 'native' ? 'ctx.unsafe.native' : 'ctx.unsafe.raw()';\n // Sem `transports` no manifesto o plugin se diz portável, mas ao ler o objeto nativo ele\n // passa a depender deste transport (ADR 0011). Não bloqueamos: o aviso deixa isso visível.\n if (manifest.transports === undefined) {\n log.warn(\n `plugin \"${manifest.name}\" acessou ${access} sem declarar transports no manifesto; ` +\n `ele fica preso ao transport \"${transport.name}\" (declare transports: ['${transport.name}'])`,\n fields,\n );\n return;\n }\n log.warn(\n `plugin \"${manifest.name}\" acessou ${access} do transport \"${transport.name}\"`,\n fields,\n );\n }\n\n return {\n forPlugin(manifest) {\n return {\n // Getter, não valor copiado: o objeto nativo pode ser trocado a cada reconexão.\n get native(): unknown {\n warnOnce(manifest, 'native');\n return transport.native;\n },\n raw(message) {\n warnOnce(manifest, 'raw');\n // Só aqui, sob demanda: o caminho da mensagem não paga nada por o plugin poder pedir.\n return transport.raw?.(interactionOf?.(message) ?? message);\n },\n };\n },\n };\n}\n","import type { MessageAction } from '#actions/actions.ts';\nimport type { Message } from '#message/types.ts';\nimport type { MessageText } from '#text/format.ts';\nimport type { MessageKey, OutgoingAction, OutgoingContent } from '#transport/types.ts';\nimport { captionFields, textContent } from './text.ts';\nimport type {\n OutboundSendOptions,\n Reply,\n ReplyOptions,\n ReplyTextOptions,\n Sender,\n} from './types.ts';\n\n/** Texto e botões que vão ao transport, depois de o kernel resolver as ações (ADR 0062). */\nexport interface PreparedActions {\n /** O texto, com o menu numerado no fim quando o transport não leva os botões. */\n readonly text: MessageText;\n readonly actions?: readonly OutgoingAction[];\n}\n\n/** Resolve as ações de uma resposta; lança `TypeError` com uma ação inválida. */\nexport type PrepareActions = (\n text: MessageText,\n actions: readonly MessageAction[],\n) => PreparedActions;\n\nexport interface CreateReplyOptions {\n /**\n * Cita a mensagem original. Padrão: `true`. Quem monta o contexto passa `false` quando o\n * transport não tem a capability `quoted`, para a resposta não falhar com `UnsupportedError`.\n */\n readonly quote?: boolean;\n /** Quem resolve `actions`. Sem ele, uma resposta com ações rejeita com `TypeError`. */\n readonly actions?: PrepareActions;\n}\n\n/**\n * Monta o `ctx.reply` de uma mensagem: envia no chat dela, citando-a, com prioridade `high`,\n * pelo `sender` (a fila de saída). O plugin não vê a fila — só chama `reply`.\n */\nexport function createReply(\n sender: Sender,\n message: Message,\n options: CreateReplyOptions = {},\n): Reply {\n const chatId = message.chat.id;\n const quoted = options.quote === false ? undefined : message;\n\n const send = (\n content: OutgoingContent,\n replyOptions: ReplyOptions = {},\n actions?: readonly OutgoingAction[],\n ): Promise<MessageKey> => {\n const sendOptions: OutboundSendOptions = {\n priority: replyOptions.priority ?? 'high',\n ...(quoted && { quoted }),\n ...(replyOptions.mentions && { mentions: replyOptions.mentions }),\n ...(actions && actions.length > 0 && { actions }),\n };\n return sender.send(chatId, content, sendOptions);\n };\n\n const sendText = (text: MessageText, o?: ReplyTextOptions): Promise<MessageKey> => {\n if (o?.actions === undefined || o.actions.length === 0) return send(textContent(text), o);\n let prepared: PreparedActions;\n try {\n if (options.actions === undefined) {\n throw new TypeError('reply: ações só no contexto de mensagem do bot');\n }\n prepared = options.actions(text, o.actions);\n } catch (error) {\n return Promise.reject(error);\n }\n return send(textContent(prepared.text), o, prepared.actions);\n };\n\n const shortcuts: Pick<Reply, keyof Reply> = {\n text: sendText,\n image: (media, o = {}) =>\n send({ type: 'image', media, ...captionFields(o.caption), ...pick(o, 'mimetype') }, o),\n video: (media, o = {}) =>\n send({ type: 'video', media, ...captionFields(o.caption), ...pick(o, 'mimetype') }, o),\n audio: (media, o = {}) => send({ type: 'audio', media, ...pick(o, 'mimetype') }, o),\n voice: (media, o = {}) => send({ type: 'voice', media, ...pick(o, 'mimetype') }, o),\n sticker: (media, o) => send({ type: 'sticker', media }, o),\n document: (media, o) =>\n send(\n {\n type: 'document',\n media,\n fileName: o.fileName,\n mimetype: o.mimetype,\n ...captionFields(o.caption),\n },\n o,\n ),\n album: (items, o = {}) => send({ type: 'album', items, ...captionFields(o.caption) }, o),\n poll: (name, choices, o = {}) =>\n send({ type: 'poll', name, options: choices, ...pick(o, 'multiple') }, o),\n };\n return Object.assign((text: MessageText, o?: ReplyTextOptions) => sendText(text, o), shortcuts);\n}\n\n/** `{ [key]: valor }` só quando definido, para não mandar `undefined` explícito ao transport. */\nfunction pick<T extends object, K extends keyof T>(source: T, key: K): Partial<Pick<T, K>> {\n const value = source[key];\n return value === undefined ? {} : ({ [key]: value } as Partial<Pick<T, K>>);\n}\n","// Contexto de mensagem do kernel (M1-16): o objeto que middlewares, roteador e listeners\n// recebem. `reply` e `log` são preguiçosos — a maioria das mensagens não responde nem loga, e o\n// caminho quente (§7 do plano) não deve alocar o que ninguém vai usar.\n\nimport type { BotMessageContext } from '#context.ts';\nimport type { ExpectReply, ExpectReplyOptions } from '#conversations/conversations.ts';\nimport { ContextExpiredError, DEADLINE, type Deadline, deadlineOf } from '#deadline.ts';\nimport type { MessageListenerFields } from '#events/types.ts';\nimport type { LogFields, Logger } from '#logger/types.ts';\nimport type { Message } from '#message/types.ts';\nimport type { SanitizedContext, SanitizedFields } from '#middleware/sanitize.ts';\nimport { createReply, type PrepareActions } from '#outbound/reply.ts';\nimport type { Outbound, Reply } from '#outbound/types.ts';\nimport type { JsonValue } from '#storage/types.ts';\nimport type { MessageKey } from '#transport/types.ts';\n\n/** O que o contexto precisa do bot; um objeto por bot, compartilhado por todas as mensagens. */\nexport interface MessageContextDeps {\n readonly sender: Outbound;\n /** Responder citando: só se o transport tem a capability `quoted`. */\n readonly quote: boolean;\n /** Logger raiz; o contexto cria o filho com `chatId` sob demanda. */\n readonly log: () => Logger;\n /**\n * Resolve as ações do `reply` (ADR 0062) em nome do plugin dono do contexto, ou de ninguém\n * (`null`) no contexto do kernel, que os middlewares veem.\n */\n readonly actions?: (owner: string | null, message: Message) => PrepareActions;\n}\n\n// Chave simbólica, não campo `#privado`: o roteador e os listeners recebem objetos derivados por\n// `Object.create(ctx)`, e campo privado não é alcançável pela cadeia de protótipos.\nconst STATE: unique symbol = Symbol('bridger.messageContext');\n\ninterface State {\n readonly deps: MessageContextDeps;\n reply: Reply | undefined;\n log: Logger | undefined;\n}\n\n/** O contexto concreto: o de mensagem do bot com o resultado do `sanitize`. */\nexport interface KernelMessageContext extends BotMessageContext, SanitizedContext {\n text: string | null;\n}\n\n/** Cria o contexto de uma mensagem; `reply` e `log` só existem quando lidos. */\nexport function createMessageContext(\n message: Message,\n deps: MessageContextDeps,\n): KernelMessageContext {\n return new MessageContextImpl(message, deps);\n}\n\nclass MessageContextImpl implements KernelMessageContext {\n readonly message: Message;\n text: string | null;\n /** Preenchido pelo middleware `sanitize`; declarado para manter a forma do objeto estável. */\n sanitized: SanitizedFields | undefined = undefined;\n readonly [STATE]: State;\n\n constructor(message: Message, deps: MessageContextDeps) {\n this.message = message;\n this.text = message.text;\n this[STATE] = { deps, reply: undefined, log: undefined };\n }\n\n get reply(): Reply {\n const state = this[STATE];\n state.reply ??= replyFor(state.deps, this.message, null);\n return state.reply;\n }\n\n get log(): Logger {\n const state = this[STATE];\n state.log ??= state.deps.log().child({ chatId: this.message.chat.id });\n return state.log;\n }\n\n react(emoji: string | null): Promise<void> {\n // Prioridade do `reply`: a reação responde a quem escreveu, como ele.\n return this[STATE].deps.sender.react(this.message.key, emoji, { priority: 'high' });\n }\n}\n\nfunction replyFor(deps: MessageContextDeps, message: Message, owner: string | null): Reply {\n return createReply(deps.sender, message, {\n quote: deps.quote,\n ...(deps.actions && { actions: deps.actions(owner, message) }),\n });\n}\n\n/**\n * O `reply` da mensagem em nome do plugin, para as ações de passo apontarem para os passos dele.\n * `undefined` fora do contexto do kernel (roteador usado solto).\n */\nfunction pluginReply(ctx: object, plugin: string): Reply | undefined {\n // O estado do contexto do kernel é alcançado pela cadeia de protótipos das visões.\n const state = (ctx as { readonly [STATE]?: State })[STATE];\n if (state === undefined) return undefined;\n return replyFor(state.deps, (ctx as { readonly message: Message }).message, plugin);\n}\n\n/**\n * Chave dos extras que o bot passa ao barramento nos eventos de mensagem. O barramento copia os\n * extras com `Object.assign`, que leria (e criaria) `reply` e `log`; com o contexto inteiro numa\n * chave só, cada listener resolve o que usar.\n */\nexport const KERNEL_CONTEXT: unique symbol = Symbol('bridger.kernelContext');\n\nexport interface WithKernelContext {\n readonly [KERNEL_CONTEXT]: KernelMessageContext;\n}\n\n/** Extras de `bus.emit` para um evento de mensagem. */\nexport function messageExtras(ctx: KernelMessageContext): WithKernelContext {\n return { [KERNEL_CONTEXT]: ctx };\n}\n\n/**\n * Descritores do `log` de um plugin: filho do logger do plugin com o `chatId` da mensagem, criado\n * no primeiro acesso e fixado no próprio objeto. Calculados uma vez por plugin.\n */\nfunction pluginLogDescriptor(pluginLog: Logger): PropertyDescriptor {\n return {\n configurable: true,\n get(this: { readonly message: Message }): Logger {\n const log = pluginLog.child({ chatId: this.message.chat.id });\n Object.defineProperty(this, 'log', { value: log });\n return log;\n },\n };\n}\n\nconst REPLY_METHODS = [\n 'text',\n 'image',\n 'video',\n 'audio',\n 'voice',\n 'sticker',\n 'document',\n 'album',\n 'poll',\n] as const satisfies readonly (keyof Reply)[];\n\n/** Recusa uma operação de um contexto expirado: loga e devolve a rejeição. */\ntype Refuse = (operation: string) => Promise<never>;\n\n/**\n * `reply` que confere o prazo a cada chamada — não só na leitura de `ctx.reply`: quem guardou a\n * função antes do prazo (`const r = ctx.reply`) também é recusado depois dele. No prazo, o envio\n * pausa o relógio até assentar (ADR 0047).\n */\nfunction expiringReply(reply: Reply, deadline: Deadline, refuse: Refuse): Reply {\n const guard =\n <A extends unknown[]>(operation: string, send: (...args: A) => Promise<MessageKey>) =>\n (...args: A): Promise<MessageKey> =>\n deadline.expired ? refuse(operation) : deadline.hold(send(...args));\n type AnySend = (...args: unknown[]) => Promise<MessageKey>;\n const shortcuts = Object.fromEntries(\n REPLY_METHODS.map((method) => [method, guard(`reply.${method}`, reply[method] as AnySend)]),\n ) as unknown as Pick<Reply, (typeof REPLY_METHODS)[number]>;\n return Object.assign(guard('reply', reply), shortcuts);\n}\n\ninterface ExpiringView {\n readonly [DEADLINE]?: Deadline;\n readonly log: Logger;\n}\n\ntype Scope<V> = (view: V) => { readonly label: string; readonly fields: LogFields };\n\n/** Recusa (com `ContextExpiredError` e uma linha de log) do que a `view` faz depois do prazo. */\nfunction refuser<V extends ExpiringView>(\n plugin: string,\n view: V,\n deadline: Deadline,\n scope: Scope<V>,\n): Refuse {\n return (operation) => {\n const { label, fields } = scope(view);\n const error = new ContextExpiredError(plugin, operation, label, deadline.reason);\n view.log.warn(`${operation} recusado: ${label} já expirou`, {\n ...fields,\n operation,\n err: error,\n });\n return Promise.reject(error);\n };\n}\n\n/**\n * Descritor do `reply` de uma execução com prazo (comando ou listener): o `reply` de `base`,\n * recusado com `ContextExpiredError` (e uma linha de log) depois que o `Deadline` expira — no\n * prazo, ou no descarte do plugin.\n * Criado no primeiro acesso e fixado no próprio objeto, como o `log`.\n */\nfunction expiringReplyDescriptor<V extends ExpiringView>(\n plugin: string,\n base: (view: V) => Reply | undefined,\n scope: Scope<V>,\n): PropertyDescriptor {\n return {\n configurable: true,\n get(this: V): Reply | undefined {\n const reply = base(this);\n const deadline = deadlineOf(this);\n if (reply === undefined || deadline === undefined) return reply;\n const guarded = expiringReply(reply, deadline, refuser(plugin, this, deadline, scope));\n Object.defineProperty(this, 'reply', { value: guarded });\n return guarded;\n },\n };\n}\n\ntype React = BotMessageContext['react'];\n\n/**\n * Descritor do `react` de uma execução com prazo: recusado depois dele e pausando o relógio no\n * prazo, como o `reply`.\n */\nfunction expiringReactDescriptor<V extends ExpiringView>(\n plugin: string,\n base: (view: V) => Pick<BotMessageContext, 'react'> | undefined,\n scope: Scope<V>,\n): PropertyDescriptor {\n return {\n configurable: true,\n get(this: V): React | undefined {\n const target = base(this);\n const deadline = deadlineOf(this);\n if (target === undefined || deadline === undefined) return target?.react;\n const refuse = refuser(plugin, this, deadline, scope);\n const react: React = (emoji) =>\n deadline.expired ? refuse('react') : deadline.hold(target.react(emoji));\n Object.defineProperty(this, 'react', { value: react });\n return react;\n },\n };\n}\n\n/** Registra uma espera em nome do plugin; o bot a liga ao registro de conversas (ADR 0060). */\nexport type PluginExpect = (message: Message, step: string, options?: ExpectReplyOptions) => void;\n\n/**\n * Descritor do `expectReply` de uma execução com prazo: a espera vale para o chat e o remetente\n * da mensagem, e é recusada (com `ContextExpiredError` e uma linha de log) depois do prazo, como\n * o `reply` — senão um handler que estourou registraria uma conversa que ninguém pediu.\n */\nfunction expectReplyDescriptor<V extends ExpiringView & { readonly message: Message }>(\n plugin: string,\n expect: PluginExpect,\n scope: Scope<V>,\n): PropertyDescriptor {\n return {\n configurable: true,\n get(this: V): ExpectReply {\n const deadline = deadlineOf(this);\n const expectReply: ExpectReply = (step, options) => {\n if (deadline?.expired) {\n const { label, fields } = scope(this);\n const error = new ContextExpiredError(plugin, 'expectReply', label, deadline.reason);\n this.log.warn(`expectReply recusado: ${label} já expirou`, {\n ...fields,\n operation: 'expectReply',\n err: error,\n });\n throw error;\n }\n expect(this.message, step, options);\n };\n Object.defineProperty(this, 'expectReply', { value: expectReply });\n return expectReply;\n },\n };\n}\n\nconst signalDescriptor: PropertyDescriptor = {\n get(this: ExpiringView): AbortSignal {\n return (deadlineOf(this) as Deadline).signal;\n },\n};\n\nexport interface CommandViews {\n /**\n * Contexto do `run` e do `onReject`: `log` do plugin, `signal` e `reply` presos ao `deadline`\n * da execução.\n */\n run<C extends object>(ctx: C, deadline: Deadline): C;\n}\n\n/**\n * Descritores comuns às execuções que respondem a uma mensagem (comando e passo): `log` do\n * plugin, `signal`, e `reply`, `react` e `expectReply` presos ao prazo.\n */\nfunction executionDescriptors<V extends ExpiringView & { readonly message: Message }>(\n plugin: string,\n pluginLog: Logger,\n expect: PluginExpect,\n scope: Scope<V>,\n): PropertyDescriptorMap {\n return {\n log: pluginLogDescriptor(pluginLog),\n signal: signalDescriptor,\n reply: expiringReplyDescriptor<V>(\n plugin,\n // O `reply` em nome do plugin ou, com o roteador solto, o do contexto recebido.\n (view) =>\n pluginReply(view, plugin) ??\n (Object.getPrototypeOf(view) as { readonly reply?: Reply }).reply,\n scope,\n ),\n react: expiringReactDescriptor<V>(\n plugin,\n (view) => {\n const base = Object.getPrototypeOf(view) as Partial<Pick<BotMessageContext, 'react'>>;\n return base.react === undefined ? undefined : (base as Pick<BotMessageContext, 'react'>);\n },\n scope,\n ),\n expectReply: expectReplyDescriptor<V>(plugin, expect, scope),\n };\n}\n\n/** Deriva os contextos de comando de um plugin. */\nexport function commandViewFactory(\n plugin: string,\n pluginLog: Logger,\n expect: PluginExpect,\n): CommandViews {\n type View = ExpiringView & { readonly command: string; readonly message: Message };\n const scope: Scope<View> = (view) => ({\n label: `comando \"${view.command}\"`,\n fields: { command: view.command },\n });\n const runDescriptors = executionDescriptors<View>(plugin, pluginLog, expect, scope);\n return {\n run(ctx, deadline) {\n const view = Object.create(ctx, runDescriptors) as { [DEADLINE]?: Deadline };\n view[DEADLINE] = deadline;\n return view as typeof ctx;\n },\n };\n}\n\n/**\n * Deriva, para os passos de conversa de um plugin, o contexto com `step`, `data` e os campos de\n * execução do comando (`log`, `signal`, `reply`, `react`, `expectReply`).\n */\nexport function stepViewFactory(\n plugin: string,\n pluginLog: Logger,\n expect: PluginExpect,\n): <C extends object>(ctx: C, deadline: Deadline, step: string, data: JsonValue) => C {\n type View = ExpiringView & { readonly step: string; readonly message: Message };\n const scope: Scope<View> = (view) => ({\n label: `passo \"${view.step}\"`,\n fields: { step: view.step },\n });\n const descriptors = executionDescriptors<View>(plugin, pluginLog, expect, scope);\n return (ctx, deadline, step, data) => {\n const view = Object.create(ctx, descriptors) as { [DEADLINE]?: Deadline };\n Object.assign(view, { step, data });\n view[DEADLINE] = deadline;\n return view as typeof ctx;\n };\n}\n\n/**\n * Deriva, para a checagem de um papel custom, a visão com o `log` do plugin dono do papel e o\n * `signal` preso ao `deadline` da checagem.\n */\nexport function roleViewFactory(\n pluginLog: Logger,\n): <C extends object>(ctx: C, deadline: Deadline) => C {\n const descriptors: PropertyDescriptorMap = {\n log: pluginLogDescriptor(pluginLog),\n signal: signalDescriptor,\n };\n return (ctx, deadline) => {\n const view = Object.create(ctx, descriptors) as { [DEADLINE]?: Deadline };\n view[DEADLINE] = deadline;\n return view as typeof ctx;\n };\n}\n\n/**\n * Deriva, para um listener de evento de mensagem, a visão com `message`, `text`, `reply`,\n * `react`, `expectReply` e `log` (do plugin). O objeto do barramento fica no protótipo: `claimed`/`claim()` seguem\n * compartilhados entre os listeners da emissão; o barramento pendura na visão o `Deadline` do\n * listener, que dá o `signal` e prende o `reply`.\n */\nexport function listenerViewFactory(\n plugin: string,\n pluginLog: Logger,\n expect: PluginExpect,\n): <C extends object>(ctx: C) => C {\n type View = Partial<WithKernelContext> &\n ExpiringView & {\n readonly payload: Message;\n readonly message: Message;\n readonly event: string;\n };\n const kernel = (view: View): KernelMessageContext | undefined => view[KERNEL_CONTEXT];\n const scope: Scope<View> = (view) => ({\n label: `listener de \"${view.event}\"`,\n fields: { event: view.event },\n });\n const descriptors: PropertyDescriptorMap = {\n message: {\n get(this: View): Message {\n return this.payload;\n },\n },\n text: {\n get(this: View): string | null {\n const ctx = kernel(this);\n return ctx === undefined ? this.payload.text : ctx.text;\n },\n },\n reply: expiringReplyDescriptor<View>(\n plugin,\n (view) => {\n const ctx = kernel(view);\n return ctx === undefined ? undefined : pluginReply(ctx, plugin);\n },\n scope,\n ),\n react: expiringReactDescriptor<View>(plugin, kernel, scope),\n expectReply: expectReplyDescriptor<View>(plugin, expect, scope),\n log: pluginLogDescriptor(pluginLog),\n } satisfies Record<keyof MessageListenerFields, PropertyDescriptor>;\n return (ctx) => Object.create(ctx, descriptors);\n}\n","// Storage do plugin com escopo de tenant (ADR 0072): cada operação vai ao namespace do tenant\n// corrente (`<plugin>@<tenant>`) ou, sem tenant, ao do plugin, como antes. A escolha é feita na\n// chamada, não na criação: uma coleção obtida no `setup` grava no tenant do handler que a usa.\n\nimport type { TenantScope } from '#tenant/scope.ts';\nimport { assertTenantId, pluginStorage } from './namespace.ts';\nimport type {\n Collection,\n CollectionOptions,\n JsonValue,\n KeyValueStore,\n PluginStorage,\n StoragePort,\n} from './types.ts';\n\n/** `ctx.storage`: o storage do tenant corrente, mais a escolha explícita de um tenant. */\nexport interface TenantStorage extends PluginStorage {\n /**\n * Storage de um tenant escolhido pelo plugin, fora do escopo corrente: no `setup`, num job sem\n * tenant ou num plugin de administração que atende vários. Lança `TypeError` com ID vazio.\n */\n forTenant(tenantId: string): PluginStorage;\n}\n\n/**\n * `ctx.storage`: o da sessão do bot e, em `shared`, o comum a todas as sessões que dividem o\n * storage (ADR 0075). Os dois seguem o tenant corrente.\n */\nexport interface PluginContextStorage extends TenantStorage {\n /**\n * Dados do plugin comuns a todos os bots no mesmo storage (WhatsApp, Telegram, web...). Os IDs\n * de contato e de chat só são únicos dentro de um transport: componha a chave com\n * `ctx.transportName` quando ela vier de um ID.\n */\n readonly shared: TenantStorage;\n}\n\n/**\n * Storage do plugin que segue o `scope`. Os storages por tenant ficam em cache (as coleções do\n * adapter criam o índice na primeira operação de cada objeto); o número de tenants de um bot é o\n * de clientes do dono, não o de usuários.\n */\nexport function tenantStorage(\n port: StoragePort,\n pluginName: string,\n scope: TenantScope,\n): TenantStorage {\n const base = pluginStorage(port, pluginName);\n const byTenant = new Map<string, PluginStorage>();\n const forTenant = (tenant: string): PluginStorage => {\n let storage = byTenant.get(tenant);\n if (storage === undefined) {\n storage = pluginStorage(port, pluginName, tenant);\n byTenant.set(tenant, storage);\n }\n return storage;\n };\n const current = (): PluginStorage => {\n const tenant = scope.current;\n return tenant === undefined ? base : forTenant(tenant);\n };\n\n const kv: KeyValueStore = {\n get: <T extends JsonValue = JsonValue>(key: string) => current().kv.get<T>(key),\n set: (key: string, value: JsonValue) => current().kv.set(key, value),\n delete: (key: string) => current().kv.delete(key),\n };\n return {\n kv,\n collection<T extends { readonly [key: string]: JsonValue }>(\n name: string,\n options?: CollectionOptions,\n ): Collection<T> {\n // Valida o nome e as opções já aqui, como o adapter faz: o erro sai no `setup`, não na\n // primeira mensagem.\n const untenanted = base.collection<T>(name, options);\n const collections = new Map<PluginStorage, Collection<T>>([[base, untenanted]]);\n const resolve = (): Collection<T> => {\n const storage = current();\n let collection = collections.get(storage);\n if (collection === undefined) {\n collection = storage.collection<T>(name, options);\n collections.set(storage, collection);\n }\n return collection;\n };\n type C = Collection<T>;\n return {\n insert: (document) => resolve().insert(document),\n get: (id) => resolve().get(id),\n find: (query?: Parameters<C['find']>[0]) => resolve().find(query),\n update: (target, patch) => resolve().update(target, patch),\n delete: (target) => resolve().delete(target),\n };\n },\n forTenant(tenantId) {\n assertTenantId(tenantId);\n return forTenant(tenantId);\n },\n };\n}\n","// Fábrica do `PluginContext` (M1-16): liga cada campo do contexto ao serviço do bot, sempre em\n// nome do plugin, e desfaz tudo no `dispose`. É a única peça que conhece todos os serviços; o\n// host de plugins só recebe a fábrica.\n\nimport { commandInfo } from '#commands/catalog.ts';\nimport type { CommandContext, CommandDefinition } from '#commands/command.ts';\nimport type { Prefixes } from '#commands/prefixes.ts';\nimport { type RoleCheck, RoleTimeoutError } from '#commands/roles.ts';\nimport type { CommandRouter } from '#commands/router.ts';\nimport { BotConfigError } from '#config/owners.ts';\nimport type { PluginConfigs } from '#config/plugin-configs.ts';\nimport {\n type ConversationRegistry,\n type KernelStep,\n type StepContext,\n type StepHandler,\n StepTimeoutError,\n} from '#conversations/conversations.ts';\nimport {\n type ArmedTimers,\n ContextExpiredError,\n Deadline,\n ExecutionTimeoutError,\n isThenable,\n settleWithin,\n} from '#deadline.ts';\nimport type { EventBus } from '#events/bus.ts';\nimport type { BotEventName, EventSubscriber, PluginErrorEvent } from '#events/types.ts';\nimport type { Groups } from '#groups/groups.ts';\nimport type { SessionHttp } from '#http/server.ts';\nimport type { HttpRoutes } from '#http/types.ts';\nimport type { Logger } from '#logger/types.ts';\nimport type { Contact } from '#message/types.ts';\nimport type { Outbound } from '#outbound/types.ts';\nimport { type PluginContextFactory, PluginHostStateError } from '#plugin/host.ts';\nimport type { PluginContext } from '#plugin/types.ts';\nimport type { SchedulerService } from '#scheduler/service.ts';\nimport type { Scheduler } from '#scheduler/types.ts';\nimport type { ServiceRegistry } from '#services/registry.ts';\nimport type { ServiceAccess } from '#services/types.ts';\nimport { type PluginContextStorage, type TenantStorage, tenantStorage } from '#storage/tenant.ts';\nimport type {\n Collection,\n CollectionOptions,\n JsonValue,\n KeyValueStore,\n PluginStorage,\n StoragePort,\n} from '#storage/types.ts';\nimport type { TenantScope } from '#tenant/scope.ts';\nimport { isFormatted } from '#text/format.ts';\nimport type { Capability } from '#transport/capabilities.ts';\nimport type { Unsubscribe } from '#transport/types.ts';\nimport type { UnsafeAccess } from '#unsafe/access.ts';\nimport {\n type CommandViews,\n commandViewFactory,\n type KernelMessageContext,\n listenerViewFactory,\n type PluginExpect,\n roleViewFactory,\n stepViewFactory,\n} from './message-context.ts';\n\nexport interface PluginContextDeps {\n readonly configs: PluginConfigs;\n readonly log: Logger;\n readonly router: CommandRouter;\n readonly prefixes: Prefixes;\n /** Passos e esperas de conversa (ADR 0060). */\n readonly conversations: ConversationRegistry<KernelMessageContext>;\n readonly bus: EventBus;\n readonly services: ServiceRegistry;\n readonly storage: StoragePort;\n /** Storage comum às sessões (ADR 0075), de onde sai o `ctx.storage.shared`. */\n readonly shared: StoragePort;\n /** Tenant corrente (ADR 0072): o `ctx.storage` do plugin grava no namespace dele. */\n readonly tenants: TenantScope;\n readonly scheduler: SchedulerService;\n readonly send: Outbound;\n readonly groups: Groups;\n /** Rotas da sessão no servidor HTTP; ausente sem `http` na config do bot (ADR 0076). */\n readonly http: SessionHttp | undefined;\n /** Falha de uma rota ou WebSocket do plugin (`phase: 'http'`). */\n readonly onHttpError: (event: PluginErrorEvent) => void;\n /** Nome, capabilities e contato da sessão, lidos do transport a cada acesso. */\n readonly transport: {\n readonly name: string;\n readonly capabilities: ReadonlySet<Capability>;\n readonly self: Contact | null;\n };\n readonly unsafe: UnsafeAccess;\n /** Prazo do `run` e do `onReject` de cada comando, em ms (ADR 0005). */\n readonly commandTimeoutMs: number;\n /** Destino da rejeição de um `run` que chegou depois do prazo (já reportado como timeout). */\n readonly onLateCommandError: (plugin: string, command: string, error: unknown) => void;\n /** Checagem de papel custom que lançou, rejeitou ou estourou o prazo (`phase: 'role'`). */\n readonly onRoleError: (event: PluginErrorEvent) => void;\n /** Prazos armados de comandos e papéis, para o shutdown desarmá-los. */\n readonly armed: ArmedTimers;\n}\n\n/** Parte do comando que roda código de plugin com prazo. */\nexport type CommandStage = 'run' | 'onReject';\n\n/**\n * O `run` ou o `onReject` de um comando estourou o prazo. Vai em `plugin.error` com\n * `timedOut: true`.\n */\nexport class CommandTimeoutError extends ExecutionTimeoutError {\n override readonly name: string = 'CommandTimeoutError';\n readonly command: string;\n readonly stage: CommandStage;\n\n constructor(plugin: string, command: string, timeoutMs: number, stage: CommandStage = 'run') {\n super(\n plugin,\n stage === 'run' ? `comando \"${command}\"` : `onReject do comando \"${command}\"`,\n timeoutMs,\n );\n this.command = command;\n this.stage = stage;\n }\n}\n\n/** Eventos cujo payload é uma `Message`: os listeners deles recebem os campos de mensagem. */\nexport function isMessageEvent(event: BotEventName): boolean {\n return event === 'message' || event === 'message.edited' || event.startsWith('message:');\n}\n\nexport function createPluginContextFactory(deps: PluginContextDeps): PluginContextFactory {\n return async (plugin) => {\n const { name } = plugin;\n // Lança `PluginConfigError` com config inválida: o host ignora o plugin (ADR 0032).\n const { config, messages } = await deps.configs.resolve(name);\n const log = deps.log.child({ plugin: name });\n\n // Um `setup` que estourou o prazo segue rodando em segundo plano (não há como abortá-lo).\n // Depois do `dispose`, tudo o que ele registrar ficaria órfão e todo efeito (envio,\n // storage, agendamento) viria de um plugin que já desceu: o contexto recusa, e o `signal`\n // dele aborta (ADR 0033). Comandos, papéis, listeners e jobs ainda em andamento têm\n // `Deadline` filho deste: o `dispose` os expira junto (#200).\n const lifetime = new Deadline();\n const guard = (what: string): void => {\n if (lifetime.expired) {\n throw new PluginHostStateError(\n `plugin \"${name}\": ${what} depois que o contexto foi descartado (setup que estourou ` +\n 'o prazo, ou registro depois do teardown)',\n );\n }\n };\n /** Rejeição (com log) de uma operação assíncrona do contexto descartado. */\n const refuse = (operation: string): Promise<never> => {\n const error = new ContextExpiredError(name, operation, 'contexto do plugin', lifetime.reason);\n log.warn(`${operation} recusado: contexto do plugin já foi descartado`, {\n operation,\n err: error,\n });\n return Promise.reject(error);\n };\n const live: Live =\n (operation, fn) =>\n (...args) =>\n lifetime.expired ? refuse(operation) : fn(...args);\n\n // A espera é sempre do plugin dono do contexto: ele só aponta para os próprios passos.\n const expect: PluginExpect = (message, step, options) =>\n deps.conversations.expect(name, message.chat.id, message.sender.id, step, options);\n const commandViews = commandViewFactory(name, log, expect);\n const listenerView = listenerViewFactory(name, log, expect);\n const stepView = stepViewFactory(name, log, expect);\n const roleView = roleViewFactory(log);\n // Nos eventos de mensagem, cada listener recebe a visão com `message`/`text`/`reply`/`log`\n // do plugin; o barramento a cria (uma por listener) e pendura nela o `Deadline`.\n const events = deps.bus.forPlugin(name, {\n view: (event) => (isMessageEvent(event) ? listenerView : undefined),\n lifetime,\n });\n const services = deps.services.forPlugin(name);\n const scheduler = deps.scheduler.forPlugin(name, lifetime);\n\n const context: PluginContext = {\n plugin: { name, version: plugin.version, messages },\n config,\n log,\n get signal(): AbortSignal {\n return lifetime.signal;\n },\n commands: {\n add(definition: CommandDefinition): void {\n guard('commands.add');\n deps.router.registry.add(\n name,\n wrapCommand(name, definition, commandViews, lifetime, deps),\n );\n },\n list: () => deps.router.registry.list().map(commandInfo),\n },\n roles: {\n define(role, check) {\n guard('roles.define');\n deps.router.roles.define(\n name,\n role,\n wrapRoleCheck(name, role, check, roleView, log, lifetime, deps),\n );\n },\n },\n prefixes: {\n get: (chat) => deps.prefixes.get(chat),\n set: live('prefixes.set', (chatId: string, prefix: string) =>\n deps.prefixes.set(chatId, prefix),\n ),\n reset: live('prefixes.reset', (chatId: string) => deps.prefixes.reset(chatId)),\n } satisfies Prefixes,\n conversations: {\n define(step: string, handler: StepHandler): void {\n guard('conversations.define');\n deps.conversations.define(\n name,\n step,\n wrapStep(name, step, handler, stepView, log, lifetime, deps),\n );\n },\n },\n events: {\n on(event: BotEventName, first: unknown, second?: unknown): Unsubscribe {\n guard('events.on');\n return (events.on as AnySubscribe)(event, first, second);\n },\n } as EventSubscriber,\n services: {\n provide(service, implementation) {\n guard('services.provide');\n services.provide(service, implementation);\n },\n get: (service) => services.get(service),\n has: (service) => services.has(service),\n } satisfies ServiceAccess,\n storage: {\n ...liveTenantStorage(tenantStorage(deps.storage, name, deps.tenants), live),\n shared: liveTenantStorage(tenantStorage(deps.shared, name, deps.tenants), live),\n } satisfies PluginContextStorage,\n scheduler: {\n at: live('scheduler.at', (when: Date | number, job: string, payload?: JsonValue) =>\n scheduler.at(when, job, payload),\n ),\n cancel: live('scheduler.cancel', (id: string) => scheduler.cancel(id)),\n on(job, handler) {\n guard('scheduler.on');\n return scheduler.on(job, handler);\n },\n } satisfies Scheduler,\n send: liveOutbound(deps.send, live),\n groups: {\n metadata: live('groups.metadata', (groupId: string) => deps.groups.metadata(groupId)),\n updateParticipants: live(\n 'groups.updateParticipants',\n (...args: Parameters<Groups['updateParticipants']>) =>\n deps.groups.updateParticipants(...args),\n ),\n } satisfies Groups,\n http: pluginHttp(name, deps, guard),\n transportName: deps.transport.name,\n capabilities: deps.transport.capabilities,\n get self(): Contact | null {\n return deps.transport.self;\n },\n unsafe: deps.unsafe.forPlugin(plugin),\n };\n\n return {\n context,\n dispose(reason?: unknown): void {\n lifetime.expire(\n reason ?? new PluginHostStateError(`plugin \"${name}\": contexto descartado`),\n );\n deps.router.registry.removePlugin(name);\n deps.router.roles.removePlugin(name);\n deps.conversations.removePlugin(name);\n deps.bus.removePlugin(name);\n deps.services.removePlugin(name);\n deps.scheduler.removePlugin(name);\n deps.http?.removeOwner(name);\n },\n };\n };\n}\n\n/** `ctx.http`: rotas sob `/plugins/<nome>`, recusadas depois do `dispose` ou sem servidor. */\nfunction pluginHttp(\n name: string,\n deps: PluginContextDeps,\n guard: (what: string) => void,\n): HttpRoutes {\n if (deps.http === undefined) {\n const missing = (): never => {\n throw new BotConfigError(\n `plugin \"${name}\": ctx.http sem servidor; passe \\`http: createHttp({ port })\\` no createBot`,\n );\n };\n return {\n get basePath(): string {\n return missing();\n },\n route: missing,\n ws: missing,\n };\n }\n const routes = deps.http.scope(\n name,\n () => `/plugins/${name}`,\n (error, route) =>\n deps.onHttpError({ plugin: name, phase: 'http', event: route, error, timedOut: false }),\n );\n return {\n get basePath() {\n return routes.basePath;\n },\n route(method, path, handler) {\n guard('http.route');\n routes.route(method, path, handler);\n },\n ws(path, accept) {\n guard('http.ws');\n routes.ws(path, accept);\n },\n };\n}\n\n/** Embrulha uma operação assíncrona para rejeitar com `ContextExpiredError` após o `dispose`. */\ntype Live = <A extends unknown[], R>(\n operation: string,\n fn: (...args: A) => Promise<R>,\n) => (...args: A) => Promise<R>;\n\n/** `ctx.send` com o envio e cada ação recusados depois do `dispose`. */\nfunction liveOutbound(outbound: Outbound, live: Live): Outbound {\n return {\n send: live('send', (...args: Parameters<Outbound['send']>) => outbound.send(...args)),\n react: live('send.react', (...args: Parameters<Outbound['react']>) => outbound.react(...args)),\n edit: live('send.edit', (...args: Parameters<Outbound['edit']>) => outbound.edit(...args)),\n delete: live('send.delete', (...args: Parameters<Outbound['delete']>) =>\n outbound.delete(...args),\n ),\n typing: live('send.typing', (...args: Parameters<Outbound['typing']>) =>\n outbound.typing(...args),\n ),\n };\n}\n\n/**\n * Storage do plugin com cada operação (KV e coleções) recusada depois do `dispose`. A checagem é\n * na chamada: uma coleção obtida antes do descarte também passa a recusar.\n */\nfunction liveStorage(storage: PluginStorage, live: Live): PluginStorage {\n const { kv } = storage;\n const liveKv: KeyValueStore = {\n get: live('storage.kv.get', (key: string) => kv.get(key)) as KeyValueStore['get'],\n set: live('storage.kv.set', (key: string, value: JsonValue) => kv.set(key, value)),\n delete: live('storage.kv.delete', (key: string) => kv.delete(key)),\n };\n return {\n kv: liveKv,\n collection<T extends { readonly [key: string]: JsonValue }>(\n collectionName: string,\n options?: CollectionOptions,\n ): Collection<T> {\n const collection = storage.collection<T>(collectionName, options);\n const op = (method: string): string => `storage.collection(\"${collectionName}\").${method}`;\n type C = Collection<T>;\n return {\n insert: live(op('insert'), (document: T) => collection.insert(document)),\n get: live(op('get'), (id: string) => collection.get(id)),\n find: live(op('find'), (query?: Parameters<C['find']>[0]) => collection.find(query)),\n update: live(\n op('update'),\n (target: Parameters<C['update']>[0], patch: Parameters<C['update']>[1]) =>\n collection.update(target, patch),\n ),\n delete: live(op('delete'), (target: Parameters<C['delete']>[0]) =>\n collection.delete(target),\n ),\n };\n },\n };\n}\n\n/** `liveStorage` também no storage de cada tenant escolhido com `forTenant`. */\nfunction liveTenantStorage(storage: TenantStorage, live: Live): TenantStorage {\n return {\n ...liveStorage(storage, live),\n forTenant: (tenantId) => liveStorage(storage.forTenant(tenantId), live),\n };\n}\n\ntype AnySubscribe = (event: BotEventName, first: unknown, second: unknown) => Unsubscribe;\n\n/**\n * Comando com o `log` do plugin dono no contexto de `run` e `onReject`, e os dois com prazo: um\n * deles preso seguraria o chat na fila de entrada para sempre (ADR 0005). Cada um tem o próprio\n * `Deadline`, filho do de vida do plugin, que dá o `signal` e prende o `reply` (ADR 0033).\n */\nfunction wrapCommand(\n plugin: string,\n definition: CommandDefinition,\n views: CommandViews,\n lifetime: Deadline,\n deps: Pick<PluginContextDeps, 'commandTimeoutMs' | 'onLateCommandError' | 'armed'>,\n): CommandDefinition {\n const { run, onReject, name } = definition;\n const timeoutMs = definition.timeoutMs ?? deps.commandTimeoutMs;\n const timed = <R>(stage: CommandStage, execute: (deadline: Deadline) => R): R => {\n const deadline = new Deadline(lifetime);\n return settleWithin(\n execute(deadline),\n timeoutMs,\n () => {\n const error = new CommandTimeoutError(plugin, name, timeoutMs, stage);\n deadline.expire(error);\n return error;\n },\n (error) => deps.onLateCommandError(plugin, name, error),\n deps.armed,\n deadline,\n ) as R;\n };\n return {\n ...definition,\n run: (ctx) =>\n timed('run', (deadline) => {\n const view = views.run(ctx, deadline);\n return replyWithResult(view, run(view));\n }),\n ...(onReject && {\n onReject: (ctx, rejection) =>\n timed('onReject', (deadline) => onReject(views.run(ctx, deadline), rejection)),\n }),\n };\n}\n\n/**\n * `run` que devolve texto (string ou `fmt`) responde com ele, como o `onReject` (ADR 0079): o\n * mesmo que terminar com `await ctx.reply(texto)`, dentro do prazo do comando. Outro valor, como\n * a chave de um `c.reply(...)` devolvido, é ignorado.\n */\nfunction replyWithResult(ctx: CommandContext, result: unknown): unknown {\n const answer = (value: unknown): unknown =>\n typeof value === 'string' || isFormatted(value) ? ctx.reply(value) : undefined;\n return isThenable(result) ? Promise.resolve(result).then(answer) : answer(result);\n}\n\n/**\n * Checagem de papel com prazo e fail-closed (ADR 0035): lançar, rejeitar ou estourar o prazo\n * recusa o comando e vira `plugin.error` do plugin dono do papel, não do dono do comando. Nunca\n * lança. Checagem síncrona passa direto, sem timer.\n */\nfunction wrapRoleCheck(\n plugin: string,\n role: string,\n check: RoleCheck,\n view: ReturnType<typeof roleViewFactory>,\n log: Logger,\n lifetime: Deadline,\n deps: Pick<PluginContextDeps, 'commandTimeoutMs' | 'onRoleError' | 'armed'>,\n): RoleCheck {\n const refuse = (error: unknown): false => {\n deps.onRoleError({\n plugin,\n phase: 'role',\n event: role,\n error,\n timedOut: error instanceof RoleTimeoutError,\n });\n return false;\n };\n return (ctx) => {\n const deadline = new Deadline(lifetime);\n let result: unknown;\n try {\n result = check(view(ctx, deadline));\n } catch (error) {\n return refuse(error);\n }\n const settled = settleWithin(\n result,\n deps.commandTimeoutMs,\n () => {\n const error = new RoleTimeoutError(plugin, role, deps.commandTimeoutMs);\n deadline.expire(error);\n return error;\n },\n (error) => log.error(`papel \"${role}\" rejeitou depois do prazo`, { role, err: error }),\n deps.armed,\n );\n if (!(settled instanceof Promise)) return settled === true;\n return settled.then((granted) => granted === true, refuse);\n };\n}\n\n/**\n * Passo de conversa com a visão do plugin e o prazo do comando (`commandMs`): o passo roda dentro\n * da tarefa da fila do chat, e um preso seguraria o chat como um comando preso (ADR 0042). Tem o\n * próprio `Deadline`, filho do de vida do plugin, como o comando.\n */\nfunction wrapStep(\n plugin: string,\n step: string,\n handler: StepHandler,\n view: ReturnType<typeof stepViewFactory>,\n log: Logger,\n lifetime: Deadline,\n deps: Pick<PluginContextDeps, 'commandTimeoutMs' | 'armed'>,\n): KernelStep<KernelMessageContext> {\n const timeoutMs = deps.commandTimeoutMs;\n return (ctx, data) => {\n const deadline = new Deadline(lifetime);\n return settleWithin(\n handler(view(ctx, deadline, step, data) as unknown as StepContext),\n timeoutMs,\n () => {\n const error = new StepTimeoutError(plugin, step, timeoutMs);\n deadline.expire(error);\n return error;\n },\n (error) => {\n // A recusa de um contexto expirado já foi logada quando aconteceu (ADR 0033).\n if (error instanceof ContextExpiredError) return;\n log.error(`passo \"${step}\" rejeitou depois do prazo`, { step, err: error });\n },\n deps.armed,\n deadline,\n );\n };\n}\n","// Executor da `ReconnectionPolicy` (M1-16.3). A política só decide; aqui o bot aguarda o atraso,\n// limpa a sessão quando é o caso e reconecta, ou desiste e para. Um timer por vez, e nenhum\n// depois do `stop()`.\n\nimport type { LogFields, Logger } from '#logger/types.ts';\nimport {\n type ReconnectionDecision,\n ReconnectionPolicy,\n type ReconnectionPolicyOptions,\n} from '#transport/reconnection.ts';\nimport type { ConnectionStatus, Transport } from '#transport/types.ts';\n\n// `pairing` sai das opções: no bot, quem diz se há pareamento é a capability do transport, não\n// a config (ADR 0068).\nexport interface BotReconnectionOptions extends Omit<ReconnectionPolicyOptions, 'pairing'> {\n /**\n * Apaga as credenciais salvas, para a decisão `clean-session` (sessão encerrada no aparelho,\n * credenciais rejeitadas num transport com `pairing`, QRs sem pareamento; queda de rede\n * nunca, ADR 0045; erro `fatal` nunca, ADR 0068). Com transport\n * por fábrica, o padrão limpa o `auth` que a fábrica recebeu; isto o substitui. Com instância\n * pronta e sem ela, o bot não tem como parear de novo sozinho: loga e para.\n */\n readonly clearSession?: () => Promise<void>;\n}\n\nexport interface Reconnector {\n /**\n * Trata `connection.status`. Antes de `activate()`, ou com um `connect()` de reconexão em\n * andamento, guarda o último `closed` e decide sobre ele quando puder (ADR 0048).\n */\n onStatus(status: ConnectionStatus): void;\n /** Trata `connection.qr` e `connection.pairing-code` (ADR 0050). */\n onQr(): void;\n /** O `connect()` inicial terminou: a partir daqui, uma queda é reconectada. */\n activate(): void;\n /** Cancela o timer e espera uma reconexão em andamento. Idempotente. */\n stop(): Promise<void>;\n}\n\nexport interface ReconnectorOptions {\n readonly transport: Pick<Transport, 'connect'>;\n readonly log: () => Logger;\n readonly options: BotReconnectionOptions;\n /** O transport declara a capability `pairing`; sem ela, `auth-failed` para (ADR 0068). */\n readonly pairing: boolean;\n /** Chamado quando não há como seguir (`stop`, ou `clean-session` sem `clearSession`). */\n readonly giveUp: (decision: ReconnectionDecision) => void;\n}\n\ntype ClosedStatus = Extract<ConnectionStatus, { status: 'closed' }>;\n\n/** Decisão que o executor agenda: reconectar, com ou sem limpar a sessão antes. */\ntype Retry = Exclude<ReconnectionDecision, { action: 'stop' }>;\n\nexport function createReconnector({\n transport,\n log,\n options,\n pairing,\n giveUp,\n}: ReconnectorOptions): Reconnector {\n const policy = new ReconnectionPolicy({ ...options, pairing });\n const { clearSession } = options;\n let active = false;\n let stopped = false;\n let timer: NodeJS.Timeout | undefined;\n let inFlight: Promise<void> | undefined;\n // Queda que chegou quando o executor não podia agir (antes do `activate()` ou durante um\n // `connect()` de reconexão): o `connect()` resolve ao iniciar a tentativa, então o `closed`\n // pode vir antes de ele terminar e não teria mais quem o tratasse (#253). Um `open` depois\n // dela a anula.\n let pending: ClosedStatus | undefined;\n\n function schedule(decision: Retry): void {\n timer = setTimeout(() => {\n timer = undefined;\n inFlight = execute(decision).then((failed) => {\n inFlight = undefined;\n // Falha ao reconectar conta como queda: a política decide de novo (backoff). O\n // `closed` guardado tem o motivo do transport, mais preciso que o genérico.\n const lost: ClosedStatus = { status: 'closed', reason: 'connection-lost', error: null };\n const closed = pending ?? (failed ? lost : undefined);\n pending = undefined;\n if (closed) handleClosed(closed);\n });\n }, decision.delayMs);\n }\n\n /** Executa a decisão; `true` se falhou (o erro já foi logado). Nunca rejeita. */\n async function execute(decision: Retry): Promise<boolean> {\n if (stopped) return false;\n try {\n if (decision.action === 'clean-session') await clearSession?.();\n if (stopped) return false;\n await transport.connect();\n return false;\n } catch (error) {\n log().error('reconexão falhou', { err: error, action: decision.action });\n return true;\n }\n }\n\n /**\n * Loga por que o bot desiste. `fatal` e a credencial sem pareamento saem em `fatal`: o bot não\n * volta sozinho, alguém precisa corrigir a config. `replaced` fica em `error`: a outra conexão\n * segue de pé.\n */\n function logStop(\n cause: Extract<ReconnectionDecision, { action: 'stop' }>['cause'],\n fields: LogFields,\n ): void {\n switch (cause) {\n case 'replaced':\n log().error(\n 'conexão encerrada (replaced): outra conexão assumiu esta sessão (o mesmo número ' +\n 'rodando em outro processo?); o bot vai parar em vez de derrubá-la',\n fields,\n );\n return;\n case 'fatal':\n log().fatal(\n 'conexão encerrada por erro fatal do transport (token sem permissão, intents, porta?); ' +\n 'reconectar não resolve: corrija a configuração. O bot vai parar',\n fields,\n );\n return;\n case 'auth-failed':\n log().fatal(\n 'conexão encerrada (auth-failed): credenciais rejeitadas, e o transport não pareia de ' +\n 'novo (token inválido?); limpar a sessão não resolve. O bot vai parar',\n fields,\n );\n return;\n }\n }\n\n function handleClosed(status: ClosedStatus): void {\n if (stopped) return;\n // Já há reconexão agendada: o `connect()` dela ainda não começou e cobre esta queda.\n if (timer !== undefined) return;\n // Sem poder agir agora: decide quando o `connect()` (inicial ou de reconexão) terminar.\n if (!active || inFlight !== undefined) {\n pending = status;\n return;\n }\n const decision = policy.decide(status.reason);\n const fields = { reason: status.reason, err: status.error, ...decision, ...policy.state };\n if (decision.action === 'stop') {\n logStop(decision.cause, fields);\n giveUp(decision);\n return;\n }\n if (decision.action === 'clean-session' && clearSession === undefined) {\n log().error(\n `conexão encerrada (${status.reason}): a sessão precisa ser pareada de novo e não há ` +\n 'clearSession configurado; o bot vai parar',\n fields,\n );\n giveUp(decision);\n return;\n }\n log().warn(\n `conexão fechada (${status.reason}): reconectando em ${decision.delayMs} ms`,\n fields,\n );\n schedule(decision);\n }\n\n return {\n onStatus(status) {\n switch (status.status) {\n case 'open':\n pending = undefined;\n policy.connected();\n log().info('conexão aberta');\n return;\n case 'connecting':\n log().debug('conectando');\n return;\n case 'closed':\n handleClosed(status);\n return;\n }\n },\n\n onQr() {\n policy.qrPresented();\n },\n\n activate() {\n active = true;\n const closed = pending;\n pending = undefined;\n if (closed) handleClosed(closed);\n },\n\n async stop() {\n stopped = true;\n clearTimeout(timer);\n timer = undefined;\n await inFlight;\n },\n };\n}\n","// Sessões vivas por storage (ADR 0036): a mesma sessão não roda em dois bots que dividem um\n// storage. O registro fica pendurado no próprio objeto do storage, e não num mapa do módulo,\n// para não haver estado global (ADR 0004); `Symbol.for` faz duas cópias do core se enxergarem.\n\nimport { BotConfigError } from '#config/owners.ts';\nimport type { StoragePort } from '#storage/types.ts';\n\nconst LIVE_SESSIONS = Symbol.for('@usebridger/core/live-sessions');\n\ntype Tracked = StoragePort & { [LIVE_SESSIONS]?: Set<string> };\n\n/** Libera a sessão; `true` se nenhum outro bot usa mais o storage (quem libera o fecha). */\nexport type ReleaseSession = () => boolean;\n\n/**\n * Reserva `session` no storage. Lança `BotConfigError` se outro bot vivo já a usa. Storage que\n * não aceita a marca (objeto congelado) fica sem a checagem: devolve `undefined`.\n */\nexport function claimSession(storage: StoragePort, session: string): ReleaseSession | undefined {\n const tracked = storage as Tracked;\n let live = tracked[LIVE_SESSIONS];\n if (live === undefined) {\n live = new Set();\n const marked = Reflect.defineProperty(tracked, LIVE_SESSIONS, { value: live });\n if (!marked) return undefined;\n }\n if (live.has(session)) {\n throw new BotConfigError(\n `sessão \"${session}\" já está em uso por outro bot neste storage: cada sessão (número) ` +\n 'roda num bot só; dê um `session` diferente a cada bot',\n );\n }\n live.add(session);\n const sessions = live;\n return () => {\n sessions.delete(session);\n return sessions.size === 0;\n };\n}\n","// Trava da sessão entre processos (ADR 0074). O `claimSession` só enxerga bots no mesmo objeto de\n// storage; dois processos sobre o mesmo banco se veem só por aqui. Nem toda plataforma derruba a\n// conexão antiga (o Discord aceita o mesmo token em vários gateways), então sem a trava os dois\n// responderiam. A trava é por nome de sessão, sem olhar o transport: plataformas diferentes com o\n// mesmo nome dividiriam o KV, os jobs e o auth state.\n\nimport { randomUUID } from 'node:crypto';\nimport { BotConfigError } from '#config/owners.ts';\nimport type { Logger } from '#logger/types.ts';\nimport type { StoragePort } from '#storage/types.ts';\n\n/** Validade da trava: por quanto tempo a sessão de um processo que caiu fica presa. */\nexport const SESSION_LEASE_TTL_MS = 30_000;\n/** Intervalo da renovação e das tentativas do `start()`: três chances antes de a trava vencer. */\nexport const SESSION_LEASE_RENEW_MS = 10_000;\n\nexport interface SessionLeaseOptions {\n readonly storage: StoragePort;\n readonly session: string;\n readonly log: Logger;\n /** Aborta a espera pela trava (`stop()` durante o `start()`); rejeita com o `reason`. */\n readonly signal: AbortSignal;\n /** Outro processo assumiu a trava com o bot rodando. Chamado uma vez; a renovação para. */\n readonly onLost: () => void;\n}\n\nexport interface SessionLease {\n /** Para a renovação, espera a que estiver em andamento e libera a trava. */\n release(): Promise<void>;\n}\n\n/**\n * Adquire a trava da sessão e a renova até o `release()`. Ocupada, tenta de novo por até uma\n * validade inteira: a trava de um processo que caiu vence nesse prazo, e o restart logo depois do\n * crash sobe sozinho. Lança `BotConfigError` se outro processo ainda a tem depois disso. Storage\n * sem a trava (memória, que vive num processo só) devolve `undefined`, sem timer.\n */\nexport async function acquireSessionLease(\n options: SessionLeaseOptions,\n): Promise<SessionLease | undefined> {\n const { storage, session, log, signal, onLost } = options;\n const { acquireLease, releaseLease } = storage;\n if (acquireLease === undefined || releaseLease === undefined) return undefined;\n const name = `session:${session}`;\n const owner = randomUUID();\n const acquire = (): Promise<boolean> =>\n acquireLease.call(storage, name, owner, SESSION_LEASE_TTL_MS);\n\n for (let waited = 0; !(await acquire()); waited += SESSION_LEASE_RENEW_MS) {\n if (waited >= SESSION_LEASE_TTL_MS) {\n throw new BotConfigError(\n `sessão \"${session}\" já está em uso por outro processo neste storage: cada sessão ` +\n 'roda num processo só; dê um `session` diferente a cada bot (inclusive em plataformas ' +\n 'diferentes)',\n );\n }\n if (waited === 0) {\n log.warn('sessão travada por outro processo; esperando a trava vencer', {\n session,\n ttlMs: SESSION_LEASE_TTL_MS,\n });\n }\n await abortableDelay(SESSION_LEASE_RENEW_MS, signal);\n }\n\n let lost = false;\n let renewing: Promise<void> | undefined;\n const renew = async (): Promise<void> => {\n try {\n if (await acquire()) return;\n lost = true;\n clearInterval(timer);\n onLost();\n } catch (error) {\n // Falha de I/O não é perda: a trava vale por mais duas renovações, e o próximo tick tenta.\n log.warn('falha ao renovar a trava da sessão; tentando no próximo intervalo', {\n session,\n err: error,\n });\n }\n };\n const timer = setInterval(() => {\n // Uma renovação por vez: um storage lento não empilha escritas.\n renewing ??= renew().finally(() => {\n renewing = undefined;\n });\n }, SESSION_LEASE_RENEW_MS);\n // Não segura o processo: quem o mantém vivo é o transport.\n timer.unref?.();\n\n return {\n async release(): Promise<void> {\n clearInterval(timer);\n // Uma renovação que terminasse depois da liberação adquiriria a trava de novo.\n await renewing;\n if (!lost) await releaseLease.call(storage, name, owner);\n },\n };\n}\n\n/** Espera `ms`, ou rejeita com `signal.reason` se o sinal abortar antes. */\nfunction abortableDelay(ms: number, signal: AbortSignal): Promise<void> {\n if (signal.aborted) return Promise.reject(signal.reason);\n return new Promise((resolve, reject) => {\n const onAbort = (): void => {\n clearTimeout(timer);\n reject(signal.reason);\n };\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n","/**\n * Gancho executado no `stop()`, antes de desconectar o transport. É por aqui que filas drenam\n * e plugins fazem `teardown`. O `signal` aborta quando o gancho estoura o prazo, para quem\n * quiser parar de trabalhar em vez de continuar rodando órfão depois do timeout.\n */\nexport type StopHook = (signal: AbortSignal) => void | Promise<void>;\n\nexport interface StopHookOptions {\n /** Nome que aparece nos erros. Padrão: o nome da função, ou `anonimo`. */\n readonly name?: string;\n /** Prazo deste gancho em ms. Padrão: `shutdown.hookTimeoutMs` do bot. */\n readonly timeoutMs?: number;\n}\n\nexport interface ShutdownOptions {\n /** Prazo padrão de cada gancho em ms. Padrão: 5000. */\n readonly hookTimeoutMs?: number;\n /** Prazo total dos ganchos em ms. Padrão: 15000. */\n readonly timeoutMs?: number;\n}\n\n/** Falha de um gancho de parada; o erro original fica em `cause`. */\nexport class StopHookError extends Error {\n readonly hookName: string;\n /** `true` quando o gancho estourou o prazo ou nem rodou porque o prazo total acabou. */\n readonly timedOut: boolean;\n\n constructor(hookName: string, message: string, timedOut: boolean, cause?: unknown) {\n super(`gancho de parada \"${hookName}\": ${message}`, { cause });\n this.name = 'StopHookError';\n this.hookName = hookName;\n this.timedOut = timedOut;\n }\n}\n\nexport interface RegisteredStopHook {\n readonly hook: StopHook;\n readonly name: string;\n readonly timeoutMs: number | undefined;\n}\n\nexport const DEFAULT_HOOK_TIMEOUT_MS = 5000;\nexport const DEFAULT_SHUTDOWN_TIMEOUT_MS = 15_000;\n\n/**\n * Roda os ganchos em sequência, na ordem recebida, e devolve as falhas em vez de lançar: um\n * gancho quebrado não pode impedir o teardown dos outros. Quem chama decide o destino dos erros.\n */\nexport async function runStopHooks(\n hooks: readonly RegisteredStopHook[],\n options: ShutdownOptions = {},\n): Promise<StopHookError[]> {\n const hookTimeoutMs = options.hookTimeoutMs ?? DEFAULT_HOOK_TIMEOUT_MS;\n const deadline = Date.now() + (options.timeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS);\n const errors: StopHookError[] = [];\n\n for (const entry of hooks) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) {\n // Prazo total esgotado: o processo precisa encerrar mesmo com ganchos pendentes.\n errors.push(new StopHookError(entry.name, 'não executado: prazo total esgotado', true));\n continue;\n }\n const error = await runOne(entry, Math.min(entry.timeoutMs ?? hookTimeoutMs, remaining));\n if (error) errors.push(error);\n }\n return errors;\n}\n\nasync function runOne(\n entry: RegisteredStopHook,\n timeoutMs: number,\n): Promise<StopHookError | undefined> {\n const controller = new AbortController();\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<StopHookError>((resolve) => {\n timer = setTimeout(() => {\n controller.abort();\n resolve(new StopHookError(entry.name, `excedeu ${timeoutMs} ms`, true));\n }, timeoutMs);\n });\n // `then` captura também o throw síncrono do gancho.\n const run = Promise.resolve()\n .then(() => entry.hook(controller.signal))\n .then(\n () => undefined,\n (cause: unknown) => new StopHookError(entry.name, 'falhou', false, cause),\n );\n try {\n return await Promise.race([run, timeout]);\n } finally {\n clearTimeout(timer);\n }\n}\n","import {\n ActionRegistry,\n type ActionTarget,\n type MessageAction,\n numberedMenu,\n pickChoice,\n} from '#actions/actions.ts';\nimport { createCommandCatalog } from '#commands/catalog.ts';\nimport { createPrefixStore, type PrefixConfig } from '#commands/prefixes.ts';\nimport { CommandConflictError, createCommandRegistry } from '#commands/registry.ts';\nimport { RoleConflictError } from '#commands/roles.ts';\nimport { createCommandRouter, type DispatchResult, type IsGroupAdmin } from '#commands/router.ts';\nimport type { ConfigEnv } from '#config/env.ts';\nimport { BotConfigError, type BotOwner, normalizeOwners } from '#config/owners.ts';\nimport {\n createPluginConfigs,\n type PluginConfigFile,\n type PluginConfigs,\n} from '#config/plugin-configs.ts';\nimport type { BotMessageContext } from '#context.ts';\nimport {\n ConversationRegistry,\n type PendingReply,\n StepTimeoutError,\n} from '#conversations/conversations.ts';\nimport { ArmedTimers, ContextExpiredError, settleWithin } from '#deadline.ts';\nimport { createEventBus, type EmittableEventName } from '#events/bus.ts';\nimport type { BotEvents, ListenerExtras, PluginErrorEvent } from '#events/types.ts';\nimport { createGroups } from '#groups/groups.ts';\nimport { sessionHttp } from '#http/server.ts';\nimport type { HttpServer } from '#http/types.ts';\nimport { createDeferredLogger } from '#logger/deferred.ts';\nimport { createLogger, createNoopLogger } from '#logger/logger.ts';\nimport { createSecretSet, type SecretSet } from '#logger/secrets.ts';\nimport type { Logger, LogLevel } from '#logger/types.ts';\nimport { createMessage } from '#message/create.ts';\nimport type { Chat, Message } from '#message/types.ts';\nimport { type ChatFilterOptions, chatAllowed, chatFilter } from '#middleware/chat-filter.ts';\nimport { ignoreBots } from '#middleware/ignore-bots.ts';\nimport { ignoreSelf } from '#middleware/ignore-self.ts';\nimport { type Middleware, MiddlewarePipeline } from '#middleware/pipeline.ts';\nimport { type RateLimitOptions, rateLimit } from '#middleware/rate-limit.ts';\nimport { type SanitizeOptions, sanitize } from '#middleware/sanitize.ts';\nimport { createOutbound, enqueueAction } from '#outbound/actions.ts';\nimport {\n OutboundQueue,\n type OutboundQueueOptions,\n type OutboundQueueStats,\n} from '#outbound/queue.ts';\nimport type { PrepareActions } from '#outbound/reply.ts';\nimport { PLUGIN_NAME_PATTERN } from '#plugin/define.ts';\nimport { createPluginHost, type PluginHost, type PluginReloadResult } from '#plugin/host.ts';\nimport type { PluginLifecycleError, PluginReportEntry } from '#plugin/report.ts';\nimport { collectPlugins } from '#plugin/sources.ts';\nimport type { PluginDefinition } from '#plugin/types.ts';\nimport { InboundQueue, type InboundQueueOptions, type InboundQueueStats } from '#queue/inbound.ts';\nimport { createSchedulerService } from '#scheduler/service.ts';\nimport { createServiceRegistry, ServiceConflictError } from '#services/registry.ts';\nimport { createMemoryStorage } from '#storage/memory.ts';\nimport { DEFAULT_SESSION, sessionStorage, sharedStorage } from '#storage/namespace.ts';\nimport type { StoragePort } from '#storage/types.ts';\nimport { TenantScope } from '#tenant/scope.ts';\nimport { type Capability, hasCapability } from '#transport/capabilities.ts';\nimport { transportIssues } from '#transport/methods.ts';\nimport type {\n CommandInteraction,\n Interaction,\n Transport,\n TransportDeps,\n} from '#transport/types.ts';\nimport { createUnsafeAccess } from '#unsafe/access.ts';\nimport {\n createMessageContext,\n type KernelMessageContext,\n type MessageContextDeps,\n messageExtras,\n} from './message-context.ts';\nimport { CommandTimeoutError, createPluginContextFactory } from './plugin-context.ts';\nimport { type BotReconnectionOptions, createReconnector, type Reconnector } from './reconnect.ts';\nimport { claimSession, type ReleaseSession } from './session.ts';\nimport { acquireSessionLease, type SessionLease } from './session-lease.ts';\nimport {\n type RegisteredStopHook,\n runStopHooks,\n type ShutdownOptions,\n type StopHook,\n type StopHookOptions,\n} from './stop-hooks.ts';\n\n/**\n * Ciclo de vida: `idle → starting → running → stopping → stopped`. `stopped` é terminal —\n * uma instância não reinicia; para subir de novo, crie outro `Bot`.\n */\nexport type BotState = 'idle' | 'starting' | 'running' | 'stopping' | 'stopped';\n\n/** Middleware do app com prioridade (maior roda antes). */\nexport interface BotMiddlewareEntry {\n readonly middleware: Middleware<BotMessageContext>;\n /** Padrão: 0 — dentro dos oficiais, que ficam entre 700 e 1000. */\n readonly priority?: number;\n}\n\n/**\n * Middlewares do bot. Os oficiais entram nesta ordem (de fora para dentro): `ignoreSelf` (1000),\n * `ignoreBots` (990), `chatFilter` (900), `rateLimit` (800), `sanitize` (700); depois os do app\n * (`use`, padrão 0).\n */\nexport interface BotMiddlewaresConfig {\n /** Barra as mensagens da própria sessão. Padrão: `true`. */\n readonly ignoreSelf?: boolean;\n /** Barra as mensagens de outros bots (`sender.isBot`). Padrão: `true`. */\n readonly ignoreBots?: boolean;\n /** Allow/blocklist de chats. Padrão: desligado. */\n readonly chatFilter?: ChatFilterOptions;\n /** Rate limit de entrada. Padrão: desligado. Sem `onLimited`, loga em `debug`. */\n readonly rateLimit?: RateLimitOptions;\n /** Truncagem de texto e nome. Padrão: ligado com os limites do `sanitize`; `false` desliga. */\n readonly sanitize?: SanitizeOptions | false;\n /** Middlewares do app. */\n readonly use?: readonly (Middleware<BotMessageContext> | BotMiddlewareEntry)[];\n}\n\n/** Prazos dos estágios que rodam código de plugin, em ms. */\nexport interface BotTimeouts {\n /** Criação do contexto e `setup` de cada plugin. Padrão: 10000. */\n readonly setupMs?: number;\n /** `teardown` e limpeza de cada plugin. Padrão: 5000. */\n readonly teardownMs?: number;\n /**\n * `run` de cada comando; estourado, o chat é liberado e sai `plugin.error`. Padrão: 30000.\n * O `timeoutMs` de um comando sobrescreve só para ele.\n */\n readonly commandMs?: number;\n /** Cada listener de evento. Padrão: 30000. */\n readonly listenerMs?: number;\n /** Cada handler de job do scheduler. Padrão: 30000. */\n readonly jobMs?: number;\n /**\n * Cada middleware do pipeline, contado só no tempo dele (o que roda dentro do `next()` não\n * conta). Estourado, a mensagem é descartada e o erro vai para o log. Padrão: 30000.\n */\n readonly middlewareMs?: number;\n}\n\nexport interface BotConfig {\n /**\n * O transport, ou a fábrica que o monta com o que o bot fornece (`session`, `auth`, `log`;\n * ADR 0037). O `createBot` chama a fábrica uma vez; ela só monta o objeto, sem I/O.\n */\n readonly transport: Transport | ((deps: TransportDeps) => Transport);\n /**\n * Sessão (o número) que este bot opera; kebab-case, como nome de plugin. Tudo o que o bot\n * persiste fica no escopo dela (ADR 0036), então trocar o nome \"esquece\" os dados da anterior.\n * Dois bots vivos no mesmo storage não podem usar a mesma. Padrão: `'default'`.\n */\n readonly session?: string;\n /**\n * Storage do bot (plugins, scheduler, overrides de config). O bot o fecha no `stop()` — o\n * último a parar, se vários bots o dividem. Padrão: em memória (`createMemoryStorage`), com\n * aviso no log — os dados somem ao reiniciar.\n */\n readonly storage?: StoragePort;\n /**\n * Servidor HTTP do processo (`createHttp`), o mesmo para todos os bots (ADR 0076). Dá\n * `ctx.http` aos plugins e `TransportDeps.http` ao transport; a porta só abre se houver rota.\n */\n readonly http?: HttpServer;\n /** Plugins da config (pacotes npm que o app importa). */\n readonly plugins?: readonly PluginDefinition[];\n /** Pastas de plugins locais (ver `collectPlugins`), relativas a `cwd`. */\n readonly pluginDirs?: readonly string[];\n /** Base de `pluginDirs`. Padrão: `process.cwd()`. */\n readonly cwd?: string;\n /** Nomes de plugin que não carregam. */\n readonly disabledPlugins?: readonly string[];\n /** Config por plugin (a camada \"arquivo\"; ver ADR 0032). */\n readonly pluginConfig?: PluginConfigFile;\n /** Ambiente da config de plugin (`BRIDGER_*`). Padrão: `process.env`. */\n readonly env?: ConfigEnv;\n /**\n * Donos (`role: 'owner'`): telefone, aceito com pontuação e normalizado no `createBot`, ou\n * `{ id }` com o ID nativo do contato, para plataformas sem telefone.\n */\n readonly owners?: readonly BotOwner[];\n /**\n * Prefixo de comando: um para todo chat (`'!'`) ou um por tipo (`{ dm: '', group: '!' }`,\n * `group` vale para todo chat que não é `dm`). Vazio é permitido. Padrão: `'!'`. Um plugin\n * troca o de um chat com `ctx.prefixes.set` (ADR 0063).\n */\n readonly prefix?: PrefixConfig;\n /**\n * Logger pronto. Sem ele, o bot cria um (`createLogger`) com `logLevel` e `secrets`. Um\n * logger próprio só censura os segredos da config se for criado com o mesmo `secrets`.\n */\n readonly logger?: Logger;\n /** Nível do logger criado pelo bot. Padrão: `'info'`. */\n readonly logLevel?: LogLevel;\n /** Fonte de segredos compartilhada entre a config de plugin e o logger. Padrão: uma nova. */\n readonly secrets?: SecretSet;\n readonly middlewares?: BotMiddlewaresConfig;\n /** Fila de entrada por chat. */\n readonly inbound?: Pick<InboundQueueOptions, 'maxPendingPerChat'>;\n /** Fila de saída (taxa, prioridade, retry, humanização). */\n readonly outbound?: Omit<OutboundQueueOptions, 'transport'>;\n /** Reconexão automática. Padrão: ligada com os padrões da `ReconnectionPolicy`. */\n readonly reconnection?: BotReconnectionOptions | false;\n readonly timeouts?: BotTimeouts;\n readonly shutdown?: ShutdownOptions;\n}\n\n/** Config de plugin em runtime, para o dashboard: overrides, visão mascarada e schema. */\nexport type BotPluginConfigs = Pick<PluginConfigs, 'setOverrides' | 'describe' | 'jsonSchema'>;\n\nexport interface Bot {\n readonly state: BotState;\n /**\n * Sobe o bot (ordem em docs/bot.md): carrega os plugins e, só se o boot deles der certo,\n * conecta o transport e liga o scheduler. Plugin quebrado (ex.: `CommandConflictError`) ⇒ o\n * transport nunca conecta. Idempotente enquanto `starting`/`running` (devolve a mesma\n * promise); rejeita com `BotStateError` depois de `stop()`. Rejeita com o erro de boot depois\n * de encerrar o que já tinha subido.\n */\n start(): Promise<void>;\n /**\n * Shutdown gracioso: roda os ganchos de parada (LIFO; os internos drenam filas e fazem o\n * `teardown` dos plugins), desconecta o transport e fecha o storage. Idempotente: chamadas\n * repetidas devolvem a mesma promise. Rejeita com `AggregateError` se alguma etapa falhar —\n * mas sempre termina em `stopped`.\n */\n stop(): Promise<void>;\n /** Registra um gancho de parada; devolve a função que o remove. */\n onStop(hook: StopHook, options?: StopHookOptions): () => void;\n /** Config dos plugins. Disponível depois que o `start()` carrega os plugins. */\n readonly config: BotPluginConfigs;\n /** Tabela de boot atual (reflete reloads); vazia antes do `start()`. */\n plugins(): PluginReportEntry[];\n /**\n * Métricas das filas de entrada e de saída, lidas de contadores (O(1)). Sempre disponível:\n * zeros antes do `start()`, valores finais depois do `stop()`. Devolve uma cópia.\n */\n stats(): BotStats;\n /**\n * Resolve quando o bot terminou de processar o que recebeu: fila de entrada vazia, nenhum\n * listener em andamento (inclusive de eventos diretos e `plugin.error`) e fila de saída vazia,\n * as três ao mesmo tempo (ADR 0044). Chamado durante o boot, espera o boot assentar. Não\n * espera jobs do scheduler; com a fila de saída pausada (conexão caída), espera a reconexão ou\n * o `maxPauseMs`. Resolve na hora antes do `start()` e depois do `stop()`; nunca rejeita.\n */\n settled(): Promise<void>;\n}\n\nexport interface BotStats {\n readonly inbound: InboundQueueStats;\n readonly outbound: OutboundQueueStats;\n}\n\n/** Operação incompatível com o estado atual do bot. */\nexport class BotStateError extends Error {\n readonly state: BotState;\n\n constructor(message: string, state: BotState) {\n super(message);\n this.name = 'BotStateError';\n this.state = state;\n }\n}\n\n/** Prazo padrão do `run` de um comando: o mesmo dos listeners. */\nconst DEFAULT_COMMAND_TIMEOUT_MS = 30_000;\n\n/** Prazo padrão de cada middleware: o mesmo dos handlers (ADR 0043). */\nconst DEFAULT_MIDDLEWARE_TIMEOUT_MS = 30_000;\n\n/**\n * Prazos dos ganchos de parada internos. Somam o total padrão (`shutdown.timeoutMs`, 15 s): um\n * gancho lento não deixa os seguintes sem prazo. O que um gancho não encerrar a tempo é\n * abandonado no fim do shutdown (`abandonInternals`).\n */\nconst STOP_TIMEOUTS = {\n reconnection: 1000,\n inbound: 4000,\n scheduler: 2000,\n plugins: 5000,\n outbound: 3000,\n} as const;\n\n/** Eventos do transport que não são mensagem: vão ao barramento sem fila nem middlewares. */\ntype DirectEvent = Extract<\n EmittableEventName,\n | 'message.deleted'\n | 'reaction'\n | 'poll.vote'\n | 'group.joined'\n | 'group.left'\n | 'group.participants'\n | 'group.updated'\n | 'contact.updated'\n>;\n\n/** O que os filtros do ADR 0038 leem de um evento; `chat: null` = não passa pelo `chatFilter`. */\ninterface EventOrigin {\n /** Com o `parentId`, para o `chatFilter` casar também o espaço (ADR 0058). */\n readonly chat: Pick<Chat, 'id' | 'parentId'> | null;\n readonly fromMe: boolean;\n /** Autor do evento, para o `ignoreBots` (ADR 0057). */\n readonly fromBot: boolean;\n}\n\nconst ALWAYS_PASSES: EventOrigin = { chat: null, fromMe: false, fromBot: false };\n\n/**\n * Origem de cada evento direto, para o `chatFilter`, o `ignoreSelf` e o `ignoreBots` (ADR 0038).\n */\nconst DIRECT_EVENTS: { readonly [E in DirectEvent]: (payload: BotEvents[E]) => EventOrigin } = {\n 'message.deleted': (payload) => ({\n chat: payload.chat,\n fromMe: payload.fromMe,\n fromBot: payload.deletedBy?.isBot === true,\n }),\n reaction: (payload) => ({\n chat: payload.chat,\n fromMe: payload.fromMe,\n fromBot: payload.sender.isBot === true,\n }),\n 'poll.vote': (payload) => ({\n chat: payload.chat,\n fromMe: payload.fromMe,\n fromBot: payload.sender.isBot === true,\n }),\n // Entrada e saída do grupo são o ciclo de vida do próprio bot: servem para o plugin limpar\n // estado, então passam mesmo com o grupo bloqueado.\n 'group.joined': () => ALWAYS_PASSES,\n 'group.left': () => ALWAYS_PASSES,\n 'group.participants': (payload) => ({ chat: payload.chat, fromMe: false, fromBot: false }),\n 'group.updated': (payload) => ({ chat: payload.chat, fromMe: false, fromBot: false }),\n // Contato não é de um chat: bloquear um chat não esconde quem está nele de outros chats.\n 'contact.updated': () => ALWAYS_PASSES,\n};\n\n/**\n * Dono e passo da espera do menu numerado (ADR 0062). O nome não é kebab-case: nenhum plugin o\n * usa.\n */\nconst MENU_OWNER = '#menu';\n// Dono das rotas do transport na tabela HTTP da sessão; nome de plugin não tem `$`.\nconst TRANSPORT_ROUTE_OWNER = '$transport';\nconst MENU_STEP = 'choice';\n\nconst MIDDLEWARE_PRIORITY = {\n ignoreSelf: 1000,\n ignoreBots: 990,\n chatFilter: 900,\n rateLimit: 800,\n sanitize: 700,\n};\n\n/**\n * Cria um bot. Valida a config e monta as peças sem efeito colateral (sem conexão, timer,\n * logger ou leitura de disco): o efeito começa em `start()`. Lança `BotConfigError` para\n * `owners` ou `session` malformados ou fábrica de transport que lança, e `TypeError`/`RangeError`\n * para opções inválidas.\n */\nexport function createBot(config: BotConfig): Bot {\n const session = validateSession(config.session ?? DEFAULT_SESSION);\n // Todo o estado vive neste closure (ADR 0004): duas instâncias nunca se enxergam.\n const hooks: RegisteredStopHook[] = [];\n let state: BotState = 'idle';\n let stopRequested = false;\n let startPromise: Promise<void> | undefined;\n let shutdownPromise: Promise<void> | undefined;\n let stopAfterStart: Promise<void> | undefined;\n\n // O logger nasce no start(): criar o do pino aqui já seria efeito colateral. Até lá, quem\n // logar (nada deveria) cai no no-op.\n let log: Logger = createNoopLogger();\n const getLog = (): Logger => log;\n const secrets = config.secrets ?? createSecretSet();\n const storage = config.storage ?? createMemoryStorage();\n // O escopo da sessão é aplicado aqui, uma vez: scheduler, config e plugins só veem esta visão.\n const scoped = sessionStorage(storage, session);\n const auth = storage.authState(session);\n // A fábrica recebe o logger antes de ele existir: este delega ao filho `{ transport }` que o\n // start() cria e, até lá, ao no-op.\n let transportLog: Logger | undefined;\n // A lista de comandos que o transport registra na plataforma (ADR 0064). O registro avisa o\n // catálogo, que junta os avisos em lote.\n const catalog = createCommandCatalog({\n list: () => registry.list(),\n onError: (error) =>\n log.error('listener de commands.onChange do transport falhou', { err: error }),\n });\n const registry = createCommandRegistry({ onChange: () => catalog.changed() });\n // Rotas da sessão no servidor do processo (ADR 0076); só entram nele no start().\n const http = config.http === undefined ? undefined : sessionHttp(config.http, session, getLog);\n let resolvedTransport: Transport | undefined;\n const transport = resolveTransport(config.transport, {\n session,\n auth,\n log: createDeferredLogger(() => transportLog ?? log),\n commands: catalog.commands,\n ...(http && {\n http: http.scope(\n TRANSPORT_ROUTE_OWNER,\n () => {\n if (resolvedTransport === undefined) {\n throw new Error('http.basePath: leia depois que a fábrica devolver o transport');\n }\n return `/transports/${encodeURIComponent(resolvedTransport.name)}`;\n },\n (error, route) => log.error(`rota ${route} do transport falhou`, { err: error }),\n ),\n }),\n });\n resolvedTransport = transport;\n // O transport registra rotas na fábrica; publicadas no start(), retiradas no stop.\n let httpAttached = false;\n let releaseSession: ReleaseSession | undefined;\n // Trava da sessão entre processos (ADR 0074); só existe com storage que a implementa.\n let sessionLease: SessionLease | undefined;\n // O `stop()` durante o `start()` aborta a espera pela trava em vez de esperar a validade.\n const bootAbort = new AbortController();\n // `connect()` já foi chamado: só então o shutdown desconecta.\n let connectCalled = false;\n // Desfaz a assinatura dos eventos do transport; existe depois que o start() a fez.\n let unsubscribe: (() => void) | undefined;\n const timeouts = config.timeouts ?? {};\n const commandTimeoutMs = timeouts.commandMs ?? DEFAULT_COMMAND_TIMEOUT_MS;\n\n // Prazos de comando, papel, consulta de admin e listener: o shutdown desarma os de handlers\n // presos (`abandonInternals`).\n const armed = new ArmedTimers();\n const bus = createEventBus({\n listenerTimeoutMs: timeouts.listenerMs,\n armed,\n onError: (event) => logPluginError(event),\n });\n const services = createServiceRegistry();\n const prefixes = createPrefixStore(config.prefix, scoped);\n const router = createCommandRouter({\n registry,\n prefix: (chat) => prefixes.get(chat),\n selfUsername: () => transport.self?.username,\n owners: normalizeOwners(config.owners ?? []),\n isGroupAdmin: groupAdminPort(\n transport,\n commandTimeoutMs,\n (error) => log.warn('consulta de admin do grupo falhou depois do prazo', { err: error }),\n armed,\n ),\n // O comando é recusado de todo jeito (fail-closed); o log diz ao autor o que falta.\n onUnknownRole: (role, command) =>\n log.error(\n `comando \"${command.name}\" exige o papel \"${role}\", que nenhum plugin carregado define: ` +\n `declare dependsOn no plugin dono do papel (em \"${command.plugin}\")`,\n { plugin: command.plugin, command: command.name, role },\n ),\n });\n const conversations = new ConversationRegistry<KernelMessageContext>();\n // O menu numerado espera a resposta pelo mesmo registro dos plugins, então um comando digitado\n // ou outra espera também o cancelam. O passo nunca roda: o `dispatchMessage` trata a escolha.\n conversations.define(MENU_OWNER, MENU_STEP, () => undefined);\n const actions = new ActionRegistry();\n // Mensagem montada pelo kernel a partir de um clique ou comando nativo -> a interação de origem,\n // para o `ctx.unsafe.raw()` pedir ao transport o objeto bruto dela (ADR 0066). Por bot, e some\n // com a mensagem.\n const interactions = new WeakMap<Message, Interaction>();\n const buttons = hasCapability(transport, 'actions');\n const maxButtons = buttonLimit(transport);\n const pipeline = createPipeline(\n config.middlewares ?? {},\n timeouts.middlewareMs ?? DEFAULT_MIDDLEWARE_TIMEOUT_MS,\n getLog,\n );\n // Os mesmos filtros, para os eventos que não passam pelo pipeline (ADR 0038).\n const chatFilterOptions = config.middlewares?.chatFilter;\n const chatIsAllowed = chatFilterOptions ? chatAllowed(chatFilterOptions) : () => true;\n const dropsSelf = config.middlewares?.ignoreSelf !== false;\n const dropsBots = config.middlewares?.ignoreBots !== false;\n const inbound = new InboundQueue({\n maxPendingPerChat: config.inbound?.maxPendingPerChat,\n onError: (error, chatId) => log.error('falha ao processar mensagem', { chatId, err: error }),\n });\n const outbound = new OutboundQueue({\n onTypingError: (error, chatId) =>\n log.debug('falha ao enviar \"digitando\"', { chatId, err: error }),\n ...config.outbound,\n transport,\n });\n // O plugin vê o envio e as ações (ADR 0040): a fila (close, stats) fica com o kernel.\n const send = createOutbound(outbound, transport);\n const groups = createGroups(transport, enqueueAction(outbound, transport));\n // Cópia: o plugin recebe um `ReadonlySet`, mas um cast não deve alterar o do transport.\n const capabilities: ReadonlySet<Capability> = new Set(transport.capabilities);\n // Tenant da mensagem ou do evento em andamento (ADR 0072): o storage dos plugins e os jobs\n // agendados seguem ele.\n const tenants = new TenantScope();\n const scheduler = createSchedulerService({\n storage: scoped,\n tenants,\n jobTimeoutMs: timeouts.jobMs,\n onError: (event) => {\n logPluginError(event);\n void bus.emit('plugin.error', event);\n },\n onLateError: (event) => logPluginError(event),\n onStorageError: (error) => log.error('scheduler: falha no storage', { err: error }),\n });\n const contextDeps: MessageContextDeps = {\n sender: send,\n quote: hasCapability(transport, 'quoted'),\n log: getLog,\n actions: prepareActions,\n };\n const reconnector: Reconnector | undefined =\n config.reconnection === false\n ? undefined\n : createReconnector({\n transport,\n log: getLog,\n options: {\n ...config.reconnection,\n // Com fábrica, o auth do transport é o do bot: o kernel sabe limpá-lo sozinho. Com\n // instância pronta, não sabe onde estão as credenciais.\n clearSession:\n config.reconnection?.clearSession ??\n (typeof config.transport === 'function' ? () => auth.clear() : undefined),\n },\n pairing: hasCapability(transport, 'pairing'),\n giveUp: () => {\n // Chamado de dentro de um handler do transport: o stop corre em paralelo.\n bot.stop().catch((error: unknown) => log.error('falha ao parar o bot', { err: error }));\n },\n });\n\n let host: PluginHost | undefined;\n let configs: PluginConfigs | undefined;\n let booted = false;\n // Mensagens que chegam enquanto os plugins sobem esperam aqui; `false` = boot abortado. Só a\n // primeira chamada vale: depois de pronto, o shutdown drena o que a fila já aceitou.\n let ready = false;\n let settleReady: (ok: boolean) => void = () => undefined;\n const readyPromise = new Promise<boolean>((resolve) => {\n settleReady = (ok) => {\n settleReady = () => undefined;\n ready = ok;\n resolve(ok);\n };\n });\n\n function logPluginError(event: PluginErrorEvent): void {\n log.error(`plugin \"${event.plugin}\" falhou (${event.phase})`, {\n plugin: event.plugin,\n phase: event.phase,\n event: event.event,\n timedOut: event.timedOut,\n err: event.error,\n });\n }\n\n /** Erros de ciclo de vida do host viram `plugin.error` (o host já os logou). */\n function emitLifecycleError(error: PluginLifecycleError): void {\n const phase = error.phase === 'context' || error.phase === 'setup' ? 'setup' : 'teardown';\n void bus.emit('plugin.error', {\n plugin: error.plugin,\n phase,\n event: null,\n error: error.cause ?? error,\n timedOut: error.timedOut,\n });\n }\n\n // --- Fluxo de uma mensagem (plano §5.3) -------------------------------------------------\n\n /**\n * Barreiras comuns à mensagem nova e à edição: espera o fim do boot e roda os middlewares em\n * volta de `handle`, que só roda se a mensagem atravessar a cadeia. A volta da cebola espera\n * `handle` terminar (ADR 0012).\n */\n async function admit(\n message: Message,\n handle: (ctx: KernelMessageContext) => Promise<void>,\n ): Promise<void> {\n if (!ready && !(await readyPromise)) return;\n await pipeline.run(createMessageContext(message, contextDeps), handle);\n }\n\n function handleMessage(message: Message): Promise<void> {\n return admit(message, dispatchMessage);\n }\n\n async function dispatchMessage(ctx: KernelMessageContext): Promise<void> {\n const { message } = ctx;\n // A espera vem antes do roteador (ADR 0060). Retirada aqui de todo jeito: um comando digitado\n // no meio da conversa a cancela e segue para o roteador.\n const pending = conversations.take(message.chat.id, message.sender.id);\n if (pending !== undefined && router.match(message, ctx.text) === null) {\n if (pending.plugin !== MENU_OWNER) {\n await runStep(ctx, pending);\n return;\n }\n // Um número do menu roda a ação, como o clique; outro texto segue o fluxo normal (ADR 0062).\n const target = menuChoice(ctx, pending.data);\n if (target !== undefined) {\n await runAction(ctx, target);\n return;\n }\n }\n const result = await router.dispatch(ctx);\n if (!result.consumed) {\n await bus.emit('message', message, listenerExtras(ctx));\n return;\n }\n await afterCommand(ctx, result);\n }\n\n /** Recusa, falha e evento `command` do comando que consumiu a mensagem ou o clique. */\n async function afterCommand(\n ctx: KernelMessageContext,\n result: Extract<DispatchResult, { readonly consumed: true }>,\n ): Promise<void> {\n const { message } = ctx;\n if (result.status === 'rejected' && result.reply !== null) {\n // Sem await: a resposta espera a taxa da fila de saída, e o chat não precisa esperar.\n ctx.reply(result.reply).catch((error: unknown) =>\n ctx.log.warn('falha ao enviar a recusa do comando', {\n plugin: result.command.plugin,\n command: result.command.name,\n err: error,\n }),\n );\n } else if (result.status === 'failed') {\n const event: PluginErrorEvent = {\n plugin: result.command.plugin,\n phase: 'command',\n event: result.command.name,\n error: result.error,\n timedOut:\n result.error instanceof CommandTimeoutError ||\n result.error instanceof GroupAdminTimeoutError,\n };\n logPluginError(event);\n void bus.emit('plugin.error', event);\n }\n // Com await, como o `message`: o observador segura o chat e entra no `settled()` (ADR 0049).\n const { plugin, name, invokedAs } = result.command;\n await bus.emit('command', { plugin, name, invokedAs, status: result.status, message });\n }\n\n /**\n * Roda o passo que esperava esta mensagem. Ela para aqui: não vai ao roteador, a `message` nem\n * a `command`. A falha vira `plugin.error` com `phase: 'step'`.\n */\n async function runStep(\n ctx: KernelMessageContext,\n pending: PendingReply<KernelMessageContext>,\n ): Promise<void> {\n try {\n await pending.run(ctx, pending.data);\n } catch (error) {\n const event: PluginErrorEvent = {\n plugin: pending.plugin,\n phase: 'step',\n event: pending.step,\n error,\n timedOut: error instanceof StepTimeoutError,\n };\n logPluginError(event);\n void bus.emit('plugin.error', event);\n }\n }\n\n // --- Ações e botões (ADR 0062) -------------------------------------------------------------\n\n /**\n * Resolve as ações de um `reply`: guarda o alvo de cada uma sob um ID e devolve os botões ou,\n * sem a capability ou acima do limite, o texto com o menu numerado e a espera do remetente.\n */\n function prepareActions(owner: string | null, message: Message): PrepareActions {\n return (text, list) => {\n const targets = list.map((action) => actionTarget(owner, action));\n const chatId = message.chat.id;\n const ids = targets.map((target) => actions.register(chatId, target));\n const labels = targets.map(({ label }) => label);\n if (buttons && ids.length <= maxButtons) {\n return { text, actions: ids.map((id, index) => ({ id, label: labels[index] as string })) };\n }\n conversations.expect(MENU_OWNER, chatId, message.sender.id, MENU_STEP, { data: ids });\n return { text: numberedMenu(text, labels) };\n };\n }\n\n /** Valida a ação e devolve o alvo: o erro sai na chamada do `reply`, não no clique. */\n function actionTarget(owner: string | null, action: MessageAction): ActionTarget {\n const label: unknown = action?.label;\n if (typeof label !== 'string' || label.trim().length === 0) {\n throw new TypeError('ação sem `label`');\n }\n if ('command' in action) {\n if (router.registry.find(action.command) === undefined) {\n throw new TypeError(`ação \"${label}\": comando \"${action.command}\" não registrado`);\n }\n return {\n kind: 'command',\n label,\n command: action.command,\n args: Object.freeze([...(action.args ?? [])]),\n };\n }\n if ('step' in action) {\n if (owner === null) {\n throw new TypeError(`ação \"${label}\": passo só no contexto de um plugin`);\n }\n if (conversations.find(owner, action.step) === undefined) {\n throw new TypeError(\n `ação \"${label}\": plugin \"${owner}\" sem o passo \"${action.step}\"; defina-o com ` +\n 'ctx.conversations.define',\n );\n }\n return { kind: 'step', label, plugin: owner, step: action.step, data: action.data ?? null };\n }\n throw new TypeError(`ação \"${label}\" sem \\`command\\` nem \\`step\\``);\n }\n\n /** O alvo que a resposta ao menu numerado escolhe, se ela for um número da lista. */\n function menuChoice(ctx: KernelMessageContext, data: unknown): ActionTarget | undefined {\n const ids = data as readonly string[];\n const index = pickChoice(ctx.text, ids.length);\n if (index === null) return undefined;\n return actions.resolve(ids[index] as string, ctx.message.chat.id);\n }\n\n /**\n * O clique num botão: passa pela fila do chat e pelos middlewares como uma mensagem de texto com\n * o `label`, e roda o comando ou o passo da ação. Vencido, desconhecido ou de outro chat, é\n * descartado.\n */\n async function handleInteraction(interaction: Interaction): Promise<void> {\n if (interaction.command !== undefined) return handleNativeCommand(interaction);\n const { chat, sender, actionId } = interaction;\n const target = actions.resolve(actionId, chat.id);\n if (target === undefined) {\n log.debug('clique em botão vencido ou desconhecido; descartado', { chatId: chat.id });\n return;\n }\n const message = createMessage({\n type: 'text',\n id: interaction.id,\n chat,\n sender,\n text: target.label,\n timestamp: interaction.timestamp,\n fromMe: false,\n });\n interactions.set(message, interaction);\n await admit(message, async (ctx) => {\n // O clique é um comando: cancela a espera do remetente, como o comando digitado (ADR 0060).\n conversations.take(chat.id, sender.id);\n await runAction(ctx, target);\n });\n }\n\n /**\n * Comando nativo da plataforma (ADR 0064): roda como o clique num botão de comando, com o texto\n * livre interpretado como o que vem depois do comando digitado.\n */\n async function handleNativeCommand(interaction: CommandInteraction): Promise<void> {\n const { chat, sender, command, args } = interaction;\n const message = createMessage({\n type: 'text',\n id: interaction.id,\n chat,\n sender,\n // O texto que a plataforma mostra para o comando: quem lê a mensagem (middlewares, log) vê\n // o que a pessoa chamou.\n text: args.trim() === '' ? `/${command}` : `/${command} ${args.trimStart()}`,\n timestamp: interaction.timestamp,\n fromMe: false,\n });\n interactions.set(message, interaction);\n await admit(message, async (ctx) => {\n // Comando cancela a espera do remetente, como o digitado (ADR 0060).\n conversations.take(chat.id, sender.id);\n const result = await router.dispatch(ctx, { command, rawArgs: args });\n if (!result.consumed) {\n ctx.log.debug('comando nativo que não existe mais; descartado', { command });\n return;\n }\n await afterCommand(ctx, result);\n });\n }\n\n /** Roda o alvo da ação. Comando ou passo que não existe mais (plugin desligado) é descartado. */\n async function runAction(ctx: KernelMessageContext, target: ActionTarget): Promise<void> {\n if (target.kind === 'command') {\n const result = await router.dispatch(ctx, { command: target.command, args: target.args });\n if (!result.consumed) {\n ctx.log.debug('botão de comando que não existe mais; descartado', {\n command: target.command,\n });\n return;\n }\n await afterCommand(ctx, result);\n return;\n }\n const run = conversations.find(target.plugin, target.step);\n if (run === undefined) {\n ctx.log.debug('botão de passo que não existe mais; descartado', {\n plugin: target.plugin,\n step: target.step,\n });\n return;\n }\n await runStep(ctx, { plugin: target.plugin, step: target.step, data: target.data, run });\n }\n\n /** Extras dos eventos de mensagem: os campos chegam aos listeners pela visão de cada plugin. */\n function listenerExtras(ctx: KernelMessageContext): ListenerExtras<'message'> {\n return messageExtras(ctx) as unknown as ListenerExtras<'message'>;\n }\n\n /**\n * Edição passa pelas mesmas barreiras da mensagem nova (fila do chat, boot, middlewares — o\n * `rateLimit` a conta), mas não dispara comando: só os listeners de `message.edited`.\n */\n function handleEdited(message: Message): Promise<void> {\n return admit(message, async (ctx) => {\n await bus.emit('message.edited', ctx.message, listenerExtras(ctx));\n });\n }\n\n /**\n * Põe a mensagem (nova ou editada) ou o clique na fila do chat dele: o mesmo chat anda em\n * série. A tarefa roda no escopo do tenant do chat (ADR 0072).\n */\n function enqueue<T extends Message | Interaction>(\n item: T,\n handle: (item: T) => Promise<void>,\n ): void {\n const result = inbound.enqueue(item.chat.id, () =>\n tenants.run(item.chat.tenantId, () => handle(item)),\n );\n if (result !== 'queued') {\n log.warn('mensagem descartada pela fila de entrada', {\n chatId: item.chat.id,\n messageId: item.id,\n reason: result,\n });\n }\n }\n\n /**\n * Repassa um evento que não é mensagem ao barramento, depois do `chatFilter`, do `ignoreSelf` e\n * do `ignoreBots` (ADR 0038). Durante o boot, espera os plugins subirem; sem fila do chat.\n */\n function forward<E extends DirectEvent>(event: E): () => void {\n const origin = DIRECT_EVENTS[event];\n return transport.on(event, (transportPayload) => {\n // `BotEvents` estende `TransportEvents`: o payload é o mesmo tipo.\n const payload = transportPayload as BotEvents[E];\n const { chat, fromMe, fromBot } = origin(payload);\n if ((fromMe && dropsSelf) || (fromBot && dropsBots)) return;\n if (chat !== null && !chatIsAllowed(chat)) return;\n // Os listeners rodam no escopo do tenant do chat (ADR 0072). Ele vem do payload, não da\n // origem: entrada e saída do grupo passam pelo filtro sem chat, mas são de um tenant.\n const tenant = 'chat' in payload ? payload.chat.tenantId : undefined;\n tenants.run(tenant, () => {\n if (ready) {\n void bus.emit(event, payload);\n return;\n }\n // Boot abortado ou `stop()` antes do fim: o evento é descartado, como a mensagem.\n void readyPromise.then((ok) => {\n if (ok) void bus.emit(event, payload);\n });\n });\n });\n }\n\n /** Assina todos os eventos do transport; devolve a função que desfaz. */\n function subscribeTransport(): () => void {\n const offs: (() => void)[] = [\n transport.on('message', (message) => enqueue(message, handleMessage)),\n transport.on('message.edited', (message) => enqueue(message, handleEdited)),\n transport.on('interaction', (interaction) => enqueue(interaction, handleInteraction)),\n transport.on('connection.status', (status) => {\n // Com a conexão caída, o envio falharia e esgotaria o retry antes da reconexão (#198).\n if (status.status === 'closed') outbound.pause();\n else if (status.status === 'open') outbound.resume();\n reconnector?.onStatus(status);\n void bus.emit('connection.status', status);\n }),\n transport.on('connection.qr', (payload) => {\n reconnector?.onQr();\n // Quem lê o log em info (agregador, arquivo) pareia o número com o QR enquanto ele vale:\n // o valor fica em debug e no barramento (`connection.qr`), para quem exibe a tela.\n log.info('QR de pareamento recebido; exiba-o pelo evento connection.qr');\n log.debug('valor do QR de pareamento', { qr: payload.qr });\n void bus.emit('connection.qr', payload);\n }),\n transport.on('connection.pairing-code', (payload) => {\n // Mesma tentativa de pareamento que o QR (ADR 0050), e o mesmo risco no log.\n reconnector?.onQr();\n log.info('código de pareamento recebido; exiba-o pelo evento connection.pairing-code');\n log.debug('valor do código de pareamento', { code: payload.code });\n void bus.emit('connection.pairing-code', payload);\n }),\n ];\n for (const event of Object.keys(DIRECT_EVENTS) as DirectEvent[]) offs.push(forward(event));\n return () => {\n for (const off of offs.splice(0)) off();\n };\n }\n\n // --- Boot ---------------------------------------------------------------------------------\n\n /**\n * Ganchos internos, empilhados para o LIFO rodar na ordem do shutdown (docs/bot.md). Estourado\n * o prazo, cada um abandona o que falta (o `signal` aborta) em vez de seguir em segundo plano.\n */\n function registerInternalHooks(): void {\n const push = (name: string, timeoutMs: number, hook: StopHook): void => {\n hooks.push({ name, timeoutMs, hook });\n };\n push('fila-de-saida', STOP_TIMEOUTS.outbound, (signal) => {\n // Conexão caída: o gancho do transporte já parou a reconexão, então drenar só gastaria o\n // prazo. Descarta já (ADR 0039).\n if (outbound.paused) return outbound.close({ drain: false });\n // Drena até o prazo; estourado, descarta o que aguarda (docs/outbound-queue.md).\n signal.addEventListener('abort', () => void outbound.close({ drain: false }), {\n once: true,\n });\n return outbound.close();\n });\n // Desce depois do scheduler: o teardown não corre junto com um job do próprio plugin.\n push('plugins', STOP_TIMEOUTS.plugins, async (signal) => {\n const errors = (await host?.stop(signal)) ?? [];\n if (errors.length > 0) {\n throw new AggregateError(errors, `teardown: ${errors.length} falha(s) de plugin`);\n }\n });\n push('scheduler', STOP_TIMEOUTS.scheduler, (signal) => scheduler.stop(signal));\n push('fila-de-entrada', STOP_TIMEOUTS.inbound, (signal) => {\n signal.addEventListener('abort', () => void inbound.close({ drain: false }), {\n once: true,\n });\n return inbound.close();\n });\n push('transporte', STOP_TIMEOUTS.reconnection, async () => {\n // Para de aceitar eventos (nada novo entra na fila) e de reconectar.\n unsubscribe?.();\n settleReady(false);\n await reconnector?.stop();\n });\n }\n\n /**\n * Passo obrigatório do shutdown, sem prazo: abandona o que os ganchos internos não encerraram\n * (estouraram o prazo, ou nem rodaram porque o prazo total acabou antes). Depois dele nenhum\n * timer do bot fica vivo e as filas estão fechadas; jobs abandonados ficam no storage e\n * disparam na próxima subida. Num shutdown limpo, não acha nada a fazer.\n */\n async function abandonInternals(): Promise<void> {\n if (unsubscribe === undefined) return;\n unsubscribe();\n settleReady(false);\n const aborted = AbortSignal.abort();\n // Sem await: o que resta delas é trabalho já em andamento, e nenhuma das três rejeita.\n void reconnector?.stop();\n void inbound.close({ drain: false });\n // Middleware preso na mensagem abandonada: sem isto, o timer dele viveria até o prazo.\n pipeline.close();\n await scheduler.stop(aborted);\n // Teardown pulado ou abandonado vira falha que o host loga; o `dispose` roda para todos.\n await host?.stop(aborted);\n // Depois do descarte dos plugins, que já expirou o `Deadline` dos handlers presos (o\n // `signal` aborta, o `reply` é recusado): sobra só o timer do prazo de cada um.\n armed.disarmAll();\n // O `dispose` de cada plugin já tirou as esperas dele; isto garante que nenhum timer de TTL\n // sobreviva ao `stop()` e que um passo atrasado não registre outra.\n conversations.close();\n actions.clear();\n void outbound.close({ drain: false });\n }\n\n async function bootPlugins(): Promise<void> {\n // Antes do `setup`: um plugin pode ler o prefixo do chat já no boot.\n await prefixes.load();\n const entries = await collectPlugins({\n plugins: config.plugins,\n pluginDirs: config.pluginDirs,\n cwd: config.cwd,\n });\n configs = createPluginConfigs({\n plugins: entries.map((entry) => entry.definition),\n file: config.pluginConfig,\n storage: scoped,\n env: config.env,\n secrets,\n log,\n reload: (name) => reload(name),\n });\n const createContext = createPluginContextFactory({\n configs,\n log,\n router,\n prefixes,\n conversations,\n bus,\n services,\n storage: scoped,\n shared: sharedStorage(storage),\n tenants,\n scheduler,\n send,\n groups,\n http,\n onHttpError: (event) => {\n logPluginError(event);\n void bus.emit('plugin.error', event);\n },\n transport: {\n name: transport.name,\n capabilities,\n get self() {\n return transport.self;\n },\n },\n unsafe: createUnsafeAccess({\n transport,\n log,\n interactionOf: (message) => interactions.get(message),\n }),\n commandTimeoutMs,\n armed,\n onRoleError: (event) => {\n logPluginError(event);\n void bus.emit('plugin.error', event);\n },\n onLateCommandError: (plugin, command, error) => {\n // A recusa de um contexto expirado já foi logada quando aconteceu (ADR 0033).\n if (error instanceof ContextExpiredError) return;\n log.error(`comando \"${command}\" rejeitou depois do prazo`, {\n plugin,\n command,\n err: error,\n });\n },\n });\n const pluginHost = createPluginHost({\n plugins: entries,\n transport,\n createContext,\n log,\n disabledPlugins: config.disabledPlugins,\n setupTimeoutMs: timeouts.setupMs,\n teardownTimeoutMs: timeouts.teardownMs,\n });\n host = pluginHost;\n const table = await pluginHost.start();\n for (const entry of table) {\n if (entry.status !== 'skipped' || entry.reason.kind !== 'setup-failed') continue;\n const { error } = entry.reason;\n // Conflito de nome é erro no boot (ADR 0007 e 0035), não \"plugin ignorado\": quem\n // respondesse ao comando, papel ou serviço dependeria da ordem de carga.\n if (isBootConflict(error.cause)) throw error.cause;\n emitLifecycleError(error);\n }\n }\n\n async function reload(name: string): Promise<PluginReloadResult> {\n if (!host) throw new BotStateError(`reload(\"${name}\"): plugins ainda não carregados`, state);\n // Um aviso só ao transport, no fim: no meio, os comandos do plugin saíram e não voltaram.\n const pluginHost = host;\n const result = await catalog.batch(() => pluginHost.reload(name));\n for (const error of result.errors) emitLifecycleError(error);\n // Os dependentes recarregados em cascata (ADR 0041) também podem falhar no `setup` novo.\n for (const entry of [result.entry, ...result.dependents]) {\n if (entry.status === 'skipped' && entry.reason.kind === 'setup-failed') {\n emitLifecycleError(entry.reason.error);\n }\n }\n return result;\n }\n\n async function runStart(): Promise<void> {\n try {\n log = config.logger ?? createLogger({ level: config.logLevel ?? 'info', secrets });\n transportLog = log.child({ transport: transport.name });\n // Antes de `booted`: um bot recusado aqui não fecha o storage do bot que usa a sessão.\n releaseSession = claimSession(storage, session);\n booted = true;\n // Ligada já no boot: o `/health` mostra a sessão subindo (503) até ela ficar `running`.\n http?.attach(() => state);\n httpAttached = http !== undefined;\n if (config.storage === undefined) {\n log.warn('sem storage configurado: usando memória, os dados somem ao reiniciar');\n }\n // Sem conexão até o primeiro `open`: o `connect()` resolve ao iniciar a tentativa, e os\n // envios do setup e dos jobs vencidos iriam para um socket ainda fechado (ADR 0048). O\n // teto da pausa conta daqui.\n outbound.pause();\n unsubscribe = subscribeTransport();\n registerInternalHooks();\n // Antes dos plugins, que já gravam no storage e agendam jobs da sessão. Depois de assinar\n // os eventos: os que chegarem esperam a trava na fila do boot, como esperam os plugins.\n sessionLease = await acquireSessionLease({\n storage,\n session,\n log,\n signal: bootAbort.signal,\n onLost: () => {\n log.error('outro processo assumiu a trava da sessão; parando o bot', { session });\n bot.stop().catch((error: unknown) => log.error('falha ao parar o bot', { err: error }));\n },\n });\n } catch (error) {\n // Nada conectou ainda: só desfaz o que foi registrado.\n await shutdown().catch((cleanup: unknown) =>\n log.error('falha ao encerrar após erro no start', { err: cleanup }),\n );\n throw error;\n }\n\n // Plugins primeiro, connect depois (plano §5.3): um plugin quebrado (conflito de comando,\n // manifesto inválido, ciclo) derruba o boot antes de o transport abrir sessão — sem QR nem\n // handshake à toa.\n try {\n await bootPlugins();\n } catch (error) {\n log.error('falha ao carregar os plugins; encerrando', { err: error });\n // O transport nunca conectou: o encerramento não chama `disconnect()`.\n await failBoot(error);\n }\n // Com as rotas dos plugins e do transport registradas, abre a porta (se houver rota) antes\n // do connect: o transport pode precisar do webhook de pé para conectar. Porta ocupada derruba\n // o boot.\n try {\n await http?.listen();\n } catch (error) {\n log.error('falha ao abrir a porta HTTP; encerrando', { err: error });\n await failBoot(error);\n }\n // Daqui em diante, mudança na lista de comandos avisa o transport.\n catalog.open();\n\n // stop() chegou durante o boot: quem chamou stop() conduz o encerramento. Conferido também\n // antes do connect, para não abrir sessão (QR, handshake) só para fechá-la em seguida.\n const stoppedDuringBoot = (): BotStateError =>\n new BotStateError('start(): bot parado durante a inicialização', state);\n if (stopRequested) throw stoppedDuringBoot();\n\n // Mensagens que chegarem durante o handshake esperam na fila de entrada (`readyPromise`)\n // até o fim do boot. Conectado, uma queda já é reconectada.\n try {\n // O transport pode conectar pela metade: daqui em diante o encerramento desconecta.\n connectCalled = true;\n await callConnect(transport);\n reconnector?.activate();\n } catch (error) {\n await failBoot(error);\n }\n\n if (stopRequested) throw stoppedDuringBoot();\n scheduler.start();\n settleReady(true);\n state = 'running';\n }\n\n /** Encerra o que o boot já subiu e relança `failure` (ou o `AggregateError` com a limpeza). */\n async function failBoot(failure: unknown): Promise<never> {\n try {\n await shutdown();\n } catch (cleanupError) {\n const cleanup = cleanupError instanceof AggregateError ? cleanupError.errors : [];\n throw new AggregateError([failure, ...cleanup], 'start(): falha no boot e ao encerrar');\n }\n throw failure;\n }\n\n // --- Shutdown -----------------------------------------------------------------------------\n\n function shutdown(): Promise<void> {\n shutdownPromise ??= runShutdown();\n return shutdownPromise;\n }\n\n async function runShutdown(): Promise<void> {\n state = 'stopping';\n // O teardown tira os comandos de cada plugin: o transport não deve apagar o menu da plataforma.\n catalog.close();\n // LIFO: quem subiu por último depende de quem subiu antes, então desce primeiro.\n const errors: unknown[] = await runStopHooks(hooks.toReversed(), config.shutdown);\n hooks.length = 0;\n await abandonInternals();\n if (connectCalled) {\n try {\n await transport.disconnect();\n } catch (error) {\n errors.push(error);\n }\n }\n // Os teardowns já tiraram as rotas dos plugins; sai a do transport, e o último bot fecha a porta.\n if (httpAttached) {\n try {\n await http?.detach();\n } catch (error) {\n errors.push(error);\n }\n }\n // Storage por último: os teardowns e o scheduler ainda o usam até aqui. Se outro bot (outra\n // sessão) ainda o usa, quem fecha é o último a parar.\n // Liberada no stop limpo, a sessão sobe em outro processo na hora, sem esperar a validade.\n try {\n await sessionLease?.release();\n } catch (error) {\n errors.push(error);\n }\n const lastUser = releaseSession?.() ?? true;\n if (booted && lastUser) {\n try {\n await storage.close();\n } catch (error) {\n errors.push(error);\n }\n }\n state = 'stopped';\n if (errors.length > 0) {\n throw new AggregateError(errors, `stop(): ${errors.length} falha(s) no encerramento`);\n }\n }\n\n /**\n * As três fontes de trabalho se realimentam (o comando envia, o envio rejeitado vira\n * `plugin.error`, o listener envia de novo): repete a espera até as três estarem ociosas na\n * mesma conferência síncrona. Só roda quando chamado: o caminho da mensagem não paga nada.\n */\n async function settled(): Promise<void> {\n // Eventos diretos que chegam no boot esperam o `readyPromise` fora do barramento.\n if (state === 'starting') await readyPromise;\n while (!(inbound.stats().activeChats === 0 && bus.idle && outbound.stats().activeChats === 0)) {\n await inbound.onIdle();\n await bus.onIdle();\n await outbound.onIdle();\n }\n }\n\n const pluginConfigs: BotPluginConfigs = {\n setOverrides: (plugin, overrides) =>\n requireConfigs('setOverrides').setOverrides(plugin, overrides),\n describe: (plugin) => requireConfigs('describe').describe(plugin),\n jsonSchema: (plugin) => requireConfigs('jsonSchema').jsonSchema(plugin),\n };\n\n function requireConfigs(method: string): PluginConfigs {\n if (!configs) {\n throw new BotStateError(`config.${method}(): plugins ainda não carregados (start)`, state);\n }\n return configs;\n }\n\n const bot: Bot = {\n get state(): BotState {\n return state;\n },\n\n config: pluginConfigs,\n\n plugins(): PluginReportEntry[] {\n return host?.report() ?? [];\n },\n\n stats(): BotStats {\n return { inbound: inbound.stats(), outbound: outbound.stats() };\n },\n\n settled,\n\n start(): Promise<void> {\n switch (state) {\n case 'idle':\n state = 'starting';\n startPromise = runStart();\n return startPromise;\n case 'starting':\n case 'running':\n return startPromise ?? Promise.resolve();\n default:\n return Promise.reject(\n new BotStateError(`start(): bot em \"${state}\" não reinicia`, state),\n );\n }\n },\n\n stop(): Promise<void> {\n switch (state) {\n case 'idle':\n return shutdown();\n case 'starting': {\n stopRequested = true;\n bootAbort.abort(new BotStateError('start(): bot parado durante a inicialização', state));\n // Espera o boot assentar (sucesso ou falha) e só então encerra; se o start já\n // encerrou por falha, `shutdown` devolve a mesma promise.\n const afterStart = (): Promise<void> => shutdown();\n stopAfterStart ??= (startPromise ?? Promise.resolve()).then(afterStart, afterStart);\n return stopAfterStart;\n }\n case 'running':\n return shutdown();\n case 'stopping':\n return stopAfterStart ?? shutdownPromise ?? Promise.resolve();\n case 'stopped':\n return Promise.resolve();\n }\n },\n\n onStop(hook: StopHook, options: StopHookOptions = {}): () => void {\n if (state === 'stopping' || state === 'stopped') {\n throw new BotStateError(`onStop(): bot em \"${state}\" não aceita ganchos`, state);\n }\n const entry: RegisteredStopHook = {\n hook,\n name: options.name ?? (hook.name || 'anonimo'),\n timeoutMs: options.timeoutMs,\n };\n hooks.push(entry);\n return () => {\n const index = hooks.indexOf(entry);\n if (index !== -1) hooks.splice(index, 1);\n };\n },\n };\n return bot;\n}\n\n/** Nome de sessão no formato de nome de plugin: vira prefixo de namespace no storage. */\n/** Erros de `setup` que derrubam o boot em vez de só ignorar o plugin. */\nconst isBootConflict = (error: unknown): boolean =>\n error instanceof CommandConflictError ||\n error instanceof RoleConflictError ||\n error instanceof ServiceConflictError;\n\nfunction validateSession(session: string): string {\n if (!PLUGIN_NAME_PATTERN.test(session)) {\n throw new BotConfigError(\n `session deve ser kebab-case minúsculo (ex.: \"atendimento\"); recebido \"${session}\"`,\n );\n }\n return session;\n}\n\n/** Instância pronta, ou a que a fábrica monta; fábrica que lança é erro de config. */\nfunction resolveTransport(transport: BotConfig['transport'], deps: TransportDeps): Transport {\n let resolved: Transport;\n if (typeof transport !== 'function') resolved = transport;\n else {\n try {\n resolved = transport(deps);\n } catch (error) {\n throw new BotConfigError('transport: a fábrica lançou ao montar o transport', {\n cause: error,\n });\n }\n }\n // Capability sem o método dela só falharia quando um plugin a usasse (ADR 0080).\n const issues = transportIssues(resolved);\n if (issues.length > 0) {\n throw new BotConfigError(`transport inválido:\\n- ${issues.join('\\n- ')}`);\n }\n return resolved;\n}\n\n/** `transport.connect()` com um throw síncrono do adapter virando rejeição. */\nfunction callConnect(transport: Transport): Promise<void> {\n try {\n return transport.connect();\n } catch (error) {\n return Promise.reject(error);\n }\n}\n\n/**\n * A consulta de admin do grupo ao transport (`role: 'group-admin'`) estourou o prazo do comando.\n * O comando não roda e sai `plugin.error` com `timedOut: true` no plugin dono do comando.\n */\nexport class GroupAdminTimeoutError extends Error {\n override readonly name = 'GroupAdminTimeoutError';\n readonly chatId: string;\n readonly timeoutMs: number;\n\n constructor(chatId: string, timeoutMs: number) {\n super(`consulta de admin do grupo \"${chatId}\" ao transport excedeu ${timeoutMs} ms`);\n this.chatId = chatId;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Porta `isGroupAdmin` do roteador, a partir do transport: o `isChatAdmin` dele, se houver, ou a\n * lista de participantes do `getGroupMetadata` (capability `groups`, ADR 0059). Com o prazo do\n * comando: uma consulta que nunca resolve seguraria o chat na fila de entrada para sempre. O\n * timer só existe para quem não é owner pedindo comando de admin num grupo.\n */\nfunction groupAdminPort(\n transport: Transport,\n timeoutMs: number,\n onLate: (error: unknown) => void,\n armed: ArmedTimers,\n): IsGroupAdmin | undefined {\n const within = <T>(work: Promise<T>, chatId: string): Promise<T> =>\n settleWithin(\n work,\n timeoutMs,\n () => new GroupAdminTimeoutError(chatId, timeoutMs),\n onLate,\n armed,\n ) as Promise<T>;\n if (transport.isChatAdmin) {\n const isChatAdmin = transport.isChatAdmin.bind(transport);\n return (chat, sender) => within(isChatAdmin(chat, sender), chat.id);\n }\n if (!hasCapability(transport, 'groups')) return undefined;\n return async (chat, sender) => {\n const metadata = await within(transport.getGroupMetadata(chat.id), chat.id);\n // Sem a lista, não há como saber: recusa (fail-closed). Transport que não lista membros\n // deve implementar `isChatAdmin`.\n if (!metadata.participants) return false;\n // Casa por id ou, quando os dois lados o têm, por telefone: o remetente e o participante\n // podem vir com IDs de espaços diferentes (no WhatsApp, LID e JID de telefone; ADR 0046).\n // Sem telefone de um lado, só o id decide (fail-closed).\n return metadata.participants.some(\n (participant) =>\n participant.isAdmin &&\n (participant.id === sender.id ||\n (sender.phone !== null && participant.phone === sender.phone)),\n );\n };\n}\n\n/** Máximo de botões por mensagem do transport (`limits.actions`); sem ele, sem limite. */\nfunction buttonLimit(transport: Transport): number {\n const limit = transport.limits?.actions;\n if (limit === undefined) return Number.POSITIVE_INFINITY;\n if (!(Number.isInteger(limit) && limit >= 1)) {\n throw new RangeError(`limits.actions do transport deve ser inteiro >= 1 (recebido: ${limit})`);\n }\n return limit;\n}\n\n/** Pipeline com os middlewares oficiais ligados pela config e os do app. */\nfunction createPipeline(\n options: BotMiddlewaresConfig,\n timeoutMs: number,\n log: () => Logger,\n): MiddlewarePipeline<KernelMessageContext> {\n // Middleware roda dentro da tarefa da fila do chat: sem prazo, um preso seguraria o chat\n // para sempre (ADR 0043).\n const pipeline = new MiddlewarePipeline<KernelMessageContext>({\n timeoutMs,\n onLateError: (error) => log().error('middleware rejeitou depois do prazo', { err: error }),\n });\n if (options.ignoreSelf !== false) {\n pipeline.use(ignoreSelf(), { priority: MIDDLEWARE_PRIORITY.ignoreSelf });\n }\n if (options.ignoreBots !== false) {\n pipeline.use(ignoreBots(), { priority: MIDDLEWARE_PRIORITY.ignoreBots });\n }\n if (options.chatFilter) {\n pipeline.use(chatFilter(options.chatFilter), { priority: MIDDLEWARE_PRIORITY.chatFilter });\n }\n if (options.rateLimit) {\n const limit = rateLimit({\n onLimited: (ctx) =>\n log().debug('mensagem barrada pelo rate limit', {\n chatId: ctx.message.chat.id,\n senderId: ctx.message.sender.id,\n }),\n ...options.rateLimit,\n });\n pipeline.use(limit, { priority: MIDDLEWARE_PRIORITY.rateLimit });\n }\n if (options.sanitize !== false) {\n pipeline.use(sanitize(options.sanitize), { priority: MIDDLEWARE_PRIORITY.sanitize });\n }\n for (const entry of options.use ?? []) {\n if (typeof entry === 'function') pipeline.use(entry);\n else pipeline.use(entry.middleware, { priority: entry.priority });\n }\n return pipeline;\n}\n"],"mappings":";;;;;;;;;;;;AA8BA,SAAgB,UAAU,OAA2C;CACnE,OAAO,OAAO,OAAO;EAAE,MAAM;EAAa,OAAO,OAAO,OAAO,CAAC,GAAG,KAAK,CAAC;CAAE,CAAC;AAC9E;;AAGA,SAAS,QAAQ,OAA2B,OAA2B;CACrE,MAAM,QAAoB,CAAC;CAC3B,KAAK,MAAM,QAAQ,OACjB,IAAI,OAAO,SAAS,UACd;MAAA,SAAS,IAAI,MAAM,KAAK,IAAI;CAAA,OAC3B,IAAI,YAAY,IAAI,GACzB,MAAM,KAAK,GAAG,KAAK,KAAK;MAExB,MAAM,IAAI,UAAU,GAAG,MAAM,gDAAgD,OAAO,MAAM;CAG9F,OAAO;AACT;AAEA,SAAgB,YAAY,OAAwC;CAClE,OACE,OAAO,UAAU,YACjB,UAAU,QACT,MAA6B,SAAS,eACvC,MAAM,QAAS,MAA8B,KAAK;AAEtD;AAGA,SAAS,MAAM,MAAyB,OAA2C;CACjF,MAAM,WAAW,QAAQ,OAAO,IAAI;CACpC,IAAI,SAAS,WAAW,GAAG,OAAO,UAAU,CAAC,CAAC;CAC9C,OAAO,UAAU,CAAC,OAAO,OAAO;EAAE;EAAM,UAAU,OAAO,OAAO,QAAQ;CAAE,CAAC,CAAC,CAAC;AAC/E;AAEA,SAAgB,KAAK,GAAG,OAAkC;CACxD,OAAO,MAAM,QAAQ,KAAK;AAC5B;AAEA,SAAgB,OAAO,GAAG,OAAkC;CAC1D,OAAO,MAAM,UAAU,KAAK;AAC9B;;AAGA,SAAgB,KAAK,MAA6B;CAChD,IAAI,OAAO,SAAS,UAAU,MAAM,IAAI,UAAU,uBAAuB;CACzE,IAAI,SAAS,IAAI,OAAO,UAAU,CAAC,CAAC;CACpC,OAAO,UAAU,CAAC,OAAO,OAAO;EAAE,MAAM;EAAQ;CAAK,CAAC,CAAC,CAAC;AAC1D;;;;;AAMA,SAAgB,KAAK,KAAa,OAAiC;CACjE,IAAI;CACJ,IAAI;EACF,SAAS,IAAI,IAAI,GAAG;CACtB,SAAS,OAAO;EACd,MAAM,IAAI,UAAU,uBAAuB,OAAO,GAAG,KAAK,EAAE,OAAO,MAAM,CAAC;CAC5E;CACA,IAAI,OAAO,aAAa,WAAW,OAAO,aAAa,UACrD,MAAM,IAAI,UAAU,sCAAsC,KAAK;CAEjE,MAAM,WAAW,QAAQ,CAAC,SAAS,GAAG,GAAG,MAAM;CAC/C,OAAO,UAAU,CACf,OAAO,OAAO;EACZ,MAAM;EACN;EACA,UAAU,OAAO,OAAO,SAAS,SAAS,WAAW,CAAC,GAAG,CAAC;CAC5D,CAAC,CACH,CAAC;AACH;;;;;AAMA,SAAgB,QAAQ,SAAuC;CAC7D,IAAI,OAAO,SAAS,OAAO,YAAY,QAAQ,OAAO,IACpD,MAAM,IAAI,UAAU,uCAAuC;CAE7D,MAAM,SAAwB,OAAO,OAAO;EAC1C,IAAI,QAAQ;EACZ,MAAM,QAAQ,QAAQ;EACtB,OAAO,QAAQ,SAAS;EACxB,GAAI,QAAQ,aAAa,KAAA,KAAa,EAAE,UAAU,QAAQ,SAAS;CACrE,CAAC;CACD,OAAO,UAAU,CAAC,OAAO,OAAO;EAAE,MAAM;EAAW,SAAS;CAAO,CAAC,CAAC,CAAC;AACxE;;;;;AAMA,SAAgB,IACd,SACA,GAAG,QACY;CACf,MAAM,QAAmB,CAAC;CAC1B,QAAQ,SAAS,SAAS,UAAU;EAClC,MAAM,KAAK,OAAO;EAClB,IAAI,QAAQ,OAAO,QAAQ;GACzB,MAAM,QAAQ,OAAO;GACrB,MAAM,KAAK,OAAO,UAAU,WAAW,OAAO,KAAK,IAAI,KAAK;EAC9D;CACF,CAAC;CACD,OAAO,UAAU,QAAQ,OAAO,KAAK,CAAC;AACxC;;;;;AAMA,SAAgB,UAAU,MAA2B;CACnD,IAAI,OAAO,SAAS,UAAU,OAAO;CACrC,IAAI,MAAM;CACV,MAAM,QAAQ,UAAqC;EACjD,KAAK,MAAM,QAAQ,OACjB,IAAI,OAAO,SAAS,UAAU,OAAO;OAChC,IAAI,KAAK,SAAS,QAAQ,OAAO,KAAK;OACtC,IAAI,KAAK,SAAS,WAAW,OAAO,IAAI,aAAa,KAAK,OAAO;OACjE,KAAK,KAAK,QAAQ;CAE3B;CACA,KAAK,KAAK,KAAK;CACf,OAAO;AACT;AAEA,SAAS,aAAa,SAAgC;CACpD,OAAO,QAAQ,YAAY,QAAQ,QAAQ,QAAQ,SAAS,QAAQ;AACtE;;;;AC9GA,MAAa,gBAAwB;;;;;AAerC,IAAa,iBAAb,MAA4B;CAE1B,2BAAoB,IAAI,IAA0B;CAClD;CAEA,YAAY,MAAoB,KAAK,KAAK;EACxC,KAAK,OAAO;CACd;;CAGA,SAAS,QAAgB,QAA8B;EACrD,MAAM,MAAM,KAAK,KAAK;EACtB,KAAK,OAAO,GAAG;EAEf,MAAM,KAAK,YAAY,EAAE,CAAC,CAAC,SAAS,WAAW;EAC/C,KAAK,SAAS,IAAI,IAAI;GAAE;GAAQ;GAAQ,WAAW,MAAM;EAAc,CAAC;EACxE,OAAO;CACT;;CAGA,QAAQ,IAAY,QAA0C;EAC5D,MAAM,SAAS,KAAK,SAAS,IAAI,EAAE;EACnC,IAAI,WAAW,KAAA,GAAW,OAAO,KAAA;EACjC,IAAI,OAAO,aAAa,KAAK,KAAK,GAAG;GACnC,KAAK,SAAS,OAAO,EAAE;GACvB;EACF;EACA,OAAO,OAAO,WAAW,SAAS,OAAO,SAAS,KAAA;CACpD;;CAGA,QAAc;EACZ,KAAK,SAAS,MAAM;CACtB;CAEA,IAAI,OAAe;EACjB,OAAO,KAAK,SAAS;CACvB;CAEA,OAAO,KAAmB;EACxB,KAAK,MAAM,CAAC,IAAI,WAAW,KAAK,UAAU;GACxC,IAAI,OAAO,YAAY,OAAO,KAAK,SAAS,OAAA,KAA2B;GACvE,KAAK,SAAS,OAAO,EAAE;EACzB;CACF;AACF;;AAGA,SAAgB,aAAa,MAAmB,QAAwC;CACtF,MAAM,OAAO,OAAO,KAAK,OAAO,UAAU,GAAG,QAAQ,EAAE,IAAI,OAAO,CAAC,CAAC,KAAK,IAAI;CAE7E,OAAO,OAAO,SAAS,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,GAAG,KAAK,MAAM;AAC5E;AAEA,MAAM,SAAS;;AAGf,SAAgB,WAAW,MAAqB,OAA8B;CAC5E,MAAM,UAAU,MAAM,KAAK;CAC3B,IAAI,YAAY,KAAA,KAAa,CAAC,OAAO,KAAK,OAAO,GAAG,OAAO;CAC3D,MAAM,SAAS,OAAO,OAAO;CAC7B,OAAO,UAAU,KAAK,UAAU,QAAQ,SAAS,IAAI;AACvD;;;;AC3HA,SAAgB,YAAY,EAAE,QAAQ,cAA8C;CAClF,OAAO;EACL;EACA,MAAM,WAAW;EACjB,SAAS,CAAC,GAAI,WAAW,WAAW,CAAC,CAAE;EACvC,aAAa,WAAW,eAAe;EACvC,MAAM,WAAW,QAAQ;CAC3B;AACF;AAwBA,SAAgB,qBAAqB,SAAgD;CACnF,IAAI,QAAoC;CAExC,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,IAAI,YAAY;CAChB,MAAM,4BAAY,IAAI,IAAc;CAEpC,SAAS,OAAO,UAA0B;EACxC,IAAI;GACF,MAAM,SAAS,SAAS;GACxB,IAAI,kBAAkB,SAAS,OAAO,MAAM,QAAQ,OAAO;EAC7D,SAAS,OAAO;GACd,QAAQ,QAAQ,KAAK;EACvB;CACF;CAEA,SAAS,QAAc;EACrB,YAAY;EAEZ,IAAI,UAAU,UAAU,QAAQ,KAAK,CAAC,OAAO;EAC7C,QAAQ;EACR,KAAK,MAAM,YAAY,CAAC,GAAG,SAAS,GAAG,OAAO,QAAQ;CACxD;CAEA,SAAS,WAAiB;EACxB,IAAI,WAAW;EACf,YAAY;EAEZ,eAAe,KAAK;CACtB;CAEA,OAAO;EACL,UAAU;GACR,YAAY,QAAQ,KAAK,CAAC,CAAC,IAAI,WAAW;GAC1C,SAAS,UAAU;IAEjB,IAAI,UAAU,UAAU,UAAU,IAAI,QAAQ;IAC9C,aAAa;KACX,UAAU,OAAO,QAAQ;IAC3B;GACF;EACF;EAEA,UAAU;GACR,IAAI,UAAU,QAAQ;GACtB,QAAQ;GACR,IAAI,UAAU,GAAG,SAAS;EAC5B;EAEA,OAAO;GACL,IAAI,UAAU,QAAQ,QAAQ;EAChC;EAEA,QAAQ;GACN,QAAQ;GACR,UAAU,MAAM;EAClB;EAEA,MAAM,MAAM,MAAM;GAChB;GACA,IAAI;IACF,OAAO,MAAM,KAAK;GACpB,UAAU;IACR;IACA,IAAI,UAAU,KAAK,OAAO,SAAS;GACrC;EACF;CACF;AACF;ACzEA,MAAM,qBAAqB;;;;;AAM3B,SAAgB,eAAe,QAAiB,OAAuB;CACrE,IAAI,OAAO,WAAW,UAAU,MAAM,IAAI,UAAU,GAAG,MAAM,2BAA2B;CACxF,IAAI,mBAAmB,KAAK,MAAM,GAChC,MAAM,IAAI,UAAU,GAAG,MAAM,kDAAkD;CAEjF,OAAO;AACT;AAEA,SAAgB,kBACd,QACA,MACa;CACb,MAAM,QAAQ,OAAO,WAAW,WAAW,SAAS;EAAE,IAAI;EAAQ,OAAO;CAAO;CAChF,MAAM,KAAK,eAAe,MAAM,MAAA,KAAsB,WAAW,CAAC,CAAC,YAAY;CAC/E,MAAM,QAAQ,eAAe,MAAM,SAAA,KAAyB,cAAc,CAAC,CAAC,YAAY;CACxF,MAAM,4BAAY,IAAI,IAAoB;CAE1C,IAAI;CACJ,MAAM,mBAA+C;EACnD,UAAU,cAAc,MAAM,UAAU,CAAC,CAAC,WAA2B,SAAS,EAC5E,SAAS,CAAC,MAAM,EAClB,CAAC;EACD,OAAO;CACT;CAGA,IAAI,QAA0B,QAAQ,QAAQ;CAC9C,MAAM,WAAc,SAAuC;EACzD,MAAM,MAAM,MAAM,KAAK,IAAI;EAC3B,QAAQ,IAAI,YAAY,KAAA,CAAS;EACjC,OAAO;CACT;CAEA,OAAO;EACL,MAAM,OAAO;GACX,KAAK,MAAM,EAAE,MAAM,YAAY,MAAM,WAAW,CAAC,CAAC,KAAK,GAAG,UAAU,IAAI,MAAM,MAAM;EACtF;EAEA,IAAI,MAAM;GACR,OAAO,UAAU,IAAI,KAAK,EAAE,MAAM,KAAK,UAAU,QAAQ;EAC3D;EAEA,IAAI,QAAQ,QAAQ;GAClB,MAAM,QAAQ,eAAe,QAAQ,cAAc,CAAC,CAAC,YAAY;GACjE,OAAO,QAAQ,YAAY;IAGzB,IAAI,MADkB,WAAW,CAAC,CAAC,OAAO,EAAE,MAAM,OAAO,GAAG,EAAE,QAAQ,MAAM,CAAC,MAC7D,GAAG,MAAM,WAAW,CAAC,CAAC,OAAO;KAAE,MAAM;KAAQ,QAAQ;IAAM,CAAC;IAC5E,UAAU,IAAI,QAAQ,KAAK;GAC7B,CAAC;EACH;EAEA,MAAM,QAAQ;GACZ,OAAO,QAAQ,YAAY;IACzB,MAAM,UAAU,MAAM,WAAW,CAAC,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC;IAC1D,UAAU,OAAO,MAAM;IACvB,OAAO,UAAU;GACnB,CAAC;EACH;CACF;AACF;;;ACaA,MAAM,QAAQ;AAEd,SAAS,YAAY,OAAe,MAAoB;CACtD,IAAI,CAAC,MAAM,KAAK,KAAK,GACnB,MAAM,IAAI,UACR,GAAG,KAAK,wBAAwB,KAAK,UAAU,KAAK,EAAE,uBACxD;AAEJ;;;;;;AAOA,SAAgB,wBAAwB,YAAqC;CAC3E,YAAY,WAAW,MAAM,MAAM;CACnC,KAAK,MAAM,SAAS,WAAW,WAAW,CAAC,GAAG,YAAY,OAAO,OAAO;CACxE,MAAM,EAAE,cAAc;CACtB,IAAI,cAAc,KAAA,KAAa,EAAE,OAAO,SAAS,SAAS,KAAK,YAAY,IACzE,MAAM,IAAI,WAAW,qBAAqB,WAAW,KAAK,cAAc,WAAW;AAEvF;;;;;AAMA,SAAgB,QAAQ,YAAkD;CACxE,wBAAwB,UAAU;CAClC,OAAO;AACT;;;;ACtIA,IAAa,uBAAb,cAA0C,MAAM;CAC9C,OAAyB;;CAEzB;CACA;CACA;CAEA,YAAY,OAAe,UAA6B,UAA6B;EACnF,MACE,wBAAwB,MAAM,MAAM,SAAS,WAAW,KAAK,eACvD,SAAS,OAAO,gBAAgB,SAAS,WAAW,KAAK,eACzD,SAAS,OAAO,iDACxB;EACA,KAAK,QAAQ;EACb,KAAK,WAAW;EAChB,KAAK,WAAW;CAClB;AACF;;AAiBA,SAAS,SAAS,YAA4C;CAC5D,MAAM,yBAAS,IAAI,IAAI,CAAC,WAAW,KAAK,YAAY,CAAC,CAAC;CACtD,KAAK,MAAM,SAAS,WAAW,WAAW,CAAC,GAAG,OAAO,IAAI,MAAM,YAAY,CAAC;CAC5E,OAAO;AACT;AAOA,SAAgB,sBAAsB,UAAkC,CAAC,GAAoB;CAE3F,MAAM,0BAAU,IAAI,IAA+B;CACnD,MAAM,2BAAW,IAAI,IAAuB;CAE5C,OAAO;EACL,IAAI,QAAQ,YAAY;GAGtB,wBAAwB,UAAU;GAClC,MAAM,QAA2B;IAAE;IAAQ;GAAW;GACtD,MAAM,SAAS,SAAS,UAAU;GAElC,KAAK,MAAM,SAAS,QAAQ;IAC1B,MAAM,WAAW,QAAQ,IAAI,KAAK;IAClC,IAAI,UAAU,MAAM,IAAI,qBAAqB,OAAO,UAAU,KAAK;GACrE;GACA,KAAK,MAAM,SAAS,QAAQ,QAAQ,IAAI,OAAO,KAAK;GACpD,SAAS,IAAI,KAAK;GAClB,QAAQ,WAAW;EACrB;EAEA,aAAa,QAAQ;GACnB,IAAI,UAAU;GACd,KAAK,MAAM,SAAS,UAAU;IAC5B,IAAI,MAAM,WAAW,QAAQ;IAC7B,SAAS,OAAO,KAAK;IACrB,KAAK,MAAM,SAAS,SAAS,MAAM,UAAU,GAAG,QAAQ,OAAO,KAAK;IACpE,UAAU;GACZ;GAEA,IAAI,SAAS,QAAQ,WAAW;EAClC;EAEA,KAAK,OAAO;GACV,OAAO,QAAQ,IAAI,MAAM,YAAY,CAAC;EACxC;EAEA,OAAO;GACL,OAAO,CAAC,GAAG,QAAQ;EACrB;CACF;AACF;;;;;;;;;;;;AClFA,IAAa,WAAb,MAAsB;CACpB;CACA,WAAW;CACX;CAGA;CACA;CAEA,SAAS;CACT;CAEA,YAAY,QAAmB;EAC7B,KAAK,UAAU;CACjB;;CAGA,IAAI,UAAmB;EACrB,OAAO,KAAK,YAAY,KAAK,SAAS,YAAY;CACpD;;CAGA,IAAI,SAAkB;EACpB,OAAO,KAAK,WAAW,KAAK,UAAU,KAAK,SAAS;CACtD;;CAGA,IAAI,SAAsB;EACxB,IAAI,KAAK,YAAY,KAAA,GAAW;GAC9B,KAAK,cAAc,IAAI,gBAAgB;GACvC,IAAI,KAAK,UAAU,KAAK,YAAY,MAAM,KAAK,OAAO;GACtD,MAAM,MAAM,KAAK,YAAY;GAG7B,KAAK,UAAU,KAAK,YAAY,KAAA,IAAY,MAAM,YAAY,IAAI,CAAC,KAAK,KAAK,QAAQ,MAAM,CAAC;EAC9F;EACA,OAAO,KAAK;CACd;;;;;;;CAQA,KAAQ,WAAmC;EACzC,IAAI,KAAK,aAAa,GAAG,KAAK,UAAU,IAAI;EAC5C,MAAM,gBAAsB;GAC1B,IAAI,EAAE,KAAK,WAAW,GAAG,KAAK,UAAU,KAAK;EAC/C;EACA,OAAO,UAAU,MACd,UAAU;GACT,QAAQ;GACR,OAAO;EACT,IACC,UAAmB;GAClB,QAAQ;GACR,MAAM;EACR,CACF;CACF;;;;;CAMA,SAAS,WAAmB,MAA8B;EACxD,IAAI,YAAY;EAChB,IAAI,YAAY;EAChB,IAAI;EACJ,MAAM,cAAoB;GACxB,YAAY,YAAY,IAAI;GAC5B,QAAQ,iBACA;IACJ,KAAK,UAAU,KAAA;IACf,KAAK;GACP,GACA,KAAK,IAAI,GAAG,SAAS,CACvB;EACF;EACA,KAAK,WAAW,SAAS;GACvB,IAAI,MAAM;IACR,aAAa,KAAK;IAClB,QAAQ,KAAA;IACR,aAAa,YAAY,IAAI,IAAI;GACnC,OACE,MAAM;EAEV;EAEA,IAAI,KAAK,WAAW,GAAG,MAAM;EAC7B,aAAa;GACX,aAAa,KAAK;GAClB,KAAK,UAAU,KAAA;EACjB;CACF;;CAGA,OAAO,QAAuB;EAC5B,IAAI,KAAK,SAAS;EAClB,KAAK,WAAW;EAChB,KAAK,UAAU;EACf,KAAK,aAAa,MAAM,MAAM;CAChC;AACF;;;;;AAMA,IAAa,wBAAb,cAA2C,MAAM;CAC/C,OAAiC;CACjC;CACA;CAEA,YAAY,QAAgB,MAAc,WAAmB;EAC3D,MAAM,GAAG,KAAK,cAAc,OAAO,YAAY,UAAU,IAAI;EAC7D,KAAK,SAAS;EACd,KAAK,YAAY;CACnB;AACF;;AAGA,IAAa,uBAAb,cAA0C,sBAAsB;CAC9D,OAAiC;CACjC;CAEA,YAAY,QAAgB,OAAe,WAAmB;EAC5D,MAAM,QAAQ,gBAAgB,MAAM,IAAI,SAAS;EACjD,KAAK,QAAQ;CACf;AACF;;AAGA,IAAa,kBAAb,cAAqC,sBAAsB;CACzD,OAAiC;CACjC;CAEA,YAAY,QAAgB,KAAa,WAAmB;EAC1D,MAAM,QAAQ,QAAQ,IAAI,IAAI,SAAS;EACvC,KAAK,MAAM;CACb;AACF;;;;;;AAOA,IAAa,sBAAb,cAAyC,MAAM;CAC7C,OAAyB;CACzB;;CAEA;;CAEA;CAEA,YAAY,QAAgB,WAAmB,OAAe,OAAgB;EAC5E,MACE,WAAW,OAAO,KAAK,UAAU,cAAc,MAAM,wHAErD,EAAE,MAAM,CACV;EACA,KAAK,SAAS;EACd,KAAK,YAAY;EACjB,KAAK,QAAQ;CACf;AACF;;;;;;AAOA,MAAa,WAA0B,OAAO,kBAAkB;;AAOhE,SAAgB,WAAW,KAAmC;CAC5D,OAAQ,IAAqB;AAC/B;AAEA,SAAgBA,aAAW,OAA+C;CACxE,OACE,UAAU,SACT,OAAO,UAAU,YAAY,OAAO,UAAU,eAC/C,OAAQ,MAA+B,SAAS;AAEpD;;;;;AAMA,IAAa,cAAb,MAAyB;CACvB,2BAAoB,IAAI,IAAgB;CAExC,IAAI,QAA0B;EAC5B,KAAK,SAAS,IAAI,MAAM;CAC1B;CAEA,OAAO,QAA0B;EAC/B,KAAK,SAAS,OAAO,MAAM;CAC7B;;;;;;CAOA,YAAkB;EAChB,KAAK,MAAM,UAAU,KAAK,UAAU,OAAO;EAC3C,KAAK,SAAS,MAAM;CACtB;AACF;;;;;;;;;AAUA,SAAgB,aACd,QACA,WACA,WACA,QACA,OACA,UACS;CACT,IAAI,CAACA,aAAW,MAAM,GAAG,OAAO;CAChC,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,IAAI,UAAU;EACd,MAAM,eAAqB;GACzB,UAAU;GACV,OAAO;GACP,MAAM,OAAO,MAAM;EACrB;EACA,MAAM,aAAmB;GACvB,OAAO;GACP,OAAO,UAAU,CAAC;EACpB;EACA,IAAI;EACJ,IAAI,aAAa,KAAA,GAAW;GAC1B,MAAM,QAAQ,WAAW,MAAM,SAAS;GACxC,eAAe,aAAa,KAAK;EACnC,OACE,SAAS,SAAS,SAAS,WAAW,IAAI;EAE5C,MAAM,IAAI,MAAM;EAChB,OAAO,MACJ,UAAU;GACT,IAAI,SAAS;GACb,OAAO;GACP,QAAQ,KAAK;EACf,IACC,UAAmB;GAClB,IAAI,SAAS;IACX,OAAO,KAAK;IACZ;GACF;GACA,OAAO;GACP,OAAO,KAAK;EACd,CACF;CACF,CAAC;AACH;;;;ACtQA,MAAa,iCAAsC,IAAI,IAAI;CAAC;CAAS;CAAe;AAAU,CAAC;;AAgC/F,IAAa,oBAAb,cAAuC,MAAM;CAC3C,OAAyB;CACzB;CACA;CACA;CAEA,YAAY,MAAc,UAAkB,UAAkB;EAC5D,MACE,aAAa,WACT,UAAU,KAAK,qCAAqC,SAAS,4FAE7D,sBAAsB,KAAK,eAAe,SAAS,yCACtC,SAAS,sCAAsC,SAAS,iDAE3E;EACA,KAAK,OAAO;EACZ,KAAK,WAAW;EAChB,KAAK,WAAW;CAClB;AACF;AAaA,MAAM,YAAY;AAElB,SAAgB,qBAAmC;CACjD,MAAM,yBAAS,IAAI,IAA4B;CAC/C,OAAO;EACL,OAAO,QAAQ,MAAM,OAAO;GAC1B,IAAI,CAAC,UAAU,KAAK,IAAI,GACtB,MAAM,IAAI,UACR,2BAA2B,KAAK,UAAU,IAAI,EAAE,uBAClD;GAEF,IAAI,eAAe,IAAI,IAAI,GACzB,MAAM,IAAI,UACR,UAAU,KAAK,0DAA0D,OAAO,yBAElF;GAEF,MAAM,WAAW,OAAO,IAAI,IAAI;GAChC,IAAI,UAAU,MAAM,IAAI,kBAAkB,MAAM,SAAS,QAAQ,MAAM;GACvE,OAAO,IAAI,MAAM;IAAE;IAAQ;IAAM;GAAM,CAAC;EAC1C;EAEA,aAAa,QAAQ;GACnB,KAAK,MAAM,CAAC,MAAM,SAAS,QACzB,IAAI,KAAK,WAAW,QAAQ,OAAO,OAAO,IAAI;EAElD;EAEA,OAAO,SAAS,OAAO,IAAI,IAAI;CACjC;AACF;;AAGA,IAAa,mBAAb,cAAsC,sBAAsB;CAC1D,OAAiC;CACjC;CAEA,YAAY,QAAgB,MAAc,WAAmB;EAC3D,MAAM,QAAQ,sBAAsB,KAAK,IAAI,SAAS;EACtD,KAAK,OAAO;CACd;AACF;;;AC7HA,MAAM,yBAAsC,IAAI,IAAI,CAClD,CAAC,MAAK,IAAG,GACT,CAAC,KAAK,GAAG,CACX,CAAC;AAED,MAAM,aAAa;;;;;;;AAQnB,SAAgB,UAAU,OAAyB;CACjD,MAAM,OAAiB,CAAC;CACxB,IAAI,UAAU;CAEd,IAAI,QAAQ;CACZ,IAAI,UAAyB;CAE7B,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,YAAY,MAAM;GACpB,IAAI,SAAS,SAAS,UAAU;QAC3B,WAAW;GAChB;EACF;EACA,MAAM,QAAQ,OAAO,IAAI,IAAI;EAC7B,IAAI,UAAU,KAAA,GAAW;GACvB,UAAU;GACV,QAAQ;GACR;EACF;EACA,IAAI,WAAW,KAAK,IAAI,GAAG;GACzB,IAAI,OAAO;IACT,KAAK,KAAK,OAAO;IACjB,UAAU;IACV,QAAQ;GACV;GACA;EACF;EACA,WAAW;EACX,QAAQ;CACV;CACA,IAAI,OAAO,KAAK,KAAK,OAAO;CAC5B,OAAO;AACT;;;ACmFA,MAAM,mBAAmB;AAQzB,SAAS,QAAQ,SAAuC;CACtD,OAAO,YAAY,QAAQ,WAAW,UAAU,QAAQ,QAAQ;AAClE;;AAGA,SAAS,eAAe,SAAkB,SAAwD;CAChG,KAAK,MAAM,QAAQ,SAAS;EAC1B,MAAM,SAAS,KAAK,WAAW,SAAS;EACxC,MAAM,SAAS,SAAS,QAAQ,SAAS;EACzC,MAAM,OAAO,SAAS,KAAK,MAAM,CAAgB,IAAI;EACrD,IAAI,WAAW,QAAQ,OAAO,SAAS,MAAM,OAAO;GAAE;GAAM,SAAS;EAAO;CAC9E;CACA,OAAO;AACT;AAEA,SAAgB,oBAAoB,UAAgC,CAAC,GAAkB;CACrF,MAAM,SAAS,QAAQ,UAAA;CACvB,IAAI;CACJ,IAAI,OAAO,WAAW,YACpB,WAAW;MACN;EACL,MAAM,QAAQ,eAAe,QAAQ,QAAQ,CAAC,CAAC,YAAY;EAC3D,iBAAiB;CACnB;CAGA,MAAM,8BAAc,IAAI,IAAY;CACpC,MAAM,2BAAW,IAAI,IAAY;CACjC,KAAK,MAAM,SAAS,QAAQ,UAAU,CAAC,GACrC,IAAI,OAAO,UAAU,UAAU,YAAY,IAAI,KAAK;MAC/C,SAAS,IAAI,MAAM,EAAE;CAE5B,MAAM,eAAe,QAAQ;CAC7B,MAAM,WAAW,QAAQ,YAAY,sBAAsB;CAC3D,MAAM,QAAQ,QAAQ,SAAS,mBAAmB;CAElD,SAAS,MAAM,SAAkB,cAAc,QAAQ,MAA2B;EAChF,MAAM,OAAO,aAAa,UAAU;EACpC,IAAI,CAAC,MAAM,OAAO;EAClB,MAAM,SAAS,SAAS,QAAQ,IAAI;EACpC,IAAI,KAAK,MAAM,GAAG,OAAO,MAAM,CAAC,CAAC,YAAY,MAAM,QAAQ,OAAO;EAIlE,MAAM,OAAO,KAAK,MAAM,OAAO,MAAM;EACrC,MAAM,MAAM,KAAK,OAAO,gBAAgB;EACxC,IAAI,SAAS,QAAQ,KAAK,OAAO,KAAK,MAAM,GAAG,GAAG,EAAA,CAAG,YAAY;EAEjE,MAAM,OAAO,QAAQ,eAAe;EACpC,IAAI,SAAS,KAAA,KAAa,MAAM,SAAS,IAAI,KAAK,YAAY,GAAG,GAC/D,QAAQ,MAAM,MAAM,GAAG,EAAE,KAAK,SAAS,EAAE;EAE3C,IAAI,MAAM,WAAW,GAAG,OAAO;EAE/B,MAAM,QAAQ,SAAS,KAAK,KAAK;EACjC,IAAI,CAAC,OAAO,OAAO;EACnB,MAAM,UAAU,QAAQ,KAAK,KAAK,KAAK,MAAM,GAAG,CAAC,CAAC,UAAU;EAC5D,OAAO;GAAE;GAAO,WAAW;GAAO;EAAQ;CAC5C;CAEA,SAAS,OAAO,YAAoD;EAClE,MAAM,QAAQ,WAAW,QAAQ,YAAY;EAC7C,MAAM,QAAQ,SAAS,KAAK,KAAK;EACjC,IAAI,CAAC,OAAO,OAAO;EAGnB,OAAO;GAAE;GAAO,WAAW;GAAO,SADhC,WAAW,SAAS,KAAA,IAAY,WAAW,QAAQ,UAAU,IAAI,WAAW,KAAK,KAAK,GAAG;EACjD;CAC5C;CAEA,eAAe,QACb,MACA,KACA,SACkB;EAClB,IAAI,SAAS,YAAY,OAAO;EAChC,MAAM,EAAE,YAAY;EAKpB,MAAM,EAAE,IAAI,UAAU,QAAQ;EAC9B,IAAI,SAAS,IAAI,EAAE,KAAM,UAAU,QAAQ,YAAY,IAAI,KAAK,GAAI,OAAO;EAC3E,IAAI,SAAS,SAAS,OAAO;EAC7B,IAAI,SAAS,eAAe;GAE1B,MAAM,SAAS,MAAM,KAAK,IAAI;GAC9B,IAAI,CAAC,QAAQ;IACX,QAAQ,gBAAgB,MAAM,OAAO;IACrC,OAAO;GACT;GAEA,OAAQ,MAAM,OAAO,MAAM,GAAG,MAAO;EACvC;EAEA,IAAI,CAAC,QAAQ,KAAK,WAAW,CAAC,cAAc,OAAO;EACnD,OAAO,aAAa,QAAQ,MAAM,QAAQ,MAAM;CAClD;CAEA,eAAe,OACb,YACA,KACA,WACwB;EACxB,OAAQ,MAAM,WAAW,WAAW,KAAK,SAAS,KAAM;CAC1D;CAEA,OAAO;EACL;EACA;EACA;EAEA,MAAM,SAAS,KAAK,YAAY;GAE9B,MAAM,OAAO,IAAI,SAAS,KAAA,IAAY,IAAI,QAAQ,OAAO,IAAI;GAC7D,MAAM,QAAQ,eAAe,KAAA,IAAY,MAAM,IAAI,SAAS,IAAI,IAAI,OAAO,UAAU;GACrF,IAAI,CAAC,OAAO,OAAO;IAAE,UAAU;IAAO,QAAQ;GAAW;GAEzD,MAAM,EAAE,OAAO,WAAW,YAAY;GAEtC,MAAM,OAAO,YAAY,SAAS,KAAA,IAAY,UAAU,OAAO,IAAI,CAAC,GAAG,WAAW,IAAI;GACtF,MAAM,EAAE,eAAe;GACvB,MAAM,UAA0B;IAAE,QAAQ,MAAM;IAAQ,MAAM,WAAW;IAAM;GAAU;GACzF,MAAM,UAAU,IAAI;GAEpB,IAAI;IAKF,MAAM,OAAsB,OAAO,OAAO,OAAO,OAAO,GAAG,GAAoB;KAC7E;KACA,SAAS,WAAW;KACpB;KACA;KACA;IACF,CAAC;IAED,MAAM,OAAO,WAAW,QAAQ;IAChC,IAAI,CAAE,MAAM,QAAQ,MAAM,MAAM,OAAO,GAAI;KACzC,MAAM,YAA8B;MAAE,QAAQ;MAAQ,UAAU;KAAK;KAErE,OAAO;MAAE,UAAU;MAAM,QAAQ;MAAY;MAAS;MAAW,OAAA,MAD7C,OAAO,YAAY,MAAM,SAAS;KACiB;IACzE;IAEA,IAAI,WAAmC;IACvC,IAAI;IACJ,IAAI,WAAW,SAAS;KACtB,WAAW,eAAe,SAAS,WAAW,OAAO;KACrD,IAAI,CAAC,UAAU;MACb,MAAM,YAA8B;OAAE,QAAQ;OAAW,SAAS,WAAW;MAAQ;MAErF,OAAO;OAAE,UAAU;OAAM,QAAQ;OAAY;OAAS;OAAW,OAAA,MAD7C,OAAO,YAAY,MAAM,SAAS;MACiB;KACzE;KACA,QAAQ,QAAQ,SAAS,OAAO;IAClC,OACE,QAAQ,QAAQ,OAAO,KAAK,QAAQ,QAAQ,MAAM;IAIpD,MAAM,aAAa,OAAO,OAAO,MAAM;KAAE;KAAU;IAAM,CAAC;IAC1D,MAAM,WAAW,IAAI,UAAU;IAC/B,OAAO;KAAE,UAAU;KAAM,QAAQ;KAAO;IAAQ;GAClD,SAAS,OAAO;IACd,OAAO;KAAE,UAAU;KAAM,QAAQ;KAAU;KAAS;IAAM;GAC5D;EACF;CACF;AACF;;;AC3SA,MAAMC,eAAa;AAEnB,MAAM,QAAQ;;AAWd,IAAa,iBAAb,cAAoC,MAAM;CACxC,OAAyB;AAC3B;;;;;AAMA,SAAgB,eAAe,OAAe,QAAQ,YAAoB;CACxE,MAAM,SAAS,MAAM,QAAQA,cAAY,EAAE;CAC3C,IAAI,CAAC,MAAM,KAAK,MAAM,GACpB,MAAM,IAAI,eACR,GAAG,MAAM,KAAK,MAAM,uLAGtB;CAEF,OAAO;AACT;AAEA,SAAS,QAAQ,OAAgB,OAAwB;CACvD,MAAM,KAAK,OAAO,UAAU,YAAY,UAAU,OAAQ,MAA2B,KAAK;CAG1F,IAAI,OAAO,OAAO,YAAY,OAAO,MAAM,GAAG,KAAK,MAAM,IACvD,MAAM,IAAI,eACR,GAAG,MAAM,yGACwB,KAAK,UAAU,KAAK,EAAE,EACzD;CAEF,OAAO,EAAE,GAAG;AACd;;;;;AAMA,SAAgB,gBAAgB,QAAyC;CACvE,MAAM,yBAAS,IAAI,IAAsB;CACzC,OAAO,SAAS,OAAO,UAAU;EAC/B,MAAM,QAAQ,UAAU,MAAM;EAC9B,IAAI,OAAO,UAAU,UAAU;GAC7B,MAAM,QAAQ,eAAe,OAAO,KAAK;GACzC,OAAO,IAAI,SAAS,SAAS,KAAK;EACpC,OAAO;GACL,MAAM,aAAa,QAAQ,OAAO,KAAK;GACvC,OAAO,IAAI,MAAM,WAAW,MAAM,UAAU;EAC9C;CACF,CAAC;CACD,OAAO,CAAC,GAAG,OAAO,OAAO,CAAC;AAC5B;;;AClCA,MAAM,SAAS;;;;;AAaf,SAAgB,aAAa,UAAyB,CAAC,GAAW;CAChE,MAAM,cAAc,oBAAoB,QAAQ,aAAa,QAAQ,OAAO;CAC5E,MAAM,OAAO,KACX;EACE,OAAO,QAAQ,SAAS;EAGxB,aAAa,EAAE,KAAK,eAAe,aAAa;EAChD,GAAI,QAAQ,UAAU,QAAQ,OAAO,SAAS,IAC1C,EAAE,QAAQ;GAAE,OAAO,CAAC,GAAG,QAAQ,MAAM;GAAG,QAAQ;EAAO,EAAE,IACzD,CAAC;CACP,GACA,WACF;CACA,OAAO,KAAK,QAAQ,WAAW,KAAK,MAAM,QAAQ,QAAQ,IAAI,IAAI;AACpE;AAKA,SAAS,oBACP,aACA,SAC4B;CAC5B,IAAI,YAAY,KAAA,GAAW,OAAO;CAClC,IAAI;CACJ,IAAI,UAAoB,CAAC;CACzB,IAAI,aAAa,SAAS,SAAS;MAC9B,UAAU,UAAU,OAAO;CAGhC,IAAI,CAAC,UAAU,QAAQ,WAAW,GAAG,OAAO;CAC5C,IAAI,OAAO;CAEX,MAAM,SAAS,eAAe,KAAK,YAAY,CAAC;CAChD,OAAO,EACL,MAAM,MAAoB;EACxB,IAAI,UAAU,OAAO,YAAY,MAAM;GACrC,OAAO,OAAO;GACd,UAAU,UAAU,OAAO,OAAO,CAAC;EACrC;EACA,IAAI,WAAW;EACf,KAAK,MAAM,UAAU,SAAS,WAAW,SAAS,WAAW,QAAQ,MAAM;EAC3E,OAAO,MAAM,QAAQ;CACvB,EACF;AACF;AAIA,SAAS,UAAU,SAAsC;CACvD,OAAO,QACJ,QAAQ,WAAW,OAAO,UAAA,CAA2B,CAAC,CACtD,KAAK,WAAW,KAAK,UAAU,MAAM,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CACpD,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AACvC;AAEA,SAAS,KAAK,KAAyB;CAGrC,OAAO;EACL,IAAI,QAAkB;GACpB,OAAO,IAAI;EACb;EACA,QAAQ,SAAS,WAAY,SAAS,IAAI,MAAM,QAAQ,OAAO,IAAI,IAAI,MAAM,OAAO;EACpF,QAAQ,SAAS,WAAY,SAAS,IAAI,MAAM,QAAQ,OAAO,IAAI,IAAI,MAAM,OAAO;EACpF,OAAO,SAAS,WAAY,SAAS,IAAI,KAAK,QAAQ,OAAO,IAAI,IAAI,KAAK,OAAO;EACjF,OAAO,SAAS,WAAY,SAAS,IAAI,KAAK,QAAQ,OAAO,IAAI,IAAI,KAAK,OAAO;EACjF,QAAQ,SAAS,WAAY,SAAS,IAAI,MAAM,QAAQ,OAAO,IAAI,IAAI,MAAM,OAAO;EACpF,QAAQ,SAAS,WAAY,SAAS,IAAI,MAAM,QAAQ,OAAO,IAAI,IAAI,MAAM,OAAO;EACpF,QAAQ,aAAa,KAAK,IAAI,MAAM,QAAQ,CAAC;CAC/C;AACF;AAGA,MAAM,aAAmB,CAEzB;AAGA,MAAM,cAAsB,OAAO,OAAO;CACxC,OAAO;CACP,OAAO;CACP,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACP,OAAO;CACP,aAAqB;AACvB,CAAC;;AAGD,SAAgB,mBAA2B;CACzC,OAAO;AACT;;;;ACrIA,MAAa,cAAc;AAW3B,MAAM,2BAAW,IAAI,IAAI;CACvB;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,SAAS,WAA2B,OAAO,KAAK;;AAGtD,SAAS,QAAQ,QAA0C;CACzD,MAAM,MAAM,MAAM,MAAM;CACxB,IAAI,SAAS,IAAI,IAAI,IAAI,GAAG,OAAO,IAAI;CAEvC,IAAI,IAAI,SAAS,QAAQ,OAAO,IAAI;AAEtC;;AAGA,SAAgB,aAAa,QAA8B;CACzD,IAAI,UAAU;CACd,KAAK,IAAI,QAAQ,QAAQ,OAAO,GAAG,OAAO,QAAQ,QAAQ,OAAO,GAAG,UAAU;CAC9E,OAAO;AACT;;AAGA,MAAa,YAAY,WAA8B,MAAM,aAAa,MAAM,CAAC,CAAC,CAAC;;AAGnF,MAAa,iBAAiB,WAC5B,MAAM,aAAa,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;;AAGzC,SAAgB,YAAY,QAAoE;CAC9F,MAAM,MAAM,MAAM,aAAa,MAAM,CAAC;CACtC,OAAO,IAAI,SAAS,WAAW,IAAI,QAAQ,KAAA;AAC7C;;;;;;;;;;AAWA,SAAgB,OAA4B,QAAc;CAGxD,OAAO,OAAO,KAAK;EAAE,QAAQ;EAAM,WAAW;CAAK,CAAC;AACtD;AAGA,MAAM,YAAY,UAChB,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,OAAQ,MAA6B,SAAS;;AAGhD,SAAS,WAAW,KAAuB;CACzC,MAAM,WAAwB,CAAC;CAC/B,KAAK,MAAM,SAAS,OAAO,OAAO,GAAG,GACnC,IAAI,SAAS,KAAK,GAAG,SAAS,KAAK,KAAK;MACnC,IAAI,MAAM,QAAQ,KAAK,GAAG,SAAS,KAAK,GAAG,MAAM,OAAO,QAAQ,CAAC;CAExE,OAAO;AACT;;;;;;;AAQA,SAAgB,iBAAiB,QAA6B;CAC5D,MAAM,QAAkB,CAAC;CACzB,MAAM,0BAAU,IAAI,IAAe;CACnC,MAAM,QAAQ,MAAiB,MAAc,WAA0B;EACrE,IAAI,QAAQ,IAAI,IAAI,GAAG;EACvB,QAAQ,IAAI,IAAI;EAChB,IAAI,KAAK,KAAK,CAAC,GAAG,cAAc,MAAM;GAEpC,IAAI,QAAQ,MAAM,KAAK,IAAI;GAC3B;EACF;EACA,MAAM,MAAM,MAAM,IAAI;EACtB,IAAI,IAAI,SAAS,UAAU;GACzB,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,SAAS,CAAC,CAAC,GACvD,KAAK,OAAO,SAAS,KAAK,MAAM,GAAG,KAAK,GAAG,OAAO,MAAM;GAE1D;EACF;EAEA,MAAM,cAAc,SAAS,IAAI,IAAI,IAAI,KAAK,IAAI,SAAS;EAC3D,KAAK,MAAM,SAAS,WAAW,GAAG,GAChC,KAAK,OAAO,cAAc,OAAO,GAAG,KAAK,MAAM,UAAU,CAAC,WAAW;CAEzE;CACA,KAAK,QAAQ,IAAI,KAAK;CACtB,OAAO;AACT;;AAGA,SAAgB,eAAe,QAA4B;CACzD,KAAK,IAAI,UAAiC,QAAQ,SAAS,UAAU,QAAQ,OAAO,GAClF,IAAI,QAAQ,KAAK,CAAC,GAAG,cAAc,MAAM,OAAO;CAElD,OAAO;AACT;;;AC5HA,MAAM,aAAa;;AAGnB,MAAa,mBAA8B,QAAQ;;AAGnD,SAAgB,aAAa,MAAsB;CACjD,OAAO,KACJ,QAAQ,sBAAsB,OAAO,CAAC,CACtC,QAAQ,wBAAwB,OAAO,CAAC,CACxC,QAAQ,MAAM,GAAG,CAAC,CAClB,YAAY;AACjB;;;;;AAMA,SAAgB,QAAQ,QAAgB,MAAiC;CACvE,OAAO,CAAC,GAAG,WAAW,GAAG,aAAa,MAAM,KAAK,GAAG,KAAK,IAAI,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI;AACvF;AAEA,MAAM,uBAAO,IAAI,IAAI;CAAC;CAAQ;CAAK;CAAO;AAAI,CAAC;AAC/C,MAAM,wBAAQ,IAAI,IAAI;CAAC;CAAS;CAAK;CAAM;AAAK,CAAC;;;;;AAMjD,SAAgB,eAAe,KAAa,QAA4B;CACtE,QAAQ,SAAS,MAAM,GAAvB;EACE,KAAK;EACL,KAAK;EACL,KAAK,oBACH,OAAO;EACT,KAAK,UAAU;GACb,MAAM,QAAQ,OAAO,GAAG;GACxB,OAAO,IAAI,KAAK,MAAM,MAAM,OAAO,MAAM,KAAK,IAAI,MAAM;EAC1D;EACA,KAAK,WAAW;GACd,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,YAAY;GACrC,IAAI,KAAK,IAAI,KAAK,GAAG,OAAO;GAC5B,IAAI,MAAM,IAAI,KAAK,GAAG,OAAO;GAC7B,OAAO;EACT;EACA,KAAK,WACH,OAAO,cAAc,MAAM,CAAC,CAAC,MAAM,UAAU,OAAO,KAAK,MAAM,GAAG,KAAK;EACzE,SAGE,IAAI;GACF,OAAO,KAAK,MAAM,GAAG;EACvB,QAAQ;GACN,OAAO;EACT;CACJ;AACF;;;;;;AAOA,SAAgB,cACd,QACA,OACA,aACuB;CACvB,MAAM,yBAAS,IAAI,IAAsB;CACzC,MAAM,OAAO,SAAkC;EAC7C,MAAM,OAAO,QAAQ,QAAQ,IAAI;EACjC,OAAO,IAAI,MAAM,CAAC,GAAI,OAAO,IAAI,IAAI,KAAK,CAAC,GAAI,KAAK,KAAK,GAAG,CAAC,CAAC;CAChE;CACA,MAAM,QAAQ,QAA6C,WAAoC;EAC7F,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAAG;GACjD,MAAM,SAAS,YAAY,KAAK;GAChC,IAAI,QAAQ,KAAK,QAAQ,CAAC,GAAG,QAAQ,GAAG,CAAC;QACpC,IAAI,CAAC,GAAG,QAAQ,GAAG,CAAC;EAC3B;CACF;CACA,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC;CACzB,KAAK,MAAM,OAAO,aAAa,IAAI,CAAC,YAAY,GAAG,CAAC;CACpD,KAAK,MAAM,CAAC,MAAM,UAAU,QAAQ,IAAI,MAAM,SAAS,GAAG,OAAO,OAAO,IAAI;CAC5E,OAAO;AACT;;;;;AAaA,SAAgB,cACd,QACA,OACA,KACA,SAA4B,CAAC,GACjB;CACZ,MAAM,QAAoB,CAAC;CAC3B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAAG;EAChD,MAAM,OAAO,CAAC,GAAG,QAAQ,GAAG;EAC5B,MAAM,SAAS,YAAY,KAAK;EAChC,IAAI,QAAQ;GACV,MAAM,KAAK,GAAG,cAAc,QAAQ,QAAQ,KAAK,IAAI,CAAC;GACtD;EACF;EACA,MAAM,OAAO,QAAQ,QAAQ,IAAI;EACjC,MAAM,MAAM,IAAI;EAChB,IAAI,QAAQ,KAAA,GAAW,MAAM,KAAK;GAAE;GAAM;GAAM,OAAO,eAAe,KAAK,KAAK;EAAE,CAAC;CACrF;CACA,OAAO;AACT;;;AChHA,MAAM,kBAAkB,QAAgB,UAAqC;CAC3E,QAAQ,MAAM,QAAd;EACE,KAAK,OACH,OAAO,OAAO,MAAM;EACtB,KAAK,QAEH,OAAO,yBAAyB,OAAO,IAD1B,MAAM,SAAS,KAAK,KAAK,IAAI,MAAM;EAGlD,KAAK,YACH,OAAO;EACT,KAAK,WACH,OAAO;CACX;AACF;;;;;;AAOA,IAAa,oBAAb,cAAuC,MAAM;CAC3C,OAAyB;CACzB;CACA;CAEA,YAAY,QAAgB,QAAsC;EAChE,MAAM,QAAQ,OAAO,KAClB,UACC,GAAG,MAAM,SAAS,KAAK,aAAa,MAAM,KAAK,IAAI,MAAM,QAAQ,WAAW,eAAe,QAAQ,KAAK,EAAE,EAC9G;EACA,MAAM,8BAA8B,OAAO,QAAQ,MAAM,KAAK,MAAM,GAAG;EACvE,KAAK,SAAS;EACd,KAAK,SAAS;CAChB;AACF;;;ACmDA,MAAM,eAAe;AACrB,MAAM,iBAAiB,WAA2B,UAAU;AAI5D,MAAM,iBAAiB,UAAyC;CAC9D,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG,OAAO;CAChF,MAAM,QAAiB,OAAO,eAAe,KAAK;CAClD,OAAO,UAAU,OAAO,aAAa,UAAU;AACjD;;AAGA,SAAS,UAAU,MAAmB,KAA+B;CACnE,MAAM,SAAsB,EAAE,GAAG,KAAK;CACtC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAAG;EAE9C,IAAI,UAAU,KAAA,GAAW;EACzB,MAAM,UAAU,OAAO;EACvB,OAAO,OACL,cAAc,OAAO,KAAK,cAAc,KAAK,IAAI,UAAU,SAAS,KAAK,IAAI;CACjF;CACA,OAAO;AACT;AAEA,SAAS,MAAM,QAAqB,MAAyB,OAAsB;CACjF,IAAI,OAAO;CACX,KAAK,MAAM,OAAO,KAAK,MAAM,GAAG,EAAE,GAAG;EACnC,MAAM,OAAO,KAAK;EAClB,IAAI,cAAc,IAAI,GAAG,OAAO;OAC3B;GACH,MAAM,UAAuB,CAAC;GAC9B,KAAK,OAAO;GACZ,OAAO;EACT;CACF;CACA,KAAK,KAAK,GAAG,EAAE,KAAe;AAChC;;AAGA,SAAS,SAAS,OAAoB,MAAuC;CAC3E,IAAI,OAAgB;CACpB,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM,OAAO;EACtD,IAAI,EAAE,OAAO,OAAO,OAAO;EAC3B,OAAQ,KAAsC;CAChD;CACA,OAAO,SAAS,KAAA;AAClB;;AAGA,SAAS,UAAU,OAAoB,SAA4B,CAAC,GAAe;CACjF,OAAO,OAAO,QAAQ,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,WAAW;EACrD,IAAI,UAAU,KAAA,GAAW,OAAO,CAAC;EACjC,MAAM,OAAO,CAAC,GAAG,QAAQ,GAAG;EAC5B,OAAO,cAAc,KAAK,KAAK,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,IAAI,UAAU,OAAO,IAAI,IAAI,CAAC,IAAI;CAC/F,CAAC;AACH;AAEA,MAAM,cAAc,MAA8B,WAChD,OAAO,OAAO,KAAK,UAAU,OAAO,KAAK,MAAM,MAAM,GAAG;;;;;AAM1D,SAAS,WACP,QACA,OACA,UACS;CACT,MAAM,QAAQ,YAAY,MAAM;CAChC,IAAI,CAAC,SAAS,CAAC,cAAc,KAAK,GAAG,OAAO;CAC5C,MAAM,OAAoB,EAAE,GAAG,MAAM;CACrC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAAG;EAChD,IAAI,KAAK,SAAS,KAAA,GAAW;EAC7B,KAAK,OAAO,eAAe,KAAK,IAC5B,SAAS,KAAK,IAAI,IAClB,WAAW,OAAO,KAAK,MAAM,QAAQ;CAC3C;CACA,OAAO;AACT;;;;;AAMA,SAAS,YACP,QACA,OACA,SAA4B,CAAC,GACjB;CACZ,MAAM,QAAQ,YAAY,MAAM;CAChC,IAAI,CAAC,SAAS,CAAC,cAAc,KAAK,GAAG,OAAO,CAAC;CAC7C,OAAO,OAAO,QAAQ,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,WAAW;EACrD,IAAI,MAAM,SAAS,KAAA,GAAW,OAAO,CAAC;EACtC,MAAM,OAAO,CAAC,GAAG,QAAQ,GAAG;EAC5B,OAAO,eAAe,KAAK,IAAI,CAAC,IAAI,IAAI,YAAY,OAAO,MAAM,MAAM,IAAI;CAC7E,CAAC;AACH;;AAGA,SAAS,QAAQ,OAAgB,MAAkC;CACjE,IAAI,OAAO;CACX,KAAK,MAAM,OAAO,MAAM,OAAO,cAAc,IAAI,IAAI,KAAK,OAAO,KAAA;CACjE,OAAO;AACT;;AAGA,SAAS,YAAY,OAAoB,MAAsC;CAC7E,MAAM,CAAC,KAAK,GAAG,QAAQ;CACvB,MAAM,OAAoB,EAAE,GAAG,MAAM;CACrC,MAAM,OAAO,KAAK;CAClB,IAAI,KAAK,WAAW,GAAG,OAAO,KAAK;MAC9B,IAAI,cAAc,IAAI,GAAG,KAAK,OAAO,YAAY,MAAM,IAAI;CAChE,OAAO;AACT;;AAGA,SAAS,cAAc,OAAgB,MAAsB;CAC3D,IAAI,OAAO,UAAU,UAAU,KAAK,KAAK,KAAK;MACzC,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU,KAAK,KAAK,OAAO,KAAK,CAAC;MACnF,IAAI,MAAM,QAAQ,KAAK,GAAG,KAAK,MAAM,QAAQ,OAAO,cAAc,MAAM,IAAI;MAC5E,IAAI,cAAc,KAAK,GAAG,KAAK,MAAM,QAAQ,OAAO,OAAO,KAAK,GAAG,cAAc,MAAM,IAAI;AAClG;;AAGA,MAAM,sBAAsB;;;;;;AAO5B,SAAS,YAAY,MAAqB;CACxC,IAAI,MAAM,QAAQ,IAAI,GAAG;EACvB,KAAK,MAAM,QAAQ,MAAM,YAAY,IAAI;EACzC;CACF;CACA,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM;CAC/C,MAAM,SAAS;CACf,IAAI,OAAO,cAAc,MAAM;EAC7B,OAAO,uBAAuB;EAC9B,IAAI,aAAa,QAAQ,OAAO,aAAa;CAC/C;CACA,KAAK,MAAM,SAAS,OAAO,OAAO,MAAM,GAAG,YAAY,KAAK;AAC9D;;AAkBA,SAAgB,oBAAoB,SAA8C;CAChF,MAAM,MAAM,QAAQ,OAAO,WAAW;CACtC,MAAM,KAAK,cAAc,QAAQ,SAAS,QAAQ,CAAC,CAAC;CACpD,MAAM,MAAM,QAAQ,OAAO,iBAAiB;CAC5C,MAAM,OAAO,QAAQ,QAAQ,CAAC;CAC9B,MAAM,SAAS,IAAI,IAAI,QAAQ,QAAQ,KAAK,WAAW,CAAC,OAAO,MAAM,MAAM,CAAC,CAAC;CAE7E,KAAK,MAAM,QAAQ,OAAO,KAAK,IAAI,GACjC,IAAI,CAAC,OAAO,IAAI,IAAI,GAClB,IAAI,KAAK,sBAAsB,KAAK,qCAAqC,EAAE,QAAQ,KAAK,CAAC;CAI7F,IAAI,QAA0B,QAAQ,QAAQ;CAE9C,MAAM,+BAAe,IAAI,IAAY;CACrC,MAAM,8BAAc,IAAI,IAAY;CAEpC,SAAS,aAAa,MAAgC;EACpD,MAAM,aAAa,OAAO,IAAI,IAAI;EAClC,IAAI,CAAC,YAAY,MAAM,IAAI,WAAW,gCAAgC,KAAK,EAAE;EAC7E,OAAO;CACT;;CAGA,SAAS,QACP,QACA,KACA,QACmB;EACnB,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAA;EAC9B,IAAI,CAAC,cAAc,GAAG,GAAG;GACvB,OAAO,KAAK;IAAE,MAAM;IAAI,SAAS;IAAyC;GAAO,CAAC;GAClF;EACF;EACA,MAAM,GAAG,eAAe,UAAU,GAAG,WAAW;EAChD,IAAI,aAAa,KAAA,KAAa,CAAC,cAAc,QAAQ,GAAG;GACtD,OAAO,KAAK;IAAE,MAAM;IAAc,SAAS;IAAoC;GAAO,CAAC;GACvF,OAAO;IAAE;IAAQ;IAAQ,UAAU,CAAC;GAAE;EACxC;EACA,OAAO;GAAE;GAAQ;GAAQ,UAAU,YAAY,CAAC;EAAE;CACpD;CAEA,SAAS,QAAQ,YAA8B,UAA6B;EAC1E,MAAM,EAAE,SAAS;EACjB,MAAM,SAAS,WAAW;EAC1B,MAAM,QAAQ,SAAS,YAAY,MAAM,IAAI,KAAA;EAE7C,IAAI,UAAU,CAAC,OACb,MAAM,IAAI,UAAU,WAAW,KAAK,gDAAgD;EAEtF,IAAI,SAAS,gBAAgB,OAC3B,MAAM,IAAI,UACR,WAAW,KAAK,MAAM,aAAa,2FAErC;EAEF,MAAM,YAAY,SAAS,iBAAiB,MAAM,IAAI,CAAC;EACvD,IAAI,UAAU,SAAS,GACrB,MAAM,IAAI,UACR,WAAW,KAAK,gKAEd,UAAU,KAAK,SAAS,IAAI,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,CAClD;EAEF,MAAM,aAAa,cAAc,MAAM,OAAO,OAAO,KAAK,WAAW,YAAY,CAAC,CAAC,CAAC;EACpF,IAAI,WAAW,OAAO,GAAG;GACvB,MAAM,OAAO,CAAC,GAAG,UAAU,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,IAAI,MAAM,KAAK,IAAI,EAAE,EAAE;GACjF,MAAM,IAAI,UACR,WAAW,KAAK,8EACJ,KAAK,KAAK,IAAI,GAC5B;EACF;EAEA,MAAM,SAA8B,CAAC;EAErC,MAAM,SAAS,CACb,QAAQ,YAAY,UAAU,MAAM,GACpC,QAAQ,QAAQ,KAAK,OAAO,MAAM,CACpC,CAAC,CAAC,QAAQ,UAAU,UAAU,KAAA,CAAS;EACvC,MAAM,YAAY,QAAQ,cAAc,MAAM,OAAO,GAAG,IAAI,CAAC;EAC7D,MAAM,cAA0B,OAAO,KAAK,WAAW,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,QAAQ;GACtF,MAAM,WAAW,QAAQ,MAAM,CAAC,cAAc,GAAG,CAAC;GAClD,MAAM,QAAQ,IAAI;GAClB,OAAO,UAAU,KAAA,IAAY,CAAC,IAAI,CAAC;IAAE,MAAM,CAAC,GAAG;IAAG,MAAM;IAAU;GAAM,CAAC;EAC3E,CAAC;EAED,IAAI,SAAsB,CAAC;EAC3B,KAAK,MAAM,SAAS,QAAQ,SAAS,UAAU,QAAQ,MAAM,MAAM;EACnE,MAAM,WAAwB,CAAC;EAC/B,KAAK,MAAM,SAAS,WAAW,MAAM,UAAU,MAAM,MAAM,MAAM,KAAK;EACtE,SAAS,UAAU,QAAQ,QAAQ;EAEnC,MAAM,YAAY,SAAqE;GACrF,MAAM,QAAQ,KAAK,IAAI,MAAM,CAAC,CAAC,KAAK,GAAG;GACvC,MAAM,UAAU,UAAU,MAAM,UAAU,WAAW,MAAM,MAAM,IAAI,CAAC;GACtE,IAAI,SAAS,OAAO;IAAE,MAAM;IAAO,QAAQ;IAAO,KAAK,QAAQ;GAAK;GACpE,KAAK,MAAM,SAAS,OAAO,WAAW,GACpC,IAAI,SAAS,MAAM,QAAQ,IAAI,GAAG,OAAO;IAAE,MAAM;IAAO,QAAQ,MAAM;GAAO;GAE/E,OAAO;IAAE,MAAM;IAAO,QAAQ;GAAU;EAC1C;EAEA,IAAI;EACJ,IAAI,CAAC,QACH,KAAK,MAAM,SAAS,QAClB,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,MAAM,GACxC,OAAO,KAAK;GACV,MAAM;GACN,SAAS;GACT,QAAQ,MAAM;EAChB,CAAC;OAGA;GACL,MAAM,SAAS,OAAO,UAAU,MAAM;GACtC,IAAI,OAAO,SAAS,SAAS,OAAO;QAGlC,KAAK,MAAM,SAAS,OAAO,MAAM,QAC/B,OAAO,KAAK;IAAE,GAAG,SAAS,MAAM,IAAI;IAAG,SAAS,MAAM;GAAQ,CAAC;EAGrE;EAEA,MAAM,OAAO,WAAW,YAAY,CAAC;EACrC,MAAM,WAAmC,EAAE,GAAG,KAAK;EACnD,MAAM,iBAA+C,OAAO,YAC1D,OAAO,KAAK,IAAI,CAAC,CAAC,KAAK,QAAQ,CAAC,GAAG,aAAa,GAAG,OAAO,SAAkB,CAAC,CAC/E;EACA,MAAM,gBAAgB,CACpB,GAAG,OAAO,KAAK,WAAW;GACxB,SAAS,OAAO,QAAQ,MAAM,QAAQ;GACtC,iBAA8D,EAAE,QAAQ,MAAM,OAAO;EACvF,EAAE,GACF;GACE,SAAS,YAAY,KAAK,UAAU,CAAC,MAAM,KAAK,IAAc,MAAM,KAAK,CAAU;GACnF,WAAW,SAA8D;IACvE,QAAQ;IACR,KAAK,QAAQ,MAAM,CAAC,cAAc,GAAG,CAAC;GACxC;EACF,CACF;EACA,KAAK,MAAM,SAAS,eAClB,KAAK,MAAM,CAAC,KAAK,SAAS,MAAM,SAAS;GACvC,MAAM,KAAK;IAAE,MAAM,GAAG,aAAa,GAAG;IAAO,GAAG,MAAM,SAAS,GAAG;GAAE;GACpE,IAAI,CAAC,OAAO,OAAO,MAAM,GAAG,GAAG;IAC7B,MAAM,QAAQ,OAAO,KAAK,IAAI;IAC9B,OAAO,KAAK;KACV,GAAG;KACH,SACE,8CACC,MAAM,WAAW,IAAI,YAAY,MAAM,KAAK,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI;IAC1E,CAAC;GACH,OAAO,IAAI,OAAO,SAAS,UACzB,OAAO,KAAK;IAAE,GAAG;IAAI,SAAS;GAAiB,CAAC;QAC3C;IACL,SAAS,OAAO;IAChB,eAAe,GAAG,QAAQ,GAAG;GAC/B;EACF;EAGF,IAAI,OAAO,SAAS,GAAG,OAAO;GAAE,IAAI;GAAO,OAAO,IAAI,kBAAkB,MAAM,MAAM;EAAE;EACtF,MAAM,UAAoB,CAAC;EAC3B,IAAI,QACF,WAAW,QAAQ,SAAS,UAAU;GACpC,cAAc,OAAO,OAAO;GAC5B,OAAO;EACT,CAAC;EAGH,MAAM,UAAwC,CAAC;EAC/C,IAAI,cAAc,MAAM,GACtB,KAAK,MAAM,QAAQ,UAAU,MAAM,GAAG,QAAQ,KAAK,KAAK,GAAG,KAAK,SAAS,IAAI,CAAC,CAAC;EAEjF,OAAO;GACL,IAAI;GACJ,UAAU;IAAE;IAAQ,UAAU,OAAO,OAAO,QAAQ;GAAE;GACtD;GACA,SAAS;IAAE,GAAG;IAAS,GAAG;GAAe;EAC3C;CACF;;;;;;CAOA,SAAS,kBAAkB,YAA8B,QAA0B;EACjF,IAAI,CAAC,WAAW,UAAU,CAAC,cAAc,MAAM,GAAG,OAAO;EACzD,IAAI,QAAQ;EACZ,KAAK,MAAM,QAAQ,YAAY,WAAW,QAAQ,MAAM,GAAG;GACzD,QAAQ,YAAY,OAAO,IAAI;GAC/B,MAAM,QAAQ,KAAK,KAAK,GAAG;GAC3B,MAAM,MAAM,GAAG,WAAW,KAAK,GAAG;GAClC,IAAI,aAAa,IAAI,GAAG,GAAG;GAC3B,aAAa,IAAI,GAAG;GAEpB,IAAI,KACF,uBAAuB,WAAW,KAAK,yBAAyB,MAAM,+BACjD,QAAQ,WAAW,MAAM,IAAI,EAAE,mBACpD;IAAE,QAAQ,WAAW;IAAM,OAAO;GAAM,CAC1C;EACF;EACA,OAAO;CACT;;;;;CAMA,SAAS,iBAAiB,YAA8B,QAAuB;EAC7E,IAAI,CAAC,WAAW,QAAQ;EACxB,KAAK,MAAM,QAAQ,YAAY,WAAW,QAAQ,MAAM,GAAG;GACzD,MAAM,SAAmB,CAAC;GAC1B,cAAc,QAAQ,QAAQ,IAAI,GAAG,MAAM;GAC3C,IAAI,CAAC,OAAO,MAAM,UAAU,MAAM,SAAA,CAA0B,GAAG;GAC/D,MAAM,QAAQ,KAAK,KAAK,GAAG;GAC3B,MAAM,MAAM,GAAG,WAAW,KAAK,GAAG;GAClC,IAAI,YAAY,IAAI,GAAG,GAAG;GAC1B,YAAY,IAAI,GAAG;GACnB,IAAI,KACF,kBAAkB,MAAM,eAAe,WAAW,KAAK,uDAEvD;IAAE,QAAQ,WAAW;IAAM,OAAO;GAAM,CAC1C;EACF;CACF;;CAGA,SAAS,aAAa,YAA8B,QAAuC;EACzF,iBAAiB,YAAY,OAAO,SAAS,MAAM;EACnD,QAAQ,SAAS,IAAI,cAAc,WAAW,IAAI,GAAG,OAAO,OAAO;CACrE;CAEA,eAAe,QAAQ,MAAgD;EACrE,MAAM,aAAa,aAAa,IAAI;EACpC,MAAM,SAAS,QAAQ,YAAY,kBAAkB,YAAY,MAAM,GAAG,IAAI,IAAI,CAAC,CAAC;EACpF,IAAI,CAAC,OAAO,IAAI,MAAM,OAAO;EAC7B,aAAa,YAAY,MAAM;EAC/B,OAAO;CACT;;;;;CAMA,SAAS,aACP,MACA,WACA,SACM;EACN,MAAM,SAAS,UAAU,SAAS,CAAC,CAAC,SAAS,SAAS;GACpD,MAAM,QAAQ,KAAK,KAAK,GAAG;GAE3B,MAAM,QAAQ,OAAO,QAAQ,OAAO,CAAC,CAAC,QACnC,CAAC,SAAS,QAAQ,SAAS,IAAI,WAAW,GAAG,MAAM,EAAE,CACxD;GACA,MAAM,CAAC,SAAS;GAChB,IAAI,CAAC,SAAS,MAAM,MAAM,GAAG,YAAY,WAAW,UAAU,GAAG,OAAO,CAAC;GACzE,OAAO,CAAC;IAAE,MAAM;IAAO,QAAQ,MAAM;GAAG,CAAC;EAC3C,CAAC;EACD,IAAI,OAAO,WAAW,GAAG;EACzB,IAAI,KACF,uBAAuB,KAAK,kBACvB,OAAO,KAAK,UAAU,IAAI,MAAM,KAAK,UAAU,MAAM,OAAO,EAAE,CAAC,CAAC,KAAK,IAAI,KAC9E;GAAE,QAAQ;GAAM;EAAO,CACzB;CACF;CAEA,eAAe,gBACb,MACA,WACyC;EACzC,MAAM,aAAa,aAAa,IAAI;EAEpC,MAAM,eAAoC,WAAW,SACjD,YAAY,WAAW,QAAQ,SAAS,CAAC,CAAC,KAAK,UAAU;GACvD,MAAM,KAAK,KAAK,GAAG;GACnB,SACE,sGAC0B,QAAQ,MAAM,IAAI,EAAE,iCAC7B,KAAK,KAAK,KAAK,KAAK,GAAG;GAC1C,QAAQ;EACV,EAAE,IACF,CAAC;EACL,IAAI,aAAa,SAAS,GAAG,MAAM,IAAI,kBAAkB,MAAM,YAAY;EAC3E,MAAM,SAAS,QAAQ,YAAY,SAAS;EAC5C,IAAI,CAAC,OAAO,IAAI,MAAM,OAAO;EAC7B,aAAa,MAAM,WAAW,OAAO,OAAO;EAE5C,aAAa,YAAY,MAAM;EAC/B,IAAI,OAAO,KAAK,SAAS,CAAC,CAAC,WAAW,GAAG,MAAM,GAAG,OAAO,IAAI;OACxD,MAAM,GAAG,IAAI,MAAM,SAAS;EACjC,OAAO,QAAQ,SAAS,QAAQ,OAAO,IAAI,IAAI,KAAA;CACjD;CAEA,OAAO;EACL,SAAS,OAAO,UAAU,MAAM,QAAQ,IAAI,EAAA,CAAG;EAE/C,aAAa,MAAc,WAAgE;GAEzF,MAAM,SAAS,MAAM,WAAW,gBAAgB,MAAM,SAAS,CAAC;GAChE,QAAQ,OAAO,WACP,KAAA,SACA,KAAA,CACR;GACA,OAAO;EACT;EAEA,MAAM,SAAS,MAAyC;GACtD,MAAM,aAAa,aAAa,IAAI;GACpC,MAAM,EAAE,UAAU,YAAY,MAAM,QAAQ,IAAI;GAChD,MAAM,EAAE,QAAQ,aAAa;GAI7B,OAAO;IAAE,QAHM,WAAW,SACtB,WAAW,WAAW,QAAQ,cAAc,WAAW,IACvD;IACqB;IAAU;GAAQ;EAC7C;EAEA,WAAW,MAAkD;GAC3D,MAAM,SAAS,aAAa,IAAI,CAAC,CAAC;GAClC,IAAI,CAAC,QAAQ,OAAO,KAAA;GAGpB,MAAM,OAAO,OAAO,aAAa;IAAE,IAAI;IAAS,iBAAiB;GAAM,CAAC;GACxE,YAAY,IAAI;GAChB,OAAO;EACT;CACF;AACF;;ACpkBA,MAAM,aAAa;;AA6CnB,IAAa,mBAAb,cAAsC,sBAAsB;CAC1D,OAAiC;CACjC;CAEA,YAAY,QAAgB,MAAc,WAAmB;EAC3D,MAAM,QAAQ,UAAU,KAAK,IAAI,SAAS;EAC1C,KAAK,OAAO;CACd;AACF;;AAqBA,IAAa,uBAAb,MAAqC;CACnC,yBAAkB,IAAI,IAAwC;CAC9D,yBAAkB,IAAI,IAAkB;CACxC,UAAU;CAEV,OAAO,QAAgB,MAAc,KAA0B;EAC7D,IAAI,OAAO,SAAS,YAAY,KAAK,WAAW,GAC9C,MAAM,IAAI,UAAU,WAAW,OAAO,uBAAuB;EAE/D,IAAI,QAAQ,KAAK,OAAO,IAAI,MAAM;EAClC,IAAI,UAAU,KAAA,GAAW;GACvB,wBAAQ,IAAI,IAAI;GAChB,KAAK,OAAO,IAAI,QAAQ,KAAK;EAC/B;EACA,IAAI,MAAM,IAAI,IAAI,GAAG,MAAM,IAAI,UAAU,WAAW,OAAO,YAAY,KAAK,cAAc;EAC1F,MAAM,IAAI,MAAM,GAAG;CACrB;CAEA,OACE,QACA,QACA,UACA,MACA,UAA8B,CAAC,GACzB;EACN,IAAI,CAAC,KAAK,OAAO,IAAI,MAAM,CAAC,EAAE,IAAI,IAAI,GACpC,MAAM,IAAI,UACR,WAAW,OAAO,kBAAkB,KAAK,sDAE3C;EAEF,MAAM,QAAQ,QAAQ,SAAA;EACtB,IAAI,EAAE,OAAO,SAAS,KAAK,KAAK,QAAQ,KAAK,SAAS,aACpD,MAAM,IAAI,WAAW,WAAW,OAAO,oCAAoC,OAAO;EAGpF,IAAI,KAAK,SAAS;EAClB,MAAM,MAAM,QAAQ,QAAQ,QAAQ;EACpC,KAAK,MAAM,GAAG;EACd,MAAM,QAAQ,iBAAiB;GAC7B,IAAI,KAAK,OAAO,IAAI,GAAG,CAAC,EAAE,UAAU,OAAO,KAAK,OAAO,OAAO,GAAG;EACnE,GAAG,KAAK;EAER,MAAM,QAAQ;EACd,KAAK,OAAO,IAAI,KAAK;GAAE;GAAQ;GAAM,MAAM,QAAQ,QAAQ;GAAM;EAAM,CAAC;CAC1E;;;;;;CAOA,KAAK,QAAgB,UAA+C;EAClE,IAAI,KAAK,OAAO,SAAS,GAAG,OAAO,KAAA;EACnC,MAAM,MAAM,QAAQ,QAAQ,QAAQ;EACpC,MAAM,OAAO,KAAK,OAAO,IAAI,GAAG;EAChC,IAAI,SAAS,KAAA,GAAW,OAAO,KAAA;EAC/B,KAAK,MAAM,GAAG;EAEd,MAAM,MAAM,KAAK,OAAO,IAAI,KAAK,MAAM,CAAC,EAAE,IAAI,KAAK,IAAI;EACvD,OAAO;GAAE,QAAQ,KAAK;GAAQ,MAAM,KAAK;GAAM,MAAM,KAAK;GAAM;EAAI;CACtE;;CAGA,KAAK,QAAgB,MAAyC;EAC5D,OAAO,KAAK,OAAO,IAAI,MAAM,CAAC,EAAE,IAAI,IAAI;CAC1C;;CAGA,aAAa,QAAsB;EACjC,KAAK,OAAO,OAAO,MAAM;EACzB,KAAK,MAAM,CAAC,KAAK,SAAS,KAAK,QAC7B,IAAI,KAAK,WAAW,QAAQ,KAAK,MAAM,GAAG;CAE9C;;CAGA,QAAc;EACZ,KAAK,UAAU;EACf,KAAK,MAAM,OAAO,CAAC,GAAG,KAAK,OAAO,KAAK,CAAC,GAAG,KAAK,MAAM,GAAG;EACzD,KAAK,OAAO,MAAM;CACpB;CAEA,MAAM,KAAmB;EACvB,MAAM,OAAO,KAAK,OAAO,IAAI,GAAG;EAChC,IAAI,SAAS,KAAA,GAAW;EACxB,aAAa,KAAK,KAAK;EACvB,KAAK,OAAO,OAAO,GAAG;CACxB;AACF;AAGA,MAAM,WAAW,QAAgB,aAA6B,GAAG,OAAO,QAAQ;ACjEhF,MAAM,aAA+B,CAAC;AACtC,MAAM,eAAoC,QAAQ,QAAQ;CACxD,WAAW;CACX,SAAS;CACT,QAAQ;AACV,CAAC;AAED,SAAS,QAAQ,GAAU,GAAkB;CAC3C,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE;AAC9C;AAEA,SAASC,aAAW,OAA+C;CACjE,OACE,UAAU,SACT,OAAO,UAAU,YAAY,OAAO,UAAU,eAC/C,OAAQ,MAA+B,SAAS;AAEpD;AAEA,SAAS,UAAU,QAAkE;CACnF,IAAI,WAAW,KAAA,GAAW,OAAO;CACjC,OAAO,IAAI,IAAI,OAAO,WAAW,WAAW,CAAC,MAAM,IAAI,MAAM;AAC/D;AAEA,SAASC,eAAa,OAAuB;CAE3C,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG,MAAM,IAAI,WAAW,mBAAmB,OAAO;CAC1F,OAAO;AACT;AAEA,SAAgB,eAAe,SAAoC;CACjE,MAAM,mBAAmBA,eAAa,QAAQ,qBAAA,GAAgD;CAC9F,MAAM,UAAU,QAAQ;CACxB,MAAM,QAAQ,QAAQ,SAAS,IAAI,YAAY;CAG/C,MAAM,0BAAU,IAAI,IAA8B;CAElD,MAAM,iCAAiB,IAAI,IAAmC;CAC9D,IAAI,MAAM;CAGV,IAAI,UAAU;CACd,IAAI,cAA8B,CAAC;CAEnC,SAAS,SAAe;EACtB;EACA,IAAI,UAAU,KAAK,YAAY,WAAW,GAAG;EAC7C,MAAM,UAAU;EAChB,cAAc,CAAC;EACf,KAAK,MAAM,WAAW,SAAS,QAAQ;CACzC;CAEA,SAAS,QAAQ,OAAe,SAAiC;EAC/D,IAAI,QAAQ,WAAW,GAAG,QAAQ,OAAO,KAAK;OACzC,QAAQ,IAAI,OAAO,OAAO;EAC/B,eAAe,MAAM;CACvB;CAEA,SAAS,kBAAkB,MAAqC;EAC9D,IAAI,SAAS,eAAe,IAAI,IAAI;EACpC,IAAI,WAAW,KAAA,GAAW;GACxB,MAAM,OAAO,QAAQ,IAAI,SAAS,KAAK;GACvC,MAAM,QAAQ,QAAQ,IAAI,WAAW,MAAM,KAAK;GAChD,IAAI,MAAM,WAAW,GAAG,SAAS;QAC5B,IAAI,KAAK,WAAW,GAAG,SAAS;QAChC,SAAS,CAAC,GAAG,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,OAAO;GAC9C,eAAe,IAAI,MAAM,MAAM;EACjC;EACA,OAAO;CACT;CAEA,SAAS,UACP,QACA,SACA,OACA,OACA,QACa;EACb,MAAM,CAAC,UAAU,QAAS,OAAO,UAAU,aAAa,CAAC,OAAO,MAAM,IAAI,CAAC,QAAQ,KAAK;EAIxF,IAAI,OAAO,aAAa,YAAY,MAAM,IAAI,UAAU,gBAAgB,MAAM,eAAe;EAC7F,MAAM,WAAW,MAAM,YAAY;EAEnC,IAAI,CAAC,OAAO,SAAS,QAAQ,GAAG,MAAM,IAAI,WAAW,wBAAwB,UAAU;EACvF,MAAM,QAAe;GACnB;GACU;GACV;GACA,WAAW,MAAM,cAAc,KAAA,IAAY,mBAAmBA,eAAa,KAAK,SAAS;GACzF,KAAK;GACL,QAAQ,UAAU,MAAM,MAAM;GAC9B,MAAM,SAAS,OAAO,KAAK;GAC3B,UAAU,SAAS;EACrB;EACA,QAAQ,OAAO,CAAC,GAAI,QAAQ,IAAI,KAAK,KAAK,YAAa,KAAK,CAAC,CAAC,KAAK,OAAO,CAAC;EAC3E,aAAa;GACX,MAAM,UAAU,QAAQ,IAAI,KAAK;GACjC,IAAI,CAAC,SAAS,SAAS,KAAK,GAAG;GAC/B,QACE,OACA,QAAQ,QAAQ,MAAM,MAAM,KAAK,CACnC;EACF;CACF;CAEA,SAAS,KAAK,OAAc,OAAqB,OAAgB,UAAyB;EACxF,MAAM,SAA2B;GAC/B,QAAQ,MAAM;GACd,OAAO;GACP;GACA;GACA;EACF;EACA,QAAQ,MAAM;EAGd,IAAI,UAAU,gBAAgB,KAAU,gBAAgB,MAAM;CAChE;;;;;CAMA,SAAS,MACP,OACA,OACA,QACA,UACkB;EAClB;EACA,OAAO,IAAI,SAAkB,YAAY;GACvC,IAAI,UAAU;GACd,MAAM,eAAqB;IACzB,UAAU;IACV,OAAO;IACP,MAAM,OAAO,MAAM;IACnB,OAAO;GACT;GAEA,MAAM,SAAS,SAAS,SAAS,MAAM,iBAAiB;IACtD,OAAO;IACP,MAAM,QAAQ,IAAI,qBAAqB,MAAM,QAAQ,OAAO,MAAM,SAAS;IAC3E,SAAS,OAAO,KAAK;IACrB,KAAK,OAAO,OAAO,OAAO,IAAI;IAC9B,QAAQ,IAAI;GACd,CAAC;GACD,MAAM,IAAI,MAAM;GAChB,OAAO,WACC;IACJ,IAAI,SAAS;IACb,OAAO;IACP,QAAQ,KAAK;GACf,IACC,UAAmB;IAClB,IAAI,SAAS;KAGX,IAAI,EAAE,iBAAiB,sBACrB,QAAQ;MAAE,QAAQ,MAAM;MAAQ,OAAO;MAAY;MAAO;MAAO,UAAU;KAAM,CAAC;KAEpF;IACF;IACA,OAAO;IACP,KAAK,OAAO,OAAO,OAAO,KAAK;IAC/B,QAAQ,IAAI;GACd,CACF;EACF,CAAC;CACH;CAEA,SAAS,KACP,OACA,SACA,GAAG,CAAC,SACiB;EACrB,MAAM,UACJ,UAAU,YACN,kBAAmB,QAAoB,IAAI,IAC1C,QAAQ,IAAI,KAAK,KAAK;EAC7B,IAAI,QAAQ,WAAW,GAAG,OAAO;EAKjC,IAAI,UAAU;EACd,MAAM,MAAM;GACV;GACA;GACA,IAAI,UAAU;IACZ,OAAO;GACT;GACA,QAAQ;IACN,UAAU;GACZ;GACA,IAAI,SAAsB;IAExB,OAAQ,WAAW,IAAI,CAAC,CAAc;GACxC;EACF;EACA,IAAI,WAAW,KAAA,GAAW,OAAO,OAAO,KAAK,MAAM;EAEnD,IAAI,YAAY;EAChB,IAAI,SAAS;EACb,IAAI;EACJ,KAAK,MAAM,SAAS,SAAS;GAC3B,IAAI,MAAM,WAAW,MAAM;IACzB,MAAM,SAAU,QAAoB;IACpC,IAAI,CAAC,UAAU,CAAC,MAAM,OAAO,IAAI,OAAO,IAAI,GAAG;GACjD;GACA;GACA,MAAM,WAAW,IAAI,SAAS,MAAM,QAAQ;GAC5C,MAAM,OACJ,MAAM,SAAS,KAAA,IAAY,OAAO,OAAO,GAAG,IAAI,MAAM,KAAK,GAAG;GAChE,KAAK,YAAY;GACjB,IAAI;GACJ,IAAI;IACF,SAAS,MAAM,SAAS,IAA6B;GACvD,SAAS,OAAO;IACd;IACA,KAAK,OAAO,OAAO,OAAO,KAAK;IAC/B;GACF;GACA,IAAID,aAAW,MAAM,GAAG;IACtB,YAAY,CAAC;IACb,QAAQ,KAAK,MAAM,OAAO,OAAO,QAAQ,QAAQ,CAAC;GACpD;EACF;EAEA,IAAI,YAAY,KAAA,GAAW,OAAO,QAAQ,QAAQ;GAAE;GAAW;GAAS;EAAO,CAAC;EAChF,OAAO,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM,YAAY;GAC5C,KAAK,MAAM,kBAAkB,SAAS,IAAI,gBAAgB;GAC1D,OAAO;IAAE;IAAW;IAAS;GAAO;EACtC,CAAC;CACH;CAEA,OAAO;EACL,UAAU,QAAQ,SAAS;GACzB,OAAO,EACL,GAAG,OAAqB,OAAgB,QAA+B;IACrE,OAAO,UAAU,QAAQ,SAAS,OAAO,OAAO,MAAM;GACxD,EACF;EACF;EAEA,aAAa,QAAQ;GACnB,KAAK,MAAM,CAAC,OAAO,YAAY,SAAS;IACtC,MAAM,OAAO,QAAQ,QAAQ,MAAM,EAAE,WAAW,MAAM;IACtD,IAAI,KAAK,WAAW,QAAQ,QAAQ,QAAQ,OAAO,IAAI;GACzD;EACF;EAEA;EAEA,cAAc,OAAO;GACnB,OAAO,QAAQ,IAAI,KAAK,CAAC,EAAE,UAAU;EACvC;EAEA,IAAI,OAAO;GACT,OAAO,YAAY;EACrB;EAEA,SAAS;GACP,IAAI,YAAY,GAAG,OAAO,QAAQ,QAAQ;GAC1C,OAAO,IAAI,SAAS,YAAY,YAAY,KAAK,OAAO,CAAC;EAC3D;CACF;AACF;;;ACpWA,SAAgB,aACd,WAIA,QACQ;CACR,OAAO;EACL,MAAM,SAAS,SAAS;GACtB,iBAAiB,WAAW,QAAQ;GACpC,OAAO,UAAU,iBAAiB,OAAO;EAC3C;EACA,qBAAqB,SAAS,gBAAgB,QAAQ,YACpD,OACE,sBAAsB,MAAM,GAC5B,eACM,UAAU,wBAAwB,SAAS,gBAAgB,MAAM,GACvE,OACF;CACJ;AACF;;;ACrBA,MAAM,0BAA+B,IAAI,IAAgB;CACvD;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,aAAa;;AAGnB,IAAa,yBAAb,cAA4C,MAAM;CAChD,OAAyB;CACzB;CACA;CAEA,YAAY,QAAoB,MAAc;EAC5C,MAAM,QAAQ,OAAO,GAAG,KAAK,eAAe;EAC5C,KAAK,SAAS;EACd,KAAK,OAAO;CACd;AACF;AAsBA,MAAM,uBAAO,IAAI,QAA6B;;;;;AAM9C,SAAgB,WAAW,SAAkC;CAC3D,MAAM,EAAE,SAAS;CACjB,IAAI,EAAE,OAAO,UAAU,IAAI,KAAK,QAAQ,KAAK,QAAQ,QACnD,MAAM,IAAI,WAAW,0DAA0D,KAAK,EAAE;CAExF,MAAM,MAAM,IAAI,QAAQ,OAAO;CAC/B,MAAM,SAAqB,EACzB,IAAI,OAAO;EACT,OAAO,IAAI;CACb,EACF;CACA,KAAK,IAAI,QAAQ,GAAG;CACpB,OAAO;AACT;;AAGA,SAAgB,YAAY,QAAoB,SAAiB,KAAgC;CAC/F,MAAM,MAAM,KAAK,IAAI,MAAM;CAC3B,IAAI,QAAQ,KAAA,GACV,MAAM,IAAI,eAAe,0DAA0D;CAErF,OAAO,IAAI,YAAY,KAAK,SAAS,GAAG;AAC1C;;AAGA,SAAS,cAAc,SAAyB;CAC9C,OAAO,YAAA,YAA8B,KAAK,aAAa;AACzD;AAEA,SAAS,cAAc,MAAsB;CAC3C,IAAI,OAAO,SAAS,YAAY,CAAC,KAAK,WAAW,GAAG,GAClD,MAAM,IAAI,UAAU,mDAAmD,OAAO,IAAI,EAAE,EAAE;CAExF,OAAO,KAAK,SAAS,KAAK,KAAK,SAAS,GAAG,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;AACrE;;AAGA,IAAa,cAAb,MAAyB;CACvB;CACA;CACA;CACA;CACA,2BAAoB,IAAI,IAAwB;CAChD,eAA6B;CAC7B,YAAY;CAEZ,YAAY,KAAc,SAAiB,KAAmB;EAC5D,KAAK,OAAO;EACZ,KAAK,UAAU;EACf,KAAK,MAAM;EACX,KAAK,UAAU,cAAc,OAAO;CACtC;;;;;CAMA,MACE,OACA,SACA,SACY;EACZ,MAAM,aAAqB,KAAK,UAAU,QAAQ;EAClD,MAAM,OAAO,QAAoB,SAAiB,WAAuC;GACvF,MAAM,OAAO,cAAc,OAAO;GAClC,MAAM,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG;GAClC,IAAI,KAAK,SAAS,IAAI,GAAG,GAAG,MAAM,IAAI,uBAAuB,QAAQ,IAAI;GACzE,KAAK,SAAS,IAAI,KAAK;IACrB;IACA;IACA;IACA;IACA;IACA,UAAU,UAAU,QAAQ,OAAO,GAAG,OAAO,GAAG,MAAM;IACtD,yBAAS,IAAI,IAAI;GACnB,CAAC;GACD,IAAI,KAAK,WAAW,KAAK,KAAK,QAAQ;EACxC;EACA,OAAO;GACL,IAAI,WAAW;IACb,OAAO,KAAK;GACd;GACA,MAAM,QAAQ,MAAM,SAAS;IAC3B,IAAI,CAAC,QAAQ,IAAI,MAAM,GACrB,MAAM,IAAI,UAAU,+BAA+B,OAAO,MAAM,GAAG;IAErE,IAAI,QAAQ,MAAM,OAAO;GAC3B;GACA,GAAG,MAAM,QAAQ;IACf,IAAI,OAAO,MAAM,EAAE,IAAI,OAAO,CAAC;GACjC;EACF;CACF;CAEA,UAAgC;EAC9B,OAAO,KAAK,SAAS,OAAO;CAC9B;CAEA,IAAI,YAAqB;EACvB,OAAO,KAAK,SAAS,OAAO;CAC9B;CAEA,QAAgB;EACd,OAAO,KAAK,OAAO;CACrB;;CAGA,YAAY,OAAqB;EAC/B,IAAI,UAAU;EACd,KAAK,MAAM,CAAC,KAAK,UAAU,KAAK,UAAU;GACxC,IAAI,MAAM,UAAU,OAAO;GAC3B,KAAK,SAAS,OAAO,GAAG;GACxB,aAAa,KAAK;GAClB,UAAU;EACZ;EACA,IAAI,WAAW,KAAK,WAAW,KAAK,KAAK,QAAQ;CACnD;;CAGA,OAAO,OAA2B;EAChC,KAAK,KAAK,OAAO,IAAI;EACrB,KAAK,SAAS;EACd,KAAK,YAAY;CACnB;;CAGA,SAAwB;EACtB,OAAO,KAAK,KAAK,OAAO;CAC1B;;CAGA,MAAM,SAAwB;EAC5B,IAAI,CAAC,KAAK,WAAW;EACrB,KAAK,YAAY;EACjB,KAAK,MAAM,SAAS,KAAK,SAAS,OAAO,GAAG,aAAa,KAAK;EAC9D,KAAK,SAAS,MAAM;EACpB,MAAM,KAAK,KAAK,OAAO,IAAI;CAC7B;AACF;AAEA,IAAM,UAAN,MAAc;CACZ;CACA,4BAAqB,IAAI,IAAyB;CAClD;CACA;CACA;CACA;CACA;CACA,WAA0B,QAAQ,QAAQ;CAE1C,SAAS;CAET,YAAY,SAAsB;EAChC,KAAK,WAAW;CAClB;CAEA,IAAI,OAA2B;EAC7B,MAAM,UAAU,KAAK,SAAS,QAAQ;EACtC,OAAO,YAAY,QAAQ,OAAO,YAAY,WAAW,QAAQ,OAAO,KAAA;CAC1E;CAEA,OAAO,SAA4B;EACjC,IAAI,KAAK,UAAU,IAAI,QAAQ,OAAO,GACpC,MAAM,IAAI,eACR,mBAAmB,QAAQ,QAAQ,+EAErC;EAEF,KAAK,UAAU,IAAI,QAAQ,SAAS,OAAO;EAC3C,KAAK,QAAQ;CACf;CAEA,MAAM,OAAO,SAAqC;EAChD,IAAI,KAAK,UAAU,IAAI,QAAQ,OAAO,MAAM,SAAS;EACrD,KAAK,UAAU,OAAO,QAAQ,OAAO;EACrC,KAAK,QAAQ;EACb,IAAI,KAAK,UAAU,SAAS,GAAG,MAAM,KAAK,OAAO;CACnD;CAEA,UAAgB;EACd,KAAK,OAAO,KAAA;EACZ,IAAI,KAAK,UAAU,KAAK,eAAe,KAAA,KAAa,KAAK,WAAW,GAClE,KAAK,QAAQ,CAAC,CAAC,OAAO,UACpB,KAAK,KAAK,CAAC,EAAE,MAAM,gCAAgC;GACjD,KAAK;GACL,MAAM,KAAK,SAAS;EACtB,CAAC,CACH;CAEJ;CAEA,SAAwB;EACtB,KAAK,SAAS;EACd,OAAO,KAAK,WAAW,IAAI,KAAK,QAAQ,IAAI,QAAQ,QAAQ;CAC9D;CAEA,aAAsB;EACpB,KAAK,MAAM,WAAW,KAAK,UAAU,OAAO,GAAG,IAAI,QAAQ,WAAW,OAAO;EAC7E,OAAO;CACT;CAEA,OAA2B;EACzB,KAAK,MAAM,WAAW,KAAK,UAAU,OAAO,GAAG,OAAO,QAAQ,IAAI;CAEpE;CAEA,UAAyB;EACvB,IAAI,KAAK,eAAe,KAAA,GAAW;GAEjC,MAAM,UAAU,KAAK,SAAS,WAAW,KAAK,MAAM,CAAC;GACrD,KAAK,aAAa;GAElB,QAAQ,YAAY;IAClB,IAAI,KAAK,eAAe,SAAS,KAAK,aAAa,KAAA;GACrD,CAAC;EACH;EACA,OAAO,KAAK;CACd;CAEA,MAAM,QAAuB;EAC3B,MAAM,CAAC,EAAE,qBAAqB,oBAAoB,EAAE,QAAQ,EAAE,qBAC5D,MAAM,QAAQ,IAAI;GAAC,OAAO;GAAsB,OAAO;GAAS,OAAO;EAAK,CAAC;EAC/E,KAAK,OAAO;GAAE;GAAM;EAAiB;EACrC,MAAM,MAAM,IAAI,gBAAgB,EAAE,UAAU,KAAK,CAAC;EAClD,MAAM,SAAS,oBAAoB;GACjC,QAAQ,SAAS,QAAQ,KAAK,YAAY,CAAC,CAAC,MAAM,SAAS,GAAG;GAC9D,WAAW,EAAE,QAAQ,IAAI;EAC3B,CAAC;EACD,MAAM,IAAI,SAAe,SAAS,WAAW;GAC3C,OAAO,KAAK,SAAS,MAAM;GAC3B,OAAO,OAAO,KAAK,SAAS,MAAM,KAAK,SAAS,gBAAgB;IAC9D,OAAO,IAAI,SAAS,MAAM;IAC1B,QAAQ;GACV,CAAC;EACH,CAAC;EACD,OAAO,GAAG,UAAU,UAAU,KAAK,KAAK,CAAC,EAAE,MAAM,0BAA0B,EAAE,KAAK,MAAM,CAAC,CAAC;EAC1F,KAAK,UAAU;EACf,KAAK,OAAO;CACd;CAEA,MAAM,SAAwB;EAC5B,KAAK,SAAS;EACd,MAAM,YAAY,KAAK;EACvB,IAAI,cAAc,KAAA,GAAW;EAC7B,KAAK,aAAa,KAAA;EAElB,MAAM,UAAU,UAAU,WAClB,KAAK,MAAM,SACX,KAAA,CACR;EACA,KAAK,WAAW,QAAQ,YAAY,KAAA,CAAS;EAC7C,MAAM;CACR;CAEA,QAAuB;EACrB,MAAM,SAAS,KAAK;EACpB,MAAM,MAAM,KAAK;EACjB,KAAK,UAAU,KAAA;EACf,KAAK,OAAO,KAAA;EACZ,IAAI,WAAW,KAAA,GAAW,OAAO,QAAQ,QAAQ;EACjD,KAAK,MAAM,UAAU,KAAK,WAAW,CAAC,GAAG,OAAO,UAAU;EAC1D,OAAO,IAAI,SAAe,SAAS,WAAW;GAC5C,OAAO,OAAO,UAAW,QAAQ,OAAO,KAAK,IAAI,QAAQ,CAAE;GAE3D,OAAO,oBAAoB;EAC7B,CAAC;CACH;CAEA,cAAoB;EAElB,MAAM,MAAM,KAAK;EACjB,KAAK,SAAS,KAAK,OAAO,GAAG;EAC7B,OAAO,KAAK;CACd;CAEA,OAAO,KAAsB;EAC3B,MAAM,MAAM,IAAI,IAAI,KAAK,EAAE,QAAQ,MAAM,CAAC;EAC1C,IAAI,IAAI,YAAY,MAAM;GACxB,MAAM,WAAmC,CAAC;GAC1C,KAAK,MAAM,CAAC,MAAM,YAAY,KAAK,WAAW,SAAS,QAAQ,QAAQ,MAAM;GAC7E,MAAM,KAAK,OAAO,OAAO,QAAQ,CAAC,CAAC,OAAO,UAAU,UAAU,SAAS;GACvE,OAAO,EAAE,KAAK;IAAE,QAAQ,KAAK,OAAO;IAAY;GAAS,GAAG,KAAK,MAAM,GAAG;EAC5E,CAAC;EACD,KAAK,MAAM,WAAW,KAAK,UAAU,OAAO,GAC1C,KAAK,MAAM,SAAS,QAAQ,QAAQ,GAAG,MAAM,KAAK,OAAO,IAAI,gBAAgB;EAE/E,IAAI,SAAS,OAAO,MAAM;GACxB,KAAK,KAAK,CAAC,EAAE,MAAM,iCAAiC,EAAE,KAAK,MAAM,CAAC;GAClE,OAAO,EAAE,KAAK,yBAAyB,GAAG;EAC5C,CAAC;EACD,OAAO;CACT;AACF;AAEA,SAAS,MAAM,KAAW,OAAmB,kBAAiD;CAC5F,MAAM,OAAO,MAAM,KAAK;CACxB,MAAM,OAAO,MAAM,SAAS,MAAM,OAAO,OAAO,MAAM;CACtD,MAAM,QAAQ,OAAiC,EAAE,QAAQ,EAAE,IAAI,MAAM,EAAE;CACvE,MAAM,EAAE,WAAW;CACnB,IAAI,OAAO,WAAW,YAAY;EAChC,IAAI,GAAG,MAAM,QAAQ,MAAM,OAAO,MAAM;GACtC,IAAI;IACF,MAAM,WAAW,MAAM,OAAO,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC;IAChD,IAAI,oBAAoB,UAAU,OAAO;IACzC,MAAM,IAAI,UAAU,gBAAgB,MAAM,OAAO,GAAG,MAAM,KAAK,0BAA0B;GAC3F,SAAS,OAAO;IACd,MAAM,QAAQ,KAAK;IACnB,OAAO,EAAE,KAAK,yBAAyB,GAAG;GAC5C;EACF,CAAC;EACD;CACF;CACA,IAAI,IAAI,MAAM,OAAO,GAAG,SAAS;EAC/B,IAAI,EAAE,IAAI,OAAO,SAAS,CAAC,EAAE,YAAY,MAAM,aAC7C,OAAO,EAAE,KAAK,oBAAoB,GAAG;EAEvC,IAAI;EACJ,IAAI;GACF,UAAU,MAAM,OAAO,GAAG,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC;EAC9C,SAAS,OAAO;GACd,MAAM,QAAQ,KAAK;GACnB,OAAO,EAAE,KAAK,yBAAyB,GAAG;EAC5C;EACA,IAAI,mBAAmB,UAAU,OAAO;EACxC,MAAM,WAAW;EAIjB,OAAQ,MAHQ,uBAAuB,aAAa,OAAO,QAAQ,GAAG,EACpE,UAAU,UAAU,MAAM,QAAQ,KAAK,EACzC,CACoB,CAAC,CAAC,GAAG,IAAI,KAAM,EAAE,KAAK,yBAAyB,GAAG;CACxE,CAAC;AACH;;AAGA,SAAS,aAAa,OAAmB,UAAwC;CAC/E,IAAI;CACJ,MAAM,QAAQ,OAA8B;EAC1C,WAAW;GAGT,OAAO,SAAS,GAAG,KAAK,IAA4B;GACpD,QAAQ,MAAM,WAAW,GAAG,MAAM,MAAM,MAAM;EAChD;EACA,OAAO;CACT;CACA,MAAM,OAAO,aAA+C;EAC1D,IAAI;GACF,QAAQ,QAAQ,SAAS,CAAC,CAAC,CAAC,MAAM,MAAM,OAAO;EACjD,SAAS,OAAO;GACd,MAAM,QAAQ,KAAK;EACrB;CACF;CACA,OAAO;EACL,OAAO,QAAQ,IAAI;GACjB,MAAM,QAAQ,IAAI,EAAE;GACpB,UAAU,SAAS,SAAS,KAAK,EAAE,CAAC,CAAC;EACvC;EACA,UAAU,OAAO,IAAI;GACnB,UAAU,SAAS,YAAY,KAAK,EAAE,GAAG,MAAM,IAA4B,CAAC;EAC9E;EACA,QAAQ,OAAO,IAAI;GACjB,MAAM,QAAQ,OAAO,EAAE;GACvB,UAAU,SAAS,UAAU,KAAK,EAAE,GAAG,MAAM,MAAM,MAAM,MAAM,CAAC;EAClE;CACF;AACF;AAEA,SAAS,aAAa,OAAyB;CAC7C,KAAK,MAAM,MAAM,MAAM,SAAS,GAAG,MAAM,YAAY,eAAe;CACpE,MAAM,QAAQ,MAAM;AACtB;;;;ACvbA,SAAgB,qBAAqB,SAA+B;CAClE,OAAO;EACL,IAAI,QAAkB;GACpB,OAAO,QAAQ,CAAC,CAAC;EACnB;EACA,QAAQ,SAAS,WAAW,QAAQ,CAAC,CAAC,MAAM,SAAS,MAAM;EAC3D,QAAQ,SAAS,WAAW,QAAQ,CAAC,CAAC,MAAM,SAAS,MAAM;EAC3D,OAAO,SAAS,WAAW,QAAQ,CAAC,CAAC,KAAK,SAAS,MAAM;EACzD,OAAO,SAAS,WAAW,QAAQ,CAAC,CAAC,KAAK,SAAS,MAAM;EACzD,QAAQ,SAAS,WAAW,QAAQ,CAAC,CAAC,MAAM,SAAS,MAAM;EAC3D,QAAQ,SAAS,WAAW,QAAQ,CAAC,CAAC,MAAM,SAAS,MAAM;EAC3D,QAAQ,aAAa,qBAAqB,QAAQ,SAAS,QAAQ,CAAC;CACtE;AACF;;AAGA,SAAS,QAAQ,SAAuB,UAAmC;CACzE,IAAI;CACJ,IAAI;CACJ,aAAa;EACX,MAAM,UAAU,QAAQ;EACxB,IAAI,YAAY,UAAU,UAAU,KAAA,GAAW;GAC7C,SAAS;GACT,QAAQ,QAAQ,MAAM,QAAQ;EAChC;EACA,OAAO;CACT;AACF;;;ACfA,SAAgB,kBAA6B;CAC3C,MAAM,0BAAU,IAAI,IAA+B;CACnD,IAAI,UAAU;CACd,IAAI;CAEJ,MAAM,gBAAsB;EAC1B,WAAW;EACX,SAAS,KAAA;CACX;CAEA,OAAO;EACL,IAAI,UAAkB;GACpB,OAAO;EACT;EACA,SAA4B;GAC1B,WAAW,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;GACpD,OAAO;EACT;EACA,IAAI,OAAe,QAAiC;GAClD,MAAM,OAAO,OAAO,QAAQ,UAAU,MAAM,SAAS,CAAC;GACtD,IAAI,KAAK,WAAW,GAAG;IACrB,IAAI,QAAQ,OAAO,KAAK,GAAG,QAAQ;IACnC;GACF;GACA,QAAQ,IAAI,OAAO,CAAC,GAAG,IAAI,CAAC;GAC5B,QAAQ;EACV;EACA,OAAO,OAAqB;GAC1B,IAAI,QAAQ,OAAO,KAAK,GAAG,QAAQ;EACrC;CACF;AACF;;;;AChCA,SAAgB,WAAW,SAAwD;CACjF,MAAM,UAAU,YAAY,OAAO;CACnC,QAAQ,KAAK,SAAU,QAAQ,IAAI,QAAQ,IAAI,IAAI,KAAK,IAAI,KAAA;AAC9D;;;;;AAMA,SAAgB,YACd,SACkD;CAClD,MAAM,QAAQ,QAAQ,UAAU,KAAA,IAAY,OAAO,IAAI,IAAI,QAAQ,KAAK;CACxE,MAAM,QAAQ,IAAI,IAAI,QAAQ,KAAK;CACnC,QAAQ,EAAE,IAAI,eAAe;EAC3B,MAAM,YAAY,SAAsB,aAAa,KAAA,KAAa,KAAK,IAAI,QAAQ;EACnF,IAAI,MAAM,IAAI,EAAE,KAAK,SAAS,KAAK,GAAG,OAAO;EAC7C,OAAO,UAAU,QAAQ,MAAM,IAAI,EAAE,KAAK,SAAS,KAAK;CAC1D;AACF;;;;;;;AC9BA,SAAgB,aAAyC;CACvD,QAAQ,KAAK,SAAU,IAAI,QAAQ,OAAO,UAAU,OAAO,KAAA,IAAY,KAAK;AAC9E;;;;ACLA,SAAgB,aAAyC;CACvD,QAAQ,KAAK,SAAU,IAAI,QAAQ,SAAS,KAAA,IAAY,KAAK;AAC/D;;;;ACuBA,IAAa,yBAAb,cAA4C,MAAM;CAChD,OAAyB;CACzB;CAEA,YAAY,WAAmB;EAC7B,MAAM,sBAAsB,UAAU,IAAI;EAC1C,KAAK,YAAY;CACnB;AACF;;AAGA,IAAa,2BAAb,cAA8C,MAAM;CAClD,OAAyB;CAEzB,cAAc;EACZ,MAAM,iDAAiD;CACzD;AACF;AAOA,MAAM,WAA0B,QAAQ,QAAQ;AAChD,MAAM,aAAmB,KAAA;;;;;AAMzB,IAAa,qBAAb,MAA2E;CACzE,WAAuB,CAAC;CACxB,SAAmC,CAAC;CACpC;CACA;CAEA,0BAAmB,IAAI,IAAgB;CAEvC,YAAY,UAAqC,CAAC,GAAG;EACnD,MAAM,EAAE,cAAc;EAEtB,IAAI,cAAc,KAAA,MAAc,CAAC,OAAO,SAAS,SAAS,KAAK,aAAa,IAC1E,MAAM,IAAI,WAAW,mBAAmB,WAAW;EAErD,KAAK,aAAa;EAClB,KAAK,eAAe,QAAQ,eAAe;CAC7C;;CAGA,IAAI,YAA2B,UAA6B,CAAC,GAAe;EAC1E,MAAM,WAAW,QAAQ,YAAY;EAErC,IAAI,CAAC,OAAO,SAAS,QAAQ,GAAG,MAAM,IAAI,WAAW,wBAAwB,UAAU;EACvF,MAAM,QAAkB;GAAE;GAAY;EAAS;EAC/C,KAAK,SAAS,KAAK,KAAK;EACxB,KAAK,SAAS;EACd,aAAa;GACX,MAAM,QAAQ,KAAK,SAAS,QAAQ,KAAK;GACzC,IAAI,UAAU,IAAI;GAClB,KAAK,SAAS,OAAO,OAAO,CAAC;GAC7B,KAAK,SAAS;EAChB;CACF;CAEA,IAAI,OAAe;EACjB,OAAO,KAAK,OAAO;CACrB;;;;;;;;;;;;;CAcA,IAAI,KAAQ,UAAwD;EAElE,MAAM,QAAQ,KAAK;EACnB,MAAM,SAAS,MAAM;EACrB,IAAI,WAAW,GACb,OAAO,aAAa,KAAA,IAAY,QAAQ,QAAQ,IAAI,IAAI,SAAS,GAAG,CAAC,CAAC,WAAW,IAAI;EAGvF,IAAI,QAAQ;EACZ,IAAI,YAAY;EAChB,IAAI;EACJ,MAAM,UAAU,UAAwC;GACtD,UAAU;EACZ;EACA,MAAM,YAAY,MAA6B;GAC7C,IAAI,YAAY,KAAA,GAAW,OAAO,QAAQ,OAAO,OAAO;GACxD,IAAI,KAAK,OAAO,OAAO,QAAQ,uBAAO,IAAI,MAAM,gCAAgC,CAAC;GACjF,QAAQ;GACR,IAAI,MAAM,QAAQ;IAChB,YAAY;IACZ,OAAO,aAAa,KAAA,IAAY,WAAW,SAAS,GAAG;GACzD;GAEA,MAAM,aAAa,MAAM;GACzB,MAAM,aAA4B,SAAS,IAAI,CAAC;GAChD,IAAI,KAAK,eAAe,KAAA,GAAW,OAAO,KAAK,OAAO,YAAY,KAAK,MAAM,MAAM;GACnF,IAAI;IAEF,OAAO,QAAQ,QAAQ,WAAW,KAAK,IAAI,CAAC;GAC9C,SAAS,OAAO;IAEd,OAAO,QAAQ,OAAO,KAAK;GAC7B;EACF;EACA,OAAO,SAAS,CAAC,CAAC,CAAC,WAAW,SAAS;CACzC;;;;;CAMA,QAAc;EACZ,KAAK,MAAM,WAAW,CAAC,GAAG,KAAK,OAAO,GAAG,QAAQ;CACnD;;;;;;CAOA,OACE,YACA,KACA,MACA,QACe;EAEf,MAAM,YAAY,KAAK;EACvB,IAAI,UAAU;EACd,IAAI,QAAQ;EACZ,IAAI,SAAS;EACb,IAAI;EACJ,IAAI,YAAY;EAChB,IAAI,YAAY;EAChB,IAAI;EACJ,IAAI,OAAiC;EAErC,MAAM,cAAoB;GACxB,IAAI,UAAU,KAAA,GAAW;GACzB,aAAa,KAAK;GAClB,QAAQ,KAAA;GACR,aAAa,YAAY,IAAI,IAAI;EACnC;EACA,MAAM,eAAqB;GACzB,UAAU;GACV,MAAM;GACN,KAAK,QAAQ,OAAO,OAAO;EAC7B;EACA,MAAM,eAAqB;GACzB,YAAY,YAAY,IAAI;GAC5B,QAAQ,iBACA;IACJ,QAAQ,KAAA;IACR,MAAM,QAAQ,IAAI,uBAAuB,SAAS;IAClD,OAAO,KAAK;IACZ,OAAO;IACP,KAAK,KAAK;GACZ,GACA,KAAK,IAAI,GAAG,SAAS,CACvB;EACF;EACA,MAAM,gBAAsB;GAC1B,IAAI,SAAS;GACb,OAAO;GACP,KAAK,IAAI,yBAAyB,CAAC;EACrC;EACA,MAAM,aAAmB;GACvB,SAAS;GACT,IAAI,SAAS,CAAC,SAAS,OAAO;EAChC;EACA,MAAM,kBAAiC;GACrC,MAAM,UAAU,KAAK;GACrB,IAAI,SAAS,OAAO;GACpB,MAAM;GACN,SAAS;GACT,WAAW;GAEX,QAAQ,KAAK,MAAM,IAAI;GACvB,OAAO;EACT;EAEA,IAAI;EACJ,IAAI;GACF,SAAS,WAAW,KAAK,SAAS;EACpC,SAAS,OAAO;GACd,UAAU;GACV,OAAO,QAAQ,OAAO,KAAK;EAC7B;EAEA,IAAI,CAACE,aAAW,MAAM,KAAK,WAAW,UAAU;GAC9C,UAAU;GACV,OAAO,QAAQ,QAAQ,MAAM;EAC/B;EACA,QAAQ;EACR,IAAI,CAAC,QAAQ,OAAO;EACpB,KAAK,QAAQ,IAAI,OAAO;EACxB,MAAM,UAAU;EAChB,OAAO,IAAI,SAAe,SAAS,WAAW;GAC5C,OAAO;GACP,QAAQ,WACA;IACJ,IAAI,SAAS;IACb,OAAO;IACP,QAAQ;GACV,IACC,UAAmB;IAClB,IAAI,SAAS;KACX,KAAK,aAAa,KAAK;KACvB;IACF;IACA,OAAO;IACP,OAAO,KAAK;GACd,CACF;EACF,CAAC;CACH;CAEA,WAAiB;EAGf,KAAK,SAAS,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;EACpD,KAAK,SAAS,KAAK,SAAS,KAAK,UAAU,MAAM,UAAU;CAC7D;AACF;;;;;;;;ACjPA,IAAa,cAAb,MAAyB;CACvB;CACA;CACA;CAGA,2BAAoB,IAAI,IAAoB;CAE5C,YAAY,SAA6B;EACvC,IAAI,CAAC,OAAO,UAAU,QAAQ,GAAG,KAAK,QAAQ,MAAM,GAClD,MAAM,IAAI,WAAW,iCAAiC,QAAQ,KAAK;EAErE,IAAI,EAAE,QAAQ,WAAW,IACvB,MAAM,IAAI,WAAW,0BAA0B,QAAQ,UAAU;EAEnE,KAAK,OAAO,QAAQ;EACpB,KAAK,YAAY,QAAQ;EACzB,KAAK,SAAS,QAAQ,gBAAgB,YAAY,IAAI;CACxD;;CAGA,IAAI,KAAsB;EACxB,MAAM,MAAM,KAAK,OAAO;EACxB,KAAK,OAAO,GAAG;EACf,MAAM,SAAS,KAAK,SAAS,IAAI,GAAG;EACpC,IAAI,WAAW,KAAA,GAAW;GACxB,KAAK,SAAS,IAAI,KAAK;IAAE,OAAO;IAAK,OAAO;GAAE,CAAC;GAC/C,OAAO;EACT;EACA,OAAO;EACP,OAAO,OAAO,SAAS,KAAK;CAC9B;;CAGA,IAAI,OAAe;EACjB,OAAO,KAAK,SAAS;CACvB;CAEA,OAAO,KAAmB;EACxB,KAAK,MAAM,CAAC,KAAK,WAAW,KAAK,UAAU;GACzC,IAAI,MAAM,OAAO,QAAQ,KAAK,WAAW;GACzC,KAAK,SAAS,OAAO,GAAG;EAC1B;CACF;AACF;AAYA,MAAM,OAAgE;CACpE,SAAS,QAAQ,IAAI,QAAQ,OAAO;CACpC,OAAO,QAAQ,IAAI,QAAQ,KAAK;CAEhC,mBAAmB,QAAQ,GAAG,IAAI,QAAQ,KAAK,GAAG,QAAQ,IAAI,QAAQ,OAAO;AAC/E;;AAGA,SAAgB,UAAU,SAAuD;CAC/E,MAAM,UAAU,IAAI,YAAY,OAAO;CACvC,MAAM,QAAQ,KAAK,QAAQ,MAAM;CACjC,MAAM,YAAY,QAAQ;CAC1B,QAAQ,KAAK,SAAS;EACpB,IAAI,QAAQ,IAAI,MAAM,GAAG,CAAC,GAAG,OAAO,KAAK;EACzC,YAAY,GAAG;CAEjB;AACF;;;;;;;ACjEA,SAAgB,SAAS,UAA2B,CAAC,GAAiC;CACpF,MAAM,UAAU,QAAQ,iBAAiB;CACzC,MAAM,UAAU,QAAQ,uBAAuB;CAC/C,KAAK,MAAM,CAAC,MAAM,UAAU,CAC1B,CAAC,iBAAiB,OAAO,GACzB,CAAC,uBAAuB,OAAO,CACjC,GACE,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GACtC,MAAM,IAAI,WAAW,GAAG,KAAK,6BAA6B,OAAO;CAGrE,QAAQ,KAAK,SAAS;EACpB,MAAM,EAAE,YAAY;EAEpB,MAAM,OAAO,SAAS,IAAI,SAAS,KAAA,IAAY,QAAQ,OAAO,IAAI,MAAM,OAAO;EAC/E,IAAI,OAAO;EACX,IAAI,YAAY;GAAE;GAAM,YAAY,SAAS,QAAQ,OAAO,MAAM,OAAO;EAAE;EAC3E,OAAO,KAAK;CACd;AACF;AAEA,SAAS,SAAS,OAAsB,KAA4B;CAClE,IAAI,UAAU,QAAQ,MAAM,UAAU,KAAK,OAAO;CAElD,MAAM,OAAO,MAAM,WAAW,MAAM,CAAC;CACrC,MAAM,MAAM,QAAQ,SAAU,QAAQ,QAAS,MAAM,IAAI;CACzD,OAAO,MAAM,MAAM,GAAG,GAAG;AAC3B;;;AC/BA,MAAM,aAAa;CAAC;CAAQ;CAAM;CAAK;AAAE;;;;;;AAOzC,SAAgB,UACd,MACA,QACA,SACe;CACf,IAAI,QAAQ,IAAI,KAAK,OAAO,OAAO,OAAO,CAAC,IAAI;CAC/C,MAAM,MAAM,OAAO,SAAS;CAC5B,MAAM,SAAS,aACb,MAAM,SAAS,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,UAAU,QAAQ,UAAU,CAAC,CAAC;CAC7E,MAAM,SAAsB,CAAC;CAE7B,MAAM,QAAQ,aACZ,QAAQ,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,OAAO,WAAW,IAAI,OAAO,QAAQ,OAAO;CAEjF,MAAM,QAAQ,UAA8B,UAAwB;EAClE,MAAM,SAAS,IAAI,UAAU,WAAW,UAAU,EAAE;EACpD,IAAI,IAAI;EACR,OAAO,IAAI,OAAO,QAAQ;GACxB,IAAI,CAAC,KAAK,OAAO,MAAM,CAAC,CAAC,GAAG;IAC1B,IAAI,QAAQ,WAAW,SAAS,GAAG,KAAK,OAAO,MAAM,CAAC,GAAG,QAAQ,CAAC;SAC7D,OAAO,KAAK,OAAO,MAAM,CAAC,CAAC;IAChC;IACA;GACF;GAGA,IAAI,KAAK;GACT,IAAI,MAAM;GACV,OAAO,IAAI,OAAO,OAAO,UAAU,KAAKC,OAAK,QAAQ,GAAG,GAAG,CAAC,GAAG;IAC7D,KAAK;IACL,OAAO;GACT;GACA,MAAM,KAAK,IAAI,KAAK,OAAO,SAAS,IAAI,CAAC;GACzC,OAAO,MAAM,KAAK,GAAG;IACnB,MAAM,MAAO,KAAK,OAAQ;IAC1B,IAAI,KAAKA,OAAK,QAAQ,GAAG,GAAG,CAAC,GAAG,KAAK;SAChC,MAAM;GACb;GACA,OAAO,KAAKA,OAAK,QAAQ,GAAG,EAAE,CAAC;GAC/B,KAAK;EACP;CACF;CACA,KAAK,QAAQ,IAAI,GAAG,CAAC;CAErB,MAAM,MAAqB,CAAC;CAC5B,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,UAAU,KAAK,KAAK;EAC1B,IAAI,QAAQ,SAAS,GAAG,IAAI,KAAK,MAAM,OAAO,CAAC;CACjD;CACA,OAAO;AACT;AAEA,SAASA,OAAK,QAA8B,OAAe,OAA0B;CACnF,OAAO,OAAO,MAAM,OAAO,QAAQ,KAAK,CAAC,CAAC,KAAK;AACjD;AAEA,SAAS,QAAQ,MAA8B;CAC7C,IAAI,OAAO,SAAS,UAAU,OAAO,CAAC;EAAE,MAAM,CAAC;EAAG;EAAM,MAAM;CAAK,CAAC;CACpE,MAAM,MAAiB,CAAC;CACxB,MAAM,QAAQ,OAA4B,SAAmC;EAC3E,KAAK,MAAM,QAAQ,OACjB,IAAI,OAAO,SAAS,UAAU,IAAI,KAAK;GAAE;GAAM,MAAM;GAAM,MAAM;EAAK,CAAC;OAClE,IAAI,KAAK,SAAS,QAAQ,IAAI,KAAK;GAAE;GAAM,MAAM,KAAK;GAAM,MAAM;EAAK,CAAC;OACxE,IAAI,KAAK,SAAS,WAAW,IAAI,KAAK;GAAE;GAAM,MAAM;GAAI,MAAM;EAAK,CAAC;OACpE,KAAK,KAAK,UAAU,CAAC,GAAG,MAAM,IAAI,CAAC;CAE5C;CACA,KAAK,KAAK,OAAO,CAAC,CAAC;CACnB,OAAO;AACT;;AAGA,SAAS,IAAI,UAA8B,WAAgC;CACzE,MAAM,SAAsB,CAAC;CAC7B,IAAI,UAAqB,CAAC;CAC1B,KAAK,MAAM,WAAW,UAAU;EAC9B,IAAI,QAAQ,MAAM,SAAS,WAAW;GACpC,QAAQ,KAAK,OAAO;GACpB;EACF;EACA,IAAI,QAAQ;EACZ,KAAK,MAAM,OAAO,UAAU,QAAQ,MAAM,SAAS,GAAG;GACpD,QAAQ,KAAK;IAAE,GAAG;IAAS,MAAM,QAAQ,KAAK,MAAM,OAAO,GAAG;GAAE,CAAC;GACjE,OAAO,KAAK,OAAO;GACnB,UAAU,CAAC;GACX,QAAQ;EACV;EACA,IAAI,QAAQ,QAAQ,KAAK,QAAQ,QAAQ,KAAK;GAAE,GAAG;GAAS,MAAM,QAAQ,KAAK,MAAM,KAAK;EAAE,CAAC;CAC/F;CACA,IAAI,QAAQ,SAAS,GAAG,OAAO,KAAK,OAAO;CAC3C,OAAO;AACT;AAEA,UAAU,UAAU,MAAc,WAAsC;CACtE,IAAI,cAAc,IAAI;EAEpB,IAAI,QAAQ;EACZ,KAAK,MAAM,QAAQ,MAAM;GACvB,SAAS,KAAK;GACd,MAAM;EACR;EACA;CACF;CAEA,KAAK,IAAI,KAAK,KAAK,QAAQ,SAAS,GAAG,OAAO,IAAI,KAAK,KAAK,QAAQ,WAAW,EAAE,GAAG;EAClF,MAAM,UAAU;EAChB,MAAM;CACR;AACF;;AAGA,SAAS,KAAK,OAAsC;CAClD,MAAM,MAAM,CAAC,GAAG,KAAK;CACrB,MAAM,QAAQ,OAAe,OAAqB;EAChD,MAAM,UAAU,IAAI;EACpB,IAAI,YAAY,KAAA,KAAa,QAAQ,SAAS,MAAM;EACpD,IAAI,SAAS;GAAE,GAAG;GAAS,MAAM,QAAQ,KAAK,QAAQ,IAAI,EAAE;EAAE;CAChE;CACA,OAAO,IAAI,SAAS,GAAG;EACrB,KAAK,GAAG,MAAM;EACd,IAAI,IAAI,EAAE,EAAE,SAAS,QAAQ,IAAI,EAAE,CAAC,SAAS,IAAI,IAAI,MAAM;OACtD;CACP;CACA,OAAO,IAAI,SAAS,GAAG;EACrB,KAAK,IAAI,SAAS,GAAG,MAAM;EAC3B,IAAI,IAAI,GAAG,EAAE,CAAC,EAAE,SAAS,QAAQ,IAAI,GAAG,EAAE,CAAC,EAAE,SAAS,IAAI,IAAI,IAAI;OAC7D;CACP;CACA,OAAO;AACT;;AAGA,SAAS,QAAQ,UAA8B,OAA2B;CACxE,MAAM,MAAkB,CAAC;CACzB,IAAI,IAAI;CACR,OAAO,IAAI,SAAS,QAAQ;EAC1B,MAAM,UAAU,SAAS;EACzB,MAAM,UAAU,QAAQ,KAAK;EAC7B,IAAI,YAAY,KAAA,GAAW;GACzB,IAAI,IAAI,IAAI;GACZ,OAAO,IAAI,SAAS,UAAU,SAAS,EAAE,EAAE,KAAK,WAAW,SAAS;GACpE,MAAM,WAAW,QAAQ,SAAS,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC;GACxD,IAAI,KACF,OAAO,OACL,QAAQ,SAAS,SACb;IAAE,MAAM;IAAQ,KAAK,QAAQ;IAAK,UAAU,OAAO,OAAO,QAAQ;GAAE,IACpE;IAAE,MAAM,QAAQ;IAAM,UAAU,OAAO,OAAO,QAAQ;GAAE,CAC9D,CACF;GACA,IAAI;GACJ;EACF;EACA,MAAM,EAAE,SAAS;EACjB,IAAI,MAAM,SAAS,WAAW;GAC5B,IAAI,KAAK,IAAI;GACb;GACA;EACF;EACA,IAAI,IAAI,IAAI;EACZ,IAAI,OAAO,QAAQ;EACnB,OACE,IAAI,SAAS,UACb,SAAS,EAAE,EAAE,KAAK,WAAW,SAC7B,SAAS,EAAE,EAAE,SAAS,MACtB;GACA,QAAQ,SAAS,EAAE,EAAE,QAAQ;GAC7B;EACF;EACA,IAAI,SAAS,IAAI,IAAI,KAAK,SAAS,OAAO,OAAO,OAAO,OAAO;GAAE,MAAM;GAAQ;EAAK,CAAC,CAAC;EACtF,IAAI;CACN;CACA,OAAO;AACT;;;;AC/LA,SAAgB,YAAY,MAAoC;CAC9D,OAAO,OAAO,SAAS,WACnB;EAAE,MAAM;EAAQ;CAAK,IACrB;EAAE,MAAM;EAAQ,MAAM,UAAU,IAAI;EAAG,WAAW;CAAK;AAC7D;;AAGA,SAAgB,cAAc,SAG5B;CACA,IAAI,YAAY,KAAA,GAAW,OAAO,CAAC;CACnC,OAAO,OAAO,YAAY,WACtB,EAAE,QAAQ,IACV;EAAE,SAAS,UAAU,OAAO;EAAG,kBAAkB;CAAQ;AAC/D;;AAGA,SAAgB,UAAU,OAAuD;CAC/E,IAAI,OAAO,UAAU,YAAY,YAAY,KAAK,GAAG,OAAO,YAAY,KAAK;CAE7E,IAAI,MAAM,SAAS,UAAU,MAAM,cAAc,KAAA,GAAW,OAAO,YAAY,MAAM,SAAS;CAC9F,IAAI,sBAAsB,SAAS,MAAM,qBAAqB,KAAA,GAC5D,OAAO;EAAE,GAAG;EAAO,SAAS,UAAU,MAAM,gBAAgB;CAAE;CAEhE,OAAO;AACT;AAEA,SAAS,eAAe,MAA2B;CACjD,OAAO,OAAO,SAAS,WAAW,KAAK,SAAS,UAAU,IAAI,CAAC,CAAC;AAClE;;AAGA,SAAgB,cAAc,MAAc,OAAmC;CAC7E,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO;CACvC,IAAI,EAAE,OAAO,UAAU,KAAK,KAAK,SAAS,IACxC,MAAM,IAAI,WAAW,UAAU,KAAK,iDAAiD,MAAM,EAAE;CAE/F,OAAO;AACT;;AAGA,IAAa,cAAb,MAAyB;CACvB;CACA;CACA;;CAEA;CAEA,YAAY,WAAsC;EAChD,MAAM,SAAqB,UAAU,UAAU,CAAC;EAChD,KAAK,QAAQ,cAAc,QAAQ,OAAO,IAAI;EAC9C,KAAK,WAAW,cAAc,WAAW,OAAO,OAAO;EACvD,MAAM,SAAS,OAAO;EACtB,KAAK,WAAW,WAAW,KAAA,IAAY,kBAAkB,SAAS,OAAO,KAAK,QAAQ,IAAI;EAC1F,KAAK,aACH,KAAK,UAAU,OAAO,qBAAqB,KAAK,aAAa,OAAO;CACxE;;;;;CAMA,MAAM,SAA0B,SAA8C;EAC5E,IAAI,KAAK,YAAY,OAAO,CAAC;GAAE;GAAS;EAAQ,CAAC;EACjD,IAAI;EACJ,IAAI;EACJ,IAAI,QAAQ,SAAS,QAAQ;GAC3B,MAAM,QAAQ,KAAK,OAAO,QAAQ,aAAa,QAAQ,MAAM,KAAK,KAAK;GACvE,IAAI,MAAM,UAAU,GAAG,OAAO,CAAC;IAAE;IAAS;GAAQ,CAAC;GACnD,QAAQ,YAAY,MAAM,EAAiB;GAC3C,OAAO,MAAM,MAAM,CAAC;EACtB,OAAO,KACJ,QAAQ,SAAS,WAChB,QAAQ,SAAS,WACjB,QAAQ,SAAS,cACjB,QAAQ,SAAS,YACnB,QAAQ,YAAY,KAAA,GACpB;GACA,MAAM,QAAQ,KAAK,OAAO,QAAQ,oBAAoB,QAAQ,SAAS,KAAK,QAAQ;GACpF,IAAI,MAAM,UAAU,GAAG,OAAO,CAAC;IAAE;IAAS;GAAQ,CAAC;GACnD,MAAM,EAAE,SAAS,UAAU,kBAAkB,YAAY,GAAG,UAAU;GACtE,QAAQ;IAAE,GAAG;IAAO,GAAG,cAAc,MAAM,EAAE;GAAE;GAC/C,OAAO,MAAM,MAAM,CAAC;EACtB,OACE,OAAO,CAAC;GAAE;GAAS;EAAQ,CAAC;EAE9B,IAAI,eAAe;EACnB,IAAI;EACJ,IAAI;EACJ,IAAI,YAAY,KAAA,GAAW;GAEzB,MAAM,EAAE,QAAQ,SAAS,SAAS,GAAG,WAAW;GAChD,cAAc;GACd,cAAc,YAAY,KAAA,IAAY,SAAS;IAAE,GAAG;IAAQ;GAAQ;GACpE,IAAI,YAAY,KAAA,GAAW;IACzB,MAAM,EAAE,SAAS,UAAU,GAAG,mBAAmB;IACjD,eAAe;GACjB;EACF;EACA,MAAM,OAAO,KAAK,SAAS;EAC3B,OAAO,CACL;GAAE,SAAS;GAAO,SAAS;EAAa,GACxC,GAAG,KAAK,KAAK,MAAM,WAAW;GAC5B,SAAS,YAAY,IAAI;GACzB,SAAS,UAAU,OAAO,cAAc;EAC1C,EAAE,CACJ;CACF;;CAGA,eAAe,MAAyB;EACtC,IAAI,KAAK,UAAU,OAAO,mBAAmB;EAC7C,MAAM,OAAO,KAAK,SAAS,IAAI;EAC/B,IAAI,OAAO,KAAK,OACd,MAAM,IAAI,WACR,uBAAuB,KAAK,4CAA4C,KAAK,MAAM,EACrF;CAEJ;CAEA,OAAO,MAAmB,OAA8B;EACtD,IAAI,UAAU,OAAO,mBAAmB,OAAO,CAAC,IAAI;EAGpD,OAAO,UAAU,MAAM;GAAE,OAAO;GAAO,MAD1B,OAAO,SAAS,KAAK,KAAK,IAAI,KAAK,QAAQ;EACZ,GAAG,KAAK,QAAQ;CAC9D;AACF;;;ACrHA,SAAgB,cACd,OACA,WACe;CACf,QAAQ,YAAY,QAAQ,KAAK,YAAY;EAC3C,IAAI;GAEF,iBAAiB,WAAW,UAAU;EACxC,SAAS,OAAO;GACd,OAAO,QAAQ,OAAO,KAAK;EAC7B;EACA,OAAO,MAAM,QAAQ,QAAQ,KAAK,OAAO;CAC3C;AACF;AAEA,SAAgB,eACd,OACA,WACU;CACV,MAAM,SAAS,cAAc,OAAO,SAAS;CAC7C,MAAM,UAAU,IAAI,YAAY,SAAS;CACzC,OAAO;EACL,OAAO,QAAQ,SAAS,YAAY,MAAM,KAAK,QAAQ,SAAS,OAAO;EACvE,QAAQ,KAAK,OAAO,YAClB,OAAO,aAAa,IAAI,cAAc,UAAU,MAAM,KAAK,KAAK,GAAG,OAAO;EAC5E,OAAO,KAAK,MAAM,YAAY;GAC5B,IAAI;IACF,QAAQ,eAAe,IAAI;GAC7B,SAAS,OAAO;IACd,OAAO,QAAQ,OAAO,KAAK;GAC7B;GAEA,IAAI,OAAO,SAAS,UAClB,OAAO,OAAO,gBAAgB,IAAI,cAAc,UAAU,KAAK,KAAK,IAAI,GAAG,OAAO;GAEpF,MAAM,UAAU,UAAU,IAAI;GAC9B,OAAO,OAAO,gBAAgB,IAAI,cAAc,UAAU,KAAK,KAAK,SAAS,IAAI,GAAG,OAAO;EAC7F;EACA,SAAS,KAAK,YACZ,OAAO,kBAAkB,IAAI,cAAc,UAAU,OAAO,GAAG,GAAG,OAAO;EAC3E,SAAS,QAAQ,MAAM,YACrB,OAAO,UAAU,cAAc,UAAU,WAAW,QAAQ,IAAI,GAAG,OAAO;CAC9E;AACF;;;;AC1DA,IAAa,gBAAb,MAA2B;;CAEzB;CAEA,YAAY,WAAuD;EACjE,MAAM,MAAM,cAAc,SAAS,UAAU,QAAQ,KAAK;EAC1D,KAAK,QAAQ,UAAU,aAAa,IAAI,YAAY,IAAI,MAAM;CAChE;;;;;;;CAQA,MAAM,SAAuB,SAA8C;EACzE,MAAM,EAAE,UAAU;EAClB,IAAI,MAAM,WAAW,GAAG,MAAM,IAAI,UAAU,iBAAiB;EAC7D,MAAM,WAA8B,CAAC;EACrC,KAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,KAAK,OAAO;GAC7D,MAAM,MAAM,MAAM,MAAM,OAAO,QAAQ,KAAK,KAAK;GACjD,MAAM,UAAU,UAAU,IAAI,UAAU,OAAO,IAAI,CAAC;GACpD,SAAS,KACP,IAAI,WAAW,IACV;IAAE,GAAG,IAAI;IAAI,GAAG;GAAQ,IACzB;IAAE,MAAM;IAAS,OAAO;IAAK,GAAG;GAAQ,CAC9C;EACF;EACA,OAAO,WAAW,UAAU,OAAO;CACrC;AACF;;AAGA,SAAS,UAAU,SAA2E;CAC5F,OAAO;EACL,GAAI,QAAQ,YAAY,KAAA,IAAY,OAAO,EAAE,SAAS,QAAQ,QAAQ;EACtE,GAAI,QAAQ,qBAAqB,KAAA,IAC7B,OACA,EAAE,kBAAkB,QAAQ,iBAAiB;CACnD;AACF;AAEA,SAAS,WAAW,UAA6B,SAA8C;CAC7F,IAAI,YAAY,KAAA,KAAa,SAAS,WAAW,GAC/C,OAAO,SAAS,KAAK,aAAa;EAAE;EAAS;CAAQ,EAAE;CAEzD,MAAM,EAAE,QAAQ,SAAS,GAAG,WAAW;CACvC,MAAM,OAAO,SAAS,SAAS;CAC/B,OAAO,SAAS,KAAK,SAAS,WAAW;EACvC;EACA,SAAS;GACP,GAAG;GACH,GAAI,UAAU,KAAK,WAAW,KAAA,IAAY,EAAE,OAAO,IAAI;GACvD,GAAI,UAAU,QAAQ,YAAY,KAAA,IAAY,EAAE,QAAQ,IAAI;EAC9D;CACF,EAAE;AACJ;;;;;;;AC6DA,IAAa,qBAAb,cAAwC,MAAM;CAC5C,OAAyB;CACzB;CAEA,YAAY,QAAkC,SAAiB;EAC7D,MAAM,OAAO;EACb,KAAK,SAAS;CAChB;AACF;AAMA,MAAM,iCAAqD,IAAI,IAAiC;CAC9F,CAAC,QAAQ,CAAC;CACV,CAAC,UAAU,CAAC;CACZ,CAAC,OAAO,CAAC;AACX,CAAC;AAED,MAAM,WAAW;CACf,kBAAkB;CAClB,gBAAgB;CAChB,YAAY;CACZ,aAAa;CACb,aAAa;CACb,YAAY;CACZ,YAAY;CACZ,eAAe;CACf,WAAW;CACX,OAAO;CACP,OAAO;AACT;;AAGA,IAAM,OAAN,MAAc;CACZ,SAA4B,CAAC;CAC7B,QAAQ;CAER,IAAI,OAAe;EACjB,OAAO,KAAK,OAAO,SAAS,KAAK;CACnC;CAEA,KAAK,MAAe;EAClB,KAAK,OAAO,KAAK,IAAI;CACvB;CAEA,OAAsB;EACpB,OAAO,KAAK,OAAO,KAAK;CAC1B;CAEA,QAAuB;EACrB,IAAI,KAAK,SAAS,KAAK,OAAO,QAAQ,OAAO,KAAA;EAC7C,MAAM,OAAO,KAAK,OAAO,KAAK;EAC9B,KAAK,OAAO,KAAK,SAAS,KAAA;EAC1B,KAAK;EACL,IAAI,KAAK,UAAU,KAAK,OAAO,QAAQ;GACrC,KAAK,SAAS,CAAC;GACf,KAAK,QAAQ;EACf,OAAO,IAAI,KAAK,SAAS,QAAQ,KAAK,QAAQ,KAAK,KAAK,OAAO,QAAQ;GAErE,KAAK,SAAS,KAAK,OAAO,MAAM,KAAK,KAAK;GAC1C,KAAK,QAAQ;EACf;EACA,OAAO;CACT;CAEA,QAAc;EACZ,KAAK,SAAS,CAAC;EACf,KAAK,QAAQ;CACf;AACF;;;;;AAoDA,IAAa,gBAAb,MAA6C;CAC3C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAIA,yBAAkB,IAAI,IAAuB;CAG7C,6BAAsB,IAAI,IAAoB;CAG9C,SAAmF;EACjF,IAAI,KAAK;EACT,IAAI,KAAK;EACT,IAAI,KAAK;CACX;CACA,aAAqD;EAAC;EAAG;EAAG;CAAC;CAC7D,cAAc;CACd,iBAAiB,OAAO;CACxB;CACA,WAAW;CACX,eAA+B,CAAC;CAChC,UAAU;CACV,cAAc;CACd,UAAU;CAEV,WAAW;CACX;CAEA,4BAAqB,IAAI,IAAgB;CACzC,YAAY;CACZ,QAAQ;CACR,UAAU;CACV,WAAW;CACX,WAAW;CAEX,YAAY,SAA+B;EACzC,MAAM,QAAQ,QAAQ,SAAS,CAAC;EAChC,KAAK,aAAa,QAAQ;EAC1B,KAAK,QAAQ,IAAI,YAAY,QAAQ,SAAS;EAC9C,KAAK,SAAS,IAAI,cAAc,QAAQ,SAAS;EAGjD,MAAM,SAAS,QAAQ,UAAU;EACjC,KAAK,oBAAoB,KAAK,oBAAoB,QAAQ,kBAAkB,MAAM;EAClF,KAAK,kBAAkB,KAAK,kBAAkB,QAAQ,gBAAgB,MAAM;EAC5E,MAAM,aAAa,QAAQ,cAAc,SAAS;EAClD,IACE,EACE,eAAe,OAAO,qBACrB,OAAO,UAAU,UAAU,KAAK,cAAc,IAGjD,MAAM,IAAI,WACR,2DAA2D,WAAW,EACxE;EAEF,KAAK,cAAc;EACnB,MAAM,cAAc,MAAM,eAAe,SAAS;EAClD,IAAI,EAAE,OAAO,UAAU,WAAW,KAAK,eAAe,IACpD,MAAM,IAAI,WAAW,sDAAsD,YAAY,EAAE;EAE3F,KAAK,eAAe;EACpB,KAAK,eAAe,YAAY,qBAAqB,MAAM,eAAe,SAAS,WAAW;EAC9F,KAAK,cAAc,YAAY,oBAAoB,MAAM,cAAc,SAAS,UAAU;EAC1F,KAAK,eAAe,MAAM,eAAe;EACzC,KAAK,YAAY,gBAAgB,QAAQ,UAAU,QAAQ,SAAS;EACpE,KAAK,iBAAiB,QAAQ;EAC9B,MAAM,aAAa,QAAQ,cAAc,SAAS;EAClD,IAAI,EAAE,cAAc,IAClB,MAAM,IAAI,WAAW,mDAAmD,WAAW,EAAE;EAEvF,KAAK,cAAc;EACnB,MAAM,gBAAgB,QAAQ,iBAAiB,SAAS;EACxD,IAAI,EAAE,gBAAgB,IACpB,MAAM,IAAI,WAAW,qDAAqD,cAAc,EAAE;EAE5F,KAAK,iBAAiB;EACtB,KAAK,SAAS,QAAQ,gBAAgB,YAAY,IAAI;EACtD,KAAK,UAAU,QAAQ,UAAU,KAAK;CACxC;;;;;;CAOA,KACE,QACA,OACA,SACqB;EACrB,IAAI;EACJ,IAAI,YAAY,KAAA,GAAW;GACzB,MAAM,EAAE,UAAU,WAAW,GAAG,SAAS;GACzC,cAAc;EAChB;EACA,IAAI;EACJ,IAAI;GACF,MAAM,UAAU,UAAU,KAAK;GAC/B,QACE,QAAQ,SAAS,UACb,KAAK,OACF,MAAM,SAAS,WAAW,CAAC,CAC3B,SAAS,SAAS,KAAK,MAAM,MAAM,KAAK,SAAS,KAAK,OAAO,CAAC,IACjE,KAAK,MAAM,MAAM,SAAS,WAAW;EAC7C,SAAS,OAAO;GACd,OAAO,QAAQ,OAAO,KAAK;EAC7B;EACA,MAAM,CAAC,MAAM,GAAG,QAAQ,MAAM,KAC3B,EAAE,SAAS,SAAS,mBAA4B;GAC/C,WAAW,KAAK,WAAW,KAAK,QAAQ,SAAS,WAAW;GAC5D;EACF,EACF;EACA,OAAO,KAAK,MAAM,QAAQ,SAAS,UAAU;GAC3C,GAAI;GACJ;GACA,MAAM,cAAc;GAGpB,aAAa;IACX,KAAK,MAAM,QAAQ,OAAO,cAAc,KAAK,YAAY,KAAK,SAAS,KAAK,OAAO;GACrF;EACF,CAAC;CACH;;;;;;CAOA,QAAW,QAAgB,QAA0B,SAAqC;EACxF,OAAO,KAAK,MAAM,QAAQ,SAAS,UAAU;GAC3C,KAAK;GACL,SAAS;GACT,MAAM,CAAC;GACP,MAAM,WAAW;EACnB,CAAC;CACH;CAEA,MACE,QACA,WACA,MACkB;EAClB,IAAI,KAAK,SAAS;GAChB,KAAK;GACL,OAAO,QAAQ,OACb,IAAI,mBAAmB,UAAU,0BAA0B,KAAK,KAAK,UAAU,CACjF;EACF;EACA,IAAI,KAAK,UAAU;GACjB,KAAK;GACL,OAAO,QAAQ,OACb,IAAI,mBACF,gBACA,4BAA4B,KAAK,YAAY,OAAO,KAAK,KAAK,UAChE,CACF;EACF;EACA,MAAM,WAAW,eAAe,IAAI,aAAa,QAAQ;EACzD,IAAI,aAAa,KAAA,GACf,OAAO,QAAQ,uBAAO,IAAI,UAAU,wBAAwB,OAAO,SAAS,GAAG,CAAC;EAElF,IAAI;GACF,KAAK,QAAQ;EACf,SAAS,OAAO;GACd,OAAO,QAAQ,OAAO,KAAK;EAC7B;EAEA,IAAI,KAAK,WAAW,aAAa,KAAK,aAAa;GACjD,KAAK;GACL,OAAO,QAAQ,OACb,IAAI,mBACF,QACA,wBAAwB,KAAK,YAAY,6BAA6B,aAAa,SAAS,KAAK,KAAK,KAAK,UAC7G,CACF;EACF;EAEA,OAAO,IAAI,SAAkB,SAAS,WAAW;GAC/C,MAAM,MAAW;IACf,KAAK,KAAK;IACV,SAAS,KAAK;IACd,MAAM,KAAK;IACX,MAAM,KAAK;IACX;IACA,UAAU;IACV;IACA;GACF;GACA,MAAM,OAAO,KAAK,SAAS,MAAM;GACjC,KAAK,KAAK,SAAS,CAAC,KAAK,GAAG;GAC5B,KAAK;GACL,KAAK,WAAW,SAAS;GACzB,KAAK,MAAM,MAAM,KAAK,OAAO,CAAC;GAC9B,KAAK,MAAM;EACb,CAAC;CACH;CAEA,QAA4B;EAC1B,OAAO;GACL,SAAS;IACP,MAAM,KAAK,WAAW;IACtB,QAAQ,KAAK,WAAW;IACxB,KAAK,KAAK,WAAW;GACvB;GACA,UAAU,KAAK;GACf,aAAa,KAAK,OAAO;GACzB,MAAM,KAAK;GACX,QAAQ,KAAK;GACb,SAAS,KAAK;GACd,SAAS,KAAK;GACd,QAAQ,KAAK;EACf;CACF;CAEA,IAAI,SAAkB;EACpB,OAAO,KAAK;CACd;CAEA,IAAI,SAAkB;EACpB,OAAO,KAAK;CACd;;;;;CAMA,QAAc;EACZ,IAAI,KAAK,SAAS;EAClB,KAAK,UAAU;EACf,IAAI,KAAK,gBAAgB,OAAO,mBAAmB;EACnD,KAAK,cAAc,iBAAiB;GAClC,KAAK,cAAc,KAAA;GACnB,KAAK,WAAW;GAChB,KAAK,qBAED,IAAI,mBACF,gBACA,4BAA4B,KAAK,YAAY,sBAC/C,CACJ;EACF,GAAG,KAAK,WAAW;CACrB;;CAGA,SAAe;EACb,IAAI,CAAC,KAAK,SAAS;EACnB,KAAK,UAAU;EACf,KAAK,WAAW;EAChB,aAAa,KAAK,WAAW;EAC7B,KAAK,cAAc,KAAA;EACnB,KAAK,MAAM;CACb;;CAGA,SAAwB;EACtB,IAAI,KAAK,OAAO,SAAS,GAAG,OAAO,QAAQ,QAAQ;EACnD,OAAO,IAAI,SAAS,YAAY,KAAK,aAAa,KAAK,OAAO,CAAC;CACjE;;;;;CAMA,MAAM,UAAgC,CAAC,GAAkB;EACvD,KAAK,UAAU;EACf,IAAI,QAAQ,UAAU,OAAO,KAAK,SAAS;EAC3C,OAAO,KAAK,OAAO;CACrB;CAEA,SAAS,QAA2B;EAClC,MAAM,WAAW,KAAK,OAAO,IAAI,MAAM;EACvC,IAAI,aAAa,KAAA,GAAW,OAAO;EACnC,MAAM,OAAkB;GACtB,IAAI;GACJ,MAAM;IAAC,IAAI,KAAK;IAAG,IAAI,KAAK;IAAG,IAAI,KAAK;GAAC;GACzC,MAAM;GACN,SAAS;GACT,MAAM;GACN,SAAS,KAAK,WAAW,IAAI,MAAM,KAAK,OAAO;GAC/C,QAAQ;GACR,gBAAgB;GAChB,OAAO,KAAA;EACT;EACA,KAAK,OAAO,IAAI,QAAQ,IAAI;EAC5B,OAAO;CACT;;CAGA,MAAM,MAAiB,KAAmB;EACxC,IAAI,KAAK,QAAQ,KAAK,YAAY,GAAG;EACrC,IAAI,MAAM,KAAK,SAAS;GACtB,KAAK,UAAU,iBAAiB;IAC9B,KAAK,QAAQ,KAAA;IACb,KAAK,MAAM,MAAM,KAAK,OAAO,CAAC;IAC9B,KAAK,MAAM;GACb,GAAG,KAAK,UAAU,GAAG;GACrB;EACF;EACA,MAAM,WAAW,KAAK,SAAS,OAAO,KAAK,KAAK,WAAW,cAAc,KAAK,IAAI;EAClF,IAAI,aAAa,MAAO,KAAK,WAAW,KAAK,KAAK,mBAAmB,UAAW;EAEhF,KAAK,SAAS,KAAK;EACnB,KAAK,iBAAiB;EACtB,KAAK,OAAO,SAAS,CAAC,KAAK;GAAE;GAAM,QAAQ,KAAK;EAAO,CAAC;CAC1D;CAEA,QAAc;EACZ,IAAI,KAAK,YAAY,KAAK,SAAS;EACnC,KAAK,WAAW;EAChB,IAAI;GACF,SAAS;IACP,MAAM,OAAO,KAAK,WAAW;IAC7B,IAAI,SAAS,KAAA,GAAW;IACxB,MAAM,MAAM,KAAK,OAAO;IACxB,IAAI,MAAM,KAAK,gBAAgB;KAC7B,KAAK,iBAAiB,iBAAiB;MACrC,KAAK,eAAe,KAAA;MACpB,KAAK,MAAM;KACb,GAAG,KAAK,iBAAiB,GAAG;KAC5B;IACF;IACA,MAAM,QAAQ,KAAK,MAAM;IACzB,IAAI,UAAU,KAAA,GAAW,KAAK,UAAU,MAAM,MAAM,GAAG;GACzD;EACF,UAAU;GACR,KAAK,WAAW;EAClB;CACF;;CAGA,aAA2C;EACzC,KAAK,MAAM,QAAQ,KAAK,QACtB,KAAK,IAAI,QAAQ,KAAK,KAAK,GAAG,UAAU,KAAA,GAAW,QAAQ,KAAK,KAAK,GAAG;GACtE,IAAI,MAAM,WAAW,MAAM,KAAK,QAAQ,OAAO;GAC/C,KAAK,MAAM;EACb;CAGJ;CAEA,UAAU,MAAiB,KAAmB;EAC5C,IAAI,MAAM,KAAK;EACf,IAAI,QAAQ,MACV,KAAK,OAAO;OACP;GACL,MAAM,WAAW,cAAc,KAAK,IAAI;GACxC,MAAM,aAAa,KAAK,OAAQ,KAAK,KAAK,SAAS,CAAC,MAAM,KAAK;GAE/D,IAAI,QAAQ,MAAM;EACpB;EACA,KAAK,SAAS;EACd,KAAK,OAAO;EACZ,KAAK;EACL,KAAK,WAAW,IAAI,SAAS;EAC7B,KAAK;EACL,KAAK,iBAAiB,MAAM,KAAK;EACjC,KAAK,UAAU,MAAM,KAAK;EAC1B,KAAK,kBAAkB,KAAK,IAAI,KAAK,SAAS,GAAG;EACjD,KAAU,SAAS,MAAM,GAAG;CAC9B;CAEA,kBAAkB,QAAgB,SAAiB,KAAmB;EACpE,KAAK,MAAM,CAAC,IAAI,UAAU,KAAK,YAAY;GACzC,IAAI,QAAQ,KAAK;GACjB,KAAK,WAAW,OAAO,EAAE;EAC3B;EACA,KAAK,WAAW,OAAO,MAAM;EAC7B,KAAK,WAAW,IAAI,QAAQ,OAAO;CACrC;CAEA,MAAM,SAAS,MAAiB,KAAyB;EACvD,IAAI;EACJ,IAAI;GACF,IAAI,KAAK,cAAc,QAAQ,IAAI,YAAY,MAC7C,MAAM,KAAK,UAAU,KAAK,IAAI,IAAI,SAAS,KAAK,SAAS;GAG3D,IAAI,KAAK,aAAa;IACpB,KAAK;IACL,IAAI,OACF,IAAI,mBAAmB,UAAU,oDAAoD,CACvF;GACF,OAAO;IACL,MAAM,SAAS,MAAM,KAAK,aAAa,IAAI,IAAI,GAAG,IAAI,IAAI;IAC1D,KAAK;IACL,KAAK,QAAQ,MAAM,KAAK,MAAM;GAChC;EACF,SAAS,OAAO;GACd,KAAK,eAAe,MAAM,KAAK,KAAK;EACtC;EACA,KAAK;EACL,KAAK,OAAO;EACZ,IAAI,KAAK,YAAY,GAAG;GACtB,aAAa,KAAK,KAAK;GACvB,KAAK,OAAO,OAAO,KAAK,EAAE;GAC1B,KAAK,YAAY;EACnB,OACE,KAAK,MAAM,MAAM,KAAK,OAAO,CAAC;EAEhC,KAAK,MAAM;CACb;;CAGA,QAAQ,MAAiB,KAAU,QAAuB;EACxD,MAAM,QAAQ,IAAI,SAAS,EAAE,OAAO,OAAO;EAC3C,MAAM,CAAC,MAAM,GAAG,QAAQ,IAAI;EAC5B,IAAI,SAAS,KAAA,GAAW;GACtB,IAAI,QAAQ,MAAM,KAAK;GACvB;EACF;EACA,IAAI,KAAK,aAAa;GACpB,KAAK;GACL,IAAI,OACF,IAAI,mBAAmB,UAAU,oDAAoD,CACvF;GACA;EACF;EACA,KAAK,OAAO;GAAE,GAAG;GAAK,GAAG;GAAM;GAAM;GAAO,UAAU;EAAE;EACxD,KAAK;EACL,KAAK,WAAW,IAAI,SAAS;CAC/B;CAEA,eAAe,MAAiB,KAAU,OAAsB;EAC9D,MAAM,MAAM,KAAK,OAAO;EACxB,MAAM,OAAO,KAAK,cAAc,KAAA,IAAY,WAAW,KAAK;EAG5D,IAAI,MAAM,WAAW,MACnB,KAAK,iBAAiB,KAAK,IAAI,KAAK,gBAAgB,MAAM,KAAK,EAAE;EAEnE,IAAI;EACJ,IAAI;GAIF,YACE,CAAC,KAAK,eACN,CAAC,KAAK,YACN,EAAE,iBAAiB,uBACnB,IAAI,WAAW,KAAK,iBACnB,SAAS,KAAA,KAAa,KAAK,MAAM,KAAK,gBACvC,KAAK,aAAa,KAAK;EAC3B,SAAS,WAAW;GAClB,KAAK;GACL,IAAI,OAAO,IAAI,eAAe,CAAC,WAAW,KAAK,GAAG,0BAA0B,CAAC;GAC7E;EACF;EACA,IAAI,CAAC,WAAW;GACd,KAAK;GACL,IAAI,OAAO,KAAK;GAChB;EACF;EACA,KAAK;EACL,KAAK,OAAO;EACZ,KAAK;EACL,KAAK,WAAW,IAAI,SAAS;EAG7B,MAAM,QAAQ,SAAS,KAAA,IAAY,KAAK,SAAS,IAAI,QAAQ,IAAI,KAAK;EACtE,KAAK,UAAU,KAAK,IAAI,KAAK,SAAS,MAAM,KAAK;CACnD;;;;;CAMA,aAAgB,WAAuB,MAA0B;EAC/D,IAAI,KAAK,mBAAmB,OAAO,mBAAmB,OAAO;EAC7D,IAAI;EACJ,MAAM,UAAU,IAAI,SAAgB,UAAU,WAAW;GACvD,QAAQ,iBAAiB;IAEvB,OAAO,IAAI,mBAAmB,WAAW,GADtB,KAAK,8BAA8B,KAAK,eAAe,IAC1B,CAAC;GACnD,GAAG,KAAK,cAAc;EACxB,CAAC;EACD,OAAO,QAAQ,KAAK,CAAC,WAAW,OAAO,CAAC,CAAC,CAAC,cAAc,aAAa,KAAK,CAAC;CAC7E;;CAGA,SAAS,UAA0B;EACjC,MAAM,SAAS,KAAK,IAAI,KAAK,aAAa,KAAK,eAAe,MAAM,WAAW,EAAE;EACjF,OAAO,SAAS,IAAK,SAAS,IAAK,KAAK,QAAQ;CAClD;CAEA,MAAM,UACJ,QACA,SACA,UACe;EACf,IAAI;EACJ,IAAI;EACJ,IAAI,QAAQ,SAAS,QAAQ;GAC3B,OAAO;GACP,KAAK,KAAK,IACR,SAAS,OACT,KAAK,IAAI,SAAS,OAAO,QAAQ,KAAK,SAAS,SAAS,SAAS,CACnE;EACF,OAAO,IAAI,QAAQ,SAAS,SAAS;GACnC,OAAO;GACP,KAAK,SAAS;EAChB,OACE;EAEF,IAAI;GACF,MAAM,KAAK,aAAa,KAAK,WAAW,WAAW,QAAQ,IAAI,GAAG,kBAAkB,QAAQ;EAC9F,SAAS,OAAO;GAEd,KAAK,iBAAiB,OAAO,MAAM;GACnC;EACF;EACA,IAAI,KAAK,KAAK,CAAC,KAAK,aAAa,MAAM,KAAK,OAAO,EAAE;CACvD;;CAGA,OAAO,IAA2B;EAChC,OAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,aAAmB;IACvB,aAAa,KAAK;IAClB,KAAK,UAAU,OAAO,IAAI;IAC1B,QAAQ;GACV;GACA,MAAM,QAAQ,WAAW,MAAM,EAAE;GACjC,KAAK,UAAU,IAAI,IAAI;EACzB,CAAC;CACH;CAEA,WAAiB;EACf,KAAK,cAAc;EACnB,aAAa,KAAK,WAAW;EAC7B,KAAK,cAAc,KAAA;EACnB,KAAK,MAAM,QAAQ,KAAK,WAAW,KAAK;EACxC,KAAK,qBACG,IAAI,mBAAmB,UAAU,oDAAoD,CAC7F;CACF;;CAGA,eAAe,OAAuC;EACpD,KAAK,MAAM,QAAQ,KAAK,OAAO,OAAO,GAAG;GACvC,MAAM,UAAiB,KAAK,SAAS,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI;GAC3D,KAAK,MAAM,QAAQ,KAAK,MACtB,KAAK,IAAI,MAAM,KAAK,MAAM,GAAG,QAAQ,KAAA,GAAW,MAAM,KAAK,MAAM,GAAG,QAAQ,KAAK,GAAG;GAEtF,KAAK,MAAM,OAAO,SAAS;IACzB,KAAK;IACL,IAAI,OAAO,MAAM,CAAC;GACpB;GACA,KAAK,OAAO;GACZ,KAAK,UAAU;GACf,KAAK,SAAS;GACd,aAAa,KAAK,KAAK;GACvB,KAAK,QAAQ,KAAA;GACb,IAAI,CAAC,KAAK,MAAM,KAAK,OAAO,OAAO,KAAK,EAAE;EAC5C;EACA,KAAK,WAAW,KAAK;EACrB,KAAK,WAAW,KAAK;EACrB,KAAK,WAAW,KAAK;EACrB,KAAK,MAAM,QAAQ,KAAK,QAAQ,KAAK,MAAM;EAC3C,aAAa,KAAK,YAAY;EAC9B,KAAK,eAAe,KAAA;EACpB,KAAK,YAAY;CACnB;CAEA,cAAoB;EAClB,IAAI,KAAK,OAAO,OAAO,KAAK,KAAK,aAAa,WAAW,GAAG;EAC5D,MAAM,UAAU,KAAK;EACrB,KAAK,eAAe,CAAC;EACrB,KAAK,MAAM,WAAW,SAAS,QAAQ;CACzC;AACF;AAEA,SAAS,cAAc,MAA6C;CAClE,IAAI,KAAK,EAAE,CAAC,OAAO,GAAG,OAAO;CAC7B,IAAI,KAAK,EAAE,CAAC,OAAO,GAAG,OAAO;CAC7B,OAAO,KAAK,EAAE,CAAC,OAAO,IAAI,IAAI;AAChC;AAEA,SAAS,YAAY,MAAc,OAAuB;CACxD,IAAI,EAAE,OAAO,SAAS,KAAK,KAAK,SAAS,IACvC,MAAM,IAAI,WAAW,GAAG,KAAK,6CAA6C,MAAM,EAAE;CAEpF,OAAO;AACT;AAEA,SAAS,KACP,MACA,YACA,QACQ;CACR,IAAI,eAAe,KAAA,GAAW,OAAO,YAAY,MAAM,UAAU;CACjE,MAAM,gBAAgB,SAAS;CAC/B,IAAI,kBAAkB,KAAA,GAAW,OAAO,YAAY,oBAAoB,QAAQ,aAAa;CAC7F,OAAO,SAAS;AAClB;;;;;;AAOA,SAAS,WAAW,OAA+E;CACjG,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,kBAAkB,QAAQ,OAAO,KAAA;CACtF,MAAM,KAAK,MAAM;CACjB,IAAI,OAAO,OAAO,YAAY,EAAE,OAAO,SAAS,EAAE,KAAK,MAAM,IAAI,OAAO,KAAA;CACxE,OAAO;EAAE;EAAI,QAAQ,qBAAqB,SAAS,MAAM,oBAAoB;CAAS;AACxF;AAEA,SAAS,YAAY,OAAyB;CAC5C,IAAI,iBAAiB,kBAAkB,OAAO;CAC9C,OAAO,EACL,OAAO,UAAU,YACjB,UAAU,QACV,eAAe,SACf,MAAM,cAAc;AAExB;AAEA,SAAS,gBACP,QACA,WACkC;CAElC,IAAI,WAAW,KAAA,KAAa,WAAW,SAAS,CAAC,cAAc,WAAW,QAAQ,GAChF,OAAO;CAET,MAAM,SAAS,WAAW,OAAO,CAAC,IAAI;CACtC,OAAO;EACL,WAAW,YAAY,sBAAsB,OAAO,aAAa,SAAS,SAAS;EACnF,OAAO,YAAY,kBAAkB,OAAO,SAAS,SAAS,KAAK;EACnE,OAAO,YAAY,kBAAkB,OAAO,SAAS,SAAS,KAAK;CACrE;AACF;;;AC/3BA,MAAM,QAAgD;CACpD,SAAS;CACT,kBAAkB;CAClB,mBAAmB;CACnB,UAAU;CACV,aAAa;CACb,gBAAgB;CAChB,cAAc;CACd,sBAAsB;CACtB,iBAAiB;CACjB,mBAAmB;CACnB,qBAAqB;CACrB,iBAAiB;CACjB,2BAA2B;CAC3B,gBAAgB;CAChB,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CACjB,mBAAmB;CACnB,oBAAoB;CACpB,oBAAoB;CACpB,mBAAmB;CACnB,gBAAgB;CAChB,mBAAmB;CACnB,SAAS;CACT,gBAAgB;AAClB;;;;;AAMA,SAAgB,eAAe,OAAsC;CACnE,OAAO,OAAO,OAAO,OAAO,KAAK;AACnC;;;AClBA,MAAM,SAAS;AACf,MAAM,aAAa;AACnB,MAAM,aAAa,GAAG,WAAW,QAAQ,WAAW;AACpD,MAAM,UAAU,IAAI,OAClB,KAAK,OAAO,OAAO,OAAO,OAAO,OAAO,QAAQ,WAAW,WAAW,WAAW,IACnF;AACA,MAAM,OAAO,GAAG,OAAO;AACvB,MAAM,UAAU,IAAI,OAClB,yBAAyB,KAAK,UAAU,KAAK,UAAU,KAAK,QAAQ,WAAW,WAAW,WAAW,QACvG;AAEA,SAAS,gBAAgB,KAA8C;CACrE,IAAI,QAAQ,KAAA,GAAW,OAAO,CAAC;CAC/B,OAAO,IAAI,MAAM,GAAG,CAAC,CAAC,KAAK,OAAQ,QAAQ,KAAK,EAAE,IAAI,OAAO,EAAE,IAAI,EAAG;AACxE;;AAGA,SAAgB,aAAa,OAAmC;CAC9D,MAAM,QAAQ,QAAQ,KAAK,MAAM,KAAK,CAAC;CACvC,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,OAAO;EACL,OAAO,OAAO,MAAM,EAAE;EACtB,OAAO,OAAO,MAAM,EAAE;EACtB,OAAO,OAAO,MAAM,EAAE;EACtB,YAAY,gBAAgB,MAAM,EAAE;CACtC;AACF;AAEA,SAAS,mBAAmB,GAAoB,GAA4B;CAC1E,IAAI,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU,OAAO,IAAI;CAE/D,IAAI,OAAO,MAAM,UAAU,OAAO;CAClC,IAAI,OAAO,MAAM,UAAU,OAAO;CAClC,OAAO,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI;AAClC;;AAGA,SAAgB,gBAAgB,GAAW,GAAmB;CAC5D,MAAM,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE;CACnE,IAAI,SAAS,GAAG,OAAO;CAEvB,IAAI,EAAE,WAAW,WAAW,KAAK,EAAE,WAAW,WAAW,GACvD,OAAO,EAAE,WAAW,SAAS,EAAE,WAAW;CAE5C,MAAM,SAAS,KAAK,IAAI,EAAE,WAAW,QAAQ,EAAE,WAAW,MAAM;CAChE,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK;EAC/B,MAAM,IAAI,EAAE,WAAW;EACvB,MAAM,IAAI,EAAE,WAAW;EACvB,IAAI,MAAM,KAAA,GAAW,OAAO;EAC5B,IAAI,MAAM,KAAA,GAAW,OAAO;EAC5B,MAAM,OAAO,mBAAmB,GAAG,CAAC;EACpC,IAAI,SAAS,GAAG,OAAO;CACzB;CACA,OAAO;AACT;AAEA,MAAM,WACJ,OACA,OACA,OACA,aAAkC,CAAC,OACvB;CAAE;CAAO;CAAO;CAAO;AAAW;AAEhD,MAAM,cAAc,UAAoB,OAA2B;CAAE;CAAU,SAAS;AAAE;AAG1F,MAAM,UAAwB,CAAC,WAAW,KAAK,QAAQ,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAErE,SAAS,UAAU,KAA6C;CAC9D,IAAI,QAAQ,KAAA,KAAa,QAAQ,OAAO,QAAQ,OAAO,QAAQ,KAAK,OAAO,KAAA;CAC3E,OAAO,OAAO,GAAG;AACnB;;AAGA,SAAS,QAAQ,MAAwC;CACvD,MAAM,QAAQ,QAAQ,KAAK,IAAI;CAC/B,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,MAAM,WAAW,MAAM,MAAM;CAC7B,MAAM,QAAQ,UAAU,MAAM,EAAE;CAChC,MAAM,QAAQ,UAAU,MAAM,EAAE;CAChC,MAAM,QAAQ,UAAU,MAAM,EAAE;CAEhC,IACG,UAAU,KAAA,KAAa,MAAM,OAAO,KAAA,KACpC,UAAU,KAAA,KAAa,MAAM,OAAO,KAAA,GAErC;CAEF,MAAM,MAAM,gBAAgB,MAAM,EAAE;CACpC,IAAI,UAAU,KAAA,GAAW,OAAO,aAAa,OAAO,aAAa,MAAM,UAAU,CAAC;CAClF,MAAM,MAAM,QAAQ,OAAO,SAAS,GAAG,SAAS,GAAG,GAAG;CAEtD,QAAQ,UAAR;EACE,KAAK;GACH,IAAI,UAAU,KAAA,GACZ,OAAO,CAAC,WAAW,MAAM,GAAG,GAAG,WAAW,KAAK,QAAQ,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC;GAC1E,IAAI,UAAU,KAAA,GACZ,OAAO,CAAC,WAAW,MAAM,GAAG,GAAG,WAAW,KAAK,QAAQ,OAAO,QAAQ,GAAG,CAAC,CAAC,CAAC;GAE9E,OAAO,CAAC,WAAW,KAAK,GAAG,CAAC;EAC9B,KAAK,KAAK;GACR,IAAI;GACJ,IAAI,QAAQ,KAAK,UAAU,KAAA,GAAW,OAAO,QAAQ,QAAQ,GAAG,GAAG,CAAC;QAC/D,IAAI,QAAQ,KAAK,UAAU,KAAA,GAAW,OAAO,QAAQ,GAAG,QAAQ,GAAG,CAAC;QACpE,OAAO,QAAQ,GAAG,GAAG,QAAQ,CAAC;GACnC,OAAO,CAAC,WAAW,MAAM,GAAG,GAAG,WAAW,KAAK,IAAI,CAAC;EACtD;EACA,KAAK,KAAK;GACR,MAAM,OAAO,UAAU,KAAA,IAAY,QAAQ,QAAQ,GAAG,GAAG,CAAC,IAAI,QAAQ,OAAO,QAAQ,GAAG,CAAC;GACzF,OAAO,CAAC,WAAW,MAAM,GAAG,GAAG,WAAW,KAAK,IAAI,CAAC;EACtD;EACA,KAAK;GACH,IAAI,UAAU,KAAA,GAAW,OAAO,CAAC,WAAW,MAAM,QAAQ,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC;GAC3E,IAAI,UAAU,KAAA,GAAW,OAAO,CAAC,WAAW,MAAM,QAAQ,OAAO,QAAQ,GAAG,CAAC,CAAC,CAAC;GAC/E,OAAO,CAAC,WAAW,KAAK,GAAG,CAAC;EAC9B,KAAK;GACH,IAAI,UAAU,KAAA,GAAW,OAAO,CAAC,WAAW,KAAK,QAAQ,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC;GAC1E,IAAI,UAAU,KAAA,GAAW,OAAO,CAAC,WAAW,KAAK,QAAQ,OAAO,QAAQ,GAAG,CAAC,CAAC,CAAC;GAC9E,OAAO,CAAC,WAAW,MAAM,GAAG,CAAC;EAC/B,SAEE,OAAO,CAAC,WAAW,UAAsB,GAAG,CAAC;CACjD;AACF;;AAGA,SAAS,WAAW,OAA2C;CAC7D,MAAM,OAAuB,CAAC;CAC9B,KAAK,MAAM,OAAO,MAAM,MAAM,IAAI,GAAG;EAEnC,MAAM,QAAQ,IACX,KAAK,CAAC,CACN,QAAQ,0BAA0B,IAAI,CAAC,CACvC,MAAM,KAAK,CAAC,CACZ,QAAQ,SAAS,KAAK,SAAS,CAAC;EACnC,MAAM,MAAoB,CAAC;EAC3B,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,cAAc,QAAQ,IAAI;GAChC,IAAI,CAAC,aAAa,OAAO,KAAA;GACzB,IAAI,KAAK,GAAG,WAAW;EACzB;EACA,KAAK,KAAK,GAAG;CACf;CACA,OAAO;AACT;;AAGA,SAAgB,aAAa,OAAwB;CACnD,OAAO,WAAW,KAAK,MAAM,KAAA;AAC/B;AAEA,SAAS,KAAK,GAAW,EAAE,UAAU,SAAS,SAA8B;CAC1E,MAAM,OAAO,gBAAgB,GAAG,KAAK;CACrC,QAAQ,UAAR;EACE,KAAK,KACH,OAAO,OAAO;EAChB,KAAK,MACH,OAAO,QAAQ;EACjB,KAAK,KACH,OAAO,OAAO;EAChB,KAAK,MACH,OAAO,QAAQ;EACjB,SACE,OAAO,SAAS;CACpB;AACF;;;;;;;;AASA,SAAgB,UAAU,aAAqB,OAAwB;CACrE,MAAM,IAAI,aAAa,WAAW;CAClC,IAAI,CAAC,GAAG,MAAM,IAAI,WAAW,4BAA4B,YAAY,EAAE;CACvE,MAAM,OAAO,WAAW,KAAK;CAC7B,IAAI,CAAC,MAAM,MAAM,IAAI,WAAW,2BAA2B,MAAM,EAAE;CACnE,OAAO,KAAK,MAAM,QAAQ;EACxB,IAAI,CAAC,IAAI,OAAO,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,OAAO;EAC1C,IAAI,EAAE,WAAW,WAAW,GAAG,OAAO;EACtC,OAAO,IAAI,MACR,EAAE,SAAS,QACV,EAAE,WAAW,SAAS,KACtB,EAAE,UAAU,EAAE,SACd,EAAE,UAAU,EAAE,SACd,EAAE,UAAU,EAAE,KAClB;CACF,CAAC;AACH;;;;;;;ACxMA,MAAa,sBAA8B;AAC3C,MAAM,kBAAkB;;AAGxB,IAAa,sBAAb,cAAyC,MAAM;CAC7C,OAAyB;;CAEzB;;CAEA;CACA;CAEA,YAAY,QAA4B,QAA2B,QAAiB;EAClF,MAAM,MAAM,WAAW,KAAA,IAAY,oBAAoB,WAAW,OAAO;EACzE,MAAM,QAAQ,WAAW,KAAA,IAAY,KAAK,KAAK,OAAO;EACtD,MAAM,yBAAyB,MAAM,MAAM,OAAO,OAAO,KAAK,MAAM,GAAG;EACvE,KAAK,SAAS;EACd,KAAK,SAAS;EACd,KAAK,SAAS;CAChB;AACF;AAEA,MAAM,YAAY,UAChB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAErE,SAAS,UAAU,OAAgB,OAAe,QAAwB;CACxE,IAAI,OAAO,UAAU,YAAY,CAAC,oBAAoB,KAAK,KAAK,GAC9D,OAAO,KACL,GAAG,MAAM,+DAA+D,KAAK,KAAK,GACpF;MACK,IAAI,MAAM,SAAS,iBACxB,OAAO,KAAK,GAAG,MAAM,YAAY,gBAAgB,YAAY;AAEjE;AAEA,MAAM,QAAQ,UACZ,OAAO,UAAU,WAAW,IAAI,MAAM,KAAK,UAAU,KAAA,IAAY,SAAS,OAAO;AAEnF,SAAS,WAAW,OAAgB,OAAe,MAAe,QAAwB;CACxF,IAAI,UAAU,KAAA,GAAW;CACzB,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;EACzB,OAAO,KAAK,GAAG,MAAM,uCAAuC;EAC5D;CACF;CACA,KAAK,MAAM,QAAQ,OAAO;EACxB,UAAU,MAAM,GAAG,MAAM,SAAS,MAAM;EACxC,IAAI,SAAS,MAAM,OAAO,KAAK,GAAG,MAAM,iCAAiC;CAC3E;AACF;;;;;AAMA,SAAS,cAAc,OAAgB,QAAwB;CAC7D,IAAI,UAAU,KAAA,GAAW;CACzB,IAAI,CAAC,SAAS,KAAK,GAAG;EACpB,OAAO,KAAK,4CAA4C;EACxD;CACF;CACA,KAAK,MAAM,CAAC,MAAM,aAAa,OAAO,QAAQ,KAAK,GAAG;EACpD,MAAM,QAAQ,aAAa,KAAK;EAChC,IAAI,CAAC,SAAS,QAAQ,GAAG;GACvB,OAAO,KAAK,GAAG,MAAM,4BAA4B;GACjD;EACF;EACA,IAAI,SAAS,YAAY,KAAA,GACvB,OAAO,KAAK,GAAG,MAAM,yCAAyC;EAEhE,IAAI,OAAO,SAAS,WAAW,YAAY,OAAO,KAAK,GAAG,MAAM,yBAAyB;EACzF,MAAM,EAAE,SAAS,aAAa,aAAa;EAC3C,IAAI,YAAY,KAAA,KAAa,EAAE,MAAM,QAAQ,OAAO,KAAK,QAAQ,MAAM,QAAQ,IAAI;GACjF,OAAO,KAAK,GAAG,MAAM,sCAAsC;GAC3D;EACF;EACA,IAAI,gBAAgB,KAAA,KAAa,OAAO,gBAAgB,UACtD,OAAO,KAAK,GAAG,MAAM,+BAA+B;EAEtD,IAAI,aAAa,KAAA,KAAa,OAAO,aAAa,YAChD,OAAO,KAAK,GAAG,MAAM,4CAA4C;EAEnE,IAAI;GACF,wBAAwB;IAAE,GAAG;IAAU;GAAK,CAAiC;EAC/E,SAAS,OAAO;GACd,OAAO,KAAK,GAAG,MAAM,IAAK,MAAgB,SAAS;EACrD;CACF;AACF;AAEA,SAAS,eAAe,OAAgB,QAAwB;CAC9D,IAAI,UAAU,KAAA,GAAW;CACzB,IAAI,CAAC,SAAS,KAAK,GAAG;EACpB,OAAO,KAAK,yCAAyC;EACrD;CACF;CACA,KAAK,MAAM,CAAC,OAAO,aAAa,OAAO,QAAQ,KAAK,GAClD,IAAI,CAAC,eAAe,KAAK,GAAG,OAAO,KAAK,4BAA4B,MAAM,EAAE;MACvE,IAAI,OAAO,aAAa,YAAY,OAAO,KAAK,OAAO,MAAM,uBAAuB;AAE7F;AAEA,MAAM,YAAY,UAAoC,OAAO,UAAU;;AAGvE,SAAgB,eAAe,OAA0B;CACvD,IAAI,CAAC,SAAS,KAAK,GAAG,OAAO,CAAC,gDAAgD;CAC9E,MAAM,SAAmB,CAAC;CAC1B,MAAM,EAAE,SAAS;CACjB,UAAU,MAAM,QAAQ,MAAM;CAE9B,IAAI,OAAO,MAAM,eAAe,YAAY,CAAC,aAAa,MAAM,UAAU,GACxE,OAAO,KAAK,oDAAoD,KAAK,MAAM,UAAU,GAAG;CAE1F,IAAI,OAAO,MAAM,cAAc,YAAY,CAAC,aAAa,MAAM,SAAS,GACtE,OAAO,KACL,sFAAsF,KAAK,MAAM,SAAS,GAC5G;CAGF,MAAM,WAAW,MAAM;CACvB,IAAI,aAAa,KAAA,GAAW;EAC1B,IAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG,OAAO,KAAK,6CAA6C;OAErF,KAAK,MAAM,cAAc,UACvB,IAAI,OAAO,eAAe,YAAY,CAAC,aAAa,UAAU,GAC5D,OAAO,KAAK,qCAAqC,KAAK,UAAU,GAAG;CAI3E;CAEA,MAAM,aAAa,MAAM;CACzB,IAAI,eAAe,KAAA,GAEf;MAAA,CAAC,MAAM,QAAQ,UAAU,KACzB,WAAW,WAAW,KACtB,CAAC,WAAW,OAAO,MAAM,OAAO,MAAM,YAAY,EAAE,SAAS,CAAC,GAE9D,OAAO,KAAK,6EAA6E;CAAA;CAI7F,MAAM,YAAY,MAAM;CACxB,IAAI,cAAc,KAAA,GAAW;EAC3B,IAAI,CAAC,SAAS,SAAS,GAAG,OAAO,KAAK,kDAAkD;OAEtF,KAAK,MAAM,CAAC,YAAY,UAAU,OAAO,QAAQ,SAAS,GAAG;GAC3D,UAAU,YAAY,mBAAmB,MAAM;GAC/C,IAAI,eAAe,MAAM,OAAO,KAAK,2CAA2C;GAChF,IAAI,OAAO,UAAU,YAAY,CAAC,aAAa,KAAK,GAClD,OAAO,KACL,cAAc,WAAW,yCAAyC,KAAK,KAAK,GAC9E;EAEJ;CAEJ;CAEA,WAAW,MAAM,UAAU,SAAS,MAAM,MAAM;CAEhD,MAAM,WAAW,MAAM;CACvB,IAAI,aAAa,KAAA,MAAc,OAAO,aAAa,YAAY,CAAC,OAAO,SAAS,QAAQ,IACtF,OAAO,KAAK,oCAAoC;CAGlD,MAAM,SAAS,MAAM;CACrB,IAAI,WAAW,KAAA,KAAa,EAAE,SAAS,MAAM,KAAK,OAAO,OAAO,iBAAiB,aAC/E,OAAO,KAAK,+BAA+B;CAG7C,MAAM,WAAW,MAAM;CACvB,IACE,aAAa,KAAA,KACb,EAAE,SAAS,QAAQ,KAAK,OAAO,OAAO,QAAQ,CAAC,CAAC,OAAO,SAAS,OAAO,SAAS,QAAQ,IAExF,OAAO,KAAK,2CAA2C;CAGzD,cAAc,MAAM,aAAa,MAAM;CACvC,eAAe,MAAM,OAAO,MAAM;CAGlC,MAAM,WAAW,MAAM,gBAAgB,KAAA,KAAa,MAAM,UAAU,KAAA;CACpE,IAAI,OAAO,MAAM,aAAa,eAAe,MAAM,aAAa,KAAA,KAAa,CAAC,WAC5E,OAAO,KAAK,6EAA6E;CAE3F,IAAI,MAAM,gBAAgB,KAAA,KAAa,OAAO,MAAM,gBAAgB,YAClE,OAAO,KAAK,4CAA4C;CAE1D,OAAO;AACT;;AAGA,SAAgB,uBACd,OACA,QACmC;CACnC,MAAM,SAAS,eAAe,KAAK;CACnC,IAAI,OAAO,WAAW,GAAG;CAEzB,MAAM,IAAI,oBADG,SAAS,KAAK,KAAK,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU,KAAA,GAChD,QAAQ,MAAM;AACpD;;;;;;AAOA,SAAgB,aAGd,YAAwF;CACxF,uBAAuB,UAAU;CACjC,OAAO;AACT;;;;;;;;;AC3NA,MAAa,eAAe;;;;ACG5B,SAAgB,gBAAgB,YAA8B,KAA0B;CACtF,KAAK,MAAM,CAAC,MAAM,aAAa,OAAO,QAAQ,WAAW,YAAY,CAAC,CAAC,GAAG;EACxE,MAAM,EAAE,KAAK,GAAG,SAAS;EACzB,IAAI,SAAS,IAAI;GAAE,GAAG;GAAM;GAAM,MAAM,MAAM,IAAI,KAAK,UAAU,GAAG,GAAG;EAAE,CAAC;CAC5E;CACA,KAAK,MAAM,CAAC,OAAO,aAAa,OAAO,QAAQ,WAAW,MAAM,CAAC,CAAC,GAG7D;EACH,MAAM,cAAsC,MAAM,SAAS,GAAG,GAAG;EACjE,IAAI,OAAO,GAAG,OAAO,UAAU;CACjC;AACF;;;;;AAMA,SAAgB,qBAAqB,YAAqD;CACxF,MAAM,WAAW,WAAW,YAAY,CAAC;CAEzC,OADoB,OAAO,KAAK,WAAW,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,KAC9C,CAAC,SAAS,SAAS,WAAW,IAAI,CAAC,GAAG,UAAU,WAAW,IAAI;AACvF;;;;ACzBA,IAAa,mBAAb,cAAsC,MAAM;CAC1C,OAAyB;;CAEzB;CAEA,YAAY,OAA0B;EACpC,MACE,wCAAwC,MAAM,KAAK,KAAK,EAAE,sEAE5D;EACA,KAAK,QAAQ;CACf;AACF;;;;;;;AAQA,SAAgB,YAAyC,SAA4B;CACnF,MAAM,QAAQ,IAAI,IAAI,QAAQ,KAAK,QAAQ,MAAM,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC;CAElE,MAAM,eAAe,QAAQ,KAAK,WAAW;EAC3C,MAAM,yBAAS,IAAI,IAAY;EAC/B,KAAK,MAAM,QAAQ,CAAC,GAAG,OAAO,KAAK,OAAO,aAAa,CAAC,CAAC,GAAG,GAAI,OAAO,SAAS,CAAC,CAAE,GAAG;GACpF,MAAM,IAAI,MAAM,IAAI,IAAI;GACxB,IAAI,MAAM,KAAA,GAAW,OAAO,IAAI,CAAC;EACnC;EACA,OAAO;CACT,CAAC;CACD,MAAM,UAAU,aAAa,KAAK,WAAW,OAAO,IAAI;CACxD,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,SAAc,CAAC;CAIrB,OAAO,OAAO,SAAS,QAAQ,QAAQ;EACrC,IAAI;EACJ,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;GACvC,IAAI,KAAK,IAAI,CAAC,KAAK,QAAQ,OAAO,GAAG;GACrC,IAAI,SAAS,KAAA,KAAa,WAAW,SAAS,CAAC,IAAI,WAAW,SAAS,IAAI,GAAG,OAAO;EACvF;EACA,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,iBAAiB,UAAU,SAAS,cAAc,IAAI,CAAC;EACzF,KAAK,IAAI,IAAI;EACb,OAAO,KAAK,QAAQ,KAAU;EAC9B,aAAa,SAAS,QAAQ,MAAM;GAClC,IAAI,OAAO,IAAI,IAAI,GAAG,QAAQ,MAAM,QAAQ,MAAM,KAAK;EACzD,CAAC;CACH;CACA,OAAO;AACT;AAEA,MAAM,cAAc,SAAuC,MACzD,QAAQ,EAAE,EAAE,YAAY;;;;;AAM1B,SAAS,UACP,SACA,cACA,MACU;CACV,MAAM,OAAiB,CAAC;CACxB,IAAI,UAAU,QAAQ,WAAW,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;CACtD,OAAO,CAAC,KAAK,SAAS,OAAO,GAAG;EAC9B,KAAK,KAAK,OAAO;EAIjB,UAHe,CAAC,GAAI,aAAa,YAAY,CAAC,CAAE,CAAC,CAC9C,QAAQ,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAC3B,MAAM,GAAG,MAAM,IAAI,CACP,CAAC,CAAC,MAAM;CACzB;CACA,MAAM,QAAQ,KAAK,MAAM,KAAK,QAAQ,OAAO,CAAC;CAC9C,MAAM,KAAK,OAAO;CAClB,OAAO,MAAM,KAAK,MAAM,QAAQ,EAAE,EAAE,QAAQ,GAAG;AACjD;;;;AC7EA,IAAa,uBAAb,cAA0C,MAAM;CAC9C,OAAyB;CACzB;CACA;;CAEA;;CAEA;CAEA,YACE,QACA,OACA,QACA,UACA,OACA;EACA,MAAM,WAAW,OAAO,KAAK,MAAM,KAAK,UAAU,EAAE,MAAM,CAAC;EAC3D,KAAK,SAAS;EACd,KAAK,QAAQ;EACb,KAAK,WAAW;EAChB,KAAK,SAAS;CAChB;AACF;;AA+BA,SAAgB,mBAAmB,QAAkC;CACnE,QAAQ,OAAO,MAAf;EACE,KAAK,YACH,OAAO;EACT,KAAK,UACH,OAAO,mCAAmC,OAAO,MAAM,iBAAiB,OAAO;EACjF,KAAK,gBACH,OAAO,oCAAoC,OAAO,QAAQ,KAAK,IAAI;EACrE,KAAK,aACH,OAAO,8BAA8B,OAAO,SAAS,KAAK,MAAM,EAAE,UAAU,OAAO;EACrF,KAAK,sBACH,OAAO,wBAAwB,OAAO;EACxC,KAAK,sBACH,OAAO,yBAAyB,OAAO;EACzC,KAAK,sBACH,OAAO,wCAAwC,OAAO,WAAW,GAAG,OAAO,QAAQ,gBAAgB,OAAO;EAC5G,KAAK,gBAAgB;GACnB,MAAM,EAAE,UAAU;GAQlB,OAAO,SAPO,MAAM,UAAU,YAAY,2BAA2B,WAO/C,IALpB,MAAM,YAAY,MAAM,UAAU,KAAA,IAC9B,MAAM,SACN,MAAM,iBAAiB,QACrB,MAAM,MAAM,UACZ,OAAO,MAAM,KAAK;EAE5B;CACF;AACF;;;;;;;;;;AAWA,SAAgB,gBAAgB,SAA+C;CAC7E,MAAM,SAAS,QAAQ,QAAQ,UAAU,MAAM,WAAW,QAAQ,CAAC,CAAC;CACpE,MAAM,SAAS,YAAY,OAAO,iBAAiB,QAAQ,SAAS,OAAO;CAC3E,MAAM,YAAY,KAAK,IAAI,GAAG,GAAG,QAAQ,KAAK,UAAU,MAAM,KAAK,MAAM,CAAC;CAC1E,MAAM,eAAe,KAAK,IAAI,GAAG,GAAG,QAAQ,KAAK,UAAU,MAAM,QAAQ,MAAM,CAAC;CAMhF,OAAO,CAAC,QAAQ,GALF,QAAQ,KAAK,UAAU;EACnC,MAAM,SACJ,MAAM,WAAW,WAAW,cAAc,aAAa,mBAAmB,MAAM,MAAM,EAAE;EAC1F,OAAO,KAAK,MAAM,KAAK,OAAO,SAAS,EAAE,IAAI,MAAM,QAAQ,OAAO,YAAY,EAAE,IAAI;CACtF,CACuB,CAAC,CAAC,CAAC,KAAK,IAAI;AACrC;;;;ACVA,IAAa,sBAAb,cAAyC,MAAM;CAC7C,OAAyB;CACzB;CACA;CAEA,YAAY,QAAgB,SAA4B;EACtD,MACE,2BAA2B,OAAO,KAAK,QAAQ,KAAK,KAAK,EAAE,6EAE7D;EACA,KAAK,SAAS;EACd,KAAK,UAAU;CACjB;AACF;;AAGA,IAAa,uBAAb,cAA0C,MAAM;CAC9C,OAAyB;AAC3B;;;;;;AAgBA,eAAe,SACb,QACA,OACA,WACA,IACA,QAC8E;CAC9E,IAAI;CACJ,IAAI;CAEJ,MAAM,UAAU,IAAI,SAAkB,YAAY;EAChD,MAAM,QAAQ,kBACZ,QAAQ;GAAE,IAAI;GAAO,OAAO,IAAI,qBAAqB,QAAQ,OAAO,SAAS,IAAI;EAAE,CAAC;EACtF,QAAQ,WAAW,KAAK,WAAW,UAAU,IAAI,GAAG,SAAS;EAC7D,UAAU,KAAK,6CAA6C;EAC5D,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;CAC3D,CAAC;CAED,MAAM,MAAM,QAAQ,QAAQ,CAAC,CAC1B,KAAK,EAAE,CAAC,CACR,MACE,WAAoB;EAAE,IAAI;EAAM;CAAM,KACtC,WAA6B;EAC5B,IAAI;EACJ,OAAO,IAAI,qBAAqB,QAAQ,OAAO,UAAU,OAAO,KAAK;CACvE,EACF;CACF,IAAI;EACF,OAAO,MAAM,QAAQ,KAAK,CAAC,KAAK,OAAO,CAAC;CAC1C,UAAU;EACR,aAAa,KAAK;EAClB,IAAI,SAAS,QAAQ,oBAAoB,SAAS,OAAO;CAC3D;AACF;AAEA,MAAM,cAAc,EAAE,YAAY,cAA2B;CAC3D,MAAM,WAAW;CACjB,SAAS,WAAW;CACpB;AACF;;AAGA,SAAgB,iBAAiB,SAAwC;CACvE,MAAM,EAAE,WAAW,eAAe,QAAQ;CAC1C,MAAM,cAAc,QAAQ,eAAA;CAC5B,IAAI,CAAC,aAAa,WAAW,GAAG,MAAM,IAAI,WAAW,0BAA0B,YAAY,EAAE;CAC7F,MAAM,iBAAiB,QAAQ,kBAAA;CAC/B,MAAM,oBAAoB,QAAQ,qBAAA;CAClC,MAAM,WAAW,IAAI,IAAI,QAAQ,mBAAmB,CAAC,CAAC;CAEtD,IAAI,QAAyB;CAC7B,IAAI,QAAgB,CAAC;CACrB,MAAM,yBAAS,IAAI,IAAkB;CACrC,IAAI;CAEJ,IAAI,QAA0B,QAAQ,QAAQ;CAE9C,SAAS,QAAW,MAAoC;EACtD,MAAM,SAAS,MAAM,KAAK,IAAI;EAE9B,QAAQ,OAAO,WACP,KAAA,SACA,KAAA,CACR;EACA,OAAO;CACT;;CAGA,SAAS,gBAAgB,YAA4D;EACnF,IAAI,SAAS,IAAI,WAAW,IAAI,GAAG,OAAO,EAAE,MAAM,WAAW;EAC7D,IAAI,CAAC,UAAU,aAAa,WAAW,MAAM,GAC3C,OAAO;GAAE,MAAM;GAAU,OAAO,WAAW;GAAQ;EAAY;EAEjE,IAAI,WAAW,cAAc,CAAC,WAAW,WAAW,SAAS,UAAU,IAAI,GACzE,OAAO;GAAE,MAAM;GAAa,UAAU,WAAW;GAAY,QAAQ,UAAU;EAAK;EAEtF,MAAM,UAAU,oBAAoB,WAAW,qBAAqB,UAAU,CAAC;EAC/E,IAAI,QAAQ,SAAS,GAAG,OAAO;GAAE,MAAM;GAAgB;EAAQ;EAC/D,KAAK,MAAM,CAAC,YAAY,UAAU,OAAO,QAAQ,WAAW,aAAa,CAAC,CAAC,GAAG;GAC5E,MAAM,OAAO,OAAO,IAAI,UAAU;GAClC,IAAI,CAAC,MAAM,OAAO;IAAE,MAAM;IAAsB;GAAW;GAC3D,MAAM,EAAE,YAAY,KAAK,MAAM;GAC/B,IAAI,CAAC,UAAU,SAAS,KAAK,GAC3B,OAAO;IAAE,MAAM;IAAsB;IAAY;IAAO;GAAQ;GAGlE,IAAI,KAAK,OAAO,WAAW,UAAU,OAAO;IAAE,MAAM;IAAsB;GAAW;EACvF;CAEF;;CAGA,eAAe,QAAQ,MAAwC;EAC7D,MAAM,EAAE,eAAe,KAAK;EAC5B,MAAM,OAAO,WAAW,KAAK,KAAK;EAClC,MAAM,UAAU,MAAM,SAAS,WAAW,MAAM,WAAW,sBACzD,cAAc,UAAU,CAC1B;EACA,IAAI,CAAC,QAAQ,IAAI,OAAO,KAAK,MAAM,QAAQ,KAAK;EAChD,MAAM,SAAS,QAAQ;EAEvB,MAAM,QAAQ,MAAM,SAAS,WAAW,MAAM,SAAS,sBAAsB;GAC3E,gBAAgB,YAAY,OAAO,OAAO;GAC1C,OAAO,WAAW,QAAQ,OAAO,OAAO;EAC1C,CAAC;EACD,IAAI,CAAC,MAAM,IAAI;GAEb,MAAM,WAAW,MAAM,SAAS,WAAW,MAAM,WAAW,yBAC1D,OAAO,QAAQ,MAAM,KAAK,CAC5B;GACA,IAAI,CAAC,SAAS,IAAI,kBAAkB,SAAS,KAAK;GAClD,OAAO,KAAK,MAAM,MAAM,KAAK;EAC/B;EACA,KAAK,SAAS;EACd,OAAO;GAAE,GAAG;GAAM,QAAQ;EAAS;CACrC;CAEA,SAAS,KACP,MACA,OACmB;EACnB,kBAAkB,KAAK;EACvB,OAAO;GAAE,GAAG;GAAM,QAAQ;GAAW,QAAQ;IAAE,MAAM;IAAgB;GAAM;EAAE;CAC/E;;CAGA,eAAe,UAAU,MAAY,QAAuD;EAC1F,MAAM,EAAE,WAAW;EACnB,IAAI,CAAC,QAAQ,OAAO,CAAC;EACrB,KAAK,SAAS,KAAA;EACd,MAAM,EAAE,eAAe,KAAK;EAC5B,MAAM,SAAiC,CAAC;EACxC,IAAI,WAAW,YAAY,QAAQ,SACjC,OAAO,KACL,IAAI,qBACF,WAAW,MACX,YACA,kDACA,IACF,CACF;OACK,IAAI,WAAW,UAAU;GAC9B,MAAM,WAAW,WAAW,SAAS,KAAK,UAAU;GACpD,MAAM,SAAS,MAAM,SACnB,WAAW,MACX,YACA,yBACM,SAAS,OAAO,OAAO,GAC7B,MACF;GACA,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,OAAO,KAAK;EAC1C;EACA,MAAM,WAAW,MAAM,SAAS,WAAW,MAAM,WAAW,yBAC1D,OAAO,QAAQ,CACjB;EACA,IAAI,CAAC,SAAS,IAAI,OAAO,KAAK,SAAS,KAAK;EAC5C,KAAK,MAAM,SAAS,QAAQ,kBAAkB,KAAK;EACnD,OAAO;CACT;CAEA,SAAS,kBAAkB,OAAmC;EAC5D,IAAI,MAAM,MAAM,SAAS;GACvB,QAAQ,MAAM;GACd,OAAO,MAAM;GACb,UAAU,MAAM;GAChB,KAAK,MAAM,SAAS;EACtB,CAAC;CACH;CAEA,SAAS,SAAS,SAAoC;EACpD,MAAM,SAAS,EACb,SAAS,QAAQ,KAAK,WAAW;GAC/B,MAAM,MAAM;GACZ,SAAS,MAAM;GACf,QAAQ,MAAM;GACd,QAAQ,MAAM;GACd,GAAI,MAAM,WAAW,YAAY,EAAE,QAAQ,mBAAmB,MAAM,MAAM,EAAE,IAAI,CAAC;EACnF,EAAE,EACJ;EAGA,IAFmB,QAAQ,MAAM,UAAU,MAAM,WAAW,SAE/C,GAAG,IAAI,KAAK,gBAAgB,OAAO,GAAG,MAAM;OACpD,IAAI,KAAK,gBAAgB,OAAO,GAAG,MAAM;CAChD;;CAGA,SAAS,OAAe;EACtB,MAAM,0BAAU,IAAI,IAAsB;EAC1C,KAAK,MAAM,EAAE,YAAY,YAAY,QAAQ,SAAS;GACpD,uBAAuB,YAAY,MAAM;GACzC,QAAQ,IAAI,WAAW,MAAM,CAAC,GAAI,QAAQ,IAAI,WAAW,IAAI,KAAK,CAAC,GAAI,MAAM,CAAC;EAChF;EACA,KAAK,MAAM,CAAC,MAAM,UAAU,SAC1B,IAAI,MAAM,SAAS,GAAG,MAAM,IAAI,oBAAoB,MAAM,KAAK;EAEjE,MAAM,QAAQ,YAAY,QAAQ,QAAQ,KAAK,UAAU,MAAM,UAAU,CAAC;EAC1E,MAAM,UAAU,IAAI,IAAI,QAAQ,QAAQ,KAAK,UAAU,CAAC,MAAM,YAAY,KAAK,CAAC,CAAC;EACjF,OAAO,MAAM,KAAK,eAAe;GAC/B,MAAM,QAAQ,QAAQ,IAAI,UAAU;GACpC,OAAO;IAAE;IAAO,QAAQ;KAAE,GAAG,WAAW,KAAK;KAAG,QAAQ;IAAS;IAAG,QAAQ,KAAA;GAAU;EACxF,CAAC;CACH;CAEA,eAAe,WAAyC;EACtD,IAAI;GACF,QAAQ,KAAK;EACf,SAAS,OAAO;GACd,QAAQ;GACR,MAAM;EACR;EACA,KAAK,MAAM,QAAQ,OAAO,OAAO,IAAI,KAAK,MAAM,WAAW,MAAM,IAAI;EACrE,KAAK,MAAM,QAAQ,UACjB,IAAI,CAAC,OAAO,IAAI,IAAI,GAClB,IAAI,KAAK,yBAAyB,KAAK,qCAAqC,EAC1E,QAAQ,KACV,CAAC;EAGL,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,SAAS,gBAAgB,KAAK,MAAM,UAAU;GACpD,KAAK,SAAS,SACV;IAAE,GAAG,WAAW,KAAK,KAAK;IAAG,QAAQ;IAAW;GAAO,IACvD,MAAM,QAAQ,IAAI;EACxB;EACA,MAAM,QAAQ,MAAM,KAAK,SAAS,KAAK,MAAM;EAC7C,SAAS,KAAK;EACd,IAAI,UAAU,YAAY,QAAQ;EAClC,OAAO;CACT;CAEA,eAAe,QAAQ,QAAuD;EAC5E,QAAQ;EACR,MAAM,SAAiC,CAAC;EAExC,KAAK,MAAM,QAAQ,MAAM,WAAW,GAAG,OAAO,KAAK,GAAI,MAAM,UAAU,MAAM,MAAM,CAAE;EACrF,QAAQ;EACR,OAAO;CACT;CAEA,eAAe,UAAU,MAA2C;EAClE,IAAI,UAAU,WACZ,MAAM,IAAI,qBAAqB,WAAW,KAAK,eAAe,MAAM,EAAE;EAExE,MAAM,OAAO,OAAO,IAAI,IAAI;EAC5B,IAAI,CAAC,MAAM,MAAM,IAAI,qBAAqB,WAAW,KAAK,wBAAwB;EAClF,MAAM,EAAE,WAAW;EACnB,IAAI,OAAO,WAAW,aAAa,OAAO,OAAO,SAAS,gBACxD,MAAM,IAAI,qBACR,WAAW,KAAK,uBAAuB,mBAAmB,OAAO,MAAM,EAAE,sDAE3E;EAIF,MAAM,WAAW,eAAe,IAAI;EACpC,MAAM,SAAiC,CAAC;EACxC,KAAK,MAAM,QAAQ,SAAS,WAAW,GAAG,OAAO,KAAK,GAAI,MAAM,UAAU,IAAI,CAAE;EAChF,KAAK,MAAM,QAAQ,UAAU;GAG3B,MAAM,SAAS,SAAS,OAAO,KAAA,IAAY,gBAAgB,KAAK,MAAM,UAAU;GAChF,KAAK,SAAS,SACV;IAAE,GAAG,WAAW,KAAK,KAAK;IAAG,QAAQ;IAAW;GAAO,IACvD,MAAM,QAAQ,IAAI;EACxB;EACA,MAAM,aAAa,SAAS,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,KAAK,MAAM;EAC9D,IAAI,KACF,WAAW,KAAK,iBAAiB,KAAK,OAAO,WAAW,WAAW,cAAc,cACjF;GACE,QAAQ;GACR,QAAQ,KAAK,OAAO;GACpB,GAAI,WAAW,SAAS,KAAK,EAC3B,YAAY,WAAW,KAAK,WAAW;IAAE,MAAM,MAAM;IAAM,QAAQ,MAAM;GAAO,EAAE,EACpF;EACF,CACF;EACA,OAAO;GAAE,OAAO,KAAK;GAAQ;GAAY;EAAO;CAClD;;;;;CAMA,SAAS,eAAe,MAAoB;EAC1C,MAAM,wBAAQ,IAAI,IAAI,CAAC,KAAK,MAAM,WAAW,IAAI,CAAC;EAElD,OAAO,MAAM,QAAQ,SAAS;GAC5B,IAAI,SAAS,MAAM,OAAO;GAE1B,IAAI,CADc,OAAO,KAAK,KAAK,MAAM,WAAW,aAAa,CAAC,CACrD,CAAC,CAAC,MAAM,eAAe,MAAM,IAAI,UAAU,CAAC,GAAG,OAAO;GACnE,MAAM,IAAI,KAAK,MAAM,WAAW,IAAI;GACpC,OAAO;EACT,CAAC;CACH;CAEA,OAAO;EACL,IAAI,QAAyB;GAC3B,OAAO;EACT;EAEA,QAAsC;GACpC,IAAI,UAAU,QACZ,OAAO,QAAQ,OAAO,IAAI,qBAAqB,qBAAqB,MAAM,EAAE,CAAC;GAE/E,QAAQ;GACR,OAAO,QAAQ,QAAQ;EACzB;EAEA,KAAK,QAAuD;GAC1D,IAAI,UAAU,QAAQ;IACpB,QAAQ;IACR,cAAc,QAAQ,QAAQ,CAAC,CAAC;GAClC;GACA,gBAAgB,cAAc,QAAQ,MAAM,CAAC;GAC7C,OAAO;EACT;EAEA,OAAO,MAA2C;GAChD,OAAO,cAAc,UAAU,IAAI,CAAC;EACtC;EAEA,SAA8B;GAC5B,OAAO,MAAM,KAAK,SAAS,KAAK,MAAM;EACxC;CACF;AACF;;;;ACzbA,IAAa,uBAAb,cAA0C,MAAM;CAC9C,OAAyB;CACzB;CAEA,YAAY,MAAc,SAAiB,OAAiB;EAC1D,MAAM,eAAe,QAAQ,IAAI,KAAK,IAAI,EAAE,MAAM,CAAC;EACnD,KAAK,OAAO;CACd;AACF;AAEA,MAAM,oBAAoB;CAAC;CAAO;CAAQ;CAAO;AAAM;;AAGvD,SAAS,UAAU,MAAuB;CACxC,OACE,KAAK,WAAW,GAAG,KACnB,KAAK,WAAW,GAAG,KACnB,KAAK,SAAS,OAAO,KACrB,KAAK,SAAS,QAAQ,KACtB,6BAA6B,KAAK,IAAI;AAE1C;;;;;AAMA,MAAM,mBAAmB,UAA8C;CACrE,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,EAAE,MAAM,OAAO,UAAU,OAAO;CACtC,OACE,OAAO,SAAS,aAAa,OAAO,UAAU,cAAc,SAAS,QAAQ,KAAK,SAAS,EAAE;AAEjG;AAEA,MAAM,YAAY,UAA4B,OAAO,UAAU,YAAY,UAAU;;AAGrF,eAAe,SAAS,KAAa,OAAiD;CACpF,MAAM,OAAO,KAAK,KAAK,MAAM,IAAI;CACjC,IAAI,MAAM,YAAY,GAAG;EACvB,MAAM,QAAQ,kBAAkB,KAAK,QAAQ,KAAK,MAAM,QAAQ,KAAK,CAAC,CAAC,CAAC,MAAM,cAC5E,WAAW,SAAS,CACtB;EACA,IAAI,UAAU,KAAA,GACZ,MAAM,IAAI,qBACR,MACA,0FACF;EAEF,OAAO;CACT;CACA,OAAO,kBAAkB,SAAS,QAAQ,MAAM,IAAI,CAAC,IAAI,OAAO,KAAA;AAClE;;;;;;;;AASA,eAAsB,gBAAgB,KAAqC;CACzE,IAAI;CACJ,IAAI;EACF,UAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;CACtD,SAAS,OAAO;EACd,MAAM,IAAI,qBAAqB,KAAK,gCAAgC,KAAK;CAC3E;CACA,QAAQ,MAAM,GAAG,MAAO,EAAE,OAAO,EAAE,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,IAAI,CAAE;CAEvE,MAAM,QAAuB,CAAC;CAC9B,KAAK,MAAM,SAAS,SAAS;EAC3B,IAAI,UAAU,MAAM,IAAI,GAAG;EAC3B,MAAM,OAAO,MAAM,SAAS,KAAK,KAAK;EACtC,IAAI,SAAS,KAAA,GAAW;EACxB,IAAI;EACJ,IAAI;GACF,YAAa,MAAM,OAAO,cAAc,IAAI,CAAC,CAAC;EAChD,SAAS,OAAO;GACd,MAAM,IAAI,qBAAqB,MAAM,8BAA8B,KAAK;EAC1E;EAEA,MAAM,UAAU,IAAI,IAAI,OAAO,OAAO,SAAS,CAAC,CAAC,OAAO,eAAe,CAAC;EACxE,IAAI,QAAQ,SAAS,GACnB,MAAM,IAAI,qBAAqB,MAAM,mDAAmD;EAE1F,KAAK,MAAM,cAAc,SAAS,MAAM,KAAK;GAAE;GAAY,QAAQ;EAAK,CAAC;CAC3E;CACA,OAAO;AACT;;AAYA,eAAsB,eAAe,SAAwD;CAC3F,MAAM,WAA0B,QAAQ,WAAW,CAAC,EAAA,CAAG,KAAK,gBAAgB;EAC1E;EACA,QAAQ;CACV,EAAE;CACF,MAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI;CACvC,KAAK,MAAM,OAAO,QAAQ,cAAc,CAAC,GACvC,QAAQ,KAAK,GAAI,MAAM,gBAAgB,QAAQ,KAAK,GAAG,CAAC,CAAE;CAE5D,OAAO;AACT;;;AC7FA,MAAM,+BAA+B;AAErC,IAAa,eAAb,MAA0B;CACxB;CACA;CAGA,yBAAkB,IAAI,IAA2B;CACjD,eAA+B,CAAC;CAChC,UAAU;CACV,WAAW;CACX,aAAa;CACb,WAAW;CACX,UAAU;CAEV,YAAY,SAA8B;EACxC,MAAM,MAAM,QAAQ,qBAAqB;EACzC,IAAI,EAAE,QAAQ,OAAO,qBAAsB,OAAO,UAAU,GAAG,KAAK,OAAO,IACzE,MAAM,IAAI,WACR,kEAAkE,IAAI,EACxE;EAEF,KAAK,WAAW,QAAQ;EACxB,KAAK,cAAc;CACrB;;;;;CAMA,QAAQ,QAAgB,MAAkC;EACxD,IAAI,KAAK,SAAS;GAChB,KAAK;GACL,OAAO;EACT;EACA,MAAM,UAAU,KAAK,OAAO,IAAI,MAAM;EACtC,IAAI,YAAY,KAAA,GAAW;GACzB,MAAM,QAAuB,CAAC;GAC9B,KAAK,OAAO,IAAI,QAAQ,KAAK;GAC7B,KAAU,KAAK,QAAQ,OAAO,IAAI;GAClC,OAAO;EACT;EACA,IAAI,QAAQ,UAAU,KAAK,aAAa;GACtC,KAAK;GACL,OAAO;EACT;EACA,QAAQ,KAAK,IAAI;EACjB,KAAK;EACL,OAAO;CACT;;CAGA,WAAW,QAAwB;EACjC,OAAO,KAAK,OAAO,IAAI,MAAM,CAAC,EAAE,UAAU;CAC5C;CAEA,QAA2B;EACzB,OAAO;GACL,aAAa,KAAK,OAAO;GACzB,SAAS,KAAK;GACd,WAAW,KAAK;GAChB,SAAS,KAAK;GACd,QAAQ,KAAK;EACf;CACF;CAEA,IAAI,SAAkB;EACpB,OAAO,KAAK;CACd;;CAGA,SAAwB;EACtB,IAAI,KAAK,OAAO,SAAS,GAAG,OAAO,QAAQ,QAAQ;EACnD,OAAO,IAAI,SAAS,YAAY,KAAK,aAAa,KAAK,OAAO,CAAC;CACjE;;;;;;CAOA,MAAM,UAAwC,CAAC,GAAkB;EAC/D,KAAK,UAAU;EACf,IAAI,QAAQ,UAAU,OACpB,KAAK,MAAM,WAAW,KAAK,OAAO,OAAO,GAAG;GAC1C,KAAK,YAAY,QAAQ;GACzB,KAAK,YAAY,QAAQ;GACzB,QAAQ,SAAS;EACnB;EAEF,OAAO,KAAK,OAAO;CACrB;CAEA,MAAM,KAAK,QAAgB,SAAwB,OAAmC;EACpF,IAAI,OAAgC;EACpC,OAAO,SAAS,KAAA,GAAW;GACzB,IAAI;IACF,MAAM,KAAK;GACb,SAAS,OAAO;IACd,KAAK;IACL,KAAK,QAAQ,OAAO,MAAM;GAC5B;GACA,KAAK;GACL,OAAO,QAAQ,MAAM;GACrB,IAAI,SAAS,KAAA,GAAW,KAAK;EAC/B;EACA,KAAK,OAAO,OAAO,MAAM;EACzB,IAAI,KAAK,OAAO,SAAS,KAAK,KAAK,aAAa,SAAS,GAAG;GAC1D,MAAM,UAAU,KAAK;GACrB,KAAK,eAAe,CAAC;GACrB,KAAK,MAAM,WAAW,SAAS,QAAQ;EACzC;CACF;CAEA,QAAQ,OAAgB,QAAsB;EAC5C,IAAI;GACF,KAAK,SAAS,OAAO,MAAM;EAC7B,SAAS,cAAc;GAGrB,qBAAqB;IACnB,MAAM,IAAI,eACR,CAAC,cAAc,KAAK,GACpB,wCAAwC,OAAO,EACjD;GACF,CAAC;EACH;CACF;AACF;;;;AC5JA,IAAa,cAAb,MAAyB;CACvB,SAAkB,IAAI,kBAAsC;;CAG5D,IAAI,UAA8B;EAChC,OAAO,KAAK,OAAO,SAAS;CAC9B;;;;;;CAOA,IAAO,QAA4B,IAAgB;EACjD,IAAI,KAAK,OAAO,SAAS,MAAM,QAAQ,OAAO,GAAG;EACjD,OAAO,KAAK,OAAO,IAAI,QAAQ,EAAE;CACnC;AACF;;ACLA,MAAM,gBAAgB;;;;;AAMtB,MAAM,qBAAqB;;AAiF3B,IAAa,0BAAb,cAA6C,MAAM;CACjD,OAAyB;CACzB;CACA;CAEA,YAAY,QAAgB,KAAa;EACvC,MACE,aAAa,OAAO,wCAAwC,IAAI,qGAElE;EACA,KAAK,SAAS;EACd,KAAK,MAAM;CACb;AACF;AAEA,SAAS,aAAa,MAAc,OAAuB;CAEzD,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG,MAAM,IAAI,WAAW,GAAG,KAAK,aAAa,OAAO;CAC5F,OAAO;AACT;AAEA,SAAS,QAAQ,MAA6B;CAC5C,MAAM,KAAK,gBAAgB,OAAO,KAAK,QAAQ,IAAI;CACnD,IAAI,OAAO,OAAO,YAAY,CAAC,OAAO,SAAS,EAAE,GAC/C,MAAM,IAAI,UAAU,gCAAgC,OAAO,IAAI,EAAE,wBAAwB;CAE3F,OAAO;AACT;AAEA,SAAS,cAAc,KAAqC;CAC1D,IAAI,OAAO,QAAQ,YAAY,QAAQ,IACrC,MAAM,IAAI,UAAU,uCAAuC;AAE/D;;;;;AAMA,SAAS,gBAAgB,OAAgB,MAAc,MAAyB;CAC9E,IAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,OAAO,UAAU,WAAW;CAC/E,IAAI,OAAO,UAAU,UAAU;EAC7B,IAAI,OAAO,SAAS,KAAK,GAAG;EAC5B,MAAM,IAAI,UAAU,uBAAuB,KAAK,IAAI,MAAM,aAAa;CACzE;CACA,IAAI,OAAO,UAAU,UACnB,MAAM,IAAI,UAAU,uBAAuB,KAAK,IAAI,OAAO,MAAM,aAAa;CAEhF,IAAI,KAAK,IAAI,KAAK,GAAG,MAAM,IAAI,UAAU,uBAAuB,KAAK,uBAAuB;CAC5F,KAAK,IAAI,KAAK;CACd,IAAI,MAAM,QAAQ,KAAK,GACrB,MAAM,SAAS,MAAM,MAAM;EACzB,gBAAgB,MAAM,GAAG,KAAK,GAAG,EAAE,IAAI,IAAI;CAC7C,CAAC;MACI;EACL,MAAM,QAAQ,OAAO,eAAe,KAAK;EACzC,IAAI,UAAU,OAAO,aAAa,UAAU,MAC1C,MAAM,IAAI,UAAU,uBAAuB,KAAK,+BAA+B;EAEjF,KAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,KAAK,GAAG,gBAAgB,MAAM,GAAG,KAAK,GAAG,OAAO,IAAI;CAC/F;CACA,KAAK,OAAO,KAAK;AACnB;AAEA,SAAS,WAAW,OAA+C;CACjE,OACE,UAAU,SACT,OAAO,UAAU,YAAY,OAAO,UAAU,eAC/C,OAAQ,MAA+B,SAAS;AAEpD;AAEA,SAAgB,uBAAuB,SAAoD;CACzF,MAAM,EAAE,SAAS,mBAAmB;CACpC,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,UAAU,QAAQ,WAAW,IAAI,YAAY;CACnD,MAAM,eAAe,aAAa,gBAAgB,QAAQ,gBAAA,GAAsC;CAChG,MAAM,UAAU,aACd,kBACA,QAAQ,kBAAA,GACV;CACA,MAAM,gBAAgB,QAAQ,qBAAA;CAC9B,IAAI,CAAC,OAAO,UAAU,aAAa,KAAK,gBAAgB,GACtD,MAAM,IAAI,WAAW,+BAA+B,eAAe;CAErE,MAAM,OAAgC,cAAc,QAAQ,SAAS,WAAW,CAAC,CAAC,WAChF,QACA,EAAE,SAAS,CAAC,QAAQ,EAAE,CACxB;CAGA,MAAM,2BAAW,IAAI,IAA4C;CAGjE,MAAM,2BAAW,IAAI,IAA2B;CAEhD,MAAM,2BAAW,IAAI,IAAuC;CAE5D,IAAI,UAAU;CACd,IAAI;CACJ,IAAI;CAEJ,IAAI;CACJ,IAAI,QAAQ;CAEZ,IAAI,UAAU;CAEd,IAAI;CAKJ,IAAI,OAAyB,QAAQ,QAAQ;CAC7C,SAAS,UAAa,IAAkC;EACtD,MAAM,SAAS,KAAK,KAAK,EAAE;EAC3B,OAAO,OAAO,YAAY,KAAA,CAAS;EACnC,OAAO;CACT;CAEA,SAAS,SAAe;EACtB,aAAa,KAAK;EAClB,QAAQ,KAAA;EACR,UAAU,KAAA;CACZ;CAEA,SAAS,IAAI,IAAkB;EAC7B,OAAO;EACP,MAAM,QAAQ,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,CAAC,GAAG,kBAAkB;EACvE,UAAU;EACV,QAAQ,iBAAiB;GACvB,QAAQ,KAAA;GACR,UAAU,KAAA;GACV,KAAK;EACP,GAAG,KAAK;CACV;;CAGA,SAAS,OAAa;EACpB,IAAI,CAAC,SAAS;EACd,IAAI,SAAS,KAAA,GAAW;GACtB,QAAQ;GACR;EACF;EACA,OAAO;EACP,QAAQ,YAAY;GAClB,GAAG;IACD,QAAQ;IACR,MAAM,KAAK;GACb,SAAS,SAAS;EACpB,EAAA,CAAG,CAAC,CAAC,cAAc;GACjB,OAAO,KAAA;EACT,CAAC;CACH;;;;;;;;CASA,SAAS,cAA8C;EACrD,IAAI,SAAS,SAAS,GAAG,OAAO,KAAA;EAChC,MAAM,wBAAQ,IAAI,IAAY;EAC9B,KAAK,MAAM,SAAS,SAAS,OAAO,GAAG,KAAK,MAAM,OAAO,MAAM,KAAK,GAAG,MAAM,IAAI,GAAG;EACpF,OAAO;GAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,SAAS,KAAK,CAAC,EAAE;GAAG,KAAK,EAAE,IAAI,CAAC,GAAG,KAAK,EAAE;EAAE;CACzE;CAEA,eAAe,OAAsB;EACnC,MAAM,MAAM,KAAK,IAAI;EAErB,UAAU,KAAA;EACV,IAAI;EACJ,IAAI;GACF,MAAM,gBAAgB,YAAY,GAAG,CAAC;GAEtC,MAAM,SAAS,YAAY;GAC3B,MAAM,CAAC,YACL,WAAW,KAAA,IACP,CAAC,IACD,MAAM,KAAK,KAAK;IACd,OAAO;KAAE,GAAG;KAAQ,QAAQ,EAAE,IAAI,IAAI;IAAE;IACxC,SAAS;IACT,OAAO;GACT,CAAC;GACP,OAAO,UAAU;EACnB,SAAS,OAAO;GACd,eAAe,KAAK;GACpB,OAAO,KAAK,IAAI,IAAI;EACtB;EACA,IAAI,YAAY,KAAA,MAAc,SAAS,KAAA,KAAa,UAAU,OAAO,OAAO;EAC5E,IAAI,WAAW,CAAC,SAAS,SAAS,KAAA,GAAW,IAAI,IAAI;CACvD;;;;;;;CAQA,eAAe,YAAY,KAA4B;EACrD,UAAU;EACV,MAAM,SAAS,YAAY;EAC3B,IAAI,WAAW,KAAA,GAAW;EAC1B,KAAK,IAAI,SAAS,GAAG,SAAS,UAAU,eAAe;GACrD,MAAM,OAAO,MAAM,KAAK,KAAK;IAC3B,OAAO;KAAE,GAAG;KAAQ,QAAQ,EAAE,KAAK,IAAI;IAAE;IACzC,SAAS;IACT,OAAO;IACP;GACF,CAAC;GACD,KAAK,MAAM,OAAO,MAAM;IACtB,IAAI,CAAC,SAAS;IACd,IAAI,SAAS,QAAQ,eAAe;KAClC,UAAU;KACV;IACF;IACA,SAAS,GAAG;GACd;GACA,IAAI,KAAK,SAAS,eAAe;EACnC;CACF;CAEA,SAAS,SAAS,KAAsB;EACtC,IAAI,SAAS,IAAI,IAAI,EAAE,GAAG;EAC1B,MAAM,aAAa,SAAS,IAAI,IAAI,MAAM,CAAC,EAAE,IAAI,IAAI,GAAG;EAExD,IAAI,eAAe,KAAA,GAAW;EAC9B,MAAM,OAAO,IAAI,KAAK,UAAU,CAAC,CAE9B,KAAK,OAAO,aAAa;GACxB,IAAI,UAAU,MAAM,KAAK,OAAO,IAAI,EAAE;GACtC,OAAO;EACT,CAAC,CAAC,CACD,MACE,YAAY,UACZ,UAAmB;GAClB,eAAe,KAAK;GAGpB,MAAM,KAAK,KAAK,IAAI,IAAI;GACxB,UAAU,KAAK,IAAI,WAAW,IAAI,EAAE;GACpC,IAAI,YAAY,YAAY,KAAA,KAAa,KAAK,UAAU,IAAI,EAAE;GAC9D,OAAO;EACT,CACF,CAAC,CACA,MAAM,YAAY;GACjB,SAAS,OAAO,IAAI,EAAE;GAGtB,IAAI,YAAY,WAAW,SAAS,KAAA,IAAY,KAAK;EACvD,CAAC;EACH,SAAS,IAAI,IAAI,IAAI,IAAI;CAC3B;CAEA,SAAS,KAAK,KAAgB,OAAgB,UAAyB;EACrE,QAAQ;GAAE,QAAQ,IAAI;GAAQ,OAAO;GAAa,OAAO,IAAI;GAAK;GAAO;EAAS,CAAC;CACrF;;;;;;CAOA,SAAS,IAAI,KAAgB,EAAE,SAAS,YAAiD;EACvF,MAAM,WAAW,IAAI,SAAS,QAAQ;EACtC,MAAM,MAAkB,EACtB,IAAI,SAAsB;GACxB,OAAO,SAAS;EAClB,EACF;EACA,IAAI;EACJ,IAAI;GAEF,SAAS,QAAQ,IAAI,IAAI,cAAc,QAAQ,IAAI,SAAS,GAAG,CAAC;EAClE,SAAS,OAAO;GACd,KAAK,KAAK,OAAO,KAAK;GACtB,OAAO,QAAQ,QAAQ,IAAI;EAC7B;EACA,IAAI,CAAC,WAAW,MAAM,GAAG,OAAO,QAAQ,QAAQ,IAAI;EACpD,OAAO,IAAI,SAAkB,YAAY;GACvC,IAAI,UAAU;GACd,MAAM,UAAU,aAA4B;IAC1C,UAAU;IACV,aAAa,OAAO;IACpB,SAAS,OAAO,IAAI,EAAE;IACtB,QAAQ,QAAQ;GAClB;GACA,MAAM,UAAU,iBAAiB;IAC/B,MAAM,QAAQ,IAAI,gBAAgB,IAAI,QAAQ,IAAI,KAAK,YAAY;IACnE,OAAO,IAAI;IACX,SAAS,OAAO,KAAK;IACrB,KAAK,KAAK,OAAO,IAAI;GACvB,GAAG,YAAY;GACf,SAAS,IAAI,IAAI,KAAK,WAAW;IAC/B,OAAO,KAAK;IACZ,SAAS,OAAO,MAAM;GACxB,CAAC;GACD,OAAO,WACC;IACJ,IAAI,CAAC,SAAS,OAAO,IAAI;GAC3B,IACC,UAAmB;IAClB,IAAI,CAAC,SAAS;KACZ,OAAO,IAAI;KACX,KAAK,KAAK,OAAO,KAAK;KACtB;IACF;IAGA,IAAI,iBAAiB,qBAAqB;IAC1C,YAAY;KACV,QAAQ,IAAI;KACZ,OAAO;KACP,OAAO,IAAI;KACX;KACA,UAAU;IACZ,CAAC;GACH,CACF;EACF,CAAC;CACH;CAEA,SAAS,UAAU,QAAgB,UAAgC;EACjE,OAAO;GACL,MAAM,GAAG,MAAM,KAAK,UAAU,MAAM;IAClC,MAAM,SAAS,QAAQ,IAAI;IAC3B,cAAc,GAAG;IACjB,gBAAgB,SAAS,2BAAW,IAAI,IAAI,CAAC;IAC7C,MAAM,SAAS,QAAQ;IACvB,MAAM,KAAK,MAAM,KAAK,OAAO;KAC3B;KACA;KACA;KACA;KACA,GAAI,WAAW,KAAA,KAAa,EAAE,OAAO;IACvC,CAAC;IACD,IAAI,SAAS;KACX,IAAI,SAAS,KAAA,GAAW,QAAQ;UAC3B,IAAI,YAAY,KAAA,KAAa,SAAS,SAAS,IAAI,MAAM;IAChE;IACA,OAAO;GACT;GAEA,OAAO,IAAI;IACT,OAAO,UAAU,YAAY;KAE3B,IAAI,SAAS,IAAI,EAAE,GAAG,OAAO;KAC7B,OAAQ,MAAM,KAAK,OAAO;MAAE;MAAI;KAAO,CAAC,IAAK;IAC/C,CAAC;GACH;GAEA,GAAG,KAAK,SAAsB;IAC5B,cAAc,GAAG;IACjB,IAAI,OAAO,YAAY,YAAY,MAAM,IAAI,UAAU,eAAe,IAAI,eAAe;IACzF,IAAI,QAAQ,SAAS,IAAI,MAAM;IAC/B,IAAI,UAAU,KAAA,GAAW;KACvB,wBAAQ,IAAI,IAAI;KAChB,SAAS,IAAI,QAAQ,KAAK;IAC5B;IACA,IAAI,MAAM,IAAI,GAAG,GAAG,MAAM,IAAI,wBAAwB,QAAQ,GAAG;IACjE,MAAM,aAAgC;KAAE;KAAS;IAAS;IAC1D,MAAM,IAAI,KAAK,UAAU;IAEzB,KAAK;IACL,aAAa;KACX,MAAM,UAAU,SAAS,IAAI,MAAM;KACnC,IAAI,SAAS,IAAI,GAAG,MAAM,YAAY;KACtC,QAAQ,OAAO,GAAG;KAClB,IAAI,QAAQ,SAAS,GAAG,SAAS,OAAO,MAAM;IAChD;GACF;EACF;CACF;CAEA,OAAO;EACL;EAEA,aAAa,QAAQ;GACnB,SAAS,OAAO,MAAM;EACxB;EAEA,QAAQ;GACN,IAAI,SAAS;GACb,UAAU;GACV,KAAK;EACP;EAEA,MAAM,KAAK,QAAQ;GACjB,UAAU;GACV,OAAO;GACP,MAAM,gBAAsB;IAC1B,KAAK,MAAM,MAAM,SAAS,OAAO,GAAG,GAAG,QAAQ,MAAM;GACvD;GACA,IAAI,QAAQ,SAAS,QAAQ;QACxB,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;GAC9D,MAAM;GAEN,OAAO;GACP,MAAM,QAAQ,IAAI,SAAS,OAAO,CAAC;EACrC;CACF;AACF;;;;ACnfA,IAAa,uBAAb,cAA0C,MAAM;CAC9C,OAAyB;CACzB;;CAEA;CAEA,YAAY,SAAiB,aAAqB;EAChD,MACE,YAAY,QAAQ,wCAAwC,YAAY,mDAC7B,YAAY,yCAC3C,QAAQ,sDACtB;EACA,KAAK,UAAU;EACf,KAAK,cAAc;CACrB;AACF;;AAGA,IAAa,uBAAb,cAA0C,MAAM;CAC9C,OAAyB;CACzB;CACA;CACA;CAEA,YAAY,SAAiB,UAAkB,UAAkB;EAC/D,MACE,aAAa,WACT,YAAY,QAAQ,oCAAoC,SAAS,kGAEjE,wBAAwB,QAAQ,eAAe,SAAS,0CACrC,SAAS,0DAClC;EACA,KAAK,UAAU;EACf,KAAK,WAAW;EAChB,KAAK,WAAW;CAClB;AACF;;AAWA,SAAgB,wBAAyC;CAEvD,MAAM,yBAAS,IAAI,IAA6B;CAEhD,OAAO;EACL,UAAU,QAAQ;GAChB,OAAO;IACL,QAA+B,MAAS,SAA4B;KAClE,MAAM,WAAW,OAAO,IAAI,IAAI;KAGhC,IAAI,UAAU,MAAM,IAAI,qBAAqB,MAAM,SAAS,QAAQ,MAAM;KAC1E,OAAO,IAAI,MAAM;MAAE;MAAQ;MAAM;KAAQ,CAAC;IAC5C;IAEA,IAA2B,MAAsB;KAC/C,MAAM,QAAQ,OAAO,IAAI,IAAI;KAC7B,IAAI,CAAC,OAAO,MAAM,IAAI,qBAAqB,MAAM,MAAM;KAEvD,OAAO,MAAM;IACf;IAEA,IAAI,MAAM;KACR,OAAO,OAAO,IAAI,IAAI;IACxB;GACF;EACF;EAEA,aAAa,QAAQ;GACnB,KAAK,MAAM,CAAC,MAAM,UAAU,QAC1B,IAAI,MAAM,WAAW,QAAQ,OAAO,OAAO,IAAI;EAEnD;EAEA,OAAO;GACL,OAAO,CAAC,GAAG,OAAO,OAAO,CAAC;EAC5B;CACF;AACF;;;AC7CA,SAAS,UAAU,OAAwB;CACzC,MAAM,OAAO,KAAK,UAAU,KAAK;CACjC,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,UAAU,iCAAiC;CAC7E,OAAO;AACT;AAEA,SAAS,MAAS,MAAiB;CACjC,OAAO,KAAK,MAAM,IAAI;AACxB;AAEA,SAAS,WAAW,KAAU,OAA0B;CACtD,IAAI,UAAU,MAAM,OAAO,IAAI;CAE/B,OAAO,OAAO,OAAO,IAAI,KAAK,KAAK,IAAK,IAAI,IAAI,SAAuB;AACzE;AAIA,SAAS,OAAO,OAAkB,SAA0B;CAC1D,IAAI,YAAY,MAAM,OAAO,UAAU;CACvC,OAAO,OAAO,UAAU,OAAO,WAAW,UAAU;AACtD;AAIA,SAAS,eAAe,GAAW,GAAmB;CACpD,IAAI,MAAM,GAAG,OAAO;CACpB,MAAM,SAAS,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;CAC1C,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAC1B,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,GACpC,OAAQ,EAAE,YAAY,CAAC,IAAgB,EAAE,YAAY,CAAC;CAG1D,OAAO,EAAE,SAAS,EAAE;AACtB;AAEA,SAAS,eAAe,OAAkB,SAA8C;CACtF,IAAI,OAAO,UAAU,YAAY,OAAO,YAAY,UAAU,OAAO,QAAQ;CAC7E,IAAI,OAAO,UAAU,YAAY,OAAO,YAAY,UAClD,OAAO,eAAe,OAAO,OAAO;AAGxC;AAEA,SAAS,QAAQ,KAAU,YAAqD;CAC9E,OAAO,WAAW,OAAO,cAAc;EACrC,MAAM,QAAQ,WAAW,KAAK,UAAU,KAAK;EAC7C,QAAQ,UAAU,IAAlB;GACE,KAAK,MACH,OAAO,OAAO,OAAO,UAAU,KAAK;GACtC,KAAK,MACH,OAAO,CAAC,OAAO,OAAO,UAAU,KAAK;GACvC,KAAK,MACH,OAAO,UAAU,MAAM,MAAM,YAAY,OAAO,OAAO,OAAO,CAAC;GACjE,SAAS;IACP,MAAM,OAAO,eAAe,OAAO,UAAU,KAAK;IAClD,IAAI,SAAS,KAAA,GAAW,OAAO;IAC/B,IAAI,UAAU,OAAO,MAAM,OAAO,OAAO;IACzC,IAAI,UAAU,OAAO,OAAO,OAAO,QAAQ;IAC3C,IAAI,UAAU,OAAO,MAAM,OAAO,OAAO;IACzC,OAAO,QAAQ;GACjB;EACF;CACF,CAAC;AACH;AAGA,SAAS,SAAS,OAA0B;CAC1C,IAAI,UAAU,MAAM,OAAO;CAC3B,IAAI,OAAO,UAAU,WAAW,OAAO;CACvC,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,OAAO;AACT;AAEA,SAAS,cAAc,GAAc,GAAsB;CACzD,MAAM,OAAO,SAAS,CAAC,IAAI,SAAS,CAAC;CACrC,IAAI,SAAS,GAAG,OAAO;CACvB,IAAI,OAAO,MAAM,WAAW,OAAO,OAAO,CAAC,IAAI,OAAO,CAAC;CACvD,IAAI,OAAO,MAAM,UAAU,OAAO,IAAK;CACvC,IAAI,OAAO,MAAM,UAAU,OAAO,eAAe,GAAG,CAAW;CAC/D,OAAO;AACT;AAEA,SAAS,SAAS,MAAa,OAAyC;CACtE,IAAI,MAAM,WAAW,GAAG,OAAO;CAE/B,OAAO,KAAK,MAAM,GAAG,MAAM;EACzB,KAAK,MAAM,EAAE,OAAO,eAAe,OAAO;GACxC,MAAM,OAAO,cAAc,WAAW,GAAG,KAAK,GAAG,WAAW,GAAG,KAAK,CAAC;GACrE,IAAI,SAAS,GAAG,OAAO,cAAc,QAAQ,OAAO,CAAC;EACvD;EACA,OAAO;CACT,CAAC;AACH;;AAGA,SAAgB,sBAAmC;CACjD,MAAM,6BAAa,IAAI,IAA2B;CAClD,MAAM,2BAAW,IAAI,IAAyB;CAC9C,IAAI,SAAS;CAEb,SAAS,aAAmB;EAC1B,IAAI,QAAQ,MAAM,IAAI,mBAAmB;CAC3C;CAEA,SAAS,cAAc,WAAkC;EACvD,IAAI,OAAO,WAAW,IAAI,SAAS;EACnC,IAAI,SAAS,KAAA,GAAW;GACtB,OAAO;IAAE,oBAAI,IAAI,IAAI;IAAG,6BAAa,IAAI,IAAI;GAAE;GAC/C,WAAW,IAAI,WAAW,IAAI;EAChC;EACA,OAAO;CACT;CAEA,SAAS,UAAU,WAAmB,MAAyB;EAC7D,MAAM,EAAE,gBAAgB,cAAc,SAAS;EAC/C,IAAI,OAAO,YAAY,IAAI,IAAI;EAC/B,IAAI,SAAS,KAAA,GAAW;GACtB,uBAAO,IAAI,IAAI;GACf,YAAY,IAAI,MAAM,IAAI;EAC5B;EACA,OAAO;CACT;CAEA,SAAS,YAAY,SAA8B;EACjD,IAAI,OAAO,SAAS,IAAI,OAAO;EAC/B,IAAI,SAAS,KAAA,GAAW;GACtB,OAAO;IAAE,OAAO,KAAA;IAAW,sBAAM,IAAI,IAAI;GAAE;GAC3C,SAAS,IAAI,SAAS,IAAI;EAC5B;EACA,OAAO;CACT;CAEA,SAAS,SAAS,WAAkC;EAClD,OAAO;GACL,MAAM,IAAqC,KAAqC;IAC9E,WAAW;IACX,MAAM,OAAO,cAAc,SAAS,CAAC,CAAC,GAAG,IAAI,GAAG;IAChD,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY,MAAS,IAAI;GACvD;GACA,MAAM,IAAI,KAAa,OAAiC;IACtD,WAAW;IACX,cAAc,SAAS,CAAC,CAAC,GAAG,IAAI,KAAK,UAAU,KAAK,CAAC;GACvD;GACA,MAAM,OAAO,KAA+B;IAC1C,WAAW;IACX,OAAO,cAAc,SAAS,CAAC,CAAC,GAAG,OAAO,GAAG;GAC/C;EACF;CACF;CAEA,SAAS,iBACP,WACA,MACe;EACf,SAAS,OAAc;GACrB,OAAO,CAAC,GAAG,UAAU,WAAW,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,WAAW;IAAE;IAAI,KAAK,MAAM,IAAI;GAAE,EAAE;EACvF;EAEA,SAAS,WAAW,QAA0B;GAC5C,IAAI,OAAO,WAAW,UAAU;IAC9B,MAAM,OAAO,UAAU,WAAW,IAAI,CAAC,CAAC,IAAI,MAAM;IAClD,OAAO,SAAS,KAAA,IAAY,CAAC,IAAI,CAAC;KAAE,IAAI;KAAQ,KAAK,MAAM,IAAI;IAAE,CAAC;GACpE;GACA,MAAM,aAAa,eAAe,MAAM;GACxC,OAAO,KAAK,CAAC,CAAC,QAAQ,QAAQ,QAAQ,KAAK,UAAU,CAAC;EACxD;EAEA,OAAO;GACL,MAAM,OAAO,UAA8B;IACzC,WAAW;IACX,MAAM,OAAO,UAAU,kBAAkB,QAAQ,CAAC;IAClD,MAAM,KAAK,WAAW;IACtB,UAAU,WAAW,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI;IACvC,OAAO;GACT;GACA,MAAM,IAAI,IAA4C;IACpD,WAAW;IACX,MAAM,OAAO,UAAU,WAAW,IAAI,CAAC,CAAC,IAAI,EAAE;IAC9C,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY;KAAE,GAAG,MAAS,IAAI;KAAG;IAAG;GAClE;GACA,MAAM,KAAK,OAA4C;IACrD,WAAW;IACX,MAAM,EAAE,OAAO,SAAS,OAAO,WAAW,eAAe,KAAK;IAC9D,MAAM,QAAQ,SACZ,KAAK,CAAC,CAAC,QAAQ,QAAQ,QAAQ,KAAK,KAAK,CAAC,GAC1C,OACF;IACA,MAAM,MAAM,UAAU,KAAA,IAAY,KAAA,IAAY,SAAS;IACvD,OAAO,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,SAAS;KAAE,GAAI,IAAI;KAAW,IAAI,IAAI;IAAG,EAAE;GAClF;GACA,MAAM,OAAO,QAAmB,OAAkC;IAChE,WAAW;IACX,MAAM,UAAU,kBAAkB,KAAK;IACvC,MAAM,OAAO,UAAU,WAAW,IAAI;IACtC,MAAM,UAAU,WAAW,MAAM;IACjC,KAAK,MAAM,OAAO,SAAS,KAAK,IAAI,IAAI,IAAI,UAAU;KAAE,GAAG,IAAI;KAAK,GAAG;IAAQ,CAAC,CAAC;IACjF,OAAO,QAAQ;GACjB;GACA,MAAM,OAAO,QAAoC;IAC/C,WAAW;IACX,MAAM,OAAO,UAAU,WAAW,IAAI;IACtC,MAAM,UAAU,WAAW,MAAM;IACjC,KAAK,MAAM,OAAO,SAAS,KAAK,OAAO,IAAI,EAAE;IAC7C,OAAO,QAAQ;GACjB;EACF;CACF;CAEA,SAAS,oBAAoB,WAAkC;EAC7D,OAAO;GACL,IAAI,SAAS,SAAS;GACtB,WACE,MACA,SACe;IAGf,iBAAiB,OAAO;IACxB,OAAO,iBAAoB,WAAW,IAAI;GAC5C;EACF;CACF;CAEA,SAAS,gBAAgB,SAAiC;EACxD,OAAO;GACL,MAAM,WAA2C;IAC/C,WAAW;IACX,MAAM,OAAO,YAAY,OAAO,CAAC,CAAC;IAClC,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY,MAAM,IAAI;GACpD;GACA,MAAM,SAAS,OAAiC;IAC9C,WAAW;IACX,YAAY,OAAO,CAAC,CAAC,QAAQ,UAAU,KAAK;GAC9C;GACA,MAAM,QAAQ,MAAc,KAA4D;IACtF,WAAW;IACX,MAAM,SAAS,YAAY,OAAO,CAAC,CAAC,KAAK,IAAI,IAAI;IACjD,MAAM,SAAoC,CAAC;IAC3C,IAAI,WAAW,KAAA,GAAW,OAAO;IACjC,KAAK,MAAM,MAAM,KAAK;KACpB,MAAM,OAAO,OAAO,IAAI,EAAE;KAC1B,IAAI,SAAS,KAAA,GAAW,OAAO,MAAM,MAAM,IAAI;IACjD;IACA,OAAO;GACT;GACA,MAAM,QAAQ,MAAkC;IAC9C,WAAW;IAGX,MAAM,QAAQ,OAAO,QAAQ,IAAI,CAAC,CAAC,KAChC,CAAC,MAAM,aACN,CACE,MACA,OAAO,QAAQ,OAAO,CAAC,CAAC,KACrB,CAAC,IAAI,WAAW,CAAC,IAAI,UAAU,OAAO,OAAO,UAAU,KAAK,CAAC,CAChE,CACF,CACJ;IACA,MAAM,EAAE,SAAS,YAAY,OAAO;IACpC,KAAK,MAAM,CAAC,MAAM,YAAY,OAAO;KACnC,IAAI,SAAS,KAAK,IAAI,IAAI;KAC1B,IAAI,WAAW,KAAA,GAAW;MACxB,yBAAS,IAAI,IAAI;MACjB,KAAK,IAAI,MAAM,MAAM;KACvB;KACA,KAAK,MAAM,CAAC,IAAI,SAAS,SACvB,IAAI,SAAS,MAAM,OAAO,OAAO,EAAE;UAC9B,OAAO,IAAI,IAAI,IAAI;IAE5B;GACF;GACA,MAAM,QAAuB;IAC3B,WAAW;IACX,SAAS,OAAO,OAAO;GACzB;EACF;CACF;CAEA,OAAO;EACL,aAAa,WAAkC;GAC7C,OAAO,oBAAoB,SAAS;EACtC;EACA,UAAU,SAAiC;GACzC,OAAO,gBAAgB,OAAO;EAChC;EACA,MAAM,QAAuB;GAC3B,SAAS;GACT,WAAW,MAAM;GACjB,SAAS,MAAM;EACjB;CACF;AACF;;;;;;;;AC/SA,SAAgB,mBAAmB,SAA4C;CAC7E,MAAM,EAAE,WAAW,KAAK,kBAAkB;CAC1C,MAAM,yBAAS,IAAI,IAAY;CAE/B,SAAS,SAAS,UAAuD,MAAsB;EAC7F,MAAM,KAAK,GAAG,KAAK,GAAG,SAAS;EAC/B,IAAI,OAAO,IAAI,EAAE,GAAG;EACpB,OAAO,IAAI,EAAE;EACb,MAAM,SAAS;GAAE,QAAQ,SAAS;GAAM,WAAW,UAAU;EAAK;EAClE,MAAM,SAAS,SAAS,WAAW,sBAAsB;EAGzD,IAAI,SAAS,eAAe,KAAA,GAAW;GACrC,IAAI,KACF,WAAW,SAAS,KAAK,YAAY,OAAO,sEACV,UAAU,KAAK,2BAA2B,UAAU,KAAK,MAC3F,MACF;GACA;EACF;EACA,IAAI,KACF,WAAW,SAAS,KAAK,YAAY,OAAO,iBAAiB,UAAU,KAAK,IAC5E,MACF;CACF;CAEA,OAAO,EACL,UAAU,UAAU;EAClB,OAAO;GAEL,IAAI,SAAkB;IACpB,SAAS,UAAU,QAAQ;IAC3B,OAAO,UAAU;GACnB;GACA,IAAI,SAAS;IACX,SAAS,UAAU,KAAK;IAExB,OAAO,UAAU,MAAM,gBAAgB,OAAO,KAAK,OAAO;GAC5D;EACF;CACF,EACF;AACF;;;;;;;AC1CA,SAAgB,YACd,QACA,SACA,UAA8B,CAAC,GACxB;CACP,MAAM,SAAS,QAAQ,KAAK;CAC5B,MAAM,SAAS,QAAQ,UAAU,QAAQ,KAAA,IAAY;CAErD,MAAM,QACJ,SACA,eAA6B,CAAC,GAC9B,YACwB;EACxB,MAAM,cAAmC;GACvC,UAAU,aAAa,YAAY;GACnC,GAAI,UAAU,EAAE,OAAO;GACvB,GAAI,aAAa,YAAY,EAAE,UAAU,aAAa,SAAS;GAC/D,GAAI,WAAW,QAAQ,SAAS,KAAK,EAAE,QAAQ;EACjD;EACA,OAAO,OAAO,KAAK,QAAQ,SAAS,WAAW;CACjD;CAEA,MAAM,YAAY,MAAmB,MAA8C;EACjF,IAAI,GAAG,YAAY,KAAA,KAAa,EAAE,QAAQ,WAAW,GAAG,OAAO,KAAK,YAAY,IAAI,GAAG,CAAC;EACxF,IAAI;EACJ,IAAI;GACF,IAAI,QAAQ,YAAY,KAAA,GACtB,MAAM,IAAI,UAAU,gDAAgD;GAEtE,WAAW,QAAQ,QAAQ,MAAM,EAAE,OAAO;EAC5C,SAAS,OAAO;GACd,OAAO,QAAQ,OAAO,KAAK;EAC7B;EACA,OAAO,KAAK,YAAY,SAAS,IAAI,GAAG,GAAG,SAAS,OAAO;CAC7D;CA0BA,OAAO,OAAO,QAAQ,MAAmB,MAAyB,SAAS,MAAM,CAAC,GAAG;EAvBnF,MAAM;EACN,QAAQ,OAAO,IAAI,CAAC,MAClB,KAAK;GAAE,MAAM;GAAS;GAAO,GAAG,cAAc,EAAE,OAAO;GAAG,GAAG,KAAK,GAAG,UAAU;EAAE,GAAG,CAAC;EACvF,QAAQ,OAAO,IAAI,CAAC,MAClB,KAAK;GAAE,MAAM;GAAS;GAAO,GAAG,cAAc,EAAE,OAAO;GAAG,GAAG,KAAK,GAAG,UAAU;EAAE,GAAG,CAAC;EACvF,QAAQ,OAAO,IAAI,CAAC,MAAM,KAAK;GAAE,MAAM;GAAS;GAAO,GAAG,KAAK,GAAG,UAAU;EAAE,GAAG,CAAC;EAClF,QAAQ,OAAO,IAAI,CAAC,MAAM,KAAK;GAAE,MAAM;GAAS;GAAO,GAAG,KAAK,GAAG,UAAU;EAAE,GAAG,CAAC;EAClF,UAAU,OAAO,MAAM,KAAK;GAAE,MAAM;GAAW;EAAM,GAAG,CAAC;EACzD,WAAW,OAAO,MAChB,KACE;GACE,MAAM;GACN;GACA,UAAU,EAAE;GACZ,UAAU,EAAE;GACZ,GAAG,cAAc,EAAE,OAAO;EAC5B,GACA,CACF;EACF,QAAQ,OAAO,IAAI,CAAC,MAAM,KAAK;GAAE,MAAM;GAAS;GAAO,GAAG,cAAc,EAAE,OAAO;EAAE,GAAG,CAAC;EACvF,OAAO,MAAM,SAAS,IAAI,CAAC,MACzB,KAAK;GAAE,MAAM;GAAQ;GAAM,SAAS;GAAS,GAAG,KAAK,GAAG,UAAU;EAAE,GAAG,CAAC;CAEiB,CAAC;AAChG;;AAGA,SAAS,KAA0C,QAAW,KAA6B;CACzF,MAAM,QAAQ,OAAO;CACrB,OAAO,UAAU,KAAA,IAAY,CAAC,IAAK,GAAG,MAAM,MAAM;AACpD;;;AC3EA,MAAM,QAAuB,OAAO,wBAAwB;;AAc5D,SAAgB,qBACd,SACA,MACsB;CACtB,OAAO,IAAI,mBAAmB,SAAS,IAAI;AAC7C;AAEA,IAAM,qBAAN,MAAyD;CACvD;CACA;;CAEA,YAAyC,KAAA;CACzC,CAAU;CAEV,YAAY,SAAkB,MAA0B;EACtD,KAAK,UAAU;EACf,KAAK,OAAO,QAAQ;EACpB,KAAK,SAAS;GAAE;GAAM,OAAO,KAAA;GAAW,KAAK,KAAA;EAAU;CACzD;CAEA,IAAI,QAAe;EACjB,MAAM,QAAQ,KAAK;EACnB,MAAM,UAAU,SAAS,MAAM,MAAM,KAAK,SAAS,IAAI;EACvD,OAAO,MAAM;CACf;CAEA,IAAI,MAAc;EAChB,MAAM,QAAQ,KAAK;EACnB,MAAM,QAAQ,MAAM,KAAK,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,KAAK,QAAQ,KAAK,GAAG,CAAC;EACrE,OAAO,MAAM;CACf;CAEA,MAAM,OAAqC;EAEzC,OAAO,KAAK,MAAM,CAAC,KAAK,OAAO,MAAM,KAAK,QAAQ,KAAK,OAAO,EAAE,UAAU,OAAO,CAAC;CACpF;AACF;AAEA,SAAS,SAAS,MAA0B,SAAkB,OAA6B;CACzF,OAAO,YAAY,KAAK,QAAQ,SAAS;EACvC,OAAO,KAAK;EACZ,GAAI,KAAK,WAAW,EAAE,SAAS,KAAK,QAAQ,OAAO,OAAO,EAAE;CAC9D,CAAC;AACH;;;;;AAMA,SAAS,YAAY,KAAa,QAAmC;CAEnE,MAAM,QAAS,IAAqC;CACpD,IAAI,UAAU,KAAA,GAAW,OAAO,KAAA;CAChC,OAAO,SAAS,MAAM,MAAO,IAAsC,SAAS,MAAM;AACpF;;;;;;AAOA,MAAa,iBAAgC,OAAO,uBAAuB;;AAO3E,SAAgB,cAAc,KAA8C;CAC1E,OAAO,GAAG,iBAAiB,IAAI;AACjC;;;;;AAMA,SAAS,oBAAoB,WAAuC;CAClE,OAAO;EACL,cAAc;EACd,MAAiD;GAC/C,MAAM,MAAM,UAAU,MAAM,EAAE,QAAQ,KAAK,QAAQ,KAAK,GAAG,CAAC;GAC5D,OAAO,eAAe,MAAM,OAAO,EAAE,OAAO,IAAI,CAAC;GACjD,OAAO;EACT;CACF;AACF;AAEA,MAAM,gBAAgB;CACpB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;AAUA,SAAS,cAAc,OAAc,UAAoB,QAAuB;CAC9E,MAAM,SACkB,WAAmB,UACxC,GAAG,SACF,SAAS,UAAU,OAAO,SAAS,IAAI,SAAS,KAAK,KAAK,GAAG,IAAI,CAAC;CAEtE,MAAM,YAAY,OAAO,YACvB,cAAc,KAAK,WAAW,CAAC,QAAQ,MAAM,SAAS,UAAU,MAAM,OAAkB,CAAC,CAAC,CAC5F;CACA,OAAO,OAAO,OAAO,MAAM,SAAS,KAAK,GAAG,SAAS;AACvD;;AAUA,SAAS,QACP,QACA,MACA,UACA,OACQ;CACR,QAAQ,cAAc;EACpB,MAAM,EAAE,OAAO,WAAW,MAAM,IAAI;EACpC,MAAM,QAAQ,IAAI,oBAAoB,QAAQ,WAAW,OAAO,SAAS,MAAM;EAC/E,KAAK,IAAI,KAAK,GAAG,UAAU,aAAa,MAAM,cAAc;GAC1D,GAAG;GACH;GACA,KAAK;EACP,CAAC;EACD,OAAO,QAAQ,OAAO,KAAK;CAC7B;AACF;;;;;;;AAQA,SAAS,wBACP,QACA,MACA,OACoB;CACpB,OAAO;EACL,cAAc;EACd,MAAgC;GAC9B,MAAM,QAAQ,KAAK,IAAI;GACvB,MAAM,WAAW,WAAW,IAAI;GAChC,IAAI,UAAU,KAAA,KAAa,aAAa,KAAA,GAAW,OAAO;GAC1D,MAAM,UAAU,cAAc,OAAO,UAAU,QAAQ,QAAQ,MAAM,UAAU,KAAK,CAAC;GACrF,OAAO,eAAe,MAAM,SAAS,EAAE,OAAO,QAAQ,CAAC;GACvD,OAAO;EACT;CACF;AACF;;;;;AAQA,SAAS,wBACP,QACA,MACA,OACoB;CACpB,OAAO;EACL,cAAc;EACd,MAAgC;GAC9B,MAAM,SAAS,KAAK,IAAI;GACxB,MAAM,WAAW,WAAW,IAAI;GAChC,IAAI,WAAW,KAAA,KAAa,aAAa,KAAA,GAAW,OAAO,QAAQ;GACnE,MAAM,SAAS,QAAQ,QAAQ,MAAM,UAAU,KAAK;GACpD,MAAM,SAAgB,UACpB,SAAS,UAAU,OAAO,OAAO,IAAI,SAAS,KAAK,OAAO,MAAM,KAAK,CAAC;GACxE,OAAO,eAAe,MAAM,SAAS,EAAE,OAAO,MAAM,CAAC;GACrD,OAAO;EACT;CACF;AACF;;;;;;AAUA,SAAS,sBACP,QACA,QACA,OACoB;CACpB,OAAO;EACL,cAAc;EACd,MAA0B;GACxB,MAAM,WAAW,WAAW,IAAI;GAChC,MAAM,eAA4B,MAAM,YAAY;IAClD,IAAI,UAAU,SAAS;KACrB,MAAM,EAAE,OAAO,WAAW,MAAM,IAAI;KACpC,MAAM,QAAQ,IAAI,oBAAoB,QAAQ,eAAe,OAAO,SAAS,MAAM;KACnF,KAAK,IAAI,KAAK,yBAAyB,MAAM,cAAc;MACzD,GAAG;MACH,WAAW;MACX,KAAK;KACP,CAAC;KACD,MAAM;IACR;IACA,OAAO,KAAK,SAAS,MAAM,OAAO;GACpC;GACA,OAAO,eAAe,MAAM,eAAe,EAAE,OAAO,YAAY,CAAC;GACjE,OAAO;EACT;CACF;AACF;AAEA,MAAM,mBAAuC,EAC3C,MAAqC;CACnC,OAAQ,WAAW,IAAI,CAAC,CAAc;AACxC,EACF;;;;;AAcA,SAAS,qBACP,QACA,WACA,QACA,OACuB;CACvB,OAAO;EACL,KAAK,oBAAoB,SAAS;EAClC,QAAQ;EACR,OAAO,wBACL,SAEC,SACC,YAAY,MAAM,MAAM,KACvB,OAAO,eAAe,IAAI,CAAC,CAAgC,OAC9D,KACF;EACA,OAAO,wBACL,SACC,SAAS;GACR,MAAM,OAAO,OAAO,eAAe,IAAI;GACvC,OAAO,KAAK,UAAU,KAAA,IAAY,KAAA,IAAa;EACjD,GACA,KACF;EACA,aAAa,sBAAyB,QAAQ,QAAQ,KAAK;CAC7D;AACF;;AAGA,SAAgB,mBACd,QACA,WACA,QACc;CAEd,MAAM,SAAsB,UAAU;EACpC,OAAO,YAAY,KAAK,QAAQ;EAChC,QAAQ,EAAE,SAAS,KAAK,QAAQ;CAClC;CACA,MAAM,iBAAiB,qBAA2B,QAAQ,WAAW,QAAQ,KAAK;CAClF,OAAO,EACL,IAAI,KAAK,UAAU;EACjB,MAAM,OAAO,OAAO,OAAO,KAAK,cAAc;EAC9C,KAAK,YAAY;EACjB,OAAO;CACT,EACF;AACF;;;;;AAMA,SAAgB,gBACd,QACA,WACA,QACoF;CAEpF,MAAM,SAAsB,UAAU;EACpC,OAAO,UAAU,KAAK,KAAK;EAC3B,QAAQ,EAAE,MAAM,KAAK,KAAK;CAC5B;CACA,MAAM,cAAc,qBAA2B,QAAQ,WAAW,QAAQ,KAAK;CAC/E,QAAQ,KAAK,UAAU,MAAM,SAAS;EACpC,MAAM,OAAO,OAAO,OAAO,KAAK,WAAW;EAC3C,OAAO,OAAO,MAAM;GAAE;GAAM;EAAK,CAAC;EAClC,KAAK,YAAY;EACjB,OAAO;CACT;AACF;;;;;AAMA,SAAgB,gBACd,WACqD;CACrD,MAAM,cAAqC;EACzC,KAAK,oBAAoB,SAAS;EAClC,QAAQ;CACV;CACA,QAAQ,KAAK,aAAa;EACxB,MAAM,OAAO,OAAO,OAAO,KAAK,WAAW;EAC3C,KAAK,YAAY;EACjB,OAAO;CACT;AACF;;;;;;;AAQA,SAAgB,oBACd,QACA,WACA,QACiC;CAOjC,MAAM,UAAU,SAAiD,KAAK;CACtE,MAAM,SAAsB,UAAU;EACpC,OAAO,gBAAgB,KAAK,MAAM;EAClC,QAAQ,EAAE,OAAO,KAAK,MAAM;CAC9B;CACA,MAAM,cAAqC;EACzC,SAAS,EACP,MAAyB;GACvB,OAAO,KAAK;EACd,EACF;EACA,MAAM,EACJ,MAA+B;GAC7B,MAAM,MAAM,OAAO,IAAI;GACvB,OAAO,QAAQ,KAAA,IAAY,KAAK,QAAQ,OAAO,IAAI;EACrD,EACF;EACA,OAAO,wBACL,SACC,SAAS;GACR,MAAM,MAAM,OAAO,IAAI;GACvB,OAAO,QAAQ,KAAA,IAAY,KAAA,IAAY,YAAY,KAAK,MAAM;EAChE,GACA,KACF;EACA,OAAO,wBAA8B,QAAQ,QAAQ,KAAK;EAC1D,aAAa,sBAA4B,QAAQ,QAAQ,KAAK;EAC9D,KAAK,oBAAoB,SAAS;CACpC;CACA,QAAQ,QAAQ,OAAO,OAAO,KAAK,WAAW;AAChD;;;;;;;;ACvYA,SAAgB,cACd,MACA,YACA,OACe;CACf,MAAM,OAAO,cAAc,MAAM,UAAU;CAC3C,MAAM,2BAAW,IAAI,IAA2B;CAChD,MAAM,aAAa,WAAkC;EACnD,IAAI,UAAU,SAAS,IAAI,MAAM;EACjC,IAAI,YAAY,KAAA,GAAW;GACzB,UAAU,cAAc,MAAM,YAAY,MAAM;GAChD,SAAS,IAAI,QAAQ,OAAO;EAC9B;EACA,OAAO;CACT;CACA,MAAM,gBAA+B;EACnC,MAAM,SAAS,MAAM;EACrB,OAAO,WAAW,KAAA,IAAY,OAAO,UAAU,MAAM;CACvD;CAOA,OAAO;EACL,IAAA;GALA,MAAuC,QAAgB,QAAQ,CAAC,CAAC,GAAG,IAAO,GAAG;GAC9E,MAAM,KAAa,UAAqB,QAAQ,CAAC,CAAC,GAAG,IAAI,KAAK,KAAK;GACnE,SAAS,QAAgB,QAAQ,CAAC,CAAC,GAAG,OAAO,GAAG;EAG/C;EACD,WACE,MACA,SACe;GAGf,MAAM,aAAa,KAAK,WAAc,MAAM,OAAO;GACnD,MAAM,8BAAc,IAAI,IAAkC,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC;GAC9E,MAAM,gBAA+B;IACnC,MAAM,UAAU,QAAQ;IACxB,IAAI,aAAa,YAAY,IAAI,OAAO;IACxC,IAAI,eAAe,KAAA,GAAW;KAC5B,aAAa,QAAQ,WAAc,MAAM,OAAO;KAChD,YAAY,IAAI,SAAS,UAAU;IACrC;IACA,OAAO;GACT;GAEA,OAAO;IACL,SAAS,aAAa,QAAQ,CAAC,CAAC,OAAO,QAAQ;IAC/C,MAAM,OAAO,QAAQ,CAAC,CAAC,IAAI,EAAE;IAC7B,OAAO,UAAqC,QAAQ,CAAC,CAAC,KAAK,KAAK;IAChE,SAAS,QAAQ,UAAU,QAAQ,CAAC,CAAC,OAAO,QAAQ,KAAK;IACzD,SAAS,WAAW,QAAQ,CAAC,CAAC,OAAO,MAAM;GAC7C;EACF;EACA,UAAU,UAAU;GAClB,eAAe,QAAQ;GACvB,OAAO,UAAU,QAAQ;EAC3B;CACF;AACF;;;;;;;ACSA,IAAa,sBAAb,cAAyC,sBAAsB;CAC7D,OAAiC;CACjC;CACA;CAEA,YAAY,QAAgB,SAAiB,WAAmB,QAAsB,OAAO;EAC3F,MACE,QACA,UAAU,QAAQ,YAAY,QAAQ,KAAK,wBAAwB,QAAQ,IAC3E,SACF;EACA,KAAK,UAAU;EACf,KAAK,QAAQ;CACf;AACF;;AAGA,SAAgB,eAAe,OAA8B;CAC3D,OAAO,UAAU,aAAa,UAAU,oBAAoB,MAAM,WAAW,UAAU;AACzF;AAEA,SAAgB,2BAA2B,MAA+C;CACxF,OAAO,OAAO,WAAW;EACvB,MAAM,EAAE,SAAS;EAEjB,MAAM,EAAE,QAAQ,aAAa,MAAM,KAAK,QAAQ,QAAQ,IAAI;EAC5D,MAAM,MAAM,KAAK,IAAI,MAAM,EAAE,QAAQ,KAAK,CAAC;EAO3C,MAAM,WAAW,IAAI,SAAS;EAC9B,MAAM,SAAS,SAAuB;GACpC,IAAI,SAAS,SACX,MAAM,IAAI,qBACR,WAAW,KAAK,KAAK,KAAK,mGAE5B;EAEJ;;EAEA,MAAM,UAAU,cAAsC;GACpD,MAAM,QAAQ,IAAI,oBAAoB,MAAM,WAAW,sBAAsB,SAAS,MAAM;GAC5F,IAAI,KAAK,GAAG,UAAU,kDAAkD;IACtE;IACA,KAAK;GACP,CAAC;GACD,OAAO,QAAQ,OAAO,KAAK;EAC7B;EACA,MAAM,QACH,WAAW,QACX,GAAG,SACF,SAAS,UAAU,OAAO,SAAS,IAAI,GAAG,GAAG,IAAI;EAGrD,MAAM,UAAwB,SAAS,MAAM,YAC3C,KAAK,cAAc,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,OAAO,IAAI,MAAM,OAAO;EACnF,MAAM,eAAe,mBAAmB,MAAM,KAAK,MAAM;EACzD,MAAM,eAAe,oBAAoB,MAAM,KAAK,MAAM;EAC1D,MAAM,WAAW,gBAAgB,MAAM,KAAK,MAAM;EAClD,MAAM,WAAW,gBAAgB,GAAG;EAGpC,MAAM,SAAS,KAAK,IAAI,UAAU,MAAM;GACtC,OAAO,UAAW,eAAe,KAAK,IAAI,eAAe,KAAA;GACzD;EACF,CAAC;EACD,MAAM,WAAW,KAAK,SAAS,UAAU,IAAI;EAC7C,MAAM,YAAY,KAAK,UAAU,UAAU,MAAM,QAAQ;EA4FzD,OAAO;GACL,SAAA;IA1FA,QAAQ;KAAE;KAAM,SAAS,OAAO;KAAS;IAAS;IAClD;IACA;IACA,IAAI,SAAsB;KACxB,OAAO,SAAS;IAClB;IACA,UAAU;KACR,IAAI,YAAqC;MACvC,MAAM,cAAc;MACpB,KAAK,OAAO,SAAS,IACnB,MACA,YAAY,MAAM,YAAY,cAAc,UAAU,IAAI,CAC5D;KACF;KACA,YAAY,KAAK,OAAO,SAAS,KAAK,CAAC,CAAC,IAAI,WAAW;IACzD;IACA,OAAO,EACL,OAAO,MAAM,OAAO;KAClB,MAAM,cAAc;KACpB,KAAK,OAAO,MAAM,OAChB,MACA,MACA,cAAc,MAAM,MAAM,OAAO,UAAU,KAAK,UAAU,IAAI,CAChE;IACF,EACF;IACA,UAAU;KACR,MAAM,SAAS,KAAK,SAAS,IAAI,IAAI;KACrC,KAAK,KAAK,iBAAiB,QAAgB,WACzC,KAAK,SAAS,IAAI,QAAQ,MAAM,CAClC;KACA,OAAO,KAAK,mBAAmB,WAAmB,KAAK,SAAS,MAAM,MAAM,CAAC;IAC/E;IACA,eAAe,EACb,OAAO,MAAc,SAA4B;KAC/C,MAAM,sBAAsB;KAC5B,KAAK,cAAc,OACjB,MACA,MACA,SAAS,MAAM,MAAM,SAAS,UAAU,KAAK,UAAU,IAAI,CAC7D;IACF,EACF;IACA,QAAQ,EACN,GAAG,OAAqB,OAAgB,QAA+B;KACrE,MAAM,WAAW;KACjB,OAAQ,OAAO,GAAoB,OAAO,OAAO,MAAM;IACzD,EACF;IACA,UAAU;KACR,QAAQ,SAAS,gBAAgB;MAC/B,MAAM,kBAAkB;MACxB,SAAS,QAAQ,SAAS,cAAc;KAC1C;KACA,MAAM,YAAY,SAAS,IAAI,OAAO;KACtC,MAAM,YAAY,SAAS,IAAI,OAAO;IACxC;IACA,SAAS;KACP,GAAG,kBAAkB,cAAc,KAAK,SAAS,MAAM,KAAK,OAAO,GAAG,IAAI;KAC1E,QAAQ,kBAAkB,cAAc,KAAK,QAAQ,MAAM,KAAK,OAAO,GAAG,IAAI;IAChF;IACA,WAAW;KACT,IAAI,KAAK,iBAAiB,MAAqB,KAAa,YAC1D,UAAU,GAAG,MAAM,KAAK,OAAO,CACjC;KACA,QAAQ,KAAK,qBAAqB,OAAe,UAAU,OAAO,EAAE,CAAC;KACrE,GAAG,KAAK,SAAS;MACf,MAAM,cAAc;MACpB,OAAO,UAAU,GAAG,KAAK,OAAO;KAClC;IACF;IACA,MAAM,aAAa,KAAK,MAAM,IAAI;IAClC,QAAQ;KACN,UAAU,KAAK,oBAAoB,YAAoB,KAAK,OAAO,SAAS,OAAO,CAAC;KACpF,oBAAoB,KAClB,8BACC,GAAG,SACF,KAAK,OAAO,mBAAmB,GAAG,IAAI,CAC1C;IACF;IACA,MAAM,WAAW,MAAM,MAAM,KAAK;IAClC,eAAe,KAAK,UAAU;IAC9B,cAAc,KAAK,UAAU;IAC7B,IAAI,OAAuB;KACzB,OAAO,KAAK,UAAU;IACxB;IACA,QAAQ,KAAK,OAAO,UAAU,MAAM;GAI9B;GACN,QAAQ,QAAwB;IAC9B,SAAS,OACP,UAAU,IAAI,qBAAqB,WAAW,KAAK,uBAAuB,CAC5E;IACA,KAAK,OAAO,SAAS,aAAa,IAAI;IACtC,KAAK,OAAO,MAAM,aAAa,IAAI;IACnC,KAAK,cAAc,aAAa,IAAI;IACpC,KAAK,IAAI,aAAa,IAAI;IAC1B,KAAK,SAAS,aAAa,IAAI;IAC/B,KAAK,UAAU,aAAa,IAAI;IAChC,KAAK,MAAM,YAAY,IAAI;GAC7B;EACF;CACF;AACF;;AAGA,SAAS,WACP,MACA,MACA,OACY;CACZ,IAAI,KAAK,SAAS,KAAA,GAAW;EAC3B,MAAM,gBAAuB;GAC3B,MAAM,IAAI,eACR,WAAW,KAAK,4EAClB;EACF;EACA,OAAO;GACL,IAAI,WAAmB;IACrB,OAAO,QAAQ;GACjB;GACA,OAAO;GACP,IAAI;EACN;CACF;CACA,MAAM,SAAS,KAAK,KAAK,MACvB,YACM,YAAY,SACjB,OAAO,UACN,KAAK,YAAY;EAAE,QAAQ;EAAM,OAAO;EAAQ,OAAO;EAAO;EAAO,UAAU;CAAM,CAAC,CAC1F;CACA,OAAO;EACL,IAAI,WAAW;GACb,OAAO,OAAO;EAChB;EACA,MAAM,QAAQ,MAAM,SAAS;GAC3B,MAAM,YAAY;GAClB,OAAO,MAAM,QAAQ,MAAM,OAAO;EACpC;EACA,GAAG,MAAM,QAAQ;GACf,MAAM,SAAS;GACf,OAAO,GAAG,MAAM,MAAM;EACxB;CACF;AACF;;AASA,SAAS,aAAa,UAAoB,MAAsB;CAC9D,OAAO;EACL,MAAM,KAAK,SAAS,GAAG,SAAuC,SAAS,KAAK,GAAG,IAAI,CAAC;EACpF,OAAO,KAAK,eAAe,GAAG,SAAwC,SAAS,MAAM,GAAG,IAAI,CAAC;EAC7F,MAAM,KAAK,cAAc,GAAG,SAAuC,SAAS,KAAK,GAAG,IAAI,CAAC;EACzF,QAAQ,KAAK,gBAAgB,GAAG,SAC9B,SAAS,OAAO,GAAG,IAAI,CACzB;EACA,QAAQ,KAAK,gBAAgB,GAAG,SAC9B,SAAS,OAAO,GAAG,IAAI,CACzB;CACF;AACF;;;;;AAMA,SAAS,YAAY,SAAwB,MAA2B;CACtE,MAAM,EAAE,OAAO;CAMf,OAAO;EACL,IAAI;GALJ,KAAK,KAAK,mBAAmB,QAAgB,GAAG,IAAI,GAAG,CAAC;GACxD,KAAK,KAAK,mBAAmB,KAAa,UAAqB,GAAG,IAAI,KAAK,KAAK,CAAC;GACjF,QAAQ,KAAK,sBAAsB,QAAgB,GAAG,OAAO,GAAG,CAAC;EAGxD;EACT,WACE,gBACA,SACe;GACf,MAAM,aAAa,QAAQ,WAAc,gBAAgB,OAAO;GAChE,MAAM,MAAM,WAA2B,uBAAuB,eAAe,KAAK;GAElF,OAAO;IACL,QAAQ,KAAK,GAAG,QAAQ,IAAI,aAAgB,WAAW,OAAO,QAAQ,CAAC;IACvE,KAAK,KAAK,GAAG,KAAK,IAAI,OAAe,WAAW,IAAI,EAAE,CAAC;IACvD,MAAM,KAAK,GAAG,MAAM,IAAI,UAAqC,WAAW,KAAK,KAAK,CAAC;IACnF,QAAQ,KACN,GAAG,QAAQ,IACV,QAAoC,UACnC,WAAW,OAAO,QAAQ,KAAK,CACnC;IACA,QAAQ,KAAK,GAAG,QAAQ,IAAI,WAC1B,WAAW,OAAO,MAAM,CAC1B;GACF;EACF;CACF;AACF;;AAGA,SAAS,kBAAkB,SAAwB,MAA2B;CAC5E,OAAO;EACL,GAAG,YAAY,SAAS,IAAI;EAC5B,YAAY,aAAa,YAAY,QAAQ,UAAU,QAAQ,GAAG,IAAI;CACxE;AACF;;;;;;AASA,SAAS,YACP,QACA,YACA,OACA,UACA,MACmB;CACnB,MAAM,EAAE,KAAK,UAAU,SAAS;CAChC,MAAM,YAAY,WAAW,aAAa,KAAK;CAC/C,MAAM,SAAY,OAAqB,YAA0C;EAC/E,MAAM,WAAW,IAAI,SAAS,QAAQ;EACtC,OAAO,aACL,QAAQ,QAAQ,GAChB,iBACM;GACJ,MAAM,QAAQ,IAAI,oBAAoB,QAAQ,MAAM,WAAW,KAAK;GACpE,SAAS,OAAO,KAAK;GACrB,OAAO;EACT,IACC,UAAU,KAAK,mBAAmB,QAAQ,MAAM,KAAK,GACtD,KAAK,OACL,QACF;CACF;CACA,OAAO;EACL,GAAG;EACH,MAAM,QACJ,MAAM,QAAQ,aAAa;GACzB,MAAM,OAAO,MAAM,IAAI,KAAK,QAAQ;GACpC,OAAO,gBAAgB,MAAM,IAAI,IAAI,CAAC;EACxC,CAAC;EACH,GAAI,YAAY,EACd,WAAW,KAAK,cACd,MAAM,aAAa,aAAa,SAAS,MAAM,IAAI,KAAK,QAAQ,GAAG,SAAS,CAAC,EACjF;CACF;AACF;;;;;;AAOA,SAAS,gBAAgB,KAAqB,QAA0B;CACtE,MAAM,UAAU,UACd,OAAO,UAAU,YAAY,YAAY,KAAK,IAAI,IAAI,MAAM,KAAK,IAAI,KAAA;CACvE,OAAOC,aAAW,MAAM,IAAI,QAAQ,QAAQ,MAAM,CAAC,CAAC,KAAK,MAAM,IAAI,OAAO,MAAM;AAClF;;;;;;AAOA,SAAS,cACP,QACA,MACA,OACA,MACA,KACA,UACA,MACW;CACX,MAAM,UAAU,UAA0B;EACxC,KAAK,YAAY;GACf;GACA,OAAO;GACP,OAAO;GACP;GACA,UAAU,iBAAiB;EAC7B,CAAC;EACD,OAAO;CACT;CACA,QAAQ,QAAQ;EACd,MAAM,WAAW,IAAI,SAAS,QAAQ;EACtC,IAAI;EACJ,IAAI;GACF,SAAS,MAAM,KAAK,KAAK,QAAQ,CAAC;EACpC,SAAS,OAAO;GACd,OAAO,OAAO,KAAK;EACrB;EACA,MAAM,UAAU,aACd,QACA,KAAK,wBACC;GACJ,MAAM,QAAQ,IAAI,iBAAiB,QAAQ,MAAM,KAAK,gBAAgB;GACtE,SAAS,OAAO,KAAK;GACrB,OAAO;EACT,IACC,UAAU,IAAI,MAAM,UAAU,KAAK,6BAA6B;GAAE;GAAM,KAAK;EAAM,CAAC,GACrF,KAAK,KACP;EACA,IAAI,EAAE,mBAAmB,UAAU,OAAO,YAAY;EACtD,OAAO,QAAQ,MAAM,YAAY,YAAY,MAAM,MAAM;CAC3D;AACF;;;;;;AAOA,SAAS,SACP,QACA,MACA,SACA,MACA,KACA,UACA,MACkC;CAClC,MAAM,YAAY,KAAK;CACvB,QAAQ,KAAK,SAAS;EACpB,MAAM,WAAW,IAAI,SAAS,QAAQ;EACtC,OAAO,aACL,QAAQ,KAAK,KAAK,UAAU,MAAM,IAAI,CAA2B,GACjE,iBACM;GACJ,MAAM,QAAQ,IAAI,iBAAiB,QAAQ,MAAM,SAAS;GAC1D,SAAS,OAAO,KAAK;GACrB,OAAO;EACT,IACC,UAAU;GAET,IAAI,iBAAiB,qBAAqB;GAC1C,IAAI,MAAM,UAAU,KAAK,6BAA6B;IAAE;IAAM,KAAK;GAAM,CAAC;EAC5E,GACA,KAAK,OACL,QACF;CACF;AACF;;;ACheA,SAAgB,kBAAkB,EAChC,WACA,KACA,SACA,SACA,UACkC;CAClC,MAAM,SAAS,IAAI,mBAAmB;EAAE,GAAG;EAAS;CAAQ,CAAC;CAC7D,MAAM,EAAE,iBAAiB;CACzB,IAAI,SAAS;CACb,IAAI,UAAU;CACd,IAAI;CACJ,IAAI;CAKJ,IAAI;CAEJ,SAAS,SAAS,UAAuB;EACvC,QAAQ,iBAAiB;GACvB,QAAQ,KAAA;GACR,WAAW,QAAQ,QAAQ,CAAC,CAAC,MAAM,WAAW;IAC5C,WAAW,KAAA;IAIX,MAAM,SAAS,YAAY,SAAS;KADP,QAAQ;KAAU,QAAQ;KAAmB,OAAO;IAC1C,IAAI,KAAA;IAC3C,UAAU,KAAA;IACV,IAAI,QAAQ,aAAa,MAAM;GACjC,CAAC;EACH,GAAG,SAAS,OAAO;CACrB;;CAGA,eAAe,QAAQ,UAAmC;EACxD,IAAI,SAAS,OAAO;EACpB,IAAI;GACF,IAAI,SAAS,WAAW,iBAAiB,MAAM,eAAe;GAC9D,IAAI,SAAS,OAAO;GACpB,MAAM,UAAU,QAAQ;GACxB,OAAO;EACT,SAAS,OAAO;GACd,IAAI,CAAC,CAAC,MAAM,oBAAoB;IAAE,KAAK;IAAO,QAAQ,SAAS;GAAO,CAAC;GACvE,OAAO;EACT;CACF;;;;;;CAOA,SAAS,QACP,OACA,QACM;EACN,QAAQ,OAAR;GACE,KAAK;IACH,IAAI,CAAC,CAAC,MACJ,qJAEA,MACF;IACA;GACF,KAAK;IACH,IAAI,CAAC,CAAC,MACJ,yJAEA,MACF;IACA;GACF,KAAK;IACH,IAAI,CAAC,CAAC,MACJ,6JAEA,MACF;IACA;EACJ;CACF;CAEA,SAAS,aAAa,QAA4B;EAChD,IAAI,SAAS;EAEb,IAAI,UAAU,KAAA,GAAW;EAEzB,IAAI,CAAC,UAAU,aAAa,KAAA,GAAW;GACrC,UAAU;GACV;EACF;EACA,MAAM,WAAW,OAAO,OAAO,OAAO,MAAM;EAC5C,MAAM,SAAS;GAAE,QAAQ,OAAO;GAAQ,KAAK,OAAO;GAAO,GAAG;GAAU,GAAG,OAAO;EAAM;EACxF,IAAI,SAAS,WAAW,QAAQ;GAC9B,QAAQ,SAAS,OAAO,MAAM;GAC9B,OAAO,QAAQ;GACf;EACF;EACA,IAAI,SAAS,WAAW,mBAAmB,iBAAiB,KAAA,GAAW;GACrE,IAAI,CAAC,CAAC,MACJ,sBAAsB,OAAO,OAAO,6FAEpC,MACF;GACA,OAAO,QAAQ;GACf;EACF;EACA,IAAI,CAAC,CAAC,KACJ,oBAAoB,OAAO,OAAO,qBAAqB,SAAS,QAAQ,MACxE,MACF;EACA,SAAS,QAAQ;CACnB;CAEA,OAAO;EACL,SAAS,QAAQ;GACf,QAAQ,OAAO,QAAf;IACE,KAAK;KACH,UAAU,KAAA;KACV,OAAO,UAAU;KACjB,IAAI,CAAC,CAAC,KAAK,gBAAgB;KAC3B;IACF,KAAK;KACH,IAAI,CAAC,CAAC,MAAM,YAAY;KACxB;IACF,KAAK;KACH,aAAa,MAAM;KACnB;GACJ;EACF;EAEA,OAAO;GACL,OAAO,YAAY;EACrB;EAEA,WAAW;GACT,SAAS;GACT,MAAM,SAAS;GACf,UAAU,KAAA;GACV,IAAI,QAAQ,aAAa,MAAM;EACjC;EAEA,MAAM,OAAO;GACX,UAAU;GACV,aAAa,KAAK;GAClB,QAAQ,KAAA;GACR,MAAM;EACR;CACF;AACF;;;ACpMA,MAAM,gBAAgB,OAAO,IAAI,gCAAgC;;;;;AAWjE,SAAgB,aAAa,SAAsB,SAA6C;CAC9F,MAAM,UAAU;CAChB,IAAI,OAAO,QAAQ;CACnB,IAAI,SAAS,KAAA,GAAW;EACtB,uBAAO,IAAI,IAAI;EAEf,IAAI,CADW,QAAQ,eAAe,SAAS,eAAe,EAAE,OAAO,KAAK,CAClE,GAAG,OAAO,KAAA;CACtB;CACA,IAAI,KAAK,IAAI,OAAO,GAClB,MAAM,IAAI,eACR,WAAW,QAAQ,2HAErB;CAEF,KAAK,IAAI,OAAO;CAChB,MAAM,WAAW;CACjB,aAAa;EACX,SAAS,OAAO,OAAO;EACvB,OAAO,SAAS,SAAS;CAC3B;AACF;;;;AC1BA,MAAa,uBAAuB;;AAEpC,MAAa,yBAAyB;;;;;;;AAuBtC,eAAsB,oBACpB,SACmC;CACnC,MAAM,EAAE,SAAS,SAAS,KAAK,QAAQ,WAAW;CAClD,MAAM,EAAE,cAAc,iBAAiB;CACvC,IAAI,iBAAiB,KAAA,KAAa,iBAAiB,KAAA,GAAW,OAAO,KAAA;CACrE,MAAM,OAAO,WAAW;CACxB,MAAM,QAAQ,WAAW;CACzB,MAAM,gBACJ,aAAa,KAAK,SAAS,MAAM,OAAO,oBAAoB;CAE9D,KAAK,IAAI,SAAS,GAAG,CAAE,MAAM,QAAQ,GAAI,UAAU,wBAAwB;EACzE,IAAI,UAAA,KACF,MAAM,IAAI,eACR,WAAW,QAAQ,kKAGrB;EAEF,IAAI,WAAW,GACb,IAAI,KAAK,+DAA+D;GACtE;GACA,OAAO;EACT,CAAC;EAEH,MAAM,eAAe,wBAAwB,MAAM;CACrD;CAEA,IAAI,OAAO;CACX,IAAI;CACJ,MAAM,QAAQ,YAA2B;EACvC,IAAI;GACF,IAAI,MAAM,QAAQ,GAAG;GACrB,OAAO;GACP,cAAc,KAAK;GACnB,OAAO;EACT,SAAS,OAAO;GAEd,IAAI,KAAK,qEAAqE;IAC5E;IACA,KAAK;GACP,CAAC;EACH;CACF;CACA,MAAM,QAAQ,kBAAkB;EAE9B,aAAa,MAAM,CAAC,CAAC,cAAc;GACjC,WAAW,KAAA;EACb,CAAC;CACH,GAAG,sBAAsB;CAEzB,MAAM,QAAQ;CAEd,OAAO,EACL,MAAM,UAAyB;EAC7B,cAAc,KAAK;EAEnB,MAAM;EACN,IAAI,CAAC,MAAM,MAAM,aAAa,KAAK,SAAS,MAAM,KAAK;CACzD,EACF;AACF;;AAGA,SAAS,eAAe,IAAY,QAAoC;CACtE,IAAI,OAAO,SAAS,OAAO,QAAQ,OAAO,OAAO,MAAM;CACvD,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,gBAAsB;GAC1B,aAAa,KAAK;GAClB,OAAO,OAAO,MAAM;EACtB;EACA,MAAM,QAAQ,iBAAiB;GAC7B,OAAO,oBAAoB,SAAS,OAAO;GAC3C,QAAQ;EACV,GAAG,EAAE;EACL,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;CAC1D,CAAC;AACH;;;;AC5FA,IAAa,gBAAb,cAAmC,MAAM;CACvC;;CAEA;CAEA,YAAY,UAAkB,SAAiB,UAAmB,OAAiB;EACjF,MAAM,qBAAqB,SAAS,KAAK,WAAW,EAAE,MAAM,CAAC;EAC7D,KAAK,OAAO;EACZ,KAAK,WAAW;EAChB,KAAK,WAAW;CAClB;AACF;;;;;AAeA,eAAsB,aACpB,OACA,UAA2B,CAAC,GACF;CAC1B,MAAM,gBAAgB,QAAQ,iBAAA;CAC9B,MAAM,WAAW,KAAK,IAAI,KAAK,QAAQ,aAAA;CACvC,MAAM,SAA0B,CAAC;CAEjC,KAAK,MAAM,SAAS,OAAO;EACzB,MAAM,YAAY,WAAW,KAAK,IAAI;EACtC,IAAI,aAAa,GAAG;GAElB,OAAO,KAAK,IAAI,cAAc,MAAM,MAAM,uCAAuC,IAAI,CAAC;GACtF;EACF;EACA,MAAM,QAAQ,MAAM,OAAO,OAAO,KAAK,IAAI,MAAM,aAAa,eAAe,SAAS,CAAC;EACvF,IAAI,OAAO,OAAO,KAAK,KAAK;CAC9B;CACA,OAAO;AACT;AAEA,eAAe,OACb,OACA,WACoC;CACpC,MAAM,aAAa,IAAI,gBAAgB;CACvC,IAAI;CACJ,MAAM,UAAU,IAAI,SAAwB,YAAY;EACtD,QAAQ,iBAAiB;GACvB,WAAW,MAAM;GACjB,QAAQ,IAAI,cAAc,MAAM,MAAM,WAAW,UAAU,MAAM,IAAI,CAAC;EACxE,GAAG,SAAS;CACd,CAAC;CAED,MAAM,MAAM,QAAQ,QAAQ,CAAC,CAC1B,WAAW,MAAM,KAAK,WAAW,MAAM,CAAC,CAAC,CACzC,WACO,KAAA,IACL,UAAmB,IAAI,cAAc,MAAM,MAAM,UAAU,OAAO,KAAK,CAC1E;CACF,IAAI;EACF,OAAO,MAAM,QAAQ,KAAK,CAAC,KAAK,OAAO,CAAC;CAC1C,UAAU;EACR,aAAa,KAAK;CACpB;AACF;;;;ACoKA,IAAa,gBAAb,cAAmC,MAAM;CACvC;CAEA,YAAY,SAAiB,OAAiB;EAC5C,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,QAAQ;CACf;AACF;;AAGA,MAAM,6BAA6B;;AAGnC,MAAM,gCAAgC;;;;;;AAOtC,MAAM,gBAAgB;CACpB,cAAc;CACd,SAAS;CACT,WAAW;CACX,SAAS;CACT,UAAU;AACZ;AAwBA,MAAM,gBAA6B;CAAE,MAAM;CAAM,QAAQ;CAAO,SAAS;AAAM;;;;AAK/E,MAAM,gBAAyF;CAC7F,oBAAoB,aAAa;EAC/B,MAAM,QAAQ;EACd,QAAQ,QAAQ;EAChB,SAAS,QAAQ,WAAW,UAAU;CACxC;CACA,WAAW,aAAa;EACtB,MAAM,QAAQ;EACd,QAAQ,QAAQ;EAChB,SAAS,QAAQ,OAAO,UAAU;CACpC;CACA,cAAc,aAAa;EACzB,MAAM,QAAQ;EACd,QAAQ,QAAQ;EAChB,SAAS,QAAQ,OAAO,UAAU;CACpC;CAGA,sBAAsB;CACtB,oBAAoB;CACpB,uBAAuB,aAAa;EAAE,MAAM,QAAQ;EAAM,QAAQ;EAAO,SAAS;CAAM;CACxF,kBAAkB,aAAa;EAAE,MAAM,QAAQ;EAAM,QAAQ;EAAO,SAAS;CAAM;CAEnF,yBAAyB;AAC3B;;;;;AAMA,MAAM,aAAa;AAEnB,MAAM,wBAAwB;AAC9B,MAAM,YAAY;AAElB,MAAM,sBAAsB;CAC1B,YAAY;CACZ,YAAY;CACZ,YAAY;CACZ,WAAW;CACX,UAAU;AACZ;;;;;;;AAQA,SAAgB,UAAU,QAAwB;CAChD,MAAM,UAAU,gBAAgB,OAAO,WAAA,SAA0B;CAEjE,MAAM,QAA8B,CAAC;CACrC,IAAI,QAAkB;CACtB,IAAI,gBAAgB;CACpB,IAAI;CACJ,IAAI;CACJ,IAAI;CAIJ,IAAI,MAAc,iBAAiB;CACnC,MAAM,eAAuB;CAC7B,MAAM,UAAU,OAAO,WAAW,gBAAgB;CAClD,MAAM,UAAU,OAAO,WAAW,oBAAoB;CAEtD,MAAM,SAAS,eAAe,SAAS,OAAO;CAC9C,MAAM,OAAO,QAAQ,UAAU,OAAO;CAGtC,IAAI;CAGJ,MAAM,UAAU,qBAAqB;EACnC,YAAY,SAAS,KAAK;EAC1B,UAAU,UACR,IAAI,MAAM,qDAAqD,EAAE,KAAK,MAAM,CAAC;CACjF,CAAC;CACD,MAAM,WAAW,sBAAsB,EAAE,gBAAgB,QAAQ,QAAQ,EAAE,CAAC;CAE5E,MAAM,OAAO,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY,YAAY,OAAO,MAAM,SAAS,MAAM;CAC7F,IAAI;CACJ,MAAM,YAAY,iBAAiB,OAAO,WAAW;EACnD;EACA;EACA,KAAK,2BAA2B,gBAAgB,GAAG;EACnD,UAAU,QAAQ;EAClB,GAAI,QAAQ,EACV,MAAM,KAAK,MACT,6BACM;GACJ,IAAI,sBAAsB,KAAA,GACxB,MAAM,IAAI,MAAM,+DAA+D;GAEjF,OAAO,eAAe,mBAAmB,kBAAkB,IAAI;EACjE,IACC,OAAO,UAAU,IAAI,MAAM,QAAQ,MAAM,uBAAuB,EAAE,KAAK,MAAM,CAAC,CACjF,EACF;CACF,CAAC;CACD,oBAAoB;CAEpB,IAAI,eAAe;CACnB,IAAI;CAEJ,IAAI;CAEJ,MAAM,YAAY,IAAI,gBAAgB;CAEtC,IAAI,gBAAgB;CAEpB,IAAI;CACJ,MAAM,WAAW,OAAO,YAAY,CAAC;CACrC,MAAM,mBAAmB,SAAS,aAAa;CAI/C,MAAM,QAAQ,IAAI,YAAY;CAC9B,MAAM,MAAM,eAAe;EACzB,mBAAmB,SAAS;EAC5B;EACA,UAAU,UAAU,eAAe,KAAK;CAC1C,CAAC;CACD,MAAM,WAAW,sBAAsB;CACvC,MAAM,WAAW,kBAAkB,OAAO,QAAQ,MAAM;CACxD,MAAM,SAAS,oBAAoB;EACjC;EACA,SAAS,SAAS,SAAS,IAAI,IAAI;EACnC,oBAAoB,UAAU,MAAM;EACpC,QAAQ,gBAAgB,OAAO,UAAU,CAAC,CAAC;EAC3C,cAAc,eACZ,WACA,mBACC,UAAU,IAAI,KAAK,qDAAqD,EAAE,KAAK,MAAM,CAAC,GACvF,KACF;EAEA,gBAAgB,MAAM,YACpB,IAAI,MACF,YAAY,QAAQ,KAAK,mBAAmB,KAAK,wFACG,QAAQ,OAAO,KACnE;GAAE,QAAQ,QAAQ;GAAQ,SAAS,QAAQ;GAAM;EAAK,CACxD;CACJ,CAAC;CACD,MAAM,gBAAgB,IAAI,qBAA2C;CAGrE,cAAc,OAAO,YAAY,iBAAiB,KAAA,CAAS;CAC3D,MAAM,UAAU,IAAI,eAAe;CAInC,MAAM,+BAAe,IAAI,QAA8B;CACvD,MAAM,UAAU,cAAc,WAAW,SAAS;CAClD,MAAM,aAAa,YAAY,SAAS;CACxC,MAAM,WAAW,eACf,OAAO,eAAe,CAAC,GACvB,SAAS,gBAAgB,+BACzB,MACF;CAEA,MAAM,oBAAoB,OAAO,aAAa;CAC9C,MAAM,gBAAgB,oBAAoB,YAAY,iBAAiB,UAAU;CACjF,MAAM,YAAY,OAAO,aAAa,eAAe;CACrD,MAAM,YAAY,OAAO,aAAa,eAAe;CACrD,MAAM,UAAU,IAAI,aAAa;EAC/B,mBAAmB,OAAO,SAAS;EACnC,UAAU,OAAO,WAAW,IAAI,MAAM,+BAA+B;GAAE;GAAQ,KAAK;EAAM,CAAC;CAC7F,CAAC;CACD,MAAM,WAAW,IAAI,cAAc;EACjC,gBAAgB,OAAO,WACrB,IAAI,MAAM,iCAA+B;GAAE;GAAQ,KAAK;EAAM,CAAC;EACjE,GAAG,OAAO;EACV;CACF,CAAC;CAED,MAAM,OAAO,eAAe,UAAU,SAAS;CAC/C,MAAM,SAAS,aAAa,WAAW,cAAc,UAAU,SAAS,CAAC;CAEzE,MAAM,eAAwC,IAAI,IAAI,UAAU,YAAY;CAG5E,MAAM,UAAU,IAAI,YAAY;CAChC,MAAM,YAAY,uBAAuB;EACvC,SAAS;EACT;EACA,cAAc,SAAS;EACvB,UAAU,UAAU;GAClB,eAAe,KAAK;GACpB,IAAS,KAAK,gBAAgB,KAAK;EACrC;EACA,cAAc,UAAU,eAAe,KAAK;EAC5C,iBAAiB,UAAU,IAAI,MAAM,+BAA+B,EAAE,KAAK,MAAM,CAAC;CACpF,CAAC;CACD,MAAM,cAAkC;EACtC,QAAQ;EACR,OAAO,cAAc,WAAW,QAAQ;EACxC,KAAK;EACL,SAAS;CACX;CACA,MAAM,cACJ,OAAO,iBAAiB,QACpB,KAAA,IACA,kBAAkB;EAChB;EACA,KAAK;EACL,SAAS;GACP,GAAG,OAAO;GAGV,cACE,OAAO,cAAc,iBACpB,OAAO,OAAO,cAAc,mBAAmB,KAAK,MAAM,IAAI,KAAA;EACnE;EACA,SAAS,cAAc,WAAW,SAAS;EAC3C,cAAc;GAEZ,IAAI,KAAK,CAAC,CAAC,OAAO,UAAmB,IAAI,MAAM,wBAAwB,EAAE,KAAK,MAAM,CAAC,CAAC;EACxF;CACF,CAAC;CAEP,IAAI;CACJ,IAAI;CACJ,IAAI,SAAS;CAGb,IAAI,QAAQ;CACZ,IAAI,oBAA2C,KAAA;CAC/C,MAAM,eAAe,IAAI,SAAkB,YAAY;EACrD,eAAe,OAAO;GACpB,oBAAoB,KAAA;GACpB,QAAQ;GACR,QAAQ,EAAE;EACZ;CACF,CAAC;CAED,SAAS,eAAe,OAA+B;EACrD,IAAI,MAAM,WAAW,MAAM,OAAO,YAAY,MAAM,MAAM,IAAI;GAC5D,QAAQ,MAAM;GACd,OAAO,MAAM;GACb,OAAO,MAAM;GACb,UAAU,MAAM;GAChB,KAAK,MAAM;EACb,CAAC;CACH;;CAGA,SAAS,mBAAmB,OAAmC;EAC7D,MAAM,QAAQ,MAAM,UAAU,aAAa,MAAM,UAAU,UAAU,UAAU;EAC/E,IAAS,KAAK,gBAAgB;GAC5B,QAAQ,MAAM;GACd;GACA,OAAO;GACP,OAAO,MAAM,SAAS;GACtB,UAAU,MAAM;EAClB,CAAC;CACH;;;;;;CASA,eAAe,MACb,SACA,QACe;EACf,IAAI,CAAC,SAAS,CAAE,MAAM,cAAe;EACrC,MAAM,SAAS,IAAI,qBAAqB,SAAS,WAAW,GAAG,MAAM;CACvE;CAEA,SAAS,cAAc,SAAiC;EACtD,OAAO,MAAM,SAAS,eAAe;CACvC;CAEA,eAAe,gBAAgB,KAA0C;EACvE,MAAM,EAAE,YAAY;EAGpB,MAAM,UAAU,cAAc,KAAK,QAAQ,KAAK,IAAI,QAAQ,OAAO,EAAE;EACrE,IAAI,YAAY,KAAA,KAAa,OAAO,MAAM,SAAS,IAAI,IAAI,MAAM,MAAM;GACrE,IAAI,QAAQ,WAAW,YAAY;IACjC,MAAM,QAAQ,KAAK,OAAO;IAC1B;GACF;GAEA,MAAM,SAAS,WAAW,KAAK,QAAQ,IAAI;GAC3C,IAAI,WAAW,KAAA,GAAW;IACxB,MAAM,UAAU,KAAK,MAAM;IAC3B;GACF;EACF;EACA,MAAM,SAAS,MAAM,OAAO,SAAS,GAAG;EACxC,IAAI,CAAC,OAAO,UAAU;GACpB,MAAM,IAAI,KAAK,WAAW,SAAS,eAAe,GAAG,CAAC;GACtD;EACF;EACA,MAAM,aAAa,KAAK,MAAM;CAChC;;CAGA,eAAe,aACb,KACA,QACe;EACf,MAAM,EAAE,YAAY;EACpB,IAAI,OAAO,WAAW,cAAc,OAAO,UAAU,MAEnD,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC,OAAO,UAC7B,IAAI,IAAI,KAAK,uCAAuC;GAClD,QAAQ,OAAO,QAAQ;GACvB,SAAS,OAAO,QAAQ;GACxB,KAAK;EACP,CAAC,CACH;OACK,IAAI,OAAO,WAAW,UAAU;GACrC,MAAM,QAA0B;IAC9B,QAAQ,OAAO,QAAQ;IACvB,OAAO;IACP,OAAO,OAAO,QAAQ;IACtB,OAAO,OAAO;IACd,UACE,OAAO,iBAAiB,uBACxB,OAAO,iBAAiB;GAC5B;GACA,eAAe,KAAK;GACpB,IAAS,KAAK,gBAAgB,KAAK;EACrC;EAEA,MAAM,EAAE,QAAQ,MAAM,cAAc,OAAO;EAC3C,MAAM,IAAI,KAAK,WAAW;GAAE;GAAQ;GAAM;GAAW,QAAQ,OAAO;GAAQ;EAAQ,CAAC;CACvF;;;;;CAMA,eAAe,QACb,KACA,SACe;EACf,IAAI;GACF,MAAM,QAAQ,IAAI,KAAK,QAAQ,IAAI;EACrC,SAAS,OAAO;GACd,MAAM,QAA0B;IAC9B,QAAQ,QAAQ;IAChB,OAAO;IACP,OAAO,QAAQ;IACf;IACA,UAAU,iBAAiB;GAC7B;GACA,eAAe,KAAK;GACpB,IAAS,KAAK,gBAAgB,KAAK;EACrC;CACF;;;;;CAQA,SAAS,eAAe,OAAsB,SAAkC;EAC9E,QAAQ,MAAM,SAAS;GACrB,MAAM,UAAU,KAAK,KAAK,WAAW,aAAa,OAAO,MAAM,CAAC;GAChE,MAAM,SAAS,QAAQ,KAAK;GAC5B,MAAM,MAAM,QAAQ,KAAK,WAAW,QAAQ,SAAS,QAAQ,MAAM,CAAC;GACpE,MAAM,SAAS,QAAQ,KAAK,EAAE,YAAY,KAAK;GAC/C,IAAI,WAAW,IAAI,UAAU,YAC3B,OAAO;IAAE;IAAM,SAAS,IAAI,KAAK,IAAI,WAAW;KAAE;KAAI,OAAO,OAAO;IAAiB,EAAE;GAAE;GAE3F,cAAc,OAAO,YAAY,QAAQ,QAAQ,OAAO,IAAI,WAAW,EAAE,MAAM,IAAI,CAAC;GACpF,OAAO,EAAE,MAAM,aAAa,MAAM,MAAM,EAAE;EAC5C;CACF;;CAGA,SAAS,aAAa,OAAsB,QAAqC;EAC/E,MAAM,QAAiB,QAAQ;EAC/B,IAAI,OAAO,UAAU,YAAY,MAAM,KAAK,CAAC,CAAC,WAAW,GACvD,MAAM,IAAI,UAAU,kBAAkB;EAExC,IAAI,aAAa,QAAQ;GACvB,IAAI,OAAO,SAAS,KAAK,OAAO,OAAO,MAAM,KAAA,GAC3C,MAAM,IAAI,UAAU,SAAS,MAAM,cAAc,OAAO,QAAQ,iBAAiB;GAEnF,OAAO;IACL,MAAM;IACN;IACA,SAAS,OAAO;IAChB,MAAM,OAAO,OAAO,CAAC,GAAI,OAAO,QAAQ,CAAC,CAAE,CAAC;GAC9C;EACF;EACA,IAAI,UAAU,QAAQ;GACpB,IAAI,UAAU,MACZ,MAAM,IAAI,UAAU,SAAS,MAAM,qCAAqC;GAE1E,IAAI,cAAc,KAAK,OAAO,OAAO,IAAI,MAAM,KAAA,GAC7C,MAAM,IAAI,UACR,SAAS,MAAM,aAAa,MAAM,iBAAiB,OAAO,KAAK,yCAEjE;GAEF,OAAO;IAAE,MAAM;IAAQ;IAAO,QAAQ;IAAO,MAAM,OAAO;IAAM,MAAM,OAAO,QAAQ;GAAK;EAC5F;EACA,MAAM,IAAI,UAAU,SAAS,MAAM,+BAA+B;CACpE;;CAGA,SAAS,WAAW,KAA2B,MAAyC;EACtF,MAAM,MAAM;EACZ,MAAM,QAAQ,WAAW,IAAI,MAAM,IAAI,MAAM;EAC7C,IAAI,UAAU,MAAM,OAAO,KAAA;EAC3B,OAAO,QAAQ,QAAQ,IAAI,QAAkB,IAAI,QAAQ,KAAK,EAAE;CAClE;;;;;;CAOA,eAAe,kBAAkB,aAAyC;EACxE,IAAI,YAAY,YAAY,KAAA,GAAW,OAAO,oBAAoB,WAAW;EAC7E,MAAM,EAAE,MAAM,QAAQ,aAAa;EACnC,MAAM,SAAS,QAAQ,QAAQ,UAAU,KAAK,EAAE;EAChD,IAAI,WAAW,KAAA,GAAW;GACxB,IAAI,MAAM,uDAAuD,EAAE,QAAQ,KAAK,GAAG,CAAC;GACpF;EACF;EACA,MAAM,UAAU,cAAc;GAC5B,MAAM;GACN,IAAI,YAAY;GAChB;GACA;GACA,MAAM,OAAO;GACb,WAAW,YAAY;GACvB,QAAQ;EACV,CAAC;EACD,aAAa,IAAI,SAAS,WAAW;EACrC,MAAM,MAAM,SAAS,OAAO,QAAQ;GAElC,cAAc,KAAK,KAAK,IAAI,OAAO,EAAE;GACrC,MAAM,UAAU,KAAK,MAAM;EAC7B,CAAC;CACH;;;;;CAMA,eAAe,oBAAoB,aAAgD;EACjF,MAAM,EAAE,MAAM,QAAQ,SAAS,SAAS;EACxC,MAAM,UAAU,cAAc;GAC5B,MAAM;GACN,IAAI,YAAY;GAChB;GACA;GAGA,MAAM,KAAK,KAAK,MAAM,KAAK,IAAI,YAAY,IAAI,QAAQ,GAAG,KAAK,UAAU;GACzE,WAAW,YAAY;GACvB,QAAQ;EACV,CAAC;EACD,aAAa,IAAI,SAAS,WAAW;EACrC,MAAM,MAAM,SAAS,OAAO,QAAQ;GAElC,cAAc,KAAK,KAAK,IAAI,OAAO,EAAE;GACrC,MAAM,SAAS,MAAM,OAAO,SAAS,KAAK;IAAE;IAAS,SAAS;GAAK,CAAC;GACpE,IAAI,CAAC,OAAO,UAAU;IACpB,IAAI,IAAI,MAAM,kDAAkD,EAAE,QAAQ,CAAC;IAC3E;GACF;GACA,MAAM,aAAa,KAAK,MAAM;EAChC,CAAC;CACH;;CAGA,eAAe,UAAU,KAA2B,QAAqC;EACvF,IAAI,OAAO,SAAS,WAAW;GAC7B,MAAM,SAAS,MAAM,OAAO,SAAS,KAAK;IAAE,SAAS,OAAO;IAAS,MAAM,OAAO;GAAK,CAAC;GACxF,IAAI,CAAC,OAAO,UAAU;IACpB,IAAI,IAAI,MAAM,oDAAoD,EAChE,SAAS,OAAO,QAClB,CAAC;IACD;GACF;GACA,MAAM,aAAa,KAAK,MAAM;GAC9B;EACF;EACA,MAAM,MAAM,cAAc,KAAK,OAAO,QAAQ,OAAO,IAAI;EACzD,IAAI,QAAQ,KAAA,GAAW;GACrB,IAAI,IAAI,MAAM,kDAAkD;IAC9D,QAAQ,OAAO;IACf,MAAM,OAAO;GACf,CAAC;GACD;EACF;EACA,MAAM,QAAQ,KAAK;GAAE,QAAQ,OAAO;GAAQ,MAAM,OAAO;GAAM,MAAM,OAAO;GAAM;EAAI,CAAC;CACzF;;CAGA,SAAS,eAAe,KAAsD;EAC5E,OAAO,cAAc,GAAG;CAC1B;;;;;CAMA,SAAS,aAAa,SAAiC;EACrD,OAAO,MAAM,SAAS,OAAO,QAAQ;GACnC,MAAM,IAAI,KAAK,kBAAkB,IAAI,SAAS,eAAe,GAAG,CAAC;EACnE,CAAC;CACH;;;;;CAMA,SAAS,QACP,MACA,QACM;EACN,MAAM,SAAS,QAAQ,QAAQ,KAAK,KAAK,UACvC,QAAQ,IAAI,KAAK,KAAK,gBAAgB,OAAO,IAAI,CAAC,CACpD;EACA,IAAI,WAAW,UACb,IAAI,KAAK,4CAA4C;GACnD,QAAQ,KAAK,KAAK;GAClB,WAAW,KAAK;GAChB,QAAQ;EACV,CAAC;CAEL;;;;;CAMA,SAAS,QAA+B,OAAsB;EAC5D,MAAM,SAAS,cAAc;EAC7B,OAAO,UAAU,GAAG,QAAQ,qBAAqB;GAE/C,MAAM,UAAU;GAChB,MAAM,EAAE,MAAM,QAAQ,YAAY,OAAO,OAAO;GAChD,IAAK,UAAU,aAAe,WAAW,WAAY;GACrD,IAAI,SAAS,QAAQ,CAAC,cAAc,IAAI,GAAG;GAG3C,MAAM,SAAS,UAAU,UAAU,QAAQ,KAAK,WAAW,KAAA;GAC3D,QAAQ,IAAI,cAAc;IACxB,IAAI,OAAO;KACT,IAAS,KAAK,OAAO,OAAO;KAC5B;IACF;IAEA,aAAkB,MAAM,OAAO;KAC7B,IAAI,IAAI,IAAS,KAAK,OAAO,OAAO;IACtC,CAAC;GACH,CAAC;EACH,CAAC;CACH;;CAGA,SAAS,qBAAiC;EACxC,MAAM,OAAuB;GAC3B,UAAU,GAAG,YAAY,YAAY,QAAQ,SAAS,aAAa,CAAC;GACpE,UAAU,GAAG,mBAAmB,YAAY,QAAQ,SAAS,YAAY,CAAC;GAC1E,UAAU,GAAG,gBAAgB,gBAAgB,QAAQ,aAAa,iBAAiB,CAAC;GACpF,UAAU,GAAG,sBAAsB,WAAW;IAE5C,IAAI,OAAO,WAAW,UAAU,SAAS,MAAM;SAC1C,IAAI,OAAO,WAAW,QAAQ,SAAS,OAAO;IACnD,aAAa,SAAS,MAAM;IAC5B,IAAS,KAAK,qBAAqB,MAAM;GAC3C,CAAC;GACD,UAAU,GAAG,kBAAkB,YAAY;IACzC,aAAa,KAAK;IAGlB,IAAI,KAAK,8DAA8D;IACvE,IAAI,MAAM,6BAA6B,EAAE,IAAI,QAAQ,GAAG,CAAC;IACzD,IAAS,KAAK,iBAAiB,OAAO;GACxC,CAAC;GACD,UAAU,GAAG,4BAA4B,YAAY;IAEnD,aAAa,KAAK;IAClB,IAAI,KAAK,4EAA4E;IACrF,IAAI,MAAM,iCAAiC,EAAE,MAAM,QAAQ,KAAK,CAAC;IACjE,IAAS,KAAK,2BAA2B,OAAO;GAClD,CAAC;EACH;EACA,KAAK,MAAM,SAAS,OAAO,KAAK,aAAa,GAAoB,KAAK,KAAK,QAAQ,KAAK,CAAC;EACzF,aAAa;GACX,KAAK,MAAM,OAAO,KAAK,OAAO,CAAC,GAAG,IAAI;EACxC;CACF;;;;;CAQA,SAAS,wBAA8B;EACrC,MAAM,QAAQ,MAAc,WAAmB,SAAyB;GACtE,MAAM,KAAK;IAAE;IAAM;IAAW;GAAK,CAAC;EACtC;EACA,KAAK,iBAAiB,cAAc,WAAW,WAAW;GAGxD,IAAI,SAAS,QAAQ,OAAO,SAAS,MAAM,EAAE,OAAO,MAAM,CAAC;GAE3D,OAAO,iBAAiB,eAAe,KAAK,SAAS,MAAM,EAAE,OAAO,MAAM,CAAC,GAAG,EAC5E,MAAM,KACR,CAAC;GACD,OAAO,SAAS,MAAM;EACxB,CAAC;EAED,KAAK,WAAW,cAAc,SAAS,OAAO,WAAW;GACvD,MAAM,SAAU,MAAM,MAAM,KAAK,MAAM,KAAM,CAAC;GAC9C,IAAI,OAAO,SAAS,GAClB,MAAM,IAAI,eAAe,QAAQ,aAAa,OAAO,OAAO,oBAAoB;EAEpF,CAAC;EACD,KAAK,aAAa,cAAc,YAAY,WAAW,UAAU,KAAK,MAAM,CAAC;EAC7E,KAAK,mBAAmB,cAAc,UAAU,WAAW;GACzD,OAAO,iBAAiB,eAAe,KAAK,QAAQ,MAAM,EAAE,OAAO,MAAM,CAAC,GAAG,EAC3E,MAAM,KACR,CAAC;GACD,OAAO,QAAQ,MAAM;EACvB,CAAC;EACD,KAAK,cAAc,cAAc,cAAc,YAAY;GAEzD,cAAc;GACd,YAAY,KAAK;GACjB,MAAM,aAAa,KAAK;EAC1B,CAAC;CACH;;;;;;;CAQA,eAAe,mBAAkC;EAC/C,IAAI,gBAAgB,KAAA,GAAW;EAC/B,YAAY;EACZ,YAAY,KAAK;EACjB,MAAM,UAAU,YAAY,MAAM;EAElC,aAAkB,KAAK;EACvB,QAAa,MAAM,EAAE,OAAO,MAAM,CAAC;EAEnC,SAAS,MAAM;EACf,MAAM,UAAU,KAAK,OAAO;EAE5B,MAAM,MAAM,KAAK,OAAO;EAGxB,MAAM,UAAU;EAGhB,cAAc,MAAM;EACpB,QAAQ,MAAM;EACd,SAAc,MAAM,EAAE,OAAO,MAAM,CAAC;CACtC;CAEA,eAAe,cAA6B;EAE1C,MAAM,SAAS,KAAK;EACpB,MAAM,UAAU,MAAM,eAAe;GACnC,SAAS,OAAO;GAChB,YAAY,OAAO;GACnB,KAAK,OAAO;EACd,CAAC;EACD,UAAU,oBAAoB;GAC5B,SAAS,QAAQ,KAAK,UAAU,MAAM,UAAU;GAChD,MAAM,OAAO;GACb,SAAS;GACT,KAAK,OAAO;GACZ;GACA;GACA,SAAS,SAAS,OAAO,IAAI;EAC/B,CAAC;EACD,MAAM,gBAAgB,2BAA2B;GAC/C;GACA;GACA;GACA;GACA;GACA;GACA;GACA,SAAS;GACT,QAAQ,cAAc,OAAO;GAC7B;GACA;GACA;GACA;GACA;GACA,cAAc,UAAU;IACtB,eAAe,KAAK;IACpB,IAAS,KAAK,gBAAgB,KAAK;GACrC;GACA,WAAW;IACT,MAAM,UAAU;IAChB;IACA,IAAI,OAAO;KACT,OAAO,UAAU;IACnB;GACF;GACA,QAAQ,mBAAmB;IACzB;IACA;IACA,gBAAgB,YAAY,aAAa,IAAI,OAAO;GACtD,CAAC;GACD;GACA;GACA,cAAc,UAAU;IACtB,eAAe,KAAK;IACpB,IAAS,KAAK,gBAAgB,KAAK;GACrC;GACA,qBAAqB,QAAQ,SAAS,UAAU;IAE9C,IAAI,iBAAiB,qBAAqB;IAC1C,IAAI,MAAM,YAAY,QAAQ,6BAA6B;KACzD;KACA;KACA,KAAK;IACP,CAAC;GACH;EACF,CAAC;EACD,MAAM,aAAa,iBAAiB;GAClC,SAAS;GACT;GACA;GACA;GACA,iBAAiB,OAAO;GACxB,gBAAgB,SAAS;GACzB,mBAAmB,SAAS;EAC9B,CAAC;EACD,OAAO;EACP,MAAM,QAAQ,MAAM,WAAW,MAAM;EACrC,KAAK,MAAM,SAAS,OAAO;GACzB,IAAI,MAAM,WAAW,aAAa,MAAM,OAAO,SAAS,gBAAgB;GACxE,MAAM,EAAE,UAAU,MAAM;GAGxB,IAAI,eAAe,MAAM,KAAK,GAAG,MAAM,MAAM;GAC7C,mBAAmB,KAAK;EAC1B;CACF;CAEA,eAAe,OAAO,MAA2C;EAC/D,IAAI,CAAC,MAAM,MAAM,IAAI,cAAc,WAAW,KAAK,mCAAmC,KAAK;EAE3F,MAAM,aAAa;EACnB,MAAM,SAAS,MAAM,QAAQ,YAAY,WAAW,OAAO,IAAI,CAAC;EAChE,KAAK,MAAM,SAAS,OAAO,QAAQ,mBAAmB,KAAK;EAE3D,KAAK,MAAM,SAAS,CAAC,OAAO,OAAO,GAAG,OAAO,UAAU,GACrD,IAAI,MAAM,WAAW,aAAa,MAAM,OAAO,SAAS,gBACtD,mBAAmB,MAAM,OAAO,KAAK;EAGzC,OAAO;CACT;CAEA,eAAe,WAA0B;EACvC,IAAI;GACF,MAAM,OAAO,UAAU,aAAa;IAAE,OAAO,OAAO,YAAY;IAAQ;GAAQ,CAAC;GACjF,eAAe,IAAI,MAAM,EAAE,WAAW,UAAU,KAAK,CAAC;GAEtD,iBAAiB,aAAa,SAAS,OAAO;GAC9C,SAAS;GAET,MAAM,aAAa,KAAK;GACxB,eAAe,SAAS,KAAA;GACxB,IAAI,OAAO,YAAY,KAAA,GACrB,IAAI,KAAK,sEAAsE;GAKjF,SAAS,MAAM;GACf,cAAc,mBAAmB;GACjC,sBAAsB;GAGtB,eAAe,MAAM,oBAAoB;IACvC;IACA;IACA;IACA,QAAQ,UAAU;IAClB,cAAc;KACZ,IAAI,MAAM,2DAA2D,EAAE,QAAQ,CAAC;KAChF,IAAI,KAAK,CAAC,CAAC,OAAO,UAAmB,IAAI,MAAM,wBAAwB,EAAE,KAAK,MAAM,CAAC,CAAC;IACxF;GACF,CAAC;EACH,SAAS,OAAO;GAEd,MAAM,SAAS,CAAC,CAAC,OAAO,YACtB,IAAI,MAAM,wCAAwC,EAAE,KAAK,QAAQ,CAAC,CACpE;GACA,MAAM;EACR;EAKA,IAAI;GACF,MAAM,YAAY;EACpB,SAAS,OAAO;GACd,IAAI,MAAM,4CAA4C,EAAE,KAAK,MAAM,CAAC;GAEpE,MAAM,SAAS,KAAK;EACtB;EAIA,IAAI;GACF,MAAM,MAAM,OAAO;EACrB,SAAS,OAAO;GACd,IAAI,MAAM,2CAA2C,EAAE,KAAK,MAAM,CAAC;GACnE,MAAM,SAAS,KAAK;EACtB;EAEA,QAAQ,KAAK;EAIb,MAAM,0BACJ,IAAI,cAAc,+CAA+C,KAAK;EACxE,IAAI,eAAe,MAAM,kBAAkB;EAI3C,IAAI;GAEF,gBAAgB;GAChB,MAAM,YAAY,SAAS;GAC3B,aAAa,SAAS;EACxB,SAAS,OAAO;GACd,MAAM,SAAS,KAAK;EACtB;EAEA,IAAI,eAAe,MAAM,kBAAkB;EAC3C,UAAU,MAAM;EAChB,YAAY,IAAI;EAChB,QAAQ;CACV;;CAGA,eAAe,SAAS,SAAkC;EACxD,IAAI;GACF,MAAM,SAAS;EACjB,SAAS,cAAc;GACrB,MAAM,UAAU,wBAAwB,iBAAiB,aAAa,SAAS,CAAC;GAChF,MAAM,IAAI,eAAe,CAAC,SAAS,GAAG,OAAO,GAAG,sCAAsC;EACxF;EACA,MAAM;CACR;CAIA,SAAS,WAA0B;EACjC,oBAAoB,YAAY;EAChC,OAAO;CACT;CAEA,eAAe,cAA6B;EAC1C,QAAQ;EAER,QAAQ,MAAM;EAEd,MAAM,SAAoB,MAAM,aAAa,MAAM,WAAW,GAAG,OAAO,QAAQ;EAChF,MAAM,SAAS;EACf,MAAM,iBAAiB;EACvB,IAAI,eACF,IAAI;GACF,MAAM,UAAU,WAAW;EAC7B,SAAS,OAAO;GACd,OAAO,KAAK,KAAK;EACnB;EAGF,IAAI,cACF,IAAI;GACF,MAAM,MAAM,OAAO;EACrB,SAAS,OAAO;GACd,OAAO,KAAK,KAAK;EACnB;EAKF,IAAI;GACF,MAAM,cAAc,QAAQ;EAC9B,SAAS,OAAO;GACd,OAAO,KAAK,KAAK;EACnB;EACA,MAAM,WAAW,iBAAiB,KAAK;EACvC,IAAI,UAAU,UACZ,IAAI;GACF,MAAM,QAAQ,MAAM;EACtB,SAAS,OAAO;GACd,OAAO,KAAK,KAAK;EACnB;EAEF,QAAQ;EACR,IAAI,OAAO,SAAS,GAClB,MAAM,IAAI,eAAe,QAAQ,WAAW,OAAO,OAAO,0BAA0B;CAExF;;;;;;CAOA,eAAe,UAAyB;EAEtC,IAAI,UAAU,YAAY,MAAM;EAChC,OAAO,EAAE,QAAQ,MAAM,CAAC,CAAC,gBAAgB,KAAK,IAAI,QAAQ,SAAS,MAAM,CAAC,CAAC,gBAAgB,IAAI;GAC7F,MAAM,QAAQ,OAAO;GACrB,MAAM,IAAI,OAAO;GACjB,MAAM,SAAS,OAAO;EACxB;CACF;CAEA,MAAM,gBAAkC;EACtC,eAAe,QAAQ,cACrB,eAAe,cAAc,CAAC,CAAC,aAAa,QAAQ,SAAS;EAC/D,WAAW,WAAW,eAAe,UAAU,CAAC,CAAC,SAAS,MAAM;EAChE,aAAa,WAAW,eAAe,YAAY,CAAC,CAAC,WAAW,MAAM;CACxE;CAEA,SAAS,eAAe,QAA+B;EACrD,IAAI,CAAC,SACH,MAAM,IAAI,cAAc,UAAU,OAAO,2CAA2C,KAAK;EAE3F,OAAO;CACT;CAEA,MAAM,MAAW;EACf,IAAI,QAAkB;GACpB,OAAO;EACT;EAEA,QAAQ;EAER,UAA+B;GAC7B,OAAO,MAAM,OAAO,KAAK,CAAC;EAC5B;EAEA,QAAkB;GAChB,OAAO;IAAE,SAAS,QAAQ,MAAM;IAAG,UAAU,SAAS,MAAM;GAAE;EAChE;EAEA;EAEA,QAAuB;GACrB,QAAQ,OAAR;IACE,KAAK;KACH,QAAQ;KACR,eAAe,SAAS;KACxB,OAAO;IACT,KAAK;IACL,KAAK,WACH,OAAO,gBAAgB,QAAQ,QAAQ;IACzC,SACE,OAAO,QAAQ,OACb,IAAI,cAAc,oBAAoB,MAAM,iBAAiB,KAAK,CACpE;GACJ;EACF;EAEA,OAAsB;GACpB,QAAQ,OAAR;IACE,KAAK,QACH,OAAO,SAAS;IAClB,KAAK,YAAY;KACf,gBAAgB;KAChB,UAAU,MAAM,IAAI,cAAc,+CAA+C,KAAK,CAAC;KAGvF,MAAM,mBAAkC,SAAS;KACjD,oBAAoB,gBAAgB,QAAQ,QAAQ,EAAA,CAAG,KAAK,YAAY,UAAU;KAClF,OAAO;IACT;IACA,KAAK,WACH,OAAO,SAAS;IAClB,KAAK,YACH,OAAO,kBAAkB,mBAAmB,QAAQ,QAAQ;IAC9D,KAAK,WACH,OAAO,QAAQ,QAAQ;GAC3B;EACF;EAEA,OAAO,MAAgB,UAA2B,CAAC,GAAe;GAChE,IAAI,UAAU,cAAc,UAAU,WACpC,MAAM,IAAI,cAAc,qBAAqB,MAAM,uBAAuB,KAAK;GAEjF,MAAM,QAA4B;IAChC;IACA,MAAM,QAAQ,SAAS,KAAK,QAAQ;IACpC,WAAW,QAAQ;GACrB;GACA,MAAM,KAAK,KAAK;GAChB,aAAa;IACX,MAAM,QAAQ,MAAM,QAAQ,KAAK;IACjC,IAAI,UAAU,IAAI,MAAM,OAAO,OAAO,CAAC;GACzC;EACF;CACF;CACA,OAAO;AACT;;;AAIA,MAAM,kBAAkB,UACtB,iBAAiB,wBACjB,iBAAiB,qBACjB,iBAAiB;AAEnB,SAAS,gBAAgB,SAAyB;CAChD,IAAI,CAAC,oBAAoB,KAAK,OAAO,GACnC,MAAM,IAAI,eACR,yEAAyE,QAAQ,EACnF;CAEF,OAAO;AACT;;AAGA,SAAS,iBAAiB,WAAmC,MAAgC;CAC3F,IAAI;CACJ,IAAI,OAAO,cAAc,YAAY,WAAW;MAE9C,IAAI;EACF,WAAW,UAAU,IAAI;CAC3B,SAAS,OAAO;EACd,MAAM,IAAI,eAAe,qDAAqD,EAC5E,OAAO,MACT,CAAC;CACH;CAGF,MAAM,SAAS,gBAAgB,QAAQ;CACvC,IAAI,OAAO,SAAS,GAClB,MAAM,IAAI,eAAe,0BAA0B,OAAO,KAAK,MAAM,GAAG;CAE1E,OAAO;AACT;;AAGA,SAAS,YAAY,WAAqC;CACxD,IAAI;EACF,OAAO,UAAU,QAAQ;CAC3B,SAAS,OAAO;EACd,OAAO,QAAQ,OAAO,KAAK;CAC7B;AACF;;;;;AAMA,IAAa,yBAAb,cAA4C,MAAM;CAChD,OAAyB;CACzB;CACA;CAEA,YAAY,QAAgB,WAAmB;EAC7C,MAAM,+BAA+B,OAAO,yBAAyB,UAAU,IAAI;EACnF,KAAK,SAAS;EACd,KAAK,YAAY;CACnB;AACF;;;;;;;AAQA,SAAS,eACP,WACA,WACA,QACA,OAC0B;CAC1B,MAAM,UAAa,MAAkB,WACnC,aACE,MACA,iBACM,IAAI,uBAAuB,QAAQ,SAAS,GAClD,QACA,KACF;CACF,IAAI,UAAU,aAAa;EACzB,MAAM,cAAc,UAAU,YAAY,KAAK,SAAS;EACxD,QAAQ,MAAM,WAAW,OAAO,YAAY,MAAM,MAAM,GAAG,KAAK,EAAE;CACpE;CACA,IAAI,CAAC,cAAc,WAAW,QAAQ,GAAG,OAAO,KAAA;CAChD,OAAO,OAAO,MAAM,WAAW;EAC7B,MAAM,WAAW,MAAM,OAAO,UAAU,iBAAiB,KAAK,EAAE,GAAG,KAAK,EAAE;EAG1E,IAAI,CAAC,SAAS,cAAc,OAAO;EAInC,OAAO,SAAS,aAAa,MAC1B,gBACC,YAAY,YACX,YAAY,OAAO,OAAO,MACxB,OAAO,UAAU,QAAQ,YAAY,UAAU,OAAO,MAC7D;CACF;AACF;;AAGA,SAAS,YAAY,WAA8B;CACjD,MAAM,QAAQ,UAAU,QAAQ;CAChC,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO;CACvC,IAAI,EAAE,OAAO,UAAU,KAAK,KAAK,SAAS,IACxC,MAAM,IAAI,WAAW,gEAAgE,MAAM,EAAE;CAE/F,OAAO;AACT;;AAGA,SAAS,eACP,SACA,WACA,KAC0C;CAG1C,MAAM,WAAW,IAAI,mBAAyC;EAC5D;EACA,cAAc,UAAU,IAAI,CAAC,CAAC,MAAM,uCAAuC,EAAE,KAAK,MAAM,CAAC;CAC3F,CAAC;CACD,IAAI,QAAQ,eAAe,OACzB,SAAS,IAAI,WAAW,GAAG,EAAE,UAAU,oBAAoB,WAAW,CAAC;CAEzE,IAAI,QAAQ,eAAe,OACzB,SAAS,IAAI,WAAW,GAAG,EAAE,UAAU,oBAAoB,WAAW,CAAC;CAEzE,IAAI,QAAQ,YACV,SAAS,IAAI,WAAW,QAAQ,UAAU,GAAG,EAAE,UAAU,oBAAoB,WAAW,CAAC;CAE3F,IAAI,QAAQ,WAAW;EACrB,MAAM,QAAQ,UAAU;GACtB,YAAY,QACV,IAAI,CAAC,CAAC,MAAM,oCAAoC;IAC9C,QAAQ,IAAI,QAAQ,KAAK;IACzB,UAAU,IAAI,QAAQ,OAAO;GAC/B,CAAC;GACH,GAAG,QAAQ;EACb,CAAC;EACD,SAAS,IAAI,OAAO,EAAE,UAAU,oBAAoB,UAAU,CAAC;CACjE;CACA,IAAI,QAAQ,aAAa,OACvB,SAAS,IAAI,SAAS,QAAQ,QAAQ,GAAG,EAAE,UAAU,oBAAoB,SAAS,CAAC;CAErF,KAAK,MAAM,SAAS,QAAQ,OAAO,CAAC,GAClC,IAAI,OAAO,UAAU,YAAY,SAAS,IAAI,KAAK;MAC9C,SAAS,IAAI,MAAM,YAAY,EAAE,UAAU,MAAM,SAAS,CAAC;CAElE,OAAO;AACT"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["formatted","isThenable","SEPARATORS","isThenable","validTimeout","isThenable","formatted","join","isThenable","isThenable"],"sources":["../src/text/format.ts","../src/actions/actions.ts","../src/commands/catalog.ts","../src/commands/prefixes.ts","../src/commands/command.ts","../src/commands/registry.ts","../src/deadline.ts","../src/commands/roles.ts","../src/commands/args.ts","../src/commands/router.ts","../src/config/owners.ts","../src/logger/pretty.ts","../src/logger/logger.ts","../src/plugin/messages.ts","../src/config/schema.ts","../src/config/env.ts","../src/config/errors.ts","../src/config/plugin-configs.ts","../src/conversations/conversations.ts","../src/events/bus.ts","../src/groups/groups.ts","../src/http/server.ts","../src/logger/deferred.ts","../src/logger/secrets.ts","../src/middleware/chat-filter.ts","../src/middleware/ignore-bots.ts","../src/middleware/ignore-self.ts","../src/middleware/pipeline.ts","../src/middleware/rate-limit.ts","../src/middleware/sanitize.ts","../src/text/split.ts","../src/outbound/text.ts","../src/outbound/actions.ts","../src/outbound/album.ts","../src/outbound/queue.ts","../src/events/names.ts","../src/plugin/semver.ts","../src/plugin/define.ts","../src/version.ts","../src/plugin/declared.ts","../src/plugin/order.ts","../src/plugin/report.ts","../src/plugin/host.ts","../src/plugin/sources.ts","../src/queue/inbound.ts","../src/tenant/scope.ts","../src/scheduler/service.ts","../src/services/registry.ts","../src/storage/memory.ts","../src/unsafe/access.ts","../src/outbound/reply.ts","../src/bot/message-context.ts","../src/commands/concurrency.ts","../src/storage/tenant.ts","../src/bot/plugin-context.ts","../src/bot/reconnect.ts","../src/bot/session.ts","../src/bot/session-lease.ts","../src/bot/stop-hooks.ts","../src/bot/bot.ts"],"sourcesContent":["// Texto formatado neutro (ADR 0061). O plugin monta uma árvore mínima com os helpers, e o\n// transport a traduz para a marcação da plataforma, com o escape dela. Texto cru (string) continua\n// valendo e vai ao transport como veio.\n\nimport type { Contact } from '#message/types.ts';\n\n/** O que uma menção precisa para virar `@número`, `<@id>` ou `text_mention` no transport. */\nexport type MentionTarget = Pick<Contact, 'id' | 'name' | 'phone' | 'username'>;\n\n/** Nó da árvore de `FormattedText`. Uma string é texto literal, que o transport escapa. */\nexport type TextNode =\n | string\n | { readonly type: 'bold' | 'italic'; readonly children: readonly TextNode[] }\n | { readonly type: 'code'; readonly text: string }\n | { readonly type: 'link'; readonly url: string; readonly children: readonly TextNode[] }\n | { readonly type: 'mention'; readonly contact: MentionTarget };\n\n/** Texto formatado neutro, congelado. Monte com `fmt`, `bold`, `italic`, `code`, `link` e `mention`. */\nexport interface FormattedText {\n readonly type: 'formatted';\n readonly nodes: readonly TextNode[];\n}\n\n/** Texto que o plugin envia: cru (a marcação da plataforma, sem escape) ou formatado neutro. */\nexport type MessageText = string | FormattedText;\n\n/** Parte que os helpers aceitam: texto literal ou outro trecho formatado. */\nexport type TextPart = string | FormattedText;\n\n/** Monta o `FormattedText`; os nós já vêm validados e congelados. */\nexport function formatted(nodes: readonly TextNode[]): FormattedText {\n return Object.freeze({ type: 'formatted', nodes: Object.freeze([...nodes]) });\n}\n\n/** Nós de `parts`, sem string vazia; lança `TypeError` para o que não é texto (JS sem tipos). */\nfunction nodesOf(parts: readonly unknown[], where: string): TextNode[] {\n const nodes: TextNode[] = [];\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') nodes.push(part);\n } else if (isFormatted(part)) {\n nodes.push(...part.nodes);\n } else {\n throw new TypeError(`${where}: esperava string ou texto formatado, recebeu ${typeof part}`);\n }\n }\n return nodes;\n}\n\nexport function isFormatted(value: unknown): value is FormattedText {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { type?: unknown }).type === 'formatted' &&\n Array.isArray((value as { nodes?: unknown }).nodes)\n );\n}\n\n// Um estilo sem conteúdo some: `****` no Discord e entity vazia no Telegram dão erro ou lixo.\nfunction style(type: 'bold' | 'italic', parts: readonly TextPart[]): FormattedText {\n const children = nodesOf(parts, type);\n if (children.length === 0) return formatted([]);\n return formatted([Object.freeze({ type, children: Object.freeze(children) })]);\n}\n\nexport function bold(...parts: TextPart[]): FormattedText {\n return style('bold', parts);\n}\n\nexport function italic(...parts: TextPart[]): FormattedText {\n return style('italic', parts);\n}\n\n/** Código em linha. O conteúdo é sempre literal: não aceita outra formatação dentro. */\nexport function code(text: string): FormattedText {\n if (typeof text !== 'string') throw new TypeError('code: esperava string');\n if (text === '') return formatted([]);\n return formatted([Object.freeze({ type: 'code', text })]);\n}\n\n/**\n * Link com rótulo; sem rótulo, mostra a URL. Só `http:` e `https:`: no web a URL vira `href`, e\n * `javascript:` seria XSS.\n */\nexport function link(url: string, label?: TextPart): FormattedText {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch (error) {\n throw new TypeError(`link: URL inválida: ${String(url)}`, { cause: error });\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new TypeError(`link: só http e https são aceitos: ${url}`);\n }\n const children = nodesOf([label ?? url], 'link');\n return formatted([\n Object.freeze({\n type: 'link',\n url,\n children: Object.freeze(children.length ? children : [url]),\n }),\n ]);\n}\n\n/**\n * Menção portátil. O transport põe a sintaxe da plataforma e notifica o contato. Guarda só os\n * campos de que precisa, para não levar os `claims` do contato ao conteúdo enviado.\n */\nexport function mention(contact: MentionTarget): FormattedText {\n if (typeof contact?.id !== 'string' || contact.id === '') {\n throw new TypeError('mention: o contato precisa de um `id`');\n }\n const target: MentionTarget = Object.freeze({\n id: contact.id,\n name: contact.name ?? null,\n phone: contact.phone ?? null,\n ...(contact.username !== undefined && { username: contact.username }),\n });\n return formatted([Object.freeze({ type: 'mention', contact: target })]);\n}\n\n/**\n * Tag que compõe o texto: `` fmt`Notas de ${bold(aluno)}: ${nota}` ``. Valores interpolados são\n * literais, então o texto do usuário nunca vira marcação.\n */\nexport function fmt(\n strings: TemplateStringsArray,\n ...values: readonly (TextPart | number)[]\n): FormattedText {\n const parts: unknown[] = [];\n strings.forEach((literal, index) => {\n parts.push(literal);\n if (index < values.length) {\n const value = values[index];\n parts.push(typeof value === 'number' ? String(value) : value);\n }\n });\n return formatted(nodesOf(parts, 'fmt'));\n}\n\n/**\n * Texto visível, sem marcação: o que a pessoa lê. Uma menção vira `@` mais o usuário, o nome, o\n * telefone ou o ID, nessa ordem. A string crua volta como está.\n */\nexport function plainText(text: MessageText): string {\n if (typeof text === 'string') return text;\n let out = '';\n const walk = (nodes: readonly TextNode[]): void => {\n for (const node of nodes) {\n if (typeof node === 'string') out += node;\n else if (node.type === 'code') out += node.text;\n else if (node.type === 'mention') out += `@${mentionLabel(node.contact)}`;\n else walk(node.children);\n }\n };\n walk(text.nodes);\n return out;\n}\n\nfunction mentionLabel(contact: MentionTarget): string {\n return contact.username ?? contact.name ?? contact.phone ?? contact.id;\n}\n","// Ações (ADR 0062): o botão leva só um ID opaco, e o kernel guarda o que o clique roda. O\n// cliente (Telegram, web) não forja um clique com outro comando ou outros argumentos, e o ID cabe\n// nos 64 bytes do `callback_data` do Telegram.\n\nimport { randomBytes } from 'node:crypto';\nimport type { JsonValue } from '#storage/types.ts';\nimport { fmt, type MessageText } from '#text/format.ts';\n\n/** Botão que roda um comando registrado (de qualquer plugin), como se a pessoa o digitasse. */\nexport interface CommandAction {\n /** Texto do botão. */\n readonly label: string;\n /** Nome ou alias do comando, sem o prefixo. */\n readonly command: string;\n /** Argumentos, entregues como vieram em `ctx.args`; o `rawArgs` é a junção por espaços. */\n readonly args?: readonly string[];\n}\n\n/** Botão que roda um passo de conversa do próprio plugin (ADR 0060), com o `data` da ação. */\nexport interface StepAction {\n /** Texto do botão. */\n readonly label: string;\n /** Passo definido com `ctx.conversations.define`. */\n readonly step: string;\n /** Entregue ao passo em `ctx.data`. Padrão: `null`. */\n readonly data?: JsonValue;\n}\n\n/** Ação anexada a uma resposta (`ctx.reply(text, { actions })`). */\nexport type MessageAction = CommandAction | StepAction;\n\n/**\n * O que o clique roda, guardado pelo kernel sob o ID do botão. O `label` vira o texto da mensagem\n * do clique.\n */\nexport type ActionTarget =\n | {\n readonly kind: 'command';\n readonly label: string;\n readonly command: string;\n readonly args: readonly string[];\n }\n | {\n readonly kind: 'step';\n readonly label: string;\n readonly plugin: string;\n readonly step: string;\n readonly data: JsonValue;\n };\n\n/** Validade de um botão: 24 horas. */\nexport const ACTION_TTL_MS: number = 24 * 60 * 60_000;\n\n/** Máximo de botões guardados; acima disso, saem os mais antigos. */\nexport const MAX_STORED_ACTIONS = 10_000;\n\ninterface StoredAction {\n readonly chatId: string;\n readonly target: ActionTarget;\n readonly expiresAt: number;\n}\n\n/**\n * Alvos dos botões de um bot (estado no closure do bot, ADR 0004). Sem timer: o vencido sai ao\n * ser consultado e quando entram IDs novos, e nada sobrevive ao `stop()`.\n */\nexport class ActionRegistry {\n // O `Map` guarda a ordem de inserção, que é a de vencimento: a poda olha só o começo.\n readonly #actions = new Map<string, StoredAction>();\n readonly #now: () => number;\n\n constructor(now: () => number = Date.now) {\n this.#now = now;\n }\n\n /** Guarda o alvo, preso ao chat, e devolve o ID do botão. */\n register(chatId: string, target: ActionTarget): string {\n const now = this.#now();\n this.#prune(now);\n // 12 bytes viram 16 caracteres base64url: imprevisível e dentro dos 64 bytes do Telegram.\n const id = randomBytes(12).toString('base64url');\n this.#actions.set(id, { chatId, target, expiresAt: now + ACTION_TTL_MS });\n return id;\n }\n\n /** O alvo do botão clicado no chat, ou `undefined` se vencido, desconhecido ou de outro chat. */\n resolve(id: string, chatId: string): ActionTarget | undefined {\n const stored = this.#actions.get(id);\n if (stored === undefined) return undefined;\n if (stored.expiresAt <= this.#now()) {\n this.#actions.delete(id);\n return undefined;\n }\n return stored.chatId === chatId ? stored.target : undefined;\n }\n\n /** Descarta tudo (shutdown). */\n clear(): void {\n this.#actions.clear();\n }\n\n get size(): number {\n return this.#actions.size;\n }\n\n #prune(now: number): void {\n for (const [id, stored] of this.#actions) {\n if (stored.expiresAt > now && this.#actions.size < MAX_STORED_ACTIONS) return;\n this.#actions.delete(id);\n }\n }\n}\n\n/** O texto com o menu numerado (`1. rótulo`) no fim, para o transport sem botões. */\nexport function numberedMenu(text: MessageText, labels: readonly string[]): MessageText {\n const menu = labels.map((label, index) => `${index + 1}. ${label}`).join('\\n');\n // Na árvore, o rótulo entra como texto literal: não vira marcação.\n return typeof text === 'string' ? `${text}\\n\\n${menu}` : fmt`${text}\\n\\n${menu}`;\n}\n\nconst CHOICE = /^\\d{1,3}$/;\n\n/** Índice (a partir de 0) da opção que o texto escolhe, ou `null` se ele não é um número dela. */\nexport function pickChoice(text: string | null, count: number): number | null {\n const trimmed = text?.trim();\n if (trimmed === undefined || !CHOICE.test(trimmed)) return null;\n const choice = Number(trimmed);\n return choice >= 1 && choice <= count ? choice - 1 : null;\n}\n","import type { TransportCommands } from '#transport/types.ts';\nimport type { CommandInfo } from './command.ts';\nimport type { RegisteredCommand } from './registry.ts';\n\n/** Comando como os plugins e o transport o veem: os dados da definição, sem `run` nem `onReject`. */\nexport function commandInfo({ plugin, definition }: RegisteredCommand): CommandInfo {\n return {\n plugin,\n name: definition.name,\n aliases: [...(definition.aliases ?? [])],\n description: definition.description ?? null,\n role: definition.role ?? 'everyone',\n };\n}\n\nexport interface CommandCatalogOptions {\n /** Comandos registrados agora. */\n readonly list: () => readonly RegisteredCommand[];\n /** Destino do erro de um listener de `onChange`, que lançou ou rejeitou. */\n readonly onError: (error: unknown) => void;\n}\n\n/** A lista de comandos que o transport lê e assina (ADR 0064), com os avisos em lote. */\nexport interface CommandCatalog {\n readonly commands: TransportCommands;\n /** O registro mudou. O aviso sai no fim do tick ou, dentro de um `batch`, no fim dele. */\n changed(): void;\n /** Liga os avisos. Antes disso (o boot, que termina antes do `connect()`), nada avisa. */\n open(): void;\n /** Desliga os avisos de vez: o `teardown` do shutdown apagaria o menu da plataforma. */\n close(): void;\n /** Roda `work` segurando os avisos; ao fim, um aviso só, se a lista mudou. */\n batch<T>(work: () => Promise<T>): Promise<T>;\n}\n\ntype Listener = () => void | Promise<void>;\n\nexport function createCommandCatalog(options: CommandCatalogOptions): CommandCatalog {\n let phase: 'boot' | 'open' | 'closed' = 'boot';\n // Lotes em andamento; o reload em cascata pode aninhar.\n let holds = 0;\n let dirty = false;\n let scheduled = false;\n const listeners = new Set<Listener>();\n\n function notify(listener: Listener): void {\n try {\n const result = listener();\n if (result instanceof Promise) result.catch(options.onError);\n } catch (error) {\n options.onError(error);\n }\n }\n\n function flush(): void {\n scheduled = false;\n // Um lote aberto depois da mudança, no mesmo tick, avisa quando terminar.\n if (phase !== 'open' || holds > 0 || !dirty) return;\n dirty = false;\n for (const listener of [...listeners]) notify(listener);\n }\n\n function schedule(): void {\n if (scheduled) return;\n scheduled = true;\n // Microtask, não timer: vários `add` seguidos viram um aviso, e nada sobrevive ao `stop()`.\n queueMicrotask(flush);\n }\n\n return {\n commands: {\n list: () => options.list().map(commandInfo),\n onChange(listener) {\n // Depois do `close()`, a assinatura fica sem efeito: o `flush` não roda mais.\n if (phase !== 'closed') listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n },\n\n changed() {\n if (phase !== 'open') return;\n dirty = true;\n if (holds === 0) schedule();\n },\n\n open() {\n if (phase === 'boot') phase = 'open';\n },\n\n close() {\n phase = 'closed';\n listeners.clear();\n },\n\n async batch(work) {\n holds++;\n try {\n return await work();\n } finally {\n holds--;\n if (holds === 0 && dirty) schedule();\n }\n },\n };\n}\n","// Prefixo de comando por tipo de chat e por chat (ADR 0063). O padrão vem da config, e o override\n// de um chat fica no storage do kernel. O override é lido inteiro no boot: o roteador consulta\n// o prefixo a cada mensagem, e o caminho quente não pode ir ao storage (plano §7).\n\nimport type { Chat } from '#message/types.ts';\nimport { kernelStorage } from '#storage/namespace.ts';\nimport type { Collection, StoragePort } from '#storage/types.ts';\n\nexport const DEFAULT_PREFIX = '!';\n\n/**\n * Prefixo da config: um texto para todo chat, ou um por tipo de chat. `group` vale para todo\n * chat que não é `dm` (grupo, canal, thread). Tipo omitido: `'!'`. Vazio é permitido.\n */\nexport type PrefixConfig = string | { readonly dm?: string; readonly group?: string };\n\n/** Prefixos vistos pelo plugin (`ctx.prefixes`). */\nexport interface Prefixes {\n /** Prefixo em vigor no chat: o override dele ou o padrão do tipo de chat. */\n get(chat: Pick<Chat, 'id' | 'isGroup'>): string;\n /** Grava o override do chat. Vazio é permitido; começado por espaço em branco lança. */\n set(chatId: string, prefix: string): Promise<void>;\n /** Apaga o override, e o chat volta ao padrão do tipo. `true` se havia override. */\n reset(chatId: string): Promise<boolean>;\n}\n\nexport interface PrefixStore extends Prefixes {\n /** Lê os overrides do storage. O bot chama no boot, antes do `setup` dos plugins. */\n load(): Promise<void>;\n}\n\ntype PrefixDocument = { chat: string; prefix: string };\n\nconst LEADING_WHITESPACE = /^\\s/;\n\n/**\n * Valida um prefixo. O texto da mensagem perde os espaços iniciais antes do match, então um\n * prefixo começado por espaço em branco nunca casaria.\n */\nexport function validatePrefix(prefix: unknown, label: string): string {\n if (typeof prefix !== 'string') throw new TypeError(`${label}: o prefixo deve ser texto`);\n if (LEADING_WHITESPACE.test(prefix)) {\n throw new TypeError(`${label}: o prefixo não pode começar com espaço em branco`);\n }\n return prefix;\n}\n\nexport function createPrefixStore(\n config: PrefixConfig | undefined,\n port: StoragePort,\n): PrefixStore {\n const split = typeof config === 'object' ? config : { dm: config, group: config };\n const dm = validatePrefix(split.dm ?? DEFAULT_PREFIX, 'prefix.dm').toLowerCase();\n const group = validatePrefix(split.group ?? DEFAULT_PREFIX, 'prefix.group').toLowerCase();\n const overrides = new Map<string, string>();\n // A coleção só é aberta no primeiro uso: o `createBot` não faz I/O.\n let chats: Collection<PrefixDocument> | undefined;\n const collection = (): Collection<PrefixDocument> => {\n chats ??= kernelStorage(port, 'prefixes').collection<PrefixDocument>('chats', {\n indexes: ['chat'],\n });\n return chats;\n };\n // Escritas em fila: duas trocas seguidas no mesmo chat terminam na ordem em que foram pedidas,\n // no storage e no Map.\n let queue: Promise<unknown> = Promise.resolve();\n const enqueue = <T>(task: () => Promise<T>): Promise<T> => {\n const run = queue.then(task);\n queue = run.catch(() => undefined);\n return run;\n };\n\n return {\n async load() {\n for (const { chat, prefix } of await collection().find()) overrides.set(chat, prefix);\n },\n\n get(chat) {\n return overrides.get(chat.id) ?? (chat.isGroup ? group : dm);\n },\n\n set(chatId, prefix) {\n const value = validatePrefix(prefix, 'prefixes.set').toLowerCase();\n return enqueue(async () => {\n // Storage primeiro: se a escrita falha, o Map continua igual ao que está gravado.\n const updated = await collection().update({ chat: chatId }, { prefix: value });\n if (updated === 0) await collection().insert({ chat: chatId, prefix: value });\n overrides.set(chatId, value);\n });\n },\n\n reset(chatId) {\n return enqueue(async () => {\n const removed = await collection().delete({ chat: chatId });\n overrides.delete(chatId);\n return removed > 0;\n });\n },\n };\n}\n","import type { BotMessageContext } from '#context.ts';\nimport type { ExpectReply } from '#conversations/conversations.ts';\nimport type { Media, MediaMessageType, Message, MessageType } from '#message/types.ts';\nimport type { MessageText } from '#plugin/messages.ts';\nimport { type Capability, isCapability } from '#transport/capabilities.ts';\nimport type { RoleName } from './roles.ts';\n\n/**\n * Quem pode rodar o comando: os embutidos (ADR 0024) ou um papel custom que um plugin define com\n * `ctx.roles.define` e declara em `Roles` (ADR 0035).\n */\nexport type CommandRole = 'owner' | 'group-admin' | 'everyone' | RoleName;\n\n/**\n * O que o comando aceita: o tipo da própria mensagem (`'image'`) ou da mensagem citada\n * (`'quoted:image'`). Um tipo com mídia pode restringir o mimetype depois de mais um `:`, exato\n * (`'document:application/pdf'`) ou com curinga no subtipo (`'quoted:video:video/*'`).\n */\nexport type AcceptSpec =\n | MessageType\n | `quoted:${MessageType}`\n | `${MediaMessageType}:${string}/${string}`\n | `quoted:${MediaMessageType}:${string}/${string}`;\n\n/** Entrada de `accepts` decomposta. */\nexport interface ParsedAccept {\n readonly quoted: boolean;\n readonly type: string;\n /** Mimetype em minúsculas (`application/pdf`, `video/*`); `null` aceita qualquer um. */\n readonly mimetype: string | null;\n}\n\n/** Decompõe a entrada sem validar; a validação fica em `assertCommandDefinition`. */\nexport function parseAccept(spec: AcceptSpec): ParsedAccept {\n const quoted = spec.startsWith('quoted:');\n const rest = quoted ? spec.slice('quoted:'.length) : spec;\n const colon = rest.indexOf(':');\n if (colon === -1) return { quoted, type: rest, mimetype: null };\n return { quoted, type: rest.slice(0, colon), mimetype: rest.slice(colon + 1).toLowerCase() };\n}\n\n/**\n * O mimetype da mídia casa com o da entrada. Compara só a essência: `audio/ogg; codecs=opus`\n * casa com `audio/ogg`, porque os parâmetros variam por plataforma.\n */\nexport function mimetypeMatches(mimetype: string, pattern: string): boolean {\n const essence = mimetype.split(';', 1)[0]?.trim().toLowerCase() ?? '';\n if (pattern.endsWith('/*')) return essence.startsWith(pattern.slice(0, -1));\n return essence === pattern;\n}\n\n// Só estes tipos têm `media`; a lista acompanha `MediaMessageType`.\nconst MEDIA_TYPES: ReadonlySet<string> = new Set<MediaMessageType>([\n 'image',\n 'video',\n 'audio',\n 'voice',\n 'sticker',\n 'document',\n]);\n\n/** `tipo/subtipo` ou `tipo/*`, nos caracteres que o RFC 6838 permite. */\nconst MIMETYPE = /^[a-z0-9][a-z0-9!#$&^_.+-]*\\/(\\*|[a-z0-9][a-z0-9!#$&^_.+-]*)$/;\n\n/** Entrada de `accepts` que casou e a mensagem (própria ou citada) a que ela se refere. */\nexport interface AcceptedMessage {\n readonly spec: AcceptSpec;\n readonly message: Message;\n}\n\n/**\n * Contexto que o `run` recebe: o da mensagem (`text`, `reply`, `log`, montados pelo `Bot`) mais\n * o que o roteador resolveu. Quem usa o roteador fora do `Bot` fornece `reply`/`log` no\n * contexto passado a `dispatch`; o roteador só herda o que recebeu.\n */\nexport interface CommandContext extends BotMessageContext {\n /** Nome canônico do comando casado (não o alias digitado). */\n readonly command: string;\n /** Token digitado, já em minúsculas: o nome ou um dos aliases. */\n readonly invokedAs: string;\n /** Argumentos após o comando, com aspas resolvidas (ver `parseArgs`). */\n readonly args: readonly string[];\n /** Texto após o comando, sem o espaço inicial e com quebras de linha preservadas. */\n readonly rawArgs: string;\n /**\n * Aborta quando o `run` (ou o `onReject`) estoura o prazo (`timeoutMs` do comando ou\n * `timeouts.commandMs`), com\n * `reason` = `CommandTimeoutError`. Repasse a `fetch`/SDKs para parar o trabalho a tempo (ADR 0033);\n * depois do prazo, o `reply` deste contexto rejeita com `ContextExpiredError`. Montado pelo\n * `Bot`: quem usa o roteador solto o fornece no contexto passado a `dispatch`.\n */\n readonly signal: AbortSignal;\n /**\n * Faz a próxima mensagem do remetente, neste chat, ir para um passo de conversa do plugin\n * (ADR 0060). O `run` pergunta, registra a espera e termina, sem segurar o chat. Montado pelo\n * `Bot`, como o `signal`.\n */\n readonly expectReply: ExpectReply;\n /**\n * Texto de `messages` do plugin com os placeholders preenchidos: `{prefix}` com o prefixo\n * deste chat, os outros com `values` (ADR 0092). Montado pelo `Bot`, como o `signal`.\n */\n readonly t: MessageText;\n /** Entrada de `accepts` que casou; `null` se o comando não declara `accepts`. */\n readonly accepted: AcceptedMessage | null;\n /**\n * Mídia da mensagem que casou com `accepts` (própria ou citada). Sem `accepts`, a da\n * própria mensagem ou, na falta dela, a da citada. `null` se nenhuma tiver mídia.\n */\n readonly media: Media | null;\n}\n\n/** Por que o roteador recusou rodar o comando. */\nexport type CommandRejection =\n | { readonly reason: 'role'; readonly required: CommandRole }\n | { readonly reason: 'accepts'; readonly accepts: readonly AcceptSpec[] };\n\n/**\n * Contexto de `onReject`: ainda não há mídia resolvida nem `accepted`. No bot, o `onReject` tem\n * o mesmo prazo do `run`, e o `signal` aborta quando ele estoura.\n */\nexport type RejectContext = Omit<CommandContext, 'accepted' | 'media'>;\n\nexport interface CommandDefinition {\n /** Nome sem o prefixo (`'sticker'`, não `'!sticker'`). Casado sem diferenciar caixa. */\n readonly name: string;\n readonly aliases?: readonly string[];\n readonly description?: string;\n /** Padrão: `'everyone'`. */\n readonly role?: CommandRole;\n /** A primeira entrada que casar, na ordem declarada, define `ctx.media`. */\n readonly accepts?: readonly AcceptSpec[];\n /**\n * Texto de resposta quando o comando é recusado (papel ou `accepts`). Sem `onReject`, ou\n * retornando `null`/`undefined`, a recusa é silenciosa.\n */\n readonly onReject?: (\n ctx: RejectContext,\n rejection: CommandRejection,\n ) => string | null | undefined | Promise<string | null | undefined>;\n /**\n * No bot, devolver texto (string ou `fmt`) responde citando a mensagem, como terminar com\n * `await ctx.reply(texto)` (ADR 0079). Outro valor é ignorado. O tipo segue `unknown` para\n * `run: (c) => c.reply('x')` continuar valendo.\n */\n readonly run: (ctx: CommandContext) => unknown;\n /**\n * Prazo do `run` e do `onReject` no bot, em ms. Padrão: `timeouts.commandMs` do bot. Para o\n * comando que legitimamente demora (download, conversão): enquanto roda, ele segura o chat\n * (ADR 0042), então o prazo maior vale só para ele.\n */\n readonly timeoutMs?: number;\n /**\n * O `run` roda fora da fila do chat (ADR 0087): a próxima mensagem do chat não espera por ele.\n * Papel, `accepts` e `onReject` seguem na fila. O `run` mantém o contexto inteiro (`reply`,\n * `signal` com o `timeoutMs`, `log`), e a falha vai para `plugin.error` quando ele termina.\n * Duas execuções do mesmo chat podem terminar fora de ordem.\n */\n readonly background?: boolean;\n /**\n * Máximo de `run` simultâneos deste comando no bot, somando todos os chats (ADR 0088). A\n * execução excedente espera a vez em ordem de chegada, e a espera conta no prazo\n * (`timeoutMs`). A vaga volta quando o `run` termina de fato, mesmo depois do prazo. Inteiro\n * >= 1; padrão: sem limite.\n */\n readonly concurrency?: number;\n /**\n * Capabilities que o comando exige do transport (ADR 0090). No bot, sem alguma delas, o\n * comando não é registrado: fica fora do roteador, do `ctx.commands.list()` e do menu nativo,\n * como um plugin pulado pelo `requires` dele. O roteador solto ignora o campo.\n */\n readonly requires?: readonly Capability[];\n}\n\n/** Comando como os plugins o veem em `ctx.commands.list()` (ADR 0040): sem `run` nem `onReject`. */\nexport interface CommandInfo {\n /** Plugin que registrou o comando. */\n readonly plugin: string;\n readonly name: string;\n readonly aliases: readonly string[];\n readonly description: string | null;\n readonly role: CommandRole;\n}\n\nconst TOKEN = /^\\S+$/;\n\nfunction assertToken(token: string, what: string): void {\n if (!TOKEN.test(token)) {\n throw new TypeError(\n `${what} de comando inválido: ${JSON.stringify(token)} (vazio ou com espaço)`,\n );\n }\n}\n\n/**\n * Lança `TypeError` se o nome ou algum alias for vazio ou tiver espaço (nunca casaria) e\n * `RangeError` se `timeoutMs` não for finito e > 0 (o `setTimeout` trataria `Infinity`/`NaN`\n * como 1 ms e o comando estouraria na hora) ou se `concurrency` não for inteiro >= 1 (0 nunca\n * rodaria). Entrada de `accepts` com mimetype mal formado, ou num tipo sem mídia, e capability\n * desconhecida em `requires` também lançam `TypeError`.\n */\nexport function assertCommandDefinition(definition: CommandDefinition): void {\n assertToken(definition.name, 'Nome');\n for (const alias of definition.aliases ?? []) assertToken(alias, 'Alias');\n const { timeoutMs } = definition;\n if (timeoutMs !== undefined && !(Number.isFinite(timeoutMs) && timeoutMs > 0)) {\n throw new RangeError(`Prazo do comando \"${definition.name}\" inválido: ${timeoutMs}`);\n }\n const { concurrency } = definition;\n if (concurrency !== undefined && !(Number.isInteger(concurrency) && concurrency >= 1)) {\n throw new RangeError(\n `Limite de concorrência do comando \"${definition.name}\" inválido: ${concurrency}`,\n );\n }\n for (const spec of definition.accepts ?? []) {\n const { type, mimetype } = parseAccept(spec);\n if (mimetype === null) continue;\n if (!MEDIA_TYPES.has(type) || !MIMETYPE.test(mimetype)) {\n throw new TypeError(\n `accepts do comando \"${definition.name}\" inválido: ${JSON.stringify(spec)} (mimetype ` +\n 'só em tipo com mídia, como \"tipo/subtipo\" ou \"tipo/*\")',\n );\n }\n }\n // O tipo já barra capability desconhecida; a checagem é para quem define em JS.\n for (const capability of definition.requires ?? []) {\n if (!isCapability(capability)) {\n throw new TypeError(\n `requires do comando \"${definition.name}\": capability desconhecida ${JSON.stringify(capability)}`,\n );\n }\n }\n}\n\n/**\n * Define um comando. Valida nome, aliases, prazo e limite na definição, para o erro apontar o plugin que\n * declarou e não aparecer só quando alguém digitar o comando.\n */\nexport function command(definition: CommandDefinition): CommandDefinition {\n assertCommandDefinition(definition);\n return definition;\n}\n","import { assertCommandDefinition, type CommandDefinition } from './command.ts';\n\n/** Comando registrado com o plugin que o declarou. */\nexport interface RegisteredCommand {\n readonly plugin: string;\n readonly definition: CommandDefinition;\n}\n\n/** Dois comandos disputam o mesmo token (nome ou alias). Lançado no registro, isto é, no boot. */\nexport class CommandConflictError extends Error {\n override readonly name = 'CommandConflictError';\n /** Token disputado, em minúsculas. */\n readonly token: string;\n readonly existing: RegisteredCommand;\n readonly incoming: RegisteredCommand;\n\n constructor(token: string, existing: RegisteredCommand, incoming: RegisteredCommand) {\n super(\n `Conflito de comando \"${token}\": \"${incoming.definition.name}\" do plugin ` +\n `\"${incoming.plugin}\" colide com \"${existing.definition.name}\" do plugin ` +\n `\"${existing.plugin}\". Renomeie o comando ou o alias em um dos dois.`,\n );\n this.token = token;\n this.existing = existing;\n this.incoming = incoming;\n }\n}\n\nexport interface CommandRegistry {\n /**\n * Registra o comando em nome do plugin. Lança `TypeError` se o nome ou algum alias for\n * inválido (como `command()`) e `CommandConflictError` se algum já pertencer a outro comando\n * (de qualquer plugin, inclusive o mesmo); nos dois casos nada do comando é registrado.\n */\n add(plugin: string, definition: CommandDefinition): void;\n /** Remove todos os comandos do plugin (teardown e reload). */\n removePlugin(plugin: string): void;\n /** Busca pelo token já sem prefixo; não diferencia caixa. */\n find(token: string): RegisteredCommand | undefined;\n list(): RegisteredCommand[];\n}\n\n/** Tokens de um comando em minúsculas e sem repetição (alias igual ao nome é inofensivo). */\nfunction tokensOf(definition: CommandDefinition): Set<string> {\n const tokens = new Set([definition.name.toLowerCase()]);\n for (const alias of definition.aliases ?? []) tokens.add(alias.toLowerCase());\n return tokens;\n}\n\nexport interface CommandRegistryOptions {\n /** Chamado a cada comando que entra ou sai (o aviso do `TransportDeps.commands`, ADR 0064). */\n readonly onChange?: () => void;\n}\n\nexport function createCommandRegistry(options: CommandRegistryOptions = {}): CommandRegistry {\n // Um Map por token deixa o match O(1), independente de quantos comandos existem.\n const byToken = new Map<string, RegisteredCommand>();\n const commands = new Set<RegisteredCommand>();\n\n return {\n add(plugin, definition) {\n // Quem registra sem passar por `command()` (o `ctx.commands.add` aceita a definição\n // literal) também falha no boot, e não com um comando que nunca casa.\n assertCommandDefinition(definition);\n const entry: RegisteredCommand = { plugin, definition };\n const tokens = tokensOf(definition);\n // Valida tudo antes de gravar: um conflito no 2º alias não pode deixar o 1º registrado.\n for (const token of tokens) {\n const existing = byToken.get(token);\n if (existing) throw new CommandConflictError(token, existing, entry);\n }\n for (const token of tokens) byToken.set(token, entry);\n commands.add(entry);\n options.onChange?.();\n },\n\n removePlugin(plugin) {\n let removed = false;\n for (const entry of commands) {\n if (entry.plugin !== plugin) continue;\n commands.delete(entry);\n for (const token of tokensOf(entry.definition)) byToken.delete(token);\n removed = true;\n }\n // Plugin sem comandos não muda a lista: o transport não precisa conferir nada.\n if (removed) options.onChange?.();\n },\n\n find(token) {\n return byToken.get(token.toLowerCase());\n },\n\n list() {\n return [...commands];\n },\n };\n}\n","// Cancelamento cooperativo (ADR 0033). O JS não mata uma promise: quando o código de um plugin\n// estoura o prazo, o kernel só consegue avisá-lo (`signal`) e recusar o que ele tentar fazer\n// pelo contexto expirado. `Deadline` guarda esse estado para uma execução — um comando, um\n// listener, um job ou o contexto inteiro do plugin.\n\n/**\n * Prazo de uma execução de código de plugin. Quem expira é o dono do timer (o barramento, o\n * roteador, o scheduler, o host); o timer de `armTimer` só conta o tempo, sem expirar sozinho.\n *\n * Com `parent` (o `Deadline` de vida do plugin), a execução expira também quando o pai expira:\n * o descarte do plugin alcança os comandos, listeners e jobs dele ainda em andamento (ADR 0033).\n * O pai não guarda os filhos: `expired` e `reason` consultam o pai na leitura, e o `signal` só o\n * escuta quando alguém o lê — o caminho quente não paga nada a mais.\n */\nexport class Deadline {\n readonly #parent: Deadline | undefined;\n #expired = false;\n #reason: unknown;\n // Criado só quando alguém lê `signal`: a maioria das execuções nem olha para ele, e o\n // `AbortController` é a parte cara (EventTarget) no caminho quente de cada mensagem.\n #controller: AbortController | undefined;\n #signal: AbortSignal | undefined;\n // Envios da execução aguardando a fila de saída: enquanto houver um, o prazo não corre (ADR 0047).\n #holds = 0;\n #onHold: ((held: boolean) => void) | undefined;\n\n constructor(parent?: Deadline) {\n this.#parent = parent;\n }\n\n /** O prazo estourou (ou o contexto foi descartado). */\n get expired(): boolean {\n return this.#expired || this.#parent?.expired === true;\n }\n\n /** Motivo da expiração (o erro de timeout ou do descarte); `undefined` enquanto no prazo. */\n get reason(): unknown {\n return this.#expired ? this.#reason : this.#parent?.reason;\n }\n\n /** Aborta quando o prazo estoura (ou o pai expira), com `reason` = o motivo. */\n get signal(): AbortSignal {\n if (this.#signal === undefined) {\n this.#controller = new AbortController();\n if (this.#expired) this.#controller.abort(this.#reason);\n const own = this.#controller.signal;\n // `any` guarda o filho por referência fraca no pai: execuções que terminam não se\n // acumulam no `signal` do plugin.\n this.#signal = this.#parent === undefined ? own : AbortSignal.any([own, this.#parent.signal]);\n }\n return this.#signal;\n }\n\n /**\n * Pausa o prazo enquanto `operation` (um envio pela fila de saída) não assenta: a espera pela\n * taxa anti-ban, o \"digitando\" e as re-tentativas são do kernel, não do plugin, e a fila tem\n * tetos próprios (ADR 0047). Devolve uma promise nova, que assenta como `operation`: uma\n * rejeição que o plugin ignore continua não tratada, como sem a pausa.\n */\n hold<T>(operation: Promise<T>): Promise<T> {\n if (this.#holds++ === 0) this.#onHold?.(true);\n const release = (): void => {\n if (--this.#holds === 0) this.#onHold?.(false);\n };\n return operation.then(\n (value) => {\n release();\n return value;\n },\n (error: unknown) => {\n release();\n throw error;\n },\n );\n }\n\n /**\n * Arma o timer do prazo: `fire` corre depois de `timeoutMs` contados só fora das pausas de\n * `hold`. Um timer por execução. Devolve o desarme.\n */\n armTimer(timeoutMs: number, fire: () => void): () => void {\n let remaining = timeoutMs;\n let startedAt = 0;\n let timer: NodeJS.Timeout | undefined;\n const start = (): void => {\n startedAt = performance.now();\n timer = setTimeout(\n () => {\n this.#onHold = undefined;\n fire();\n },\n Math.max(0, remaining),\n );\n };\n this.#onHold = (held) => {\n if (held) {\n clearTimeout(timer);\n timer = undefined;\n remaining -= performance.now() - startedAt;\n } else {\n start();\n }\n };\n // O handler pode ter enviado antes de o timer armar (envio síncrono no início do `run`).\n if (this.#holds === 0) start();\n return () => {\n clearTimeout(timer);\n this.#onHold = undefined;\n };\n }\n\n /** Marca como expirado e aborta o `signal`. Só a primeira expiração vale, a do pai inclusive. */\n expire(reason: unknown): void {\n if (this.expired) return;\n this.#expired = true;\n this.#reason = reason;\n this.#controller?.abort(reason);\n }\n}\n\n/**\n * Uma execução com prazo (comando, listener ou job) estourou o tempo. É o `reason` do `signal`\n * abortado: o plugin distingue timeout de outro motivo com `instanceof` (ADR 0033).\n */\nexport class ExecutionTimeoutError extends Error {\n override readonly name: string = 'ExecutionTimeoutError';\n readonly plugin: string;\n readonly timeoutMs: number;\n\n constructor(plugin: string, what: string, timeoutMs: number) {\n super(`${what} do plugin \"${plugin}\" excedeu ${timeoutMs} ms`);\n this.plugin = plugin;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/** Um listener estourou o prazo. Vai em `plugin.error` com `timedOut: true`. */\nexport class ListenerTimeoutError extends ExecutionTimeoutError {\n override readonly name: string = 'ListenerTimeoutError';\n readonly event: string;\n\n constructor(plugin: string, event: string, timeoutMs: number) {\n super(plugin, `listener em \"${event}\"`, timeoutMs);\n this.event = event;\n }\n}\n\n/** O handler de um job estourou o prazo. Vai em `plugin.error` com `timedOut: true`. */\nexport class JobTimeoutError extends ExecutionTimeoutError {\n override readonly name: string = 'JobTimeoutError';\n readonly job: string;\n\n constructor(plugin: string, job: string, timeoutMs: number) {\n super(plugin, `job \"${job}\"`, timeoutMs);\n this.job = job;\n }\n}\n\n/**\n * Operação de um contexto expirado: `reply` de um comando ou listener que estourou o prazo, ou\n * `send`/`storage`/`scheduler` de um contexto de plugin descartado. A operação não executa;\n * `cause` é o motivo da expiração (o erro de timeout ou do descarte).\n */\nexport class ContextExpiredError extends Error {\n override readonly name = 'ContextExpiredError';\n readonly plugin: string;\n /** O que foi recusado: `'reply'`, `'reply.image'`, `'send'`, `'storage.kv.set'`… */\n readonly operation: string;\n /** Dono do contexto: `'comando \"ping\"'`, `'listener de \"message\"'`, `'contexto do plugin'`. */\n readonly scope: string;\n\n constructor(plugin: string, operation: string, scope: string, cause: unknown) {\n super(\n `plugin \"${plugin}\": ${operation} recusado — ${scope} já expirou (prazo estourado ou ` +\n 'contexto descartado). Repasse ctx.signal ao trabalho assíncrono para pará-lo a tempo.',\n { cause },\n );\n this.plugin = plugin;\n this.operation = operation;\n this.scope = scope;\n }\n}\n\n/**\n * Chave do `Deadline` de uma execução no objeto de contexto. Simbólica, não `#privada`: as\n * visões por plugin derivam o contexto por `Object.create`, e a chave precisa ser alcançável\n * pela cadeia de protótipos.\n */\nexport const DEADLINE: unique symbol = Symbol('bridger.deadline');\n\nexport interface WithDeadline {\n readonly [DEADLINE]?: Deadline;\n}\n\n/** `Deadline` da execução dona do contexto, se houver. */\nexport function deadlineOf(ctx: object): Deadline | undefined {\n return (ctx as WithDeadline)[DEADLINE];\n}\n\nexport function isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n value !== null &&\n (typeof value === 'object' || typeof value === 'function') &&\n typeof (value as PromiseLike<unknown>).then === 'function'\n );\n}\n\n/**\n * Prazos armados de um bot, cada um pela função que o desarma. O JS não mata o handler preso,\n * mas o timer do prazo dele não pode sobreviver ao `stop()`: o shutdown chama `disarmAll`.\n */\nexport class ArmedTimers {\n readonly #disarms = new Set<() => void>();\n\n add(disarm: () => void): void {\n this.#disarms.add(disarm);\n }\n\n delete(disarm: () => void): void {\n this.#disarms.delete(disarm);\n }\n\n /**\n * Desarma todos. A execução abandonada não assenta: rejeitar viraria `plugin.error` e novos\n * listeners com prazo no meio do shutdown, e ninguém mais espera por ela (a fila de entrada já\n * foi abandonada). O `Deadline` dela já expirou com o descarte do plugin.\n */\n disarmAll(): void {\n for (const disarm of this.#disarms) disarm();\n this.#disarms.clear();\n }\n}\n\n/**\n * Corre `result` contra um prazo de `timeoutMs`. Estourado, rejeita com o erro de `onTimeout`\n * (que também é a hora de expirar o `Deadline` da execução); o trabalho não tem como ser\n * cancelado e segue em segundo plano, e uma rejeição dele depois do prazo vai para `onLate`,\n * nunca vira rejeição não tratada. Resultado síncrono passa direto, sem timer: o caminho quente\n * não paga nada (plano §7). O timer fica em `armed` enquanto corre, para o shutdown desarmá-lo.\n * Com `deadline`, o prazo pausa enquanto a execução aguarda a fila de saída (`Deadline.hold`).\n */\nexport function settleWithin(\n result: unknown,\n timeoutMs: number,\n onTimeout: () => Error,\n onLate: (error: unknown) => void,\n armed: ArmedTimers,\n deadline?: Deadline,\n): unknown {\n if (!isThenable(result)) return result;\n return new Promise((resolve, reject) => {\n let settled = false;\n const disarm = (): void => {\n settled = true;\n cancel();\n armed.delete(disarm);\n };\n const fire = (): void => {\n disarm();\n reject(onTimeout());\n };\n let cancel: () => void;\n if (deadline === undefined) {\n const timer = setTimeout(fire, timeoutMs);\n cancel = () => clearTimeout(timer);\n } else {\n cancel = deadline.armTimer(timeoutMs, fire);\n }\n armed.add(disarm);\n result.then(\n (value) => {\n if (settled) return;\n disarm();\n resolve(value);\n },\n (error: unknown) => {\n if (settled) {\n onLate(error);\n return;\n }\n disarm();\n reject(error);\n },\n );\n });\n}\n","// Papéis custom nomeados (ADR 0035): um plugin define o papel, qualquer plugin o exige no comando\n// e o roteador o avalia, como faz com os embutidos.\n\nimport { ExecutionTimeoutError } from '#deadline.ts';\nimport type { Logger } from '#logger/types.ts';\nimport type { Message } from '#message/types.ts';\n\n/**\n * Papéis custom, preenchidos por declaration merging no plugin que os define:\n *\n * ```ts\n * declare module '@usebridger/core' {\n * interface Roles { moderador: true }\n * }\n * ```\n */\n// biome-ignore lint/suspicious/noEmptyInterface: vazio de propósito; plugins estendem por declaration merging.\nexport interface Roles {}\n\n/** Nomes declarados em `Roles`; só strings, porque viram chave de mapa e texto de erro. */\nexport type RoleName = Extract<keyof Roles, string>;\n\n/** Papéis que o roteador resolve sozinho; nenhum plugin pode redefini-los. */\nexport const RESERVED_ROLES: ReadonlySet<string> = new Set(['owner', 'group-admin', 'everyone']);\n\n/** O que a checagem de um papel recebe: a mensagem e o comando que exige o papel. */\nexport interface RoleContext {\n readonly message: Message;\n /** Texto de trabalho (`ctx.text`). */\n readonly text: string | null;\n /** Nome canônico do comando que exige o papel. */\n readonly command: string;\n /** Logger do plugin dono do papel, com `chatId`. */\n readonly log: Logger;\n /**\n * Aborta quando a checagem estoura o prazo (`timeouts.commandMs`), com `reason` =\n * `RoleTimeoutError`. Repasse a consultas externas (ADR 0033).\n */\n readonly signal: AbortSignal;\n}\n\n/**\n * Concede o papel só com `true`. Lançar, rejeitar, estourar o prazo ou devolver qualquer outra\n * coisa recusa o comando (fail-closed).\n */\nexport type RoleCheck = (ctx: RoleContext) => boolean | Promise<boolean>;\n\n/** Papel registrado com o plugin que o definiu. */\nexport interface RegisteredRole {\n readonly plugin: string;\n readonly name: string;\n readonly check: RoleCheck;\n}\n\n/** Dois plugins (ou o mesmo, duas vezes) definem o mesmo papel. Lançado no `setup`. */\nexport class RoleConflictError extends Error {\n override readonly name = 'RoleConflictError';\n readonly role: string;\n readonly existing: string;\n readonly incoming: string;\n\n constructor(role: string, existing: string, incoming: string) {\n super(\n existing === incoming\n ? `Papel \"${role}\" definido duas vezes pelo plugin \"${incoming}\". Cada papel é definido ` +\n 'uma vez por setup; para trocar a checagem, recarregue o plugin.'\n : `Conflito de papel \"${role}\": o plugin \"${incoming}\" tenta definir um papel que o ` +\n `plugin \"${existing}\" já define. Use o papel do plugin \"${existing}\" (declarando ` +\n 'dependsOn nele) ou renomeie o seu.',\n );\n this.role = role;\n this.existing = existing;\n this.incoming = incoming;\n }\n}\n\nexport interface RoleRegistry {\n /**\n * Registra o papel em nome do plugin. Lança `TypeError` para nome vazio, com espaço ou\n * reservado (`owner`, `group-admin`, `everyone`) e `RoleConflictError` se o nome já tem dono.\n */\n define(plugin: string, name: string, check: RoleCheck): void;\n /** Remove os papéis do plugin (teardown e reload). */\n removePlugin(plugin: string): void;\n find(name: string): RegisteredRole | undefined;\n}\n\nconst ROLE_NAME = /^\\S+$/;\n\nexport function createRoleRegistry(): RoleRegistry {\n const byName = new Map<string, RegisteredRole>();\n return {\n define(plugin, name, check) {\n if (!ROLE_NAME.test(name)) {\n throw new TypeError(\n `Nome de papel inválido: ${JSON.stringify(name)} (vazio ou com espaço)`,\n );\n }\n if (RESERVED_ROLES.has(name)) {\n throw new TypeError(\n `Papel \"${name}\" é reservado (owner, group-admin, everyone): o plugin \"${plugin}\" ` +\n 'precisa de outro nome.',\n );\n }\n const existing = byName.get(name);\n if (existing) throw new RoleConflictError(name, existing.plugin, plugin);\n byName.set(name, { plugin, name, check });\n },\n\n removePlugin(plugin) {\n for (const [name, role] of byName) {\n if (role.plugin === plugin) byName.delete(name);\n }\n },\n\n find: (name) => byName.get(name),\n };\n}\n\n/** A checagem de um papel custom estourou o prazo: o comando é recusado e sai `plugin.error`. */\nexport class RoleTimeoutError extends ExecutionTimeoutError {\n override readonly name: string = 'RoleTimeoutError';\n readonly role: string;\n\n constructor(plugin: string, role: string, timeoutMs: number) {\n super(plugin, `checagem do papel \"${role}\"`, timeoutMs);\n this.role = role;\n }\n}\n","// Aspas de abertura → fechamento aceitas. As tipográficas entram porque o teclado do celular\n// (iOS principalmente) troca `\"` por `“ ”` sozinho. Aspas simples ficam de fora: o apóstrofo\n// aparece em texto comum (\"d'água\") e quebraria o argumento.\nconst QUOTES: ReadonlyMap<string, string> = new Map([\n ['\"', '\"'],\n ['“', '”'],\n]);\n\nconst WHITESPACE = /\\s/;\n\n/**\n * Quebra o texto em argumentos por espaço em branco, respeitando trechos entre aspas\n * (`\"a b\"` vira um argumento só, sem as aspas). Aspa sem fechamento estende o argumento até o\n * fim do texto: é o que o usuário quis dizer na maioria das vezes, e não há como responder\n * \"erro de sintaxe\" de forma útil num chat.\n */\nexport function parseArgs(input: string): string[] {\n const args: string[] = [];\n let current = '';\n // Distingue \"nenhum argumento em curso\" de argumento vazio vindo de `\"\"`.\n let inArg = false;\n let closing: string | null = null;\n\n for (const char of input) {\n if (closing !== null) {\n if (char === closing) closing = null;\n else current += char;\n continue;\n }\n const close = QUOTES.get(char);\n if (close !== undefined) {\n closing = close;\n inArg = true;\n continue;\n }\n if (WHITESPACE.test(char)) {\n if (inArg) {\n args.push(current);\n current = '';\n inArg = false;\n }\n continue;\n }\n current += char;\n inArg = true;\n }\n if (inArg) args.push(current);\n return args;\n}\n","import type { BotOwner } from '#config/owners.ts';\nimport type { BotMessageContext, MessageContext } from '#context.ts';\nimport type { Chat, Contact, Media, Message } from '#message/types.ts';\nimport { parseArgs } from './args.ts';\nimport {\n type AcceptedMessage,\n type AcceptSpec,\n type CommandContext,\n type CommandDefinition,\n type CommandRejection,\n type CommandRole,\n mimetypeMatches,\n parseAccept,\n type RejectContext,\n} from './command.ts';\nimport { DEFAULT_PREFIX, validatePrefix } from './prefixes.ts';\nimport { type CommandRegistry, createCommandRegistry, type RegisteredCommand } from './registry.ts';\nimport { createRoleRegistry, type RoleContext, type RoleRegistry } from './roles.ts';\n\n/**\n * Porta para consultar admins de grupo. Vem do transport (`isChatAdmin` ou capability `groups`,\n * ADR 0059); o core não importa transport, então quem compõe o bot injeta. Recebe o chat\n * inteiro, porque no Discord o admin é do servidor (`parentId`), e o contato inteiro, porque o id\n * do remetente e o do participante podem vir em espaços diferentes (no WhatsApp, LID e JID de\n * telefone), e o telefone é o que os liga (ADR 0046).\n */\nexport type IsGroupAdmin = (chat: Chat, sender: Contact) => boolean | Promise<boolean>;\n\nexport interface CommandRouterOptions {\n /**\n * Padrão: `'!'`. Comparado sem diferenciar caixa; vazio faz a primeira palavra ser o token. Uma\n * função resolve o prefixo pelo chat da mensagem (no bot, o override do chat ou o padrão do\n * tipo, ADR 0063) e deve devolver o texto já validado e em minúsculas.\n */\n readonly prefix?: string | ((chat: Chat) => string);\n /**\n * `@usuario` da própria sessão, sem o `@`. Com ele, `cmd@usuario` vira o token `cmd`: é como o\n * Telegram endereça um comando ao bot num grupo. Lido a cada mensagem, porque só existe depois\n * da conexão.\n */\n readonly selfUsername?: () => string | undefined;\n /**\n * Donos do bot, já normalizados (`normalizeOwners`): telefone só com dígitos e DDI, comparado\n * com `message.sender.phone`, ou `{ id }`, comparado com `message.sender.id`.\n */\n readonly owners?: readonly BotOwner[];\n /** Sem a porta, `role: 'group-admin'` recusa todo mundo exceto owners (fail-closed). */\n readonly isGroupAdmin?: IsGroupAdmin;\n /** Registro a usar; padrão: um novo. */\n readonly registry?: CommandRegistry;\n /** Papéis custom (ADR 0035); padrão: um registro novo, vazio. */\n readonly roles?: RoleRegistry;\n /**\n * Comando exige um papel custom que nenhum plugin carregado define. O comando é recusado\n * (fail-closed) de todo jeito; aqui quem compõe o roteador registra o erro de configuração.\n */\n readonly onUnknownRole?: (role: string, command: MatchedCommand) => void;\n}\n\n/** Comando casado, para quem chamou o roteador saber o que rodou. */\nexport interface MatchedCommand {\n readonly plugin: string;\n readonly name: string;\n readonly invokedAs: string;\n}\n\n/** Como terminou o `run` de um comando: rodou ou falhou. */\nexport type CommandOutcome =\n | { readonly consumed: true; readonly status: 'ran'; readonly command: MatchedCommand }\n | {\n readonly consumed: true;\n readonly status: 'failed';\n readonly command: MatchedCommand;\n /**\n * Erro de `run`, `onReject` ou `isGroupAdmin` (no bot, também o prazo estourado de cada\n * um); quem chamou registra/reporta.\n */\n readonly error: unknown;\n };\n\n/**\n * Resultado de `dispatch`. `consumed` diz se a mensagem para aqui (não vai aos listeners):\n * basta o token casar, mesmo que o comando seja recusado ou falhe.\n */\nexport type DispatchResult =\n | { readonly consumed: false; readonly status: 'no-match' }\n | CommandOutcome\n | {\n readonly consumed: true;\n readonly status: 'rejected';\n readonly command: MatchedCommand;\n readonly rejection: CommandRejection;\n /** Texto de `onReject` a enviar ao chat; `null` = recusa silenciosa. */\n readonly reply: string | null;\n }\n | {\n readonly consumed: true;\n /** Comando com `background: true`: o `run` começou e `dispatch` não o espera (ADR 0087). */\n readonly status: 'background';\n readonly command: MatchedCommand;\n /** Assenta quando o `run` termina, com `ran` ou `failed`. Nunca rejeita. */\n readonly done: Promise<CommandOutcome>;\n };\n\nexport interface CommandRouter {\n readonly registry: CommandRegistry;\n readonly roles: RoleRegistry;\n /**\n * Comando que a mensagem invoca, sem validar papel nem `accepts`. `text` é o texto de\n * trabalho (`ctx.text`); padrão: `message.text`.\n */\n match(message: Message, text?: string | null): CommandMatch | null;\n /**\n * Casa, valida papel e `accepts` e roda. Nunca rejeita: erros vêm em `status: 'failed'`. Com\n * `invocation`, roda o comando dado sem casar o texto (o clique num botão, ADR 0062, ou o\n * comando nativo da plataforma, ADR 0064).\n */\n dispatch(ctx: MessageContext, invocation?: CommandInvocation): Promise<DispatchResult>;\n}\n\n/**\n * Comando a rodar sem casar o texto: com `args` já separados (botão) ou com o texto livre em\n * `rawArgs` (comando nativo), interpretado como o texto depois do comando digitado.\n */\nexport type CommandInvocation =\n | {\n /** Nome ou alias, sem o prefixo. */\n readonly command: string;\n /** Vão como vieram em `ctx.args`; o `rawArgs` é a junção por espaços. */\n readonly args: readonly string[];\n readonly rawArgs?: never;\n }\n | {\n /** Nome ou alias, sem o prefixo. */\n readonly command: string;\n readonly rawArgs: string;\n readonly args?: never;\n };\n\nexport interface CommandMatch {\n readonly entry: RegisteredCommand;\n readonly invokedAs: string;\n readonly rawArgs: string;\n}\n\nconst FIRST_WHITESPACE = /\\s/;\n\n/**\n * O contexto recebido, com o `signal`, o `expectReply` e o `t` que o Bot (ou quem chama\n * `dispatch`) fornece.\n */\ntype SignalContext = BotMessageContext & Pick<RejectContext, 'signal' | 'expectReply' | 't'>;\n\nfunction mediaOf(message: Message | null): Media | null {\n return message !== null && 'media' in message ? message.media : null;\n}\n\n/** Primeira entrada de `accepts` que casa (tipo e, se houver, mimetype), na ordem declarada. */\nfunction resolveAccepts(message: Message, accepts: readonly AcceptSpec[]): AcceptedMessage | null {\n for (const spec of accepts) {\n const { quoted, type, mimetype } = parseAccept(spec);\n const target = quoted ? message.quoted : message;\n if (target === null || target.type !== type) continue;\n if (mimetype !== null) {\n const media = mediaOf(target);\n if (media === null || !mimetypeMatches(media.mimetype, mimetype)) continue;\n }\n return { spec, message: target };\n }\n return null;\n}\n\n/** Roda o `run`; o erro, síncrono ou não, vira `failed`. Nunca rejeita. */\nasync function runCommand(\n definition: CommandDefinition,\n ctx: CommandContext,\n command: MatchedCommand,\n): Promise<CommandOutcome> {\n try {\n await definition.run(ctx);\n return { consumed: true, status: 'ran', command };\n } catch (error) {\n return { consumed: true, status: 'failed', command, error };\n }\n}\n\nexport function createCommandRouter(options: CommandRouterOptions = {}): CommandRouter {\n const option = options.prefix ?? DEFAULT_PREFIX;\n let prefixOf: (chat: Chat) => string;\n if (typeof option === 'function') {\n prefixOf = option;\n } else {\n const fixed = validatePrefix(option, 'prefix').toLowerCase();\n prefixOf = () => fixed;\n }\n // Dois conjuntos, um por espaço: um ID com texto de telefone não casa com o telefone de\n // ninguém, e vice-versa (ADR 0056).\n const ownerPhones = new Set<string>();\n const ownerIds = new Set<string>();\n for (const owner of options.owners ?? []) {\n if (typeof owner === 'string') ownerPhones.add(owner);\n else ownerIds.add(owner.id);\n }\n const isGroupAdmin = options.isGroupAdmin;\n const registry = options.registry ?? createCommandRegistry();\n const roles = options.roles ?? createRoleRegistry();\n\n function match(message: Message, workingText = message.text): CommandMatch | null {\n const text = workingText?.trimStart();\n if (!text) return null;\n const prefix = prefixOf(message.chat);\n if (text.slice(0, prefix.length).toLowerCase() !== prefix) return null;\n\n // Token = do fim do prefixo até o primeiro espaço em branco. Match exato no Map: o\n // `includes()` do legacy fazia \"!s\" casar dentro de \"vou mandar !sticker depois\".\n const rest = text.slice(prefix.length);\n const end = rest.search(FIRST_WHITESPACE);\n let token = (end === -1 ? rest : rest.slice(0, end)).toLowerCase();\n // Só o @ da própria sessão sai: `cmd@OutroBot` é de outro bot e não casa.\n const self = options.selfUsername?.();\n if (self !== undefined && token.endsWith(`@${self.toLowerCase()}`)) {\n token = token.slice(0, -(self.length + 1));\n }\n if (token.length === 0) return null;\n\n const entry = registry.find(token);\n if (!entry) return null;\n const rawArgs = end === -1 ? '' : rest.slice(end).trimStart();\n return { entry, invokedAs: token, rawArgs };\n }\n\n function invoke(invocation: CommandInvocation): CommandMatch | null {\n const token = invocation.command.toLowerCase();\n const entry = registry.find(token);\n if (!entry) return null;\n const rawArgs =\n invocation.args === undefined ? invocation.rawArgs.trimStart() : invocation.args.join(' ');\n return { entry, invokedAs: token, rawArgs };\n }\n\n async function hasRole(\n role: CommandRole,\n ctx: RoleContext,\n command: MatchedCommand,\n ): Promise<boolean> {\n if (role === 'everyone') return true;\n const { message } = ctx;\n // Dono é superusuário: passa também em `group-admin`. Owner por telefone compara com\n // `sender.phone`, não com o `sender.id`: o ID é opaco e nem sempre carrega o número (no\n // WhatsApp, um LID; M1-16.4). Owner `{ id }` compara com o `sender.id`, para quem não tem\n // telefone.\n const { id, phone } = message.sender;\n if (ownerIds.has(id) || (phone !== null && ownerPhones.has(phone))) return true;\n if (role === 'owner') return false;\n if (role !== 'group-admin') {\n // Papel custom: sem dono carregado (plugin desligado, ignorado ou recarregando), recusa.\n const custom = roles.find(role);\n if (!custom) {\n options.onUnknownRole?.(role, command);\n return false;\n }\n // Só `true` concede: o `check` embrulhado pelo bot já recusa em erro e no prazo.\n return (await custom.check(ctx)) === true;\n }\n // `group-admin` fora de grupo não tem a quem se referir: recusa.\n if (!message.chat.isGroup || !isGroupAdmin) return false;\n return isGroupAdmin(message.chat, message.sender);\n }\n\n async function reject(\n definition: CommandDefinition,\n ctx: RejectContext,\n rejection: CommandRejection,\n ): Promise<string | null> {\n return (await definition.onReject?.(ctx, rejection)) ?? null;\n }\n\n return {\n registry,\n roles,\n match,\n\n async dispatch(ctx, invocation) {\n // O texto de trabalho (M1-16.2) vem do contexto: um middleware pode tê-lo reescrito.\n const text = ctx.text === undefined ? ctx.message.text : ctx.text;\n const found = invocation === undefined ? match(ctx.message, text) : invoke(invocation);\n if (!found) return { consumed: false, status: 'no-match' };\n\n const { entry, invokedAs, rawArgs } = found;\n // Os argumentos do botão vão como o plugin os deu: reparseá-los partiria um com espaço.\n const args = invocation?.args === undefined ? parseArgs(rawArgs) : [...invocation.args];\n const { definition } = entry;\n const command: MatchedCommand = { plugin: entry.plugin, name: definition.name, invokedAs };\n const message = ctx.message;\n\n try {\n // Herda do contexto recebido em vez de copiar: preserva métodos e getters que os\n // estágios anteriores (ou o Bot) tenham colocado nele.\n // `reply`/`log` vêm do contexto do Bot pela cadeia de protótipos, e o `signal`, da visão\n // que o Bot monta para `run` e `onReject` (ver `CommandContext`).\n const base: RejectContext = Object.assign(Object.create(ctx) as SignalContext, {\n text,\n command: definition.name,\n invokedAs,\n args,\n rawArgs,\n });\n\n const role = definition.role ?? 'everyone';\n if (!(await hasRole(role, base, command))) {\n const rejection: CommandRejection = { reason: 'role', required: role };\n const reply = await reject(definition, base, rejection);\n return { consumed: true, status: 'rejected', command, rejection, reply };\n }\n\n let accepted: AcceptedMessage | null = null;\n let media: Media | null;\n if (definition.accepts) {\n accepted = resolveAccepts(message, definition.accepts);\n if (!accepted) {\n const rejection: CommandRejection = { reason: 'accepts', accepts: definition.accepts };\n const reply = await reject(definition, base, rejection);\n return { consumed: true, status: 'rejected', command, rejection, reply };\n }\n media = mediaOf(accepted.message);\n } else {\n media = mediaOf(message) ?? mediaOf(message.quoted);\n }\n\n // `signal` vem do Bot, na visão do comando (ADR 0033); solto, do contexto recebido.\n const commandCtx = Object.assign(base, { accepted, media }) as CommandContext;\n const done = runCommand(definition, commandCtx, command);\n if (definition.background) return { consumed: true, status: 'background', command, done };\n return await done;\n } catch (error) {\n return { consumed: true, status: 'failed', command, error };\n }\n },\n };\n}\n","// `owners` da config do bot. Uma string é telefone, comparado com `Contact.phone`, que o transport\n// entrega só com dígitos (M1-16). Normalizar aqui deixa o operador escrever o número como está\n// acostumado (`+55 (11) 99999-9999`) sem que a comparação dependa da formatação. `{ id }` é o ID\n// nativo do contato (`Contact.id`), para plataformas sem telefone (ADR 0056).\n\n// Pontuação comum em telefone escrito à mão. Qualquer outra coisa (letra, `@` de JID) é erro:\n// melhor recusar no boot do que nunca reconhecer o dono.\nconst SEPARATORS = /[\\s+().-]/g;\n// E.164 tem no máximo 15 dígitos; menos de 8 não é número internacional completo.\nconst PHONE = /^\\d{8,15}$/;\n\n/** Dono reconhecido pelo ID nativo do contato (`Contact.id`), comparado sem normalizar. */\nexport interface OwnerId {\n readonly id: string;\n}\n\n/** Entrada de `owners`: telefone (com ou sem pontuação) ou `{ id }`. */\nexport type BotOwner = string | OwnerId;\n\n/** Config do bot inválida (ex.: `owners` com telefone malformado). */\nexport class BotConfigError extends Error {\n override readonly name = 'BotConfigError';\n}\n\n/**\n * Telefone só com dígitos, com DDI: `'+55 11 99999-9999'` → `'5511999999999'`. Lança\n * `BotConfigError` se sobrar algo além de dígitos ou se o tamanho não for de um telefone.\n */\nexport function normalizePhone(value: string, label = 'telefone'): string {\n const digits = value.replace(SEPARATORS, '');\n if (!PHONE.test(digits)) {\n throw new BotConfigError(\n `${label}: \"${value}\" não é um telefone válido. Use só o número com DDI e DDD ` +\n '(ex.: \"5511999999999\" ou \"+55 11 99999-9999\"); para um ID de contato (JID, ID do ' +\n 'Discord ou do Telegram), use { id: \"...\" }.',\n );\n }\n return digits;\n}\n\nfunction ownerId(owner: unknown, label: string): OwnerId {\n const id = typeof owner === 'object' && owner !== null ? (owner as { id?: unknown }).id : owner;\n // O ID é comparado por igualdade exata: espaço nas pontas é engano de config, e número perde\n // precisão (um snowflake do Discord passa de 2^53). Recusar no boot em vez de nunca casar.\n if (typeof id !== 'string' || id === '' || id.trim() !== id) {\n throw new BotConfigError(\n `${label}: esperava um telefone ou { id: \"...\" } com o ID em texto, não vazio e sem ` +\n `espaço nas pontas; recebido ${JSON.stringify(owner)}.`,\n );\n }\n return { id };\n}\n\n/**\n * Normaliza `owners`: telefones por `normalizePhone`, `{ id }` validado e mantido como está. Sem\n * repetidos, na ordem dada. Telefone e ID com o mesmo texto não se fundem: são espaços diferentes.\n */\nexport function normalizeOwners(owners: readonly BotOwner[]): BotOwner[] {\n const unique = new Map<string, BotOwner>();\n owners.forEach((owner, index) => {\n const label = `owners[${index}]`;\n if (typeof owner === 'string') {\n const phone = normalizePhone(owner, label);\n unique.set(`phone:${phone}`, phone);\n } else {\n const normalized = ownerId(owner, label);\n unique.set(`id:${normalized.id}`, normalized);\n }\n });\n return [...unique.values()];\n}\n","// Formato `pretty` do logger: a linha JSON do pino vira texto para ler no terminal. Converte a\n// linha já serializada (e já censurada), em vez de ter um segundo caminho de serialização: os\n// segredos e o `err` saem iguais aos do JSON, e o custo fica só na linha emitida.\n\nimport { styleText } from 'node:util';\nimport type { LogDestination } from './logger.ts';\n\ntype Style = Parameters<typeof styleText>[0];\n\nconst LEVELS: Readonly<Record<number, readonly [label: string, style: Style]>> = {\n 10: ['TRACE', 'gray'],\n 20: ['DEBUG', 'blue'],\n 30: ['INFO ', 'green'],\n 40: ['WARN ', 'yellow'],\n 50: ['ERROR', 'red'],\n 60: ['FATAL', ['bgRed', 'white']],\n};\n\n/** Campos que o cabeçalho já mostra ou que não ajudam a ler no terminal. */\nconst HIDDEN = new Set(['level', 'time', 'pid', 'hostname', 'msg', 'plugin', 'err']);\n\ninterface SerializedError {\n readonly type?: string;\n readonly message?: string;\n readonly stack?: string;\n readonly cause?: unknown;\n}\n\n/**\n * Embrulha `target` para receber texto legível em vez de JSON. `color` liga as cores ANSI; o\n * `styleText` ainda as desliga com `NO_COLOR` ou quando o stdout não é um terminal.\n */\nexport function prettyDestination(target: LogDestination, color: boolean): LogDestination {\n const paint = (style: Style, text: string): string =>\n color ? styleText(style, text, { stream: process.stdout }) : text;\n return {\n write(line: string): void {\n let record: Record<string, unknown>;\n try {\n record = JSON.parse(line) as Record<string, unknown>;\n } catch {\n // Linha que não é JSON (não deveria acontecer com o pino): sai como veio, sem perder nada.\n target.write(line);\n return;\n }\n target.write(`${formatRecord(record, paint)}\\n`);\n },\n };\n}\n\nfunction formatRecord(\n record: Record<string, unknown>,\n paint: (style: Style, text: string) => string,\n): string {\n const [label, style] = LEVELS[record['level'] as number] ?? ['? ', 'white'];\n const parts = [paint('gray', clock(record['time'])), paint(style, label)];\n if (typeof record['plugin'] === 'string') parts.push(paint('cyan', `[${record['plugin']}]`));\n parts.push(String(record['msg'] ?? ''));\n const fields = Object.entries(record)\n .filter(([key]) => !HIDDEN.has(key))\n .map(([key, value]) => paint('gray', `${key}=${formatValue(value)}`));\n let text = [...parts, ...fields].join(' ');\n if (record['err'] !== undefined) text += `\\n${indent(formatError(record['err']))}`;\n return text;\n}\n\n/** Hora local `HH:MM:SS`; o dia fica de fora, o terminal é para acompanhar ao vivo. */\nfunction clock(time: unknown): string {\n const date = typeof time === 'number' ? new Date(time) : new Date();\n return date.toTimeString().slice(0, 8);\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string') return /^[^\\s\"=]+$/.test(value) ? value : JSON.stringify(value);\n return JSON.stringify(value) ?? String(value);\n}\n\n/** Stack do erro e as das causas, em sequência; sem stack, `tipo: mensagem` ou o JSON. */\nfunction formatError(err: unknown): string {\n if (typeof err !== 'object' || err === null) return String(err);\n const { type, message, stack, cause } = err as SerializedError;\n const own = stack ?? (message === undefined ? JSON.stringify(err) : `${type}: ${message}`);\n return cause === undefined ? own : `${own}\\ncausa: ${formatError(cause)}`;\n}\n\nfunction indent(text: string): string {\n return text.replaceAll(/^/gm, ' ');\n}\n","// Implementação do `Logger` sobre pino (M1-14). O pino fica só aqui dentro: a API pública fala\n// `Logger`/`LoggerOptions`, para trocar a implementação sem quebrar plugins.\n\nimport { type Logger as PinoLogger, pino, stdSerializers } from 'pino';\nimport { prettyDestination } from './pretty.ts';\nimport type { SecretSource } from './secrets.ts';\nimport type { LogFields, Logger, LogLevel } from './types.ts';\n\n/** Para onde vão as linhas JSON (uma por chamada, terminada em `\\n`). */\nexport interface LogDestination {\n write(line: string): void;\n}\n\nexport interface LoggerOptions {\n /** Nível mínimo emitido. Padrão: `'info'`. */\n readonly level?: LogLevel;\n /**\n * `'json'` (padrão): uma linha JSON por chamada, para agregador. Com `'pretty'`, cada linha\n * sai como `14:03:22 INFO [plugin] mensagem chave=valor`, com o `err` (stack e causas) nas\n * linhas seguintes, e colorida quando vai ao stdout de um terminal. Os segredos são censurados\n * igual.\n */\n readonly format?: 'json' | 'pretty';\n /** Destino das linhas. Padrão: stdout do processo. */\n readonly destination?: LogDestination;\n /** Campos presentes em toda linha deste logger e dos filhos (ex.: `{ app: 'meu-bot' }`). */\n readonly bindings?: LogFields;\n /**\n * Caminhos de campos trocados por `[REDACTED]`, na sintaxe de redação do pino\n * (`'password'`, `'config.apiKey'`, `'*.token'`). Pega o campo pelo nome, onde quer que o\n * valor esteja.\n */\n readonly redact?: readonly string[];\n /**\n * Valores secretos (ex.: campos `secret` da config) trocados por `[REDACTED]` em qualquer\n * lugar da linha: mensagem, campos, bindings, `err.message`/`err.stack`. Pega o valor, sob\n * qualquer nome de campo. Valores com menos de `MIN_SECRET_LENGTH` caracteres são ignorados.\n * Uma `SecretSource` (ex.: `createSecretSet()`) é consultada a cada linha: segredos descobertos\n * depois da criação do logger — como os da config de plugin, resolvida no setup e no reload —\n * também são censurados.\n */\n readonly secrets?: readonly string[] | SecretSource;\n}\n\nconst CENSOR = '[REDACTED]';\n\n/**\n * Tamanho mínimo de um segredo para ser censurado no log. A censura troca o valor onde ele\n * aparecer na linha: um segredo de 1 a 3 caracteres (`\"1\"`, `\"on\"`) apagaria pedaços de todo\n * log, e um valor tão curto não protege nada de qualquer forma.\n */\nexport const MIN_SECRET_LENGTH = 4;\n\n/**\n * Logger estruturado em JSON. `child({ plugin })` e `child({ chatId })` acumulam contexto; o\n * campo `err` é serializado com `message`, `stack` e `cause`.\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const destination = withSecretsCensored(formatted(options), options.secrets);\n const root = pino(\n {\n level: options.level ?? 'info',\n // `errWithCause` mantém a `cause` como objeto estruturado (com stack própria), em vez de\n // concatená-la na mensagem como o serializer padrão.\n serializers: { err: stdSerializers.errWithCause },\n ...(options.redact && options.redact.length > 0\n ? { redact: { paths: [...options.redact], censor: CENSOR } }\n : {}),\n },\n destination,\n );\n return wrap(options.bindings ? root.child(options.bindings) : root);\n}\n\n// O `pretty` converte a linha que sai da censura: os segredos são achados no JSON, onde a forma\n// escapada é conhecida, e o texto final nunca os vê.\nfunction formatted(options: LoggerOptions): LogDestination | undefined {\n if (options.format !== 'pretty') return options.destination;\n // Cor só no stdout padrão: um destino próprio (arquivo, teste) recebe texto puro.\n return prettyDestination(options.destination ?? pino.destination(1), !options.destination);\n}\n\n// Censura por valor no texto já serializado: pega o segredo onde quer que ele apareça, o que a\n// redação por caminho não garante (ex.: token interpolado na mensagem ou no `err.message`).\n// Custo só em linha emitida, e só quando há segredo configurado.\nfunction withSecretsCensored(\n destination: LogDestination | undefined,\n secrets: readonly string[] | SecretSource | undefined,\n): LogDestination | undefined {\n if (secrets === undefined) return destination;\n let source: SecretSource | undefined;\n let needles: string[] = [];\n if ('version' in secrets) source = secrets;\n else needles = toNeedles(secrets);\n // Lista fixa e vazia: nada a censurar, nem precisa embrulhar o destino. Com fonte viva, sempre\n // embrulha, porque um segredo pode aparecer depois.\n if (!source && needles.length === 0) return destination;\n let seen = -1;\n // Sem destino explícito, o padrão é o mesmo do pino: stdout.\n const target = destination ?? pino.destination(1);\n return {\n write(line: string): void {\n if (source && source.version !== seen) {\n seen = source.version;\n needles = toNeedles(source.values());\n }\n let censored = line;\n for (const needle of needles) censored = censored.replaceAll(needle, CENSOR);\n target.write(censored);\n },\n };\n}\n\n// O segredo aparece na linha na forma escapada do JSON; o mais longo primeiro, para um segredo\n// que contém outro ser trocado inteiro.\nfunction toNeedles(secrets: readonly string[]): string[] {\n return secrets\n .filter((secret) => secret.length >= MIN_SECRET_LENGTH)\n .map((secret) => JSON.stringify(secret).slice(1, -1))\n .sort((a, b) => b.length - a.length);\n}\n\nfunction wrap(log: PinoLogger): Logger {\n // Sem campos, chama o pino só com a mensagem: evita alocar um objeto vazio por linha. Em nível\n // desabilitado o método do pino já é um no-op, então nada é serializado.\n return {\n get level(): LogLevel {\n return log.level as LogLevel;\n },\n trace: (message, fields) => (fields ? log.trace(fields, message) : log.trace(message)),\n debug: (message, fields) => (fields ? log.debug(fields, message) : log.debug(message)),\n info: (message, fields) => (fields ? log.info(fields, message) : log.info(message)),\n warn: (message, fields) => (fields ? log.warn(fields, message) : log.warn(message)),\n error: (message, fields) => (fields ? log.error(fields, message) : log.error(message)),\n fatal: (message, fields) => (fields ? log.fatal(fields, message) : log.fatal(message)),\n child: (bindings) => wrap(log.child(bindings)),\n };\n}\n\n// Descarta a linha: é o propósito do logger no-op.\nconst noop = (): void => {\n return;\n};\n\n// Objeto congelado e sem recurso: compartilhá-lo não cria estado global mutável.\nconst NOOP_LOGGER: Logger = Object.freeze({\n level: 'silent',\n trace: noop,\n debug: noop,\n info: noop,\n warn: noop,\n error: noop,\n fatal: noop,\n child: (): Logger => NOOP_LOGGER,\n});\n\n/** Logger que descarta tudo, sem custo: para testes e como padrão quando ninguém configurou. */\nexport function createNoopLogger(): Logger {\n return NOOP_LOGGER;\n}\n","// Placeholders nas `messages` do plugin (ADR 0092): `{nome}` no texto, preenchido na hora de usar\n// por `ctx.t`. O `{prefix}` o kernel resolve para o chat da mensagem; os outros o plugin passa.\n\n/** Valores dos placeholders de uma mensagem. */\nexport type MessageValues = Readonly<Record<string, string | number>>;\n\n/**\n * Texto de `messages` com os placeholders preenchidos. O `{prefix}` vem do chat da mensagem; os\n * demais, de `values`. Chave que o plugin não declara, ou placeholder sem valor, lança\n * `TypeError`: é erro do plugin, e a config só sobrescreve com os placeholders do texto padrão.\n */\nexport type MessageText = (key: string, values?: MessageValues) => string;\n\n/** Placeholder que o kernel preenche: o prefixo de comando do chat (ADR 0063). */\nexport const PREFIX_PLACEHOLDER = 'prefix';\n\n// Só `{identificador}`: chaves com espaço ou pontuação (`{ ok }`, JSON) ficam como texto.\nconst PLACEHOLDER = /\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g;\n\n/** Nomes dos placeholders do texto, na ordem em que aparecem, sem repetição. */\nexport function placeholders(text: string): string[] {\n return [...new Set(Array.from(text.matchAll(PLACEHOLDER), (match) => match[1] as string))];\n}\n\n/** Preenche os placeholders de `text`; `key` só entra na mensagem de erro. */\nexport function fillMessage(text: string, values: MessageValues, key: string): string {\n return text.replaceAll(PLACEHOLDER, (_match, name: string) => {\n // `hasOwn`: um `{constructor}` sem valor não pode cair no método herdado do `Object`.\n const value = Object.hasOwn(values, name) ? values[name] : undefined;\n if (value === undefined) {\n throw new TypeError(`mensagem \"${key}\": falta o valor do placeholder {${name}}`);\n }\n return String(value);\n });\n}\n\n/** O `ctx.t`: a mensagem `key` das `messages` do plugin, com o `{prefix}` do chat. */\nexport function formatMessage(\n messages: Readonly<Record<string, string>>,\n key: string,\n values: MessageValues | undefined,\n prefix: string,\n): string {\n if (!Object.hasOwn(messages, key)) {\n throw new TypeError(`mensagem \"${key}\" não declarada em messages`);\n }\n return fillMessage(messages[key] as string, { ...values, [PREFIX_PLACEHOLDER]: prefix }, key);\n}\n","// Leitura estrutural de schemas Zod: achar o tipo \"de verdade\" atrás de optional/default/pipe,\n// percorrer campos de objeto e saber se um campo é secreto. Olha `_zod.def.type` (string) em vez\n// de `instanceof`, para funcionar mesmo se o plugin trouxer outra cópia do Zod. O core importa\n// o Zod só como tipo: carregar o módulo cria globais (`__zod_globalRegistry`), e importar o core\n// não pode ter side effect (ADR 0004). Por isso tudo passa por métodos do próprio schema\n// (`meta()`, `toJSONSchema()`), que já vêm do Zod que o plugin carregou.\n\nimport type { z } from 'zod';\n\n/** Texto que substitui um valor secreto em qualquer exibição (dashboard, `describe`). */\nexport const SECRET_MASK = '********';\n\ninterface Def {\n readonly type: string;\n readonly innerType?: z.ZodType;\n readonly in?: z.ZodType;\n readonly shape?: Readonly<Record<string, z.ZodType>>;\n readonly values?: readonly unknown[];\n}\n\n// Embrulhos que não mudam o formato do valor de entrada.\nconst WRAPPERS = new Set([\n 'optional',\n 'nullable',\n 'default',\n 'prefault',\n 'readonly',\n 'catch',\n 'nonoptional',\n]);\n\nconst defOf = (schema: z.ZodType): Def => schema._zod.def as unknown as Def;\n\n/** Próximo nível do embrulho, ou `undefined` se `schema` já é o tipo base. */\nfunction innerOf(schema: z.ZodType): z.ZodType | undefined {\n const def = defOf(schema);\n if (WRAPPERS.has(def.type)) return def.innerType;\n // Num pipe (transform, coerce), a entrada é o lado `in`.\n if (def.type === 'pipe') return def.in;\n return undefined;\n}\n\n/** O schema base atrás de optional/default/nullable/pipe. */\nexport function unwrapSchema(schema: z.ZodType): z.ZodType {\n let current = schema;\n for (let inner = innerOf(current); inner; inner = innerOf(current)) current = inner;\n return current;\n}\n\n/** Tipo base do schema (`'string'`, `'number'`, `'object'`...). */\nexport const baseType = (schema: z.ZodType): string => defOf(unwrapSchema(schema)).type;\n\n/** Valores aceitos por um `z.literal` (vazio para outros tipos). */\nexport const literalValues = (schema: z.ZodType): readonly unknown[] =>\n defOf(unwrapSchema(schema)).values ?? [];\n\n/** Campos do objeto, se o schema base for `z.object`. */\nexport function objectShape(schema: z.ZodType): Readonly<Record<string, z.ZodType>> | undefined {\n const def = defOf(unwrapSchema(schema));\n return def.type === 'object' ? def.shape : undefined;\n}\n\n/**\n * Marca um campo como secreto: o valor é censurado no log, mascarado em `describe` e o JSON\n * Schema exportado sai com `secret: true` e `writeOnly: true`. Vale em qualquer nível de objeto\n * e sobrevive a `.optional()`/`.default()` aplicados depois.\n *\n * ```ts\n * config: z.object({ apiKey: secret(z.string().min(1)) })\n * ```\n */\nexport function secret<T extends z.ZodType>(schema: T): T {\n // `meta` clona e registra no registro global do Zod, que o `toJSONSchema` lê; a descrição e\n // outros metadados do schema original são herdados pelo clone.\n return schema.meta({ secret: true, writeOnly: true }) as T;\n}\n\n// Os `checks` (`.min()`, `.refine()`) também têm `_zod`, mas não são schemas: não têm `meta`.\nconst isSchema = (value: unknown): value is z.ZodType =>\n typeof value === 'object' &&\n value !== null &&\n '_zod' in value &&\n typeof (value as { meta?: unknown }).meta === 'function';\n\n/** Sub-schemas guardados na definição (`element`, `options`, `keyType`, `items`...). */\nfunction childrenOf(def: Def): z.ZodType[] {\n const children: z.ZodType[] = [];\n for (const value of Object.values(def)) {\n if (isSchema(value)) children.push(value);\n else if (Array.isArray(value)) children.push(...value.filter(isSchema));\n }\n return children;\n}\n\n/**\n * Caminhos de `secret()` fora de campo de `z.object` (dentro de array, record, union...). A config\n * só acha segredo seguindo objetos — para censurar no log, mascarar e recusar no override —, então\n * um segredo noutro lugar passaria sem nenhuma dessas proteções. `[*]` marca o nível que não é\n * objeto. `z.lazy` não é percorrido.\n */\nexport function misplacedSecrets(schema: z.ZodType): string[] {\n const found: string[] = [];\n const visited = new Set<z.ZodType>();\n const walk = (node: z.ZodType, path: string, nested: boolean): void => {\n if (visited.has(node)) return;\n visited.add(node);\n if (node.meta()?.['secret'] === true) {\n // Num campo de objeto, o valor inteiro é segredo: o que houver dentro já está coberto.\n if (nested) found.push(path);\n return;\n }\n const def = defOf(node);\n if (def.type === 'object') {\n for (const [key, field] of Object.entries(def.shape ?? {})) {\n walk(field, path === '' ? key : `${path}.${key}`, nested);\n }\n return;\n }\n // Embrulhos e pipes não mudam o nível; qualquer outro contêiner tira do caminho de objetos.\n const transparent = WRAPPERS.has(def.type) || def.type === 'pipe';\n for (const child of childrenOf(def)) {\n walk(child, transparent ? path : `${path}[*]`, nested || !transparent);\n }\n };\n walk(schema, '', false);\n return found;\n}\n\n/** `true` se o campo foi marcado com `secret()` (em qualquer nível do embrulho). */\nexport function isSecretSchema(schema: z.ZodType): boolean {\n for (let current: z.ZodType | undefined = schema; current; current = innerOf(current)) {\n if (current.meta()?.['secret'] === true) return true;\n }\n return false;\n}\n","// Camada de variáveis de ambiente da config de plugin. Este é o único lugar do core que lê\n// `process.env` (regra do Biome), e só como padrão quando quem cria a config não injeta um\n// ambiente — testes sempre injetam.\n\nimport type { z } from 'zod';\nimport { baseType, literalValues, objectShape } from './schema.ts';\n\n/** Ambiente consultado: nome → valor. `process.env` tem esse formato. */\nexport type ConfigEnv = Readonly<Record<string, string | undefined>>;\n\nconst ENV_PREFIX = 'BRIDGER';\n\n/** O ambiente do processo. Lido na chamada, nunca no import. */\nexport const processEnv = (): ConfigEnv => process.env;\n\n/** `apiKey` → `API_KEY`, `user-names` → `USER_NAMES`, `openAIKey` → `OPEN_AI_KEY`. */\nexport function toEnvSegment(name: string): string {\n return name\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1_$2')\n .replace(/-/g, '_')\n .toUpperCase();\n}\n\n/**\n * Nome da variável de um campo: `BRIDGER_<PLUGIN>__<CAMPO>[__<SUBCAMPO>...]`. O `__` separa\n * níveis, então `user-names` + `apiKey` vira `BRIDGER_USER_NAMES__API_KEY`.\n */\nexport function envName(plugin: string, path: readonly string[]): string {\n return [`${ENV_PREFIX}_${toEnvSegment(plugin)}`, ...path.map(toEnvSegment)].join('__');\n}\n\nconst TRUE = new Set(['true', '1', 'yes', 'on']);\nconst FALSE = new Set(['false', '0', 'no', 'off']);\n\n/**\n * Converte o texto da variável para o tipo que o schema espera. Se não der, devolve o texto\n * como veio: o Zod rejeita com a mensagem dele e o erro aponta a variável como fonte.\n */\nexport function coerceEnvValue(raw: string, schema: z.ZodType): unknown {\n switch (baseType(schema)) {\n case 'string':\n case 'enum':\n case 'template_literal':\n return raw;\n case 'number': {\n const value = Number(raw);\n return raw.trim() === '' || Number.isNaN(value) ? raw : value;\n }\n case 'boolean': {\n const lower = raw.trim().toLowerCase();\n if (TRUE.has(lower)) return true;\n if (FALSE.has(lower)) return false;\n return raw;\n }\n case 'literal':\n return literalValues(schema).find((value) => String(value) === raw) ?? raw;\n default:\n // Arrays, records, uniões: a variável traz JSON (`[\"a\",\"b\"]`). Texto que não é JSON\n // segue cru, e o Zod decide se uma string serve.\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return raw;\n }\n }\n}\n\n/**\n * Variáveis de ambiente que dois caminhos da config produzem iguais: `openAIKey` e `openAiKey`\n * viram ambos `OPEN_AI_KEY`, e uma variável preencheria os dois campos. Devolve, por variável,\n * os caminhos em conflito. `messages` entra como `messages.<chave>`.\n */\nexport function envCollisions(\n plugin: string,\n shape: Readonly<Record<string, z.ZodType>> | undefined,\n messageKeys: readonly string[],\n): Map<string, string[]> {\n const byName = new Map<string, string[]>();\n const add = (path: readonly string[]): void => {\n const name = envName(plugin, path);\n byName.set(name, [...(byName.get(name) ?? []), path.join('.')]);\n };\n const walk = (fields: Readonly<Record<string, z.ZodType>>, prefix: readonly string[]): void => {\n for (const [key, field] of Object.entries(fields)) {\n const nested = objectShape(field);\n if (nested) walk(nested, [...prefix, key]);\n else add([...prefix, key]);\n }\n };\n if (shape) walk(shape, []);\n for (const key of messageKeys) add(['messages', key]);\n for (const [name, paths] of byName) if (paths.length < 2) byName.delete(name);\n return byName;\n}\n\n/** Um valor lido do ambiente: caminho no objeto de config e a variável de onde veio. */\nexport interface EnvEntry {\n readonly path: readonly string[];\n readonly name: string;\n readonly value: unknown;\n}\n\n/**\n * Valores do ambiente para os campos do schema, percorrendo objetos aninhados. Só campos\n * declarados no schema são procurados — o ambiente não cria chave nova.\n */\nexport function readEnvFields(\n plugin: string,\n shape: Readonly<Record<string, z.ZodType>>,\n env: ConfigEnv,\n prefix: readonly string[] = [],\n): EnvEntry[] {\n const found: EnvEntry[] = [];\n for (const [key, field] of Object.entries(shape)) {\n const path = [...prefix, key];\n const nested = objectShape(field);\n if (nested) {\n found.push(...readEnvFields(plugin, nested, env, path));\n continue;\n }\n const name = envName(plugin, path);\n const raw = env[name];\n if (raw !== undefined) found.push({ path, name, value: coerceEnvValue(raw, field) });\n }\n return found;\n}\n","/** De onde veio o valor de um campo, em ordem crescente de precedência. */\nexport type ConfigSource = 'default' | 'override' | 'file' | 'env';\n\nexport interface PluginConfigIssue {\n /** Caminho do campo (`quality`, `openai.apiKey`, `messages.needMedia`); vazio = o objeto todo. */\n readonly path: string;\n /** O que está errado. Nunca contém o valor recebido (pode ser secreto). */\n readonly message: string;\n /** Camada que forneceu o valor rejeitado; `default` = nenhuma (valor ausente). */\n readonly source: ConfigSource;\n /** Variável de ambiente, quando `source` é `env`. */\n readonly env?: string;\n}\n\nconst describeSource = (plugin: string, issue: PluginConfigIssue): string => {\n switch (issue.source) {\n case 'env':\n return `env ${issue.env}`;\n case 'file': {\n const path = issue.path === '' ? '' : `.${issue.path}`;\n return `arquivo pluginConfig[\"${plugin}\"]${path}`;\n }\n case 'override':\n return 'override salvo no storage';\n case 'default':\n return 'ausente, sem default no schema';\n }\n};\n\n/**\n * Config de plugin rejeitada: lista todos os problemas, cada um com campo e fonte. No boot, a\n * fábrica de contexto que lança este erro faz o plugin ser ignorado (motivo na tabela); numa\n * mudança de config, a mudança é recusada e o plugin segue com a config anterior.\n */\nexport class PluginConfigError extends Error {\n override readonly name = 'PluginConfigError';\n readonly plugin: string;\n readonly issues: readonly PluginConfigIssue[];\n\n constructor(plugin: string, issues: readonly PluginConfigIssue[]) {\n const lines = issues.map(\n (issue) =>\n `${issue.path === '' ? '(config)' : issue.path}: ${issue.message} (fonte: ${describeSource(plugin, issue)})`,\n );\n super(`config inválida do plugin \"${plugin}\":\\n- ${lines.join('\\n- ')}`);\n this.plugin = plugin;\n this.issues = issues;\n }\n}\n","// Config por plugin (M1-13, ADRs 0017 e 0025). Junta as camadas — default do schema < override\n// salvo no storage (dashboard) < arquivo (config do app) < env —, valida com o schema Zod do\n// plugin, mescla os `messages` sobrescritos e mantém os valores secretos no `SecretSet` que o\n// logger consulta. Quem monta o `PluginContext` (M1-16) chama `resolve` a cada setup; uma\n// mudança de override é validada antes de salvar e dispara o reload do plugin. Campo `secret` não\n// entra por override: o storage guarda em texto puro (ADR 0032).\n\nimport type { z } from 'zod';\nimport { createNoopLogger, MIN_SECRET_LENGTH } from '#logger/logger.ts';\nimport type { SecretSet } from '#logger/secrets.ts';\nimport type { Logger } from '#logger/types.ts';\nimport type { PluginReloadResult } from '#plugin/host.ts';\nimport { PREFIX_PLACEHOLDER, placeholders } from '#plugin/messages.ts';\nimport type { PluginDefinition, PluginMessages } from '#plugin/types.ts';\nimport { kernelStorage } from '#storage/namespace.ts';\nimport type { JsonObject, StoragePort } from '#storage/types.ts';\nimport {\n type ConfigEnv,\n type EnvEntry,\n envCollisions,\n envName,\n processEnv,\n readEnvFields,\n} from './env.ts';\nimport { type ConfigSource, PluginConfigError, type PluginConfigIssue } from './errors.ts';\nimport { isSecretSchema, misplacedSecrets, objectShape, SECRET_MASK } from './schema.ts';\n\n/**\n * Config de um plugin vinda do app ou do storage: os campos do schema e, opcionalmente,\n * `messages` com textos a sobrescrever (ADR 0025). `messages` é chave reservada.\n */\nexport type PluginConfigEntry = Readonly<Record<string, unknown>>;\n\n/** \"Arquivo\" de config: nome do plugin → entrada. É o `pluginConfig` da config do bot. */\nexport type PluginConfigFile = Readonly<Record<string, PluginConfigEntry>>;\n\n/** O que o contexto do plugin recebe: `ctx.config` e `ctx.plugin.messages`. */\nexport interface ResolvedPluginConfig {\n /** Saída do schema (defaults aplicados); `undefined` se o plugin não declara `config`. */\n readonly config: unknown;\n /** `messages` do manifesto com as sobrescritas aplicadas. */\n readonly messages: PluginMessages;\n}\n\n/** Config para exibição (dashboard, diagnóstico): campos `secret` trocados por `SECRET_MASK`. */\nexport interface PluginConfigView {\n readonly config: unknown;\n readonly messages: PluginMessages;\n /**\n * Fonte de cada folha da config (`\"openai.token\"`) e de cada mensagem (`\"messages.done\"`).\n * Mostra ao dashboard quando um override não vale porque o arquivo ou o env decide o campo.\n */\n readonly sources: Readonly<Record<string, ConfigSource>>;\n}\n\n/**\n * JSON Schema (draft 2020-12) da entrada da config; campos secretos com `secret: true`,\n * `writeOnly: true` e `x-bridger-override: false` (não editáveis por override).\n */\nexport type PluginConfigJsonSchema = Readonly<Record<string, unknown>>;\n\nexport interface PluginConfigsOptions {\n /** Plugins conhecidos (os mesmos passados ao host). */\n readonly plugins: readonly PluginDefinition[];\n /** Config do app por plugin. */\n readonly file?: PluginConfigFile;\n /** Overrides ficam em `kernelStorage(storage, 'config').kv`, chave = nome do plugin. */\n readonly storage: StoragePort;\n /** Ambiente lido. Padrão: `process.env` (testes injetam o seu). */\n readonly env?: ConfigEnv;\n /** Recebe os valores dos campos `secret` de cada plugin resolvido (compartilhe com o logger). */\n readonly secrets?: SecretSet;\n /** Chamado depois de salvar um override válido; normalmente `(name) => host.reload(name)`. */\n readonly reload?: (plugin: string) => Promise<PluginReloadResult>;\n /** Avisos de configuração (ex.: `pluginConfig` citando plugin inexistente). */\n readonly log?: Logger;\n}\n\nexport interface PluginConfigs {\n /**\n * Config atual do plugin, validada, e `messages` mesclado. Lança `PluginConfigError` se\n * alguma camada tiver valor inválido. Registra os segredos no `SecretSet`.\n */\n resolve(plugin: string): Promise<ResolvedPluginConfig>;\n /**\n * Substitui os overrides do plugin (`{}` remove). Campo `secret` (em qualquer nível) é\n * recusado com `PluginConfigError` (fonte `override`): segredo vem de env ou do arquivo.\n * Valida a config resultante antes de salvar:\n * se inválida, rejeita com `PluginConfigError` e nada muda — o plugin segue rodando. Se\n * válida, salva e chama `reload` (devolve o resultado dele; `undefined` sem `reload`).\n * Campo do override que o arquivo ou o env já definem não tem efeito: é salvo mesmo assim\n * (vale se a camada de cima sair) e gera um aviso no log com os caminhos sombreados.\n */\n setOverrides(plugin: string, overrides: JsonObject): Promise<PluginReloadResult | undefined>;\n /** Config atual com os segredos mascarados. Lança `PluginConfigError` se inválida. */\n describe(plugin: string): Promise<PluginConfigView>;\n /** JSON Schema da config para gerar formulário; `undefined` se o plugin não declara `config`. */\n jsonSchema(plugin: string): PluginConfigJsonSchema | undefined;\n}\n\nconst MESSAGES_KEY = 'messages';\n\n/**\n * Problema da sobrescrita que usa placeholder que o texto padrão não tem (o `{prefix}` vale\n * sempre); `null` se está tudo certo.\n */\nfunction placeholderIssue(text: string, base: string): string | null {\n const allowed = [...placeholders(base), PREFIX_PLACEHOLDER];\n const unknown = placeholders(text).filter((name) => !allowed.includes(name));\n if (unknown.length === 0) return null;\n const show = (names: string[]): string => names.map((name) => `{${name}}`).join(', ');\n return `placeholder desconhecido ${show(unknown)}; a mensagem aceita ${show(allowed)}`;\n}\nconst SECRETS_OWNER = (plugin: string): string => `plugin:${plugin}`;\n\ntype PlainObject = Record<string, unknown>;\n\nconst isPlainObject = (value: unknown): value is PlainObject => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n};\n\n/** `top` sobre `base`: objetos mesclam recursivamente; o resto (arrays inclusive) substitui. */\nfunction deepMerge(base: PlainObject, top: PlainObject): PlainObject {\n const merged: PlainObject = { ...base };\n for (const [key, value] of Object.entries(top)) {\n // `undefined` é ausência: não apaga o que veio de camada mais baixa.\n if (value === undefined) continue;\n const current = merged[key];\n merged[key] =\n isPlainObject(current) && isPlainObject(value) ? deepMerge(current, value) : value;\n }\n return merged;\n}\n\nfunction setIn(target: PlainObject, path: readonly string[], value: unknown): void {\n let node = target;\n for (const key of path.slice(0, -1)) {\n const next = node[key];\n if (isPlainObject(next)) node = next;\n else {\n const created: PlainObject = {};\n node[key] = created;\n node = created;\n }\n }\n node[path.at(-1) as string] = value;\n}\n\n/** `true` se a camada forneceu algum valor no caminho. */\nfunction provides(layer: PlainObject, path: readonly PropertyKey[]): boolean {\n let node: unknown = layer;\n for (const key of path) {\n if (typeof node !== 'object' || node === null) return true;\n if (!(key in node)) return false;\n node = (node as Record<PropertyKey, unknown>)[key];\n }\n return node !== undefined;\n}\n\n/** Caminhos das folhas: objetos simples abrem; o resto (arrays inclusive) é folha. */\nfunction leafPaths(value: PlainObject, prefix: readonly string[] = []): string[][] {\n return Object.entries(value).flatMap(([key, child]) => {\n if (child === undefined) return [];\n const path = [...prefix, key];\n return isPlainObject(child) && Object.keys(child).length > 0 ? leafPaths(child, path) : [path];\n });\n}\n\nconst startsWith = (path: readonly PropertyKey[], prefix: readonly string[]): boolean =>\n prefix.every((key, index) => String(path[index]) === key);\n\n/**\n * Copia `value` trocando cada campo `secret` por `onSecret(valor)`. Percorre só objetos\n * declarados no schema; o que o schema não descreve passa intacto.\n */\nfunction mapSecrets(\n schema: z.ZodType,\n value: unknown,\n onSecret: (value: unknown) => unknown,\n): unknown {\n const shape = objectShape(schema);\n if (!shape || !isPlainObject(value)) return value;\n const copy: PlainObject = { ...value };\n for (const [key, field] of Object.entries(shape)) {\n if (copy[key] === undefined) continue;\n copy[key] = isSecretSchema(field)\n ? onSecret(copy[key])\n : mapSecrets(field, copy[key], onSecret);\n }\n return copy;\n}\n\n/**\n * Caminhos dos campos `secret` presentes em `value`, seguindo o schema. Mesmo critério de\n * `mapSecrets`: só objetos declarados; `undefined` é ausência.\n */\nfunction secretPaths(\n schema: z.ZodType,\n value: unknown,\n prefix: readonly string[] = [],\n): string[][] {\n const shape = objectShape(schema);\n if (!shape || !isPlainObject(value)) return [];\n return Object.entries(shape).flatMap(([key, field]) => {\n if (value[key] === undefined) return [];\n const path = [...prefix, key];\n return isSecretSchema(field) ? [path] : secretPaths(field, value[key], path);\n });\n}\n\n/** Valor no caminho de objetos `path` (`undefined` se algum nível faltar). */\nfunction valueAt(value: unknown, path: readonly string[]): unknown {\n let node = value;\n for (const key of path) node = isPlainObject(node) ? node[key] : undefined;\n return node;\n}\n\n/** Cópia de `value` sem o campo em `path` (os objetos do caminho são copiados, não alterados). */\nfunction withoutPath(value: PlainObject, path: readonly string[]): PlainObject {\n const [key, ...rest] = path as [string, ...string[]];\n const copy: PlainObject = { ...value };\n const next = copy[key];\n if (rest.length === 0) delete copy[key];\n else if (isPlainObject(next)) copy[key] = withoutPath(next, rest);\n return copy;\n}\n\n/** Valores de um campo secreto como texto, para o logger achá-los na linha. */\nfunction secretStrings(value: unknown, into: string[]): void {\n if (typeof value === 'string') into.push(value);\n else if (typeof value === 'number' || typeof value === 'bigint') into.push(String(value));\n else if (Array.isArray(value)) for (const item of value) secretStrings(item, into);\n else if (isPlainObject(value)) for (const item of Object.values(value)) secretStrings(item, into);\n}\n\n/** Anotação do JSON Schema que diz ao dashboard que o campo não aceita override. */\nconst OVERRIDE_ANNOTATION = 'x-bridger-override';\n\n/**\n * No JSON Schema exportado, marca campo secreto como não editável por override e troca o\n * `default` dele pela máscara. `x-bridger-override` em vez de `readOnly`: o campo já é\n * `writeOnly`, e `readOnly` + `writeOnly` juntos se contradizem no JSON Schema.\n */\nfunction markSecrets(node: unknown): void {\n if (Array.isArray(node)) {\n for (const item of node) markSecrets(item);\n return;\n }\n if (typeof node !== 'object' || node === null) return;\n const record = node as PlainObject;\n if (record['secret'] === true) {\n record[OVERRIDE_ANNOTATION] = false;\n if ('default' in record) record['default'] = SECRET_MASK;\n }\n for (const value of Object.values(record)) markSecrets(value);\n}\n\ninterface Layer {\n readonly source: Exclude<ConfigSource, 'default' | 'env'>;\n readonly fields: PlainObject;\n readonly messages: PlainObject;\n}\n\ntype Computed =\n | {\n ok: true;\n resolved: ResolvedPluginConfig;\n secrets: string[];\n sources: Record<string, ConfigSource>;\n }\n | { ok: false; error: PluginConfigError };\n\n/** Cria a config dos plugins. Não lê storage nem ambiente até a primeira chamada. */\nexport function createPluginConfigs(options: PluginConfigsOptions): PluginConfigs {\n const env = options.env ?? processEnv();\n const kv = kernelStorage(options.storage, 'config').kv;\n const log = options.log ?? createNoopLogger();\n const file = options.file ?? {};\n const byName = new Map(options.plugins.map((plugin) => [plugin.name, plugin]));\n\n for (const name of Object.keys(file)) {\n if (!byName.has(name)) {\n log.warn(`pluginConfig cita \"${name}\", que não existe entre os plugins`, { plugin: name });\n }\n }\n\n let queue: Promise<unknown> = Promise.resolve();\n // Avisa uma vez por campo: `resolve` roda a cada setup/reload/describe.\n const warnedLegacy = new Set<string>();\n const warnedShort = new Set<string>();\n\n function definitionOf(name: string): PluginDefinition {\n const definition = byName.get(name);\n if (!definition) throw new RangeError(`config: plugin desconhecido \"${name}\"`);\n return definition;\n }\n\n /** Separa campos e `messages` de uma entrada; formato errado vira problema da fonte. */\n function toLayer(\n source: Layer['source'],\n raw: unknown,\n issues: PluginConfigIssue[],\n ): Layer | undefined {\n if (raw === undefined) return undefined;\n if (!isPlainObject(raw)) {\n issues.push({ path: '', message: 'a config do plugin deve ser um objeto', source });\n return undefined;\n }\n const { [MESSAGES_KEY]: messages, ...fields } = raw;\n if (messages !== undefined && !isPlainObject(messages)) {\n issues.push({ path: MESSAGES_KEY, message: 'deve ser um objeto chave → texto', source });\n return { source, fields, messages: {} };\n }\n return { source, fields, messages: messages ?? {} };\n }\n\n function compute(definition: PluginDefinition, override: unknown): Computed {\n const { name } = definition;\n const schema = definition.config;\n const shape = schema ? objectShape(schema) : undefined;\n // Erros do autor do plugin, não da config: mensagem direta, sem fonte.\n if (schema && !shape) {\n throw new TypeError(`plugin \"${name}\": o schema de config deve ser um z.object(...)`);\n }\n if (shape && MESSAGES_KEY in shape) {\n throw new TypeError(\n `plugin \"${name}\": \"${MESSAGES_KEY}\" é reservado para sobrescrever textos (ADR 0025) ` +\n 'e não pode ser campo do schema de config',\n );\n }\n const misplaced = schema ? misplacedSecrets(schema) : [];\n if (misplaced.length > 0) {\n throw new TypeError(\n `plugin \"${name}\": secret() só vale em campo de z.object (em qualquer nível de objetos); ` +\n `dentro de array, record ou union ele não seria censurado nem protegido (ADR 0032): ` +\n misplaced.map((path) => `\"${path}\"`).join(', '),\n );\n }\n const collisions = envCollisions(name, shape, Object.keys(definition.messages ?? {}));\n if (collisions.size > 0) {\n const list = [...collisions].map(([env, paths]) => `${env} (${paths.join(', ')})`);\n throw new TypeError(\n `plugin \"${name}\": campos diferentes geram a mesma variável de ambiente; renomeie um ` +\n `deles: ${list.join('; ')}`,\n );\n }\n\n const issues: PluginConfigIssue[] = [];\n // Da menor para a maior precedência.\n const layers = [\n toLayer('override', override, issues),\n toLayer('file', file[name], issues),\n ].filter((layer) => layer !== undefined);\n const envFields = shape ? readEnvFields(name, shape, env) : [];\n const envMessages: EnvEntry[] = Object.keys(definition.messages ?? {}).flatMap((key) => {\n const variable = envName(name, [MESSAGES_KEY, key]);\n const value = env[variable];\n return value === undefined ? [] : [{ path: [key], name: variable, value }];\n });\n\n let fields: PlainObject = {};\n for (const layer of layers) fields = deepMerge(fields, layer.fields);\n const envLayer: PlainObject = {};\n for (const entry of envFields) setIn(envLayer, entry.path, entry.value);\n fields = deepMerge(fields, envLayer);\n\n const sourceOf = (path: readonly PropertyKey[]): Omit<PluginConfigIssue, 'message'> => {\n const label = path.map(String).join('.');\n const fromEnv = envFields.find((entry) => startsWith(path, entry.path));\n if (fromEnv) return { path: label, source: 'env', env: fromEnv.name };\n for (const layer of layers.toReversed()) {\n if (provides(layer.fields, path)) return { path: label, source: layer.source };\n }\n return { path: label, source: 'default' };\n };\n\n let config: unknown;\n if (!schema) {\n for (const layer of layers) {\n for (const key of Object.keys(layer.fields)) {\n issues.push({\n path: key,\n message: 'o plugin não declara config; o campo não tem para onde ir',\n source: layer.source,\n });\n }\n }\n } else {\n const parsed = schema.safeParse(fields);\n if (parsed.success) config = parsed.data;\n else {\n // Só a mensagem do Zod: ela não inclui o valor recebido, que pode ser secreto.\n for (const issue of parsed.error.issues) {\n issues.push({ ...sourceOf(issue.path), message: issue.message });\n }\n }\n }\n\n const base = definition.messages ?? {};\n const messages: Record<string, string> = { ...base };\n const messageSources: Record<string, ConfigSource> = Object.fromEntries(\n Object.keys(base).map((key) => [`${MESSAGES_KEY}.${key}`, 'default' as const]),\n );\n const messageLayers = [\n ...layers.map((layer) => ({\n entries: Object.entries(layer.messages),\n sourceOf: (): Omit<PluginConfigIssue, 'message' | 'path'> => ({ source: layer.source }),\n })),\n {\n entries: envMessages.map((entry) => [entry.path[0] as string, entry.value] as const),\n sourceOf: (key: string): Omit<PluginConfigIssue, 'message' | 'path'> => ({\n source: 'env',\n env: envName(name, [MESSAGES_KEY, key]),\n }),\n },\n ];\n for (const layer of messageLayers) {\n for (const [key, text] of layer.entries) {\n const at = { path: `${MESSAGES_KEY}.${key}`, ...layer.sourceOf(key) };\n if (!Object.hasOwn(base, key)) {\n const known = Object.keys(base);\n issues.push({\n ...at,\n message:\n `mensagem desconhecida; o plugin declara ` +\n (known.length === 0 ? 'nenhuma' : known.map((k) => `\"${k}\"`).join(', ')),\n });\n } else if (typeof text !== 'string') {\n issues.push({ ...at, message: 'deve ser texto' });\n } else {\n // O plugin só passa os valores do texto padrão: um placeholder a mais na sobrescrita\n // faria o `ctx.t` lançar na hora de usar, longe da config (ADR 0092).\n const problem = placeholderIssue(text, base[key] as string);\n if (problem !== null) {\n issues.push({ ...at, message: problem });\n } else {\n messages[key] = text;\n messageSources[at.path] = at.source;\n }\n }\n }\n }\n\n if (issues.length > 0) return { ok: false, error: new PluginConfigError(name, issues) };\n const secrets: string[] = [];\n if (schema) {\n mapSecrets(schema, config, (value) => {\n secretStrings(value, secrets);\n return value;\n });\n }\n // Pelos caminhos da saída: é o que o plugin recebe, defaults inclusive.\n const sources: Record<string, ConfigSource> = {};\n if (isPlainObject(config)) {\n for (const path of leafPaths(config)) sources[path.join('.')] = sourceOf(path).source;\n }\n return {\n ok: true,\n resolved: { config, messages: Object.freeze(messages) },\n secrets,\n sources: { ...sources, ...messageSources },\n };\n }\n\n /**\n * Override salvo antes da regra de segredos (ou escrito direto no banco) pode ter campo\n * `secret`. O valor é ignorado com aviso em vez de falhar a config: um dado legado não deve\n * desligar o plugin, e o segredo de verdade continua vindo de env ou do arquivo.\n */\n function dropLegacySecrets(definition: PluginDefinition, stored: unknown): unknown {\n if (!definition.config || !isPlainObject(stored)) return stored;\n let clean = stored;\n for (const path of secretPaths(definition.config, stored)) {\n clean = withoutPath(clean, path);\n const label = path.join('.');\n const key = `${definition.name}:${label}`;\n if (warnedLegacy.has(key)) continue;\n warnedLegacy.add(key);\n // Só o caminho: o valor é segredo e ainda não está no `SecretSet`.\n log.warn(\n `override do plugin \"${definition.name}\" tem o campo secreto \"${label}\", ignorado; ` +\n `defina pela env ${envName(definition.name, path)} ou pelo arquivo`,\n { plugin: definition.name, field: label },\n );\n }\n return clean;\n }\n\n /**\n * Avisa (uma vez por campo, sem o valor) do segredo curto demais para a censura do log\n * (`MIN_SECRET_LENGTH`): o logger não o censura, e ele sai no log como qualquer texto.\n */\n function warnShortSecrets(definition: PluginDefinition, config: unknown): void {\n if (!definition.config) return;\n for (const path of secretPaths(definition.config, config)) {\n const values: string[] = [];\n secretStrings(valueAt(config, path), values);\n if (!values.some((value) => value.length < MIN_SECRET_LENGTH)) continue;\n const label = path.join('.');\n const key = `${definition.name}:${label}`;\n if (warnedShort.has(key)) continue;\n warnedShort.add(key);\n log.warn(\n `campo secreto \"${label}\" do plugin \"${definition.name}\" tem menos de ` +\n `${MIN_SECRET_LENGTH} caracteres e não é censurado no log`,\n { plugin: definition.name, field: label },\n );\n }\n }\n\n /** Grava os segredos da config resolvida no `SecretSet` e avisa dos curtos demais. */\n function trackSecrets(definition: PluginDefinition, result: Computed & { ok: true }): void {\n warnShortSecrets(definition, result.resolved.config);\n options.secrets?.set(SECRETS_OWNER(definition.name), result.secrets);\n }\n\n async function current(name: string): Promise<Computed & { ok: true }> {\n const definition = definitionOf(name);\n const result = compute(definition, dropLegacySecrets(definition, await kv.get(name)));\n if (!result.ok) throw result.error;\n trackSecrets(definition, result);\n return result;\n }\n\n /**\n * O dashboard diria \"salvo\" para um campo que o arquivo ou o env decidem (precedência do\n * ADR 0017/0032). Avisa com caminho e fonte; o valor fica de fora (pode ser sensível).\n */\n function warnShadowed(\n name: string,\n overrides: JsonObject,\n sources: Readonly<Record<string, ConfigSource>>,\n ): void {\n const fields = leafPaths(overrides).flatMap((path) => {\n const label = path.join('.');\n // Folha do override que virou objeto mais em cima: vale a fonte das folhas de baixo.\n const below = Object.entries(sources).filter(\n ([key]) => key === label || key.startsWith(`${label}.`),\n );\n const [first] = below;\n if (!first || below.some(([, source]) => source === 'override')) return [];\n return [{ path: label, source: first[1] }];\n });\n if (fields.length === 0) return;\n log.warn(\n `override do plugin \"${name}\" sem efeito em ` +\n `${fields.map((field) => `\"${field.path}\" (vale ${field.source})`).join(', ')}`,\n { plugin: name, fields },\n );\n }\n\n async function runSetOverrides(\n name: string,\n overrides: JsonObject,\n ): Promise<PluginReloadResult | undefined> {\n const definition = definitionOf(name);\n // O storage guarda o override em texto puro (banco, backups): segredo não entra (ADR 0032).\n const secretIssues: PluginConfigIssue[] = definition.config\n ? secretPaths(definition.config, overrides).map((path) => ({\n path: path.join('.'),\n message:\n 'campo secreto não pode ser definido por override (o storage guarda em texto ' +\n `puro); defina pela env ${envName(name, path)} ou pelo arquivo ` +\n `pluginConfig[\"${name}\"].${path.join('.')}`,\n source: 'override',\n }))\n : [];\n if (secretIssues.length > 0) throw new PluginConfigError(name, secretIssues);\n const result = compute(definition, overrides);\n if (!result.ok) throw result.error;\n warnShadowed(name, overrides, result.sources);\n // Antes de salvar e de recarregar: o reload loga, e o segredo novo já precisa sair censurado.\n trackSecrets(definition, result);\n if (Object.keys(overrides).length === 0) await kv.delete(name);\n else await kv.set(name, overrides);\n return options.reload ? options.reload(name) : undefined;\n }\n\n return {\n resolve: async (name) => (await current(name)).resolved,\n\n setOverrides(name: string, overrides: JsonObject): Promise<PluginReloadResult | undefined> {\n // Uma mudança por vez: duas gravações concorrentes reordenariam save e reload.\n const result = queue.then(() => runSetOverrides(name, overrides));\n queue = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n },\n\n async describe(name: string): Promise<PluginConfigView> {\n const definition = definitionOf(name);\n const { resolved, sources } = await current(name);\n const { config, messages } = resolved;\n const masked = definition.config\n ? mapSecrets(definition.config, config, () => SECRET_MASK)\n : config;\n return { config: masked, messages, sources };\n },\n\n jsonSchema(name: string): PluginConfigJsonSchema | undefined {\n const schema = definitionOf(name).config;\n if (!schema) return undefined;\n // `input`: o formulário preenche a entrada (campos com default são opcionais). Transform\n // não tem JSON Schema; vira `{}` em vez de lançar.\n const json = schema.toJSONSchema({ io: 'input', unrepresentable: 'any' });\n markSecrets(json);\n return json as PluginConfigJsonSchema;\n },\n };\n}\n","// Resposta esperada (ADR 0060): o handler pergunta, registra qual passo trata a próxima mensagem\n// daquela pessoa naquele chat e termina, sem segurar o chat na fila de entrada (ADR 0042). O\n// estado fica em memória; o passo é nomeado e o `data` é JSON para que uma espera possa ir ao\n// storage depois sem mudar a API.\n\nimport type { BotMessageContext } from '#context.ts';\nimport { ExecutionTimeoutError } from '#deadline.ts';\nimport type { MessageText } from '#plugin/messages.ts';\nimport type { JsonValue } from '#storage/types.ts';\n\n/** Validade padrão de uma espera: 5 minutos. */\nexport const DEFAULT_REPLY_TTL_MS: number = 5 * 60_000;\n\n/** Maior atraso que o `setTimeout` aceita; acima disso ele dispara na hora. */\nconst MAX_TTL_MS = 2_147_483_647;\n\nexport interface ExpectReplyOptions {\n /** Estado do fluxo, entregue ao passo em `ctx.data`. Padrão: `null`. */\n readonly data?: JsonValue;\n /** Validade da espera em ms. Padrão: 5 minutos. Expirada, some sem aviso. */\n readonly ttlMs?: number;\n}\n\n/**\n * Registra que a próxima mensagem do remetente, neste chat, vai para o passo `step` deste plugin.\n * Uma espera por (chat, remetente): registrar de novo, deste plugin ou de outro, troca a\n * anterior. Lança `TypeError` se o plugin não definiu o passo e `RangeError` com `ttlMs`\n * inválido.\n */\nexport type ExpectReply = (step: string, options?: ExpectReplyOptions) => void;\n\n/** Contexto do passo: o da mensagem que respondeu, com o estado guardado na espera. */\nexport interface StepContext extends BotMessageContext {\n /** Nome do passo que está rodando. */\n readonly step: string;\n /** O `data` da espera; `null` se ela não trouxe nenhum. */\n readonly data: JsonValue;\n /**\n * Aborta quando o passo estoura o prazo (`timeouts.commandMs`), com `reason` =\n * `StepTimeoutError`, como o `signal` do comando.\n */\n readonly signal: AbortSignal;\n /** Encadeia a pergunta seguinte do fluxo (ver `ExpectReply`). */\n readonly expectReply: ExpectReply;\n /** Texto de `messages` do plugin com os placeholders preenchidos (ver `CommandContext.t`). */\n readonly t: MessageText;\n}\n\nexport type StepHandler = (ctx: StepContext) => unknown;\n\n/** Passos de conversa do plugin (`ctx.conversations`). */\nexport interface Conversations {\n /**\n * Define o passo `step`, que trata a resposta registrada com `expectReply(step)`. Nome vazio ou\n * repetido no mesmo plugin lança `TypeError`. O passo e as esperas dele saem no\n * teardown/reload.\n */\n define(step: string, handler: StepHandler): void;\n}\n\n/** O passo estourou o prazo. Vai em `plugin.error` com `phase: 'step'` e `timedOut: true`. */\nexport class StepTimeoutError extends ExecutionTimeoutError {\n override readonly name: string = 'StepTimeoutError';\n readonly step: string;\n\n constructor(plugin: string, step: string, timeoutMs: number) {\n super(plugin, `passo \"${step}\"`, timeoutMs);\n this.step = step;\n }\n}\n\n/** Passo como o kernel o roda: já com prazo e visão do plugin, montados por quem o define. */\nexport type KernelStep<C> = (ctx: C, data: JsonValue) => unknown;\n\n/** Espera consumida por `take`: o que o bot precisa para rodar o passo. */\nexport interface PendingReply<C> {\n readonly plugin: string;\n readonly step: string;\n readonly data: JsonValue;\n readonly run: KernelStep<C>;\n}\n\ninterface Wait {\n readonly plugin: string;\n readonly step: string;\n readonly data: JsonValue;\n readonly timer: ReturnType<typeof setTimeout>;\n}\n\n/** Esperas e passos de todos os plugins de um bot (estado no closure do bot, ADR 0004). */\nexport class ConversationRegistry<C> {\n readonly #steps = new Map<string, Map<string, KernelStep<C>>>();\n readonly #waits = new Map<string, Wait>();\n #closed = false;\n\n define(plugin: string, step: string, run: KernelStep<C>): void {\n if (typeof step !== 'string' || step.length === 0) {\n throw new TypeError(`plugin \"${plugin}\": nome de passo vazio`);\n }\n let steps = this.#steps.get(plugin);\n if (steps === undefined) {\n steps = new Map();\n this.#steps.set(plugin, steps);\n }\n if (steps.has(step)) throw new TypeError(`plugin \"${plugin}\": passo \"${step}\" já definido`);\n steps.set(step, run);\n }\n\n expect(\n plugin: string,\n chatId: string,\n senderId: string,\n step: string,\n options: ExpectReplyOptions = {},\n ): void {\n if (!this.#steps.get(plugin)?.has(step)) {\n throw new TypeError(\n `plugin \"${plugin}\": expectReply(\"${step}\") sem o passo; defina-o com ` +\n 'ctx.conversations.define',\n );\n }\n const ttlMs = options.ttlMs ?? DEFAULT_REPLY_TTL_MS;\n if (!(Number.isFinite(ttlMs) && ttlMs > 0 && ttlMs <= MAX_TTL_MS)) {\n throw new RangeError(`plugin \"${plugin}\": ttlMs de expectReply inválido: ${ttlMs}`);\n }\n // Depois do shutdown não há quem responda, e o timer sobreviveria ao `stop()`.\n if (this.#closed) return;\n const key = waitKey(chatId, senderId);\n this.#drop(key);\n const timer = setTimeout(() => {\n if (this.#waits.get(key)?.timer === timer) this.#waits.delete(key);\n }, ttlMs);\n // A espera não mantém o processo vivo: ela só importa se chegar mensagem.\n timer.unref?.();\n this.#waits.set(key, { plugin, step, data: options.data ?? null, timer });\n }\n\n /**\n * Retira a espera do remetente no chat, se houver. Quem chama decide se roda o passo ou, com um\n * comando digitado, só a descarta. O mapa vazio sai sem montar a chave: o caminho de cada\n * mensagem não paga nada sem conversa aberta.\n */\n take(chatId: string, senderId: string): PendingReply<C> | undefined {\n if (this.#waits.size === 0) return undefined;\n const key = waitKey(chatId, senderId);\n const wait = this.#waits.get(key);\n if (wait === undefined) return undefined;\n this.#drop(key);\n // O passo existe: o `removePlugin` tira passos e esperas juntos.\n const run = this.#steps.get(wait.plugin)?.get(wait.step) as KernelStep<C>;\n return { plugin: wait.plugin, step: wait.step, data: wait.data, run };\n }\n\n /** O passo do plugin, para rodar sem espera (o clique num botão, ADR 0062). */\n find(plugin: string, step: string): KernelStep<C> | undefined {\n return this.#steps.get(plugin)?.get(step);\n }\n\n /** Tira os passos e as esperas do plugin (teardown/reload), com os timers. */\n removePlugin(plugin: string): void {\n this.#steps.delete(plugin);\n for (const [key, wait] of this.#waits) {\n if (wait.plugin === plugin) this.#drop(key);\n }\n }\n\n /** Descarta tudo e recusa esperas novas: nenhum timer sobrevive ao shutdown. */\n close(): void {\n this.#closed = true;\n for (const key of [...this.#waits.keys()]) this.#drop(key);\n this.#steps.clear();\n }\n\n #drop(key: string): void {\n const wait = this.#waits.get(key);\n if (wait === undefined) return;\n clearTimeout(wait.timer);\n this.#waits.delete(key);\n }\n}\n\n// NUL não aparece em ID de chat nem de contato de nenhuma plataforma: a chave não colide.\nconst waitKey = (chatId: string, senderId: string): string => `${chatId}\\u0000${senderId}`;\n","import {\n ArmedTimers,\n ContextExpiredError,\n DEADLINE,\n Deadline,\n deadlineOf,\n ListenerTimeoutError,\n} from '#deadline.ts';\nimport type { Message, MessageType } from '#message/types.ts';\nimport type { Unsubscribe } from '#transport/types.ts';\nimport type {\n BotEventName,\n BotEvents,\n EventSubscriber,\n ListenerContext,\n ListenerExtras,\n MessageFilter,\n MessageTypeEvents,\n PluginErrorEvent,\n SubscribeOptions,\n} from './types.ts';\n\n/** Eventos que se emitem diretamente. `message:<type>` não entra: o bus o deriva de `message`. */\nexport type EmittableEventName = Exclude<BotEventName, keyof MessageTypeEvents>;\n\n/**\n * Extras do contexto. Opcionais para o barramento: ele só os copia, sem conferir. Nos eventos de\n * mensagem o `ListenerContext` declara `MessageListenerFields`, e quem garante que eles chegam é\n * o `Bot`, que monta o contexto de cada plugin (M1-16); quem usa o barramento solto e emite\n * mensagem sem extras entrega listeners sem esses campos.\n */\nexport type EmitExtras<E extends BotEventName> = [extras?: ListenerExtras<E>];\n\nexport interface EmitResult {\n /** Listeners que rodaram (os barrados pelo filtro não contam). */\n readonly listeners: number;\n /** Algum listener chamou `claim()`, antes ou depois do primeiro `await`. */\n readonly claimed: boolean;\n /** Listeners que lançaram, rejeitaram ou estouraram o prazo. */\n readonly failed: number;\n}\n\nexport interface EventBusOptions {\n /** Prazo padrão de cada listener em ms; `ListenerOptions.timeoutMs` sobrescreve. Padrão: 30000. */\n readonly listenerTimeoutMs?: number;\n /**\n * Destino garantido de toda falha de listener (o log do kernel). Recebe também as falhas que\n * não viram evento: as dos listeners de `plugin.error` e as rejeições que chegam depois do\n * prazo. Não deve lançar.\n */\n readonly onError: (error: PluginErrorEvent) => void;\n /** Onde ficam os prazos armados dos listeners, para o shutdown do `Bot` desarmá-los. */\n readonly armed?: ArmedTimers;\n}\n\n/** Deriva o contexto que um listener recebe a partir do contexto da emissão. */\nexport type ListenerView = <C extends object>(ctx: C) => C;\n\nexport interface PluginSubscriberOptions {\n /**\n * Visão por listener para os listeners deste plugin no `event` assinado; `undefined` usa a\n * padrão (`Object.create(ctx)`). A visão precisa herdar do contexto recebido. O `Bot` a usa\n * para pôr `message`/`text`/`reply`/`log` do plugin nos eventos de mensagem sem uma segunda\n * camada de protótipo no caminho quente.\n */\n readonly view?: (event: BotEventName) => ListenerView | undefined;\n /**\n * `Deadline` de vida do plugin: o de cada listener é filho dele, então o descarte do plugin\n * aborta o `signal` e recusa o `reply` dos listeners ainda em andamento.\n */\n readonly lifetime?: Deadline;\n}\n\nexport interface EventBus {\n /** Assinatura em nome do plugin: falhas saem com o nome dele e `removePlugin` as desfaz. */\n forPlugin(plugin: string, options?: PluginSubscriberOptions): EventSubscriber;\n /** Remove todos os listeners do plugin (teardown e reload). */\n removePlugin(plugin: string): void;\n /**\n * Inicia todos os listeners do evento, em ordem de prioridade decrescente, sem esperar um\n * pelo outro. `message` alcança também os listeners de `message:<tipo da mensagem>`, numa\n * única ordem e com o mesmo `claim()`. Resolve quando todos assentam (ou estouram o prazo);\n * nunca rejeita, porque cada falha já foi entregue a `plugin.error` e ao `onError`.\n */\n emit<E extends EmittableEventName>(\n event: E,\n payload: BotEvents[E],\n ...extras: EmitExtras<E>\n ): Promise<EmitResult>;\n listenerCount(event: BotEventName): number;\n /** Nenhum listener assíncrono em andamento (os que estouraram o prazo já não contam). */\n readonly idle: boolean;\n /** Resolve quando `idle`. Não impede novas emissões. */\n onIdle(): Promise<void>;\n}\n\nexport const DEFAULT_LISTENER_TIMEOUT_MS = 30_000;\n\ntype AnyContext = ListenerContext<BotEventName>;\ntype AnyListener = (ctx: AnyContext) => unknown;\n\ninterface Entry {\n readonly plugin: string;\n readonly listener: AnyListener;\n readonly priority: number;\n readonly timeoutMs: number;\n /** Ordem de registro, para desempatar prioridades iguais de forma estável entre eventos. */\n readonly seq: number;\n /** Tipos aceitos em `quoted`; `null` sem filtro. */\n readonly quoted: ReadonlySet<MessageType> | null;\n readonly view: ListenerView | undefined;\n readonly lifetime: Deadline | undefined;\n}\n\nconst NO_ENTRIES: readonly Entry[] = [];\nconst NO_LISTENERS: Promise<EmitResult> = Promise.resolve({\n listeners: 0,\n claimed: false,\n failed: 0,\n});\n\nfunction compare(a: Entry, b: Entry): number {\n return b.priority - a.priority || a.seq - b.seq;\n}\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n value !== null &&\n (typeof value === 'object' || typeof value === 'function') &&\n typeof (value as PromiseLike<unknown>).then === 'function'\n );\n}\n\nfunction quotedSet(filter: MessageFilter['quoted']): ReadonlySet<MessageType> | null {\n if (filter === undefined) return null;\n return new Set(typeof filter === 'string' ? [filter] : filter);\n}\n\nfunction validTimeout(value: number): number {\n // setTimeout trata Infinity/NaN como 1 ms: o listener estouraria na hora.\n if (!Number.isFinite(value) || value <= 0) throw new RangeError(`Prazo inválido: ${value}`);\n return value;\n}\n\nexport function createEventBus(options: EventBusOptions): EventBus {\n const defaultTimeoutMs = validTimeout(options.listenerTimeoutMs ?? DEFAULT_LISTENER_TIMEOUT_MS);\n const onError = options.onError;\n const armed = options.armed ?? new ArmedTimers();\n // Arrays imutáveis (copy-on-write): a emissão percorre o array da vez sem copiar, e quem\n // (des)assina durante uma emissão não afeta a rodada em andamento.\n const byEvent = new Map<string, readonly Entry[]>();\n // `message` + `message:<tipo>` já mesclados por tipo; refeito só quando as assinaturas mudam.\n const messageEntries = new Map<MessageType, readonly Entry[]>();\n let seq = 0;\n // Listeners assíncronos em andamento, para o `bot.settled()`: eventos diretos e `plugin.error`\n // são emitidos sem ninguém esperar, então só o barramento sabe que ainda há trabalho.\n let running = 0;\n let idleWaiters: (() => void)[] = [];\n\n function settle(): void {\n running--;\n if (running > 0 || idleWaiters.length === 0) return;\n const waiters = idleWaiters;\n idleWaiters = [];\n for (const resolve of waiters) resolve();\n }\n\n function changed(event: string, entries: readonly Entry[]): void {\n if (entries.length === 0) byEvent.delete(event);\n else byEvent.set(event, entries);\n messageEntries.clear();\n }\n\n function entriesForMessage(type: MessageType): readonly Entry[] {\n let merged = messageEntries.get(type);\n if (merged === undefined) {\n const base = byEvent.get('message') ?? NO_ENTRIES;\n const typed = byEvent.get(`message:${type}`) ?? NO_ENTRIES;\n if (typed.length === 0) merged = base;\n else if (base.length === 0) merged = typed;\n else merged = [...base, ...typed].sort(compare);\n messageEntries.set(type, merged);\n }\n return merged;\n }\n\n function subscribe(\n plugin: string,\n options: PluginSubscriberOptions | undefined,\n event: BotEventName,\n first: unknown,\n second: unknown,\n ): Unsubscribe {\n const [listener, opts] = (typeof first === 'function' ? [first, second] : [second, first]) as [\n unknown,\n (SubscribeOptions<'message'> & SubscribeOptions<BotEventName>) | undefined,\n ];\n if (typeof listener !== 'function') throw new TypeError(`Listener de \"${event}\" não é função`);\n const priority = opts?.priority ?? 0;\n // NaN quebraria a comparação do sort e embaralharia a ordem do evento inteiro.\n if (!Number.isFinite(priority)) throw new RangeError(`Prioridade inválida: ${priority}`);\n const entry: Entry = {\n plugin,\n listener: listener as AnyListener,\n priority,\n timeoutMs: opts?.timeoutMs === undefined ? defaultTimeoutMs : validTimeout(opts.timeoutMs),\n seq: seq++,\n quoted: quotedSet(opts?.quoted),\n view: options?.view?.(event),\n lifetime: options?.lifetime,\n };\n changed(event, [...(byEvent.get(event) ?? NO_ENTRIES), entry].sort(compare));\n return () => {\n const current = byEvent.get(event);\n if (!current?.includes(entry)) return;\n changed(\n event,\n current.filter((e) => e !== entry),\n );\n };\n }\n\n function fail(entry: Entry, event: BotEventName, error: unknown, timedOut: boolean): void {\n const report: PluginErrorEvent = {\n plugin: entry.plugin,\n phase: 'listener',\n event,\n error,\n timedOut,\n };\n onError(report);\n // Falha de um listener de `plugin.error` viraria outro `plugin.error`, em loop: fica só no\n // onError.\n if (event !== 'plugin.error') void emit('plugin.error', report);\n }\n\n /**\n * Corre a promise do listener contra o prazo; resolve `true` se ele falhou. Estourado o prazo,\n * expira o `Deadline` do listener: o `ctx.signal` dele aborta (ADR 0033).\n */\n function watch(\n entry: Entry,\n event: BotEventName,\n result: PromiseLike<unknown>,\n deadline: Deadline,\n ): Promise<boolean> {\n running++;\n return new Promise<boolean>((resolve) => {\n let settled = false;\n const disarm = (): void => {\n settled = true;\n cancel();\n armed.delete(disarm);\n settle();\n };\n // Pausa enquanto o `reply` do listener aguarda a fila de saída (ADR 0047).\n const cancel = deadline.armTimer(entry.timeoutMs, () => {\n disarm();\n const error = new ListenerTimeoutError(entry.plugin, event, entry.timeoutMs);\n deadline.expire(error);\n fail(entry, event, error, true);\n resolve(true);\n });\n armed.add(disarm);\n result.then(\n () => {\n if (settled) return;\n disarm();\n resolve(false);\n },\n (error: unknown) => {\n if (settled) {\n // Já reportado como timeout; o erro tardio só vai para o log. A recusa de um\n // contexto expirado já foi logada quando aconteceu (ADR 0033): não repete.\n if (!(error instanceof ContextExpiredError)) {\n onError({ plugin: entry.plugin, phase: 'listener', event, error, timedOut: false });\n }\n return;\n }\n disarm();\n fail(entry, event, error, false);\n resolve(true);\n },\n );\n });\n }\n\n function emit<E extends EmittableEventName>(\n event: E,\n payload: BotEvents[E],\n ...[extras]: EmitExtras<E>\n ): Promise<EmitResult> {\n const entries =\n event === 'message'\n ? entriesForMessage((payload as Message).type)\n : (byEvent.get(event) ?? NO_ENTRIES);\n if (entries.length === 0) return NO_LISTENERS;\n\n // Um contexto por emissão, compartilhado: é o que torna o claim() visível aos demais. Cada\n // listener recebe uma visão derivada dele com o próprio `Deadline`: o prazo é por listener,\n // e um lento expirar não pode abortar o `signal` de outro que está no prazo.\n let claimed = false;\n const ctx = {\n event,\n payload,\n get claimed() {\n return claimed;\n },\n claim() {\n claimed = true;\n },\n get signal(): AbortSignal {\n // `this` é a visão do listener (ou uma derivada dela); o `Deadline` está nela.\n return (deadlineOf(this) as Deadline).signal;\n },\n };\n if (extras !== undefined) Object.assign(ctx, extras);\n\n let listeners = 0;\n let failed = 0;\n let pending: Promise<boolean>[] | undefined;\n for (const entry of entries) {\n if (entry.quoted !== null) {\n const quoted = (payload as Message).quoted;\n if (!quoted || !entry.quoted.has(quoted.type)) continue;\n }\n listeners++;\n const deadline = new Deadline(entry.lifetime);\n const view: { [DEADLINE]?: Deadline } =\n entry.view === undefined ? Object.create(ctx) : entry.view(ctx);\n view[DEADLINE] = deadline;\n let result: unknown;\n try {\n result = entry.listener(view as unknown as AnyContext);\n } catch (error) {\n failed++;\n fail(entry, event, error, false);\n continue;\n }\n if (isThenable(result)) {\n pending ??= [];\n pending.push(watch(entry, event, result, deadline));\n }\n }\n\n if (pending === undefined) return Promise.resolve({ listeners, claimed, failed });\n return Promise.all(pending).then((results) => {\n for (const listenerFailed of results) if (listenerFailed) failed++;\n return { listeners, claimed, failed };\n });\n }\n\n return {\n forPlugin(plugin, options) {\n return {\n on(event: BotEventName, first: unknown, second?: unknown): Unsubscribe {\n return subscribe(plugin, options, event, first, second);\n },\n } as EventSubscriber;\n },\n\n removePlugin(plugin) {\n for (const [event, entries] of byEvent) {\n const kept = entries.filter((e) => e.plugin !== plugin);\n if (kept.length !== entries.length) changed(event, kept);\n }\n },\n\n emit,\n\n listenerCount(event) {\n return byEvent.get(event)?.length ?? 0;\n },\n\n get idle() {\n return running === 0;\n },\n\n onIdle() {\n if (running === 0) return Promise.resolve();\n return new Promise((resolve) => idleWaiters.push(resolve));\n },\n };\n}\n","// `ctx.groups` (ADR 0040): leitura dos metadados direto no transport; alteração de participantes\n// é tráfego e passa pela fila de saída, como as ações de `ctx.send`.\n\nimport type { EnqueueAction } from '#outbound/actions.ts';\nimport type { ActionOptions } from '#outbound/types.ts';\nimport { assertCapability, groupActionCapability } from '#transport/capabilities.ts';\nimport type { GroupMetadata, GroupParticipantAction, Transport } from '#transport/types.ts';\n\nexport interface Groups {\n /**\n * Nome, descrição e participantes do grupo (capability `groups`). `participants` fica ausente\n * onde a plataforma não lista membros (ADR 0059). Sem cache: cada chamada consulta o transport.\n */\n metadata(groupId: string): Promise<GroupMetadata>;\n /**\n * Adiciona, remove, promove ou rebaixa participantes, pela fila de saída. Cada ação exige a\n * sua capability: `groups.add`, `groups.remove` ou `groups.promote` (que vale também para\n * `demote`); o bot precisa ser admin do grupo.\n */\n updateParticipants(\n groupId: string,\n participantIds: readonly string[],\n action: GroupParticipantAction,\n options?: ActionOptions,\n ): Promise<void>;\n}\n\nexport function createGroups(\n transport: Pick<\n Transport,\n 'name' | 'capabilities' | 'getGroupMetadata' | 'updateGroupParticipants'\n >,\n action: EnqueueAction,\n): Groups {\n return {\n async metadata(groupId) {\n assertCapability(transport, 'groups');\n return transport.getGroupMetadata(groupId);\n },\n updateParticipants: (groupId, participantIds, change, options) =>\n action(\n groupActionCapability(change),\n groupId,\n () => transport.updateGroupParticipants(groupId, participantIds, change),\n options,\n ),\n };\n}\n","// Servidor HTTP do processo (ADR 0020, 0076). Um por processo, dividido pelos bots como o\n// storage: cada bot publica a própria tabela de rotas (`SessionHttp`) ao subir e a retira ao\n// parar. O router do Hono não remove rota, então o app é remontado da tabela a cada mudança,\n// que só acontece no boot, no reload e no stop. Hono, adapter do Node e `ws` carregam só ao\n// abrir a porta: bot sem rota não paga a memória deles.\n\nimport type { Server } from 'node:http';\nimport type { upgradeWebSocket as UpgradeWebSocket } from '@hono/node-server';\nimport type { Context, Hono } from 'hono';\nimport type { WSContext, WSEvents } from 'hono/ws';\nimport type { WebSocketServer } from 'ws';\nimport { BotConfigError } from '#config/owners.ts';\nimport type { Logger } from '#logger/types.ts';\nimport { DEFAULT_SESSION } from '#storage/namespace.ts';\nimport type {\n HttpHandler,\n HttpMethod,\n HttpOptions,\n HttpRequestInfo,\n HttpRoutes,\n HttpServer,\n HttpSocket,\n HttpSocketAccept,\n HttpSocketHandlers,\n} from './types.ts';\n\nconst METHODS: ReadonlySet<string> = new Set<HttpMethod>([\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n]);\n\n/** Código de fechamento \"going away\": a rota sumiu (reload, teardown ou stop). */\nconst GOING_AWAY = 1001;\n\n/** O mesmo método e caminho registrados duas vezes pelo mesmo dono. */\nexport class HttpRouteConflictError extends Error {\n override readonly name = 'HttpRouteConflictError';\n readonly method: HttpMethod;\n readonly path: string;\n\n constructor(method: HttpMethod, path: string) {\n super(`rota ${method} ${path} já registrada`);\n this.method = method;\n this.path = path;\n }\n}\n\n/** Módulos do servidor, carregados na primeira abertura da porta. */\ninterface ServerLib {\n readonly Hono: typeof Hono;\n readonly upgradeWebSocket: typeof UpgradeWebSocket;\n}\n\ninterface RouteEntry {\n readonly owner: string;\n readonly method: HttpMethod;\n /** Caminho relativo, normalizado (sem barra final). */\n readonly path: string;\n /** Resolvido ao montar o app: o nome do transport só existe depois da fábrica. */\n readonly base: () => string;\n readonly target: HttpHandler | { readonly ws: HttpSocketAccept };\n readonly onError: (error: unknown) => void;\n /** Conexões abertas, fechadas quando a rota sai. */\n readonly sockets: Set<WSContext>;\n}\n\n// O `HttpServer` público só expõe a porta; o resto é do kernel.\nconst hubs = new WeakMap<HttpServer, HttpHub>();\n\n/**\n * Servidor HTTP para `BotConfig.http`, o mesmo para todos os bots do processo. Nada abre aqui:\n * a porta abre no `start()` do primeiro bot que tiver rota (ver docs/http.md).\n */\nexport function createHttp(options: HttpOptions): HttpServer {\n const { port } = options;\n if (!(Number.isInteger(port) && port >= 0 && port <= 65_535)) {\n throw new RangeError(`http: port deve ser inteiro entre 0 e 65535 (recebido: ${port})`);\n }\n const hub = new HttpHub(options);\n const server: HttpServer = {\n get port() {\n return hub.port;\n },\n };\n hubs.set(server, hub);\n return server;\n}\n\n/** Tabela de rotas de uma sessão nesse servidor; sem efeito até o `attach`. */\nexport function sessionHttp(server: HttpServer, session: string, log: () => Logger): SessionHttp {\n const hub = hubs.get(server);\n if (hub === undefined) {\n throw new BotConfigError('http: passe o servidor criado por `createHttp({ port })`');\n }\n return new SessionHttp(hub, session, log);\n}\n\n/** Prefixo das rotas da sessão: nenhum na `default`, para a URL não mudar quando entra outro bot. */\nfunction sessionPrefix(session: string): string {\n return session === DEFAULT_SESSION ? '' : `/sessions/${session}`;\n}\n\nfunction normalizePath(path: string): string {\n if (typeof path !== 'string' || !path.startsWith('/')) {\n throw new TypeError(`http: o caminho deve começar com \"/\" (recebido: ${String(path)})`);\n }\n return path.length > 1 && path.endsWith('/') ? path.slice(0, -1) : path;\n}\n\n/** Rotas de um bot no servidor. Publicadas no `attach` (start) e retiradas no `detach` (stop). */\nexport class SessionHttp {\n readonly session: string;\n readonly log: () => Logger;\n readonly #hub: HttpHub;\n readonly #prefix: string;\n readonly #entries = new Map<string, RouteEntry>();\n #state: () => string = () => 'idle';\n #attached = false;\n\n constructor(hub: HttpHub, session: string, log: () => Logger) {\n this.#hub = hub;\n this.session = session;\n this.log = log;\n this.#prefix = sessionPrefix(session);\n }\n\n /**\n * Rotas de um dono (um plugin, ou o transport) sob `prefixo + segment()`. `onError` recebe a\n * falha de um handler com a rota (`POST /webhook`).\n */\n scope(\n owner: string,\n segment: () => string,\n onError: (error: unknown, route: string) => void,\n ): HttpRoutes {\n const base = (): string => this.#prefix + segment();\n const add = (method: HttpMethod, rawPath: string, target: RouteEntry['target']): void => {\n const path = normalizePath(rawPath);\n const key = `${owner} ${method} ${path}`;\n if (this.#entries.has(key)) throw new HttpRouteConflictError(method, path);\n this.#entries.set(key, {\n owner,\n method,\n path,\n base,\n target,\n onError: (error) => onError(error, `${method} ${path}`),\n sockets: new Set(),\n });\n if (this.#attached) this.#hub.changed();\n };\n return {\n get basePath() {\n return base();\n },\n route(method, path, handler) {\n if (!METHODS.has(method)) {\n throw new TypeError(`http: método não suportado: ${String(method)}`);\n }\n add(method, path, handler);\n },\n ws(path, accept) {\n add('GET', path, { ws: accept });\n },\n };\n }\n\n entries(): Iterable<RouteEntry> {\n return this.#entries.values();\n }\n\n get hasRoutes(): boolean {\n return this.#entries.size > 0;\n }\n\n state(): string {\n return this.#state();\n }\n\n /** Tira as rotas de um dono (teardown ou reload do plugin) e fecha as conexões delas. */\n removeOwner(owner: string): void {\n let removed = false;\n for (const [key, entry] of this.#entries) {\n if (entry.owner !== owner) continue;\n this.#entries.delete(key);\n closeSockets(entry);\n removed = true;\n }\n if (removed && this.#attached) this.#hub.changed();\n }\n\n /** Publica as rotas no servidor; sessão repetida no mesmo servidor é erro de config. */\n attach(state: () => string): void {\n this.#hub.attach(this);\n this.#state = state;\n this.#attached = true;\n }\n\n /** Abre a porta se alguma sessão tiver rota (e, daqui em diante, quando a primeira chegar). */\n listen(): Promise<void> {\n return this.#hub.listen();\n }\n\n /** Retira as rotas; o último bot a sair fecha a porta. */\n async detach(): Promise<void> {\n if (!this.#attached) return;\n this.#attached = false;\n for (const entry of this.#entries.values()) closeSockets(entry);\n this.#entries.clear();\n await this.#hub.detach(this);\n }\n}\n\nclass HttpHub {\n readonly #options: HttpOptions;\n readonly #sessions = new Map<string, SessionHttp>();\n #app: Hono | undefined;\n #lib: ServerLib | undefined;\n #server: Server | undefined;\n #wss: WebSocketServer | undefined;\n #listening: Promise<void> | undefined;\n #closing: Promise<void> = Promise.resolve();\n // Algum bot terminou o boot: rota que chegar depois (reload) abre a porta na hora.\n #armed = false;\n\n constructor(options: HttpOptions) {\n this.#options = options;\n }\n\n get port(): number | undefined {\n const address = this.#server?.address();\n return address !== null && typeof address === 'object' ? address.port : undefined;\n }\n\n attach(session: SessionHttp): void {\n if (this.#sessions.has(session.session)) {\n throw new BotConfigError(\n `http: a sessão \"${session.session}\" já está ligada a este servidor; cada bot precisa ` +\n 'de um `session` diferente',\n );\n }\n this.#sessions.set(session.session, session);\n this.changed();\n }\n\n async detach(session: SessionHttp): Promise<void> {\n if (this.#sessions.get(session.session) !== session) return;\n this.#sessions.delete(session.session);\n this.changed();\n if (this.#sessions.size === 0) await this.#close();\n }\n\n changed(): void {\n this.#app = undefined;\n if (this.#armed && this.#listening === undefined && this.#hasRoutes()) {\n this.#listen().catch((error: unknown) =>\n this.#log()?.error('http: falha ao abrir a porta', {\n err: error,\n port: this.#options.port,\n }),\n );\n }\n }\n\n listen(): Promise<void> {\n this.#armed = true;\n return this.#hasRoutes() ? this.#listen() : Promise.resolve();\n }\n\n #hasRoutes(): boolean {\n for (const session of this.#sessions.values()) if (session.hasRoutes) return true;\n return false;\n }\n\n #log(): Logger | undefined {\n for (const session of this.#sessions.values()) return session.log();\n return undefined;\n }\n\n #listen(): Promise<void> {\n if (this.#listening === undefined) {\n // Um fechamento em curso libera a porta antes de abrir de novo.\n const opening = this.#closing.then(() => this.#open());\n this.#listening = opening;\n // Falhou (porta ocupada): a próxima chamada tenta de novo. O erro segue para quem esperou.\n opening.catch(() => {\n if (this.#listening === opening) this.#listening = undefined;\n });\n }\n return this.#listening;\n }\n\n async #open(): Promise<void> {\n const [{ createAdaptorServer, upgradeWebSocket }, { Hono }, { WebSocketServer }] =\n await Promise.all([import('@hono/node-server'), import('hono'), import('ws')]);\n this.#lib = { Hono, upgradeWebSocket };\n const wss = new WebSocketServer({ noServer: true });\n const server = createAdaptorServer({\n fetch: (request, env) => this.#currentApp().fetch(request, env),\n websocket: { server: wss },\n }) as Server;\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(this.#options.port, this.#options.hostname, () => {\n server.off('error', reject);\n resolve();\n });\n });\n server.on('error', (error) => this.#log()?.error('http: erro no servidor', { err: error }));\n this.#server = server;\n this.#wss = wss;\n }\n\n async #close(): Promise<void> {\n this.#armed = false;\n const listening = this.#listening;\n if (listening === undefined) return;\n this.#listening = undefined;\n // Abertura que falhou não deixou nada para fechar.\n const closing = listening.then(\n () => this.#shut(),\n () => undefined,\n );\n this.#closing = closing.catch(() => undefined);\n await closing;\n }\n\n #shut(): Promise<void> {\n const server = this.#server;\n const wss = this.#wss;\n this.#server = undefined;\n this.#wss = undefined;\n if (server === undefined) return Promise.resolve();\n for (const client of wss?.clients ?? []) client.terminate();\n return new Promise<void>((resolve, reject) => {\n server.close((error) => (error ? reject(error) : resolve()));\n // Os bots já pararam: requisição em curso (ou keep-alive) não segura o encerramento.\n server.closeAllConnections();\n });\n }\n\n #currentApp(): Hono {\n // Só há requisição com a porta aberta, e a abertura carregou a lib.\n const lib = this.#lib as ServerLib;\n this.#app ??= this.#build(lib);\n return this.#app;\n }\n\n #build(lib: ServerLib): Hono {\n const app = new lib.Hono({ strict: false });\n app.get('/health', (c) => {\n const sessions: Record<string, string> = {};\n for (const [name, session] of this.#sessions) sessions[name] = session.state();\n const ok = Object.values(sessions).every((state) => state === 'running');\n return c.json({ status: ok ? 'ok' : 'degraded', sessions }, ok ? 200 : 503);\n });\n for (const session of this.#sessions.values()) {\n for (const entry of session.entries()) mount(app, entry, lib.upgradeWebSocket);\n }\n app.onError((error, c) => {\n this.#log()?.error('http: erro fora de um handler', { err: error });\n return c.text('Internal Server Error', 500);\n });\n return app;\n }\n}\n\nfunction mount(app: Hono, entry: RouteEntry, upgradeWebSocket: typeof UpgradeWebSocket): void {\n const base = entry.base();\n const path = entry.path === '/' ? base : base + entry.path;\n const info = (c: Context): HttpRequestInfo => ({ params: c.req.param() });\n const { target } = entry;\n if (typeof target === 'function') {\n app.on(entry.method, path, async (c) => {\n try {\n const response = await target(c.req.raw, info(c));\n if (response instanceof Response) return response;\n throw new TypeError(`o handler de ${entry.method} ${entry.path} não devolveu um Response`);\n } catch (error) {\n entry.onError(error);\n return c.text('Internal Server Error', 500);\n }\n });\n return;\n }\n app.get(path, async (c, next) => {\n if (c.req.header('upgrade')?.toLowerCase() !== 'websocket') {\n return c.text('Upgrade Required', 426);\n }\n let decided: HttpSocketHandlers | Response;\n try {\n decided = await target.ws(c.req.raw, info(c));\n } catch (error) {\n entry.onError(error);\n return c.text('Internal Server Error', 500);\n }\n if (decided instanceof Response) return decided;\n const handlers = decided;\n const upgrade = upgradeWebSocket(() => socketEvents(entry, handlers), {\n onError: (error) => entry.onError(error),\n });\n return (await upgrade(c, next)) ?? c.text('Internal Server Error', 500);\n });\n}\n\n/** Callbacks do Hono ligados aos do autor, com cada conexão registrada na rota. */\nfunction socketEvents(entry: RouteEntry, handlers: HttpSocketHandlers): WSEvents {\n let socket: HttpSocket | undefined;\n const wrap = (ws: WSContext): HttpSocket => {\n socket ??= {\n // O `ws` do Node aceita qualquer `Uint8Array` (Buffer incluso); o tipo do Hono pede o de\n // `ArrayBuffer` só.\n send: (data) => ws.send(data as string | ArrayBuffer),\n close: (code, reason) => ws.close(code, reason),\n };\n return socket;\n };\n const run = (callback: () => void | Promise<void>): void => {\n try {\n Promise.resolve(callback()).catch(entry.onError);\n } catch (error) {\n entry.onError(error);\n }\n };\n return {\n onOpen(_event, ws) {\n entry.sockets.add(ws);\n run(() => handlers.onOpen?.(wrap(ws)));\n },\n onMessage(event, ws) {\n run(() => handlers.onMessage?.(wrap(ws), event.data as string | ArrayBuffer));\n },\n onClose(event, ws) {\n entry.sockets.delete(ws);\n run(() => handlers.onClose?.(wrap(ws), event.code, event.reason));\n },\n };\n}\n\nfunction closeSockets(entry: RouteEntry): void {\n for (const ws of entry.sockets) ws.close(GOING_AWAY, 'rota removida');\n entry.sockets.clear();\n}\n","// Logger que resolve o destino a cada linha (M1-21). O `createBot` entrega um logger à fábrica\n// do transport antes de existir o logger real, que só nasce no `start()` (criá-lo antes seria\n// efeito colateral, ADR 0004). Este repassa cada chamada ao logger que valer no momento.\n\nimport type { LogFields, Logger, LogLevel } from './types.ts';\n\n/** Logger que delega cada chamada a `resolve()`; `child` acumula os bindings sobre o destino. */\nexport function createDeferredLogger(resolve: () => Logger): Logger {\n return {\n get level(): LogLevel {\n return resolve().level;\n },\n trace: (message, fields) => resolve().trace(message, fields),\n debug: (message, fields) => resolve().debug(message, fields),\n info: (message, fields) => resolve().info(message, fields),\n warn: (message, fields) => resolve().warn(message, fields),\n error: (message, fields) => resolve().error(message, fields),\n fatal: (message, fields) => resolve().fatal(message, fields),\n child: (bindings) => createDeferredLogger(childOf(resolve, bindings)),\n };\n}\n\n/** Filho do destino atual, recriado só quando o destino muda: não aloca um logger por linha. */\nfunction childOf(resolve: () => Logger, bindings: LogFields): () => Logger {\n let parent: Logger | undefined;\n let child: Logger | undefined;\n return () => {\n const current = resolve();\n if (current !== parent || child === undefined) {\n parent = current;\n child = current.child(bindings);\n }\n return child;\n };\n}\n","// Fonte viva de segredos para o logger. A lista fixa de `createLogger({ secrets })` não basta\n// para a config de plugin: ela é resolvida depois que o logger existe e muda no reload. Quem\n// cria o bot compartilha um `SecretSet` entre o logger e a config; o logger relê os valores só\n// quando `version` muda, então o custo por linha é uma comparação de número.\n\n/** O que o logger consulta: os valores atuais e um contador que muda junto com eles. */\nexport interface SecretSource {\n /** Muda sempre que o conjunto de valores muda. */\n readonly version: number;\n values(): readonly string[];\n}\n\n/** Segredos agrupados por dono (ex.: `plugin:ai`), para trocar os de um sem tocar nos outros. */\nexport interface SecretSet extends SecretSource {\n /** Substitui os segredos do dono. Lista vazia equivale a `delete`. */\n set(owner: string, values: readonly string[]): void;\n delete(owner: string): void;\n}\n\nexport function createSecretSet(): SecretSet {\n const byOwner = new Map<string, readonly string[]>();\n let version = 0;\n let cached: readonly string[] | undefined;\n\n const changed = (): void => {\n version += 1;\n cached = undefined;\n };\n\n return {\n get version(): number {\n return version;\n },\n values(): readonly string[] {\n cached ??= [...new Set([...byOwner.values()].flat())];\n return cached;\n },\n set(owner: string, values: readonly string[]): void {\n const kept = values.filter((value) => value.length > 0);\n if (kept.length === 0) {\n if (byOwner.delete(owner)) changed();\n return;\n }\n byOwner.set(owner, [...kept]);\n changed();\n },\n delete(owner: string): void {\n if (byOwner.delete(owner)) changed();\n },\n };\n}\n","import type { MessageContext } from '#context.ts';\nimport type { Chat } from '#message/types.ts';\nimport type { Middleware } from './pipeline.ts';\n\nexport interface ChatFilterOptions {\n /**\n * Se informado, só esses chats passam. Vale o ID do chat ou o do espaço (`parentId`): liberar\n * um servidor libera todos os canais dele.\n */\n readonly allow?: Iterable<string>;\n /**\n * Chats que nunca passam, pelo ID do chat ou do espaço. Vence a `allow`: um canal bloqueado\n * fica de fora mesmo com o servidor dele liberado.\n */\n readonly block?: Iterable<string>;\n}\n\n/** Allow/blocklist de chats (ADR 0024). As listas são copiadas na criação. */\nexport function chatFilter(options: ChatFilterOptions): Middleware<MessageContext> {\n const allowed = chatAllowed(options);\n return (ctx, next) => (allowed(ctx.message.chat) ? next() : undefined);\n}\n\n/**\n * A regra do `chatFilter` sem o middleware: o bot a aplica também aos eventos que não são\n * mensagem (ADR 0038). As listas são copiadas na criação.\n */\nexport function chatAllowed(\n options: ChatFilterOptions,\n): (chat: Pick<Chat, 'id' | 'parentId'>) => boolean {\n const allow = options.allow === undefined ? null : new Set(options.allow);\n const block = new Set(options.block);\n return ({ id, parentId }) => {\n const inParent = (list: Set<string>) => parentId !== undefined && list.has(parentId);\n if (block.has(id) || inParent(block)) return false;\n return allow === null || allow.has(id) || inParent(allow);\n };\n}\n","import type { MessageContext } from '#context.ts';\nimport type { Middleware } from './pipeline.ts';\n\n/**\n * Descarta mensagens de outros bots (`sender.isBot`): no Discord e no Telegram, dois bots que\n * respondem um ao outro entram em loop (ADR 0057). Remetente sem `isBot` conta como pessoa.\n */\nexport function ignoreBots(): Middleware<MessageContext> {\n return (ctx, next) => (ctx.message.sender.isBot === true ? undefined : next());\n}\n","import type { MessageContext } from '#context.ts';\nimport type { Middleware } from './pipeline.ts';\n\n/** Descarta mensagens enviadas pela própria sessão do bot, evitando que ele responda a si mesmo. */\nexport function ignoreSelf(): Middleware<MessageContext> {\n return (ctx, next) => (ctx.message.fromMe ? undefined : next());\n}\n","import type { MessageContext } from '#context.ts';\nimport { isThenable } from '#deadline.ts';\n\n/** Avança para o próximo middleware (ou para o fim do pipeline). Chamar duas vezes é erro. */\nexport type Next = () => Promise<void>;\n\n/**\n * Estágio do pipeline em onion (estilo Koa). Para interromper, não chame `next()`. O código\n * depois de `await next()` roda na volta, depois dos middlewares internos.\n */\nexport type Middleware<C extends MessageContext = MessageContext> = (ctx: C, next: Next) => unknown;\n\nexport interface MiddlewareOptions {\n /** Maior prioridade roda antes (mais por fora). Empate: ordem de registro. Padrão `0`. */\n readonly priority?: number;\n}\n\nexport interface MiddlewarePipelineOptions {\n /**\n * Prazo de cada middleware, contado só no tempo dele: o que passa dentro do `next()` (os\n * middlewares internos, comando e listeners) não conta, porque cada um tem o próprio prazo.\n * Sem ele, middleware não tem prazo.\n */\n readonly timeoutMs?: number;\n /** Rejeição de um middleware que já estourou o prazo (o `run` já rejeitou por ele). */\n readonly onLateError?: (error: unknown) => void;\n}\n\n/** Um middleware estourou o prazo. A mensagem é descartada (o `run` rejeita com este erro). */\nexport class MiddlewareTimeoutError extends Error {\n override readonly name = 'MiddlewareTimeoutError';\n readonly timeoutMs: number;\n\n constructor(timeoutMs: number) {\n super(`middleware excedeu ${timeoutMs} ms`);\n this.timeoutMs = timeoutMs;\n }\n}\n\n/** O pipeline foi encerrado (`close`) com o middleware ainda em andamento. */\nexport class MiddlewareAbandonedError extends Error {\n override readonly name = 'MiddlewareAbandonedError';\n\n constructor() {\n super('middleware abandonado: o pipeline foi encerrado');\n }\n}\n\ninterface Entry<C extends MessageContext> {\n readonly middleware: Middleware<C>;\n readonly priority: number;\n}\n\nconst RESOLVED: Promise<void> = Promise.resolve();\nconst NOOP = (): void => undefined;\n\n/**\n * Primeiro estágio do fluxo de mensagem (ADR 0012). A ordem é calculada em `use`/remoção,\n * não a cada mensagem: `run` só percorre um array pronto.\n */\nexport class MiddlewarePipeline<C extends MessageContext = MessageContext> {\n #entries: Entry<C>[] = [];\n #chain: readonly Middleware<C>[] = [];\n readonly #timeoutMs: number | undefined;\n readonly #onLateError: (error: unknown) => void;\n // Abandono dos estágios com timer armado, para o `close` não deixar timer vivo.\n readonly #active = new Set<() => void>();\n\n constructor(options: MiddlewarePipelineOptions = {}) {\n const { timeoutMs } = options;\n // setTimeout trata Infinity/NaN como 1 ms: todo middleware assíncrono estouraria na hora.\n if (timeoutMs !== undefined && (!Number.isFinite(timeoutMs) || timeoutMs <= 0)) {\n throw new RangeError(`Prazo inválido: ${timeoutMs}`);\n }\n this.#timeoutMs = timeoutMs;\n this.#onLateError = options.onLateError ?? NOOP;\n }\n\n /** Registra um middleware; devolve a função que o remove (idempotente). */\n use(middleware: Middleware<C>, options: MiddlewareOptions = {}): () => void {\n const priority = options.priority ?? 0;\n // NaN quebraria a comparação do sort e embaralharia a cadeia inteira.\n if (!Number.isFinite(priority)) throw new RangeError(`Prioridade inválida: ${priority}`);\n const entry: Entry<C> = { middleware, priority };\n this.#entries.push(entry);\n this.#rebuild();\n return () => {\n const index = this.#entries.indexOf(entry);\n if (index === -1) return;\n this.#entries.splice(index, 1);\n this.#rebuild();\n };\n }\n\n get size(): number {\n return this.#chain.length;\n }\n\n /**\n * Passa o contexto pela cadeia. Resolve `true` se a mensagem atravessou até o fim (todos\n * chamaram `next()`) e `false` se algum middleware a interrompeu. Erros de middleware\n * rejeitam a promise: o destino deles é de quem executa o pipeline.\n *\n * `terminal` é o estágio mais interno: roda quando o último middleware chama `next()`, e a\n * volta da cebola espera por ele. É onde o kernel põe comando e listeners (ADR 0012).\n *\n * Com `timeoutMs`, um middleware que estoura o prazo rejeita o `run` com\n * `MiddlewareTimeoutError`, e a mensagem para ali: um `next()` chamado depois disso rejeita\n * com o mesmo erro, sem rodar o resto da cadeia.\n */\n run(ctx: C, terminal?: (ctx: C) => Promise<void>): Promise<boolean> {\n // Snapshot: registrar/remover durante a execução não afeta a mensagem em andamento.\n const chain = this.#chain;\n const length = chain.length;\n if (length === 0) {\n return terminal === undefined ? Promise.resolve(true) : terminal(ctx).then(() => true);\n }\n\n let index = -1;\n let completed = false;\n let expired: MiddlewareTimeoutError | undefined;\n const expire = (error: MiddlewareTimeoutError): void => {\n expired = error;\n };\n const dispatch = (i: number): Promise<void> => {\n if (expired !== undefined) return Promise.reject(expired);\n if (i <= index) return Promise.reject(new Error('next() chamado mais de uma vez'));\n index = i;\n if (i === length) {\n completed = true;\n return terminal === undefined ? RESOLVED : terminal(ctx);\n }\n // biome-ignore lint/style/noNonNullAssertion: 0 <= i < length\n const middleware = chain[i]!;\n const next = (): Promise<void> => dispatch(i + 1);\n if (this.#timeoutMs !== undefined) return this.#timed(middleware, ctx, next, expire);\n try {\n // O valor devolvido pelo middleware é ignorado; o cast evita um `.then` por estágio.\n return Promise.resolve(middleware(ctx, next)) as Promise<void>;\n } catch (error) {\n // Middleware síncrono que lança vira rejeição, como no caso assíncrono.\n return Promise.reject(error);\n }\n };\n return dispatch(0).then(() => completed);\n }\n\n /**\n * Abandona os middlewares ainda em andamento (rejeitam com `MiddlewareAbandonedError`) e\n * desarma os timers deles. É o fim do shutdown: depois dele nenhum timer do pipeline fica vivo.\n */\n close(): void {\n for (const abandon of [...this.#active]) abandon();\n }\n\n /**\n * Roda um estágio com prazo. O relógio só corre fora do `next()`: para ao chamá-lo e volta,\n * com o que sobrou, quando ele termina. Middleware síncrono, ou que só devolve o `next()`,\n * não arma timer: o caminho quente não paga nada (plano §7).\n */\n #timed(\n middleware: Middleware<C>,\n ctx: C,\n next: () => Promise<void>,\n expire: (error: MiddlewareTimeoutError) => void,\n ): Promise<void> {\n // biome-ignore lint/style/noNonNullAssertion: só é chamado com prazo\n const timeoutMs = this.#timeoutMs!;\n let settled = false;\n let async = false;\n let inside = false;\n let lastNext: Promise<void> | undefined;\n let remaining = timeoutMs;\n let startedAt = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let fail: (error: unknown) => void = NOOP;\n\n const pause = (): void => {\n if (timer === undefined) return;\n clearTimeout(timer);\n timer = undefined;\n remaining -= performance.now() - startedAt;\n };\n const finish = (): void => {\n settled = true;\n pause();\n this.#active.delete(abandon);\n };\n const resume = (): void => {\n startedAt = performance.now();\n timer = setTimeout(\n () => {\n timer = undefined;\n const error = new MiddlewareTimeoutError(timeoutMs);\n expire(error);\n finish();\n fail(error);\n },\n Math.max(0, remaining),\n );\n };\n const abandon = (): void => {\n if (settled) return;\n finish();\n fail(new MiddlewareAbandonedError());\n };\n const back = (): void => {\n inside = false;\n if (async && !settled) resume();\n };\n const timedNext = (): Promise<void> => {\n const pending = next();\n if (settled) return pending;\n pause();\n inside = true;\n lastNext = pending;\n // `back` não lança: esta derivada nunca rejeita. O erro do `next()` é de quem o chamou.\n pending.then(back, back);\n return pending;\n };\n\n let result: unknown;\n try {\n result = middleware(ctx, timedNext);\n } catch (error) {\n settled = true;\n return Promise.reject(error);\n }\n // Síncrono, ou devolveu o próprio `next()`: não sobra tempo do middleware para medir.\n if (!isThenable(result) || result === lastNext) {\n settled = true;\n return Promise.resolve(result) as Promise<void>;\n }\n async = true;\n if (!inside) resume();\n this.#active.add(abandon);\n const promise = result;\n return new Promise<void>((resolve, reject) => {\n fail = reject;\n promise.then(\n () => {\n if (settled) return;\n finish();\n resolve();\n },\n (error: unknown) => {\n if (settled) {\n this.#onLateError(error);\n return;\n }\n finish();\n reject(error);\n },\n );\n });\n }\n\n #rebuild(): void {\n // Maior prioridade primeiro. O sort é estável e a entrada nova chega no fim do array já\n // ordenado, então o empate preserva a ordem de registro.\n this.#entries.sort((a, b) => b.priority - a.priority);\n this.#chain = this.#entries.map((entry) => entry.middleware);\n }\n}\n","import type { MessageContext } from '#context.ts';\nimport type { Middleware } from './pipeline.ts';\n\nexport interface RateLimiterOptions {\n /** Máximo de ocorrências por chave dentro de uma janela. */\n readonly max: number;\n /** Duração da janela fixa, em ms. */\n readonly windowMs: number;\n /** Relógio em ms. Padrão `performance.now` (monotônico: não volta com ajuste de hora). */\n readonly clock?: () => number;\n}\n\ninterface Window {\n readonly start: number;\n count: number;\n}\n\n/**\n * Contador de janela fixa por chave. As janelas vencidas são removidas a cada `hit`, então a\n * memória fica limitada às chaves ativas na última janela — o `rateLimiter` do LumaBot nunca\n * limpava o `Map` e crescia com cada contato visto (débito #7 do plano).\n */\nexport class RateLimiter {\n readonly #max: number;\n readonly #windowMs: number;\n readonly #clock: () => number;\n // Ordem de inserção = ordem de início da janela: uma janela vencida sai do Map antes de a\n // chave abrir outra, então a varredura para na primeira janela ainda válida.\n readonly #windows = new Map<string, Window>();\n\n constructor(options: RateLimiterOptions) {\n if (!Number.isInteger(options.max) || options.max < 1) {\n throw new RangeError(`max deve ser um inteiro >= 1: ${options.max}`);\n }\n if (!(options.windowMs > 0)) {\n throw new RangeError(`windowMs deve ser > 0: ${options.windowMs}`);\n }\n this.#max = options.max;\n this.#windowMs = options.windowMs;\n this.#clock = options.clock ?? (() => performance.now());\n }\n\n /** Conta uma ocorrência da chave; `false` se ela estourou o limite da janela atual. */\n hit(key: string): boolean {\n const now = this.#clock();\n this.#sweep(now);\n const window = this.#windows.get(key);\n if (window === undefined) {\n this.#windows.set(key, { start: now, count: 1 });\n return true;\n }\n window.count++;\n return window.count <= this.#max;\n }\n\n /** Chaves com janela aberta. */\n get size(): number {\n return this.#windows.size;\n }\n\n #sweep(now: number): void {\n for (const [key, window] of this.#windows) {\n if (now - window.start < this.#windowMs) return;\n this.#windows.delete(key);\n }\n }\n}\n\n/** Por quem a mensagem é contada: remetente (em qualquer chat), chat, ou remetente em cada chat. */\nexport type RateLimitScope = 'sender' | 'chat' | 'sender-in-chat';\n\nexport interface RateLimitOptions extends RateLimiterOptions {\n /** Padrão `'sender'`. */\n readonly by?: RateLimitScope;\n /** Chamado quando uma mensagem é barrada (ex.: para registrar). Erro aqui propaga ao pipeline. */\n readonly onLimited?: (ctx: MessageContext) => void;\n}\n\nconst KEYS: Record<RateLimitScope, (ctx: MessageContext) => string> = {\n sender: (ctx) => ctx.message.sender.id,\n chat: (ctx) => ctx.message.chat.id,\n // NUL não aparece em IDs de transport, então não há colisão entre pares diferentes.\n 'sender-in-chat': (ctx) => `${ctx.message.chat.id}\\u0000${ctx.message.sender.id}`,\n};\n\n/** Rate limit de entrada: barra a mensagem quando a chave estoura `max` dentro da janela. */\nexport function rateLimit(options: RateLimitOptions): Middleware<MessageContext> {\n const limiter = new RateLimiter(options);\n const keyOf = KEYS[options.by ?? 'sender'];\n const onLimited = options.onLimited;\n return (ctx, next) => {\n if (limiter.hit(keyOf(ctx))) return next();\n onLimited?.(ctx);\n return undefined;\n };\n}\n","import type { MessageContext } from '#context.ts';\nimport type { Middleware } from './pipeline.ts';\n\n/** Campos do remetente/texto já limitados pelo middleware `sanitize`. */\nexport interface SanitizedFields {\n readonly text: string | null;\n readonly senderName: string | null;\n}\n\n/**\n * Contexto com o resultado de `sanitize`. `ctx.message` é imutável (contrato compartilhado),\n * então o texto limpo fica ao lado dele: em `ctx.text`, o texto de trabalho que o roteador e os\n * listeners leem (M1-16.2), e em `sanitized`, junto do nome do remetente. Sem o middleware,\n * `sanitized` fica ausente.\n */\nexport interface SanitizedContext extends MessageContext {\n sanitized?: SanitizedFields;\n}\n\nexport interface SanitizeOptions {\n /** Padrão `4096`, o limite do LumaBot. */\n readonly maxTextLength?: number;\n /** Padrão `100`. */\n readonly maxSenderNameLength?: number;\n}\n\n/**\n * Trunca texto/legenda e nome do remetente: um texto gigante custa CPU em todo estágio\n * seguinte (parse de comando, regex de listeners, prompt de IA) e um nome gigante polui logs.\n */\nexport function sanitize(options: SanitizeOptions = {}): Middleware<SanitizedContext> {\n const maxText = options.maxTextLength ?? 4096;\n const maxName = options.maxSenderNameLength ?? 100;\n for (const [name, value] of [\n ['maxTextLength', maxText],\n ['maxSenderNameLength', maxName],\n ] as const) {\n if (!Number.isInteger(value) || value < 1) {\n throw new RangeError(`${name} deve ser um inteiro >= 1: ${value}`);\n }\n }\n return (ctx, next) => {\n const { message } = ctx;\n // Trunca o texto de trabalho, não o original: um middleware anterior pode tê-lo reescrito.\n const text = truncate(ctx.text === undefined ? message.text : ctx.text, maxText);\n ctx.text = text;\n ctx.sanitized = { text, senderName: truncate(message.sender.name, maxName) };\n return next();\n };\n}\n\nfunction truncate(value: string | null, max: number): string | null {\n if (value === null || value.length <= max) return value;\n // Não corta um par surrogate ao meio (emoji etc.): sobraria um caractere inválido.\n const code = value.charCodeAt(max - 1);\n const end = code >= 0xd800 && code <= 0xdbff ? max - 1 : max;\n return value.slice(0, end);\n}\n","// Divisão de texto longo em partes que cabem no limite do transport (ADR 0061). Corta num\n// parágrafo, depois numa linha, num espaço e, por último, num caractere; um nó partido continua\n// formatado nas duas partes.\n\nimport { formatted, type MessageText, type TextNode } from './format.ts';\n\ntype Wrapper = Extract<TextNode, { readonly children: readonly TextNode[] }>;\ntype Leaf = Extract<TextNode, { readonly type: 'code' | 'mention' }>;\n\n/** Trecho achatado: texto (de string ou de `code`) ou menção, com os estilos que o envolvem. */\ninterface Segment {\n /** Estilos e links de fora para dentro; a identidade do nó junta os pedaços de volta. */\n readonly wrap: readonly Wrapper[];\n /** Vazio na menção, que nunca é cortada. */\n readonly text: string;\n /** O `code` de origem ou a menção; `null` no texto literal. */\n readonly leaf: Leaf | null;\n}\n\nexport interface SplitLimits {\n /** Limite da primeira parte (a legenda, quando a primeira parte é a mídia). */\n readonly first: number;\n /** Limite das outras partes. */\n readonly rest: number;\n}\n\nconst SEPARATORS = ['\\n\\n', '\\n', ' ', ''] as const;\n\n/**\n * Divide `text` em partes com `measure(parte)` dentro do limite. Um texto que cabe volta sozinho,\n * sem cópia. Um caractere ou uma menção maior que o limite sai sozinho numa parte: não há como\n * cortar menos, e o transport rejeita.\n */\nexport function splitText(\n text: MessageText,\n limits: SplitLimits,\n measure: (text: MessageText) => number,\n): MessageText[] {\n if (measure(text) <= limits.first) return [text];\n const raw = typeof text === 'string';\n const build = (segments: readonly Segment[]): MessageText =>\n raw ? segments.map((s) => s.text).join('') : formatted(rebuild(segments, 0));\n const chunks: Segment[][] = [];\n // Mede a parte já sem o espaço das pontas, como ela sai: o separador fica no fim do pedaço.\n const fits = (segments: readonly Segment[]): boolean =>\n measure(build(trim(segments))) <= (chunks.length === 0 ? limits.first : limits.rest);\n\n const pack = (segments: readonly Segment[], level: number): void => {\n const pieces = cut(segments, SEPARATORS[level] ?? '');\n let i = 0;\n while (i < pieces.length) {\n if (!fits(pieces[i] ?? [])) {\n if (level < SEPARATORS.length - 1) pack(pieces[i] ?? [], level + 1);\n else chunks.push(pieces[i] ?? []);\n i++;\n continue;\n }\n // Busca galopante: dobra até não caber e refina por bisseção. Cada medida custa no máximo\n // o dobro do limite, e o total fica em O(n log n).\n let ok = 1;\n let bad = 2;\n while (i + bad <= pieces.length && fits(join(pieces, i, bad))) {\n ok = bad;\n bad *= 2;\n }\n bad = Math.min(bad, pieces.length - i + 1);\n while (bad - ok > 1) {\n const mid = (ok + bad) >> 1;\n if (fits(join(pieces, i, mid))) ok = mid;\n else bad = mid;\n }\n chunks.push(join(pieces, i, ok));\n i += ok;\n }\n };\n pack(flatten(text), 0);\n\n const out: MessageText[] = [];\n for (const chunk of chunks) {\n const trimmed = trim(chunk);\n if (trimmed.length > 0) out.push(build(trimmed));\n }\n return out;\n}\n\nfunction join(pieces: readonly Segment[][], start: number, count: number): Segment[] {\n return pieces.slice(start, start + count).flat();\n}\n\nfunction flatten(text: MessageText): Segment[] {\n if (typeof text === 'string') return [{ wrap: [], text, leaf: null }];\n const out: Segment[] = [];\n const walk = (nodes: readonly TextNode[], wrap: readonly Wrapper[]): void => {\n for (const node of nodes) {\n if (typeof node === 'string') out.push({ wrap, text: node, leaf: null });\n else if (node.type === 'code') out.push({ wrap, text: node.text, leaf: node });\n else if (node.type === 'mention') out.push({ wrap, text: '', leaf: node });\n else walk(node.children, [...wrap, node]);\n }\n };\n walk(text.nodes, []);\n return out;\n}\n\n/** Corta logo depois de cada `separator` (ou entre code points, com `''`); a menção não corta. */\nfunction cut(segments: readonly Segment[], separator: string): Segment[][] {\n const pieces: Segment[][] = [];\n let current: Segment[] = [];\n for (const segment of segments) {\n if (segment.leaf?.type === 'mention') {\n current.push(segment);\n continue;\n }\n let start = 0;\n for (const end of cutPoints(segment.text, separator)) {\n current.push({ ...segment, text: segment.text.slice(start, end) });\n pieces.push(current);\n current = [];\n start = end;\n }\n if (start < segment.text.length) current.push({ ...segment, text: segment.text.slice(start) });\n }\n if (current.length > 0) pieces.push(current);\n return pieces;\n}\n\nfunction* cutPoints(text: string, separator: string): Generator<number> {\n if (separator === '') {\n // Por code point: partir um par surrogate deixaria um caractere inválido em cada parte.\n let index = 0;\n for (const char of text) {\n index += char.length;\n yield index;\n }\n return;\n }\n // Inclusive no fim do trecho: o separador pode ser o último caractere antes de um estilo.\n for (let at = text.indexOf(separator); at !== -1; at = text.indexOf(separator, at)) {\n at += separator.length;\n yield at;\n }\n}\n\n/** Tira o espaço em branco das pontas da parte (fora de `code`) e os trechos que ficam vazios. */\nfunction trim(chunk: readonly Segment[]): Segment[] {\n const out = [...chunk];\n const edge = (index: number, re: RegExp): void => {\n const segment = out[index];\n if (segment === undefined || segment.leaf !== null) return;\n out[index] = { ...segment, text: segment.text.replace(re, '') };\n };\n while (out.length > 0) {\n edge(0, /^\\s+/);\n if (out[0]?.leaf === null && out[0].text === '') out.shift();\n else break;\n }\n while (out.length > 0) {\n edge(out.length - 1, /\\s+$/);\n if (out.at(-1)?.leaf === null && out.at(-1)?.text === '') out.pop();\n else break;\n }\n return out;\n}\n\n/** Remonta a árvore: trechos seguidos com o mesmo nó de estilo voltam para um nó só. */\nfunction rebuild(segments: readonly Segment[], depth: number): TextNode[] {\n const out: TextNode[] = [];\n let i = 0;\n while (i < segments.length) {\n const segment = segments[i] as Segment;\n const wrapper = segment.wrap[depth];\n if (wrapper !== undefined) {\n let j = i + 1;\n while (j < segments.length && segments[j]?.wrap[depth] === wrapper) j++;\n const children = rebuild(segments.slice(i, j), depth + 1);\n out.push(\n Object.freeze(\n wrapper.type === 'link'\n ? { type: 'link', url: wrapper.url, children: Object.freeze(children) }\n : { type: wrapper.type, children: Object.freeze(children) },\n ),\n );\n i = j;\n continue;\n }\n const { leaf } = segment;\n if (leaf?.type === 'mention') {\n out.push(leaf);\n i++;\n continue;\n }\n let j = i + 1;\n let text = segment.text;\n while (\n j < segments.length &&\n segments[j]?.wrap.length === depth &&\n segments[j]?.leaf === leaf\n ) {\n text += segments[j]?.text ?? '';\n j++;\n }\n if (text !== '') out.push(leaf === null ? text : Object.freeze({ type: 'code', text }));\n i = j;\n }\n return out;\n}\n","// Texto do envio (ADR 0061): a árvore neutra vira o par `text` visível + `formatted`, e o texto\n// acima do limite do transport vira várias partes, antes de entrar na fila de saída.\n\nimport { type FormattedText, isFormatted, type MessageText, plainText } from '#text/format.ts';\nimport { splitText } from '#text/split.ts';\nimport type { OutgoingContent, SendOptions, TextLimits, Transport } from '#transport/types.ts';\n\n/** Uma parte do envio: o conteúdo e as opções com que vai ao transport. */\nexport interface SendPart {\n readonly content: OutgoingContent;\n readonly options: SendOptions | undefined;\n}\n\n/** Conteúdo de texto com o `text` visível e, para a árvore, o `formatted`. */\nexport function textContent(text: MessageText): OutgoingContent {\n return typeof text === 'string'\n ? { type: 'text', text }\n : { type: 'text', text: plainText(text), formatted: text };\n}\n\n/** Campos da legenda no conteúdo, ou nada, para não mandar `undefined` explícito ao transport. */\nexport function captionFields(caption: MessageText | undefined): {\n caption?: string;\n formattedCaption?: FormattedText;\n} {\n if (caption === undefined) return {};\n return typeof caption === 'string'\n ? { caption }\n : { caption: plainText(caption), formattedCaption: caption };\n}\n\n/** O que o `send` aceita: o conteúdo ou, como atalho, só o texto. */\nexport function toContent(input: OutgoingContent | MessageText): OutgoingContent {\n if (typeof input === 'string' || isFormatted(input)) return textContent(input);\n // O texto visível sai sempre da árvore: o transport que não a conhece envia o mesmo texto.\n if (input.type === 'text' && input.formatted !== undefined) return textContent(input.formatted);\n if ('formattedCaption' in input && input.formattedCaption !== undefined) {\n return { ...input, caption: plainText(input.formattedCaption) };\n }\n return input;\n}\n\nfunction measureVisible(text: MessageText): number {\n return typeof text === 'string' ? text.length : plainText(text).length;\n}\n\n/** O limite do transport validado; ausente vira `Infinity`. */\nexport function positiveLimit(name: string, value: number | undefined): number {\n if (value === undefined) return Number.POSITIVE_INFINITY;\n if (!(Number.isInteger(value) && value >= 1)) {\n throw new RangeError(`limits.${name} do transport deve ser inteiro >= 1 (recebido: ${value})`);\n }\n return value;\n}\n\n/** Os limites do transport, validados uma vez: são fixos na vida da instância. */\nexport class TextLimiter {\n readonly #text: number;\n readonly #caption: number;\n readonly #measure: (text: MessageText) => number;\n /** Sem limite nenhum, o envio passa direto, sem medir. */\n readonly #unlimited: boolean;\n\n constructor(transport: Pick<Transport, 'limits'>) {\n const limits: TextLimits = transport.limits ?? {};\n this.#text = positiveLimit('text', limits.text);\n this.#caption = positiveLimit('caption', limits.caption);\n const custom = limits.measure;\n this.#measure = custom === undefined ? measureVisible : (text) => custom.call(limits, text);\n this.#unlimited =\n this.#text === Number.POSITIVE_INFINITY && this.#caption === Number.POSITIVE_INFINITY;\n }\n\n /**\n * As partes do envio, na ordem. Só a primeira cita a mensagem, e só a última leva os botões; as\n * menções vão em todas. Uma legenda longa fica com o começo na mídia, e o resto vira texto.\n */\n split(content: OutgoingContent, options: SendOptions | undefined): SendPart[] {\n if (this.#unlimited) return [{ content, options }];\n let first: OutgoingContent;\n let rest: MessageText[];\n if (content.type === 'text') {\n const parts = this.#split(content.formatted ?? content.text, this.#text);\n if (parts.length <= 1) return [{ content, options }];\n first = textContent(parts[0] as MessageText);\n rest = parts.slice(1);\n } else if (\n (content.type === 'image' ||\n content.type === 'video' ||\n content.type === 'document' ||\n content.type === 'album') &&\n content.caption !== undefined\n ) {\n const parts = this.#split(content.formattedCaption ?? content.caption, this.#caption);\n if (parts.length <= 1) return [{ content, options }];\n const { caption: _caption, formattedCaption: _formatted, ...media } = content;\n first = { ...media, ...captionFields(parts[0]) };\n rest = parts.slice(1);\n } else {\n return [{ content, options }];\n }\n let firstOptions = options;\n let restOptions: SendOptions | undefined;\n let lastOptions: SendOptions | undefined;\n if (options !== undefined) {\n // Os botões vão onde a leitura termina, na última parte (ADR 0062).\n const { quoted: _quoted, actions, ...others } = options;\n restOptions = others;\n lastOptions = actions === undefined ? others : { ...others, actions };\n if (actions !== undefined) {\n const { actions: _actions, ...withoutActions } = options;\n firstOptions = withoutActions;\n }\n }\n const last = rest.length - 1;\n return [\n { content: first, options: firstOptions },\n ...rest.map((text, index) => ({\n content: textContent(text),\n options: index === last ? lastOptions : restOptions,\n })),\n ];\n }\n\n /** Afirma que o texto da edição cabe; a edição não se divide. */\n assertEditFits(text: MessageText): void {\n if (this.#text === Number.POSITIVE_INFINITY) return;\n const size = this.#measure(text);\n if (size > this.#text) {\n throw new RangeError(\n `texto da edição com ${size} caracteres passa do limite do transport (${this.#text})`,\n );\n }\n }\n\n #split(text: MessageText, limit: number): MessageText[] {\n if (limit === Number.POSITIVE_INFINITY) return [text];\n // A primeira parte de uma legenda segue o limite da legenda; as outras viram texto.\n const rest = Number.isFinite(this.#text) ? this.#text : limit;\n return splitText(text, { first: limit, rest }, this.#measure);\n }\n}\n","// `ctx.send` (ADR 0040): o envio e as ações sobre mensagens e chats, todos pela fila de saída. A\n// fila não conhece as ações; aqui cada uma confere a capability e vira uma chamada enfileirada.\n\nimport { plainText } from '#text/format.ts';\nimport { assertCapability, type Capability } from '#transport/capabilities.ts';\nimport type { Transport } from '#transport/types.ts';\nimport type { OutboundQueue } from './queue.ts';\nimport { TextLimiter } from './text.ts';\nimport type { ActionOptions, Outbound } from './types.ts';\n\n/** O que as ações usam do transport. */\nexport type ActionTransport = Pick<\n Transport,\n 'name' | 'capabilities' | 'react' | 'edit' | 'delete' | 'sendTyping' | 'limits'\n>;\n\n/** Enfileira `run` no chat se o transport tem a capability; sem ela, rejeita já. */\nexport type EnqueueAction = (\n capability: Capability,\n chatId: string,\n run: () => Promise<void>,\n options?: ActionOptions,\n) => Promise<void>;\n\nexport function enqueueAction(\n queue: Pick<OutboundQueue, 'enqueue'>,\n transport: Pick<Transport, 'name' | 'capabilities'>,\n): EnqueueAction {\n return (capability, chatId, run, options) => {\n try {\n // Capability ausente nunca vira tentativa, como no envio.\n assertCapability(transport, capability);\n } catch (error) {\n return Promise.reject(error);\n }\n return queue.enqueue(chatId, run, options);\n };\n}\n\nexport function createOutbound(\n queue: Pick<OutboundQueue, 'send' | 'enqueue'>,\n transport: ActionTransport,\n): Outbound {\n const action = enqueueAction(queue, transport);\n const limiter = new TextLimiter(transport);\n return {\n send: (chatId, content, options) => queue.send(chatId, content, options),\n react: (key, emoji, options) =>\n action('reactions', key.chatId, () => transport.react(key, emoji), options),\n edit: (key, text, options) => {\n try {\n limiter.assertEditFits(text);\n } catch (error) {\n return Promise.reject(error);\n }\n // A árvore vai junto do texto visível, como no envio (ADR 0061).\n if (typeof text === 'string') {\n return action('message.edit', key.chatId, () => transport.edit(key, text), options);\n }\n const visible = plainText(text);\n return action('message.edit', key.chatId, () => transport.edit(key, visible, text), options);\n },\n delete: (key, options) =>\n action('message.delete', key.chatId, () => transport.delete(key), options),\n typing: (chatId, kind, options) =>\n action('typing', chatId, () => transport.sendTyping(chatId, kind), options),\n };\n}\n","// Álbum do envio (ADR 0065): com a capability `send.album`, vai em lotes de até `limits.album`\n// itens; sem ela, item a item. Roda antes da divisão da legenda (ADR 0061), na entrada da fila.\n\nimport type { OutgoingContent, SendOptions, Transport } from '#transport/types.ts';\nimport { positiveLimit, type SendPart } from './text.ts';\n\ntype AlbumContent = Extract<OutgoingContent, { readonly type: 'album' }>;\n\n/** A capability e o limite do transport, lidos uma vez: são fixos na vida da instância. */\nexport class AlbumSplitter {\n /** Itens por mensagem: `limits.album` com a capability, um sem ela. */\n readonly #size: number;\n\n constructor(transport: Pick<Transport, 'capabilities' | 'limits'>) {\n const max = positiveLimit('album', transport.limits?.album);\n this.#size = transport.capabilities.has('send.album') ? max : 1;\n }\n\n /**\n * As mensagens do álbum, na ordem, com a legenda na primeira. Um lote de um item sai como\n * mensagem comum, porque o Telegram não aceita álbum de um. As opções seguem a regra das partes\n * do texto: só a primeira cita, só a última leva os botões, as menções vão em todas. Lança\n * `TypeError` com o álbum vazio.\n */\n split(content: AlbumContent, options: SendOptions | undefined): SendPart[] {\n const { items } = content;\n if (items.length === 0) throw new TypeError('álbum sem itens');\n const contents: OutgoingContent[] = [];\n for (let start = 0; start < items.length; start += this.#size) {\n const lot = items.slice(start, start + this.#size);\n const caption = start === 0 ? captionOf(content) : {};\n contents.push(\n lot.length === 1\n ? ({ ...lot[0], ...caption } as OutgoingContent)\n : { type: 'album', items: lot, ...caption },\n );\n }\n return distribute(contents, options);\n }\n}\n\n/** Legenda do álbum, só com os campos definidos: o transport não recebe `undefined` explícito. */\nfunction captionOf(content: AlbumContent): Pick<AlbumContent, 'caption' | 'formattedCaption'> {\n return {\n ...(content.caption === undefined ? null : { caption: content.caption }),\n ...(content.formattedCaption === undefined\n ? null\n : { formattedCaption: content.formattedCaption }),\n };\n}\n\nfunction distribute(contents: OutgoingContent[], options: SendOptions | undefined): SendPart[] {\n if (options === undefined || contents.length === 1) {\n return contents.map((content) => ({ content, options }));\n }\n const { quoted, actions, ...others } = options;\n const last = contents.length - 1;\n return contents.map((content, index) => ({\n content,\n options: {\n ...others,\n ...(index === 0 && quoted !== undefined ? { quoted } : null),\n ...(index === last && actions !== undefined ? { actions } : null),\n },\n }));\n}\n","// Fila de saída anti-ban (ADR 0019). Todo envio do bot passa por aqui: intervalo mínimo global\n// e por chat, prioridade (comando > broadcast), retry com backoff (ou na janela que a plataforma\n// informou, ADR 0067) e humanização opcional.\n\nimport type { MessageText } from '#text/format.ts';\nimport { assertCanSend, hasCapability, UnsupportedError } from '#transport/capabilities.ts';\nimport type {\n MessageKey,\n OutgoingContent,\n SendOptions,\n Transport,\n TransportPacing,\n TypingKind,\n} from '#transport/types.ts';\nimport { AlbumSplitter } from './album.ts';\nimport { type SendPart, TextLimiter, toContent } from './text.ts';\nimport type { ActionOptions, OutboundSendOptions, Sender, SendPriority } from './types.ts';\n\n/** O que a fila usa do transport. */\nexport type OutboundTransport = Pick<\n Transport,\n 'name' | 'capabilities' | 'send' | 'sendTyping' | 'limits' | 'pacing'\n>;\n\nexport interface RetryOptions {\n /** Tentativas no total, contando a primeira. Padrão: 3. `1` desliga o retry. */\n readonly maxAttempts?: number;\n /** Espera antes da primeira re-tentativa, em ms; dobra a cada falha. Padrão: 1000. */\n readonly baseDelayMs?: number;\n /**\n * Teto da espera, em ms. Padrão: 30000. Um erro com `retryAfterMs` acima dele não re-tenta: a\n * resposta já sairia fora de contexto (ADR 0067).\n */\n readonly maxDelayMs?: number;\n /**\n * Decide se a falha é transitória. Padrão: tudo, exceto `UnsupportedError` e erros com\n * `retryable: false` (convenção para o transport marcar falha permanente).\n */\n readonly isRetryable?: (error: unknown) => boolean;\n}\n\nexport interface HumanizeOptions {\n /** Tempo \"digitando\" por caractere do texto, em ms. Padrão: 50. */\n readonly msPerChar?: number;\n /** Piso do tempo de \"digitando\", em ms. Padrão: 500. */\n readonly minMs?: number;\n /** Teto do tempo de \"digitando\", em ms; voz usa o teto. Padrão: 3000. */\n readonly maxMs?: number;\n}\n\nexport interface OutboundQueueOptions {\n readonly transport: OutboundTransport;\n /**\n * Intervalo mínimo entre dois envios quaisquer, em ms. Padrão: o `transport.pacing`, ou 300.\n */\n readonly globalIntervalMs?: number;\n /**\n * Intervalo mínimo entre dois envios ao mesmo chat, em ms. Padrão: o `transport.pacing`, ou\n * 1000.\n */\n readonly chatIntervalMs?: number;\n /**\n * Máximo de mensagens aguardando em cada prioridade, somando os chats. Padrão: 1000.\n * `Infinity` desliga. Por prioridade para um broadcast que encheu a fila não recusar respostas.\n */\n readonly maxPending?: number;\n readonly retry?: RetryOptions;\n /**\n * \"Digitando\" (`text`) antes de texto e \"gravando\" (`voice`) antes de voz, se o transport tiver a\n * capability `typing`. Padrão: desligada.\n */\n readonly humanize?: boolean | HumanizeOptions;\n /**\n * Destino das falhas do \"digitando\", que não impedem o envio. Sem ele, a falha é descartada:\n * o indicador é cosmético e quem chamou `send` só se importa com a mensagem.\n */\n readonly onTypingError?: (error: unknown, chatId: string) => void;\n /**\n * Quanto o que aguarda pode esperar com a fila pausada (conexão caída), em ms. Estourado, rejeita\n * com `OutboundQueueError` `'disconnected'`, e envios novos rejeitam na hora até o `resume()`.\n * Padrão: 60000 (cobre o ciclo de reconexão padrão, 5 + 10 + 15 s). `Infinity` desliga.\n */\n readonly maxPauseMs?: number;\n /**\n * Prazo de cada chamada ao transport (\"digitando\" e envio), em ms. Estourado, o envio rejeita com\n * `OutboundQueueError` `'timeout'`, sem re-tentar, e libera o chat. Padrão: 30000. `Infinity`\n * desliga.\n */\n readonly sendTimeoutMs?: number;\n /** Relógio em ms. Padrão: `performance.now` (monotônico). */\n readonly clock?: () => number;\n /** Fonte do jitter do backoff, em [0, 1). Padrão: `Math.random`. */\n readonly random?: () => number;\n}\n\nexport interface OutboundQueueStats {\n /** Mensagens aguardando, inclusive as em espera de re-tentativa. */\n readonly pending: { readonly high: number; readonly normal: number; readonly low: number };\n /** Envios em andamento (\"digitando\" + transport). */\n readonly inFlight: number;\n /** Chats com mensagem aguardando ou em andamento. */\n readonly activeChats: number;\n readonly sent: number;\n /** Envios que rejeitaram com o erro final. */\n readonly failed: number;\n readonly retries: number;\n /** Recusadas (fila cheia, fechada ou desconectada) ou descartadas sem envio. */\n readonly dropped: number;\n /** Despacho pausado pela conexão caída. */\n readonly paused: boolean;\n}\n\nexport interface OutboundCloseOptions {\n /**\n * `true` (padrão): envia tudo o que já foi aceito antes de resolver. `false`: rejeita o que\n * aguarda e só espera os envios em andamento.\n */\n readonly drain?: boolean;\n}\n\nexport type OutboundQueueErrorReason = 'full' | 'closed' | 'disconnected' | 'timeout';\n\n/**\n * Envio recusado ou abandonado pela fila: backlog cheio, fila fechada, conexão caída além de\n * `maxPauseMs` ou transport sem resposta em `sendTimeoutMs`.\n */\nexport class OutboundQueueError extends Error {\n override readonly name = 'OutboundQueueError';\n readonly reason: OutboundQueueErrorReason;\n\n constructor(reason: OutboundQueueErrorReason, message: string) {\n super(message);\n this.reason = reason;\n }\n}\n\n/** Índice nas estruturas por prioridade: 0 é a mais alta. */\ntype PriorityIndex = 0 | 1 | 2;\n\n// Map e não objeto: prioridade vinda de JS sem tipos (ex.: `'toString'`) não casa por engano.\nconst PRIORITY_INDEX: ReadonlyMap<string, PriorityIndex> = new Map<SendPriority, PriorityIndex>([\n ['high', 0],\n ['normal', 1],\n ['low', 2],\n]);\n\nconst DEFAULTS = {\n globalIntervalMs: 300,\n chatIntervalMs: 1000,\n maxPending: 1000,\n maxAttempts: 3,\n baseDelayMs: 1000,\n maxDelayMs: 30_000,\n maxPauseMs: 60_000,\n sendTimeoutMs: 30_000,\n msPerChar: 50,\n minMs: 500,\n maxMs: 3000,\n} as const;\n\n/** FIFO com remoção O(1) na frente; `Array.shift` é O(n) e o backlog pode ter milhares. */\nclass Fifo<T> {\n #items: (T | undefined)[] = [];\n #head = 0;\n\n get size(): number {\n return this.#items.length - this.#head;\n }\n\n push(item: T): void {\n this.#items.push(item);\n }\n\n peek(): T | undefined {\n return this.#items[this.#head];\n }\n\n shift(): T | undefined {\n if (this.#head >= this.#items.length) return undefined;\n const item = this.#items[this.#head];\n this.#items[this.#head] = undefined;\n this.#head++;\n if (this.#head === this.#items.length) {\n this.#items = [];\n this.#head = 0;\n } else if (this.#head >= 1024 && this.#head * 2 >= this.#items.length) {\n // Compacta só quando a parte consumida domina: custo amortizado O(1).\n this.#items = this.#items.slice(this.#head);\n this.#head = 0;\n }\n return item;\n }\n\n clear(): void {\n this.#items = [];\n this.#head = 0;\n }\n}\n\n/** Uma chamada ao transport e o conteúdo dela, para a humanização (`null` nas ações). */\ninterface JobPart {\n readonly run: () => Promise<unknown>;\n readonly content: OutgoingContent | null;\n}\n\ninterface Job extends JobPart {\n /**\n * Partes seguintes de um texto dividido (ADR 0061). Cada uma sai logo depois da anterior, na\n * frente do chat, para outro envio não se intrometer.\n */\n readonly rest: readonly JobPart[];\n /** Resultado da primeira parte, com que a última resolve; ausente até ela sair. */\n readonly first?: { readonly value: unknown };\n /** O que é a chamada, para a mensagem do prazo estourado. */\n readonly what: string;\n readonly priority: PriorityIndex;\n /** Tentativas já feitas. */\n attempts: number;\n readonly resolve: (value: unknown) => void;\n readonly reject: (error: unknown) => void;\n}\n\ninterface ChatState {\n readonly id: string;\n readonly jobs: readonly [Fifo<Job>, Fifo<Job>, Fifo<Job>];\n /**\n * Mensagem em espera de re-tentativa ou parte seguinte de um texto dividido: sai antes das\n * outras do chat, para não embaralhar.\n */\n head: Job | null;\n pending: number;\n busy: boolean;\n /** Antes disso o chat não envia (intervalo por chat ou backoff). */\n readyAt: number;\n /** Senha da entrada válida numa lista de prontos; 0 = fora das listas. */\n ticket: number;\n listedPriority: PriorityIndex | -1;\n timer: NodeJS.Timeout | undefined;\n}\n\ninterface ReadyEntry {\n readonly chat: ChatState;\n readonly ticket: number;\n}\n\n/**\n * Fila de saída de uma instância do bot. Chats diferentes enviam em paralelo, limitados só\n * pelo intervalo global; dentro do chat, uma mensagem por vez, em ordem por prioridade.\n */\nexport class OutboundQueue implements Sender {\n readonly #transport: OutboundTransport;\n readonly #text: TextLimiter;\n readonly #album: AlbumSplitter;\n readonly #globalIntervalMs: number;\n readonly #chatIntervalMs: number;\n readonly #maxPending: number;\n readonly #maxAttempts: number;\n readonly #baseDelayMs: number;\n readonly #maxDelayMs: number;\n readonly #isRetryable: (error: unknown) => boolean;\n readonly #humanize: Required<HumanizeOptions> | null;\n readonly #onTypingError: ((error: unknown, chatId: string) => void) | undefined;\n readonly #maxPauseMs: number;\n readonly #sendTimeoutMs: number;\n readonly #clock: () => number;\n readonly #random: () => number;\n\n // Só chats com mensagem aguardando ou em andamento: ao esvaziar, saem (o vazamento do\n // rateLimiter do legacy).\n readonly #chats = new Map<string, ChatState>();\n // Fim do intervalo por chat, em ordem de envio. Como o intervalo é fixo, a ordem de inserção\n // é a de vencimento e a limpeza para na primeira entrada válida.\n readonly #cooldowns = new Map<string, number>();\n // Chats prontos para enviar, um FIFO por prioridade. Remoção preguiçosa: entradas cujo\n // ticket não bate mais são descartadas ao chegar na frente.\n readonly #ready: readonly [Fifo<ReadyEntry>, Fifo<ReadyEntry>, Fifo<ReadyEntry>] = [\n new Fifo(),\n new Fifo(),\n new Fifo(),\n ];\n readonly #pendingBy: Record<PriorityIndex, number> = [0, 0, 0];\n #nextTicket = 1;\n #globalReadyAt = Number.NEGATIVE_INFINITY;\n #globalTimer: NodeJS.Timeout | undefined;\n #pumping = false;\n #idleWaiters: (() => void)[] = [];\n #closed = false;\n #discarding = false;\n #paused = false;\n // Pausada além do teto: o que chega rejeita na hora, em vez de acumular sem previsão de saída.\n #offline = false;\n #pauseTimer: NodeJS.Timeout | undefined;\n // Esperas de humanização em curso: o descarte as encerra para o envio não sair depois do close.\n readonly #sleepers = new Set<() => void>();\n #inFlight = 0;\n #sent = 0;\n #failed = 0;\n #retries = 0;\n #dropped = 0;\n\n constructor(options: OutboundQueueOptions) {\n const retry = options.retry ?? {};\n this.#transport = options.transport;\n this.#text = new TextLimiter(options.transport);\n this.#album = new AlbumSplitter(options.transport);\n // O ritmo é da plataforma (ADR 0067): a config do bot sobrescreve o do transport, e sem\n // nenhum dos dois vale o padrão anti-ban do WhatsApp (ADR 0019).\n const pacing = options.transport.pacing;\n this.#globalIntervalMs = pace('globalIntervalMs', options.globalIntervalMs, pacing);\n this.#chatIntervalMs = pace('chatIntervalMs', options.chatIntervalMs, pacing);\n const maxPending = options.maxPending ?? DEFAULTS.maxPending;\n if (\n !(\n maxPending === Number.POSITIVE_INFINITY ||\n (Number.isInteger(maxPending) && maxPending >= 0)\n )\n ) {\n throw new RangeError(\n `maxPending deve ser inteiro >= 0 ou Infinity (recebido: ${maxPending})`,\n );\n }\n this.#maxPending = maxPending;\n const maxAttempts = retry.maxAttempts ?? DEFAULTS.maxAttempts;\n if (!(Number.isInteger(maxAttempts) && maxAttempts >= 1)) {\n throw new RangeError(`retry.maxAttempts deve ser inteiro >= 1 (recebido: ${maxAttempts})`);\n }\n this.#maxAttempts = maxAttempts;\n this.#baseDelayMs = nonNegative('retry.baseDelayMs', retry.baseDelayMs ?? DEFAULTS.baseDelayMs);\n this.#maxDelayMs = nonNegative('retry.maxDelayMs', retry.maxDelayMs ?? DEFAULTS.maxDelayMs);\n this.#isRetryable = retry.isRetryable ?? isTransient;\n this.#humanize = resolveHumanize(options.humanize, options.transport);\n this.#onTypingError = options.onTypingError;\n const maxPauseMs = options.maxPauseMs ?? DEFAULTS.maxPauseMs;\n if (!(maxPauseMs >= 0)) {\n throw new RangeError(`maxPauseMs deve ser >= 0 ou Infinity (recebido: ${maxPauseMs})`);\n }\n this.#maxPauseMs = maxPauseMs;\n const sendTimeoutMs = options.sendTimeoutMs ?? DEFAULTS.sendTimeoutMs;\n if (!(sendTimeoutMs > 0)) {\n throw new RangeError(`sendTimeoutMs deve ser > 0 ou Infinity (recebido: ${sendTimeoutMs})`);\n }\n this.#sendTimeoutMs = sendTimeoutMs;\n this.#clock = options.clock ?? (() => performance.now());\n this.#random = options.random ?? Math.random;\n }\n\n /**\n * Enfileira o envio. Resolve com a chave da mensagem criada ou rejeita com o erro final\n * (capability ausente, fila cheia/fechada ou falha do transport após as re-tentativas). Um\n * texto acima do limite do transport sai em partes, e a chave é a da primeira (ADR 0061).\n */\n send(\n chatId: string,\n input: OutgoingContent | MessageText,\n options?: OutboundSendOptions,\n ): Promise<MessageKey> {\n let sendOptions: SendOptions | undefined;\n if (options !== undefined) {\n const { priority: _priority, ...rest } = options;\n sendOptions = rest;\n }\n let parts: SendPart[];\n try {\n const content = toContent(input);\n parts =\n content.type === 'album'\n ? this.#album\n .split(content, sendOptions)\n .flatMap((part) => this.#text.split(part.content, part.options))\n : this.#text.split(content, sendOptions);\n } catch (error) {\n return Promise.reject(error);\n }\n const [head, ...rest] = parts.map(\n ({ content, options: partOptions }): JobPart => ({\n run: () => this.#transport.send(chatId, content, partOptions),\n content,\n }),\n );\n return this.#push(chatId, options?.priority, {\n ...(head as JobPart),\n rest,\n what: `envio para ${chatId}`,\n // Capability ausente nunca vira tentativa: falha já, sem ocupar a fila. Uma legenda\n // dividida também exige `send.text`.\n check: () => {\n for (const part of parts) assertCanSend(this.#transport, part.content, part.options);\n },\n }) as Promise<MessageKey>;\n }\n\n /**\n * Enfileira uma ação que gera tráfego sem ser envio (reação, edição, \"digitando\", participantes de\n * grupo; ADR 0040), com as mesmas regras do envio: intervalos, prioridade, retry, pausa e prazo.\n * Sem humanização. Quem chama confere a capability antes: a fila não conhece a ação.\n */\n enqueue<T>(chatId: string, action: () => Promise<T>, options?: ActionOptions): Promise<T> {\n return this.#push(chatId, options?.priority, {\n run: action,\n content: null,\n rest: [],\n what: `ação em ${chatId}`,\n }) as Promise<T>;\n }\n\n #push(\n chatId: string,\n requested: SendPriority | undefined,\n spec: Pick<Job, 'run' | 'content' | 'rest' | 'what'> & { readonly check?: () => void },\n ): Promise<unknown> {\n if (this.#closed) {\n this.#dropped++;\n return Promise.reject(\n new OutboundQueueError('closed', `fila de saída fechada: ${spec.what} recusado`),\n );\n }\n if (this.#offline) {\n this.#dropped++;\n return Promise.reject(\n new OutboundQueueError(\n 'disconnected',\n `conexão caída há mais de ${this.#maxPauseMs} ms: ${spec.what} recusado`,\n ),\n );\n }\n const priority = PRIORITY_INDEX.get(requested ?? 'normal');\n if (priority === undefined) {\n return Promise.reject(new TypeError(`prioridade inválida: ${String(requested)}`));\n }\n try {\n spec.check?.();\n } catch (error) {\n return Promise.reject(error);\n }\n // Limite por prioridade: `low`/`normal` acumulados nunca tiram a vaga de uma `high`.\n if (this.#pendingBy[priority] >= this.#maxPending) {\n this.#dropped++;\n return Promise.reject(\n new OutboundQueueError(\n 'full',\n `fila de saída cheia (${this.#maxPending} aguardando com prioridade ${requested ?? 'normal'}): ${spec.what} recusado`,\n ),\n );\n }\n\n return new Promise<unknown>((resolve, reject) => {\n const job: Job = {\n run: spec.run,\n content: spec.content,\n rest: spec.rest,\n what: spec.what,\n priority,\n attempts: 0,\n resolve,\n reject,\n };\n const chat = this.#chatFor(chatId);\n chat.jobs[priority].push(job);\n chat.pending++;\n this.#pendingBy[priority]++;\n this.#wake(chat, this.#clock());\n this.#pump();\n });\n }\n\n stats(): OutboundQueueStats {\n return {\n pending: {\n high: this.#pendingBy[0],\n normal: this.#pendingBy[1],\n low: this.#pendingBy[2],\n },\n inFlight: this.#inFlight,\n activeChats: this.#chats.size,\n sent: this.#sent,\n failed: this.#failed,\n retries: this.#retries,\n dropped: this.#dropped,\n paused: this.#paused,\n };\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n\n get paused(): boolean {\n return this.#paused;\n }\n\n /**\n * Para de despachar (a conexão caiu): o que aguarda e o que chegar esperam o `resume()`, até\n * `maxPauseMs`. Envios em andamento terminam; se falharem, a re-tentativa também espera.\n */\n pause(): void {\n if (this.#paused) return;\n this.#paused = true;\n if (this.#maxPauseMs === Number.POSITIVE_INFINITY) return;\n this.#pauseTimer = setTimeout(() => {\n this.#pauseTimer = undefined;\n this.#offline = true;\n this.#rejectWaiting(\n () =>\n new OutboundQueueError(\n 'disconnected',\n `conexão caída há mais de ${this.#maxPauseMs} ms: envio descartado`,\n ),\n );\n }, this.#maxPauseMs);\n }\n\n /** Volta a despachar (a conexão abriu), inclusive depois de estourado o `maxPauseMs`. */\n resume(): void {\n if (!this.#paused) return;\n this.#paused = false;\n this.#offline = false;\n clearTimeout(this.#pauseTimer);\n this.#pauseTimer = undefined;\n this.#pump();\n }\n\n /** Resolve quando não há mensagem aguardando nem em andamento. Não impede novos envios. */\n onIdle(): Promise<void> {\n if (this.#chats.size === 0) return Promise.resolve();\n return new Promise((resolve) => this.#idleWaiters.push(resolve));\n }\n\n /**\n * Para de aceitar envios (novos rejeitam com `OutboundQueueError` `'closed'`) e resolve quando\n * a fila esvaziar. Pode ser chamado de novo com `drain: false` para abortar uma drenagem.\n */\n close(options: OutboundCloseOptions = {}): Promise<void> {\n this.#closed = true;\n if (options.drain === false) this.#discard();\n return this.onIdle();\n }\n\n #chatFor(chatId: string): ChatState {\n const existing = this.#chats.get(chatId);\n if (existing !== undefined) return existing;\n const chat: ChatState = {\n id: chatId,\n jobs: [new Fifo(), new Fifo(), new Fifo()],\n head: null,\n pending: 0,\n busy: false,\n readyAt: this.#cooldowns.get(chatId) ?? Number.NEGATIVE_INFINITY,\n ticket: 0,\n listedPriority: -1,\n timer: undefined,\n };\n this.#chats.set(chatId, chat);\n return chat;\n }\n\n /** Coloca o chat na lista de prontos ou agenda quando ele ficará pronto. */\n #wake(chat: ChatState, now: number): void {\n if (chat.busy || chat.pending === 0) return;\n if (now < chat.readyAt) {\n chat.timer ??= setTimeout(() => {\n chat.timer = undefined;\n this.#wake(chat, this.#clock());\n this.#pump();\n }, chat.readyAt - now);\n return;\n }\n const priority = chat.head !== null ? chat.head.priority : firstNonEmpty(chat.jobs);\n if (priority === -1 || (chat.ticket !== 0 && chat.listedPriority === priority)) return;\n // Nova senha invalida a entrada antiga (ex.: chegou mensagem de prioridade maior).\n chat.ticket = this.#nextTicket++;\n chat.listedPriority = priority;\n this.#ready[priority].push({ chat, ticket: chat.ticket });\n }\n\n #pump(): void {\n if (this.#pumping || this.#paused) return;\n this.#pumping = true;\n try {\n for (;;) {\n const list = this.#peekReady();\n if (list === undefined) return;\n const now = this.#clock();\n if (now < this.#globalReadyAt) {\n this.#globalTimer ??= setTimeout(() => {\n this.#globalTimer = undefined;\n this.#pump();\n }, this.#globalReadyAt - now);\n return;\n }\n const entry = list.shift();\n if (entry !== undefined) this.#dispatch(entry.chat, now);\n }\n } finally {\n this.#pumping = false;\n }\n }\n\n /** Lista de maior prioridade com entrada válida na frente; descarta as obsoletas. */\n #peekReady(): Fifo<ReadyEntry> | undefined {\n for (const list of this.#ready) {\n for (let entry = list.peek(); entry !== undefined; entry = list.peek()) {\n if (entry.ticket === entry.chat.ticket) return list;\n list.shift();\n }\n }\n return undefined;\n }\n\n #dispatch(chat: ChatState, now: number): void {\n let job = chat.head;\n if (job !== null) {\n chat.head = null;\n } else {\n const priority = firstNonEmpty(chat.jobs);\n job = priority === -1 ? null : (chat.jobs[priority].shift() ?? null);\n // Inalcançável: só chat com mensagem entra na lista de prontos.\n if (job === null) return;\n }\n chat.ticket = 0;\n chat.busy = true;\n chat.pending--;\n this.#pendingBy[job.priority]--;\n this.#inFlight++;\n this.#globalReadyAt = now + this.#globalIntervalMs;\n chat.readyAt = now + this.#chatIntervalMs;\n this.#rememberCooldown(chat.id, chat.readyAt, now);\n void this.#execute(chat, job);\n }\n\n #rememberCooldown(chatId: string, readyAt: number, now: number): void {\n for (const [id, until] of this.#cooldowns) {\n if (until > now) break;\n this.#cooldowns.delete(id);\n }\n this.#cooldowns.delete(chatId);\n this.#cooldowns.set(chatId, readyAt);\n }\n\n async #execute(chat: ChatState, job: Job): Promise<void> {\n job.attempts++;\n try {\n if (this.#humanize !== null && job.content !== null) {\n await this.#simulate(chat.id, job.content, this.#humanize);\n }\n // Descartada durante o \"digitando\": o envio não chegou ao transport e não sai.\n if (this.#discarding) {\n this.#dropped++;\n job.reject(\n new OutboundQueueError('closed', 'fila de saída fechada sem drenar: envio descartado'),\n );\n } else {\n const result = await this.#withTimeout(job.run(), job.what);\n this.#sent++;\n this.#settle(chat, job, result);\n }\n } catch (error) {\n this.#handleFailure(chat, job, error);\n }\n this.#inFlight--;\n chat.busy = false;\n if (chat.pending === 0) {\n clearTimeout(chat.timer);\n this.#chats.delete(chat.id);\n this.#notifyIdle();\n } else {\n this.#wake(chat, this.#clock());\n }\n this.#pump();\n }\n\n /** Resolve o envio ou, num texto dividido, põe a parte seguinte na frente do chat. */\n #settle(chat: ChatState, job: Job, result: unknown): void {\n const first = job.first ?? { value: result };\n const [next, ...rest] = job.rest;\n if (next === undefined) {\n job.resolve(first.value);\n return;\n }\n if (this.#discarding) {\n this.#dropped++;\n job.reject(\n new OutboundQueueError('closed', 'fila de saída fechada sem drenar: envio descartado'),\n );\n return;\n }\n chat.head = { ...job, ...next, rest, first, attempts: 0 };\n chat.pending++;\n this.#pendingBy[job.priority]++;\n }\n\n #handleFailure(chat: ChatState, job: Job, error: unknown): void {\n const now = this.#clock();\n const hint = this.#discarding ? undefined : retryAfter(error);\n // Janela global (429 global): nenhum chat envia antes dela, nem quando este envio não\n // re-tenta. Mandar antes só gastaria requisições recusadas, que a plataforma também pune.\n if (hint?.global === true) {\n this.#globalReadyAt = Math.max(this.#globalReadyAt, now + hint.ms);\n }\n let retryable: boolean;\n try {\n // Prazo estourado não re-tenta: o transport pode ainda entregar, e reenviar duplicaria.\n // Pausada além do teto, a re-tentativa ficaria parada sem previsão. Janela acima do teto\n // de espera também não: a resposta sairia fora de contexto.\n retryable =\n !this.#discarding &&\n !this.#offline &&\n !(error instanceof OutboundQueueError) &&\n job.attempts < this.#maxAttempts &&\n (hint === undefined || hint.ms <= this.#maxDelayMs) &&\n this.#isRetryable(error);\n } catch (hookError) {\n this.#failed++;\n job.reject(new AggregateError([hookError, error], 'retry.isRetryable lançou'));\n return;\n }\n if (!retryable) {\n this.#failed++;\n job.reject(error);\n return;\n }\n this.#retries++;\n chat.head = job;\n chat.pending++;\n this.#pendingBy[job.priority]++;\n // A janela informada pela plataforma é exata: sem jitter, e no lugar do backoff, que\n // tentaria cedo demais e gastaria as tentativas antes de ela abrir.\n const delay = hint === undefined ? this.#backoff(job.attempts) : hint.ms;\n chat.readyAt = Math.max(chat.readyAt, now + delay);\n }\n\n /**\n * Corre `operation` contra `sendTimeoutMs`. O resultado tardio é ignorado de propósito: quem\n * chamou `send` já recebeu o `'timeout'`, e o `race` mantém um handler na promise original.\n */\n #withTimeout<T>(operation: Promise<T>, what: string): Promise<T> {\n if (this.#sendTimeoutMs === Number.POSITIVE_INFINITY) return operation;\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n const message = `${what}: transport sem resposta em ${this.#sendTimeoutMs} ms`;\n reject(new OutboundQueueError('timeout', message));\n }, this.#sendTimeoutMs);\n });\n return Promise.race([operation, timeout]).finally(() => clearTimeout(timer));\n }\n\n /** Exponencial com teto e jitter \"igual\": metade fixa, metade aleatória. */\n #backoff(failures: number): number {\n const capped = Math.min(this.#maxDelayMs, this.#baseDelayMs * 2 ** (failures - 1));\n return capped / 2 + (capped / 2) * this.#random();\n }\n\n async #simulate(\n chatId: string,\n content: OutgoingContent,\n humanize: Required<HumanizeOptions>,\n ): Promise<void> {\n let kind: TypingKind;\n let ms: number;\n if (content.type === 'text') {\n kind = 'text';\n ms = Math.min(\n humanize.maxMs,\n Math.max(humanize.minMs, content.text.length * humanize.msPerChar),\n );\n } else if (content.type === 'voice') {\n kind = 'voice';\n ms = humanize.maxMs;\n } else {\n return;\n }\n try {\n await this.#withTimeout(this.#transport.sendTyping(chatId, kind), `\"digitando\" em ${chatId}`);\n } catch (error) {\n // O indicador é cosmético: a falha vai para o destino configurado e o envio segue já.\n this.#onTypingError?.(error, chatId);\n return;\n }\n if (ms > 0 && !this.#discarding) await this.#sleep(ms);\n }\n\n /** Espera `ms`, ou menos se a fila for descartada antes. */\n #sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const done = (): void => {\n clearTimeout(timer);\n this.#sleepers.delete(done);\n resolve();\n };\n const timer = setTimeout(done, ms);\n this.#sleepers.add(done);\n });\n }\n\n #discard(): void {\n this.#discarding = true;\n clearTimeout(this.#pauseTimer);\n this.#pauseTimer = undefined;\n for (const done of this.#sleepers) done();\n this.#rejectWaiting(\n () => new OutboundQueueError('closed', 'fila de saída fechada sem drenar: envio descartado'),\n );\n }\n\n /** Rejeita tudo o que aguarda, inclusive re-tentativas; os envios em andamento seguem. */\n #rejectWaiting(error: () => OutboundQueueError): void {\n for (const chat of this.#chats.values()) {\n const waiting: Job[] = chat.head === null ? [] : [chat.head];\n for (const fifo of chat.jobs) {\n for (let job = fifo.shift(); job !== undefined; job = fifo.shift()) waiting.push(job);\n }\n for (const job of waiting) {\n this.#dropped++;\n job.reject(error());\n }\n chat.head = null;\n chat.pending = 0;\n chat.ticket = 0;\n clearTimeout(chat.timer);\n chat.timer = undefined;\n if (!chat.busy) this.#chats.delete(chat.id);\n }\n this.#pendingBy[0] = 0;\n this.#pendingBy[1] = 0;\n this.#pendingBy[2] = 0;\n for (const list of this.#ready) list.clear();\n clearTimeout(this.#globalTimer);\n this.#globalTimer = undefined;\n this.#notifyIdle();\n }\n\n #notifyIdle(): void {\n if (this.#chats.size > 0 || this.#idleWaiters.length === 0) return;\n const waiters = this.#idleWaiters;\n this.#idleWaiters = [];\n for (const resolve of waiters) resolve();\n }\n}\n\nfunction firstNonEmpty(jobs: ChatState['jobs']): PriorityIndex | -1 {\n if (jobs[0].size > 0) return 0;\n if (jobs[1].size > 0) return 1;\n return jobs[2].size > 0 ? 2 : -1;\n}\n\nfunction nonNegative(name: string, value: number): number {\n if (!(Number.isFinite(value) && value >= 0)) {\n throw new RangeError(`${name} deve ser um número finito >= 0 (recebido: ${value})`);\n }\n return value;\n}\n\nfunction pace(\n name: keyof TransportPacing,\n configured: number | undefined,\n pacing: TransportPacing | undefined,\n): number {\n if (configured !== undefined) return nonNegative(name, configured);\n const fromTransport = pacing?.[name];\n if (fromTransport !== undefined) return nonNegative(`transport.pacing.${name}`, fromTransport);\n return DEFAULTS[name];\n}\n\n/**\n * Janela que a plataforma informou num erro do transport (ADR 0067): `retryAfterMs` finito e\n * >= 0, e `retryAfterScope: 'global'` quando ela vale para todos os chats. Duck typing, como o\n * `retryable`: o transport não precisa de classe do core para lançar o erro nativo enriquecido.\n */\nfunction retryAfter(error: unknown): { readonly ms: number; readonly global: boolean } | undefined {\n if (typeof error !== 'object' || error === null || !('retryAfterMs' in error)) return undefined;\n const ms = error.retryAfterMs;\n if (typeof ms !== 'number' || !(Number.isFinite(ms) && ms >= 0)) return undefined;\n return { ms, global: 'retryAfterScope' in error && error.retryAfterScope === 'global' };\n}\n\nfunction isTransient(error: unknown): boolean {\n if (error instanceof UnsupportedError) return false;\n return !(\n typeof error === 'object' &&\n error !== null &&\n 'retryable' in error &&\n error.retryable === false\n );\n}\n\nfunction resolveHumanize(\n option: boolean | HumanizeOptions | undefined,\n transport: OutboundTransport,\n): Required<HumanizeOptions> | null {\n // Capabilities são fixas na vida do transport: decide uma vez, não a cada envio.\n if (option === undefined || option === false || !hasCapability(transport, 'typing')) {\n return null;\n }\n const custom = option === true ? {} : option;\n return {\n msPerChar: nonNegative('humanize.msPerChar', custom.msPerChar ?? DEFAULTS.msPerChar),\n minMs: nonNegative('humanize.minMs', custom.minMs ?? DEFAULTS.minMs),\n maxMs: nonNegative('humanize.maxMs', custom.maxMs ?? DEFAULTS.maxMs),\n };\n}\n","import type { BotEventName } from './types.ts';\n\n// Objeto mapeado em vez de array: o compilador barra evento faltando e evento a mais, então a\n// lista de runtime não descola de `BotEvents`.\nconst names: { readonly [E in BotEventName]: true } = {\n message: true,\n 'message.edited': true,\n 'message.deleted': true,\n reaction: true,\n 'poll.vote': true,\n 'group.joined': true,\n 'group.left': true,\n 'group.participants': true,\n 'group.updated': true,\n 'contact.updated': true,\n 'connection.status': true,\n 'connection.qr': true,\n 'connection.pairing-code': true,\n 'message:text': true,\n 'message:image': true,\n 'message:video': true,\n 'message:audio': true,\n 'message:voice': true,\n 'message:sticker': true,\n 'message:document': true,\n 'message:location': true,\n 'message:contact': true,\n 'message:poll': true,\n 'message:unknown': true,\n command: true,\n 'plugin.error': true,\n};\n\n/**\n * Valida nomes de evento vindos de fora do sistema de tipos (o `on` de um manifesto em JS): um\n * nome com erro de digitação nunca dispararia, sem aviso nenhum.\n */\nexport function isBotEventName(value: string): value is BotEventName {\n return Object.hasOwn(names, value);\n}\n","// Subconjunto de semver suficiente para `engine` e `dependsOn` (ADR 0016): versões\n// `M.m.p[-pre][+build]` e faixas com `^`, `~`, `>=`, `>`, `<=`, `<`, `=`, curingas (`x`, `X`,\n// `*`, versão parcial), comparadores separados por espaço (E) e `||` (OU). Faixas com hífen\n// (`1.0.0 - 2.0.0`) ficam de fora. Implementado aqui em vez do pacote `semver` para o core não\n// carregar dependência de runtime por ~100 linhas; a semântica segue a do npm, inclusive a\n// regra de pré-release (ver `satisfies`).\n\nexport interface SemVer {\n readonly major: number;\n readonly minor: number;\n readonly patch: number;\n readonly prerelease: readonly (string | number)[];\n}\n\ntype Operator = '<' | '<=' | '>' | '>=' | '=';\n\ninterface Comparator {\n readonly operator: Operator;\n readonly version: SemVer;\n}\n\nconst NUMBER = '0|[1-9]\\\\d*';\nconst IDENTIFIER = '[0-9A-Za-z-]+';\nconst PRERELEASE = `${IDENTIFIER}(?:\\\\.${IDENTIFIER})*`;\nconst VERSION = new RegExp(\n `^(${NUMBER})\\\\.(${NUMBER})\\\\.(${NUMBER})(?:-(${PRERELEASE}))?(?:\\\\+${PRERELEASE})?$`,\n);\nconst PART = `${NUMBER}|x|X|\\\\*`;\nconst PARTIAL = new RegExp(\n `^(\\\\^|~|>=|<=|>|<|=)?(${PART})(?:\\\\.(${PART})(?:\\\\.(${PART})(?:-(${PRERELEASE}))?(?:\\\\+${PRERELEASE})?)?)?$`,\n);\n\nfunction parsePrerelease(raw: string | undefined): (string | number)[] {\n if (raw === undefined) return [];\n return raw.split('.').map((id) => (/^\\d+$/.test(id) ? Number(id) : id));\n}\n\n/** Versão exata (`1.2.3`, `1.0.0-beta.1`); `undefined` se não for semver válido. */\nexport function parseVersion(value: string): SemVer | undefined {\n const match = VERSION.exec(value.trim());\n if (!match) return undefined;\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n prerelease: parsePrerelease(match[4]),\n };\n}\n\nfunction compareIdentifiers(a: string | number, b: string | number): number {\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n // Identificador numérico tem precedência menor que alfanumérico.\n if (typeof a === 'number') return -1;\n if (typeof b === 'number') return 1;\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\n/** Negativo, zero ou positivo, como em `Array#sort`. `+build` não conta. */\nexport function compareVersions(a: SemVer, b: SemVer): number {\n const core = a.major - b.major || a.minor - b.minor || a.patch - b.patch;\n if (core !== 0) return core;\n // Sem pré-release é maior que com: 1.0.0 > 1.0.0-rc.1.\n if (a.prerelease.length === 0 || b.prerelease.length === 0) {\n return b.prerelease.length - a.prerelease.length;\n }\n const length = Math.max(a.prerelease.length, b.prerelease.length);\n for (let i = 0; i < length; i++) {\n const x = a.prerelease[i];\n const y = b.prerelease[i];\n if (x === undefined) return -1;\n if (y === undefined) return 1;\n const diff = compareIdentifiers(x, y);\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\nconst version = (\n major: number,\n minor: number,\n patch: number,\n prerelease: (string | number)[] = [],\n): SemVer => ({ major, minor, patch, prerelease });\n\nconst comparator = (operator: Operator, v: SemVer): Comparator => ({ operator, version: v });\n\n// Nada é menor que 0.0.0-0: um comparador que nenhuma versão satisfaz (ex.: `<*`).\nconst NOTHING: Comparator[] = [comparator('<', version(0, 0, 0, [0]))];\n\nfunction parsePart(raw: string | undefined): number | undefined {\n if (raw === undefined || raw === 'x' || raw === 'X' || raw === '*') return undefined;\n return Number(raw);\n}\n\n/** Converte um termo da faixa (`^1.2`, `>=1.0.0`, `1.x`) em comparadores; `undefined` se inválido. */\nfunction desugar(term: string): Comparator[] | undefined {\n const match = PARTIAL.exec(term);\n if (!match) return undefined;\n const operator = match[1] ?? '=';\n const major = parsePart(match[2]);\n const minor = parsePart(match[3]);\n const patch = parsePart(match[4]);\n // Curinga só no fim: `1.x.3` não é faixa.\n if (\n (major === undefined && match[3] !== undefined) ||\n (minor === undefined && match[4] !== undefined)\n ) {\n return undefined;\n }\n const pre = parsePrerelease(match[5]);\n if (major === undefined) return operator === '<' || operator === '>' ? NOTHING : [];\n const low = version(major, minor ?? 0, patch ?? 0, pre);\n\n switch (operator) {\n case '=':\n if (minor === undefined)\n return [comparator('>=', low), comparator('<', version(major + 1, 0, 0))];\n if (patch === undefined) {\n return [comparator('>=', low), comparator('<', version(major, minor + 1, 0))];\n }\n return [comparator('=', low)];\n case '^': {\n let high: SemVer;\n if (major > 0 || minor === undefined) high = version(major + 1, 0, 0);\n else if (minor > 0 || patch === undefined) high = version(0, minor + 1, 0);\n else high = version(0, 0, patch + 1);\n return [comparator('>=', low), comparator('<', high)];\n }\n case '~': {\n const high = minor === undefined ? version(major + 1, 0, 0) : version(major, minor + 1, 0);\n return [comparator('>=', low), comparator('<', high)];\n }\n case '>':\n if (minor === undefined) return [comparator('>=', version(major + 1, 0, 0))];\n if (patch === undefined) return [comparator('>=', version(major, minor + 1, 0))];\n return [comparator('>', low)];\n case '<=':\n if (minor === undefined) return [comparator('<', version(major + 1, 0, 0))];\n if (patch === undefined) return [comparator('<', version(major, minor + 1, 0))];\n return [comparator('<=', low)];\n default:\n // `>=` e `<` com versão parcial completam com zeros.\n return [comparator(operator as Operator, low)];\n }\n}\n\n/** Conjuntos de comparadores (OU entre conjuntos, E dentro de cada um); `undefined` se inválida. */\nfunction parseRange(range: string): Comparator[][] | undefined {\n const sets: Comparator[][] = [];\n for (const raw of range.split('||')) {\n // `>= 1.2.3` vale como `>=1.2.3`.\n const terms = raw\n .trim()\n .replace(/(\\^|~|>=|<=|>|<|=)\\s+/g, '$1')\n .split(/\\s+/)\n .filter((term) => term.length > 0);\n const set: Comparator[] = [];\n for (const term of terms) {\n const comparators = desugar(term);\n if (!comparators) return undefined;\n set.push(...comparators);\n }\n sets.push(set);\n }\n return sets;\n}\n\n/** `true` se `range` é uma faixa que este subconjunto entende. */\nexport function isValidRange(range: string): boolean {\n return parseRange(range) !== undefined;\n}\n\nfunction test(v: SemVer, { operator, version: other }: Comparator): boolean {\n const diff = compareVersions(v, other);\n switch (operator) {\n case '<':\n return diff < 0;\n case '<=':\n return diff <= 0;\n case '>':\n return diff > 0;\n case '>=':\n return diff >= 0;\n default:\n return diff === 0;\n }\n}\n\n/**\n * `version` está dentro de `range`? Lança `RangeError` se algum dos dois for inválido.\n *\n * Como no npm, uma versão de pré-release só satisfaz a faixa se algum comparador do mesmo\n * conjunto citar pré-release da mesma `M.m.p`: `^1.0.0` não aceita `1.1.0-beta`, mas\n * `^1.1.0-alpha` aceita. Isso evita que um plugin estável carregue em core instável por acaso.\n */\nexport function satisfies(versionText: string, range: string): boolean {\n const v = parseVersion(versionText);\n if (!v) throw new RangeError(`Versão semver inválida: \"${versionText}\"`);\n const sets = parseRange(range);\n if (!sets) throw new RangeError(`Faixa semver inválida: \"${range}\"`);\n return sets.some((set) => {\n if (!set.every((c) => test(v, c))) return false;\n if (v.prerelease.length === 0) return true;\n return set.some(\n ({ version: c }) =>\n c.prerelease.length > 0 &&\n c.major === v.major &&\n c.minor === v.minor &&\n c.patch === v.patch,\n );\n });\n}\n","import type { z } from 'zod';\nimport { assertCommandDefinition, type CommandDefinition } from '#commands/command.ts';\nimport { isBotEventName } from '#events/names.ts';\nimport { isCapability } from '#transport/capabilities.ts';\nimport { isValidRange, parseVersion } from './semver.ts';\nimport type { PluginDefinition, PluginMessages } from './types.ts';\n\n/**\n * Nome de plugin: kebab-case minúsculo, começando por letra. É estável porque vira chave de\n * `disabledPlugins`, namespace de storage e prefixo de rota HTTP (`/plugins/<name>/…`).\n */\nexport const PLUGIN_NAME_PATTERN: RegExp = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;\nconst MAX_NAME_LENGTH = 64;\n\n/** Manifesto malformado: erro de quem escreveu o plugin, então derruba o boot. */\nexport class PluginManifestError extends Error {\n override readonly name = 'PluginManifestError';\n /** `name` declarado, se havia um string. */\n readonly plugin: string | undefined;\n /** De onde o plugin veio (`config` ou caminho do módulo), quando conhecido. */\n readonly origin: string | undefined;\n readonly issues: readonly string[];\n\n constructor(plugin: string | undefined, issues: readonly string[], origin?: string) {\n const who = plugin === undefined ? 'plugin sem nome' : `plugin \"${plugin}\"`;\n const where = origin === undefined ? '' : ` (${origin})`;\n super(`Manifesto inválido no ${who}${where}:\\n- ${issues.join('\\n- ')}`);\n this.plugin = plugin;\n this.origin = origin;\n this.issues = issues;\n }\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nfunction checkName(value: unknown, label: string, issues: string[]): void {\n if (typeof value !== 'string' || !PLUGIN_NAME_PATTERN.test(value)) {\n issues.push(\n `${label} deve ser kebab-case minúsculo (ex.: \"user-names\"); recebido ${show(value)}`,\n );\n } else if (value.length > MAX_NAME_LENGTH) {\n issues.push(`${label} passa de ${MAX_NAME_LENGTH} caracteres`);\n }\n}\n\nconst show = (value: unknown): string =>\n typeof value === 'string' ? `\"${value}\"` : value === undefined ? 'nada' : typeof value;\n\nfunction checkNames(value: unknown, label: string, self: unknown, issues: string[]): void {\n if (value === undefined) return;\n if (!Array.isArray(value)) {\n issues.push(`${label} deve ser uma lista de nomes de plugin`);\n return;\n }\n for (const name of value) {\n checkName(name, `${label}: item`, issues);\n if (name === self) issues.push(`${label} não pode citar o próprio plugin`);\n }\n}\n\n/**\n * `commands` do manifesto (ADR 0079). Confere aqui o que o `ctx.commands.add` só descobriria no\n * boot, para o erro sair no `definePlugin`, que aponta a linha do plugin.\n */\nfunction checkCommands(value: unknown, issues: string[]): void {\n if (value === undefined) return;\n if (!isRecord(value)) {\n issues.push('commands deve ser um objeto nome → comando');\n return;\n }\n for (const [name, declared] of Object.entries(value)) {\n const label = `commands[\"${name}\"]`;\n if (!isRecord(declared)) {\n issues.push(`${label} deve ser um objeto com run`);\n continue;\n }\n if (declared['name'] !== undefined) {\n issues.push(`${label}: o nome vem da chave; tire o campo name`);\n }\n if (typeof declared['run'] !== 'function') issues.push(`${label}.run deve ser uma função`);\n const { aliases, description, onReject } = declared;\n if (aliases !== undefined && !(Array.isArray(aliases) && aliases.every(isString))) {\n issues.push(`${label}.aliases deve ser uma lista de textos`);\n continue;\n }\n if (description !== undefined && typeof description !== 'string') {\n issues.push(`${label}.description deve ser um texto`);\n }\n if (onReject !== undefined && typeof onReject !== 'function') {\n issues.push(`${label}.onReject, se presente, deve ser uma função`);\n }\n try {\n assertCommandDefinition({ ...declared, name } as unknown as CommandDefinition);\n } catch (error) {\n issues.push(`${label}: ${(error as Error).message}`);\n }\n }\n}\n\nfunction checkListeners(value: unknown, issues: string[]): void {\n if (value === undefined) return;\n if (!isRecord(value)) {\n issues.push('on deve ser um objeto evento → listener');\n return;\n }\n for (const [event, listener] of Object.entries(value)) {\n if (!isBotEventName(event)) issues.push(`on: evento desconhecido \"${event}\"`);\n else if (typeof listener !== 'function') issues.push(`on[\"${event}\"] deve ser uma função`);\n }\n}\n\nconst isString = (value: unknown): value is string => typeof value === 'string';\n\n/** Problemas do manifesto, um por linha; lista vazia = válido. Não olha compatibilidade. */\nexport function manifestIssues(value: unknown): string[] {\n if (!isRecord(value)) return ['o plugin deve ser um objeto (use definePlugin)'];\n const issues: string[] = [];\n const { name } = value;\n checkName(name, 'name', issues);\n\n if (typeof value['version'] !== 'string' || !parseVersion(value['version'])) {\n issues.push(`version deve ser semver (ex.: \"1.2.0\"); recebido ${show(value['version'])}`);\n }\n if (typeof value['engine'] !== 'string' || !isValidRange(value['engine'])) {\n issues.push(\n `engine é obrigatório e deve ser uma faixa semver do core (ex.: \"^1.0.0\"); recebido ${show(value['engine'])}`,\n );\n }\n\n const requires = value['requires'];\n if (requires !== undefined) {\n if (!Array.isArray(requires)) issues.push('requires deve ser uma lista de capabilities');\n else {\n for (const capability of requires) {\n if (typeof capability !== 'string' || !isCapability(capability)) {\n issues.push(`requires: capability desconhecida ${show(capability)}`);\n }\n }\n }\n }\n\n const transports = value['transports'];\n if (transports !== undefined) {\n if (\n !Array.isArray(transports) ||\n transports.length === 0 ||\n !transports.every((t) => typeof t === 'string' && t.length > 0)\n ) {\n issues.push('transports, se presente, deve ser uma lista não vazia de nomes de transport');\n }\n }\n\n const dependsOn = value['dependsOn'];\n if (dependsOn !== undefined) {\n if (!isRecord(dependsOn)) issues.push('dependsOn deve ser um objeto nome → faixa semver');\n else {\n for (const [dependency, range] of Object.entries(dependsOn)) {\n checkName(dependency, 'dependsOn: nome', issues);\n if (dependency === name) issues.push('dependsOn não pode citar o próprio plugin');\n if (typeof range !== 'string' || !isValidRange(range)) {\n issues.push(\n `dependsOn[\"${dependency}\"] deve ser uma faixa semver; recebido ${show(range)}`,\n );\n }\n }\n }\n }\n\n checkNames(value['after'], 'after', name, issues);\n\n const priority = value['priority'];\n if (priority !== undefined && (typeof priority !== 'number' || !Number.isFinite(priority))) {\n issues.push('priority deve ser um número finito');\n }\n\n const config = value['config'];\n if (config !== undefined && !(isRecord(config) && typeof config['safeParse'] === 'function')) {\n issues.push('config deve ser um schema Zod');\n }\n\n const messages = value['messages'];\n if (\n messages !== undefined &&\n !(isRecord(messages) && Object.values(messages).every((text) => typeof text === 'string'))\n ) {\n issues.push('messages deve ser um objeto chave → texto');\n }\n\n checkCommands(value['commands'], issues);\n checkListeners(value['on'], issues);\n\n // Sem `commands` nem `on`, o `setup` é o único jeito de o plugin fazer algo.\n const declares = value['commands'] !== undefined || value['on'] !== undefined;\n if (typeof value['setup'] !== 'function' && (value['setup'] !== undefined || !declares)) {\n issues.push('setup deve ser uma função (opcional quando o plugin declara commands ou on)');\n }\n if (value['teardown'] !== undefined && typeof value['teardown'] !== 'function') {\n issues.push('teardown, se presente, deve ser uma função');\n }\n return issues;\n}\n\n/** Lança `PluginManifestError` se `value` não for um plugin bem formado. */\nexport function assertPluginDefinition(\n value: unknown,\n origin?: string,\n): asserts value is PluginDefinition {\n const issues = manifestIssues(value);\n if (issues.length === 0) return;\n const name = isRecord(value) && typeof value['name'] === 'string' ? value['name'] : undefined;\n throw new PluginManifestError(name, issues, origin);\n}\n\n/**\n * Declara um plugin. Valida o manifesto na hora (lança `PluginManifestError`) e devolve a\n * própria definição, tipada: o `ctx.config` de `setup`/`teardown` sai de `z.output` do schema\n * em `config`, e `ctx.plugin.messages` tem as chaves de `messages`.\n */\nexport function definePlugin<\n TSchema extends z.ZodType = z.ZodType,\n TMessages extends PluginMessages = PluginMessages,\n>(definition: PluginDefinition<TSchema, TMessages>): PluginDefinition<TSchema, TMessages> {\n assertPluginDefinition(definition);\n return definition;\n}\n","/**\n * Versão do `@usebridger/core`, contra a qual o loader confere o `engine` dos plugins. Fica numa\n * constante (e não lida do `package.json` em runtime) para valer igual no fonte e no bundle.\n * Não edite à mão: `pnpm version-packages` roda o `changeset version` e reescreve esta linha\n * (`scripts/sync-version.ts`); o `version.test.ts` falha se ela divergir do `package.json`.\n */\nexport const CORE_VERSION = '0.3.0';\n","// Açúcar do manifesto (ADR 0079): `commands` e `on` viram as chamadas que o `setup` faria à mão.\n// Não há segundo caminho de execução: o comando passa pelo mesmo `ctx.commands.add`, com prazo,\n// recusa e teardown iguais aos da forma longa.\n\nimport type { BotEventName, Listener } from '#events/types.ts';\nimport type { Capability } from '#transport/capabilities.ts';\nimport type { PluginContext, PluginDefinition, PluginListener } from './types.ts';\n\n/** Registra os `commands` e o `on` do manifesto. Chamado pelo host antes do `setup`. */\nexport function installDeclared(definition: PluginDefinition, ctx: PluginContext): void {\n for (const [name, declared] of Object.entries(definition.commands ?? {})) {\n const { run, onReject, ...rest } = declared;\n ctx.commands.add({\n ...rest,\n name,\n run: (c) => run.call(declared, c, ctx),\n ...(onReject && { onReject: (c, rejection) => onReject.call(declared, c, rejection, ctx) }),\n });\n }\n for (const [event, listener] of Object.entries(definition.on ?? {}) as [\n BotEventName,\n PluginListener<BotEventName>,\n ][]) {\n const subscribed: Listener<BotEventName> = (e) => listener(e, ctx);\n ctx.events.on(event, subscribed);\n }\n}\n\n/**\n * `requires` declarado mais o que o manifesto implica: comando declarado pode responder texto\n * devolvendo-o, então exige `send.text` sem o autor precisar repeti-lo.\n */\nexport function requiredCapabilities(definition: PluginDefinition): readonly Capability[] {\n const declared = definition.requires ?? [];\n const hasCommands = Object.keys(definition.commands ?? {}).length > 0;\n return hasCommands && !declared.includes('send.text') ? [...declared, 'send.text'] : declared;\n}\n","import type { PluginManifest } from './types.ts';\n\n/** O que a ordenação lê do manifesto. */\nexport type OrderableManifest = Pick<PluginManifest, 'name' | 'priority' | 'after' | 'dependsOn'>;\n\n/** `dependsOn`/`after` formam um ciclo: não existe ordem de carga possível. Erro no boot. */\nexport class PluginCycleError extends Error {\n override readonly name = 'PluginCycleError';\n /** Caminho do ciclo, fechando no primeiro: `['a', 'b', 'a']` = a depende de b, b de a. */\n readonly cycle: readonly string[];\n\n constructor(cycle: readonly string[]) {\n super(\n `Ciclo na ordem de carga dos plugins: ${cycle.join(' → ')} ` +\n '(→ = depende de / carrega depois de). Remova um dos dependsOn/after.',\n );\n this.cycle = cycle;\n }\n}\n\n/**\n * Ordem de carga (ADR 0007): toposort em que `dependsOn` e `after` são arestas (a dependência\n * vem antes) e, entre os prontos, desempata `priority` maior e depois a ordem recebida. Nomes\n * citados que não estão na lista não criam aresta — dependência ausente é motivo de \"ignorado\",\n * não de ordem. Lança `PluginCycleError` com o caminho do ciclo.\n */\nexport function sortPlugins<T extends OrderableManifest>(plugins: readonly T[]): T[] {\n const index = new Map(plugins.map((plugin, i) => [plugin.name, i]));\n // predecessors[i]: índices que precisam carregar antes de i.\n const predecessors = plugins.map((plugin) => {\n const before = new Set<number>();\n for (const name of [...Object.keys(plugin.dependsOn ?? {}), ...(plugin.after ?? [])]) {\n const j = index.get(name);\n if (j !== undefined) before.add(j);\n }\n return before;\n });\n const pending = predecessors.map((before) => before.size);\n const done = new Set<number>();\n const result: T[] = [];\n\n // O(n²) de propósito: são dezenas de plugins, e a escolha explícita do melhor pronto deixa a\n // regra de desempate óbvia.\n while (result.length < plugins.length) {\n let best: number | undefined;\n for (let i = 0; i < plugins.length; i++) {\n if (done.has(i) || pending[i] !== 0) continue;\n if (best === undefined || priorityOf(plugins, i) > priorityOf(plugins, best)) best = i;\n }\n if (best === undefined) throw new PluginCycleError(findCycle(plugins, predecessors, done));\n done.add(best);\n result.push(plugins[best] as T);\n predecessors.forEach((before, i) => {\n if (before.has(best)) pending[i] = (pending[i] ?? 0) - 1;\n });\n }\n return result;\n}\n\nconst priorityOf = (plugins: readonly OrderableManifest[], i: number): number =>\n plugins[i]?.priority ?? 0;\n\n/**\n * Todo nó que sobrou tem um predecessor que também sobrou; andando de predecessor em\n * predecessor, uma hora repete — o trecho desde a repetição é o ciclo.\n */\nfunction findCycle(\n plugins: readonly OrderableManifest[],\n predecessors: readonly Set<number>[],\n done: ReadonlySet<number>,\n): string[] {\n const path: number[] = [];\n let current = plugins.findIndex((_, i) => !done.has(i));\n while (!path.includes(current)) {\n path.push(current);\n const before = [...(predecessors[current] ?? [])]\n .filter((j) => !done.has(j))\n .sort((a, b) => a - b);\n current = before[0] ?? current;\n }\n const cycle = path.slice(path.indexOf(current));\n cycle.push(current);\n return cycle.map((i) => plugins[i]?.name ?? '?');\n}\n","import type { Capability } from '#transport/capabilities.ts';\n\n/** Fase do lifecycle em que um plugin falhou. `context` = a fábrica do contexto lançou. */\nexport type PluginPhase = 'context' | 'setup' | 'teardown' | 'dispose';\n\n/** Falha de um plugin numa fase do lifecycle; o erro original fica em `cause`. */\nexport class PluginLifecycleError extends Error {\n override readonly name = 'PluginLifecycleError';\n readonly plugin: string;\n readonly phase: PluginPhase;\n /** `true` quando a fase estourou o prazo. */\n readonly timedOut: boolean;\n /** O que aconteceu, sem o prefixo do plugin (ex.: `excedeu 5000 ms`). */\n readonly detail: string;\n\n constructor(\n plugin: string,\n phase: PluginPhase,\n detail: string,\n timedOut: boolean,\n cause?: unknown,\n ) {\n super(`plugin \"${plugin}\" (${phase}): ${detail}`, { cause });\n this.plugin = plugin;\n this.phase = phase;\n this.timedOut = timedOut;\n this.detail = detail;\n }\n}\n\n/** Por que um plugin não está carregado. */\nexport type PluginSkipReason =\n | { readonly kind: 'disabled' }\n | { readonly kind: 'engine'; readonly range: string; readonly coreVersion: string }\n | { readonly kind: 'capabilities'; readonly missing: readonly Capability[] }\n | { readonly kind: 'transport'; readonly expected: readonly string[]; readonly actual: string }\n | { readonly kind: 'dependency-missing'; readonly dependency: string }\n | { readonly kind: 'dependency-skipped'; readonly dependency: string }\n | {\n readonly kind: 'dependency-version';\n readonly dependency: string;\n readonly range: string;\n readonly version: string;\n }\n | { readonly kind: 'setup-failed'; readonly error: PluginLifecycleError };\n\ninterface ReportBase {\n readonly name: string;\n readonly version: string;\n /** `'config'` ou caminho do módulo (ver `PluginEntry`). */\n readonly origin: string;\n}\n\n/** Uma linha da tabela de boot. A tabela segue a ordem de carga. */\nexport type PluginReportEntry =\n | (ReportBase & { readonly status: 'loaded' })\n | (ReportBase & { readonly status: 'skipped'; readonly reason: PluginSkipReason });\n\n/** Motivo em texto curto, como aparece na tabela de boot. */\nexport function describeSkipReason(reason: PluginSkipReason): string {\n switch (reason.kind) {\n case 'disabled':\n return 'desabilitado em disabledPlugins';\n case 'engine':\n return `engine incompatível: exige core ${reason.range}, versão atual ${reason.coreVersion}`;\n case 'capabilities':\n return `capability ausente no transport: ${reason.missing.join(', ')}`;\n case 'transport':\n return `transport diferente: exige ${reason.expected.join(' ou ')}, atual ${reason.actual}`;\n case 'dependency-missing':\n return `dependência ausente: ${reason.dependency}`;\n case 'dependency-skipped':\n return `dependência ignorada: ${reason.dependency}`;\n case 'dependency-version':\n return `dependência com versão incompatível: ${reason.dependency}@${reason.version} não satisfaz ${reason.range}`;\n case 'setup-failed': {\n const { error } = reason;\n const phase = error.phase === 'context' ? 'na criação do contexto' : 'no setup';\n const detail =\n error.timedOut || error.cause === undefined\n ? error.detail\n : error.cause instanceof Error\n ? error.cause.message\n : String(error.cause);\n return `falha ${phase}: ${detail}`;\n }\n }\n}\n\n/**\n * Tabela de boot para log, uma linha por plugin, alinhada em colunas:\n *\n * ```\n * Plugins: 1 carregado(s), 1 ignorado(s)\n * sticker 1.2.0 carregado\n * ai 1.0.0 ignorado (capability ausente no transport: polls)\n * ```\n */\nexport function formatBootTable(entries: readonly PluginReportEntry[]): string {\n const loaded = entries.filter((entry) => entry.status === 'loaded').length;\n const header = `Plugins: ${loaded} carregado(s), ${entries.length - loaded} ignorado(s)`;\n const nameWidth = Math.max(0, ...entries.map((entry) => entry.name.length));\n const versionWidth = Math.max(0, ...entries.map((entry) => entry.version.length));\n const lines = entries.map((entry) => {\n const status =\n entry.status === 'loaded' ? 'carregado' : `ignorado (${describeSkipReason(entry.reason)})`;\n return ` ${entry.name.padEnd(nameWidth)} ${entry.version.padEnd(versionWidth)} ${status}`;\n });\n return [header, ...lines].join('\\n');\n}\n","import type { Logger } from '#logger/types.ts';\nimport { type CapabilityHolder, missingCapabilities } from '#transport/capabilities.ts';\nimport { CORE_VERSION } from '#version.ts';\nimport { installDeclared, requiredCapabilities } from './declared.ts';\nimport { assertPluginDefinition } from './define.ts';\nimport { sortPlugins } from './order.ts';\nimport {\n describeSkipReason,\n formatBootTable,\n PluginLifecycleError,\n type PluginPhase,\n type PluginReportEntry,\n type PluginSkipReason,\n} from './report.ts';\nimport { parseVersion, satisfies } from './semver.ts';\nimport type { PluginEntry } from './sources.ts';\nimport type { PluginContext, PluginDefinition } from './types.ts';\n\n/**\n * Contexto de um plugin montado pelo `Bot`. `dispose` desfaz tudo o que o plugin registrou\n * por esse contexto (comandos, listeners, serviços, jobs) e roda sempre depois do `teardown` —\n * ou no lugar dele, quando o `setup` falhou no meio. `reason` é a falha do `setup` (o erro de\n * timeout, se ele estourou o prazo), que vira o motivo do `ctx.signal` abortado (ADR 0033).\n */\nexport interface PluginContextHandle {\n readonly context: PluginContext;\n dispose(reason?: unknown): void | Promise<void>;\n}\n\n/** Monta o contexto de um plugin. O loader não conhece os serviços concretos (M1-16 fornece). */\nexport type PluginContextFactory = (\n plugin: PluginDefinition,\n) => PluginContextHandle | Promise<PluginContextHandle>;\n\nexport interface PluginHostOptions {\n /** Plugins já coletados (ver `collectPlugins`), em ordem de declaração. */\n readonly plugins: readonly PluginEntry[];\n /** Nome e capabilities do transport ativo, conferidos contra `transports` e `requires`. */\n readonly transport: CapabilityHolder;\n readonly createContext: PluginContextFactory;\n readonly log: Logger;\n /** Nomes de plugin que não carregam. */\n readonly disabledPlugins?: readonly string[];\n /** Prazo de criação do contexto e de `setup` em ms. Padrão: 10000. */\n readonly setupTimeoutMs?: number;\n /** Prazo de `teardown` e de `dispose` em ms. Padrão: 5000. */\n readonly teardownTimeoutMs?: number;\n /** Versão conferida contra `engine`. Padrão: `CORE_VERSION`; existe para testes. */\n readonly coreVersion?: string;\n}\n\n/** `idle → starting → running → stopping → stopped`; `stopped` é terminal. */\nexport type PluginHostState = 'idle' | 'starting' | 'running' | 'stopping' | 'stopped';\n\nexport interface PluginReloadResult {\n /** Linha nova do plugin na tabela: `loaded`, ou `skipped` se o `setup` novo falhou. */\n readonly entry: PluginReportEntry;\n /**\n * Linhas novas de quem depende dele (`dependsOn`, transitivo), recarregados em cascata, na\n * ordem de carga. `dependency-skipped` se o plugin recarregado não subiu.\n */\n readonly dependents: readonly PluginReportEntry[];\n /**\n * Falhas do `teardown`/`dispose` das instâncias anteriores, do plugin e dos dependentes (já\n * registradas no log). Falha do `setup` novo fica na `entry` de cada um.\n */\n readonly errors: readonly PluginLifecycleError[];\n}\n\nexport interface PluginHost {\n readonly state: PluginHostState;\n /**\n * Valida, ordena e roda o `setup` de cada plugin compatível, em ordem topológica. Devolve a\n * tabela de boot (também logada). Rejeita — sem rodar nenhum `setup` — com\n * `PluginManifestError`, `PluginConflictError` ou `PluginCycleError`. Falha de um `setup`\n * não rejeita: o plugin e quem depende dele viram \"ignorado\".\n */\n start(): Promise<PluginReportEntry[]>;\n /**\n * `teardown` e `dispose` dos carregados, na ordem inversa da carga. Nunca rejeita por falha\n * de plugin: devolve as falhas (também logadas), e uma não impede o resto. Abortado o\n * `signal`, o `teardown` em curso é abandonado e os seguintes não rodam (cada um vira falha\n * com `timedOut`), mas o `dispose` de todos roda: o kernel desfaz o que o plugin registrou.\n * Idempotente: só o `signal` da primeira chamada vale.\n */\n stop(signal?: AbortSignal): Promise<PluginLifecycleError[]>;\n /**\n * Derruba e sobe de novo um plugin (`teardown` → `dispose` → novo contexto → `setup`) e, em\n * cascata, quem depende dele por `dependsOn` (ADR 0041): os dependentes descem antes (ordem\n * inversa) e sobem depois (ordem de carga), reavaliados como no boot. É a primitiva do reload\n * por mudança de config (ADR 0017): o contexto novo sai da fábrica, que já lê a config\n * atualizada. Vale para plugin carregado ou cujo `setup` falhou.\n */\n reload(name: string): Promise<PluginReloadResult>;\n /** Tabela atual, na ordem de carga (reflete reloads). */\n report(): PluginReportEntry[];\n}\n\n/** Dois plugins com o mesmo `name` (ADR 0007). Erro no boot. */\nexport class PluginConflictError extends Error {\n override readonly name = 'PluginConflictError';\n readonly plugin: string;\n readonly origins: readonly string[];\n\n constructor(plugin: string, origins: readonly string[]) {\n super(\n `Dois plugins se chamam \"${plugin}\" (${origins.join(' e ')}). ` +\n 'O nome identifica o plugin em config, storage e rotas: renomeie um deles.',\n );\n this.plugin = plugin;\n this.origins = origins;\n }\n}\n\n/** Operação incompatível com o estado do host ou do plugin. */\nexport class PluginHostStateError extends Error {\n override readonly name = 'PluginHostStateError';\n}\n\nexport const DEFAULT_SETUP_TIMEOUT_MS = 10_000;\nexport const DEFAULT_TEARDOWN_TIMEOUT_MS = 5000;\n\ninterface Slot {\n readonly entry: PluginEntry;\n report: PluginReportEntry;\n handle: PluginContextHandle | undefined;\n}\n\n/**\n * Roda `fn` com prazo e devolve a falha em vez de lançar. A promise de `fn` sempre ganha um\n * handler, então um `setup` que rejeita depois do timeout não vira rejeição não tratada.\n * Abortado o `signal`, desiste na hora, como num timeout.\n */\nasync function runPhase<T>(\n plugin: string,\n phase: PluginPhase,\n timeoutMs: number,\n fn: () => T | Promise<T>,\n signal?: AbortSignal,\n): Promise<{ ok: true; value: T } | { ok: false; error: PluginLifecycleError }> {\n let timer: NodeJS.Timeout | undefined;\n let onAbort: (() => void) | undefined;\n type Outcome = { ok: true; value: T } | { ok: false; error: PluginLifecycleError };\n const timeout = new Promise<Outcome>((resolve) => {\n const give = (message: string) => () =>\n resolve({ ok: false, error: new PluginLifecycleError(plugin, phase, message, true) });\n timer = setTimeout(give(`excedeu ${timeoutMs} ms`), timeoutMs);\n onAbort = give('abandonado: prazo de parada do bot esgotado');\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n // `then` captura também o throw síncrono.\n const run = Promise.resolve()\n .then(fn)\n .then(\n (value): Outcome => ({ ok: true, value }),\n (cause: unknown): Outcome => ({\n ok: false,\n error: new PluginLifecycleError(plugin, phase, 'falhou', false, cause),\n }),\n );\n try {\n return await Promise.race([run, timeout]);\n } finally {\n clearTimeout(timer);\n if (onAbort) signal?.removeEventListener('abort', onAbort);\n }\n}\n\nconst reportBase = ({ definition, origin }: PluginEntry) => ({\n name: definition.name,\n version: definition.version,\n origin,\n});\n\n/** Cria o host de plugins. Não roda nada até `start()`. */\nexport function createPluginHost(options: PluginHostOptions): PluginHost {\n const { transport, createContext, log } = options;\n const coreVersion = options.coreVersion ?? CORE_VERSION;\n if (!parseVersion(coreVersion)) throw new RangeError(`coreVersion inválida: \"${coreVersion}\"`);\n const setupTimeoutMs = options.setupTimeoutMs ?? DEFAULT_SETUP_TIMEOUT_MS;\n const teardownTimeoutMs = options.teardownTimeoutMs ?? DEFAULT_TEARDOWN_TIMEOUT_MS;\n const disabled = new Set(options.disabledPlugins ?? []);\n\n let state: PluginHostState = 'idle';\n let slots: Slot[] = [];\n const byName = new Map<string, Slot>();\n let stopPromise: Promise<PluginLifecycleError[]> | undefined;\n // start, stop e reload rodam um de cada vez: um reload no meio do stop deixaria contexto órfão.\n let queue: Promise<unknown> = Promise.resolve();\n\n function enqueue<T>(task: () => Promise<T>): Promise<T> {\n const result = queue.then(task);\n // A fila só precisa saber que a tarefa acabou; o erro chega a quem chamou por `result`.\n queue = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n }\n\n /** Motivo estático para não carregar, na ordem em que a tabela mostra. */\n function incompatibility(definition: PluginDefinition): PluginSkipReason | undefined {\n if (disabled.has(definition.name)) return { kind: 'disabled' };\n if (!satisfies(coreVersion, definition.engine)) {\n return { kind: 'engine', range: definition.engine, coreVersion };\n }\n if (definition.transports && !definition.transports.includes(transport.name)) {\n return { kind: 'transport', expected: definition.transports, actual: transport.name };\n }\n const missing = missingCapabilities(transport, requiredCapabilities(definition));\n if (missing.length > 0) return { kind: 'capabilities', missing };\n for (const [dependency, range] of Object.entries(definition.dependsOn ?? {})) {\n const slot = byName.get(dependency);\n if (!slot) return { kind: 'dependency-missing', dependency };\n const { version } = slot.entry.definition;\n if (!satisfies(version, range)) {\n return { kind: 'dependency-version', dependency, range, version };\n }\n // A ordem topológica garante que a dependência já foi decidida.\n if (slot.report.status !== 'loaded') return { kind: 'dependency-skipped', dependency };\n }\n return undefined;\n }\n\n /** Contexto + `setup`. Em falha, desfaz o que o plugin registrou e devolve o motivo. */\n async function bringUp(slot: Slot): Promise<PluginReportEntry> {\n const { definition } = slot.entry;\n const base = reportBase(slot.entry);\n const created = await runPhase(definition.name, 'context', setupTimeoutMs, () =>\n createContext(definition),\n );\n if (!created.ok) return fail(base, created.error);\n const handle = created.value;\n // O declarado entra na fase do `setup`: um conflito de nome falha e desfaz como na forma longa.\n const setup = await runPhase(definition.name, 'setup', setupTimeoutMs, () => {\n installDeclared(definition, handle.context);\n return definition.setup?.(handle.context);\n });\n if (!setup.ok) {\n // Sem teardown: ele pareia com um setup que terminou. O dispose limpa o registro parcial.\n const disposed = await runPhase(definition.name, 'dispose', teardownTimeoutMs, () =>\n handle.dispose(setup.error),\n );\n if (!disposed.ok) logLifecycleError(disposed.error);\n return fail(base, setup.error);\n }\n slot.handle = handle;\n return { ...base, status: 'loaded' };\n }\n\n function fail(\n base: ReturnType<typeof reportBase>,\n error: PluginLifecycleError,\n ): PluginReportEntry {\n logLifecycleError(error);\n return { ...base, status: 'skipped', reason: { kind: 'setup-failed', error } };\n }\n\n /** `teardown` (se houver) e `dispose`, sempre os dois; devolve as falhas. */\n async function bringDown(slot: Slot, signal?: AbortSignal): Promise<PluginLifecycleError[]> {\n const { handle } = slot;\n if (!handle) return [];\n slot.handle = undefined;\n const { definition } = slot.entry;\n const errors: PluginLifecycleError[] = [];\n if (definition.teardown && signal?.aborted) {\n errors.push(\n new PluginLifecycleError(\n definition.name,\n 'teardown',\n 'não executado: prazo de parada do bot esgotado',\n true,\n ),\n );\n } else if (definition.teardown) {\n const teardown = definition.teardown.bind(definition);\n const result = await runPhase(\n definition.name,\n 'teardown',\n teardownTimeoutMs,\n () => teardown(handle.context),\n signal,\n );\n if (!result.ok) errors.push(result.error);\n }\n const disposed = await runPhase(definition.name, 'dispose', teardownTimeoutMs, () =>\n handle.dispose(),\n );\n if (!disposed.ok) errors.push(disposed.error);\n for (const error of errors) logLifecycleError(error);\n return errors;\n }\n\n function logLifecycleError(error: PluginLifecycleError): void {\n log.error(error.message, {\n plugin: error.plugin,\n phase: error.phase,\n timedOut: error.timedOut,\n err: error.cause ?? error,\n });\n }\n\n function logTable(entries: PluginReportEntry[]): void {\n const fields = {\n plugins: entries.map((entry) => ({\n name: entry.name,\n version: entry.version,\n origin: entry.origin,\n status: entry.status,\n ...(entry.status === 'skipped' ? { reason: describeSkipReason(entry.reason) } : {}),\n })),\n };\n const anySkipped = entries.some((entry) => entry.status === 'skipped');\n // Plugin ignorado é configuração a revisar: warn chama atenção sem ser falha do bot.\n if (anySkipped) log.warn(formatBootTable(entries), fields);\n else log.info(formatBootTable(entries), fields);\n }\n\n /** Erros de boot: manifesto, nome repetido e ciclo. Lança antes de qualquer setup. */\n function plan(): Slot[] {\n const origins = new Map<string, string[]>();\n for (const { definition, origin } of options.plugins) {\n assertPluginDefinition(definition, origin);\n origins.set(definition.name, [...(origins.get(definition.name) ?? []), origin]);\n }\n for (const [name, found] of origins) {\n if (found.length > 1) throw new PluginConflictError(name, found);\n }\n const order = sortPlugins(options.plugins.map((entry) => entry.definition));\n const entryOf = new Map(options.plugins.map((entry) => [entry.definition, entry]));\n return order.map((definition) => {\n const entry = entryOf.get(definition) as PluginEntry;\n return { entry, report: { ...reportBase(entry), status: 'loaded' }, handle: undefined };\n });\n }\n\n async function runStart(): Promise<PluginReportEntry[]> {\n try {\n slots = plan();\n } catch (error) {\n state = 'stopped';\n throw error;\n }\n for (const slot of slots) byName.set(slot.entry.definition.name, slot);\n for (const name of disabled) {\n if (!byName.has(name)) {\n log.warn(`disabledPlugins cita \"${name}\", que não existe entre os plugins`, {\n plugin: name,\n });\n }\n }\n for (const slot of slots) {\n const reason = incompatibility(slot.entry.definition);\n slot.report = reason\n ? { ...reportBase(slot.entry), status: 'skipped', reason }\n : await bringUp(slot);\n }\n const table = slots.map((slot) => slot.report);\n logTable(table);\n if (state === 'starting') state = 'running';\n return table;\n }\n\n async function runStop(signal?: AbortSignal): Promise<PluginLifecycleError[]> {\n state = 'stopping';\n const errors: PluginLifecycleError[] = [];\n // Ordem inversa: quem subiu depois pode usar serviços de quem subiu antes.\n for (const slot of slots.toReversed()) errors.push(...(await bringDown(slot, signal)));\n state = 'stopped';\n return errors;\n }\n\n async function runReload(name: string): Promise<PluginReloadResult> {\n if (state !== 'running') {\n throw new PluginHostStateError(`reload(\"${name}\"): host em \"${state}\"`);\n }\n const slot = byName.get(name);\n if (!slot) throw new PluginHostStateError(`reload(\"${name}\"): plugin desconhecido`);\n const { report } = slot;\n if (report.status === 'skipped' && report.reason.kind !== 'setup-failed') {\n throw new PluginHostStateError(\n `reload(\"${name}\"): plugin ignorado (${describeSkipReason(report.reason)}); ` +\n 'só recarrega plugin carregado ou cujo setup falhou',\n );\n }\n // Quem guardou um serviço do plugin no `setup` ficaria com a instância do contexto\n // descartado: o subgrafo de dependentes desce e sobe junto (ADR 0041).\n const affected = withDependents(slot);\n const errors: PluginLifecycleError[] = [];\n for (const each of affected.toReversed()) errors.push(...(await bringDown(each)));\n for (const each of affected) {\n // O próprio plugin não passa por `incompatibility`: o motivo estático dele não muda, e\n // um `setup-failed` anterior precisa de uma nova tentativa.\n const reason = each === slot ? undefined : incompatibility(each.entry.definition);\n each.report = reason\n ? { ...reportBase(each.entry), status: 'skipped', reason }\n : await bringUp(each);\n }\n const dependents = affected.slice(1).map((each) => each.report);\n log.info(\n `plugin \"${name}\" recarregado: ${slot.report.status === 'loaded' ? 'carregado' : 'ignorado'}`,\n {\n plugin: name,\n status: slot.report.status,\n ...(dependents.length > 0 && {\n dependents: dependents.map((entry) => ({ name: entry.name, status: entry.status })),\n }),\n },\n );\n return { entry: slot.report, dependents, errors };\n }\n\n /**\n * O slot e quem depende dele por `dependsOn`, direta ou transitivamente, na ordem de carga.\n * `after` só ordena: quem o usa não pega nada do outro plugin, então não entra.\n */\n function withDependents(root: Slot): Slot[] {\n const names = new Set([root.entry.definition.name]);\n // Na ordem topológica, toda dependência aparece antes do dependente: uma passada basta.\n return slots.filter((each) => {\n if (each === root) return true;\n const dependsOn = Object.keys(each.entry.definition.dependsOn ?? {});\n if (!dependsOn.some((dependency) => names.has(dependency))) return false;\n names.add(each.entry.definition.name);\n return true;\n });\n }\n\n return {\n get state(): PluginHostState {\n return state;\n },\n\n start(): Promise<PluginReportEntry[]> {\n if (state !== 'idle') {\n return Promise.reject(new PluginHostStateError(`start(): host em \"${state}\"`));\n }\n state = 'starting';\n return enqueue(runStart);\n },\n\n stop(signal?: AbortSignal): Promise<PluginLifecycleError[]> {\n if (state === 'idle') {\n state = 'stopped';\n stopPromise = Promise.resolve([]);\n }\n stopPromise ??= enqueue(() => runStop(signal));\n return stopPromise;\n },\n\n reload(name: string): Promise<PluginReloadResult> {\n return enqueue(() => runReload(name));\n },\n\n report(): PluginReportEntry[] {\n return slots.map((slot) => slot.report);\n },\n };\n}\n","import { existsSync } from 'node:fs';\nimport { readdir } from 'node:fs/promises';\nimport { extname, join, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { PluginDefinition } from './types.ts';\n\n/**\n * Plugin a carregar e de onde veio. As duas fontes (ADR 0007) produzem a mesma `definition`;\n * `origin` só serve para mensagens de erro e para a tabela de boot.\n */\nexport interface PluginEntry {\n readonly definition: PluginDefinition;\n /** `'config'` para a lista da config; caminho absoluto do módulo para `pluginDirs`. */\n readonly origin: string;\n}\n\n/** Falha ao ler uma pasta de plugins ou importar um módulo dela. Erro no boot. */\nexport class PluginDiscoveryError extends Error {\n override readonly name = 'PluginDiscoveryError';\n readonly path: string;\n\n constructor(path: string, message: string, cause?: unknown) {\n super(`pluginDirs: ${message} (${path})`, { cause });\n this.path = path;\n }\n}\n\nconst MODULE_EXTENSIONS = ['.ts', '.mts', '.js', '.mjs'];\n\n/** Arquivos que convivem na pasta sem serem plugin: testes, tipos e helpers com `_`/`.`. */\nfunction isIgnored(name: string): boolean {\n return (\n name.startsWith('.') ||\n name.startsWith('_') ||\n name.endsWith('.d.ts') ||\n name.endsWith('.d.mts') ||\n /\\.(test|spec)\\.[cm]?[jt]s$/.test(name)\n );\n}\n\n/**\n * Duck typing de propósito: o core instalado no app pode ser outra cópia que a do plugin.\n * `commands` ou `on` contam como o `setup`: o plugin só declarativo não tem `setup` (ADR 0079).\n */\nconst looksLikePlugin = (value: unknown): value is PluginDefinition => {\n if (typeof value !== 'object' || value === null) return false;\n const { name, setup, commands, on } = value as Record<string, unknown>;\n return (\n typeof name === 'string' && (typeof setup === 'function' || isObject(commands) || isObject(on))\n );\n};\n\nconst isObject = (value: unknown): boolean => typeof value === 'object' && value !== null;\n\n/** Módulo da entrada da pasta: o próprio arquivo, ou o `index.*` de uma subpasta. */\nasync function moduleOf(dir: string, entry: { name: string; isDirectory(): boolean }) {\n const path = join(dir, entry.name);\n if (entry.isDirectory()) {\n const index = MODULE_EXTENSIONS.map((ext) => join(path, `index${ext}`)).find((candidate) =>\n existsSync(candidate),\n );\n if (index === undefined) {\n throw new PluginDiscoveryError(\n path,\n 'subpasta sem index.ts/index.js; para a pasta não ser lida como plugin, prefixe com \"_\"',\n );\n }\n return index;\n }\n return MODULE_EXTENSIONS.includes(extname(entry.name)) ? path : undefined;\n}\n\n/**\n * Descobre os plugins de uma pasta. Convenção: cada arquivo `.ts`/`.mts`/`.js`/`.mjs` e cada\n * subpasta com `index.*` é um módulo que exporta (export nomeado) um ou mais plugins; todo\n * export com `name` string e `setup` função (ou `commands`/`on`) entra. Ficam de fora nomes\n * começando com `_` ou `.`, testes e `.d.ts`. A ordem é a alfabética dos nomes — nunca a do\n * sistema de arquivos — e um módulo sem plugin é erro, porque quase sempre é engano.\n */\nexport async function discoverPlugins(dir: string): Promise<PluginEntry[]> {\n let entries: { name: string; isDirectory(): boolean }[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (cause) {\n throw new PluginDiscoveryError(dir, 'não foi possível ler a pasta', cause);\n }\n entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));\n\n const found: PluginEntry[] = [];\n for (const entry of entries) {\n if (isIgnored(entry.name)) continue;\n const path = await moduleOf(dir, entry);\n if (path === undefined) continue;\n let namespace: Record<string, unknown>;\n try {\n namespace = (await import(pathToFileURL(path).href)) as Record<string, unknown>;\n } catch (cause) {\n throw new PluginDiscoveryError(path, 'falha ao importar o módulo', cause);\n }\n // O mesmo plugin pode sair por dois exports (ex.: nomeado e default): conta uma vez.\n const plugins = new Set(Object.values(namespace).filter(looksLikePlugin));\n if (plugins.size === 0) {\n throw new PluginDiscoveryError(path, 'o módulo não exporta nenhum plugin (definePlugin)');\n }\n for (const definition of plugins) found.push({ definition, origin: path });\n }\n return found;\n}\n\nexport interface CollectPluginsOptions {\n /** Plugins instanciados na config (ex.: pacotes npm que o app importa). */\n readonly plugins?: readonly PluginDefinition[];\n /** Pastas varridas por `discoverPlugins`, relativas a `cwd`. */\n readonly pluginDirs?: readonly string[];\n /** Base dos caminhos relativos de `pluginDirs`. Padrão: `process.cwd()`. */\n readonly cwd?: string;\n}\n\n/** Junta as duas fontes: primeiro a lista da config, depois cada pasta na ordem dada. */\nexport async function collectPlugins(options: CollectPluginsOptions): Promise<PluginEntry[]> {\n const entries: PluginEntry[] = (options.plugins ?? []).map((definition) => ({\n definition,\n origin: 'config',\n }));\n const cwd = options.cwd ?? process.cwd();\n for (const dir of options.pluginDirs ?? []) {\n entries.push(...(await discoverPlugins(resolve(cwd, dir))));\n }\n return entries;\n}\n","// Fila de entrada por chat (veio da fila por chat do legacy). Mesmo chat em série — sem race no\n// histórico/estado da conversa —, chats distintos em paralelo, sem bloqueio global.\n\n/** Trabalho de uma mensagem. Pode ser síncrono ou assíncrono. */\nexport type InboundTask = () => unknown;\n\n/**\n * Resultado de `enqueue`. `'queued'`: aceita (iniciada ou na fila). `'full'`: o backlog do chat\n * está no limite e a tarefa foi descartada. `'closed'`: a fila foi fechada (shutdown).\n */\nexport type EnqueueResult = 'queued' | 'full' | 'closed';\n\nexport interface InboundQueueOptions {\n /** Destino de todo erro lançado por uma tarefa. A fila segue para a próxima tarefa do chat. */\n readonly onError: (error: unknown, chatId: string) => void;\n /**\n * Máximo de tarefas aguardando por chat, sem contar a que está rodando. Ao exceder, a nova\n * tarefa é rejeitada (`'full'`). Padrão: 100. `Infinity` desliga o limite.\n */\n readonly maxPendingPerChat?: number;\n}\n\n/** Fotografia das métricas da fila. Leitura O(1): os contadores são mantidos incrementalmente. */\nexport interface InboundQueueStats {\n /** Chats com tarefa rodando (e possivelmente outras aguardando). */\n readonly activeChats: number;\n /** Tarefas aguardando em todos os chats, sem contar as que estão rodando. */\n readonly pending: number;\n /** Tarefas concluídas, com sucesso ou erro. */\n readonly processed: number;\n /** Tarefas rejeitadas (`'full'` ou `'closed'`), nunca executadas. */\n readonly dropped: number;\n /** Tarefas que lançaram erro (subconjunto de `processed`). */\n readonly errors: number;\n}\n\nconst DEFAULT_MAX_PENDING_PER_CHAT = 100;\n\nexport class InboundQueue {\n readonly #onError: (error: unknown, chatId: string) => void;\n readonly #maxPending: number;\n // Um chat só tem entrada enquanto há tarefa rodando; o runner a remove ao esvaziar, então o\n // Map nunca acumula chats ociosos (o vazamento do rateLimiter do legacy).\n readonly #chats = new Map<string, InboundTask[]>();\n #idleWaiters: (() => void)[] = [];\n #closed = false;\n #pending = 0;\n #processed = 0;\n #dropped = 0;\n #errors = 0;\n\n constructor(options: InboundQueueOptions) {\n const max = options.maxPendingPerChat ?? DEFAULT_MAX_PENDING_PER_CHAT;\n if (!(max === Number.POSITIVE_INFINITY || (Number.isInteger(max) && max >= 0))) {\n throw new RangeError(\n `maxPendingPerChat deve ser inteiro >= 0 ou Infinity (recebido: ${max})`,\n );\n }\n this.#onError = options.onError;\n this.#maxPending = max;\n }\n\n /**\n * Agenda `task` no chat. Se o chat está ocioso, a tarefa começa já, de forma síncrona; senão\n * aguarda as anteriores. Nunca lança nem rejeita: erros da tarefa vão para `onError`.\n */\n enqueue(chatId: string, task: InboundTask): EnqueueResult {\n if (this.#closed) {\n this.#dropped++;\n return 'closed';\n }\n const waiting = this.#chats.get(chatId);\n if (waiting === undefined) {\n const fresh: InboundTask[] = [];\n this.#chats.set(chatId, fresh);\n void this.#run(chatId, fresh, task);\n return 'queued';\n }\n if (waiting.length >= this.#maxPending) {\n this.#dropped++;\n return 'full';\n }\n waiting.push(task);\n this.#pending++;\n return 'queued';\n }\n\n /** Tarefas aguardando no chat, sem contar a que está rodando. */\n pendingFor(chatId: string): number {\n return this.#chats.get(chatId)?.length ?? 0;\n }\n\n stats(): InboundQueueStats {\n return {\n activeChats: this.#chats.size,\n pending: this.#pending,\n processed: this.#processed,\n dropped: this.#dropped,\n errors: this.#errors,\n };\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n\n /** Resolve quando não há tarefa rodando nem aguardando. Não impede novas tarefas. */\n onIdle(): Promise<void> {\n if (this.#chats.size === 0) return Promise.resolve();\n return new Promise((resolve) => this.#idleWaiters.push(resolve));\n }\n\n /**\n * Shutdown gracioso: para de aceitar tarefas (novas viram `'closed'`) e resolve quando as já\n * aceitas terminarem. Com `drain: false`, descarta as que aguardam (contam em `dropped`); as\n * que já rodam terminam. Pode ser chamado de novo com `drain: false` para abortar uma drenagem.\n */\n close(options: { readonly drain?: boolean } = {}): Promise<void> {\n this.#closed = true;\n if (options.drain === false) {\n for (const waiting of this.#chats.values()) {\n this.#dropped += waiting.length;\n this.#pending -= waiting.length;\n waiting.length = 0;\n }\n }\n return this.onIdle();\n }\n\n async #run(chatId: string, waiting: InboundTask[], first: InboundTask): Promise<void> {\n let task: InboundTask | undefined = first;\n while (task !== undefined) {\n try {\n await task();\n } catch (error) {\n this.#errors++;\n this.#report(error, chatId);\n }\n this.#processed++;\n task = waiting.shift();\n if (task !== undefined) this.#pending--;\n }\n this.#chats.delete(chatId);\n if (this.#chats.size === 0 && this.#idleWaiters.length > 0) {\n const waiters = this.#idleWaiters;\n this.#idleWaiters = [];\n for (const resolve of waiters) resolve();\n }\n }\n\n #report(error: unknown, chatId: string): void {\n try {\n this.#onError(error, chatId);\n } catch (handlerError) {\n // Bug no próprio onError: não há outro destino seguro sem logger, então vira exceção não\n // capturada (fora do runner, para não travar a fila do chat) em vez de sumir.\n queueMicrotask(() => {\n throw new AggregateError(\n [handlerError, error],\n `onError da InboundQueue lançou (chat ${chatId})`,\n );\n });\n }\n }\n}\n","// Escopo de tenant do bot (ADR 0072). O kernel roda cada mensagem e evento cujo chat tem\n// `tenantId` dentro deste escopo, e o storage do plugin lê dele o tenant corrente. Assim o mesmo\n// `ctx.storage` serve ao handler, à closure do `setup`, ao service de outro plugin e ao timer\n// disparado no handler, sem o plugin repassar nada: o isolamento não depende da disciplina dele.\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\n/** Um por bot (ADR 0004: nada global); dois bots no processo não veem o tenant um do outro. */\nexport class TenantScope {\n readonly #store = new AsyncLocalStorage<string | undefined>();\n\n /** Tenant do trabalho corrente, ou `undefined` fora de um (setup, timer solto, sem tenant). */\n get current(): string | undefined {\n return this.#store.getStore();\n }\n\n /**\n * Roda `fn` no escopo de `tenant`; `undefined` sai de qualquer escopo, para o trabalho sem\n * tenant não herdar o de quem o disparou (o loop do scheduler acordado por um handler, por\n * exemplo). Sem troca de escopo, chama direto: a mensagem sem tenant não paga nada.\n */\n run<R>(tenant: string | undefined, fn: () => R): R {\n if (this.#store.getStore() === tenant) return fn();\n return this.#store.run(tenant, fn);\n }\n}\n","// Scheduler do bot (M1-11, plano §6.8). Um serviço por bot: os jobs de todos os plugins ficam\n// numa única coleção do namespace do kernel (`$scheduler`), e um único timer fica armado para o\n// próximo horário. Nada de polling: sem job futuro, nenhum timer existe.\n//\n// Entrega \"pelo menos uma vez\": o documento só sai do storage depois que o handler termina.\n// Se o processo cair no meio, o job continua lá e dispara de novo ao subir.\n\nimport { ContextExpiredError, Deadline, JobTimeoutError } from '#deadline.ts';\nimport type { PluginErrorEvent } from '#events/types.ts';\nimport { kernelStorage } from '#storage/namespace.ts';\nimport type { Collection, JsonValue, StoragePort, Where, WithId } from '#storage/types.ts';\nimport { TenantScope } from '#tenant/scope.ts';\nimport type { Unsubscribe } from '#transport/types.ts';\nimport type { JobContext, JobHandler, Scheduler } from './types.ts';\n\nexport const DEFAULT_JOB_TIMEOUT_MS = 30_000;\nexport const DEFAULT_STORAGE_RETRY_MS = 5000;\nexport const DEFAULT_MAX_CONCURRENT_JOBS = 10;\n\n/** Vencidos lidos por consulta: a leitura é paginada, nunca a coleção inteira na memória. */\nconst DUE_PAGE_SIZE = 100;\n\n/**\n * Maior atraso que o `setTimeout` aceita (~24,8 dias). Acima disso o Node dispara em 1 ms; job\n * mais distante arma o teto e, ao acordar, o loop só recalcula e rearma.\n */\nconst MAX_TIMER_DELAY_MS = 2_147_483_647;\n\n/** Documento de um agendamento. `type` (não `interface`) para casar com o JSON da coleção. */\ntype JobDocument = {\n plugin: string;\n job: string;\n /** Epoch ms. Indexado: é por ele que o loop consulta. */\n fireAt: number;\n payload: JsonValue;\n /** Tenant de quem agendou (ADR 0072); o handler roda no escopo dele. Ausente: sem tenant. */\n tenant?: string;\n};\n\ntype StoredJob = WithId<JobDocument>;\n\ninterface RegisteredHandler {\n readonly handler: JobHandler;\n /** `Deadline` de vida do plugin: pai do `Deadline` de cada execução do handler. */\n readonly lifetime: Deadline | undefined;\n}\n\nexport interface SchedulerServiceOptions {\n /** Storage do bot; os jobs ficam em `kernelStorage(storage, 'scheduler')`. */\n readonly storage: StoragePort;\n /**\n * Destino de toda falha de handler (lançou, rejeitou ou estourou o prazo), com\n * `phase: 'scheduler'` e o nome do job em `event`. Não deve lançar.\n */\n readonly onError: (error: PluginErrorEvent) => void;\n /**\n * Destino da rejeição de um handler que chegou depois do prazo, já reportado como timeout\n * pelo `onError`: normalmente só o log, para não virar um segundo `plugin.error`. Padrão:\n * `onError`. Não deve lançar.\n */\n readonly onLateError?: (error: PluginErrorEvent) => void;\n /**\n * Destino das falhas do próprio storage (consulta do loop, remoção depois do handler). O loop\n * não morre: tenta de novo após `storageRetryMs`. Não deve lançar.\n */\n readonly onStorageError: (error: unknown) => void;\n /**\n * Escopo de tenant do bot (ADR 0072): `at` guarda o tenant corrente no job, e o handler roda\n * no escopo dele. Padrão: um escopo próprio, sem tenant.\n */\n readonly tenants?: TenantScope;\n /** Prazo de cada handler em ms. Padrão: 30000. */\n readonly jobTimeoutMs?: number;\n /** Espera antes de reconsultar o storage depois de uma falha, em ms. Padrão: 5000. */\n readonly storageRetryMs?: number;\n /**\n * Máximo de handlers rodando ao mesmo tempo, somando todos os plugins. Os vencidos além dele\n * esperam vaga, em ordem de `fireAt` (depois de um downtime longo, nada de milhares de handlers\n * de uma vez). Padrão: 10.\n */\n readonly maxConcurrentJobs?: number;\n}\n\nexport interface SchedulerService {\n /**\n * Scheduler em nome do plugin (`ctx.scheduler`): jobs e handlers no namespace dele. Com\n * `lifetime` (o `Deadline` de vida do plugin), o descarte do plugin aborta o `signal` dos jobs\n * dele ainda em andamento.\n */\n forPlugin(plugin: string, lifetime?: Deadline): Scheduler;\n /**\n * Remove os handlers do plugin (teardown e reload). Os jobs persistidos ficam: disparam\n * quando o plugin registrar o handler de novo.\n */\n removePlugin(plugin: string): void;\n /** Liga o loop: dispara o que venceu (inclusive durante o downtime) e arma o próximo. */\n start(): void;\n /**\n * Desarma o timer e espera os handlers em andamento (cada um limitado pelo prazo de job).\n * Abortado o `signal`, abandona os que ainda rodam: o `signal` do job aborta, o prazo dele é\n * desarmado e o documento fica no storage, para disparar de novo na próxima subida. Depois\n * dele não sobra timer vivo. Idempotente.\n */\n stop(signal?: AbortSignal): Promise<void>;\n}\n\n/** Dois handlers para o mesmo job do mesmo plugin: o job seria consumido por um só. */\nexport class JobHandlerConflictError extends Error {\n override readonly name = 'JobHandlerConflictError';\n readonly plugin: string;\n readonly job: string;\n\n constructor(plugin: string, job: string) {\n super(\n `O plugin \"${plugin}\" já registrou um handler para o job \"${job}\". Cada job tem um ` +\n 'handler; cancele o anterior (a função devolvida por on) antes de registrar outro.',\n );\n this.plugin = plugin;\n this.job = job;\n }\n}\n\nfunction validTimeout(name: string, value: number): number {\n // setTimeout trata Infinity/NaN como 1 ms: tudo estouraria na hora.\n if (!Number.isFinite(value) || value <= 0) throw new RangeError(`${name} inválido: ${value}`);\n return value;\n}\n\nfunction toEpoch(when: Date | number): number {\n const ms = when instanceof Date ? when.getTime() : when;\n if (typeof ms !== 'number' || !Number.isFinite(ms)) {\n throw new TypeError(`Horário inválido para o job: ${String(when)}. Use Date ou epoch ms.`);\n }\n return ms;\n}\n\nfunction assertJobName(job: unknown): asserts job is string {\n if (typeof job !== 'string' || job === '') {\n throw new TypeError('Nome de job deve ser texto não vazio.');\n }\n}\n\n/**\n * Recusa o que o JSON perderia ou alteraria em silêncio (`undefined`, `NaN`, `Date`, `Map`,\n * classes, ciclos): o handler tem de receber exatamente o payload agendado.\n */\nfunction assertJsonValue(value: unknown, path: string, seen: Set<object>): void {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return;\n if (typeof value === 'number') {\n if (Number.isFinite(value)) return;\n throw new TypeError(`Payload inválido em ${path}: ${value} não é JSON.`);\n }\n if (typeof value !== 'object') {\n throw new TypeError(`Payload inválido em ${path}: ${typeof value} não é JSON.`);\n }\n if (seen.has(value)) throw new TypeError(`Payload inválido em ${path}: referência circular.`);\n seen.add(value);\n if (Array.isArray(value)) {\n value.forEach((item, i) => {\n assertJsonValue(item, `${path}[${i}]`, seen);\n });\n } else {\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) {\n throw new TypeError(`Payload inválido em ${path}: só objetos simples são JSON.`);\n }\n for (const [key, item] of Object.entries(value)) assertJsonValue(item, `${path}.${key}`, seen);\n }\n seen.delete(value);\n}\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n value !== null &&\n (typeof value === 'object' || typeof value === 'function') &&\n typeof (value as PromiseLike<unknown>).then === 'function'\n );\n}\n\nexport function createSchedulerService(options: SchedulerServiceOptions): SchedulerService {\n const { onError, onStorageError } = options;\n const onLateError = options.onLateError ?? onError;\n const tenants = options.tenants ?? new TenantScope();\n const jobTimeoutMs = validTimeout('jobTimeoutMs', options.jobTimeoutMs ?? DEFAULT_JOB_TIMEOUT_MS);\n const retryMs = validTimeout(\n 'storageRetryMs',\n options.storageRetryMs ?? DEFAULT_STORAGE_RETRY_MS,\n );\n const maxConcurrent = options.maxConcurrentJobs ?? DEFAULT_MAX_CONCURRENT_JOBS;\n if (!Number.isInteger(maxConcurrent) || maxConcurrent < 1) {\n throw new RangeError(`maxConcurrentJobs inválido: ${maxConcurrent}`);\n }\n const jobs: Collection<JobDocument> = kernelStorage(options.storage, 'scheduler').collection(\n 'jobs',\n { indexes: ['fireAt'] },\n );\n\n // plugin → job → handler (com o `Deadline` de vida do plugin que o registrou).\n const handlers = new Map<string, Map<string, RegisteredHandler>>();\n // id → handler em andamento (resolve quando o job saiu do storage). Impede entrega dupla\n // enquanto o handler roda e responde ao `cancel` de job já disparado.\n const inFlight = new Map<string, Promise<void>>();\n // id → abandono do handler em andamento, usado pelo `stop` abortado.\n const abandons = new Map<string, (reason: unknown) => void>();\n\n let started = false;\n let timer: NodeJS.Timeout | undefined;\n let armedAt: number | undefined;\n // Volta do loop em andamento; `rerun` pede outra volta quando algo mudou durante a atual.\n let loop: Promise<void> | undefined;\n let rerun = false;\n // A última volta parou por falta de vaga: quando um handler termina, o loop roda de novo.\n let backlog = false;\n // Uma remoção falhou: a volta nesse horário reentrega o job (pelo menos uma vez).\n let retryAt: number | undefined;\n\n // Exclusão mútua entre \"ler os vencidos e despachar\" e `cancel`: sem ela, um `cancel` poderia\n // apagar o job depois da leitura e antes do despacho, devolver `true` e o job disparar mesmo\n // assim.\n let lock: Promise<unknown> = Promise.resolve();\n function exclusive<T>(fn: () => Promise<T>): Promise<T> {\n const result = lock.then(fn);\n lock = result.catch(() => undefined);\n return result;\n }\n\n function disarm(): void {\n clearTimeout(timer);\n timer = undefined;\n armedAt = undefined;\n }\n\n function arm(at: number): void {\n disarm();\n const delay = Math.min(Math.max(at - Date.now(), 0), MAX_TIMER_DELAY_MS);\n armedAt = at;\n timer = setTimeout(() => {\n timer = undefined;\n armedAt = undefined;\n wake();\n }, delay);\n }\n\n /** Pede uma volta do loop; se já há uma rodando, ela repete ao terminar. */\n function wake(): void {\n if (!started) return;\n if (loop !== undefined) {\n rerun = true;\n return;\n }\n disarm();\n loop = (async () => {\n do {\n rerun = false;\n await tick();\n } while (rerun && started);\n })().finally(() => {\n loop = undefined;\n });\n }\n\n /**\n * Filtro dos jobs que têm handler, ou `undefined` sem nenhum. Sem ele, os órfãos (plugin\n * desligado, job renomeado) seriam relidos do storage a cada volta, e o custo de cada disparo\n * cresceria com o lixo acumulado (#228). Como `Where` só combina campos com E, o filtro é o\n * produto `plugin × job`: um órfão só passa se outro plugin tiver handler com o mesmo nome de\n * job, e o `dispatch` o pula.\n */\n function withHandler(): Where<JobDocument> | undefined {\n if (handlers.size === 0) return undefined;\n const names = new Set<string>();\n for (const byJob of handlers.values()) for (const job of byJob.keys()) names.add(job);\n return { plugin: { in: [...handlers.keys()] }, job: { in: [...names] } };\n }\n\n async function tick(): Promise<void> {\n const now = Date.now();\n // Esta volta já reentrega o que a remoção não tirou do storage.\n retryAt = undefined;\n let next: number | undefined;\n try {\n await exclusive(() => dispatchDue(now));\n // Job sem handler não arma timer: espera o `on` do plugin, que acorda o loop.\n const filter = withHandler();\n const [upcoming] =\n filter === undefined\n ? []\n : await jobs.find({\n where: { ...filter, fireAt: { gt: now } },\n orderBy: 'fireAt',\n limit: 1,\n });\n next = upcoming?.fireAt;\n } catch (error) {\n onStorageError(error);\n next = Date.now() + retryMs;\n }\n if (retryAt !== undefined && (next === undefined || retryAt < next)) next = retryAt;\n if (started && !rerun && next !== undefined) arm(next);\n }\n\n /**\n * Despacha os vencidos com handler em ordem de `fireAt` até acabarem as vagas, lendo uma\n * página por vez. Os que estão em andamento não ocupam vaga e são pulados pelo `offset`, para\n * não travarem os de trás (no máximo `maxConcurrent` deles). Se um handler terminar no meio da varredura e o `offset` pular um\n * vencido, a volta extra que esse término pede (`wake`) o encontra.\n */\n async function dispatchDue(now: number): Promise<void> {\n backlog = false;\n const filter = withHandler();\n if (filter === undefined) return;\n for (let offset = 0; started; offset += DUE_PAGE_SIZE) {\n const page = await jobs.find({\n where: { ...filter, fireAt: { lte: now } },\n orderBy: 'fireAt',\n limit: DUE_PAGE_SIZE,\n offset,\n });\n for (const doc of page) {\n if (!started) return;\n if (inFlight.size >= maxConcurrent) {\n backlog = true;\n return;\n }\n dispatch(doc);\n }\n if (page.length < DUE_PAGE_SIZE) return;\n }\n }\n\n function dispatch(doc: StoredJob): void {\n if (inFlight.has(doc.id)) return;\n const registered = handlers.get(doc.plugin)?.get(doc.job);\n // Órfão que passou pelo filtro (ver `withHandler`): fica pendente no storage.\n if (registered === undefined) return;\n const done = run(doc, registered)\n // Abandonado no shutdown, o job não terminou: fica no storage para a próxima subida.\n .then(async (finished) => {\n if (finished) await jobs.delete(doc.id);\n return finished;\n })\n .then(\n (removed) => removed,\n (error: unknown) => {\n onStorageError(error);\n // O job ficou no storage: uma volta depois do retry o entrega de novo, mesmo sem outro\n // evento que acorde o loop. Uma volta em curso também respeita `retryAt` ao rearmar.\n const at = Date.now() + retryMs;\n retryAt = Math.min(retryAt ?? at, at);\n if (started && (armedAt === undefined || at < armedAt)) arm(at);\n return false;\n },\n )\n .then((removed) => {\n inFlight.delete(doc.id);\n // Vaga liberada com vencidos esperando, ou varredura em curso que pode ter pulado um\n // (o `offset` anda, e a remoção puxou a fila uma posição).\n if (removed && (backlog || loop !== undefined)) wake();\n });\n inFlight.set(doc.id, done);\n }\n\n function fail(doc: StoredJob, error: unknown, timedOut: boolean): void {\n onError({ plugin: doc.plugin, phase: 'scheduler', event: doc.job, error, timedOut });\n }\n\n /**\n * Roda o handler contra o prazo e resolve `false` só se ele foi abandonado no `stop`. Nunca\n * rejeita: toda falha já foi entregue ao `onError`. Estourado o prazo (ou abandonado), o\n * `signal` do job aborta (ADR 0033).\n */\n function run(doc: StoredJob, { handler, lifetime }: RegisteredHandler): Promise<boolean> {\n const deadline = new Deadline(lifetime);\n const job: JobContext = {\n get signal(): AbortSignal {\n return deadline.signal;\n },\n };\n let result: unknown;\n try {\n // O job sem tenant sai de qualquer escopo: o loop pode ter sido acordado no handler de um.\n result = tenants.run(doc.tenant, () => handler(doc.payload, job));\n } catch (error) {\n fail(doc, error, false);\n return Promise.resolve(true);\n }\n if (!isThenable(result)) return Promise.resolve(true);\n return new Promise<boolean>((resolve) => {\n let settled = false;\n const settle = (finished: boolean): void => {\n settled = true;\n clearTimeout(timeout);\n abandons.delete(doc.id);\n resolve(finished);\n };\n const timeout = setTimeout(() => {\n const error = new JobTimeoutError(doc.plugin, doc.job, jobTimeoutMs);\n settle(true);\n deadline.expire(error);\n fail(doc, error, true);\n }, jobTimeoutMs);\n abandons.set(doc.id, (reason) => {\n settle(false);\n deadline.expire(reason);\n });\n result.then(\n () => {\n if (!settled) settle(true);\n },\n (error: unknown) => {\n if (!settled) {\n settle(true);\n fail(doc, error, false);\n return;\n }\n // Rejeição depois do prazo: já reportado como timeout; o erro tardio vai só ao\n // `onLateError`. A recusa de um contexto expirado já foi logada (ADR 0033).\n if (error instanceof ContextExpiredError) return;\n onLateError({\n plugin: doc.plugin,\n phase: 'scheduler',\n event: doc.job,\n error,\n timedOut: false,\n });\n },\n );\n });\n }\n\n function forPlugin(plugin: string, lifetime?: Deadline): Scheduler {\n return {\n async at(when, job, payload = null) {\n const fireAt = toEpoch(when);\n assertJobName(job);\n assertJsonValue(payload, 'payload', new Set());\n const tenant = tenants.current;\n const id = await jobs.insert({\n plugin,\n job,\n fireAt,\n payload,\n ...(tenant !== undefined && { tenant }),\n });\n if (started) {\n if (loop !== undefined) rerun = true;\n else if (armedAt === undefined || fireAt < armedAt) arm(fireAt);\n }\n return id;\n },\n\n cancel(id) {\n return exclusive(async () => {\n // Já disparou: o handler está rodando e o job sai do storage quando ele terminar.\n if (inFlight.has(id)) return false;\n return (await jobs.delete({ id, plugin })) > 0;\n });\n },\n\n on(job, handler): Unsubscribe {\n assertJobName(job);\n if (typeof handler !== 'function') throw new TypeError(`Handler de \"${job}\" não é função`);\n let byJob = handlers.get(plugin);\n if (byJob === undefined) {\n byJob = new Map();\n handlers.set(plugin, byJob);\n }\n if (byJob.has(job)) throw new JobHandlerConflictError(plugin, job);\n const registered: RegisteredHandler = { handler, lifetime };\n byJob.set(job, registered);\n // Pode haver jobs vencidos esperando por este handler.\n wake();\n return () => {\n const current = handlers.get(plugin);\n if (current?.get(job) !== registered) return;\n current.delete(job);\n if (current.size === 0) handlers.delete(plugin);\n };\n },\n };\n }\n\n return {\n forPlugin,\n\n removePlugin(plugin) {\n handlers.delete(plugin);\n },\n\n start() {\n if (started) return;\n started = true;\n wake();\n },\n\n async stop(signal) {\n started = false;\n disarm();\n const abandon = (): void => {\n for (const fn of abandons.values()) fn(signal?.reason);\n };\n if (signal?.aborted) abandon();\n else signal?.addEventListener('abort', abandon, { once: true });\n await loop;\n // Um `at` pode ter rearmado enquanto o loop terminava; nada pode sobrar vivo.\n disarm();\n await Promise.all(inFlight.values());\n },\n };\n}\n","import type { ServiceAccess, ServiceName, Services } from './types.ts';\n\n/** Serviço registrado com o plugin que o proveu. */\nexport interface ProvidedService {\n readonly plugin: string;\n readonly name: string;\n readonly service: unknown;\n}\n\n/** `get` de um serviço que nenhum plugin carregado provê. */\nexport class ServiceNotFoundError extends Error {\n override readonly name = 'ServiceNotFoundError';\n readonly service: string;\n /** Plugin que pediu o serviço. */\n readonly requestedBy: string;\n\n constructor(service: string, requestedBy: string) {\n super(\n `Serviço \"${service}\" não encontrado (pedido pelo plugin \"${requestedBy}\"): nenhum ` +\n `plugin carregado o provê. Declare em \"${requestedBy}\" o \\`dependsOn\\` do plugin que ` +\n `provê \"${service}\", para que ele carregue (e chame \\`provide\\`) antes.`,\n );\n this.service = service;\n this.requestedBy = requestedBy;\n }\n}\n\n/** Dois `provide` com o mesmo nome. Lançado no `setup`, isto é, no boot. */\nexport class ServiceConflictError extends Error {\n override readonly name = 'ServiceConflictError';\n readonly service: string;\n readonly existing: string;\n readonly incoming: string;\n\n constructor(service: string, existing: string, incoming: string) {\n super(\n existing === incoming\n ? `Serviço \"${service}\" provido duas vezes pelo plugin \"${incoming}\". Cada serviço é ` +\n `provido uma vez por setup; para trocar a implementação, recarregue o plugin.`\n : `Conflito de serviço \"${service}\": o plugin \"${incoming}\" tenta prover um serviço ` +\n `que o plugin \"${existing}\" já provê. Desabilite um dos dois ou renomeie o serviço.`,\n );\n this.service = service;\n this.existing = existing;\n this.incoming = incoming;\n }\n}\n\nexport interface ServiceRegistry {\n /** O `ctx.services` do plugin: `provide` atribui a ele, e os erros o citam. */\n forPlugin(plugin: string): ServiceAccess;\n /** Remove os serviços que o plugin proveu (teardown e reload). */\n removePlugin(plugin: string): void;\n list(): ProvidedService[];\n}\n\n/** Um registry por bot: nada global, então dois bots no mesmo processo não se enxergam. */\nexport function createServiceRegistry(): ServiceRegistry {\n // Chave string: em runtime o core não conhece os nomes, que só existem no type-level.\n const byName = new Map<string, ProvidedService>();\n\n return {\n forPlugin(plugin) {\n return {\n provide<K extends ServiceName>(name: K, service: Services[K]): void {\n const existing = byName.get(name);\n // Re-prover é erro mesmo no próprio plugin: quem já fez `get` guardaria a instância\n // antiga sem saber. Trocar a implementação passa por teardown + setup (reload).\n if (existing) throw new ServiceConflictError(name, existing.plugin, plugin);\n byName.set(name, { plugin, name, service });\n },\n\n get<K extends ServiceName>(name: K): Services[K] {\n const entry = byName.get(name);\n if (!entry) throw new ServiceNotFoundError(name, plugin);\n // O tipo foi garantido no `provide`, que só aceita `Services[K]` para o nome K.\n return entry.service as Services[K];\n },\n\n has(name) {\n return byName.has(name);\n },\n };\n },\n\n removePlugin(plugin) {\n for (const [name, entry] of byName) {\n if (entry.plugin === plugin) byName.delete(name);\n }\n },\n\n list() {\n return [...byName.values()];\n },\n };\n}\n","// Adapter em memória do StoragePort: referência executável da semântica do contrato, usado em\n// testes e no M1-16. Guarda tudo como texto JSON — como os adapters reais —, então o que entra\n// e o que sai são sempre cópias, sem aliasing com objetos do plugin. Cada chamada de\n// `createMemoryStorage` tem dados próprios (nenhum estado de módulo).\n\nimport { randomUUID } from 'node:crypto';\nimport { StorageClosedError } from './errors.ts';\nimport {\n type NormalizedCondition,\n type NormalizedSort,\n normalizeDocument,\n normalizeIndexes,\n normalizeQuery,\n normalizeWhere,\n} from './query.ts';\nimport type {\n AuthKeyData,\n AuthStateStore,\n Collection,\n FindQuery,\n JsonObject,\n JsonValue,\n KeyValueStore,\n Patch,\n PluginStorage,\n Scalar,\n StoragePort,\n Target,\n WithId,\n} from './types.ts';\n\n// id → documento em JSON. A ordem de inserção do Map é a ordem de desempate do contrato, e\n// `Map.set` numa chave existente (update) não muda a posição.\ntype Documents = Map<string, string>;\n\ninterface NamespaceData {\n readonly kv: Map<string, string>;\n readonly collections: Map<string, Documents>;\n}\n\ninterface SessionData {\n creds: string | undefined;\n readonly keys: Map<string, Map<string, string>>;\n}\n\ninterface Row {\n readonly id: string;\n readonly doc: JsonObject;\n}\n\nfunction serialize(value: unknown): string {\n const text = JSON.stringify(value);\n if (text === undefined) throw new TypeError('Valor não serializável em JSON.');\n return text;\n}\n\nfunction parse<T>(text: string): T {\n return JSON.parse(text) as T;\n}\n\nfunction fieldValue(row: Row, field: string): JsonValue {\n if (field === 'id') return row.id;\n // Campo ausente vale null, igual ao `json_extract`/`->>` dos adapters SQL.\n return Object.hasOwn(row.doc, field) ? (row.doc[field] as JsonValue) : null;\n}\n\n// Igualdade estrita de tipo e valor: o adapter SQLite precisa conferir `json_type`, porque\n// `json_extract` devolve `true` como 1.\nfunction equals(value: JsonValue, operand: Scalar): boolean {\n if (operand === null) return value === null;\n return typeof value === typeof operand && value === operand;\n}\n\n// Ordem de code point (= ordem de bytes UTF-8, a do SQLite BINARY e do Postgres COLLATE \"C\").\n// O `<` do JS compara unidades UTF-16 e erra quando um lado é surrogate.\nfunction compareStrings(a: string, b: string): number {\n if (a === b) return 0;\n const length = Math.min(a.length, b.length);\n for (let i = 0; i < length; i++) {\n if (a.charCodeAt(i) !== b.charCodeAt(i)) {\n return (a.codePointAt(i) as number) - (b.codePointAt(i) as number);\n }\n }\n return a.length - b.length;\n}\n\nfunction compareOrdered(value: JsonValue, operand: string | number): number | undefined {\n if (typeof value === 'number' && typeof operand === 'number') return value - operand;\n if (typeof value === 'string' && typeof operand === 'string') {\n return compareStrings(value, operand);\n }\n return undefined;\n}\n\nfunction matches(row: Row, conditions: readonly NormalizedCondition[]): boolean {\n return conditions.every((condition) => {\n const value = fieldValue(row, condition.field);\n switch (condition.op) {\n case 'eq':\n return equals(value, condition.value);\n case 'ne':\n return !equals(value, condition.value);\n case 'in':\n return condition.value.some((operand) => equals(value, operand));\n default: {\n const diff = compareOrdered(value, condition.value);\n if (diff === undefined) return false;\n if (condition.op === 'gt') return diff > 0;\n if (condition.op === 'gte') return diff >= 0;\n if (condition.op === 'lt') return diff < 0;\n return diff <= 0;\n }\n }\n });\n}\n\n// null/ausente < booleano < número < texto < array/objeto (iguais entre si).\nfunction typeRank(value: JsonValue): number {\n if (value === null) return 0;\n if (typeof value === 'boolean') return 1;\n if (typeof value === 'number') return 2;\n if (typeof value === 'string') return 3;\n return 4;\n}\n\nfunction compareValues(a: JsonValue, b: JsonValue): number {\n const rank = typeRank(a) - typeRank(b);\n if (rank !== 0) return rank;\n if (typeof a === 'boolean') return Number(a) - Number(b);\n if (typeof a === 'number') return a - (b as number);\n if (typeof a === 'string') return compareStrings(a, b as string);\n return 0;\n}\n\nfunction sortRows(rows: Row[], sorts: readonly NormalizedSort[]): Row[] {\n if (sorts.length === 0) return rows;\n // `Array.prototype.sort` é estável: empates mantêm a ordem de inserção.\n return rows.sort((a, b) => {\n for (const { field, direction } of sorts) {\n const diff = compareValues(fieldValue(a, field), fieldValue(b, field));\n if (diff !== 0) return direction === 'asc' ? diff : -diff;\n }\n return 0;\n });\n}\n\n/** Cria um StoragePort em memória, com dados próprios e descartados no `close()`. */\nexport function createMemoryStorage(): StoragePort {\n const namespaces = new Map<string, NamespaceData>();\n const sessions = new Map<string, SessionData>();\n let closed = false;\n\n function ensureOpen(): void {\n if (closed) throw new StorageClosedError();\n }\n\n function namespaceData(namespace: string): NamespaceData {\n let data = namespaces.get(namespace);\n if (data === undefined) {\n data = { kv: new Map(), collections: new Map() };\n namespaces.set(namespace, data);\n }\n return data;\n }\n\n function documents(namespace: string, name: string): Documents {\n const { collections } = namespaceData(namespace);\n let docs = collections.get(name);\n if (docs === undefined) {\n docs = new Map();\n collections.set(name, docs);\n }\n return docs;\n }\n\n function sessionData(session: string): SessionData {\n let data = sessions.get(session);\n if (data === undefined) {\n data = { creds: undefined, keys: new Map() };\n sessions.set(session, data);\n }\n return data;\n }\n\n function createKv(namespace: string): KeyValueStore {\n return {\n async get<T extends JsonValue = JsonValue>(key: string): Promise<T | undefined> {\n ensureOpen();\n const text = namespaceData(namespace).kv.get(key);\n return text === undefined ? undefined : parse<T>(text);\n },\n async set(key: string, value: JsonValue): Promise<void> {\n ensureOpen();\n namespaceData(namespace).kv.set(key, serialize(value));\n },\n async delete(key: string): Promise<boolean> {\n ensureOpen();\n return namespaceData(namespace).kv.delete(key);\n },\n };\n }\n\n function createCollection<T extends { readonly [key: string]: JsonValue }>(\n namespace: string,\n name: string,\n ): Collection<T> {\n function rows(): Row[] {\n return [...documents(namespace, name)].map(([id, text]) => ({ id, doc: parse(text) }));\n }\n\n function targetRows(target: Target<T>): Row[] {\n if (typeof target === 'string') {\n const text = documents(namespace, name).get(target);\n return text === undefined ? [] : [{ id: target, doc: parse(text) }];\n }\n const conditions = normalizeWhere(target);\n return rows().filter((row) => matches(row, conditions));\n }\n\n return {\n async insert(document: T): Promise<string> {\n ensureOpen();\n const text = serialize(normalizeDocument(document));\n const id = randomUUID();\n documents(namespace, name).set(id, text);\n return id;\n },\n async get(id: string): Promise<WithId<T> | undefined> {\n ensureOpen();\n const text = documents(namespace, name).get(id);\n return text === undefined ? undefined : { ...parse<T>(text), id };\n },\n async find(query?: FindQuery<T>): Promise<WithId<T>[]> {\n ensureOpen();\n const { where, orderBy, limit, offset } = normalizeQuery(query);\n const found = sortRows(\n rows().filter((row) => matches(row, where)),\n orderBy,\n );\n const end = limit === undefined ? undefined : offset + limit;\n return found.slice(offset, end).map((row) => ({ ...(row.doc as T), id: row.id }));\n },\n async update(target: Target<T>, patch: Patch<T>): Promise<number> {\n ensureOpen();\n const changes = normalizeDocument(patch);\n const docs = documents(namespace, name);\n const targets = targetRows(target);\n for (const row of targets) docs.set(row.id, serialize({ ...row.doc, ...changes }));\n return targets.length;\n },\n async delete(target: Target<T>): Promise<number> {\n ensureOpen();\n const docs = documents(namespace, name);\n const targets = targetRows(target);\n for (const row of targets) docs.delete(row.id);\n return targets.length;\n },\n };\n }\n\n function createPluginStorage(namespace: string): PluginStorage {\n return {\n kv: createKv(namespace),\n collection<T extends { readonly [key: string]: JsonValue }>(\n name: string,\n options?: Parameters<PluginStorage['collection']>[1],\n ): Collection<T> {\n // Índice não muda o resultado em memória; validar mantém o erro igual ao dos outros\n // adapters, que criam o índice de verdade.\n normalizeIndexes(options);\n return createCollection<T>(namespace, name);\n },\n };\n }\n\n function createAuthState(session: string): AuthStateStore {\n return {\n async getCreds(): Promise<JsonValue | undefined> {\n ensureOpen();\n const text = sessionData(session).creds;\n return text === undefined ? undefined : parse(text);\n },\n async setCreds(creds: JsonValue): Promise<void> {\n ensureOpen();\n sessionData(session).creds = serialize(creds);\n },\n async getKeys(type: string, ids: readonly string[]): Promise<Record<string, JsonValue>> {\n ensureOpen();\n const stored = sessionData(session).keys.get(type);\n const result: Record<string, JsonValue> = {};\n if (stored === undefined) return result;\n for (const id of ids) {\n const text = stored.get(id);\n if (text !== undefined) result[id] = parse(text);\n }\n return result;\n },\n async setKeys(data: AuthKeyData): Promise<void> {\n ensureOpen();\n // Serializa o lote inteiro antes de aplicar: um valor inválido no meio não deixa o\n // lote pela metade (o equivalente da transação dos adapters SQL).\n const batch = Object.entries(data).map(\n ([type, entries]) =>\n [\n type,\n Object.entries(entries).map(\n ([id, value]) => [id, value === null ? null : serialize(value)] as const,\n ),\n ] as const,\n );\n const { keys } = sessionData(session);\n for (const [type, entries] of batch) {\n let stored = keys.get(type);\n if (stored === undefined) {\n stored = new Map();\n keys.set(type, stored);\n }\n for (const [id, text] of entries) {\n if (text === null) stored.delete(id);\n else stored.set(id, text);\n }\n }\n },\n async clear(): Promise<void> {\n ensureOpen();\n sessions.delete(session);\n },\n };\n }\n\n return {\n forNamespace(namespace: string): PluginStorage {\n return createPluginStorage(namespace);\n },\n authState(session: string): AuthStateStore {\n return createAuthState(session);\n },\n async close(): Promise<void> {\n closed = true;\n namespaces.clear();\n sessions.clear();\n },\n };\n}\n","// Fábrica do escape hatch `ctx.unsafe` (M1-15, ADR 0011; `raw` no ADR 0066).\n\nimport type { Logger } from '#logger/types.ts';\nimport type { Message } from '#message/types.ts';\nimport type { PluginManifest } from '#plugin/types.ts';\nimport type { Interaction, Transport } from '#transport/types.ts';\nimport type { Unsafe } from './types.ts';\n\nexport interface UnsafeAccessOptions {\n /**\n * Só `name` (vai no aviso), `native` (lido a cada acesso) e `raw` (consultado a cada chamada)\n * são usados.\n */\n readonly transport: Pick<Transport, 'name' | 'native' | 'raw'>;\n readonly log: Logger;\n /**\n * A interação de onde o kernel montou a mensagem (clique ou comando nativo). O transport nunca\n * viu essa `Message`, então o `raw` pergunta a ele pela interação. Ausente: nenhuma mensagem\n * vem de interação.\n */\n readonly interactionOf?: (message: Message) => Interaction | undefined;\n}\n\n/** Fábrica de `Unsafe` de um bot; guarda quais plugins já foram avisados. */\nexport interface UnsafeAccess {\n /**\n * `Unsafe` do plugin. Pode ser chamado várias vezes para o mesmo plugin (ex.: um por\n * contexto de mensagem): o aviso continua saindo uma vez só por plugin.\n */\n forPlugin(manifest: Pick<PluginManifest, 'name' | 'transports'>): Unsafe;\n}\n\n/** O que o plugin acessou; cada um avisa uma vez, para o log medir os dois usos (ADR 0011). */\ntype Accessor = 'native' | 'raw';\n\n/**\n * Uma por instância de bot. O registro de \"já avisou\" mora aqui, e não em cada `Unsafe` nem em\n * escopo de módulo: assim o aviso sai uma vez por plugin mesmo com vários `Unsafe` do mesmo\n * plugin, e dois bots no mesmo processo não silenciam um ao outro.\n */\nexport function createUnsafeAccess(options: UnsafeAccessOptions): UnsafeAccess {\n const { transport, log, interactionOf } = options;\n const warned = new Set<string>();\n\n function warnOnce(manifest: Pick<PluginManifest, 'name' | 'transports'>, what: Accessor): void {\n const id = `${what}:${manifest.name}`;\n if (warned.has(id)) return;\n warned.add(id);\n const fields = { plugin: manifest.name, transport: transport.name };\n const access = what === 'native' ? 'ctx.unsafe.native' : 'ctx.unsafe.raw()';\n // Sem `transports` no manifesto o plugin se diz portável, mas ao ler o objeto nativo ele\n // passa a depender deste transport (ADR 0011). Não bloqueamos: o aviso deixa isso visível.\n if (manifest.transports === undefined) {\n log.warn(\n `plugin \"${manifest.name}\" acessou ${access} sem declarar transports no manifesto; ` +\n `ele fica preso ao transport \"${transport.name}\" (declare transports: ['${transport.name}'])`,\n fields,\n );\n return;\n }\n log.warn(\n `plugin \"${manifest.name}\" acessou ${access} do transport \"${transport.name}\"`,\n fields,\n );\n }\n\n return {\n forPlugin(manifest) {\n return {\n // Getter, não valor copiado: o objeto nativo pode ser trocado a cada reconexão.\n get native(): unknown {\n warnOnce(manifest, 'native');\n return transport.native;\n },\n raw(message) {\n warnOnce(manifest, 'raw');\n // Só aqui, sob demanda: o caminho da mensagem não paga nada por o plugin poder pedir.\n return transport.raw?.(interactionOf?.(message) ?? message);\n },\n };\n },\n };\n}\n","import type { MessageAction } from '#actions/actions.ts';\nimport type { Message } from '#message/types.ts';\nimport type { MessageText } from '#text/format.ts';\nimport type { MessageKey, OutgoingAction, OutgoingContent } from '#transport/types.ts';\nimport { captionFields, textContent } from './text.ts';\nimport type {\n OutboundSendOptions,\n Reply,\n ReplyOptions,\n ReplyTextOptions,\n Sender,\n} from './types.ts';\n\n/** Texto e botões que vão ao transport, depois de o kernel resolver as ações (ADR 0062). */\nexport interface PreparedActions {\n /** O texto, com o menu numerado no fim quando o transport não leva os botões. */\n readonly text: MessageText;\n readonly actions?: readonly OutgoingAction[];\n}\n\n/** Resolve as ações de uma resposta; lança `TypeError` com uma ação inválida. */\nexport type PrepareActions = (\n text: MessageText,\n actions: readonly MessageAction[],\n) => PreparedActions;\n\nexport interface CreateReplyOptions {\n /**\n * Cita a mensagem original. Padrão: `true`. Quem monta o contexto passa `false` quando o\n * transport não tem a capability `quoted`, para a resposta não falhar com `UnsupportedError`.\n */\n readonly quote?: boolean;\n /** Quem resolve `actions`. Sem ele, uma resposta com ações rejeita com `TypeError`. */\n readonly actions?: PrepareActions;\n}\n\n/**\n * Monta o `ctx.reply` de uma mensagem: envia no chat dela, citando-a, com prioridade `high`,\n * pelo `sender` (a fila de saída). O plugin não vê a fila — só chama `reply`.\n */\nexport function createReply(\n sender: Sender,\n message: Message,\n options: CreateReplyOptions = {},\n): Reply {\n const chatId = message.chat.id;\n const quoted = options.quote === false ? undefined : message;\n\n const send = (\n content: OutgoingContent,\n replyOptions: ReplyOptions = {},\n actions?: readonly OutgoingAction[],\n ): Promise<MessageKey> => {\n const sendOptions: OutboundSendOptions = {\n priority: replyOptions.priority ?? 'high',\n ...(quoted && { quoted }),\n ...(replyOptions.mentions && { mentions: replyOptions.mentions }),\n ...(actions && actions.length > 0 && { actions }),\n };\n return sender.send(chatId, content, sendOptions);\n };\n\n const sendText = (text: MessageText, o?: ReplyTextOptions): Promise<MessageKey> => {\n if (o?.actions === undefined || o.actions.length === 0) return send(textContent(text), o);\n let prepared: PreparedActions;\n try {\n if (options.actions === undefined) {\n throw new TypeError('reply: ações só no contexto de mensagem do bot');\n }\n prepared = options.actions(text, o.actions);\n } catch (error) {\n return Promise.reject(error);\n }\n return send(textContent(prepared.text), o, prepared.actions);\n };\n\n const shortcuts: Pick<Reply, keyof Reply> = {\n text: sendText,\n image: (media, o = {}) =>\n send({ type: 'image', media, ...captionFields(o.caption), ...pick(o, 'mimetype') }, o),\n video: (media, o = {}) =>\n send({ type: 'video', media, ...captionFields(o.caption), ...pick(o, 'mimetype') }, o),\n audio: (media, o = {}) => send({ type: 'audio', media, ...pick(o, 'mimetype') }, o),\n voice: (media, o = {}) => send({ type: 'voice', media, ...pick(o, 'mimetype') }, o),\n sticker: (media, o) => send({ type: 'sticker', media }, o),\n document: (media, o) =>\n send(\n {\n type: 'document',\n media,\n fileName: o.fileName,\n mimetype: o.mimetype,\n ...captionFields(o.caption),\n },\n o,\n ),\n album: (items, o = {}) => send({ type: 'album', items, ...captionFields(o.caption) }, o),\n poll: (name, choices, o = {}) =>\n send({ type: 'poll', name, options: choices, ...pick(o, 'multiple') }, o),\n };\n return Object.assign((text: MessageText, o?: ReplyTextOptions) => sendText(text, o), shortcuts);\n}\n\n/** `{ [key]: valor }` só quando definido, para não mandar `undefined` explícito ao transport. */\nfunction pick<T extends object, K extends keyof T>(source: T, key: K): Partial<Pick<T, K>> {\n const value = source[key];\n return value === undefined ? {} : ({ [key]: value } as Partial<Pick<T, K>>);\n}\n","// Contexto de mensagem do kernel (M1-16): o objeto que middlewares, roteador e listeners\n// recebem. `reply` e `log` são preguiçosos — a maioria das mensagens não responde nem loga, e o\n// caminho quente (§7 do plano) não deve alocar o que ninguém vai usar.\n\nimport type { BotMessageContext } from '#context.ts';\nimport type { ExpectReply, ExpectReplyOptions } from '#conversations/conversations.ts';\nimport { ContextExpiredError, DEADLINE, type Deadline, deadlineOf } from '#deadline.ts';\nimport type { MessageListenerFields } from '#events/types.ts';\nimport type { LogFields, Logger } from '#logger/types.ts';\nimport type { Message } from '#message/types.ts';\nimport type { SanitizedContext, SanitizedFields } from '#middleware/sanitize.ts';\nimport { createReply, type PrepareActions } from '#outbound/reply.ts';\nimport type { Outbound, Reply } from '#outbound/types.ts';\nimport type { MessageText, MessageValues } from '#plugin/messages.ts';\nimport type { JsonValue } from '#storage/types.ts';\nimport type { MessageKey } from '#transport/types.ts';\n\n/** O que o contexto precisa do bot; um objeto por bot, compartilhado por todas as mensagens. */\nexport interface MessageContextDeps {\n readonly sender: Outbound;\n /** Responder citando: só se o transport tem a capability `quoted`. */\n readonly quote: boolean;\n /** O transport tem a capability `reactions`; sem ela, `react` vira no-op (ADR 0093). */\n readonly reactions: boolean;\n /** Logger raiz; o contexto cria o filho com `chatId` sob demanda. */\n readonly log: () => Logger;\n /**\n * Resolve as ações do `reply` (ADR 0062) em nome do plugin dono do contexto, ou de ninguém\n * (`null`) no contexto do kernel, que os middlewares veem.\n */\n readonly actions?: (owner: string | null, message: Message) => PrepareActions;\n}\n\n// Chave simbólica, não campo `#privado`: o roteador e os listeners recebem objetos derivados por\n// `Object.create(ctx)`, e campo privado não é alcançável pela cadeia de protótipos.\nconst STATE: unique symbol = Symbol('bridger.messageContext');\n\ninterface State {\n readonly deps: MessageContextDeps;\n reply: Reply | undefined;\n log: Logger | undefined;\n}\n\n/** O contexto concreto: o de mensagem do bot com o resultado do `sanitize`. */\nexport interface KernelMessageContext extends BotMessageContext, SanitizedContext {\n text: string | null;\n}\n\n/** Cria o contexto de uma mensagem; `reply` e `log` só existem quando lidos. */\nexport function createMessageContext(\n message: Message,\n deps: MessageContextDeps,\n): KernelMessageContext {\n return new MessageContextImpl(message, deps);\n}\n\nclass MessageContextImpl implements KernelMessageContext {\n readonly message: Message;\n text: string | null;\n /** Preenchido pelo middleware `sanitize`; declarado para manter a forma do objeto estável. */\n sanitized: SanitizedFields | undefined = undefined;\n readonly [STATE]: State;\n\n constructor(message: Message, deps: MessageContextDeps) {\n this.message = message;\n this.text = message.text;\n this[STATE] = { deps, reply: undefined, log: undefined };\n }\n\n get reply(): Reply {\n const state = this[STATE];\n state.reply ??= replyFor(state.deps, this.message, null);\n return state.reply;\n }\n\n get log(): Logger {\n const state = this[STATE];\n state.log ??= state.deps.log().child({ chatId: this.message.chat.id });\n return state.log;\n }\n\n react(emoji: string | null): Promise<void> {\n const { deps } = this[STATE];\n // Reação aqui é enfeite de andamento: sem a capability, não falha. Quem precisa saber que\n // não saiu usa o `ctx.send.react`, que continua estrito (ADR 0093).\n if (!deps.reactions) {\n this.log.debug('react ignorado: o transport não tem a capability \"reactions\"', { emoji });\n return Promise.resolve();\n }\n // Prioridade do `reply`: a reação responde a quem escreveu, como ele.\n return deps.sender.react(this.message.key, emoji, { priority: 'high' });\n }\n}\n\nfunction replyFor(deps: MessageContextDeps, message: Message, owner: string | null): Reply {\n return createReply(deps.sender, message, {\n quote: deps.quote,\n ...(deps.actions && { actions: deps.actions(owner, message) }),\n });\n}\n\n/**\n * O `reply` da mensagem em nome do plugin, para as ações de passo apontarem para os passos dele.\n * `undefined` fora do contexto do kernel (roteador usado solto).\n */\nfunction pluginReply(ctx: object, plugin: string): Reply | undefined {\n // O estado do contexto do kernel é alcançado pela cadeia de protótipos das visões.\n const state = (ctx as { readonly [STATE]?: State })[STATE];\n if (state === undefined) return undefined;\n return replyFor(state.deps, (ctx as { readonly message: Message }).message, plugin);\n}\n\n/**\n * Chave dos extras que o bot passa ao barramento nos eventos de mensagem. O barramento copia os\n * extras com `Object.assign`, que leria (e criaria) `reply` e `log`; com o contexto inteiro numa\n * chave só, cada listener resolve o que usar.\n */\nexport const KERNEL_CONTEXT: unique symbol = Symbol('bridger.kernelContext');\n\nexport interface WithKernelContext {\n readonly [KERNEL_CONTEXT]: KernelMessageContext;\n}\n\n/** Extras de `bus.emit` para um evento de mensagem. */\nexport function messageExtras(ctx: KernelMessageContext): WithKernelContext {\n return { [KERNEL_CONTEXT]: ctx };\n}\n\n/**\n * Descritores do `log` de um plugin: filho do logger do plugin com o `chatId` da mensagem, criado\n * no primeiro acesso e fixado no próprio objeto. Calculados uma vez por plugin.\n */\nfunction pluginLogDescriptor(pluginLog: Logger): PropertyDescriptor {\n return {\n configurable: true,\n get(this: { readonly message: Message }): Logger {\n const log = pluginLog.child({ chatId: this.message.chat.id });\n Object.defineProperty(this, 'log', { value: log });\n return log;\n },\n };\n}\n\nconst REPLY_METHODS = [\n 'text',\n 'image',\n 'video',\n 'audio',\n 'voice',\n 'sticker',\n 'document',\n 'album',\n 'poll',\n] as const satisfies readonly (keyof Reply)[];\n\n/** Recusa uma operação de um contexto expirado: loga e devolve a rejeição. */\ntype Refuse = (operation: string) => Promise<never>;\n\n/**\n * `reply` que confere o prazo a cada chamada — não só na leitura de `ctx.reply`: quem guardou a\n * função antes do prazo (`const r = ctx.reply`) também é recusado depois dele. No prazo, o envio\n * pausa o relógio até assentar (ADR 0047).\n */\nfunction expiringReply(reply: Reply, deadline: Deadline, refuse: Refuse): Reply {\n const guard =\n <A extends unknown[]>(operation: string, send: (...args: A) => Promise<MessageKey>) =>\n (...args: A): Promise<MessageKey> =>\n deadline.expired ? refuse(operation) : deadline.hold(send(...args));\n type AnySend = (...args: unknown[]) => Promise<MessageKey>;\n const shortcuts = Object.fromEntries(\n REPLY_METHODS.map((method) => [method, guard(`reply.${method}`, reply[method] as AnySend)]),\n ) as unknown as Pick<Reply, (typeof REPLY_METHODS)[number]>;\n return Object.assign(guard('reply', reply), shortcuts);\n}\n\ninterface ExpiringView {\n readonly [DEADLINE]?: Deadline;\n readonly log: Logger;\n}\n\ntype Scope<V> = (view: V) => { readonly label: string; readonly fields: LogFields };\n\n/** Recusa (com `ContextExpiredError` e uma linha de log) do que a `view` faz depois do prazo. */\nfunction refuser<V extends ExpiringView>(\n plugin: string,\n view: V,\n deadline: Deadline,\n scope: Scope<V>,\n): Refuse {\n return (operation) => {\n const { label, fields } = scope(view);\n const error = new ContextExpiredError(plugin, operation, label, deadline.reason);\n view.log.warn(`${operation} recusado: ${label} já expirou`, {\n ...fields,\n operation,\n err: error,\n });\n return Promise.reject(error);\n };\n}\n\n/**\n * Descritor do `reply` de uma execução com prazo (comando ou listener): o `reply` de `base`,\n * recusado com `ContextExpiredError` (e uma linha de log) depois que o `Deadline` expira — no\n * prazo, ou no descarte do plugin.\n * Criado no primeiro acesso e fixado no próprio objeto, como o `log`.\n */\nfunction expiringReplyDescriptor<V extends ExpiringView>(\n plugin: string,\n base: (view: V) => Reply | undefined,\n scope: Scope<V>,\n): PropertyDescriptor {\n return {\n configurable: true,\n get(this: V): Reply | undefined {\n const reply = base(this);\n const deadline = deadlineOf(this);\n if (reply === undefined || deadline === undefined) return reply;\n const guarded = expiringReply(reply, deadline, refuser(plugin, this, deadline, scope));\n Object.defineProperty(this, 'reply', { value: guarded });\n return guarded;\n },\n };\n}\n\ntype React = BotMessageContext['react'];\n\n/**\n * Descritor do `react` de uma execução com prazo: recusado depois dele e pausando o relógio no\n * prazo, como o `reply`.\n */\nfunction expiringReactDescriptor<V extends ExpiringView>(\n plugin: string,\n base: (view: V) => Pick<BotMessageContext, 'react'> | undefined,\n scope: Scope<V>,\n): PropertyDescriptor {\n return {\n configurable: true,\n get(this: V): React | undefined {\n const target = base(this);\n const deadline = deadlineOf(this);\n if (target === undefined || deadline === undefined) return target?.react;\n const refuse = refuser(plugin, this, deadline, scope);\n const react: React = (emoji) =>\n deadline.expired ? refuse('react') : deadline.hold(target.react(emoji));\n Object.defineProperty(this, 'react', { value: react });\n return react;\n },\n };\n}\n\n/** Registra uma espera em nome do plugin; o bot a liga ao registro de conversas (ADR 0060). */\nexport type PluginExpect = (message: Message, step: string, options?: ExpectReplyOptions) => void;\n\n/**\n * Descritor do `expectReply` de uma execução com prazo: a espera vale para o chat e o remetente\n * da mensagem, e é recusada (com `ContextExpiredError` e uma linha de log) depois do prazo, como\n * o `reply` — senão um handler que estourou registraria uma conversa que ninguém pediu.\n */\nfunction expectReplyDescriptor<V extends ExpiringView & { readonly message: Message }>(\n plugin: string,\n expect: PluginExpect,\n scope: Scope<V>,\n): PropertyDescriptor {\n return {\n configurable: true,\n get(this: V): ExpectReply {\n const deadline = deadlineOf(this);\n const expectReply: ExpectReply = (step, options) => {\n if (deadline?.expired) {\n const { label, fields } = scope(this);\n const error = new ContextExpiredError(plugin, 'expectReply', label, deadline.reason);\n this.log.warn(`expectReply recusado: ${label} já expirou`, {\n ...fields,\n operation: 'expectReply',\n err: error,\n });\n throw error;\n }\n expect(this.message, step, options);\n };\n Object.defineProperty(this, 'expectReply', { value: expectReply });\n return expectReply;\n },\n };\n}\n\nconst signalDescriptor: PropertyDescriptor = {\n get(this: ExpiringView): AbortSignal {\n return (deadlineOf(this) as Deadline).signal;\n },\n};\n\nexport interface CommandViews {\n /**\n * Contexto do `run` e do `onReject`: `log` do plugin, `signal` e `reply` presos ao `deadline`\n * da execução.\n */\n run<C extends object>(ctx: C, deadline: Deadline): C;\n}\n\n/** Texto das `messages` do plugin para o chat de uma mensagem (ADR 0092). */\nexport type PluginText = (message: Message, key: string, values?: MessageValues) => string;\n\n/**\n * Descritor do `t`: a função presa à mensagem da visão, criada no primeiro acesso e fixada, para\n * `({ t }) => ...` funcionar desestruturado.\n */\nfunction textDescriptor(text: PluginText): PropertyDescriptor {\n return {\n configurable: true,\n get(this: { readonly message: Message }): MessageText {\n const { message } = this;\n const t: MessageText = (key, values) => text(message, key, values);\n Object.defineProperty(this, 't', { value: t });\n return t;\n },\n };\n}\n\n/**\n * Descritores comuns às execuções que respondem a uma mensagem (comando e passo): `log` e `t` do\n * plugin, `signal`, e `reply`, `react` e `expectReply` presos ao prazo.\n */\nfunction executionDescriptors<V extends ExpiringView & { readonly message: Message }>(\n plugin: string,\n pluginLog: Logger,\n expect: PluginExpect,\n text: PluginText,\n scope: Scope<V>,\n): PropertyDescriptorMap {\n return {\n log: pluginLogDescriptor(pluginLog),\n t: textDescriptor(text),\n signal: signalDescriptor,\n reply: expiringReplyDescriptor<V>(\n plugin,\n // O `reply` em nome do plugin ou, com o roteador solto, o do contexto recebido.\n (view) =>\n pluginReply(view, plugin) ??\n (Object.getPrototypeOf(view) as { readonly reply?: Reply }).reply,\n scope,\n ),\n react: expiringReactDescriptor<V>(\n plugin,\n (view) => {\n const base = Object.getPrototypeOf(view) as Partial<Pick<BotMessageContext, 'react'>>;\n return base.react === undefined ? undefined : (base as Pick<BotMessageContext, 'react'>);\n },\n scope,\n ),\n expectReply: expectReplyDescriptor<V>(plugin, expect, scope),\n };\n}\n\n/** Deriva os contextos de comando de um plugin. */\nexport function commandViewFactory(\n plugin: string,\n pluginLog: Logger,\n expect: PluginExpect,\n text: PluginText,\n): CommandViews {\n type View = ExpiringView & { readonly command: string; readonly message: Message };\n const scope: Scope<View> = (view) => ({\n label: `comando \"${view.command}\"`,\n fields: { command: view.command },\n });\n const runDescriptors = executionDescriptors<View>(plugin, pluginLog, expect, text, scope);\n return {\n run(ctx, deadline) {\n const view = Object.create(ctx, runDescriptors) as { [DEADLINE]?: Deadline };\n view[DEADLINE] = deadline;\n return view as typeof ctx;\n },\n };\n}\n\n/**\n * Deriva, para os passos de conversa de um plugin, o contexto com `step`, `data` e os campos de\n * execução do comando (`log`, `signal`, `reply`, `react`, `expectReply`).\n */\nexport function stepViewFactory(\n plugin: string,\n pluginLog: Logger,\n expect: PluginExpect,\n text: PluginText,\n): <C extends object>(ctx: C, deadline: Deadline, step: string, data: JsonValue) => C {\n type View = ExpiringView & { readonly step: string; readonly message: Message };\n const scope: Scope<View> = (view) => ({\n label: `passo \"${view.step}\"`,\n fields: { step: view.step },\n });\n const descriptors = executionDescriptors<View>(plugin, pluginLog, expect, text, scope);\n return (ctx, deadline, step, data) => {\n const view = Object.create(ctx, descriptors) as { [DEADLINE]?: Deadline };\n Object.assign(view, { step, data });\n view[DEADLINE] = deadline;\n return view as typeof ctx;\n };\n}\n\n/**\n * Deriva, para a checagem de um papel custom, a visão com o `log` do plugin dono do papel e o\n * `signal` preso ao `deadline` da checagem.\n */\nexport function roleViewFactory(\n pluginLog: Logger,\n): <C extends object>(ctx: C, deadline: Deadline) => C {\n const descriptors: PropertyDescriptorMap = {\n log: pluginLogDescriptor(pluginLog),\n signal: signalDescriptor,\n };\n return (ctx, deadline) => {\n const view = Object.create(ctx, descriptors) as { [DEADLINE]?: Deadline };\n view[DEADLINE] = deadline;\n return view as typeof ctx;\n };\n}\n\n/**\n * Deriva, para um listener de evento de mensagem, a visão com `message`, `text`, `reply`,\n * `react`, `expectReply` e `log` (do plugin). O objeto do barramento fica no protótipo: `claimed`/`claim()` seguem\n * compartilhados entre os listeners da emissão; o barramento pendura na visão o `Deadline` do\n * listener, que dá o `signal` e prende o `reply`.\n */\nexport function listenerViewFactory(\n plugin: string,\n pluginLog: Logger,\n expect: PluginExpect,\n text: PluginText,\n): <C extends object>(ctx: C) => C {\n type View = Partial<WithKernelContext> &\n ExpiringView & {\n readonly payload: Message;\n readonly message: Message;\n readonly event: string;\n };\n const kernel = (view: View): KernelMessageContext | undefined => view[KERNEL_CONTEXT];\n const scope: Scope<View> = (view) => ({\n label: `listener de \"${view.event}\"`,\n fields: { event: view.event },\n });\n const descriptors: PropertyDescriptorMap = {\n message: {\n get(this: View): Message {\n return this.payload;\n },\n },\n text: {\n get(this: View): string | null {\n const ctx = kernel(this);\n return ctx === undefined ? this.payload.text : ctx.text;\n },\n },\n reply: expiringReplyDescriptor<View>(\n plugin,\n (view) => {\n const ctx = kernel(view);\n return ctx === undefined ? undefined : pluginReply(ctx, plugin);\n },\n scope,\n ),\n react: expiringReactDescriptor<View>(plugin, kernel, scope),\n expectReply: expectReplyDescriptor<View>(plugin, expect, scope),\n log: pluginLogDescriptor(pluginLog),\n t: textDescriptor(text),\n } satisfies Record<keyof MessageListenerFields, PropertyDescriptor>;\n return (ctx) => Object.create(ctx, descriptors);\n}\n","import { isThenable } from '#deadline.ts';\n\n/** Teto de execuções simultâneas de um comando (`concurrency`, ADR 0088). */\nexport interface ConcurrencyLimit {\n /**\n * Roda `task` se houver vaga; senão, espera a vez em ordem de chegada. A vaga só volta quando o\n * resultado de `task` assenta, não quando o prazo estoura: o trabalho que ignora o `signal`\n * continua consumindo CPU. `signal` abortado tira da espera e rejeita com o `reason` dele.\n */\n run(task: () => unknown, signal: AbortSignal): unknown;\n}\n\nexport function createConcurrencyLimit(max: number): ConcurrencyLimit {\n let active = 0;\n // Em ordem de inserção: o `Set` dá a fila e a remoção de quem desistiu.\n const waiting = new Set<() => void>();\n\n const release = (): void => {\n const next = waiting.values().next();\n if (next.done) {\n active--;\n return;\n }\n // A vaga passa direto para o próximo, sem voltar a `active`.\n waiting.delete(next.value);\n next.value();\n };\n\n const start = (task: () => unknown): unknown => {\n let result: unknown;\n try {\n result = task();\n } catch (error) {\n release();\n throw error;\n }\n // Só libera: quem rodou recebe `result` e trata a rejeição.\n if (isThenable(result)) result.then(release, release);\n else release();\n return result;\n };\n\n return {\n run(task, signal) {\n if (active < max) {\n active++;\n return start(task);\n }\n return new Promise((resolve, reject) => {\n if (signal.aborted) {\n reject(signal.reason);\n return;\n }\n const onAbort = (): void => {\n waiting.delete(go);\n reject(signal.reason);\n };\n const go = (): void => {\n signal.removeEventListener('abort', onAbort);\n try {\n resolve(start(task));\n } catch (error) {\n reject(error);\n }\n };\n waiting.add(go);\n signal.addEventListener('abort', onAbort, { once: true });\n });\n },\n };\n}\n","// Storage do plugin com escopo de tenant (ADR 0072): cada operação vai ao namespace do tenant\n// corrente (`<plugin>@<tenant>`) ou, sem tenant, ao do plugin, como antes. A escolha é feita na\n// chamada, não na criação: uma coleção obtida no `setup` grava no tenant do handler que a usa.\n\nimport type { TenantScope } from '#tenant/scope.ts';\nimport { assertTenantId, pluginStorage } from './namespace.ts';\nimport type {\n Collection,\n CollectionOptions,\n JsonValue,\n KeyValueStore,\n PluginStorage,\n StoragePort,\n} from './types.ts';\n\n/** `ctx.storage`: o storage do tenant corrente, mais a escolha explícita de um tenant. */\nexport interface TenantStorage extends PluginStorage {\n /**\n * Storage de um tenant escolhido pelo plugin, fora do escopo corrente: no `setup`, num job sem\n * tenant ou num plugin de administração que atende vários. Lança `TypeError` com ID vazio.\n */\n forTenant(tenantId: string): PluginStorage;\n}\n\n/**\n * `ctx.storage`: o da sessão do bot e, em `shared`, o comum a todas as sessões que dividem o\n * storage (ADR 0075). Os dois seguem o tenant corrente.\n */\nexport interface PluginContextStorage extends TenantStorage {\n /**\n * Dados do plugin comuns a todos os bots no mesmo storage (WhatsApp, Telegram, web...). Os IDs\n * de contato e de chat só são únicos dentro de um transport: componha a chave com\n * `ctx.transportName` quando ela vier de um ID.\n */\n readonly shared: TenantStorage;\n}\n\n/**\n * Storage do plugin que segue o `scope`. Os storages por tenant ficam em cache (as coleções do\n * adapter criam o índice na primeira operação de cada objeto); o número de tenants de um bot é o\n * de clientes do dono, não o de usuários.\n */\nexport function tenantStorage(\n port: StoragePort,\n pluginName: string,\n scope: TenantScope,\n): TenantStorage {\n const base = pluginStorage(port, pluginName);\n const byTenant = new Map<string, PluginStorage>();\n const forTenant = (tenant: string): PluginStorage => {\n let storage = byTenant.get(tenant);\n if (storage === undefined) {\n storage = pluginStorage(port, pluginName, tenant);\n byTenant.set(tenant, storage);\n }\n return storage;\n };\n const current = (): PluginStorage => {\n const tenant = scope.current;\n return tenant === undefined ? base : forTenant(tenant);\n };\n\n const kv: KeyValueStore = {\n get: <T extends JsonValue = JsonValue>(key: string) => current().kv.get<T>(key),\n set: (key: string, value: JsonValue) => current().kv.set(key, value),\n delete: (key: string) => current().kv.delete(key),\n };\n return {\n kv,\n collection<T extends { readonly [key: string]: JsonValue }>(\n name: string,\n options?: CollectionOptions,\n ): Collection<T> {\n // Valida o nome e as opções já aqui, como o adapter faz: o erro sai no `setup`, não na\n // primeira mensagem.\n const untenanted = base.collection<T>(name, options);\n const collections = new Map<PluginStorage, Collection<T>>([[base, untenanted]]);\n const resolve = (): Collection<T> => {\n const storage = current();\n let collection = collections.get(storage);\n if (collection === undefined) {\n collection = storage.collection<T>(name, options);\n collections.set(storage, collection);\n }\n return collection;\n };\n type C = Collection<T>;\n return {\n insert: (document) => resolve().insert(document),\n get: (id) => resolve().get(id),\n find: (query?: Parameters<C['find']>[0]) => resolve().find(query),\n update: (target, patch) => resolve().update(target, patch),\n delete: (target) => resolve().delete(target),\n };\n },\n forTenant(tenantId) {\n assertTenantId(tenantId);\n return forTenant(tenantId);\n },\n };\n}\n","// Fábrica do `PluginContext` (M1-16): liga cada campo do contexto ao serviço do bot, sempre em\n// nome do plugin, e desfaz tudo no `dispose`. É a única peça que conhece todos os serviços; o\n// host de plugins só recebe a fábrica.\n\nimport { commandInfo } from '#commands/catalog.ts';\nimport {\n assertCommandDefinition,\n type CommandContext,\n type CommandDefinition,\n} from '#commands/command.ts';\nimport { createConcurrencyLimit } from '#commands/concurrency.ts';\nimport type { Prefixes } from '#commands/prefixes.ts';\nimport { type RoleCheck, RoleTimeoutError } from '#commands/roles.ts';\nimport type { CommandRouter } from '#commands/router.ts';\nimport { BotConfigError } from '#config/owners.ts';\nimport type { PluginConfigs } from '#config/plugin-configs.ts';\nimport {\n type ConversationRegistry,\n type KernelStep,\n type StepContext,\n type StepHandler,\n StepTimeoutError,\n} from '#conversations/conversations.ts';\nimport {\n type ArmedTimers,\n ContextExpiredError,\n Deadline,\n ExecutionTimeoutError,\n isThenable,\n settleWithin,\n} from '#deadline.ts';\nimport type { EventBus } from '#events/bus.ts';\nimport type { BotEventName, EventSubscriber, PluginErrorEvent } from '#events/types.ts';\nimport type { Groups } from '#groups/groups.ts';\nimport type { SessionHttp } from '#http/server.ts';\nimport type { HttpRoutes } from '#http/types.ts';\nimport type { Logger } from '#logger/types.ts';\nimport type { Contact } from '#message/types.ts';\nimport type { Outbound } from '#outbound/types.ts';\nimport { type PluginContextFactory, PluginHostStateError } from '#plugin/host.ts';\nimport { formatMessage } from '#plugin/messages.ts';\nimport type { PluginContext } from '#plugin/types.ts';\nimport type { SchedulerService } from '#scheduler/service.ts';\nimport type { Scheduler } from '#scheduler/types.ts';\nimport type { ServiceRegistry } from '#services/registry.ts';\nimport type { ServiceAccess } from '#services/types.ts';\nimport { type PluginContextStorage, type TenantStorage, tenantStorage } from '#storage/tenant.ts';\nimport type {\n Collection,\n CollectionOptions,\n JsonValue,\n KeyValueStore,\n PluginStorage,\n StoragePort,\n} from '#storage/types.ts';\nimport type { TenantScope } from '#tenant/scope.ts';\nimport { isFormatted } from '#text/format.ts';\nimport { type Capability, missingCapabilities } from '#transport/capabilities.ts';\nimport type { Unsubscribe } from '#transport/types.ts';\nimport type { UnsafeAccess } from '#unsafe/access.ts';\nimport {\n type CommandViews,\n commandViewFactory,\n type KernelMessageContext,\n listenerViewFactory,\n type PluginExpect,\n type PluginText,\n roleViewFactory,\n stepViewFactory,\n} from './message-context.ts';\n\nexport interface PluginContextDeps {\n readonly configs: PluginConfigs;\n readonly log: Logger;\n readonly router: CommandRouter;\n readonly prefixes: Prefixes;\n /** Passos e esperas de conversa (ADR 0060). */\n readonly conversations: ConversationRegistry<KernelMessageContext>;\n readonly bus: EventBus;\n readonly services: ServiceRegistry;\n readonly storage: StoragePort;\n /** Storage comum às sessões (ADR 0075), de onde sai o `ctx.storage.shared`. */\n readonly shared: StoragePort;\n /** Tenant corrente (ADR 0072): o `ctx.storage` do plugin grava no namespace dele. */\n readonly tenants: TenantScope;\n readonly scheduler: SchedulerService;\n readonly send: Outbound;\n readonly groups: Groups;\n /** Rotas da sessão no servidor HTTP; ausente sem `http` na config do bot (ADR 0076). */\n readonly http: SessionHttp | undefined;\n /** Falha de uma rota ou WebSocket do plugin (`phase: 'http'`). */\n readonly onHttpError: (event: PluginErrorEvent) => void;\n /** Nome, capabilities e contato da sessão, lidos do transport a cada acesso. */\n readonly transport: {\n readonly name: string;\n readonly capabilities: ReadonlySet<Capability>;\n readonly self: Contact | null;\n };\n readonly unsafe: UnsafeAccess;\n /** Prazo do `run` e do `onReject` de cada comando, em ms (ADR 0005). */\n readonly commandTimeoutMs: number;\n /** Destino da rejeição de um `run` que chegou depois do prazo (já reportado como timeout). */\n readonly onLateCommandError: (plugin: string, command: string, error: unknown) => void;\n /** Checagem de papel custom que lançou, rejeitou ou estourou o prazo (`phase: 'role'`). */\n readonly onRoleError: (event: PluginErrorEvent) => void;\n /** Prazos armados de comandos e papéis, para o shutdown desarmá-los. */\n readonly armed: ArmedTimers;\n}\n\n/** Parte do comando que roda código de plugin com prazo. */\nexport type CommandStage = 'run' | 'onReject';\n\n/**\n * O `run` ou o `onReject` de um comando estourou o prazo. Vai em `plugin.error` com\n * `timedOut: true`.\n */\nexport class CommandTimeoutError extends ExecutionTimeoutError {\n override readonly name: string = 'CommandTimeoutError';\n readonly command: string;\n readonly stage: CommandStage;\n\n constructor(plugin: string, command: string, timeoutMs: number, stage: CommandStage = 'run') {\n super(\n plugin,\n stage === 'run' ? `comando \"${command}\"` : `onReject do comando \"${command}\"`,\n timeoutMs,\n );\n this.command = command;\n this.stage = stage;\n }\n}\n\n/** Eventos cujo payload é uma `Message`: os listeners deles recebem os campos de mensagem. */\nexport function isMessageEvent(event: BotEventName): boolean {\n return event === 'message' || event === 'message.edited' || event.startsWith('message:');\n}\n\nexport function createPluginContextFactory(deps: PluginContextDeps): PluginContextFactory {\n return async (plugin) => {\n const { name } = plugin;\n // Lança `PluginConfigError` com config inválida: o host ignora o plugin (ADR 0032).\n const { config, messages } = await deps.configs.resolve(name);\n const log = deps.log.child({ plugin: name });\n\n // Um `setup` que estourou o prazo segue rodando em segundo plano (não há como abortá-lo).\n // Depois do `dispose`, tudo o que ele registrar ficaria órfão e todo efeito (envio,\n // storage, agendamento) viria de um plugin que já desceu: o contexto recusa, e o `signal`\n // dele aborta (ADR 0033). Comandos, papéis, listeners e jobs ainda em andamento têm\n // `Deadline` filho deste: o `dispose` os expira junto (#200).\n const lifetime = new Deadline();\n const guard = (what: string): void => {\n if (lifetime.expired) {\n throw new PluginHostStateError(\n `plugin \"${name}\": ${what} depois que o contexto foi descartado (setup que estourou ` +\n 'o prazo, ou registro depois do teardown)',\n );\n }\n };\n /** Rejeição (com log) de uma operação assíncrona do contexto descartado. */\n const refuse = (operation: string): Promise<never> => {\n const error = new ContextExpiredError(name, operation, 'contexto do plugin', lifetime.reason);\n log.warn(`${operation} recusado: contexto do plugin já foi descartado`, {\n operation,\n err: error,\n });\n return Promise.reject(error);\n };\n const live: Live =\n (operation, fn) =>\n (...args) =>\n lifetime.expired ? refuse(operation) : fn(...args);\n\n // A espera é sempre do plugin dono do contexto: ele só aponta para os próprios passos.\n const expect: PluginExpect = (message, step, options) =>\n deps.conversations.expect(name, message.chat.id, message.sender.id, step, options);\n // `{prefix}` lido a cada chamada: um `ctx.prefixes.set` vale já para a mensagem seguinte.\n const text: PluginText = (message, key, values) =>\n formatMessage(messages, key, values, deps.prefixes.get(message.chat));\n const commandViews = commandViewFactory(name, log, expect, text);\n const listenerView = listenerViewFactory(name, log, expect, text);\n const stepView = stepViewFactory(name, log, expect, text);\n const roleView = roleViewFactory(log);\n // Nos eventos de mensagem, cada listener recebe a visão com `message`/`text`/`reply`/`log`\n // do plugin; o barramento a cria (uma por listener) e pendura nela o `Deadline`.\n const events = deps.bus.forPlugin(name, {\n view: (event) => (isMessageEvent(event) ? listenerView : undefined),\n lifetime,\n });\n const services = deps.services.forPlugin(name);\n const scheduler = deps.scheduler.forPlugin(name, lifetime);\n\n const context: PluginContext = {\n plugin: { name, version: plugin.version, messages },\n config,\n log,\n get signal(): AbortSignal {\n return lifetime.signal;\n },\n commands: {\n add(definition: CommandDefinition): void {\n guard('commands.add');\n // Comando que o transport não sustenta nem entra no registro: anunciá-lo no menu e\n // no `list()` para recusar depois seria pior que não tê-lo (ADR 0090). A definição\n // inválida lança mesmo assim, para o erro não depender do transport.\n assertCommandDefinition(definition);\n const missing = missingCapabilities(deps.transport, definition.requires ?? []);\n if (missing.length > 0) {\n log.info(\n `comando \"${definition.name}\" não registrado: capability ausente no transport`,\n {\n command: definition.name,\n missing,\n },\n );\n return;\n }\n deps.router.registry.add(\n name,\n wrapCommand(name, definition, commandViews, lifetime, deps),\n );\n },\n list: () => deps.router.registry.list().map(commandInfo),\n },\n roles: {\n define(role, check) {\n guard('roles.define');\n deps.router.roles.define(\n name,\n role,\n wrapRoleCheck(name, role, check, roleView, log, lifetime, deps),\n );\n },\n },\n prefixes: {\n get: (chat) => deps.prefixes.get(chat),\n set: live('prefixes.set', (chatId: string, prefix: string) =>\n deps.prefixes.set(chatId, prefix),\n ),\n reset: live('prefixes.reset', (chatId: string) => deps.prefixes.reset(chatId)),\n } satisfies Prefixes,\n conversations: {\n define(step: string, handler: StepHandler): void {\n guard('conversations.define');\n deps.conversations.define(\n name,\n step,\n wrapStep(name, step, handler, stepView, log, lifetime, deps),\n );\n },\n },\n events: {\n on(event: BotEventName, first: unknown, second?: unknown): Unsubscribe {\n guard('events.on');\n return (events.on as AnySubscribe)(event, first, second);\n },\n } as EventSubscriber,\n services: {\n provide(service, implementation) {\n guard('services.provide');\n services.provide(service, implementation);\n },\n get: (service) => services.get(service),\n has: (service) => services.has(service),\n } satisfies ServiceAccess,\n storage: {\n ...liveTenantStorage(tenantStorage(deps.storage, name, deps.tenants), live),\n shared: liveTenantStorage(tenantStorage(deps.shared, name, deps.tenants), live),\n } satisfies PluginContextStorage,\n scheduler: {\n at: live('scheduler.at', (when: Date | number, job: string, payload?: JsonValue) =>\n scheduler.at(when, job, payload),\n ),\n cancel: live('scheduler.cancel', (id: string) => scheduler.cancel(id)),\n on(job, handler) {\n guard('scheduler.on');\n return scheduler.on(job, handler);\n },\n } satisfies Scheduler,\n send: liveOutbound(deps.send, live),\n groups: {\n metadata: live('groups.metadata', (groupId: string) => deps.groups.metadata(groupId)),\n updateParticipants: live(\n 'groups.updateParticipants',\n (...args: Parameters<Groups['updateParticipants']>) =>\n deps.groups.updateParticipants(...args),\n ),\n } satisfies Groups,\n http: pluginHttp(name, deps, guard),\n transportName: deps.transport.name,\n capabilities: deps.transport.capabilities,\n get self(): Contact | null {\n return deps.transport.self;\n },\n unsafe: deps.unsafe.forPlugin(plugin),\n };\n\n return {\n context,\n dispose(reason?: unknown): void {\n lifetime.expire(\n reason ?? new PluginHostStateError(`plugin \"${name}\": contexto descartado`),\n );\n deps.router.registry.removePlugin(name);\n deps.router.roles.removePlugin(name);\n deps.conversations.removePlugin(name);\n deps.bus.removePlugin(name);\n deps.services.removePlugin(name);\n deps.scheduler.removePlugin(name);\n deps.http?.removeOwner(name);\n },\n };\n };\n}\n\n/** `ctx.http`: rotas sob `/plugins/<nome>`, recusadas depois do `dispose` ou sem servidor. */\nfunction pluginHttp(\n name: string,\n deps: PluginContextDeps,\n guard: (what: string) => void,\n): HttpRoutes {\n if (deps.http === undefined) {\n const missing = (): never => {\n throw new BotConfigError(\n `plugin \"${name}\": ctx.http sem servidor; passe \\`http: createHttp({ port })\\` no createBot`,\n );\n };\n return {\n get basePath(): string {\n return missing();\n },\n route: missing,\n ws: missing,\n };\n }\n const routes = deps.http.scope(\n name,\n () => `/plugins/${name}`,\n (error, route) =>\n deps.onHttpError({ plugin: name, phase: 'http', event: route, error, timedOut: false }),\n );\n return {\n get basePath() {\n return routes.basePath;\n },\n route(method, path, handler) {\n guard('http.route');\n routes.route(method, path, handler);\n },\n ws(path, accept) {\n guard('http.ws');\n routes.ws(path, accept);\n },\n };\n}\n\n/** Embrulha uma operação assíncrona para rejeitar com `ContextExpiredError` após o `dispose`. */\ntype Live = <A extends unknown[], R>(\n operation: string,\n fn: (...args: A) => Promise<R>,\n) => (...args: A) => Promise<R>;\n\n/** `ctx.send` com o envio e cada ação recusados depois do `dispose`. */\nfunction liveOutbound(outbound: Outbound, live: Live): Outbound {\n return {\n send: live('send', (...args: Parameters<Outbound['send']>) => outbound.send(...args)),\n react: live('send.react', (...args: Parameters<Outbound['react']>) => outbound.react(...args)),\n edit: live('send.edit', (...args: Parameters<Outbound['edit']>) => outbound.edit(...args)),\n delete: live('send.delete', (...args: Parameters<Outbound['delete']>) =>\n outbound.delete(...args),\n ),\n typing: live('send.typing', (...args: Parameters<Outbound['typing']>) =>\n outbound.typing(...args),\n ),\n };\n}\n\n/**\n * Storage do plugin com cada operação (KV e coleções) recusada depois do `dispose`. A checagem é\n * na chamada: uma coleção obtida antes do descarte também passa a recusar.\n */\nfunction liveStorage(storage: PluginStorage, live: Live): PluginStorage {\n const { kv } = storage;\n const liveKv: KeyValueStore = {\n get: live('storage.kv.get', (key: string) => kv.get(key)) as KeyValueStore['get'],\n set: live('storage.kv.set', (key: string, value: JsonValue) => kv.set(key, value)),\n delete: live('storage.kv.delete', (key: string) => kv.delete(key)),\n };\n return {\n kv: liveKv,\n collection<T extends { readonly [key: string]: JsonValue }>(\n collectionName: string,\n options?: CollectionOptions,\n ): Collection<T> {\n const collection = storage.collection<T>(collectionName, options);\n const op = (method: string): string => `storage.collection(\"${collectionName}\").${method}`;\n type C = Collection<T>;\n return {\n insert: live(op('insert'), (document: T) => collection.insert(document)),\n get: live(op('get'), (id: string) => collection.get(id)),\n find: live(op('find'), (query?: Parameters<C['find']>[0]) => collection.find(query)),\n update: live(\n op('update'),\n (target: Parameters<C['update']>[0], patch: Parameters<C['update']>[1]) =>\n collection.update(target, patch),\n ),\n delete: live(op('delete'), (target: Parameters<C['delete']>[0]) =>\n collection.delete(target),\n ),\n };\n },\n };\n}\n\n/** `liveStorage` também no storage de cada tenant escolhido com `forTenant`. */\nfunction liveTenantStorage(storage: TenantStorage, live: Live): TenantStorage {\n return {\n ...liveStorage(storage, live),\n forTenant: (tenantId) => liveStorage(storage.forTenant(tenantId), live),\n };\n}\n\ntype AnySubscribe = (event: BotEventName, first: unknown, second: unknown) => Unsubscribe;\n\n/**\n * Comando com o `log` do plugin dono no contexto de `run` e `onReject`, e os dois com prazo: um\n * deles preso seguraria o chat na fila de entrada para sempre (ADR 0005). Cada um tem o próprio\n * `Deadline`, filho do de vida do plugin, que dá o `signal` e prende o `reply` (ADR 0033).\n */\nfunction wrapCommand(\n plugin: string,\n definition: CommandDefinition,\n views: CommandViews,\n lifetime: Deadline,\n deps: Pick<PluginContextDeps, 'commandTimeoutMs' | 'onLateCommandError' | 'armed'>,\n): CommandDefinition {\n const { run, onReject, name } = definition;\n const timeoutMs = definition.timeoutMs ?? deps.commandTimeoutMs;\n // Um por registro do comando: o reload cria outro, e os `run` antigos ainda vivos ocupam só o\n // teto do registro anterior.\n const limit =\n definition.concurrency === undefined\n ? undefined\n : createConcurrencyLimit(definition.concurrency);\n const timed = <R>(stage: CommandStage, execute: (deadline: Deadline) => R): R => {\n const deadline = new Deadline(lifetime);\n return settleWithin(\n execute(deadline),\n timeoutMs,\n () => {\n const error = new CommandTimeoutError(plugin, name, timeoutMs, stage);\n deadline.expire(error);\n return error;\n },\n (error) => {\n // Rejeitar com o próprio erro do prazo (a espera por vaga, ou o `run` que repassa o\n // `signal.reason`) não é falha nova: o prazo já foi reportado.\n if (error === deadline.reason) return;\n deps.onLateCommandError(plugin, name, error);\n },\n deps.armed,\n deadline,\n ) as R;\n };\n return {\n ...definition,\n run: (ctx) =>\n timed('run', (deadline) => {\n const start = (): unknown => {\n const view = views.run(ctx, deadline);\n return replyWithResult(view, run(view));\n };\n // A espera por vaga fica dentro do prazo: o chat não fica preso além do `timeoutMs`.\n return limit === undefined ? start() : limit.run(start, deadline.signal);\n }),\n ...(onReject && {\n onReject: (ctx, rejection) =>\n timed('onReject', (deadline) => onReject(views.run(ctx, deadline), rejection)),\n }),\n };\n}\n\n/**\n * `run` que devolve texto (string ou `fmt`) responde com ele, como o `onReject` (ADR 0079): o\n * mesmo que terminar com `await ctx.reply(texto)`, dentro do prazo do comando. Outro valor, como\n * a chave de um `c.reply(...)` devolvido, é ignorado.\n */\nfunction replyWithResult(ctx: CommandContext, result: unknown): unknown {\n const answer = (value: unknown): unknown =>\n typeof value === 'string' || isFormatted(value) ? ctx.reply(value) : undefined;\n return isThenable(result) ? Promise.resolve(result).then(answer) : answer(result);\n}\n\n/**\n * Checagem de papel com prazo e fail-closed (ADR 0035): lançar, rejeitar ou estourar o prazo\n * recusa o comando e vira `plugin.error` do plugin dono do papel, não do dono do comando. Nunca\n * lança. Checagem síncrona passa direto, sem timer.\n */\nfunction wrapRoleCheck(\n plugin: string,\n role: string,\n check: RoleCheck,\n view: ReturnType<typeof roleViewFactory>,\n log: Logger,\n lifetime: Deadline,\n deps: Pick<PluginContextDeps, 'commandTimeoutMs' | 'onRoleError' | 'armed'>,\n): RoleCheck {\n const refuse = (error: unknown): false => {\n deps.onRoleError({\n plugin,\n phase: 'role',\n event: role,\n error,\n timedOut: error instanceof RoleTimeoutError,\n });\n return false;\n };\n return (ctx) => {\n const deadline = new Deadline(lifetime);\n let result: unknown;\n try {\n result = check(view(ctx, deadline));\n } catch (error) {\n return refuse(error);\n }\n const settled = settleWithin(\n result,\n deps.commandTimeoutMs,\n () => {\n const error = new RoleTimeoutError(plugin, role, deps.commandTimeoutMs);\n deadline.expire(error);\n return error;\n },\n (error) => log.error(`papel \"${role}\" rejeitou depois do prazo`, { role, err: error }),\n deps.armed,\n );\n if (!(settled instanceof Promise)) return settled === true;\n return settled.then((granted) => granted === true, refuse);\n };\n}\n\n/**\n * Passo de conversa com a visão do plugin e o prazo do comando (`commandMs`): o passo roda dentro\n * da tarefa da fila do chat, e um preso seguraria o chat como um comando preso (ADR 0042). Tem o\n * próprio `Deadline`, filho do de vida do plugin, como o comando.\n */\nfunction wrapStep(\n plugin: string,\n step: string,\n handler: StepHandler,\n view: ReturnType<typeof stepViewFactory>,\n log: Logger,\n lifetime: Deadline,\n deps: Pick<PluginContextDeps, 'commandTimeoutMs' | 'armed'>,\n): KernelStep<KernelMessageContext> {\n const timeoutMs = deps.commandTimeoutMs;\n return (ctx, data) => {\n const deadline = new Deadline(lifetime);\n return settleWithin(\n handler(view(ctx, deadline, step, data) as unknown as StepContext),\n timeoutMs,\n () => {\n const error = new StepTimeoutError(plugin, step, timeoutMs);\n deadline.expire(error);\n return error;\n },\n (error) => {\n // A recusa de um contexto expirado já foi logada quando aconteceu (ADR 0033).\n if (error instanceof ContextExpiredError) return;\n log.error(`passo \"${step}\" rejeitou depois do prazo`, { step, err: error });\n },\n deps.armed,\n deadline,\n );\n };\n}\n","// Executor da `ReconnectionPolicy` (M1-16.3). A política só decide; aqui o bot aguarda o atraso,\n// limpa a sessão quando é o caso e reconecta, ou desiste e para. Um timer por vez, e nenhum\n// depois do `stop()`.\n\nimport type { LogFields, Logger } from '#logger/types.ts';\nimport {\n type ReconnectionDecision,\n ReconnectionPolicy,\n type ReconnectionPolicyOptions,\n} from '#transport/reconnection.ts';\nimport type { ConnectionStatus, Transport } from '#transport/types.ts';\n\n// `pairing` sai das opções: no bot, quem diz se há pareamento é a capability do transport, não\n// a config (ADR 0068).\nexport interface BotReconnectionOptions extends Omit<ReconnectionPolicyOptions, 'pairing'> {\n /**\n * Apaga as credenciais salvas, para a decisão `clean-session` (sessão encerrada no aparelho,\n * credenciais rejeitadas num transport com `pairing`, QRs sem pareamento; queda de rede\n * nunca, ADR 0045; erro `fatal` nunca, ADR 0068). Com transport\n * por fábrica, o padrão limpa o `auth` que a fábrica recebeu; isto o substitui. Com instância\n * pronta e sem ela, o bot não tem como parear de novo sozinho: loga e para.\n */\n readonly clearSession?: () => Promise<void>;\n}\n\nexport interface Reconnector {\n /**\n * Trata `connection.status`. Antes de `activate()`, ou com um `connect()` de reconexão em\n * andamento, guarda o último `closed` e decide sobre ele quando puder (ADR 0048).\n */\n onStatus(status: ConnectionStatus): void;\n /** Trata `connection.qr` e `connection.pairing-code` (ADR 0050). */\n onQr(): void;\n /** O `connect()` inicial terminou: a partir daqui, uma queda é reconectada. */\n activate(): void;\n /** Cancela o timer e espera uma reconexão em andamento. Idempotente. */\n stop(): Promise<void>;\n}\n\nexport interface ReconnectorOptions {\n readonly transport: Pick<Transport, 'connect'>;\n readonly log: () => Logger;\n readonly options: BotReconnectionOptions;\n /** O transport declara a capability `pairing`; sem ela, `auth-failed` para (ADR 0068). */\n readonly pairing: boolean;\n /** Chamado quando não há como seguir (`stop`, ou `clean-session` sem `clearSession`). */\n readonly giveUp: (decision: ReconnectionDecision) => void;\n}\n\ntype ClosedStatus = Extract<ConnectionStatus, { status: 'closed' }>;\n\n/** Decisão que o executor agenda: reconectar, com ou sem limpar a sessão antes. */\ntype Retry = Exclude<ReconnectionDecision, { action: 'stop' }>;\n\nexport function createReconnector({\n transport,\n log,\n options,\n pairing,\n giveUp,\n}: ReconnectorOptions): Reconnector {\n const policy = new ReconnectionPolicy({ ...options, pairing });\n const { clearSession } = options;\n let active = false;\n let stopped = false;\n let timer: NodeJS.Timeout | undefined;\n let inFlight: Promise<void> | undefined;\n // Queda que chegou quando o executor não podia agir (antes do `activate()` ou durante um\n // `connect()` de reconexão): o `connect()` resolve ao iniciar a tentativa, então o `closed`\n // pode vir antes de ele terminar e não teria mais quem o tratasse (#253). Um `open` depois\n // dela a anula.\n let pending: ClosedStatus | undefined;\n\n function schedule(decision: Retry): void {\n timer = setTimeout(() => {\n timer = undefined;\n inFlight = execute(decision).then((failed) => {\n inFlight = undefined;\n // Falha ao reconectar conta como queda: a política decide de novo (backoff). O\n // `closed` guardado tem o motivo do transport, mais preciso que o genérico.\n const lost: ClosedStatus = { status: 'closed', reason: 'connection-lost', error: null };\n const closed = pending ?? (failed ? lost : undefined);\n pending = undefined;\n if (closed) handleClosed(closed);\n });\n }, decision.delayMs);\n }\n\n /** Executa a decisão; `true` se falhou (o erro já foi logado). Nunca rejeita. */\n async function execute(decision: Retry): Promise<boolean> {\n if (stopped) return false;\n try {\n if (decision.action === 'clean-session') await clearSession?.();\n if (stopped) return false;\n await transport.connect();\n return false;\n } catch (error) {\n log().error('reconexão falhou', { err: error, action: decision.action });\n return true;\n }\n }\n\n /**\n * Loga por que o bot desiste. `fatal` e a credencial sem pareamento saem em `fatal`: o bot não\n * volta sozinho, alguém precisa corrigir a config. `replaced` fica em `error`: a outra conexão\n * segue de pé.\n */\n function logStop(\n cause: Extract<ReconnectionDecision, { action: 'stop' }>['cause'],\n fields: LogFields,\n ): void {\n switch (cause) {\n case 'replaced':\n log().error(\n 'conexão encerrada (replaced): outra conexão assumiu esta sessão (o mesmo número ' +\n 'rodando em outro processo?); o bot vai parar em vez de derrubá-la',\n fields,\n );\n return;\n case 'fatal':\n log().fatal(\n 'conexão encerrada por erro fatal do transport (token sem permissão, intents, porta?); ' +\n 'reconectar não resolve: corrija a configuração. O bot vai parar',\n fields,\n );\n return;\n case 'auth-failed':\n log().fatal(\n 'conexão encerrada (auth-failed): credenciais rejeitadas, e o transport não pareia de ' +\n 'novo (token inválido?); limpar a sessão não resolve. O bot vai parar',\n fields,\n );\n return;\n }\n }\n\n function handleClosed(status: ClosedStatus): void {\n if (stopped) return;\n // Já há reconexão agendada: o `connect()` dela ainda não começou e cobre esta queda.\n if (timer !== undefined) return;\n // Sem poder agir agora: decide quando o `connect()` (inicial ou de reconexão) terminar.\n if (!active || inFlight !== undefined) {\n pending = status;\n return;\n }\n const decision = policy.decide(status.reason);\n const fields = { reason: status.reason, err: status.error, ...decision, ...policy.state };\n if (decision.action === 'stop') {\n logStop(decision.cause, fields);\n giveUp(decision);\n return;\n }\n if (decision.action === 'clean-session' && clearSession === undefined) {\n log().error(\n `conexão encerrada (${status.reason}): a sessão precisa ser pareada de novo e não há ` +\n 'clearSession configurado; o bot vai parar',\n fields,\n );\n giveUp(decision);\n return;\n }\n log().warn(\n `conexão fechada (${status.reason}): reconectando em ${decision.delayMs} ms`,\n fields,\n );\n schedule(decision);\n }\n\n return {\n onStatus(status) {\n switch (status.status) {\n case 'open':\n pending = undefined;\n policy.connected();\n log().info('conexão aberta');\n return;\n case 'connecting':\n log().debug('conectando');\n return;\n case 'closed':\n handleClosed(status);\n return;\n }\n },\n\n onQr() {\n policy.qrPresented();\n },\n\n activate() {\n active = true;\n const closed = pending;\n pending = undefined;\n if (closed) handleClosed(closed);\n },\n\n async stop() {\n stopped = true;\n clearTimeout(timer);\n timer = undefined;\n await inFlight;\n },\n };\n}\n","// Sessões vivas por storage (ADR 0036): a mesma sessão não roda em dois bots que dividem um\n// storage. O registro fica pendurado no próprio objeto do storage, e não num mapa do módulo,\n// para não haver estado global (ADR 0004); `Symbol.for` faz duas cópias do core se enxergarem.\n\nimport { BotConfigError } from '#config/owners.ts';\nimport type { StoragePort } from '#storage/types.ts';\n\nconst LIVE_SESSIONS = Symbol.for('@usebridger/core/live-sessions');\n\ntype Tracked = StoragePort & { [LIVE_SESSIONS]?: Set<string> };\n\n/** Libera a sessão; `true` se nenhum outro bot usa mais o storage (quem libera o fecha). */\nexport type ReleaseSession = () => boolean;\n\n/**\n * Reserva `session` no storage. Lança `BotConfigError` se outro bot vivo já a usa. Storage que\n * não aceita a marca (objeto congelado) fica sem a checagem: devolve `undefined`.\n */\nexport function claimSession(storage: StoragePort, session: string): ReleaseSession | undefined {\n const tracked = storage as Tracked;\n let live = tracked[LIVE_SESSIONS];\n if (live === undefined) {\n live = new Set();\n const marked = Reflect.defineProperty(tracked, LIVE_SESSIONS, { value: live });\n if (!marked) return undefined;\n }\n if (live.has(session)) {\n throw new BotConfigError(\n `sessão \"${session}\" já está em uso por outro bot neste storage: cada sessão (número) ` +\n 'roda num bot só; dê um `session` diferente a cada bot',\n );\n }\n live.add(session);\n const sessions = live;\n return () => {\n sessions.delete(session);\n return sessions.size === 0;\n };\n}\n","// Trava da sessão entre processos (ADR 0074). O `claimSession` só enxerga bots no mesmo objeto de\n// storage; dois processos sobre o mesmo banco se veem só por aqui. Nem toda plataforma derruba a\n// conexão antiga (o Discord aceita o mesmo token em vários gateways), então sem a trava os dois\n// responderiam. A trava é por nome de sessão, sem olhar o transport: plataformas diferentes com o\n// mesmo nome dividiriam o KV, os jobs e o auth state.\n\nimport { randomUUID } from 'node:crypto';\nimport { BotConfigError } from '#config/owners.ts';\nimport type { Logger } from '#logger/types.ts';\nimport type { StoragePort } from '#storage/types.ts';\n\n/** Validade da trava: por quanto tempo a sessão de um processo que caiu fica presa. */\nexport const SESSION_LEASE_TTL_MS = 30_000;\n/** Intervalo da renovação e das tentativas do `start()`: três chances antes de a trava vencer. */\nexport const SESSION_LEASE_RENEW_MS = 10_000;\n\nexport interface SessionLeaseOptions {\n readonly storage: StoragePort;\n readonly session: string;\n readonly log: Logger;\n /** Aborta a espera pela trava (`stop()` durante o `start()`); rejeita com o `reason`. */\n readonly signal: AbortSignal;\n /** Outro processo assumiu a trava com o bot rodando. Chamado uma vez; a renovação para. */\n readonly onLost: () => void;\n}\n\nexport interface SessionLease {\n /** Para a renovação, espera a que estiver em andamento e libera a trava. */\n release(): Promise<void>;\n}\n\n/**\n * Adquire a trava da sessão e a renova até o `release()`. Ocupada, tenta de novo por até uma\n * validade inteira: a trava de um processo que caiu vence nesse prazo, e o restart logo depois do\n * crash sobe sozinho. Lança `BotConfigError` se outro processo ainda a tem depois disso. Storage\n * sem a trava (memória, que vive num processo só) devolve `undefined`, sem timer.\n */\nexport async function acquireSessionLease(\n options: SessionLeaseOptions,\n): Promise<SessionLease | undefined> {\n const { storage, session, log, signal, onLost } = options;\n const { acquireLease, releaseLease } = storage;\n if (acquireLease === undefined || releaseLease === undefined) return undefined;\n const name = `session:${session}`;\n const owner = randomUUID();\n const acquire = (): Promise<boolean> =>\n acquireLease.call(storage, name, owner, SESSION_LEASE_TTL_MS);\n\n for (let waited = 0; !(await acquire()); waited += SESSION_LEASE_RENEW_MS) {\n if (waited >= SESSION_LEASE_TTL_MS) {\n throw new BotConfigError(\n `sessão \"${session}\" já está em uso por outro processo neste storage: cada sessão ` +\n 'roda num processo só; dê um `session` diferente a cada bot (inclusive em plataformas ' +\n 'diferentes)',\n );\n }\n if (waited === 0) {\n log.warn('sessão travada por outro processo; esperando a trava vencer', {\n session,\n ttlMs: SESSION_LEASE_TTL_MS,\n });\n }\n await abortableDelay(SESSION_LEASE_RENEW_MS, signal);\n }\n\n let lost = false;\n let renewing: Promise<void> | undefined;\n const renew = async (): Promise<void> => {\n try {\n if (await acquire()) return;\n lost = true;\n clearInterval(timer);\n onLost();\n } catch (error) {\n // Falha de I/O não é perda: a trava vale por mais duas renovações, e o próximo tick tenta.\n log.warn('falha ao renovar a trava da sessão; tentando no próximo intervalo', {\n session,\n err: error,\n });\n }\n };\n const timer = setInterval(() => {\n // Uma renovação por vez: um storage lento não empilha escritas.\n renewing ??= renew().finally(() => {\n renewing = undefined;\n });\n }, SESSION_LEASE_RENEW_MS);\n // Não segura o processo: quem o mantém vivo é o transport.\n timer.unref?.();\n\n return {\n async release(): Promise<void> {\n clearInterval(timer);\n // Uma renovação que terminasse depois da liberação adquiriria a trava de novo.\n await renewing;\n if (!lost) await releaseLease.call(storage, name, owner);\n },\n };\n}\n\n/** Espera `ms`, ou rejeita com `signal.reason` se o sinal abortar antes. */\nfunction abortableDelay(ms: number, signal: AbortSignal): Promise<void> {\n if (signal.aborted) return Promise.reject(signal.reason);\n return new Promise((resolve, reject) => {\n const onAbort = (): void => {\n clearTimeout(timer);\n reject(signal.reason);\n };\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n","/**\n * Gancho executado no `stop()`, antes de desconectar o transport. É por aqui que filas drenam\n * e plugins fazem `teardown`. O `signal` aborta quando o gancho estoura o prazo, para quem\n * quiser parar de trabalhar em vez de continuar rodando órfão depois do timeout.\n */\nexport type StopHook = (signal: AbortSignal) => void | Promise<void>;\n\nexport interface StopHookOptions {\n /** Nome que aparece nos erros. Padrão: o nome da função, ou `anonimo`. */\n readonly name?: string;\n /** Prazo deste gancho em ms. Padrão: `shutdown.hookTimeoutMs` do bot. */\n readonly timeoutMs?: number;\n}\n\nexport interface ShutdownOptions {\n /** Prazo padrão de cada gancho em ms. Padrão: 5000. */\n readonly hookTimeoutMs?: number;\n /** Prazo total dos ganchos em ms. Padrão: 15000. */\n readonly timeoutMs?: number;\n}\n\n/** Falha de um gancho de parada; o erro original fica em `cause`. */\nexport class StopHookError extends Error {\n readonly hookName: string;\n /** `true` quando o gancho estourou o prazo ou nem rodou porque o prazo total acabou. */\n readonly timedOut: boolean;\n\n constructor(hookName: string, message: string, timedOut: boolean, cause?: unknown) {\n super(`gancho de parada \"${hookName}\": ${message}`, { cause });\n this.name = 'StopHookError';\n this.hookName = hookName;\n this.timedOut = timedOut;\n }\n}\n\nexport interface RegisteredStopHook {\n readonly hook: StopHook;\n readonly name: string;\n readonly timeoutMs: number | undefined;\n}\n\nexport const DEFAULT_HOOK_TIMEOUT_MS = 5000;\nexport const DEFAULT_SHUTDOWN_TIMEOUT_MS = 15_000;\n\n/**\n * Roda os ganchos em sequência, na ordem recebida, e devolve as falhas em vez de lançar: um\n * gancho quebrado não pode impedir o teardown dos outros. Quem chama decide o destino dos erros.\n */\nexport async function runStopHooks(\n hooks: readonly RegisteredStopHook[],\n options: ShutdownOptions = {},\n): Promise<StopHookError[]> {\n const hookTimeoutMs = options.hookTimeoutMs ?? DEFAULT_HOOK_TIMEOUT_MS;\n const deadline = Date.now() + (options.timeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS);\n const errors: StopHookError[] = [];\n\n for (const entry of hooks) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) {\n // Prazo total esgotado: o processo precisa encerrar mesmo com ganchos pendentes.\n errors.push(new StopHookError(entry.name, 'não executado: prazo total esgotado', true));\n continue;\n }\n const error = await runOne(entry, Math.min(entry.timeoutMs ?? hookTimeoutMs, remaining));\n if (error) errors.push(error);\n }\n return errors;\n}\n\nasync function runOne(\n entry: RegisteredStopHook,\n timeoutMs: number,\n): Promise<StopHookError | undefined> {\n const controller = new AbortController();\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<StopHookError>((resolve) => {\n timer = setTimeout(() => {\n controller.abort();\n resolve(new StopHookError(entry.name, `excedeu ${timeoutMs} ms`, true));\n }, timeoutMs);\n });\n // `then` captura também o throw síncrono do gancho.\n const run = Promise.resolve()\n .then(() => entry.hook(controller.signal))\n .then(\n () => undefined,\n (cause: unknown) => new StopHookError(entry.name, 'falhou', false, cause),\n );\n try {\n return await Promise.race([run, timeout]);\n } finally {\n clearTimeout(timer);\n }\n}\n","import {\n ActionRegistry,\n type ActionTarget,\n type MessageAction,\n numberedMenu,\n pickChoice,\n} from '#actions/actions.ts';\nimport { createCommandCatalog } from '#commands/catalog.ts';\nimport { createPrefixStore, type PrefixConfig } from '#commands/prefixes.ts';\nimport { CommandConflictError, createCommandRegistry } from '#commands/registry.ts';\nimport { RoleConflictError } from '#commands/roles.ts';\nimport { createCommandRouter, type DispatchResult, type IsGroupAdmin } from '#commands/router.ts';\nimport type { ConfigEnv } from '#config/env.ts';\nimport { BotConfigError, type BotOwner, normalizeOwners } from '#config/owners.ts';\nimport {\n createPluginConfigs,\n type PluginConfigFile,\n type PluginConfigs,\n} from '#config/plugin-configs.ts';\nimport type { BotMessageContext } from '#context.ts';\nimport {\n ConversationRegistry,\n type PendingReply,\n StepTimeoutError,\n} from '#conversations/conversations.ts';\nimport { ArmedTimers, ContextExpiredError, settleWithin } from '#deadline.ts';\nimport { createEventBus, type EmittableEventName } from '#events/bus.ts';\nimport type { BotEvents, ListenerExtras, PluginErrorEvent } from '#events/types.ts';\nimport { createGroups } from '#groups/groups.ts';\nimport { sessionHttp } from '#http/server.ts';\nimport type { HttpServer } from '#http/types.ts';\nimport { createDeferredLogger } from '#logger/deferred.ts';\nimport { createLogger, createNoopLogger, type LoggerOptions } from '#logger/logger.ts';\nimport { createSecretSet, type SecretSet } from '#logger/secrets.ts';\nimport type { Logger, LogLevel } from '#logger/types.ts';\nimport { createMessage } from '#message/create.ts';\nimport type { Chat, Message } from '#message/types.ts';\nimport { type ChatFilterOptions, chatAllowed, chatFilter } from '#middleware/chat-filter.ts';\nimport { ignoreBots } from '#middleware/ignore-bots.ts';\nimport { ignoreSelf } from '#middleware/ignore-self.ts';\nimport { type Middleware, MiddlewarePipeline } from '#middleware/pipeline.ts';\nimport { type RateLimitOptions, rateLimit } from '#middleware/rate-limit.ts';\nimport { type SanitizeOptions, sanitize } from '#middleware/sanitize.ts';\nimport { createOutbound, enqueueAction } from '#outbound/actions.ts';\nimport {\n OutboundQueue,\n type OutboundQueueOptions,\n type OutboundQueueStats,\n} from '#outbound/queue.ts';\nimport type { PrepareActions } from '#outbound/reply.ts';\nimport { PLUGIN_NAME_PATTERN } from '#plugin/define.ts';\nimport { createPluginHost, type PluginHost, type PluginReloadResult } from '#plugin/host.ts';\nimport type { PluginLifecycleError, PluginReportEntry } from '#plugin/report.ts';\nimport { collectPlugins } from '#plugin/sources.ts';\nimport type { PluginDefinition } from '#plugin/types.ts';\nimport { InboundQueue, type InboundQueueOptions, type InboundQueueStats } from '#queue/inbound.ts';\nimport { createSchedulerService } from '#scheduler/service.ts';\nimport { createServiceRegistry, ServiceConflictError } from '#services/registry.ts';\nimport { createMemoryStorage } from '#storage/memory.ts';\nimport { DEFAULT_SESSION, sessionStorage, sharedStorage } from '#storage/namespace.ts';\nimport type { StoragePort } from '#storage/types.ts';\nimport { TenantScope } from '#tenant/scope.ts';\nimport { type Capability, hasCapability } from '#transport/capabilities.ts';\nimport { transportIssues } from '#transport/methods.ts';\nimport type {\n CommandInteraction,\n Interaction,\n Transport,\n TransportDeps,\n} from '#transport/types.ts';\nimport { createUnsafeAccess } from '#unsafe/access.ts';\nimport {\n createMessageContext,\n type KernelMessageContext,\n type MessageContextDeps,\n messageExtras,\n} from './message-context.ts';\nimport { CommandTimeoutError, createPluginContextFactory } from './plugin-context.ts';\nimport { type BotReconnectionOptions, createReconnector, type Reconnector } from './reconnect.ts';\nimport { claimSession, type ReleaseSession } from './session.ts';\nimport { acquireSessionLease, type SessionLease } from './session-lease.ts';\nimport {\n type RegisteredStopHook,\n runStopHooks,\n type ShutdownOptions,\n type StopHook,\n type StopHookOptions,\n} from './stop-hooks.ts';\n\n/**\n * Ciclo de vida: `idle → starting → running → stopping → stopped`. `stopped` é terminal —\n * uma instância não reinicia; para subir de novo, crie outro `Bot`.\n */\nexport type BotState = 'idle' | 'starting' | 'running' | 'stopping' | 'stopped';\n\n/** Middleware do app com prioridade (maior roda antes). */\nexport interface BotMiddlewareEntry {\n readonly middleware: Middleware<BotMessageContext>;\n /** Padrão: 0 — dentro dos oficiais, que ficam entre 700 e 1000. */\n readonly priority?: number;\n}\n\n/**\n * Middlewares do bot. Os oficiais entram nesta ordem (de fora para dentro): `ignoreSelf` (1000),\n * `ignoreBots` (990), `chatFilter` (900), `rateLimit` (800), `sanitize` (700); depois os do app\n * (`use`, padrão 0).\n */\nexport interface BotMiddlewaresConfig {\n /** Barra as mensagens da própria sessão. Padrão: `true`. */\n readonly ignoreSelf?: boolean;\n /** Barra as mensagens de outros bots (`sender.isBot`). Padrão: `true`. */\n readonly ignoreBots?: boolean;\n /** Allow/blocklist de chats. Padrão: desligado. */\n readonly chatFilter?: ChatFilterOptions;\n /** Rate limit de entrada. Padrão: desligado. Sem `onLimited`, loga em `debug`. */\n readonly rateLimit?: RateLimitOptions;\n /** Truncagem de texto e nome. Padrão: ligado com os limites do `sanitize`; `false` desliga. */\n readonly sanitize?: SanitizeOptions | false;\n /** Middlewares do app. */\n readonly use?: readonly (Middleware<BotMessageContext> | BotMiddlewareEntry)[];\n}\n\n/** Prazos dos estágios que rodam código de plugin, em ms. */\nexport interface BotTimeouts {\n /** Criação do contexto e `setup` de cada plugin. Padrão: 10000. */\n readonly setupMs?: number;\n /** `teardown` e limpeza de cada plugin. Padrão: 5000. */\n readonly teardownMs?: number;\n /**\n * `run` de cada comando; estourado, o chat é liberado e sai `plugin.error`. Padrão: 30000.\n * O `timeoutMs` de um comando sobrescreve só para ele.\n */\n readonly commandMs?: number;\n /** Cada listener de evento. Padrão: 30000. */\n readonly listenerMs?: number;\n /** Cada handler de job do scheduler. Padrão: 30000. */\n readonly jobMs?: number;\n /**\n * Cada middleware do pipeline, contado só no tempo dele (o que roda dentro do `next()` não\n * conta). Estourado, a mensagem é descartada e o erro vai para o log. Padrão: 30000.\n */\n readonly middlewareMs?: number;\n}\n\nexport interface BotConfig {\n /**\n * O transport, ou a fábrica que o monta com o que o bot fornece (`session`, `auth`, `log`;\n * ADR 0037). O `createBot` chama a fábrica uma vez; ela só monta o objeto, sem I/O.\n */\n readonly transport: Transport | ((deps: TransportDeps) => Transport);\n /**\n * Sessão (o número) que este bot opera; kebab-case, como nome de plugin. Tudo o que o bot\n * persiste fica no escopo dela (ADR 0036), então trocar o nome \"esquece\" os dados da anterior.\n * Dois bots vivos no mesmo storage não podem usar a mesma. Padrão: `'default'`.\n */\n readonly session?: string;\n /**\n * Storage do bot (plugins, scheduler, overrides de config). O bot o fecha no `stop()` — o\n * último a parar, se vários bots o dividem. Padrão: em memória (`createMemoryStorage`), com\n * aviso no log — os dados somem ao reiniciar.\n */\n readonly storage?: StoragePort;\n /**\n * Servidor HTTP do processo (`createHttp`), o mesmo para todos os bots (ADR 0076). Dá\n * `ctx.http` aos plugins e `TransportDeps.http` ao transport; a porta só abre se houver rota.\n */\n readonly http?: HttpServer;\n /** Plugins da config (pacotes npm que o app importa). */\n readonly plugins?: readonly PluginDefinition[];\n /** Pastas de plugins locais (ver `collectPlugins`), relativas a `cwd`. */\n readonly pluginDirs?: readonly string[];\n /** Base de `pluginDirs`. Padrão: `process.cwd()`. */\n readonly cwd?: string;\n /** Nomes de plugin que não carregam. */\n readonly disabledPlugins?: readonly string[];\n /** Config por plugin (a camada \"arquivo\"; ver ADR 0032). */\n readonly pluginConfig?: PluginConfigFile;\n /** Ambiente da config de plugin (`BRIDGER_*`). Padrão: `process.env`. */\n readonly env?: ConfigEnv;\n /**\n * Donos (`role: 'owner'`): telefone, aceito com pontuação e normalizado no `createBot`, ou\n * `{ id }` com o ID nativo do contato, para plataformas sem telefone.\n */\n readonly owners?: readonly BotOwner[];\n /**\n * Prefixo de comando: um para todo chat (`'!'`) ou um por tipo (`{ dm: '', group: '!' }`,\n * `group` vale para todo chat que não é `dm`). Vazio é permitido. Padrão: `'!'`. Um plugin\n * troca o de um chat com `ctx.prefixes.set` (ADR 0063).\n */\n readonly prefix?: PrefixConfig;\n /**\n * Logger pronto. Sem ele, o bot cria um (`createLogger`) com `logLevel` e `secrets`. Um\n * logger próprio só censura os segredos da config se for criado com o mesmo `secrets`.\n */\n readonly logger?: Logger;\n /** Nível do logger criado pelo bot. Padrão: `'info'`. */\n readonly logLevel?: LogLevel;\n /**\n * Formato do logger criado pelo bot: `'json'` (padrão) ou `'pretty'`, legível no terminal\n * (ver `LoggerOptions.format`).\n */\n readonly logFormat?: LoggerOptions['format'];\n /** Fonte de segredos compartilhada entre a config de plugin e o logger. Padrão: uma nova. */\n readonly secrets?: SecretSet;\n readonly middlewares?: BotMiddlewaresConfig;\n /** Fila de entrada por chat. */\n readonly inbound?: Pick<InboundQueueOptions, 'maxPendingPerChat'>;\n /** Fila de saída (taxa, prioridade, retry, humanização). */\n readonly outbound?: Omit<OutboundQueueOptions, 'transport'>;\n /** Reconexão automática. Padrão: ligada com os padrões da `ReconnectionPolicy`. */\n readonly reconnection?: BotReconnectionOptions | false;\n readonly timeouts?: BotTimeouts;\n readonly shutdown?: ShutdownOptions;\n}\n\n/** Config de plugin em runtime, para o dashboard: overrides, visão mascarada e schema. */\nexport type BotPluginConfigs = Pick<PluginConfigs, 'setOverrides' | 'describe' | 'jsonSchema'>;\n\nexport interface Bot {\n readonly state: BotState;\n /**\n * Sobe o bot (ordem em docs/bot.md): carrega os plugins e, só se o boot deles der certo,\n * conecta o transport e liga o scheduler. Plugin quebrado (ex.: `CommandConflictError`) ⇒ o\n * transport nunca conecta. Idempotente enquanto `starting`/`running` (devolve a mesma\n * promise); rejeita com `BotStateError` depois de `stop()`. Rejeita com o erro de boot depois\n * de encerrar o que já tinha subido.\n */\n start(): Promise<void>;\n /**\n * Shutdown gracioso: roda os ganchos de parada (LIFO; os internos drenam filas e fazem o\n * `teardown` dos plugins), desconecta o transport e fecha o storage. Idempotente: chamadas\n * repetidas devolvem a mesma promise. Rejeita com `AggregateError` se alguma etapa falhar —\n * mas sempre termina em `stopped`.\n */\n stop(): Promise<void>;\n /** Registra um gancho de parada; devolve a função que o remove. */\n onStop(hook: StopHook, options?: StopHookOptions): () => void;\n /** Config dos plugins. Disponível depois que o `start()` carrega os plugins. */\n readonly config: BotPluginConfigs;\n /** Tabela de boot atual (reflete reloads); vazia antes do `start()`. */\n plugins(): PluginReportEntry[];\n /**\n * Métricas das filas de entrada e de saída, lidas de contadores (O(1)). Sempre disponível:\n * zeros antes do `start()`, valores finais depois do `stop()`. Devolve uma cópia.\n */\n stats(): BotStats;\n /**\n * Resolve quando o bot terminou de processar o que recebeu: fila de entrada vazia, nenhum\n * comando em segundo plano (ADR 0087) nem listener em andamento (inclusive de eventos diretos e\n * `plugin.error`) e fila de saída vazia, tudo ao mesmo tempo (ADR 0044). Chamado durante o boot, espera o boot assentar. Não\n * espera jobs do scheduler; com a fila de saída pausada (conexão caída), espera a reconexão ou\n * o `maxPauseMs`. Resolve na hora antes do `start()` e depois do `stop()`; nunca rejeita.\n */\n settled(): Promise<void>;\n}\n\nexport interface BotStats {\n readonly inbound: InboundQueueStats;\n readonly outbound: OutboundQueueStats;\n}\n\n/** Operação incompatível com o estado atual do bot. */\nexport class BotStateError extends Error {\n readonly state: BotState;\n\n constructor(message: string, state: BotState) {\n super(message);\n this.name = 'BotStateError';\n this.state = state;\n }\n}\n\n/** Prazo padrão do `run` de um comando: o mesmo dos listeners. */\nconst DEFAULT_COMMAND_TIMEOUT_MS = 30_000;\n\n/** Prazo padrão de cada middleware: o mesmo dos handlers (ADR 0043). */\nconst DEFAULT_MIDDLEWARE_TIMEOUT_MS = 30_000;\n\n/**\n * Prazos dos ganchos de parada internos. Somam o total padrão (`shutdown.timeoutMs`, 15 s): um\n * gancho lento não deixa os seguintes sem prazo. O que um gancho não encerrar a tempo é\n * abandonado no fim do shutdown (`abandonInternals`).\n */\nconst STOP_TIMEOUTS = {\n reconnection: 1000,\n inbound: 4000,\n scheduler: 2000,\n plugins: 5000,\n outbound: 3000,\n} as const;\n\n/** Eventos do transport que não são mensagem: vão ao barramento sem fila nem middlewares. */\ntype DirectEvent = Extract<\n EmittableEventName,\n | 'message.deleted'\n | 'reaction'\n | 'poll.vote'\n | 'group.joined'\n | 'group.left'\n | 'group.participants'\n | 'group.updated'\n | 'contact.updated'\n>;\n\n/** O que os filtros do ADR 0038 leem de um evento; `chat: null` = não passa pelo `chatFilter`. */\ninterface EventOrigin {\n /** Com o `parentId`, para o `chatFilter` casar também o espaço (ADR 0058). */\n readonly chat: Pick<Chat, 'id' | 'parentId'> | null;\n readonly fromMe: boolean;\n /** Autor do evento, para o `ignoreBots` (ADR 0057). */\n readonly fromBot: boolean;\n}\n\nconst ALWAYS_PASSES: EventOrigin = { chat: null, fromMe: false, fromBot: false };\n\n/**\n * Origem de cada evento direto, para o `chatFilter`, o `ignoreSelf` e o `ignoreBots` (ADR 0038).\n */\nconst DIRECT_EVENTS: { readonly [E in DirectEvent]: (payload: BotEvents[E]) => EventOrigin } = {\n 'message.deleted': (payload) => ({\n chat: payload.chat,\n fromMe: payload.fromMe,\n fromBot: payload.deletedBy?.isBot === true,\n }),\n reaction: (payload) => ({\n chat: payload.chat,\n fromMe: payload.fromMe,\n fromBot: payload.sender.isBot === true,\n }),\n 'poll.vote': (payload) => ({\n chat: payload.chat,\n fromMe: payload.fromMe,\n fromBot: payload.sender.isBot === true,\n }),\n // Entrada e saída do grupo são o ciclo de vida do próprio bot: servem para o plugin limpar\n // estado, então passam mesmo com o grupo bloqueado.\n 'group.joined': () => ALWAYS_PASSES,\n 'group.left': () => ALWAYS_PASSES,\n 'group.participants': (payload) => ({ chat: payload.chat, fromMe: false, fromBot: false }),\n 'group.updated': (payload) => ({ chat: payload.chat, fromMe: false, fromBot: false }),\n // Contato não é de um chat: bloquear um chat não esconde quem está nele de outros chats.\n 'contact.updated': () => ALWAYS_PASSES,\n};\n\n/**\n * Dono e passo da espera do menu numerado (ADR 0062). O nome não é kebab-case: nenhum plugin o\n * usa.\n */\nconst MENU_OWNER = '#menu';\n// Dono das rotas do transport na tabela HTTP da sessão; nome de plugin não tem `$`.\nconst TRANSPORT_ROUTE_OWNER = '$transport';\nconst MENU_STEP = 'choice';\n\nconst MIDDLEWARE_PRIORITY = {\n ignoreSelf: 1000,\n ignoreBots: 990,\n chatFilter: 900,\n rateLimit: 800,\n sanitize: 700,\n};\n\n/**\n * Cria um bot. Valida a config e monta as peças sem efeito colateral (sem conexão, timer,\n * logger ou leitura de disco): o efeito começa em `start()`. Lança `BotConfigError` para\n * `owners` ou `session` malformados ou fábrica de transport que lança, e `TypeError`/`RangeError`\n * para opções inválidas.\n */\nexport function createBot(config: BotConfig): Bot {\n const session = validateSession(config.session ?? DEFAULT_SESSION);\n // Todo o estado vive neste closure (ADR 0004): duas instâncias nunca se enxergam.\n const hooks: RegisteredStopHook[] = [];\n let state: BotState = 'idle';\n let stopRequested = false;\n let startPromise: Promise<void> | undefined;\n let shutdownPromise: Promise<void> | undefined;\n let stopAfterStart: Promise<void> | undefined;\n\n // O logger nasce no start(): criar o do pino aqui já seria efeito colateral. Até lá, quem\n // logar (nada deveria) cai no no-op.\n let log: Logger = createNoopLogger();\n const getLog = (): Logger => log;\n const secrets = config.secrets ?? createSecretSet();\n const storage = config.storage ?? createMemoryStorage();\n // O escopo da sessão é aplicado aqui, uma vez: scheduler, config e plugins só veem esta visão.\n const scoped = sessionStorage(storage, session);\n const auth = storage.authState(session);\n // A fábrica recebe o logger antes de ele existir: este delega ao filho `{ transport }` que o\n // start() cria e, até lá, ao no-op.\n let transportLog: Logger | undefined;\n // A lista de comandos que o transport registra na plataforma (ADR 0064). O registro avisa o\n // catálogo, que junta os avisos em lote.\n const catalog = createCommandCatalog({\n list: () => registry.list(),\n onError: (error) =>\n log.error('listener de commands.onChange do transport falhou', { err: error }),\n });\n const registry = createCommandRegistry({ onChange: () => catalog.changed() });\n // Rotas da sessão no servidor do processo (ADR 0076); só entram nele no start().\n const http = config.http === undefined ? undefined : sessionHttp(config.http, session, getLog);\n let resolvedTransport: Transport | undefined;\n const transport = resolveTransport(config.transport, {\n session,\n auth,\n log: createDeferredLogger(() => transportLog ?? log),\n commands: catalog.commands,\n ...(http && {\n http: http.scope(\n TRANSPORT_ROUTE_OWNER,\n () => {\n if (resolvedTransport === undefined) {\n throw new Error('http.basePath: leia depois que a fábrica devolver o transport');\n }\n return `/transports/${encodeURIComponent(resolvedTransport.name)}`;\n },\n (error, route) => log.error(`rota ${route} do transport falhou`, { err: error }),\n ),\n }),\n });\n resolvedTransport = transport;\n // O transport registra rotas na fábrica; publicadas no start(), retiradas no stop.\n let httpAttached = false;\n let releaseSession: ReleaseSession | undefined;\n // Trava da sessão entre processos (ADR 0074); só existe com storage que a implementa.\n let sessionLease: SessionLease | undefined;\n // O `stop()` durante o `start()` aborta a espera pela trava em vez de esperar a validade.\n const bootAbort = new AbortController();\n // `connect()` já foi chamado: só então o shutdown desconecta.\n let connectCalled = false;\n // Desfaz a assinatura dos eventos do transport; existe depois que o start() a fez.\n let unsubscribe: (() => void) | undefined;\n const timeouts = config.timeouts ?? {};\n const commandTimeoutMs = timeouts.commandMs ?? DEFAULT_COMMAND_TIMEOUT_MS;\n\n // Prazos de comando, papel, consulta de admin e listener: o shutdown desarma os de handlers\n // presos (`abandonInternals`).\n const armed = new ArmedTimers();\n // `run` de comandos com `background: true` em andamento (ADR 0087): fora da fila do chat, mas\n // dentro do `settled()`. O shutdown os solta (`abandonInternals`): quem ignora o `signal`\n // abortado e tem o prazo desarmado nunca assenta.\n const background = new Set<Promise<void>>();\n const backgroundWaiters: (() => void)[] = [];\n const releaseBackgroundWaiters = (): void => {\n for (const resolve of backgroundWaiters.splice(0)) resolve();\n };\n const trackBackground = (task: Promise<void>): void => {\n background.add(task);\n void task.finally(() => {\n background.delete(task);\n if (background.size === 0) releaseBackgroundWaiters();\n });\n };\n const backgroundIdle = (): Promise<void> =>\n background.size === 0\n ? Promise.resolve()\n : new Promise((resolve) => backgroundWaiters.push(resolve));\n const bus = createEventBus({\n listenerTimeoutMs: timeouts.listenerMs,\n armed,\n onError: (event) => logPluginError(event),\n });\n const services = createServiceRegistry();\n const prefixes = createPrefixStore(config.prefix, scoped);\n const router = createCommandRouter({\n registry,\n prefix: (chat) => prefixes.get(chat),\n selfUsername: () => transport.self?.username,\n owners: normalizeOwners(config.owners ?? []),\n isGroupAdmin: groupAdminPort(\n transport,\n commandTimeoutMs,\n (error) => log.warn('consulta de admin do grupo falhou depois do prazo', { err: error }),\n armed,\n ),\n // O comando é recusado de todo jeito (fail-closed); o log diz ao autor o que falta.\n onUnknownRole: (role, command) =>\n log.error(\n `comando \"${command.name}\" exige o papel \"${role}\", que nenhum plugin carregado define: ` +\n `declare dependsOn no plugin dono do papel (em \"${command.plugin}\")`,\n { plugin: command.plugin, command: command.name, role },\n ),\n });\n const conversations = new ConversationRegistry<KernelMessageContext>();\n // O menu numerado espera a resposta pelo mesmo registro dos plugins, então um comando digitado\n // ou outra espera também o cancelam. O passo nunca roda: o `dispatchMessage` trata a escolha.\n conversations.define(MENU_OWNER, MENU_STEP, () => undefined);\n const actions = new ActionRegistry();\n // Mensagem montada pelo kernel a partir de um clique ou comando nativo -> a interação de origem,\n // para o `ctx.unsafe.raw()` pedir ao transport o objeto bruto dela (ADR 0066). Por bot, e some\n // com a mensagem.\n const interactions = new WeakMap<Message, Interaction>();\n const buttons = hasCapability(transport, 'actions');\n const maxButtons = buttonLimit(transport);\n const pipeline = createPipeline(\n config.middlewares ?? {},\n timeouts.middlewareMs ?? DEFAULT_MIDDLEWARE_TIMEOUT_MS,\n getLog,\n );\n // Os mesmos filtros, para os eventos que não passam pelo pipeline (ADR 0038).\n const chatFilterOptions = config.middlewares?.chatFilter;\n const chatIsAllowed = chatFilterOptions ? chatAllowed(chatFilterOptions) : () => true;\n const dropsSelf = config.middlewares?.ignoreSelf !== false;\n const dropsBots = config.middlewares?.ignoreBots !== false;\n const inbound = new InboundQueue({\n maxPendingPerChat: config.inbound?.maxPendingPerChat,\n onError: (error, chatId) => log.error('falha ao processar mensagem', { chatId, err: error }),\n });\n const outbound = new OutboundQueue({\n onTypingError: (error, chatId) =>\n log.debug('falha ao enviar \"digitando\"', { chatId, err: error }),\n ...config.outbound,\n transport,\n });\n // O plugin vê o envio e as ações (ADR 0040): a fila (close, stats) fica com o kernel.\n const send = createOutbound(outbound, transport);\n const groups = createGroups(transport, enqueueAction(outbound, transport));\n // Cópia: o plugin recebe um `ReadonlySet`, mas um cast não deve alterar o do transport.\n const capabilities: ReadonlySet<Capability> = new Set(transport.capabilities);\n // Tenant da mensagem ou do evento em andamento (ADR 0072): o storage dos plugins e os jobs\n // agendados seguem ele.\n const tenants = new TenantScope();\n const scheduler = createSchedulerService({\n storage: scoped,\n tenants,\n jobTimeoutMs: timeouts.jobMs,\n onError: (event) => {\n logPluginError(event);\n void bus.emit('plugin.error', event);\n },\n onLateError: (event) => logPluginError(event),\n onStorageError: (error) => log.error('scheduler: falha no storage', { err: error }),\n });\n const contextDeps: MessageContextDeps = {\n sender: send,\n quote: hasCapability(transport, 'quoted'),\n reactions: hasCapability(transport, 'reactions'),\n log: getLog,\n actions: prepareActions,\n };\n const reconnector: Reconnector | undefined =\n config.reconnection === false\n ? undefined\n : createReconnector({\n transport,\n log: getLog,\n options: {\n ...config.reconnection,\n // Com fábrica, o auth do transport é o do bot: o kernel sabe limpá-lo sozinho. Com\n // instância pronta, não sabe onde estão as credenciais.\n clearSession:\n config.reconnection?.clearSession ??\n (typeof config.transport === 'function' ? () => auth.clear() : undefined),\n },\n pairing: hasCapability(transport, 'pairing'),\n giveUp: () => {\n // Chamado de dentro de um handler do transport: o stop corre em paralelo.\n bot.stop().catch((error: unknown) => log.error('falha ao parar o bot', { err: error }));\n },\n });\n\n let host: PluginHost | undefined;\n let configs: PluginConfigs | undefined;\n let booted = false;\n // Mensagens que chegam enquanto os plugins sobem esperam aqui; `false` = boot abortado. Só a\n // primeira chamada vale: depois de pronto, o shutdown drena o que a fila já aceitou.\n let ready = false;\n let settleReady: (ok: boolean) => void = () => undefined;\n const readyPromise = new Promise<boolean>((resolve) => {\n settleReady = (ok) => {\n settleReady = () => undefined;\n ready = ok;\n resolve(ok);\n };\n });\n\n function logPluginError(event: PluginErrorEvent): void {\n log.error(`plugin \"${event.plugin}\" falhou (${event.phase})`, {\n plugin: event.plugin,\n phase: event.phase,\n event: event.event,\n timedOut: event.timedOut,\n err: event.error,\n });\n }\n\n /** Erros de ciclo de vida do host viram `plugin.error` (o host já os logou). */\n function emitLifecycleError(error: PluginLifecycleError): void {\n const phase = error.phase === 'context' || error.phase === 'setup' ? 'setup' : 'teardown';\n void bus.emit('plugin.error', {\n plugin: error.plugin,\n phase,\n event: null,\n error: error.cause ?? error,\n timedOut: error.timedOut,\n });\n }\n\n // --- Fluxo de uma mensagem (plano §5.3) -------------------------------------------------\n\n /**\n * Barreiras comuns à mensagem nova e à edição: espera o fim do boot e roda os middlewares em\n * volta de `handle`, que só roda se a mensagem atravessar a cadeia. A volta da cebola espera\n * `handle` terminar (ADR 0012).\n */\n async function admit(\n message: Message,\n handle: (ctx: KernelMessageContext) => Promise<void>,\n ): Promise<void> {\n if (!ready && !(await readyPromise)) return;\n await pipeline.run(createMessageContext(message, contextDeps), handle);\n }\n\n function handleMessage(message: Message): Promise<void> {\n return admit(message, dispatchMessage);\n }\n\n async function dispatchMessage(ctx: KernelMessageContext): Promise<void> {\n const { message } = ctx;\n // A espera vem antes do roteador (ADR 0060). Retirada aqui de todo jeito: um comando digitado\n // no meio da conversa a cancela e segue para o roteador.\n const pending = conversations.take(message.chat.id, message.sender.id);\n if (pending !== undefined && router.match(message, ctx.text) === null) {\n if (pending.plugin !== MENU_OWNER) {\n await runStep(ctx, pending);\n return;\n }\n // Um número do menu roda a ação, como o clique; outro texto segue o fluxo normal (ADR 0062).\n const target = menuChoice(ctx, pending.data);\n if (target !== undefined) {\n await runAction(ctx, target);\n return;\n }\n }\n const result = await router.dispatch(ctx);\n if (!result.consumed) {\n await bus.emit('message', message, listenerExtras(ctx));\n return;\n }\n await afterCommand(ctx, result);\n }\n\n /** Recusa, falha e evento `command` do comando que consumiu a mensagem ou o clique. */\n async function afterCommand(\n ctx: KernelMessageContext,\n result: Extract<DispatchResult, { readonly consumed: true }>,\n ): Promise<void> {\n const { message } = ctx;\n if (result.status === 'background') {\n // O chat já está livre; a falha e o `command` saem quando o `run` terminar (ADR 0087).\n trackBackground(\n result.done\n .then((outcome) => afterCommand(ctx, outcome))\n .catch((error: unknown) =>\n ctx.log.error('falha ao concluir o comando em segundo plano', {\n plugin: result.command.plugin,\n command: result.command.name,\n err: error,\n }),\n ),\n );\n return;\n }\n if (result.status === 'rejected' && result.reply !== null) {\n // Sem await: a resposta espera a taxa da fila de saída, e o chat não precisa esperar.\n ctx.reply(result.reply).catch((error: unknown) =>\n ctx.log.warn('falha ao enviar a recusa do comando', {\n plugin: result.command.plugin,\n command: result.command.name,\n err: error,\n }),\n );\n } else if (result.status === 'failed') {\n const event: PluginErrorEvent = {\n plugin: result.command.plugin,\n phase: 'command',\n event: result.command.name,\n error: result.error,\n timedOut:\n result.error instanceof CommandTimeoutError ||\n result.error instanceof GroupAdminTimeoutError,\n };\n logPluginError(event);\n void bus.emit('plugin.error', event);\n }\n // Com await, como o `message`: o observador segura o chat e entra no `settled()` (ADR 0049).\n const { plugin, name, invokedAs } = result.command;\n await bus.emit('command', { plugin, name, invokedAs, status: result.status, message });\n }\n\n /**\n * Roda o passo que esperava esta mensagem. Ela para aqui: não vai ao roteador, a `message` nem\n * a `command`. A falha vira `plugin.error` com `phase: 'step'`.\n */\n async function runStep(\n ctx: KernelMessageContext,\n pending: PendingReply<KernelMessageContext>,\n ): Promise<void> {\n try {\n await pending.run(ctx, pending.data);\n } catch (error) {\n const event: PluginErrorEvent = {\n plugin: pending.plugin,\n phase: 'step',\n event: pending.step,\n error,\n timedOut: error instanceof StepTimeoutError,\n };\n logPluginError(event);\n void bus.emit('plugin.error', event);\n }\n }\n\n // --- Ações e botões (ADR 0062) -------------------------------------------------------------\n\n /**\n * Resolve as ações de um `reply`: guarda o alvo de cada uma sob um ID e devolve os botões ou,\n * sem a capability ou acima do limite, o texto com o menu numerado e a espera do remetente.\n */\n function prepareActions(owner: string | null, message: Message): PrepareActions {\n return (text, list) => {\n const targets = list.map((action) => actionTarget(owner, action));\n const chatId = message.chat.id;\n const ids = targets.map((target) => actions.register(chatId, target));\n const labels = targets.map(({ label }) => label);\n if (buttons && ids.length <= maxButtons) {\n return { text, actions: ids.map((id, index) => ({ id, label: labels[index] as string })) };\n }\n conversations.expect(MENU_OWNER, chatId, message.sender.id, MENU_STEP, { data: ids });\n return { text: numberedMenu(text, labels) };\n };\n }\n\n /** Valida a ação e devolve o alvo: o erro sai na chamada do `reply`, não no clique. */\n function actionTarget(owner: string | null, action: MessageAction): ActionTarget {\n const label: unknown = action?.label;\n if (typeof label !== 'string' || label.trim().length === 0) {\n throw new TypeError('ação sem `label`');\n }\n if ('command' in action) {\n if (router.registry.find(action.command) === undefined) {\n throw new TypeError(`ação \"${label}\": comando \"${action.command}\" não registrado`);\n }\n return {\n kind: 'command',\n label,\n command: action.command,\n args: Object.freeze([...(action.args ?? [])]),\n };\n }\n if ('step' in action) {\n if (owner === null) {\n throw new TypeError(`ação \"${label}\": passo só no contexto de um plugin`);\n }\n if (conversations.find(owner, action.step) === undefined) {\n throw new TypeError(\n `ação \"${label}\": plugin \"${owner}\" sem o passo \"${action.step}\"; defina-o com ` +\n 'ctx.conversations.define',\n );\n }\n return { kind: 'step', label, plugin: owner, step: action.step, data: action.data ?? null };\n }\n throw new TypeError(`ação \"${label}\" sem \\`command\\` nem \\`step\\``);\n }\n\n /** O alvo que a resposta ao menu numerado escolhe, se ela for um número da lista. */\n function menuChoice(ctx: KernelMessageContext, data: unknown): ActionTarget | undefined {\n const ids = data as readonly string[];\n const index = pickChoice(ctx.text, ids.length);\n if (index === null) return undefined;\n return actions.resolve(ids[index] as string, ctx.message.chat.id);\n }\n\n /**\n * O clique num botão: passa pela fila do chat e pelos middlewares como uma mensagem de texto com\n * o `label`, e roda o comando ou o passo da ação. Vencido, desconhecido ou de outro chat, é\n * descartado.\n */\n async function handleInteraction(interaction: Interaction): Promise<void> {\n if (interaction.command !== undefined) return handleNativeCommand(interaction);\n const { chat, sender, actionId } = interaction;\n const target = actions.resolve(actionId, chat.id);\n if (target === undefined) {\n log.debug('clique em botão vencido ou desconhecido; descartado', { chatId: chat.id });\n return;\n }\n const message = createMessage({\n type: 'text',\n id: interaction.id,\n chat,\n sender,\n text: target.label,\n timestamp: interaction.timestamp,\n fromMe: false,\n });\n interactions.set(message, interaction);\n await admit(message, async (ctx) => {\n // O clique é um comando: cancela a espera do remetente, como o comando digitado (ADR 0060).\n conversations.take(chat.id, sender.id);\n await runAction(ctx, target);\n });\n }\n\n /**\n * Comando nativo da plataforma (ADR 0064): roda como o clique num botão de comando, com o texto\n * livre interpretado como o que vem depois do comando digitado.\n */\n async function handleNativeCommand(interaction: CommandInteraction): Promise<void> {\n const { chat, sender, command, args } = interaction;\n const message = createMessage({\n type: 'text',\n id: interaction.id,\n chat,\n sender,\n // O texto que a plataforma mostra para o comando: quem lê a mensagem (middlewares, log) vê\n // o que a pessoa chamou.\n text: args.trim() === '' ? `/${command}` : `/${command} ${args.trimStart()}`,\n timestamp: interaction.timestamp,\n fromMe: false,\n });\n interactions.set(message, interaction);\n await admit(message, async (ctx) => {\n // Comando cancela a espera do remetente, como o digitado (ADR 0060).\n conversations.take(chat.id, sender.id);\n const result = await router.dispatch(ctx, { command, rawArgs: args });\n if (!result.consumed) {\n ctx.log.debug('comando nativo que não existe mais; descartado', { command });\n return;\n }\n await afterCommand(ctx, result);\n });\n }\n\n /** Roda o alvo da ação. Comando ou passo que não existe mais (plugin desligado) é descartado. */\n async function runAction(ctx: KernelMessageContext, target: ActionTarget): Promise<void> {\n if (target.kind === 'command') {\n const result = await router.dispatch(ctx, { command: target.command, args: target.args });\n if (!result.consumed) {\n ctx.log.debug('botão de comando que não existe mais; descartado', {\n command: target.command,\n });\n return;\n }\n await afterCommand(ctx, result);\n return;\n }\n const run = conversations.find(target.plugin, target.step);\n if (run === undefined) {\n ctx.log.debug('botão de passo que não existe mais; descartado', {\n plugin: target.plugin,\n step: target.step,\n });\n return;\n }\n await runStep(ctx, { plugin: target.plugin, step: target.step, data: target.data, run });\n }\n\n /** Extras dos eventos de mensagem: os campos chegam aos listeners pela visão de cada plugin. */\n function listenerExtras(ctx: KernelMessageContext): ListenerExtras<'message'> {\n return messageExtras(ctx) as unknown as ListenerExtras<'message'>;\n }\n\n /**\n * Edição passa pelas mesmas barreiras da mensagem nova (fila do chat, boot, middlewares — o\n * `rateLimit` a conta), mas não dispara comando: só os listeners de `message.edited`.\n */\n function handleEdited(message: Message): Promise<void> {\n return admit(message, async (ctx) => {\n await bus.emit('message.edited', ctx.message, listenerExtras(ctx));\n });\n }\n\n /**\n * Põe a mensagem (nova ou editada) ou o clique na fila do chat dele: o mesmo chat anda em\n * série. A tarefa roda no escopo do tenant do chat (ADR 0072).\n */\n function enqueue<T extends Message | Interaction>(\n item: T,\n handle: (item: T) => Promise<void>,\n ): void {\n const result = inbound.enqueue(item.chat.id, () =>\n tenants.run(item.chat.tenantId, () => handle(item)),\n );\n if (result !== 'queued') {\n log.warn('mensagem descartada pela fila de entrada', {\n chatId: item.chat.id,\n messageId: item.id,\n reason: result,\n });\n }\n }\n\n /**\n * Repassa um evento que não é mensagem ao barramento, depois do `chatFilter`, do `ignoreSelf` e\n * do `ignoreBots` (ADR 0038). Durante o boot, espera os plugins subirem; sem fila do chat.\n */\n function forward<E extends DirectEvent>(event: E): () => void {\n const origin = DIRECT_EVENTS[event];\n return transport.on(event, (transportPayload) => {\n // `BotEvents` estende `TransportEvents`: o payload é o mesmo tipo.\n const payload = transportPayload as BotEvents[E];\n const { chat, fromMe, fromBot } = origin(payload);\n if ((fromMe && dropsSelf) || (fromBot && dropsBots)) return;\n if (chat !== null && !chatIsAllowed(chat)) return;\n // Os listeners rodam no escopo do tenant do chat (ADR 0072). Ele vem do payload, não da\n // origem: entrada e saída do grupo passam pelo filtro sem chat, mas são de um tenant.\n const tenant = 'chat' in payload ? payload.chat.tenantId : undefined;\n tenants.run(tenant, () => {\n if (ready) {\n void bus.emit(event, payload);\n return;\n }\n // Boot abortado ou `stop()` antes do fim: o evento é descartado, como a mensagem.\n void readyPromise.then((ok) => {\n if (ok) void bus.emit(event, payload);\n });\n });\n });\n }\n\n /** Assina todos os eventos do transport; devolve a função que desfaz. */\n function subscribeTransport(): () => void {\n const offs: (() => void)[] = [\n transport.on('message', (message) => enqueue(message, handleMessage)),\n transport.on('message.edited', (message) => enqueue(message, handleEdited)),\n transport.on('interaction', (interaction) => enqueue(interaction, handleInteraction)),\n transport.on('connection.status', (status) => {\n // Com a conexão caída, o envio falharia e esgotaria o retry antes da reconexão (#198).\n if (status.status === 'closed') outbound.pause();\n else if (status.status === 'open') outbound.resume();\n reconnector?.onStatus(status);\n void bus.emit('connection.status', status);\n }),\n transport.on('connection.qr', (payload) => {\n reconnector?.onQr();\n // Quem lê o log em info (agregador, arquivo) pareia o número com o QR enquanto ele vale:\n // o valor fica em debug e no barramento (`connection.qr`), para quem exibe a tela.\n log.info('QR de pareamento recebido; exiba-o pelo evento connection.qr');\n log.debug('valor do QR de pareamento', { qr: payload.qr });\n void bus.emit('connection.qr', payload);\n }),\n transport.on('connection.pairing-code', (payload) => {\n // Mesma tentativa de pareamento que o QR (ADR 0050), e o mesmo risco no log.\n reconnector?.onQr();\n log.info('código de pareamento recebido; exiba-o pelo evento connection.pairing-code');\n log.debug('valor do código de pareamento', { code: payload.code });\n void bus.emit('connection.pairing-code', payload);\n }),\n ];\n for (const event of Object.keys(DIRECT_EVENTS) as DirectEvent[]) offs.push(forward(event));\n return () => {\n for (const off of offs.splice(0)) off();\n };\n }\n\n // --- Boot ---------------------------------------------------------------------------------\n\n /**\n * Ganchos internos, empilhados para o LIFO rodar na ordem do shutdown (docs/bot.md). Estourado\n * o prazo, cada um abandona o que falta (o `signal` aborta) em vez de seguir em segundo plano.\n */\n function registerInternalHooks(): void {\n const push = (name: string, timeoutMs: number, hook: StopHook): void => {\n hooks.push({ name, timeoutMs, hook });\n };\n push('fila-de-saida', STOP_TIMEOUTS.outbound, (signal) => {\n // Conexão caída: o gancho do transporte já parou a reconexão, então drenar só gastaria o\n // prazo. Descarta já (ADR 0039).\n if (outbound.paused) return outbound.close({ drain: false });\n // Drena até o prazo; estourado, descarta o que aguarda (docs/outbound-queue.md).\n signal.addEventListener('abort', () => void outbound.close({ drain: false }), {\n once: true,\n });\n return outbound.close();\n });\n // Desce depois do scheduler: o teardown não corre junto com um job do próprio plugin.\n push('plugins', STOP_TIMEOUTS.plugins, async (signal) => {\n const errors = (await host?.stop(signal)) ?? [];\n if (errors.length > 0) {\n throw new AggregateError(errors, `teardown: ${errors.length} falha(s) de plugin`);\n }\n });\n push('scheduler', STOP_TIMEOUTS.scheduler, (signal) => scheduler.stop(signal));\n push('fila-de-entrada', STOP_TIMEOUTS.inbound, (signal) => {\n signal.addEventListener('abort', () => void inbound.close({ drain: false }), {\n once: true,\n });\n return inbound.close();\n });\n push('transporte', STOP_TIMEOUTS.reconnection, async () => {\n // Para de aceitar eventos (nada novo entra na fila) e de reconectar.\n unsubscribe?.();\n settleReady(false);\n await reconnector?.stop();\n });\n }\n\n /**\n * Passo obrigatório do shutdown, sem prazo: abandona o que os ganchos internos não encerraram\n * (estouraram o prazo, ou nem rodaram porque o prazo total acabou antes). Depois dele nenhum\n * timer do bot fica vivo e as filas estão fechadas; jobs abandonados ficam no storage e\n * disparam na próxima subida. Num shutdown limpo, não acha nada a fazer.\n */\n async function abandonInternals(): Promise<void> {\n if (unsubscribe === undefined) return;\n unsubscribe();\n settleReady(false);\n const aborted = AbortSignal.abort();\n // Sem await: o que resta delas é trabalho já em andamento, e nenhuma das três rejeita.\n void reconnector?.stop();\n void inbound.close({ drain: false });\n // Middleware preso na mensagem abandonada: sem isto, o timer dele viveria até o prazo.\n pipeline.close();\n await scheduler.stop(aborted);\n // Teardown pulado ou abandonado vira falha que o host loga; o `dispose` roda para todos.\n await host?.stop(aborted);\n // Depois do descarte dos plugins, que já expirou o `Deadline` dos handlers presos (o\n // `signal` aborta, o `reply` é recusado): sobra só o timer do prazo de cada um.\n armed.disarmAll();\n // Comando em segundo plano preso fica sem prazo e não assentaria: o `settled()` não o espera.\n background.clear();\n releaseBackgroundWaiters();\n // O `dispose` de cada plugin já tirou as esperas dele; isto garante que nenhum timer de TTL\n // sobreviva ao `stop()` e que um passo atrasado não registre outra.\n conversations.close();\n actions.clear();\n void outbound.close({ drain: false });\n }\n\n async function bootPlugins(): Promise<void> {\n // Antes do `setup`: um plugin pode ler o prefixo do chat já no boot.\n await prefixes.load();\n const entries = await collectPlugins({\n plugins: config.plugins,\n pluginDirs: config.pluginDirs,\n cwd: config.cwd,\n });\n configs = createPluginConfigs({\n plugins: entries.map((entry) => entry.definition),\n file: config.pluginConfig,\n storage: scoped,\n env: config.env,\n secrets,\n log,\n reload: (name) => reload(name),\n });\n const createContext = createPluginContextFactory({\n configs,\n log,\n router,\n prefixes,\n conversations,\n bus,\n services,\n storage: scoped,\n shared: sharedStorage(storage),\n tenants,\n scheduler,\n send,\n groups,\n http,\n onHttpError: (event) => {\n logPluginError(event);\n void bus.emit('plugin.error', event);\n },\n transport: {\n name: transport.name,\n capabilities,\n get self() {\n return transport.self;\n },\n },\n unsafe: createUnsafeAccess({\n transport,\n log,\n interactionOf: (message) => interactions.get(message),\n }),\n commandTimeoutMs,\n armed,\n onRoleError: (event) => {\n logPluginError(event);\n void bus.emit('plugin.error', event);\n },\n onLateCommandError: (plugin, command, error) => {\n // A recusa de um contexto expirado já foi logada quando aconteceu (ADR 0033).\n if (error instanceof ContextExpiredError) return;\n log.error(`comando \"${command}\" rejeitou depois do prazo`, {\n plugin,\n command,\n err: error,\n });\n },\n });\n const pluginHost = createPluginHost({\n plugins: entries,\n transport,\n createContext,\n log,\n disabledPlugins: config.disabledPlugins,\n setupTimeoutMs: timeouts.setupMs,\n teardownTimeoutMs: timeouts.teardownMs,\n });\n host = pluginHost;\n const table = await pluginHost.start();\n for (const entry of table) {\n if (entry.status !== 'skipped' || entry.reason.kind !== 'setup-failed') continue;\n const { error } = entry.reason;\n // Conflito de nome é erro no boot (ADR 0007 e 0035), não \"plugin ignorado\": quem\n // respondesse ao comando, papel ou serviço dependeria da ordem de carga.\n if (isBootConflict(error.cause)) throw error.cause;\n emitLifecycleError(error);\n }\n }\n\n async function reload(name: string): Promise<PluginReloadResult> {\n if (!host) throw new BotStateError(`reload(\"${name}\"): plugins ainda não carregados`, state);\n // Um aviso só ao transport, no fim: no meio, os comandos do plugin saíram e não voltaram.\n const pluginHost = host;\n const result = await catalog.batch(() => pluginHost.reload(name));\n for (const error of result.errors) emitLifecycleError(error);\n // Os dependentes recarregados em cascata (ADR 0041) também podem falhar no `setup` novo.\n for (const entry of [result.entry, ...result.dependents]) {\n if (entry.status === 'skipped' && entry.reason.kind === 'setup-failed') {\n emitLifecycleError(entry.reason.error);\n }\n }\n return result;\n }\n\n async function runStart(): Promise<void> {\n try {\n log =\n config.logger ??\n createLogger({\n level: config.logLevel ?? 'info',\n ...(config.logFormat && { format: config.logFormat }),\n secrets,\n });\n transportLog = log.child({ transport: transport.name });\n // Antes de `booted`: um bot recusado aqui não fecha o storage do bot que usa a sessão.\n releaseSession = claimSession(storage, session);\n booted = true;\n // Ligada já no boot: o `/health` mostra a sessão subindo (503) até ela ficar `running`.\n http?.attach(() => state);\n httpAttached = http !== undefined;\n if (config.storage === undefined) {\n log.warn('sem storage configurado: usando memória, os dados somem ao reiniciar');\n }\n // Sem conexão até o primeiro `open`: o `connect()` resolve ao iniciar a tentativa, e os\n // envios do setup e dos jobs vencidos iriam para um socket ainda fechado (ADR 0048). O\n // teto da pausa conta daqui.\n outbound.pause();\n unsubscribe = subscribeTransport();\n registerInternalHooks();\n // Antes dos plugins, que já gravam no storage e agendam jobs da sessão. Depois de assinar\n // os eventos: os que chegarem esperam a trava na fila do boot, como esperam os plugins.\n sessionLease = await acquireSessionLease({\n storage,\n session,\n log,\n signal: bootAbort.signal,\n onLost: () => {\n log.error('outro processo assumiu a trava da sessão; parando o bot', { session });\n bot.stop().catch((error: unknown) => log.error('falha ao parar o bot', { err: error }));\n },\n });\n } catch (error) {\n // Nada conectou ainda: só desfaz o que foi registrado.\n await shutdown().catch((cleanup: unknown) =>\n log.error('falha ao encerrar após erro no start', { err: cleanup }),\n );\n throw error;\n }\n\n // Plugins primeiro, connect depois (plano §5.3): um plugin quebrado (conflito de comando,\n // manifesto inválido, ciclo) derruba o boot antes de o transport abrir sessão — sem QR nem\n // handshake à toa.\n try {\n await bootPlugins();\n } catch (error) {\n log.error('falha ao carregar os plugins; encerrando', { err: error });\n // O transport nunca conectou: o encerramento não chama `disconnect()`.\n await failBoot(error);\n }\n // Com as rotas dos plugins e do transport registradas, abre a porta (se houver rota) antes\n // do connect: o transport pode precisar do webhook de pé para conectar. Porta ocupada derruba\n // o boot.\n try {\n await http?.listen();\n } catch (error) {\n log.error('falha ao abrir a porta HTTP; encerrando', { err: error });\n await failBoot(error);\n }\n // Daqui em diante, mudança na lista de comandos avisa o transport.\n catalog.open();\n\n // stop() chegou durante o boot: quem chamou stop() conduz o encerramento. Conferido também\n // antes do connect, para não abrir sessão (QR, handshake) só para fechá-la em seguida.\n const stoppedDuringBoot = (): BotStateError =>\n new BotStateError('start(): bot parado durante a inicialização', state);\n if (stopRequested) throw stoppedDuringBoot();\n\n // Mensagens que chegarem durante o handshake esperam na fila de entrada (`readyPromise`)\n // até o fim do boot. Conectado, uma queda já é reconectada.\n try {\n // O transport pode conectar pela metade: daqui em diante o encerramento desconecta.\n connectCalled = true;\n await callConnect(transport);\n reconnector?.activate();\n } catch (error) {\n await failBoot(error);\n }\n\n if (stopRequested) throw stoppedDuringBoot();\n scheduler.start();\n settleReady(true);\n state = 'running';\n }\n\n /** Encerra o que o boot já subiu e relança `failure` (ou o `AggregateError` com a limpeza). */\n async function failBoot(failure: unknown): Promise<never> {\n try {\n await shutdown();\n } catch (cleanupError) {\n const cleanup = cleanupError instanceof AggregateError ? cleanupError.errors : [];\n throw new AggregateError([failure, ...cleanup], 'start(): falha no boot e ao encerrar');\n }\n throw failure;\n }\n\n // --- Shutdown -----------------------------------------------------------------------------\n\n function shutdown(): Promise<void> {\n shutdownPromise ??= runShutdown();\n return shutdownPromise;\n }\n\n async function runShutdown(): Promise<void> {\n state = 'stopping';\n // O teardown tira os comandos de cada plugin: o transport não deve apagar o menu da plataforma.\n catalog.close();\n // LIFO: quem subiu por último depende de quem subiu antes, então desce primeiro.\n const errors: unknown[] = await runStopHooks(hooks.toReversed(), config.shutdown);\n hooks.length = 0;\n await abandonInternals();\n if (connectCalled) {\n try {\n await transport.disconnect();\n } catch (error) {\n errors.push(error);\n }\n }\n // Os teardowns já tiraram as rotas dos plugins; sai a do transport, e o último bot fecha a porta.\n if (httpAttached) {\n try {\n await http?.detach();\n } catch (error) {\n errors.push(error);\n }\n }\n // Storage por último: os teardowns e o scheduler ainda o usam até aqui. Se outro bot (outra\n // sessão) ainda o usa, quem fecha é o último a parar.\n // Liberada no stop limpo, a sessão sobe em outro processo na hora, sem esperar a validade.\n try {\n await sessionLease?.release();\n } catch (error) {\n errors.push(error);\n }\n const lastUser = releaseSession?.() ?? true;\n if (booted && lastUser) {\n try {\n await storage.close();\n } catch (error) {\n errors.push(error);\n }\n }\n state = 'stopped';\n if (errors.length > 0) {\n throw new AggregateError(errors, `stop(): ${errors.length} falha(s) no encerramento`);\n }\n }\n\n /**\n * As três fontes de trabalho se realimentam (o comando envia, o envio rejeitado vira\n * `plugin.error`, o listener envia de novo): repete a espera até as três estarem ociosas na\n * mesma conferência síncrona. Só roda quando chamado: o caminho da mensagem não paga nada.\n */\n async function settled(): Promise<void> {\n // Eventos diretos que chegam no boot esperam o `readyPromise` fora do barramento.\n if (state === 'starting') await readyPromise;\n while (\n !(\n inbound.stats().activeChats === 0 &&\n background.size === 0 &&\n bus.idle &&\n outbound.stats().activeChats === 0\n )\n ) {\n await inbound.onIdle();\n await backgroundIdle();\n await bus.onIdle();\n await outbound.onIdle();\n }\n }\n\n const pluginConfigs: BotPluginConfigs = {\n setOverrides: (plugin, overrides) =>\n requireConfigs('setOverrides').setOverrides(plugin, overrides),\n describe: (plugin) => requireConfigs('describe').describe(plugin),\n jsonSchema: (plugin) => requireConfigs('jsonSchema').jsonSchema(plugin),\n };\n\n function requireConfigs(method: string): PluginConfigs {\n if (!configs) {\n throw new BotStateError(`config.${method}(): plugins ainda não carregados (start)`, state);\n }\n return configs;\n }\n\n const bot: Bot = {\n get state(): BotState {\n return state;\n },\n\n config: pluginConfigs,\n\n plugins(): PluginReportEntry[] {\n return host?.report() ?? [];\n },\n\n stats(): BotStats {\n return { inbound: inbound.stats(), outbound: outbound.stats() };\n },\n\n settled,\n\n start(): Promise<void> {\n switch (state) {\n case 'idle':\n state = 'starting';\n startPromise = runStart();\n return startPromise;\n case 'starting':\n case 'running':\n return startPromise ?? Promise.resolve();\n default:\n return Promise.reject(\n new BotStateError(`start(): bot em \"${state}\" não reinicia`, state),\n );\n }\n },\n\n stop(): Promise<void> {\n switch (state) {\n case 'idle':\n return shutdown();\n case 'starting': {\n stopRequested = true;\n bootAbort.abort(new BotStateError('start(): bot parado durante a inicialização', state));\n // Espera o boot assentar (sucesso ou falha) e só então encerra; se o start já\n // encerrou por falha, `shutdown` devolve a mesma promise.\n const afterStart = (): Promise<void> => shutdown();\n stopAfterStart ??= (startPromise ?? Promise.resolve()).then(afterStart, afterStart);\n return stopAfterStart;\n }\n case 'running':\n return shutdown();\n case 'stopping':\n return stopAfterStart ?? shutdownPromise ?? Promise.resolve();\n case 'stopped':\n return Promise.resolve();\n }\n },\n\n onStop(hook: StopHook, options: StopHookOptions = {}): () => void {\n if (state === 'stopping' || state === 'stopped') {\n throw new BotStateError(`onStop(): bot em \"${state}\" não aceita ganchos`, state);\n }\n const entry: RegisteredStopHook = {\n hook,\n name: options.name ?? (hook.name || 'anonimo'),\n timeoutMs: options.timeoutMs,\n };\n hooks.push(entry);\n return () => {\n const index = hooks.indexOf(entry);\n if (index !== -1) hooks.splice(index, 1);\n };\n },\n };\n return bot;\n}\n\n/** Nome de sessão no formato de nome de plugin: vira prefixo de namespace no storage. */\n/** Erros de `setup` que derrubam o boot em vez de só ignorar o plugin. */\nconst isBootConflict = (error: unknown): boolean =>\n error instanceof CommandConflictError ||\n error instanceof RoleConflictError ||\n error instanceof ServiceConflictError;\n\nfunction validateSession(session: string): string {\n if (!PLUGIN_NAME_PATTERN.test(session)) {\n throw new BotConfigError(\n `session deve ser kebab-case minúsculo (ex.: \"atendimento\"); recebido \"${session}\"`,\n );\n }\n return session;\n}\n\n/** Instância pronta, ou a que a fábrica monta; fábrica que lança é erro de config. */\nfunction resolveTransport(transport: BotConfig['transport'], deps: TransportDeps): Transport {\n let resolved: Transport;\n if (typeof transport !== 'function') resolved = transport;\n else {\n try {\n resolved = transport(deps);\n } catch (error) {\n throw new BotConfigError('transport: a fábrica lançou ao montar o transport', {\n cause: error,\n });\n }\n }\n // Capability sem o método dela só falharia quando um plugin a usasse (ADR 0080).\n const issues = transportIssues(resolved);\n if (issues.length > 0) {\n throw new BotConfigError(`transport inválido:\\n- ${issues.join('\\n- ')}`);\n }\n return resolved;\n}\n\n/** `transport.connect()` com um throw síncrono do adapter virando rejeição. */\nfunction callConnect(transport: Transport): Promise<void> {\n try {\n return transport.connect();\n } catch (error) {\n return Promise.reject(error);\n }\n}\n\n/**\n * A consulta de admin do grupo ao transport (`role: 'group-admin'`) estourou o prazo do comando.\n * O comando não roda e sai `plugin.error` com `timedOut: true` no plugin dono do comando.\n */\nexport class GroupAdminTimeoutError extends Error {\n override readonly name = 'GroupAdminTimeoutError';\n readonly chatId: string;\n readonly timeoutMs: number;\n\n constructor(chatId: string, timeoutMs: number) {\n super(`consulta de admin do grupo \"${chatId}\" ao transport excedeu ${timeoutMs} ms`);\n this.chatId = chatId;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Porta `isGroupAdmin` do roteador, a partir do transport: o `isChatAdmin` dele, se houver, ou a\n * lista de participantes do `getGroupMetadata` (capability `groups`, ADR 0059). Com o prazo do\n * comando: uma consulta que nunca resolve seguraria o chat na fila de entrada para sempre. O\n * timer só existe para quem não é owner pedindo comando de admin num grupo.\n */\nfunction groupAdminPort(\n transport: Transport,\n timeoutMs: number,\n onLate: (error: unknown) => void,\n armed: ArmedTimers,\n): IsGroupAdmin | undefined {\n const within = <T>(work: Promise<T>, chatId: string): Promise<T> =>\n settleWithin(\n work,\n timeoutMs,\n () => new GroupAdminTimeoutError(chatId, timeoutMs),\n onLate,\n armed,\n ) as Promise<T>;\n if (transport.isChatAdmin) {\n const isChatAdmin = transport.isChatAdmin.bind(transport);\n return (chat, sender) => within(isChatAdmin(chat, sender), chat.id);\n }\n if (!hasCapability(transport, 'groups')) return undefined;\n return async (chat, sender) => {\n const metadata = await within(transport.getGroupMetadata(chat.id), chat.id);\n // Sem a lista, não há como saber: recusa (fail-closed). Transport que não lista membros\n // deve implementar `isChatAdmin`.\n if (!metadata.participants) return false;\n // Casa por id ou, quando os dois lados o têm, por telefone: o remetente e o participante\n // podem vir com IDs de espaços diferentes (no WhatsApp, LID e JID de telefone; ADR 0046).\n // Sem telefone de um lado, só o id decide (fail-closed).\n return metadata.participants.some(\n (participant) =>\n participant.isAdmin &&\n (participant.id === sender.id ||\n (sender.phone !== null && participant.phone === sender.phone)),\n );\n };\n}\n\n/** Máximo de botões por mensagem do transport (`limits.actions`); sem ele, sem limite. */\nfunction buttonLimit(transport: Transport): number {\n const limit = transport.limits?.actions;\n if (limit === undefined) return Number.POSITIVE_INFINITY;\n if (!(Number.isInteger(limit) && limit >= 1)) {\n throw new RangeError(`limits.actions do transport deve ser inteiro >= 1 (recebido: ${limit})`);\n }\n return limit;\n}\n\n/** Pipeline com os middlewares oficiais ligados pela config e os do app. */\nfunction createPipeline(\n options: BotMiddlewaresConfig,\n timeoutMs: number,\n log: () => Logger,\n): MiddlewarePipeline<KernelMessageContext> {\n // Middleware roda dentro da tarefa da fila do chat: sem prazo, um preso seguraria o chat\n // para sempre (ADR 0043).\n const pipeline = new MiddlewarePipeline<KernelMessageContext>({\n timeoutMs,\n onLateError: (error) => log().error('middleware rejeitou depois do prazo', { err: error }),\n });\n if (options.ignoreSelf !== false) {\n pipeline.use(ignoreSelf(), { priority: MIDDLEWARE_PRIORITY.ignoreSelf });\n }\n if (options.ignoreBots !== false) {\n pipeline.use(ignoreBots(), { priority: MIDDLEWARE_PRIORITY.ignoreBots });\n }\n if (options.chatFilter) {\n pipeline.use(chatFilter(options.chatFilter), { priority: MIDDLEWARE_PRIORITY.chatFilter });\n }\n if (options.rateLimit) {\n const limit = rateLimit({\n onLimited: (ctx) =>\n log().debug('mensagem barrada pelo rate limit', {\n chatId: ctx.message.chat.id,\n senderId: ctx.message.sender.id,\n }),\n ...options.rateLimit,\n });\n pipeline.use(limit, { priority: MIDDLEWARE_PRIORITY.rateLimit });\n }\n if (options.sanitize !== false) {\n pipeline.use(sanitize(options.sanitize), { priority: MIDDLEWARE_PRIORITY.sanitize });\n }\n for (const entry of options.use ?? []) {\n if (typeof entry === 'function') pipeline.use(entry);\n else pipeline.use(entry.middleware, { priority: entry.priority });\n }\n return pipeline;\n}\n"],"mappings":"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"}
|