@warlock.js/core 4.6.0 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/esm/ai/src/agent/agent-input-builder.mjs +1 -0
  3. package/esm/ai/src/agent/agent-input-builder.mjs.map +1 -1
  4. package/esm/ai/src/errors/index.mjs +1 -0
  5. package/esm/ai/src/errors/prompt-refinement-error.mjs +27 -0
  6. package/esm/ai/src/errors/prompt-refinement-error.mjs.map +1 -0
  7. package/esm/ai/src/index.mjs +2 -0
  8. package/esm/ai/src/prompts/prompts-manager.mjs +1 -1
  9. package/esm/ai/src/prompts/prompts-manager.mjs.map +1 -1
  10. package/esm/ai/src/prompts/prompts-validate.mjs +0 -0
  11. package/esm/ai/src/prompts/prompts-validate.mjs.map +1 -1
  12. package/esm/ai/src/system-prompt/index.mjs +1 -0
  13. package/esm/ai/src/system-prompt/refined-system-prompt.mjs +461 -0
  14. package/esm/ai/src/system-prompt/refined-system-prompt.mjs.map +1 -0
  15. package/esm/ai/src/system-prompt/system-prompt.mjs +19 -0
  16. package/esm/ai/src/system-prompt/system-prompt.mjs.map +1 -1
  17. package/esm/bootstrap.d.mts.map +1 -1
  18. package/esm/bootstrap.mjs +3 -1
  19. package/esm/bootstrap.mjs.map +1 -1
  20. package/esm/config/config-getter.mjs +5 -5
  21. package/esm/config/config-getter.mjs.map +1 -1
  22. package/esm/config/config-loader.mjs +2 -2
  23. package/esm/config/config-loader.mjs.map +1 -1
  24. package/esm/connectors/access-connector.mjs +2 -2
  25. package/esm/connectors/access-connector.mjs.map +1 -1
  26. package/esm/connectors/ai-connector.mjs +2 -2
  27. package/esm/connectors/ai-connector.mjs.map +1 -1
  28. package/esm/connectors/cache-connector.mjs +2 -2
  29. package/esm/connectors/cache-connector.mjs.map +1 -1
  30. package/esm/connectors/database-connector.mjs +2 -2
  31. package/esm/connectors/database-connector.mjs.map +1 -1
  32. package/esm/connectors/herald-connector.mjs +2 -2
  33. package/esm/connectors/herald-connector.mjs.map +1 -1
  34. package/esm/connectors/http-connector.mjs +7 -7
  35. package/esm/connectors/http-connector.mjs.map +1 -1
  36. package/esm/connectors/logger-connector.mjs +2 -2
  37. package/esm/connectors/logger-connector.mjs.map +1 -1
  38. package/esm/connectors/mail-connector.mjs +2 -2
  39. package/esm/connectors/mail-connector.mjs.map +1 -1
  40. package/esm/connectors/notifications-connector.mjs +2 -2
  41. package/esm/connectors/notifications-connector.mjs.map +1 -1
  42. package/esm/connectors/socket-connector.mjs +3 -3
  43. package/esm/connectors/socket-connector.mjs.map +1 -1
  44. package/esm/http/config.mjs +2 -2
  45. package/esm/http/config.mjs.map +1 -1
  46. package/esm/http/createHttpApplication.mjs +2 -2
  47. package/esm/http/createHttpApplication.mjs.map +1 -1
  48. package/esm/http/middleware/idempotency.middleware.mjs +5 -5
  49. package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
  50. package/esm/http/middleware/inject-request-context.mjs +2 -2
  51. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  52. package/esm/http/middleware/maintenance.middleware.mjs +4 -4
  53. package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
  54. package/esm/http/plugins.mjs +9 -9
  55. package/esm/http/plugins.mjs.map +1 -1
  56. package/esm/http/response.mjs +5 -5
  57. package/esm/http/response.mjs.map +1 -1
  58. package/esm/http/server.mjs +4 -4
  59. package/esm/http/server.mjs.map +1 -1
  60. package/esm/production/production-builder.mjs +24 -16
  61. package/esm/production/production-builder.mjs.map +1 -1
  62. package/esm/production/resolve-build-config.mjs +1 -1
  63. package/esm/production/resolve-build-config.mjs.map +1 -1
  64. package/esm/utils/paths.mjs +2 -2
  65. package/esm/utils/paths.mjs.map +1 -1
  66. package/esm/validation/validateAll.mjs +2 -2
  67. package/esm/validation/validateAll.mjs.map +1 -1
  68. package/esm/warlock-config/default-configurations.mjs +1 -1
  69. package/esm/warlock-config/default-configurations.mjs.map +1 -1
  70. package/esm/warlock-config/types.d.mts +3 -2
  71. package/esm/warlock-config/types.d.mts.map +1 -1
  72. package/package.json +9 -9
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.mjs","names":[],"sources":["../../../../../../../../../@warlock.js/ai/src/system-prompt/system-prompt.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport type { Placeholders } from \"../contracts/placeholders.type\";\nimport type {\n InstructionContract,\n PersonaContract,\n SystemPromptBlockContract,\n SystemPromptContract,\n SystemPromptMergeOptions,\n SystemPromptMeta,\n} from \"../contracts/system-prompt.contract\";\nimport { InvalidRequestError } from \"../errors\";\nimport { defaultPromptsManager, promptKey } from \"../prompts/prompts-manager\";\nimport type {\n PromptValidationResult,\n PromptsValidateOptions,\n} from \"../prompts/prompts-manager.type\";\nimport { Instruction } from \"./instruction\";\nimport { Persona } from \"./persona\";\n\n/**\n * Monotonic source of the internal, non-registry display id every\n * `SystemPrompt` carries. Anonymous (unnamed) prompts have nothing else to\n * identify them by; this id never feeds the registry and is never derived from\n * the wall clock, so it stays stable and order-deterministic across a run.\n */\nlet displayIdCounter = 0;\n\n/**\n * Narrow an arbitrary value to a `SystemPromptContract` — true when it exposes\n * the builder surface (`blocks` array + a callable `resolve`). Used by the\n * registry-aware `merge` overload to tell a folded contract from a raw block\n * or a registry name string, robustly across duplicate package copies.\n */\nfunction isSystemPromptContract(\n value: unknown,\n): value is SystemPromptContract {\n return (\n typeof value === \"object\" &&\n value !== null &&\n Array.isArray((value as { blocks?: unknown }).blocks) &&\n typeof (value as { resolve?: unknown }).resolve === \"function\"\n );\n}\n\n/**\n * Build the deterministic provenance label for a prompt — `name@version` when\n * it is registered, otherwise its internal display id. No random suffixes, so\n * the same source always yields the same `composedFrom` entry.\n */\nfunction provenanceLabel(prompt: SystemPromptContract): string {\n const meta = prompt.meta();\n\n if (meta?.name) {\n return promptKey(meta.name, meta.version ?? \"1\");\n }\n\n return prompt instanceof SystemPrompt ? prompt.id : \"anonymous\";\n}\n\n/**\n * Concrete `SystemPromptContract` — an immutable layered prompt builder.\n *\n * **Role.** The top-level composer for a system prompt: it holds an ordered\n * list of typed blocks (persona + instructions) and resolves the whole\n * stack into one final string when the agent is about to call the model.\n *\n * **Responsibility.**\n * - Owns: the ordered `blocks` list and the block-join rules (insertion\n * order, blank-line separator, trim).\n * - Does NOT own: how any individual block is rendered (delegated to each\n * block's `resolve()`), the placeholder syntax (delegated to\n * `renderPlaceholders`), or any knowledge of the agent, model, or\n * session consuming the resolved text.\n *\n * Blocks are discriminated by a string `type` tag (`\"persona\"` /\n * `\"instruction\"`) rather than `instanceof`, so user-supplied blocks that\n * implement `SystemPromptBlockContract` interoperate seamlessly with blocks\n * built via `ai.persona()` / `ai.instruction()` — even across duplicate\n * package copies or bundler scope boundaries.\n *\n * The builder is **immutable** — every `.persona()` / `.instruction()`\n * call returns a fresh `SystemPrompt` instance sharing nothing mutable\n * with its parent. This makes forking a base prompt into specialized\n * variants a safe, side-effect-free operation.\n *\n * Users construct via the `ai.systemPrompt()` factory — `new SystemPrompt()`\n * is not the public API (see §4.2 of code-style.md). Modeled as a class so\n * that methods live on the prototype (one copy shared across every forked\n * instance) and downstream code can branch via `instanceof SystemPrompt`.\n *\n * @example\n * // Chainable form\n * const alex = ai.persona(\"You are Alex, a TypeScript expert.\");\n * const replyIn = ai.instruction(\"Respond in {{language|English}}.\");\n *\n * const base = ai.systemPrompt().persona(alex).instruction(replyIn);\n * const arabicVariant = base.instruction(\"Prefer Arabic comments.\");\n *\n * base.resolve({ language: \"English\" });\n * arabicVariant.resolve({ language: \"Arabic\" });\n *\n * @example\n * // Array form — insertion order is preserved exactly\n * const prompt = ai.systemPrompt([\n * ai.persona(\"You are Alex, a TypeScript expert.\"),\n * ai.instruction(\"Respond in {{language|English}}.\"),\n * ]);\n */\nexport class SystemPrompt implements SystemPromptContract {\n /**\n * Internal, non-registry id for display / provenance. Stable for the life of\n * the instance; sourced from a monotonic counter, never the wall clock.\n * Anonymous prompts are identified solely by this id.\n */\n public readonly id: string;\n\n public constructor(\n public readonly blocks: readonly SystemPromptBlockContract[] = [],\n private readonly metaData?: SystemPromptMeta,\n ) {\n this.id = `prompt#${displayIdCounter++}`;\n\n // Auto-register the moment a builder acquires a name — whether through the\n // `systemPrompt(input, { name })` factory or a `.meta({ name })` rename.\n // Forks built by `persona()` / `instruction()` / `merge()` deliberately\n // drop the name (they pass no meta), so they stay anonymous and never land\n // in the registry unless explicitly re-named.\n if (metaData?.name) {\n defaultPromptsManager().register(this);\n }\n }\n\n /**\n * Read the current metadata snapshot (no argument) or derive a renamed\n * builder (with `meta`). The accessor returns `undefined` for an anonymous\n * prompt; the updater shallow-merges `meta` onto the current metadata and\n * returns a fresh builder. Naming the result registers it in `ai.prompts`.\n */\n public meta(): SystemPromptMeta | undefined;\n public meta(meta: SystemPromptMeta): SystemPromptContract;\n public meta(\n meta?: SystemPromptMeta,\n ): SystemPromptMeta | undefined | SystemPromptContract {\n if (meta === undefined) {\n return this.metaData;\n }\n\n return new SystemPrompt(this.blocks, { ...this.metaData, ...meta });\n }\n\n /**\n * Build a system prompt by reading the file at `path` once, synchronously,\n * at construction time. The file's UTF-8 contents seed a single instruction\n * block — the same semantics as the string-seed form of `systemPrompt()` —\n * so placeholders inside the file (`{{language|English}}`) resolve at\n * `resolve()` time and the result can be forked with further\n * `.persona()` / `.instruction()` calls.\n *\n * One-shot by design: the file is read exactly once here, never re-read on\n * `resolve()`. Reads are synchronous so the call stays a drop-in for the\n * synchronous `systemPrompt()` factory and the synchronous `resolve()` API.\n *\n * Throws `InvalidRequestError` when the file cannot be read (missing path,\n * permission denied) — surfacing the underlying cause so a typo in the\n * prompt path fails loudly at construction instead of silently producing an\n * empty prompt.\n *\n * @param path - Filesystem path to the prompt template file.\n *\n * @example\n * const prompt = SystemPrompt.fromFile(\"./prompts/support-agent.md\");\n *\n * const localized = prompt.instruction(\"Respond in {{language|English}}.\");\n * localized.resolve({ language: \"Arabic\" });\n */\n public static fromFile(path: string): SystemPrompt {\n let contents: string;\n\n try {\n contents = readFileSync(path, \"utf8\");\n } catch (error) {\n throw new InvalidRequestError(\n `Failed to read system prompt file \"${path}\" — ${\n error instanceof Error ? error.message : String(error)\n }`,\n { context: { path }, cause: error },\n );\n }\n\n return new SystemPrompt([new Instruction(contents)]);\n }\n\n /**\n * Return a new builder with the persona block set. If a persona already\n * exists it's replaced in place (preserving its position in `blocks`);\n * otherwise the new persona is prepended so persona-first remains the\n * default for chain-built prompts. Accepts either raw text (auto-wrapped\n * via `new Persona`) or an existing `PersonaContract` instance for reuse\n * across prompts.\n */\n public persona(value: PersonaContract | string): SystemPromptContract {\n const block = typeof value === \"string\" ? new Persona(value) : value;\n const existingIndex = this.blocks.findIndex(\n candidate => candidate.type === \"persona\",\n );\n\n if (existingIndex >= 0) {\n const next = [...this.blocks];\n next[existingIndex] = block;\n\n return new SystemPrompt(next) as this;\n }\n\n return new SystemPrompt([block, ...this.blocks]);\n }\n\n /**\n * Return a new builder with the given instruction appended. Instructions\n * render in insertion order. Accepts either raw text (auto-wrapped via\n * `new Instruction`) or an existing `InstructionContract` instance for\n * cross-prompt reuse.\n */\n public instruction(\n value: InstructionContract | string,\n ): SystemPromptContract {\n const block = typeof value === \"string\" ? new Instruction(value) : value;\n\n return new SystemPrompt([...this.blocks, block]);\n }\n\n /**\n * Fold predefined blocks, another prompt contract, or a registered prompt\n * name into this builder. Three forms share one method:\n *\n * - `merge(...blocks)` — N pre-built `ai.persona()` / `ai.instruction()`\n * blocks. A `persona` block sets/replaces the single, leading persona;\n * every other block appends in order. `base.merge(reviewer, style, lang)`\n * equals `base.persona(reviewer).instruction(style).instruction(lang)`.\n * - `merge(contract)` — another prompt; its blocks fold in (persona\n * replaces, instructions append) and `meta.composedFrom` records the\n * provenance of both sides.\n * - `merge(name, { fromVersion })` — a prompt resolved from `ai.prompts`\n * (latest version unless `fromVersion` selects another); throws\n * `InvalidRequestError` when the name / version is unregistered.\n *\n * Immutable — the original builder is untouched; passing zero blocks returns\n * an equivalent builder. The folded result is anonymous (no `name`), so it\n * is never auto-registered even though it carries `composedFrom` provenance.\n */\n public merge(\n ...blocks: readonly SystemPromptBlockContract[]\n ): SystemPromptContract;\n public merge(source: SystemPromptContract): SystemPromptContract;\n public merge(\n name: string,\n options?: SystemPromptMergeOptions,\n ): SystemPromptContract;\n public merge(\n first?:\n | SystemPromptBlockContract\n | SystemPromptContract\n | string,\n // `undefined` is part of the element union so the `merge(name, options?)`\n // overload's optional trailing `options?` (i.e. `… | undefined`) stays\n // assignable to this implementation signature.\n ...rest: readonly (\n | SystemPromptBlockContract\n | SystemPromptMergeOptions\n | undefined\n )[]\n ): SystemPromptContract {\n // Registry-name form: resolve from ai.prompts at the chosen version.\n if (typeof first === \"string\") {\n const options = rest[0] as SystemPromptMergeOptions | undefined;\n const resolved = defaultPromptsManager().get(first, options?.fromVersion);\n\n return this.mergeContract(resolved);\n }\n\n // Contract form: fold another prompt's blocks + record provenance.\n if (isSystemPromptContract(first)) {\n return this.mergeContract(first);\n }\n\n // Variadic block form (the original behavior).\n const all = [\n ...(first ? [first] : []),\n ...rest,\n ] as readonly SystemPromptBlockContract[];\n\n return this.foldBlocks(this, all);\n }\n\n /**\n * Fold an ordered list of blocks onto a starting prompt: persona blocks\n * set/replace the single leading persona; every other block appends in\n * order. The shared core of the variadic-block `merge` and the contract fold.\n */\n private foldBlocks(\n start: SystemPromptContract,\n blocks: readonly SystemPromptBlockContract[],\n ): SystemPromptContract {\n return blocks.reduce<SystemPromptContract>((prompt, block) => {\n if (block.type === \"persona\") {\n return prompt.persona(block as PersonaContract);\n }\n\n return new SystemPrompt([...prompt.blocks, block]);\n }, start);\n }\n\n /**\n * Fold another prompt contract into this one (persona replaces, instructions\n * append) and stamp the deterministic `composedFrom` provenance — this\n * prompt's existing provenance (or its own label) followed by the folded\n * source's label. The result is anonymous so it never auto-registers.\n */\n private mergeContract(\n source: SystemPromptContract,\n ): SystemPromptContract {\n const folded = this.foldBlocks(this, source.blocks);\n\n const baseProvenance =\n this.metaData?.composedFrom ??\n (this.metaData?.name ? [provenanceLabel(this)] : []);\n\n const composedFrom = [...baseProvenance, provenanceLabel(source)];\n\n // Carry forward only provenance — never the name — so the merged result is\n // a fresh anonymous prompt (immutable rename = new key; original stays).\n return new SystemPrompt(folded.blocks, { composedFrom });\n }\n\n /**\n * Resolve every block against the placeholder map, join the results with\n * blank-line separators (in insertion order), and trim. Returns an empty\n * string when no blocks are present — callers treat that as \"no system\n * message\".\n */\n public resolve(placeholders?: Placeholders): string {\n return this.blocks\n .map(block => block.resolve(placeholders))\n .join(\"\\n\\n\")\n .trim();\n }\n\n /**\n * Validate this prompt via the process-wide `ai.prompts` manager — sugar for\n * `ai.prompts.validate(this, options)`. Runs the deterministic placeholder\n * check and, when `options.judge` is supplied, the Nova-safe LLM-as-judge\n * pass. Never throws on a judge failure; `ok` tracks the deterministic\n * verdict alone.\n */\n public validate(\n options?: PromptsValidateOptions,\n ): Promise<PromptValidationResult> {\n return defaultPromptsManager().validate(this, options);\n }\n}\n\n/**\n * Public factory for `SystemPrompt`, callable directly or via its\n * `fromFile` static. Exists as a named interface so the callable signature\n * and the `fromFile` attachment travel together as one public type.\n */\nexport interface SystemPromptFactory {\n (\n input?: string | ReadonlyArray<SystemPromptBlockContract>,\n meta?: SystemPromptMeta,\n ): SystemPrompt;\n\n /**\n * Build a system prompt from a file read once at construction. Delegates\n * to {@link SystemPrompt.fromFile}, so `ai.systemPrompt.fromFile(path)` and\n * `SystemPrompt.fromFile(path)` behave identically.\n *\n * @example\n * const prompt = ai.systemPrompt.fromFile(\"./prompts/support-agent.md\");\n */\n fromFile(path: string): SystemPrompt;\n}\n\nfunction systemPromptFactory(\n input?: string | ReadonlyArray<SystemPromptBlockContract>,\n meta?: SystemPromptMeta,\n): SystemPrompt {\n if (input === undefined) {\n return new SystemPrompt([], meta);\n }\n\n if (typeof input === \"string\") {\n return new SystemPrompt([new Instruction(input)], meta);\n }\n\n return new SystemPrompt([...input], meta);\n}\n\n/**\n * Create a new immutable system-prompt builder.\n *\n * **Role.** Public factory for `SystemPrompt` — keeps user-facing code\n * free of `new` and consistent with `ai.tool()`, `ai.agent()`,\n * `ai.persona()`, `ai.instruction()`.\n *\n * Input forms:\n * - No argument → empty builder, chain `.persona()` / `.instruction()`\n * - Single string → seeded with one instruction for quick one-shot prompts\n * - Array of blocks → used verbatim, preserving insertion order\n * - `.fromFile(path)` → seeded from a file read once at construction\n *\n * Pass a second `meta` argument to name the prompt — a named prompt\n * auto-registers in `ai.prompts` under `name@version` (version defaults to the\n * next integer). Forks (`.persona()`, `.instruction()`, `.merge()`) are\n * anonymous unless re-named via `.meta({ name })`.\n *\n * @example\n * // Composed builder\n * const prompt = systemPrompt()\n * .persona(\"You are Alex, a senior TypeScript engineer.\")\n * .instruction(\"Always include working code examples.\")\n * .instruction(\"Respond in {{language|English}}.\");\n *\n * prompt.resolve({ language: \"Arabic\" });\n *\n * @example\n * // One-shot seed\n * const prompt = systemPrompt(\"Answer only with JSON matching the schema.\");\n *\n * @example\n * // From a file, read once at construction\n * const prompt = systemPrompt.fromFile(\"./prompts/support-agent.md\");\n *\n * @example\n * // Array form — fully declarative\n * const prompt = systemPrompt([\n * ai.persona(\"You are Alex.\"),\n * ai.instruction(\"Always cite sources.\"),\n * ai.instruction(\"Respond in {{language|English}}.\"),\n * ]);\n */\nexport const systemPrompt: SystemPromptFactory = Object.assign(\n systemPromptFactory,\n { fromFile: SystemPrompt.fromFile },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"system-prompt.mjs","names":[],"sources":["../../../../../../../../../@warlock.js/ai/src/system-prompt/system-prompt.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport type { Placeholders } from \"../contracts/placeholders.type\";\nimport type {\n InstructionContract,\n PersonaContract,\n RefinedSystemPromptContract,\n RefinedSystemPromptOptions,\n SystemPromptBlockContract,\n SystemPromptContract,\n SystemPromptMergeOptions,\n SystemPromptMeta,\n} from \"../contracts/system-prompt.contract\";\nimport { InvalidRequestError } from \"../errors\";\nimport { defaultPromptsManager, promptKey } from \"../prompts/prompts-manager\";\nimport type {\n PromptValidationResult,\n PromptsValidateOptions,\n} from \"../prompts/prompts-manager.type\";\nimport { Instruction } from \"./instruction\";\nimport { Persona } from \"./persona\";\nimport { RefinedSystemPrompt } from \"./refined-system-prompt\";\n\n/**\n * Monotonic source of the internal, non-registry display id every\n * `SystemPrompt` carries. Anonymous (unnamed) prompts have nothing else to\n * identify them by; this id never feeds the registry and is never derived from\n * the wall clock, so it stays stable and order-deterministic across a run.\n */\nlet displayIdCounter = 0;\n\n/**\n * Narrow an arbitrary value to a `SystemPromptContract` — true when it exposes\n * the builder surface (`blocks` array + a callable `resolve`). Used by the\n * registry-aware `merge` overload to tell a folded contract from a raw block\n * or a registry name string, robustly across duplicate package copies.\n */\nfunction isSystemPromptContract(\n value: unknown,\n): value is SystemPromptContract {\n return (\n typeof value === \"object\" &&\n value !== null &&\n Array.isArray((value as { blocks?: unknown }).blocks) &&\n typeof (value as { resolve?: unknown }).resolve === \"function\"\n );\n}\n\n/**\n * Build the deterministic provenance label for a prompt — `name@version` when\n * it is registered, otherwise its internal display id. No random suffixes, so\n * the same source always yields the same `composedFrom` entry.\n */\nfunction provenanceLabel(prompt: SystemPromptContract): string {\n const meta = prompt.meta();\n\n if (meta?.name) {\n return promptKey(meta.name, meta.version ?? \"1\");\n }\n\n return prompt instanceof SystemPrompt ? prompt.id : \"anonymous\";\n}\n\n/**\n * Concrete `SystemPromptContract` — an immutable layered prompt builder.\n *\n * **Role.** The top-level composer for a system prompt: it holds an ordered\n * list of typed blocks (persona + instructions) and resolves the whole\n * stack into one final string when the agent is about to call the model.\n *\n * **Responsibility.**\n * - Owns: the ordered `blocks` list and the block-join rules (insertion\n * order, blank-line separator, trim).\n * - Does NOT own: how any individual block is rendered (delegated to each\n * block's `resolve()`), the placeholder syntax (delegated to\n * `renderPlaceholders`), or any knowledge of the agent, model, or\n * session consuming the resolved text.\n *\n * Blocks are discriminated by a string `type` tag (`\"persona\"` /\n * `\"instruction\"`) rather than `instanceof`, so user-supplied blocks that\n * implement `SystemPromptBlockContract` interoperate seamlessly with blocks\n * built via `ai.persona()` / `ai.instruction()` — even across duplicate\n * package copies or bundler scope boundaries.\n *\n * The builder is **immutable** — every `.persona()` / `.instruction()`\n * call returns a fresh `SystemPrompt` instance sharing nothing mutable\n * with its parent. This makes forking a base prompt into specialized\n * variants a safe, side-effect-free operation.\n *\n * Users construct via the `ai.systemPrompt()` factory — `new SystemPrompt()`\n * is not the public API (see §4.2 of code-style.md). Modeled as a class so\n * that methods live on the prototype (one copy shared across every forked\n * instance) and downstream code can branch via `instanceof SystemPrompt`.\n *\n * @example\n * // Chainable form\n * const alex = ai.persona(\"You are Alex, a TypeScript expert.\");\n * const replyIn = ai.instruction(\"Respond in {{language|English}}.\");\n *\n * const base = ai.systemPrompt().persona(alex).instruction(replyIn);\n * const arabicVariant = base.instruction(\"Prefer Arabic comments.\");\n *\n * base.resolve({ language: \"English\" });\n * arabicVariant.resolve({ language: \"Arabic\" });\n *\n * @example\n * // Array form — insertion order is preserved exactly\n * const prompt = ai.systemPrompt([\n * ai.persona(\"You are Alex, a TypeScript expert.\"),\n * ai.instruction(\"Respond in {{language|English}}.\"),\n * ]);\n */\nexport class SystemPrompt implements SystemPromptContract {\n /**\n * Internal, non-registry id for display / provenance. Stable for the life of\n * the instance; sourced from a monotonic counter, never the wall clock.\n * Anonymous prompts are identified solely by this id.\n */\n public readonly id: string;\n\n public constructor(\n public readonly blocks: readonly SystemPromptBlockContract[] = [],\n private readonly metaData?: SystemPromptMeta,\n ) {\n this.id = `prompt#${displayIdCounter++}`;\n\n // Auto-register the moment a builder acquires a name — whether through the\n // `systemPrompt(input, { name })` factory or a `.meta({ name })` rename.\n // Forks built by `persona()` / `instruction()` / `merge()` deliberately\n // drop the name (they pass no meta), so they stay anonymous and never land\n // in the registry unless explicitly re-named.\n if (metaData?.name) {\n defaultPromptsManager().register(this);\n }\n }\n\n /**\n * Read the current metadata snapshot (no argument) or derive a renamed\n * builder (with `meta`). The accessor returns `undefined` for an anonymous\n * prompt; the updater shallow-merges `meta` onto the current metadata and\n * returns a fresh builder. Naming the result registers it in `ai.prompts`.\n */\n public meta(): SystemPromptMeta | undefined;\n public meta(meta: SystemPromptMeta): SystemPromptContract;\n public meta(\n meta?: SystemPromptMeta,\n ): SystemPromptMeta | undefined | SystemPromptContract {\n if (meta === undefined) {\n return this.metaData;\n }\n\n return new SystemPrompt(this.blocks, { ...this.metaData, ...meta });\n }\n\n /**\n * Build a system prompt by reading the file at `path` once, synchronously,\n * at construction time. The file's UTF-8 contents seed a single instruction\n * block — the same semantics as the string-seed form of `systemPrompt()` —\n * so placeholders inside the file (`{{language|English}}`) resolve at\n * `resolve()` time and the result can be forked with further\n * `.persona()` / `.instruction()` calls.\n *\n * One-shot by design: the file is read exactly once here, never re-read on\n * `resolve()`. Reads are synchronous so the call stays a drop-in for the\n * synchronous `systemPrompt()` factory and the synchronous `resolve()` API.\n *\n * Throws `InvalidRequestError` when the file cannot be read (missing path,\n * permission denied) — surfacing the underlying cause so a typo in the\n * prompt path fails loudly at construction instead of silently producing an\n * empty prompt.\n *\n * @param path - Filesystem path to the prompt template file.\n *\n * @example\n * const prompt = SystemPrompt.fromFile(\"./prompts/support-agent.md\");\n *\n * const localized = prompt.instruction(\"Respond in {{language|English}}.\");\n * localized.resolve({ language: \"Arabic\" });\n */\n public static fromFile(path: string): SystemPrompt {\n let contents: string;\n\n try {\n contents = readFileSync(path, \"utf8\");\n } catch (error) {\n throw new InvalidRequestError(\n `Failed to read system prompt file \"${path}\" — ${\n error instanceof Error ? error.message : String(error)\n }`,\n { context: { path }, cause: error },\n );\n }\n\n return new SystemPrompt([new Instruction(contents)]);\n }\n\n /**\n * Return a new builder with the persona block set. If a persona already\n * exists it's replaced in place (preserving its position in `blocks`);\n * otherwise the new persona is prepended so persona-first remains the\n * default for chain-built prompts. Accepts either raw text (auto-wrapped\n * via `new Persona`) or an existing `PersonaContract` instance for reuse\n * across prompts.\n */\n public persona(value: PersonaContract | string): SystemPromptContract {\n const block = typeof value === \"string\" ? new Persona(value) : value;\n const existingIndex = this.blocks.findIndex(\n candidate => candidate.type === \"persona\",\n );\n\n if (existingIndex >= 0) {\n const next = [...this.blocks];\n next[existingIndex] = block;\n\n return new SystemPrompt(next) as this;\n }\n\n return new SystemPrompt([block, ...this.blocks]);\n }\n\n /**\n * Return a new builder with the given instruction appended. Instructions\n * render in insertion order. Accepts either raw text (auto-wrapped via\n * `new Instruction`) or an existing `InstructionContract` instance for\n * cross-prompt reuse.\n */\n public instruction(\n value: InstructionContract | string,\n ): SystemPromptContract {\n const block = typeof value === \"string\" ? new Instruction(value) : value;\n\n return new SystemPrompt([...this.blocks, block]);\n }\n\n /**\n * Fold predefined blocks, another prompt contract, or a registered prompt\n * name into this builder. Three forms share one method:\n *\n * - `merge(...blocks)` — N pre-built `ai.persona()` / `ai.instruction()`\n * blocks. A `persona` block sets/replaces the single, leading persona;\n * every other block appends in order. `base.merge(reviewer, style, lang)`\n * equals `base.persona(reviewer).instruction(style).instruction(lang)`.\n * - `merge(contract)` — another prompt; its blocks fold in (persona\n * replaces, instructions append) and `meta.composedFrom` records the\n * provenance of both sides.\n * - `merge(name, { fromVersion })` — a prompt resolved from `ai.prompts`\n * (latest version unless `fromVersion` selects another); throws\n * `InvalidRequestError` when the name / version is unregistered.\n *\n * Immutable — the original builder is untouched; passing zero blocks returns\n * an equivalent builder. The folded result is anonymous (no `name`), so it\n * is never auto-registered even though it carries `composedFrom` provenance.\n */\n public merge(\n ...blocks: readonly SystemPromptBlockContract[]\n ): SystemPromptContract;\n public merge(source: SystemPromptContract): SystemPromptContract;\n public merge(\n name: string,\n options?: SystemPromptMergeOptions,\n ): SystemPromptContract;\n public merge(\n first?:\n | SystemPromptBlockContract\n | SystemPromptContract\n | string,\n // `undefined` is part of the element union so the `merge(name, options?)`\n // overload's optional trailing `options?` (i.e. `… | undefined`) stays\n // assignable to this implementation signature.\n ...rest: readonly (\n | SystemPromptBlockContract\n | SystemPromptMergeOptions\n | undefined\n )[]\n ): SystemPromptContract {\n // Registry-name form: resolve from ai.prompts at the chosen version.\n if (typeof first === \"string\") {\n const options = rest[0] as SystemPromptMergeOptions | undefined;\n const resolved = defaultPromptsManager().get(first, options?.fromVersion);\n\n return this.mergeContract(resolved);\n }\n\n // Contract form: fold another prompt's blocks + record provenance.\n if (isSystemPromptContract(first)) {\n return this.mergeContract(first);\n }\n\n // Variadic block form (the original behavior).\n const all = [\n ...(first ? [first] : []),\n ...rest,\n ] as readonly SystemPromptBlockContract[];\n\n return this.foldBlocks(this, all);\n }\n\n /**\n * Fold an ordered list of blocks onto a starting prompt: persona blocks\n * set/replace the single leading persona; every other block appends in\n * order. The shared core of the variadic-block `merge` and the contract fold.\n */\n private foldBlocks(\n start: SystemPromptContract,\n blocks: readonly SystemPromptBlockContract[],\n ): SystemPromptContract {\n return blocks.reduce<SystemPromptContract>((prompt, block) => {\n if (block.type === \"persona\") {\n return prompt.persona(block as PersonaContract);\n }\n\n return new SystemPrompt([...prompt.blocks, block]);\n }, start);\n }\n\n /**\n * Fold another prompt contract into this one (persona replaces, instructions\n * append) and stamp the deterministic `composedFrom` provenance — this\n * prompt's existing provenance (or its own label) followed by the folded\n * source's label. The result is anonymous so it never auto-registers.\n */\n private mergeContract(\n source: SystemPromptContract,\n ): SystemPromptContract {\n const folded = this.foldBlocks(this, source.blocks);\n\n const baseProvenance =\n this.metaData?.composedFrom ??\n (this.metaData?.name ? [provenanceLabel(this)] : []);\n\n const composedFrom = [...baseProvenance, provenanceLabel(source)];\n\n // Carry forward only provenance — never the name — so the merged result is\n // a fresh anonymous prompt (immutable rename = new key; original stays).\n return new SystemPrompt(folded.blocks, { composedFrom });\n }\n\n /**\n * Resolve every block against the placeholder map, join the results with\n * blank-line separators (in insertion order), and trim. Returns an empty\n * string when no blocks are present — callers treat that as \"no system\n * message\".\n */\n public resolve(placeholders?: Placeholders): string {\n return this.blocks\n .map(block => block.resolve(placeholders))\n .join(\"\\n\\n\")\n .trim();\n }\n\n /**\n * Validate this prompt via the process-wide `ai.prompts` manager — sugar for\n * `ai.prompts.validate(this, options)`. Runs the deterministic placeholder\n * check and, when `options.judge` is supplied, the Nova-safe LLM-as-judge\n * pass. Never throws on a judge failure; `ok` tracks the deterministic\n * verdict alone.\n */\n public validate(\n options?: PromptsValidateOptions,\n ): Promise<PromptValidationResult> {\n return defaultPromptsManager().validate(this, options);\n }\n\n /**\n * Derive the compiled form of this prompt — a lazy wrapper that rewrites\n * the human-authored text into a model-optimized version on first use,\n * pins the result, and serves the pin thereafter. See\n * {@link RefinedSystemPromptContract} for the full semantics (lockfile\n * pinning, placeholder parity, advisory fallback, `refine()` /\n * `refinePrompt()`).\n *\n * The wrapper's collaborators are injected here rather than imported by\n * `refined-system-prompt.ts` — importing this module (or the prompts\n * manager) back from there would close an import cycle.\n */\n public refined(\n options: RefinedSystemPromptOptions,\n ): RefinedSystemPromptContract {\n return new RefinedSystemPrompt(this, options, {\n buildPrompt: (blocks, meta) => new SystemPrompt([...blocks], meta),\n validatePrompt: (target, validateOptions) =>\n defaultPromptsManager().validate(target, validateOptions),\n });\n }\n}\n\n/**\n * Public factory for `SystemPrompt`, callable directly or via its\n * `fromFile` static. Exists as a named interface so the callable signature\n * and the `fromFile` attachment travel together as one public type.\n */\nexport interface SystemPromptFactory {\n (\n input?: string | ReadonlyArray<SystemPromptBlockContract>,\n meta?: SystemPromptMeta,\n ): SystemPrompt;\n\n /**\n * Build a system prompt from a file read once at construction. Delegates\n * to {@link SystemPrompt.fromFile}, so `ai.systemPrompt.fromFile(path)` and\n * `SystemPrompt.fromFile(path)` behave identically.\n *\n * @example\n * const prompt = ai.systemPrompt.fromFile(\"./prompts/support-agent.md\");\n */\n fromFile(path: string): SystemPrompt;\n}\n\nfunction systemPromptFactory(\n input?: string | ReadonlyArray<SystemPromptBlockContract>,\n meta?: SystemPromptMeta,\n): SystemPrompt {\n if (input === undefined) {\n return new SystemPrompt([], meta);\n }\n\n if (typeof input === \"string\") {\n return new SystemPrompt([new Instruction(input)], meta);\n }\n\n return new SystemPrompt([...input], meta);\n}\n\n/**\n * Create a new immutable system-prompt builder.\n *\n * **Role.** Public factory for `SystemPrompt` — keeps user-facing code\n * free of `new` and consistent with `ai.tool()`, `ai.agent()`,\n * `ai.persona()`, `ai.instruction()`.\n *\n * Input forms:\n * - No argument → empty builder, chain `.persona()` / `.instruction()`\n * - Single string → seeded with one instruction for quick one-shot prompts\n * - Array of blocks → used verbatim, preserving insertion order\n * - `.fromFile(path)` → seeded from a file read once at construction\n *\n * Pass a second `meta` argument to name the prompt — a named prompt\n * auto-registers in `ai.prompts` under `name@version` (version defaults to the\n * next integer). Forks (`.persona()`, `.instruction()`, `.merge()`) are\n * anonymous unless re-named via `.meta({ name })`.\n *\n * @example\n * // Composed builder\n * const prompt = systemPrompt()\n * .persona(\"You are Alex, a senior TypeScript engineer.\")\n * .instruction(\"Always include working code examples.\")\n * .instruction(\"Respond in {{language|English}}.\");\n *\n * prompt.resolve({ language: \"Arabic\" });\n *\n * @example\n * // One-shot seed\n * const prompt = systemPrompt(\"Answer only with JSON matching the schema.\");\n *\n * @example\n * // From a file, read once at construction\n * const prompt = systemPrompt.fromFile(\"./prompts/support-agent.md\");\n *\n * @example\n * // Array form — fully declarative\n * const prompt = systemPrompt([\n * ai.persona(\"You are Alex.\"),\n * ai.instruction(\"Always cite sources.\"),\n * ai.instruction(\"Respond in {{language|English}}.\"),\n * ]);\n */\nexport const systemPrompt: SystemPromptFactory = Object.assign(\n systemPromptFactory,\n { fromFile: SystemPrompt.fromFile },\n);\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.d.mts","names":[],"sources":["../../../../../../@warlock.js/core/src/bootstrap.ts"],"mappings":";iBAIsB,SAAA,IAAS,OAAA"}
1
+ {"version":3,"file":"bootstrap.d.mts","names":[],"sources":["../../../../../../@warlock.js/core/src/bootstrap.ts"],"mappings":";iBAKsB,SAAA,IAAS,OAAA"}
package/esm/bootstrap.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ import { Application } from "./application/application.mjs";
2
+ import "./application/index.mjs";
1
3
  import { loadEnv } from "@mongez/dotenv";
2
4
  import { captureAnyUnhandledRejection } from "@warlock.js/logger";
3
5
  import { initializeDayjs } from "@mongez/time-wizard";
@@ -6,7 +8,7 @@ import { initializeDayjs } from "@mongez/time-wizard";
6
8
  async function bootstrap() {
7
9
  await loadEnv();
8
10
  initializeDayjs();
9
- captureAnyUnhandledRejection();
11
+ captureAnyUnhandledRejection({ exitOnUncaughtException: Application.isProduction });
10
12
  }
11
13
 
12
14
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.mjs","names":[],"sources":["../../../../../../@warlock.js/core/src/bootstrap.ts"],"sourcesContent":["import { loadEnv } from \"@mongez/dotenv\";\nimport { initializeDayjs } from \"@mongez/time-wizard\";\nimport { captureAnyUnhandledRejection } from \"@warlock.js/logger\";\n\nexport async function bootstrap() {\n await loadEnv();\n\n initializeDayjs();\n captureAnyUnhandledRejection();\n}\n"],"mappings":";;;;;AAIA,eAAsB,YAAY;CAChC,MAAM,QAAQ;CAEd,gBAAgB;CAChB,6BAA6B;AAC/B"}
1
+ {"version":3,"file":"bootstrap.mjs","names":[],"sources":["../../../../../../@warlock.js/core/src/bootstrap.ts"],"sourcesContent":["import { loadEnv } from \"@mongez/dotenv\";\nimport { initializeDayjs } from \"@mongez/time-wizard\";\nimport { captureAnyUnhandledRejection } from \"@warlock.js/logger\";\nimport { Application } from \"./application\";\n\nexport async function bootstrap() {\n await loadEnv();\n\n initializeDayjs();\n\n // In production a fatal `uncaughtException` must take the process down loudly\n // (Node's own default) so supervisors restart and `warlock start` surfaces\n // the failure instead of exiting 0 in silence. In development the dev server\n // intentionally survives runtime errors so HMR can recover, so we only log.\n captureAnyUnhandledRejection({ exitOnUncaughtException: Application.isProduction });\n}\n"],"mappings":";;;;;;;AAKA,eAAsB,YAAY;CAChC,MAAM,QAAQ;CAEd,gBAAgB;CAMhB,6BAA6B,EAAE,yBAAyB,YAAY,aAAa,CAAC;AACpF"}
@@ -1,4 +1,4 @@
1
- import config from "@mongez/config";
1
+ import baseConfig from "@mongez/config";
2
2
 
3
3
  //#region ../@warlock.js/core/src/config/config-getter.ts
4
4
  /**
@@ -14,15 +14,15 @@ import config from "@mongez/config";
14
14
  * const port = config.key<number>("database.port", 27017);
15
15
  * ```
16
16
  */
17
- const config$1 = {
17
+ const config = {
18
18
  key(key, defaultValue) {
19
- return config.get(key, defaultValue);
19
+ return baseConfig.get(key, defaultValue);
20
20
  },
21
21
  get(name, defaultValue) {
22
- return config.get(name, defaultValue);
22
+ return baseConfig.get(name, defaultValue);
23
23
  }
24
24
  };
25
25
 
26
26
  //#endregion
27
- export { config$1 as config };
27
+ export { config };
28
28
  //# sourceMappingURL=config-getter.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-getter.mjs","names":["config","baseConfig"],"sources":["../../../../../../../@warlock.js/core/src/config/config-getter.ts"],"sourcesContent":["import baseConfig from \"@mongez/config\";\nimport type { ConfigKey, ConfigRegistry } from \"./types\";\n\n/**\n * Config accessor interface with typed overloads\n */\ninterface ConfigAccessor {\n /**\n * Get a config value by dot-notation key path.\n */\n key<T = any>(key: ConfigKey | (string & {}), defaultValue?: T): T;\n\n /**\n * Get an entire config group by name with type inference.\n * Returns the typed config object for known config names.\n */\n get<K extends keyof ConfigRegistry>(name: K, defaultValue?: ConfigRegistry[K]): ConfigRegistry[K];\n\n /**\n * Get an entire config group by name (dynamic string).\n */\n get<T = any>(name: string, defaultValue?: T): T;\n}\n\n/**\n * Config accessor with typed autocomplete and return type inference.\n *\n * @example\n * ```typescript\n * // Get entire config group - returns the actual config type\n * const db = config.get(\"database\"); // → DatabaseConfigurations\n *\n * // Get specific key with dot notation\n * const host = config.key(\"database.host\");\n * const port = config.key<number>(\"database.port\", 27017);\n * ```\n */\nexport const config: ConfigAccessor = {\n key(key: ConfigKey | (string & {}), defaultValue?: any): any {\n return baseConfig.get(key, defaultValue);\n },\n\n get(name: string, defaultValue?: any): any {\n return baseConfig.get(name, defaultValue);\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAqCA,MAAaA,WAAyB;CACpC,IAAI,KAAgC,cAAyB;EAC3D,OAAOC,OAAW,IAAI,KAAK,YAAY;CACzC;CAEA,IAAI,MAAc,cAAyB;EACzC,OAAOA,OAAW,IAAI,MAAM,YAAY;CAC1C;AACF"}
1
+ {"version":3,"file":"config-getter.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/config/config-getter.ts"],"sourcesContent":["import baseConfig from \"@mongez/config\";\nimport type { ConfigKey, ConfigRegistry } from \"./types\";\n\n/**\n * Config accessor interface with typed overloads\n */\ninterface ConfigAccessor {\n /**\n * Get a config value by dot-notation key path.\n */\n key<T = any>(key: ConfigKey | (string & {}), defaultValue?: T): T;\n\n /**\n * Get an entire config group by name with type inference.\n * Returns the typed config object for known config names.\n */\n get<K extends keyof ConfigRegistry>(name: K, defaultValue?: ConfigRegistry[K]): ConfigRegistry[K];\n\n /**\n * Get an entire config group by name (dynamic string).\n */\n get<T = any>(name: string, defaultValue?: T): T;\n}\n\n/**\n * Config accessor with typed autocomplete and return type inference.\n *\n * @example\n * ```typescript\n * // Get entire config group - returns the actual config type\n * const db = config.get(\"database\"); // → DatabaseConfigurations\n *\n * // Get specific key with dot notation\n * const host = config.key(\"database.host\");\n * const port = config.key<number>(\"database.port\", 27017);\n * ```\n */\nexport const config: ConfigAccessor = {\n key(key: ConfigKey | (string & {}), defaultValue?: any): any {\n return baseConfig.get(key, defaultValue);\n },\n\n get(name: string, defaultValue?: any): any {\n return baseConfig.get(name, defaultValue);\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAqCA,MAAa,SAAyB;CACpC,IAAI,KAAgC,cAAyB;EAC3D,OAAO,WAAW,IAAI,KAAK,YAAY;CACzC;CAEA,IAAI,MAAc,cAAyB;EACzC,OAAO,WAAW,IAAI,MAAM,YAAY;CAC1C;AACF"}
@@ -1,5 +1,5 @@
1
1
  import { configSpecialHandlers } from "./config-special-handlers.mjs";
2
- import config from "@mongez/config";
2
+ import baseConfig from "@mongez/config";
3
3
  import { colors } from "@mongez/copper";
4
4
  import { pathToFileURL } from "node:url";
5
5
 
@@ -27,7 +27,7 @@ var ConfigLoader = class {
27
27
  console.log(colors.red(`config error: `), `Config file ${colors.yellow(file.relativePath)} does not have a default export`);
28
28
  return;
29
29
  }
30
- config.set(configName, configValue);
30
+ baseConfig.set(configName, configValue);
31
31
  await configSpecialHandlers.execute(configName, configValue);
32
32
  } catch (error) {
33
33
  throw error;
@@ -1 +1 @@
1
- {"version":3,"file":"config-loader.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/config/config-loader.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { colors } from \"@mongez/copper\";\r\nimport { pathToFileURL } from \"node:url\";\r\nimport type { FileManager } from \"../dev-server/file-manager\";\r\nimport { configSpecialHandlers } from \"./config-special-handlers\";\r\n\r\n/**\r\n * Special Config Handler\r\n * A function that handles special configuration loading\r\n */\r\nexport type SpecialConfigHandler = (configValue: any) => void | Promise<void>;\r\n\r\n/**\r\n * Config Loader\r\n * Dynamically loads all configuration files and registers them with @mongez/config\r\n * Supports special handlers for configs that require additional processing\r\n */\r\nexport class ConfigLoader {\r\n public async loadAll(configFiles: FileManager[]): Promise<void> {\r\n for (const file of configFiles) {\r\n await this.loadConfig(file);\r\n }\r\n }\r\n\r\n /**\r\n * Load a single configuration file.\r\n *\r\n * The ESM loader hook stamps a version token onto the URL so that each HMR\r\n * cycle gets a fresh module — no manual cache-busting needed here.\r\n */\r\n public async loadConfig(file: FileManager): Promise<void> {\r\n const configName = this.getConfigName(file.relativePath);\r\n\r\n try {\r\n const fileUrl = pathToFileURL(file.absolutePath).href;\r\n const configModule = await import(fileUrl);\r\n const configValue = configModule.default;\r\n\r\n if (configValue === undefined) {\r\n console.log(\r\n colors.red(`config error: `),\r\n `Config file ${colors.yellow(file.relativePath)} does not have a default export`,\r\n );\r\n return;\r\n }\r\n\r\n config.set(configName, configValue);\r\n await configSpecialHandlers.execute(configName, configValue);\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n public async reloadConfig(file: FileManager): Promise<void> {\r\n await this.loadConfig(file);\r\n }\r\n\r\n private getConfigName(relativePath: string): string {\r\n const match = relativePath.match(/^src\\/config\\/(.+)\\.(ts|tsx)$/);\r\n\r\n if (!match) {\r\n throw new Error(`Invalid config file path: ${relativePath}`);\r\n }\r\n\r\n return match[1];\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;AAiBA,IAAa,eAAb,MAA0B;CACxB,MAAa,QAAQ,aAA2C;EAC9D,KAAK,MAAM,QAAQ,aACjB,MAAM,KAAK,WAAW,IAAI;CAE9B;;;;;;;CAQA,MAAa,WAAW,MAAkC;EACxD,MAAM,aAAa,KAAK,cAAc,KAAK,YAAY;EAEvD,IAAI;GAGF,MAAM,eAAc,MADO,OADX,cAAc,KAAK,YAAY,CAAC,CAAC,MAEjB,CAAC;GAEjC,IAAI,gBAAgB,QAAW;IAC7B,QAAQ,IACN,OAAO,IAAI,gBAAgB,GAC3B,eAAe,OAAO,OAAO,KAAK,YAAY,EAAE,gCAClD;IACA;GACF;GAEA,OAAO,IAAI,YAAY,WAAW;GAClC,MAAM,sBAAsB,QAAQ,YAAY,WAAW;EAC7D,SAAS,OAAO;GACd,MAAM;EACR;CACF;CAEA,MAAa,aAAa,MAAkC;EAC1D,MAAM,KAAK,WAAW,IAAI;CAC5B;CAEA,AAAQ,cAAc,cAA8B;EAClD,MAAM,QAAQ,aAAa,MAAM,+BAA+B;EAEhE,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,6BAA6B,cAAc;EAG7D,OAAO,MAAM;CACf;AACF"}
1
+ {"version":3,"file":"config-loader.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/config/config-loader.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { colors } from \"@mongez/copper\";\r\nimport { pathToFileURL } from \"node:url\";\r\nimport type { FileManager } from \"../dev-server/file-manager\";\r\nimport { configSpecialHandlers } from \"./config-special-handlers\";\r\n\r\n/**\r\n * Special Config Handler\r\n * A function that handles special configuration loading\r\n */\r\nexport type SpecialConfigHandler = (configValue: any) => void | Promise<void>;\r\n\r\n/**\r\n * Config Loader\r\n * Dynamically loads all configuration files and registers them with @mongez/config\r\n * Supports special handlers for configs that require additional processing\r\n */\r\nexport class ConfigLoader {\r\n public async loadAll(configFiles: FileManager[]): Promise<void> {\r\n for (const file of configFiles) {\r\n await this.loadConfig(file);\r\n }\r\n }\r\n\r\n /**\r\n * Load a single configuration file.\r\n *\r\n * The ESM loader hook stamps a version token onto the URL so that each HMR\r\n * cycle gets a fresh module — no manual cache-busting needed here.\r\n */\r\n public async loadConfig(file: FileManager): Promise<void> {\r\n const configName = this.getConfigName(file.relativePath);\r\n\r\n try {\r\n const fileUrl = pathToFileURL(file.absolutePath).href;\r\n const configModule = await import(fileUrl);\r\n const configValue = configModule.default;\r\n\r\n if (configValue === undefined) {\r\n console.log(\r\n colors.red(`config error: `),\r\n `Config file ${colors.yellow(file.relativePath)} does not have a default export`,\r\n );\r\n return;\r\n }\r\n\r\n config.set(configName, configValue);\r\n await configSpecialHandlers.execute(configName, configValue);\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n public async reloadConfig(file: FileManager): Promise<void> {\r\n await this.loadConfig(file);\r\n }\r\n\r\n private getConfigName(relativePath: string): string {\r\n const match = relativePath.match(/^src\\/config\\/(.+)\\.(ts|tsx)$/);\r\n\r\n if (!match) {\r\n throw new Error(`Invalid config file path: ${relativePath}`);\r\n }\r\n\r\n return match[1];\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;AAiBA,IAAa,eAAb,MAA0B;CACxB,MAAa,QAAQ,aAA2C;EAC9D,KAAK,MAAM,QAAQ,aACjB,MAAM,KAAK,WAAW,IAAI;CAE9B;;;;;;;CAQA,MAAa,WAAW,MAAkC;EACxD,MAAM,aAAa,KAAK,cAAc,KAAK,YAAY;EAEvD,IAAI;GAGF,MAAM,eAAc,MADO,OADX,cAAc,KAAK,YAAY,CAAC,CAAC,MAEjB,CAAC;GAEjC,IAAI,gBAAgB,QAAW;IAC7B,QAAQ,IACN,OAAO,IAAI,gBAAgB,GAC3B,eAAe,OAAO,OAAO,KAAK,YAAY,EAAE,gCAClD;IACA;GACF;GAEA,WAAO,IAAI,YAAY,WAAW;GAClC,MAAM,sBAAsB,QAAQ,YAAY,WAAW;EAC7D,SAAS,OAAO;GACd,MAAM;EACR;CACF;CAEA,MAAa,aAAa,MAAkC;EAC1D,MAAM,KAAK,WAAW,IAAI;CAC5B;CAEA,AAAQ,cAAc,cAA8B;EAClD,MAAM,QAAQ,aAAa,MAAM,+BAA+B;EAEhE,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,6BAA6B,cAAc;EAG7D,OAAO,MAAM;CACf;AACF"}
@@ -1,6 +1,6 @@
1
1
  import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
2
2
  import { BaseConnector } from "./base-connector.mjs";
3
- import config from "@mongez/config";
3
+ import baseConfig from "@mongez/config";
4
4
  import { log } from "@warlock.js/logger";
5
5
 
6
6
  //#region ../@warlock.js/core/src/connectors/access-connector.ts
@@ -29,7 +29,7 @@ var AccessConnector = class extends BaseConnector {
29
29
  * Register the access configuration with the package.
30
30
  */
31
31
  async start() {
32
- const accessConfiguration = config.get("access");
32
+ const accessConfiguration = baseConfig.get("access");
33
33
  if (!accessConfiguration) return;
34
34
  const { setAccessConfig } = await import("@warlock.js/access");
35
35
  setAccessConfig(accessConfiguration);
@@ -1 +1 @@
1
- {"version":3,"file":"access-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/access-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport { BaseConnector } from \"./base-connector\";\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\n\n/**\n * Access Connector\n *\n * Wires `@warlock.js/access` from `src/config/access.ts` at boot: reads the\n * exported config object and hands it to the package's `setAccessConfig`, which\n * validates that a resolver is present — so a misconfigured authorization layer\n * fails at STARTUP, not on the first protected request. Config files stay\n * declarative; the connector performs the side-effect.\n *\n * The package is lazy-imported (only when an access config is present), so core\n * carries no hard dependency on it — the same pattern as the notifications and\n * herald connectors.\n */\nexport class AccessConnector extends BaseConnector {\n public readonly name = \"access\";\n public readonly priority = ConnectorPriority.ACCESS;\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\n\n /**\n * Files that trigger an access restart\n */\n protected readonly watchedFiles = [\"src/config/access.ts\"];\n\n /**\n * Register the access configuration with the package.\n */\n public async start(): Promise<void> {\n const accessConfiguration = config.get(\"access\");\n\n if (!accessConfiguration) {\n return;\n }\n\n const { setAccessConfig } = await import(\"@warlock.js/access\");\n\n setAccessConfig(accessConfiguration);\n this.active = true;\n\n log.info(\"access\", \"configured\", \"Authorization wired from config/access.ts\");\n }\n\n /**\n * Clear the active config so a dev restart re-registers from the (possibly\n * changed, or now-removed) config file. The package holds no external\n * connection of its own.\n */\n public async shutdown(): Promise<void> {\n if (!this.active) {\n return;\n }\n\n const { resetAccessConfig } = await import(\"@warlock.js/access\");\n\n resetAccessConfig();\n this.active = false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW,CAAC,sBAAsB;;;;;CAKzD,MAAa,QAAuB;EAClC,MAAM,sBAAsB,OAAO,IAAI,QAAQ;EAE/C,IAAI,CAAC,qBACH;EAGF,MAAM,EAAE,oBAAoB,MAAM,OAAO;EAEzC,gBAAgB,mBAAmB;EACnC,KAAK,SAAS;EAEd,IAAI,KAAK,UAAU,cAAc,2CAA2C;CAC9E;;;;;;CAOA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,MAAM,EAAE,sBAAsB,MAAM,OAAO;EAE3C,kBAAkB;EAClB,KAAK,SAAS;CAChB;AACF"}
1
+ {"version":3,"file":"access-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/access-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport { BaseConnector } from \"./base-connector\";\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\n\n/**\n * Access Connector\n *\n * Wires `@warlock.js/access` from `src/config/access.ts` at boot: reads the\n * exported config object and hands it to the package's `setAccessConfig`, which\n * validates that a resolver is present — so a misconfigured authorization layer\n * fails at STARTUP, not on the first protected request. Config files stay\n * declarative; the connector performs the side-effect.\n *\n * The package is lazy-imported (only when an access config is present), so core\n * carries no hard dependency on it — the same pattern as the notifications and\n * herald connectors.\n */\nexport class AccessConnector extends BaseConnector {\n public readonly name = \"access\";\n public readonly priority = ConnectorPriority.ACCESS;\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\n\n /**\n * Files that trigger an access restart\n */\n protected readonly watchedFiles = [\"src/config/access.ts\"];\n\n /**\n * Register the access configuration with the package.\n */\n public async start(): Promise<void> {\n const accessConfiguration = config.get(\"access\");\n\n if (!accessConfiguration) {\n return;\n }\n\n const { setAccessConfig } = await import(\"@warlock.js/access\");\n\n setAccessConfig(accessConfiguration);\n this.active = true;\n\n log.info(\"access\", \"configured\", \"Authorization wired from config/access.ts\");\n }\n\n /**\n * Clear the active config so a dev restart re-registers from the (possibly\n * changed, or now-removed) config file. The package holds no external\n * connection of its own.\n */\n public async shutdown(): Promise<void> {\n if (!this.active) {\n return;\n }\n\n const { resetAccessConfig } = await import(\"@warlock.js/access\");\n\n resetAccessConfig();\n this.active = false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW,CAAC,sBAAsB;;;;;CAKzD,MAAa,QAAuB;EAClC,MAAM,sBAAsBA,WAAO,IAAI,QAAQ;EAE/C,IAAI,CAAC,qBACH;EAGF,MAAM,EAAE,oBAAoB,MAAM,OAAO;EAEzC,gBAAgB,mBAAmB;EACnC,KAAK,SAAS;EAEd,IAAI,KAAK,UAAU,cAAc,2CAA2C;CAC9E;;;;;;CAOA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,MAAM,EAAE,sBAAsB,MAAM,OAAO;EAE3C,kBAAkB;EAClB,KAAK,SAAS;CAChB;AACF"}
@@ -1,6 +1,6 @@
1
1
  import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
2
2
  import { BaseConnector } from "./base-connector.mjs";
3
- import config from "@mongez/config";
3
+ import baseConfig from "@mongez/config";
4
4
  import { log } from "@warlock.js/logger";
5
5
 
6
6
  //#region ../@warlock.js/core/src/connectors/ai-connector.ts
@@ -33,7 +33,7 @@ var AiConnector = class extends BaseConnector {
33
33
  * Register the ai configuration with the package.
34
34
  */
35
35
  async start() {
36
- const aiConfiguration = config.get("ai");
36
+ const aiConfiguration = baseConfig.get("ai");
37
37
  if (!aiConfiguration) return;
38
38
  const { ai } = await import("../ai/src/index.mjs");
39
39
  ai.config(aiConfiguration);
@@ -1 +1 @@
1
- {"version":3,"file":"ai-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/ai-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport { BaseConnector } from \"./base-connector\";\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\n\n/**\n * AI Connector\n *\n * Wires `@warlock.js/ai` from `src/config/ai.ts` at boot: reads the exported\n * config object and hands it to the package's `ai.config(...)`. Config files stay\n * declarative; the connector performs the side-effect.\n *\n * The package is lazy-imported (only when an ai config is present), so core\n * carries no hard dependency on it — the same pattern as the access,\n * notifications and herald connectors.\n *\n * Because the satellite packages' side-effect imports sit at the TOP of\n * config/ai.ts, they have already registered their surface on `ai` (ai.tools /\n * ai.mcp, ai.workspace, panoptic) by the time config-loader runs the file and\n * this connector applies the config — so this single `ai.config(...)` call also\n * fires panoptic's onConfigApplied wiring.\n */\nexport class AiConnector extends BaseConnector {\n public readonly name = \"ai\";\n public readonly priority = ConnectorPriority.AI;\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\n\n /**\n * Files that trigger an ai restart\n */\n protected readonly watchedFiles = [\"src/config/ai.ts\"];\n\n /**\n * Register the ai configuration with the package.\n */\n public async start(): Promise<void> {\n const aiConfiguration = config.get(\"ai\");\n\n if (!aiConfiguration) return;\n\n const { ai } = await import(\"@warlock.js/ai\");\n\n ai.config(aiConfiguration);\n this.active = true;\n\n log.info(\"ai\", \"configured\", \"AI wired from config/ai.ts\");\n }\n\n /**\n * Clear the active flag so a dev restart re-registers from the (possibly\n * changed, or now-removed) config file. The package holds no external\n * connection of its own.\n */\n public async shutdown(): Promise<void> {\n if (!this.active) return;\n\n this.active = false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsBA,IAAa,cAAb,cAAiC,cAAc;;;cACtB;;;sBAOW,CAAC,kBAAkB;;;;;CAKrD,MAAa,QAAuB;EAClC,MAAM,kBAAkB,OAAO,IAAI,IAAI;EAEvC,IAAI,CAAC,iBAAiB;EAEtB,MAAM,EAAE,OAAO,MAAM,OAAO;EAE5B,GAAG,OAAO,eAAe;EACzB,KAAK,SAAS;EAEd,IAAI,KAAK,MAAM,cAAc,4BAA4B;CAC3D;;;;;;CAOA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QAAQ;EAElB,KAAK,SAAS;CAChB;AACF"}
1
+ {"version":3,"file":"ai-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/ai-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport { BaseConnector } from \"./base-connector\";\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\n\n/**\n * AI Connector\n *\n * Wires `@warlock.js/ai` from `src/config/ai.ts` at boot: reads the exported\n * config object and hands it to the package's `ai.config(...)`. Config files stay\n * declarative; the connector performs the side-effect.\n *\n * The package is lazy-imported (only when an ai config is present), so core\n * carries no hard dependency on it — the same pattern as the access,\n * notifications and herald connectors.\n *\n * Because the satellite packages' side-effect imports sit at the TOP of\n * config/ai.ts, they have already registered their surface on `ai` (ai.tools /\n * ai.mcp, ai.workspace, panoptic) by the time config-loader runs the file and\n * this connector applies the config — so this single `ai.config(...)` call also\n * fires panoptic's onConfigApplied wiring.\n */\nexport class AiConnector extends BaseConnector {\n public readonly name = \"ai\";\n public readonly priority = ConnectorPriority.AI;\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\n\n /**\n * Files that trigger an ai restart\n */\n protected readonly watchedFiles = [\"src/config/ai.ts\"];\n\n /**\n * Register the ai configuration with the package.\n */\n public async start(): Promise<void> {\n const aiConfiguration = config.get(\"ai\");\n\n if (!aiConfiguration) return;\n\n const { ai } = await import(\"@warlock.js/ai\");\n\n ai.config(aiConfiguration);\n this.active = true;\n\n log.info(\"ai\", \"configured\", \"AI wired from config/ai.ts\");\n }\n\n /**\n * Clear the active flag so a dev restart re-registers from the (possibly\n * changed, or now-removed) config file. The package holds no external\n * connection of its own.\n */\n public async shutdown(): Promise<void> {\n if (!this.active) return;\n\n this.active = false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsBA,IAAa,cAAb,cAAiC,cAAc;;;cACtB;;;sBAOW,CAAC,kBAAkB;;;;;CAKrD,MAAa,QAAuB;EAClC,MAAM,kBAAkBA,WAAO,IAAI,IAAI;EAEvC,IAAI,CAAC,iBAAiB;EAEtB,MAAM,EAAE,OAAO,MAAM,OAAO;EAE5B,GAAG,OAAO,eAAe;EACzB,KAAK,SAAS;EAEd,IAAI,KAAK,MAAM,cAAc,4BAA4B;CAC3D;;;;;;CAOA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QAAQ;EAElB,KAAK,SAAS;CAChB;AACF"}
@@ -1,6 +1,6 @@
1
1
  import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
2
2
  import { BaseConnector } from "./base-connector.mjs";
3
- import config from "@mongez/config";
3
+ import baseConfig from "@mongez/config";
4
4
  import { cache } from "@warlock.js/cache";
5
5
 
6
6
  //#region ../@warlock.js/core/src/connectors/cache-connector.ts
@@ -20,7 +20,7 @@ var CacheConnector = class extends BaseConnector {
20
20
  * Initialize cache connection
21
21
  */
22
22
  async start() {
23
- const cacheConfig = config.get("cache");
23
+ const cacheConfig = baseConfig.get("cache");
24
24
  if (!cacheConfig) return;
25
25
  cache.setCacheConfigurations(cacheConfig);
26
26
  await cache.init();
@@ -1 +1 @@
1
- {"version":3,"file":"cache-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/cache-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { cache } from \"@warlock.js/cache\";\nimport type { CacheDriver } from \"@warlock.js/cache\";\nimport { BaseConnector } from \"./base-connector\";\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\n\n/**\n * Cache Connector\n * Manages cache engine connection lifecycle\n */\nexport class CacheConnector extends BaseConnector {\n public readonly name = \"cache\";\n public readonly priority = ConnectorPriority.CACHE;\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\n\n /**\n * Files that trigger cache restart\n */\n protected readonly watchedFiles = [\"src/config/cache.ts\", \"src/config/cache.tsx\"];\n\n /**\n * Initialize cache connection\n */\n public async start(): Promise<void> {\n const cacheConfig = config.get(\"cache\");\n\n if (!cacheConfig) return;\n\n cache.setCacheConfigurations(cacheConfig);\n\n await cache.init();\n\n this.active = true;\n }\n\n /**\n * Shutdown cache connection\n *\n * Disconnects every loaded cache driver so external clients (e.g. a Redis\n * connection) are released instead of left dangling — mirroring the\n * database and herald connectors, which disconnect all registered\n * connections on shutdown.\n */\n public async shutdown(): Promise<void> {\n if (!this.active) {\n return;\n }\n\n // Disconnect every driver the manager loaded (not just the current one),\n // so secondary drivers selected via `cache.use(\"...\")` also release their\n // connections.\n const drivers: CacheDriver<unknown, unknown>[] = Object.values(cache.loadedDrivers);\n\n for (const driver of drivers) {\n await driver.disconnect();\n }\n\n this.active = false;\n }\n}\n"],"mappings":";;;;;;;;;;AAUA,IAAa,iBAAb,cAAoC,cAAc;;;cACzB;;;sBAOW,CAAC,uBAAuB,sBAAsB;;;;;CAKhF,MAAa,QAAuB;EAClC,MAAM,cAAc,OAAO,IAAI,OAAO;EAEtC,IAAI,CAAC,aAAa;EAElB,MAAM,uBAAuB,WAAW;EAExC,MAAM,MAAM,KAAK;EAEjB,KAAK,SAAS;CAChB;;;;;;;;;CAUA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAMF,MAAM,UAA2C,OAAO,OAAO,MAAM,aAAa;EAElF,KAAK,MAAM,UAAU,SACnB,MAAM,OAAO,WAAW;EAG1B,KAAK,SAAS;CAChB;AACF"}
1
+ {"version":3,"file":"cache-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/cache-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { cache } from \"@warlock.js/cache\";\nimport type { CacheDriver } from \"@warlock.js/cache\";\nimport { BaseConnector } from \"./base-connector\";\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\n\n/**\n * Cache Connector\n * Manages cache engine connection lifecycle\n */\nexport class CacheConnector extends BaseConnector {\n public readonly name = \"cache\";\n public readonly priority = ConnectorPriority.CACHE;\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\n\n /**\n * Files that trigger cache restart\n */\n protected readonly watchedFiles = [\"src/config/cache.ts\", \"src/config/cache.tsx\"];\n\n /**\n * Initialize cache connection\n */\n public async start(): Promise<void> {\n const cacheConfig = config.get(\"cache\");\n\n if (!cacheConfig) return;\n\n cache.setCacheConfigurations(cacheConfig);\n\n await cache.init();\n\n this.active = true;\n }\n\n /**\n * Shutdown cache connection\n *\n * Disconnects every loaded cache driver so external clients (e.g. a Redis\n * connection) are released instead of left dangling — mirroring the\n * database and herald connectors, which disconnect all registered\n * connections on shutdown.\n */\n public async shutdown(): Promise<void> {\n if (!this.active) {\n return;\n }\n\n // Disconnect every driver the manager loaded (not just the current one),\n // so secondary drivers selected via `cache.use(\"...\")` also release their\n // connections.\n const drivers: CacheDriver<unknown, unknown>[] = Object.values(cache.loadedDrivers);\n\n for (const driver of drivers) {\n await driver.disconnect();\n }\n\n this.active = false;\n }\n}\n"],"mappings":";;;;;;;;;;AAUA,IAAa,iBAAb,cAAoC,cAAc;;;cACzB;;;sBAOW,CAAC,uBAAuB,sBAAsB;;;;;CAKhF,MAAa,QAAuB;EAClC,MAAM,cAAcA,WAAO,IAAI,OAAO;EAEtC,IAAI,CAAC,aAAa;EAElB,MAAM,uBAAuB,WAAW;EAExC,MAAM,MAAM,KAAK;EAEjB,KAAK,SAAS;CAChB;;;;;;;;;CAUA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAMF,MAAM,UAA2C,OAAO,OAAO,MAAM,aAAa;EAElF,KAAK,MAAM,UAAU,SACnB,MAAM,OAAO,WAAW;EAG1B,KAAK,SAAS;CAChB;AACF"}
@@ -1,7 +1,7 @@
1
1
  import { container } from "../container/index.mjs";
2
2
  import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
3
3
  import { BaseConnector } from "./base-connector.mjs";
4
- import config from "@mongez/config";
4
+ import baseConfig from "@mongez/config";
5
5
  import { connectToDatabase, dataSourceRegistry } from "@warlock.js/cascade";
6
6
 
7
7
  //#region ../@warlock.js/core/src/connectors/database-connector.ts
@@ -21,7 +21,7 @@ var DatabaseConnector = class extends BaseConnector {
21
21
  * Initialize database connection
22
22
  */
23
23
  async start() {
24
- const databaseConfig = config.get("database");
24
+ const databaseConfig = baseConfig.get("database");
25
25
  if (!databaseConfig) return;
26
26
  try {
27
27
  const source = await connectToDatabase(databaseConfig);
@@ -1 +1 @@
1
- {"version":3,"file":"database-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/database-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { connectToDatabase, dataSourceRegistry } from \"@warlock.js/cascade\";\r\nimport { container } from \"../container\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Database Connector\r\n * Manages database connection lifecycle using @warlock.js/cascade\r\n */\r\nexport class DatabaseConnector extends BaseConnector {\r\n public readonly name = \"database\";\r\n public readonly priority = ConnectorPriority.DATABASE;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger database restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/database.ts\", \"src/config/database.tsx\"];\r\n\r\n /**\r\n * Initialize database connection\r\n */\r\n public async start(): Promise<void> {\r\n const databaseConfig = config.get(\"database\");\r\n\r\n if (!databaseConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n const source = await connectToDatabase(databaseConfig);\r\n container.set(\"database.source\", source);\r\n this.active = true;\r\n } catch (error) {\r\n console.error(\"Failed to connect to database:\", error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown database connection\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n // Disconnect all registered data sources\r\n const dataSources = dataSourceRegistry.getAllDataSources();\r\n\r\n for (const dataSource of dataSources) {\r\n if (dataSource.driver.isConnected) {\r\n await dataSource.driver.disconnect();\r\n }\r\n }\r\n\r\n this.active = false;\r\n } catch (error) {\r\n console.error(\"Failed to disconnect from database:\", error);\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;AAUA,IAAa,oBAAb,cAAuC,cAAc;;;cAC5B;;;sBAOW,CAAC,0BAA0B,yBAAyB;;;;;CAKtF,MAAa,QAAuB;EAClC,MAAM,iBAAiB,OAAO,IAAI,UAAU;EAE5C,IAAI,CAAC,gBACH;EAGF,IAAI;GACF,MAAM,SAAS,MAAM,kBAAkB,cAAc;GACrD,UAAU,IAAI,mBAAmB,MAAM;GACvC,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,kCAAkC,KAAK;GACrD,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GAEF,MAAM,cAAc,mBAAmB,kBAAkB;GAEzD,KAAK,MAAM,cAAc,aACvB,IAAI,WAAW,OAAO,aACpB,MAAM,WAAW,OAAO,WAAW;GAIvC,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,uCAAuC,KAAK;GAC1D,MAAM;EACR;CACF;AACF"}
1
+ {"version":3,"file":"database-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/database-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { connectToDatabase, dataSourceRegistry } from \"@warlock.js/cascade\";\r\nimport { container } from \"../container\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Database Connector\r\n * Manages database connection lifecycle using @warlock.js/cascade\r\n */\r\nexport class DatabaseConnector extends BaseConnector {\r\n public readonly name = \"database\";\r\n public readonly priority = ConnectorPriority.DATABASE;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger database restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/database.ts\", \"src/config/database.tsx\"];\r\n\r\n /**\r\n * Initialize database connection\r\n */\r\n public async start(): Promise<void> {\r\n const databaseConfig = config.get(\"database\");\r\n\r\n if (!databaseConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n const source = await connectToDatabase(databaseConfig);\r\n container.set(\"database.source\", source);\r\n this.active = true;\r\n } catch (error) {\r\n console.error(\"Failed to connect to database:\", error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown database connection\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n // Disconnect all registered data sources\r\n const dataSources = dataSourceRegistry.getAllDataSources();\r\n\r\n for (const dataSource of dataSources) {\r\n if (dataSource.driver.isConnected) {\r\n await dataSource.driver.disconnect();\r\n }\r\n }\r\n\r\n this.active = false;\r\n } catch (error) {\r\n console.error(\"Failed to disconnect from database:\", error);\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;AAUA,IAAa,oBAAb,cAAuC,cAAc;;;cAC5B;;;sBAOW,CAAC,0BAA0B,yBAAyB;;;;;CAKtF,MAAa,QAAuB;EAClC,MAAM,iBAAiBA,WAAO,IAAI,UAAU;EAE5C,IAAI,CAAC,gBACH;EAGF,IAAI;GACF,MAAM,SAAS,MAAM,kBAAkB,cAAc;GACrD,UAAU,IAAI,mBAAmB,MAAM;GACvC,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,kCAAkC,KAAK;GACrD,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GAEF,MAAM,cAAc,mBAAmB,kBAAkB;GAEzD,KAAK,MAAM,cAAc,aACvB,IAAI,WAAW,OAAO,aACpB,MAAM,WAAW,OAAO,WAAW;GAIvC,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,uCAAuC,KAAK;GAC1D,MAAM;EACR;CACF;AACF"}
@@ -1,6 +1,6 @@
1
1
  import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
2
2
  import { BaseConnector } from "./base-connector.mjs";
3
- import config from "@mongez/config";
3
+ import baseConfig from "@mongez/config";
4
4
  import { log } from "@warlock.js/logger";
5
5
 
6
6
  //#region ../@warlock.js/core/src/connectors/herald-connector.ts
@@ -20,7 +20,7 @@ var HeraldConnector = class extends BaseConnector {
20
20
  * Initialize broker connection
21
21
  */
22
22
  async start() {
23
- const heraldConfig = config.get("herald");
23
+ const heraldConfig = baseConfig.get("herald");
24
24
  if (!heraldConfig) return;
25
25
  try {
26
26
  const { connectToBroker } = await import("@warlock.js/herald");
@@ -1 +1 @@
1
- {"version":3,"file":"herald-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/herald-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Herald Connector\r\n * Manages message broker connection lifecycle using @warlock.js/herald\r\n */\r\nexport class HeraldConnector extends BaseConnector {\r\n public readonly name = \"herald\";\r\n public readonly priority = ConnectorPriority.COMMUNICATOR;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger herald restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/herald.ts\"];\r\n\r\n /**\r\n * Initialize broker connection\r\n */\r\n public async start(): Promise<void> {\r\n const heraldConfig = config.get(\"herald\");\r\n\r\n if (!heraldConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n const { connectToBroker } = await import(\"@warlock.js/herald\");\r\n\r\n log.info(`herald.${heraldConfig.driver}`, \"connection\", \"Connecting to message broker\");\r\n await connectToBroker(heraldConfig);\r\n log.success(`herald.${heraldConfig.driver}`, \"connection\", \"Connected to message broker\");\r\n this.active = true;\r\n } catch (error) {\r\n // Boot-time broker connection failure is unrecoverable — `fatal` makes\r\n // \"page on fatal only\" alerting clean, aligned with the cascade and\r\n // cache drivers. Disconnect failures (shutdown path) stay at error.\r\n log.fatal(\r\n `herald.${heraldConfig.driver}`,\r\n \"connection\",\r\n \"Failed to connect to message broker\",\r\n );\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown broker connection\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n const { brokerRegistry } = await import(\"@warlock.js/herald\");\r\n\r\n // Disconnect all registered brokers\r\n const brokers = brokerRegistry.getAll();\r\n\r\n for (const broker of brokers) {\r\n if (broker.driver.isConnected) {\r\n await broker.driver.disconnect();\r\n }\r\n }\r\n\r\n // Clear the registry for clean restart\r\n brokerRegistry.clear();\r\n\r\n this.active = false;\r\n } catch (error) {\r\n log.error(\"herald\", \"shutdown\", \"Failed to disconnect from message broker\");\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;AASA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW,CAAC,sBAAsB;;;;;CAKzD,MAAa,QAAuB;EAClC,MAAM,eAAe,OAAO,IAAI,QAAQ;EAExC,IAAI,CAAC,cACH;EAGF,IAAI;GACF,MAAM,EAAE,oBAAoB,MAAM,OAAO;GAEzC,IAAI,KAAK,UAAU,aAAa,UAAU,cAAc,8BAA8B;GACtF,MAAM,gBAAgB,YAAY;GAClC,IAAI,QAAQ,UAAU,aAAa,UAAU,cAAc,6BAA6B;GACxF,KAAK,SAAS;EAChB,SAAS,OAAO;GAId,IAAI,MACF,UAAU,aAAa,UACvB,cACA,qCACF;GACA,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GACF,MAAM,EAAE,mBAAmB,MAAM,OAAO;GAGxC,MAAM,UAAU,eAAe,OAAO;GAEtC,KAAK,MAAM,UAAU,SACnB,IAAI,OAAO,OAAO,aAChB,MAAM,OAAO,OAAO,WAAW;GAKnC,eAAe,MAAM;GAErB,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,IAAI,MAAM,UAAU,YAAY,0CAA0C;GAC1E,MAAM;EACR;CACF;AACF"}
1
+ {"version":3,"file":"herald-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/herald-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Herald Connector\r\n * Manages message broker connection lifecycle using @warlock.js/herald\r\n */\r\nexport class HeraldConnector extends BaseConnector {\r\n public readonly name = \"herald\";\r\n public readonly priority = ConnectorPriority.COMMUNICATOR;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger herald restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/herald.ts\"];\r\n\r\n /**\r\n * Initialize broker connection\r\n */\r\n public async start(): Promise<void> {\r\n const heraldConfig = config.get(\"herald\");\r\n\r\n if (!heraldConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n const { connectToBroker } = await import(\"@warlock.js/herald\");\r\n\r\n log.info(`herald.${heraldConfig.driver}`, \"connection\", \"Connecting to message broker\");\r\n await connectToBroker(heraldConfig);\r\n log.success(`herald.${heraldConfig.driver}`, \"connection\", \"Connected to message broker\");\r\n this.active = true;\r\n } catch (error) {\r\n // Boot-time broker connection failure is unrecoverable — `fatal` makes\r\n // \"page on fatal only\" alerting clean, aligned with the cascade and\r\n // cache drivers. Disconnect failures (shutdown path) stay at error.\r\n log.fatal(\r\n `herald.${heraldConfig.driver}`,\r\n \"connection\",\r\n \"Failed to connect to message broker\",\r\n );\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown broker connection\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n const { brokerRegistry } = await import(\"@warlock.js/herald\");\r\n\r\n // Disconnect all registered brokers\r\n const brokers = brokerRegistry.getAll();\r\n\r\n for (const broker of brokers) {\r\n if (broker.driver.isConnected) {\r\n await broker.driver.disconnect();\r\n }\r\n }\r\n\r\n // Clear the registry for clean restart\r\n brokerRegistry.clear();\r\n\r\n this.active = false;\r\n } catch (error) {\r\n log.error(\"herald\", \"shutdown\", \"Failed to disconnect from message broker\");\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;AASA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW,CAAC,sBAAsB;;;;;CAKzD,MAAa,QAAuB;EAClC,MAAM,eAAeA,WAAO,IAAI,QAAQ;EAExC,IAAI,CAAC,cACH;EAGF,IAAI;GACF,MAAM,EAAE,oBAAoB,MAAM,OAAO;GAEzC,IAAI,KAAK,UAAU,aAAa,UAAU,cAAc,8BAA8B;GACtF,MAAM,gBAAgB,YAAY;GAClC,IAAI,QAAQ,UAAU,aAAa,UAAU,cAAc,6BAA6B;GACxF,KAAK,SAAS;EAChB,SAAS,OAAO;GAId,IAAI,MACF,UAAU,aAAa,UACvB,cACA,qCACF;GACA,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GACF,MAAM,EAAE,mBAAmB,MAAM,OAAO;GAGxC,MAAM,UAAU,eAAe,OAAO;GAEtC,KAAK,MAAM,UAAU,SACnB,IAAI,OAAO,OAAO,aAChB,MAAM,OAAO,OAAO,WAAW;GAKnC,eAAe,MAAM;GAErB,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,IAAI,MAAM,UAAU,YAAY,0CAA0C;GAC1E,MAAM;EACR;CACF;AACF"}
@@ -9,7 +9,7 @@ import { health } from "../http/health.mjs";
9
9
  import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
10
10
  import { BaseConnector } from "./base-connector.mjs";
11
11
  import { devLogError } from "../dev-server/dev-logger.mjs";
12
- import config from "@mongez/config";
12
+ import baseConfig from "@mongez/config";
13
13
  import { log } from "@warlock.js/logger";
14
14
  import { colors } from "@mongez/copper";
15
15
 
@@ -45,14 +45,14 @@ var HttpConnector = class extends BaseConnector {
45
45
  * `start()` so it reads the router after app code has registered.
46
46
  */
47
47
  async boot() {
48
- const httpConfig = config.get("http");
48
+ const httpConfig = baseConfig.get("http");
49
49
  if (!httpConfig) return;
50
50
  const port = httpConfig.port;
51
51
  log.info(`http`, "connection", `Starting http server on port ${port} in ${environmentColor(Application.environment)} mode`);
52
52
  this.http = startHttpServer(httpConfig.serverOptions);
53
53
  container.set("http.server", this.http);
54
54
  await registerHttpPlugins(this.http);
55
- setBaseUrl(config.get("app.baseUrl"));
55
+ setBaseUrl(baseConfig.get("app.baseUrl"));
56
56
  this.registerHealthRoutes();
57
57
  }
58
58
  /**
@@ -64,7 +64,7 @@ var HttpConnector = class extends BaseConnector {
64
64
  */
65
65
  registerHealthRoutes() {
66
66
  if (!this.http) return;
67
- const healthConfig = config.get("http.health");
67
+ const healthConfig = baseConfig.get("http.health");
68
68
  if (healthConfig?.enabled === false) return;
69
69
  const livenessPath = healthConfig?.path ?? "/health";
70
70
  const readinessPath = healthConfig?.readinessPath ?? "/ready";
@@ -83,7 +83,7 @@ var HttpConnector = class extends BaseConnector {
83
83
  * app code without losing routes.
84
84
  */
85
85
  async start() {
86
- const httpConfig = config.get("http");
86
+ const httpConfig = baseConfig.get("http");
87
87
  if (!httpConfig || !this.http) return;
88
88
  if (Application.runtimeStrategy === "development") router.scanDevServer(this.http);
89
89
  else router.scan(this.http);
@@ -94,7 +94,7 @@ var HttpConnector = class extends BaseConnector {
94
94
  port: httpConfig.port,
95
95
  host: httpConfig.host || "localhost"
96
96
  });
97
- const baseUrl = config.get("app.baseUrl");
97
+ const baseUrl = baseConfig.get("app.baseUrl");
98
98
  log.success(`http`, "connection", `Server ready at ${baseUrl}`);
99
99
  } catch (error) {
100
100
  devLogError("Error while starting http server", error);
@@ -121,7 +121,7 @@ var HttpConnector = class extends BaseConnector {
121
121
  if (!this.active) return;
122
122
  const server = getHttpServer();
123
123
  if (server) {
124
- const timeout = config.get("http.gracefulShutdown.timeout", DEFAULT_SHUTDOWN_TIMEOUT);
124
+ const timeout = baseConfig.get("http.gracefulShutdown.timeout", DEFAULT_SHUTDOWN_TIMEOUT);
125
125
  if (!await closeServerWithTimeout(server, timeout)) log.warn("http", "shutdown", `In-flight requests did not drain within ${timeout}ms; closing anyway`);
126
126
  }
127
127
  this.active = false;
@@ -1 +1 @@
1
- {"version":3,"file":"http-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/http-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { colors } from \"@mongez/copper\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { Application } from \"../application\";\r\nimport { devLogError } from \"../dev-server/dev-logger\";\r\nimport { health } from \"../http/health\";\r\nimport { registerHttpPlugins } from \"../http/plugins\";\r\nimport { closeServerWithTimeout, FastifyInstance, getHttpServer, startHttpServer } from \"../http/server\";\r\nimport { router } from \"../router/router\";\r\nimport { Environment } from \"../utils\";\r\nimport { setBaseUrl } from \"../utils/urls\";\r\nimport { container } from \"./../container\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\nfunction environmentColor(environment: Environment) {\r\n switch (environment) {\r\n case \"development\":\r\n return colors.magentaBright(environment);\r\n case \"test\":\r\n return colors.yellowBright(environment);\r\n case \"production\":\r\n return colors.greenBright(environment);\r\n default:\r\n return colors.white(environment);\r\n }\r\n}\r\n\r\n/**\r\n * Default time to wait for in-flight requests to drain on shutdown before the\r\n * HTTP server is force-closed. Override via `http.gracefulShutdown.timeout`.\r\n */\r\nconst DEFAULT_SHUTDOWN_TIMEOUT = 10_000;\r\n\r\n/**\r\n * HTTP Connector\r\n * Manages HTTP server (Fastify) lifecycle\r\n */\r\nexport class HttpConnector extends BaseConnector {\r\n public readonly name = \"http\";\r\n public readonly priority = ConnectorPriority.HTTP;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Late;\r\n\r\n /**\r\n * Files that trigger HTTP server restart\r\n * Note: routes.ts changes will be handled by HMR with wildcard routing\r\n * Connectors receive config file paths directly (not .env) thanks to layer-executor\r\n */\r\n protected readonly watchedFiles = [\"src/config/http.ts\", \"src/config/http.tsx\"];\r\n\r\n /**\r\n * Fastify Server instance\r\n */\r\n protected http?: FastifyInstance;\r\n\r\n /**\r\n * Boot the connector — construction only (create Fastify, register\r\n * plugins, populate container). Route scanning is deferred to\r\n * `start()` so it reads the router after app code has registered.\r\n */\r\n public async boot() {\r\n const httpConfig = config.get(\"http\");\r\n\r\n if (!httpConfig) return;\r\n\r\n const port = httpConfig.port;\r\n log.info(\r\n `http`,\r\n \"connection\",\r\n `Starting http server on port ${port} in ${environmentColor(Application.environment)} mode`,\r\n );\r\n\r\n this.http = startHttpServer(httpConfig.serverOptions);\r\n\r\n container.set(\"http.server\", this.http);\r\n\r\n await registerHttpPlugins(this.http);\r\n\r\n const baseUrl = config.get(\"app.baseUrl\");\r\n\r\n // update base url\r\n setBaseUrl(baseUrl);\r\n\r\n // Liveness/readiness endpoints — registered on Fastify before start() scans\r\n // the app router, so they exist by the time the server listens.\r\n this.registerHealthRoutes();\r\n }\r\n\r\n /**\r\n * Register the built-in liveness (`/health`) and readiness (`/ready`)\r\n * endpoints directly on the Fastify instance — infra routes, kept off the app\r\n * router so they're immune to HMR and never collide with route scanning. Opt\r\n * out via `http.health.enabled = false`; rename via `http.health.path` /\r\n * `http.health.readinessPath`.\r\n */\r\n private registerHealthRoutes(): void {\r\n if (!this.http) {\r\n return;\r\n }\r\n\r\n const healthConfig = config.get(\"http.health\");\r\n\r\n if (healthConfig?.enabled === false) {\r\n return;\r\n }\r\n\r\n const livenessPath = healthConfig?.path ?? \"/health\";\r\n const readinessPath = healthConfig?.readinessPath ?? \"/ready\";\r\n\r\n this.http.get(livenessPath, async (_request: any, reply: any) => {\r\n const result = health.liveness();\r\n\r\n return reply.code(result.status === \"ok\" ? 200 : 503).send(result);\r\n });\r\n\r\n this.http.get(readinessPath, async (_request: any, reply: any) => {\r\n const result = await health.readiness();\r\n\r\n return reply.code(result.status === \"ok\" ? 200 : 503).send(result);\r\n });\r\n }\r\n\r\n /**\r\n * Initialize HTTP server — bind app-registered routes to Fastify\r\n * then listen. Scanning here (not in `boot`) lets HTTP boot before\r\n * app code without losing routes.\r\n */\r\n public async start(): Promise<void> {\r\n const httpConfig = config.get(\"http\");\r\n\r\n if (!httpConfig || !this.http) return;\r\n\r\n if (Application.runtimeStrategy === \"development\") {\r\n router.scanDevServer(this.http);\r\n } else {\r\n router.scan(this.http);\r\n }\r\n\r\n // Surface the route table as a readiness signal + a boot log, so an empty\r\n // or partial route surface (e.g. a route module that failed to register) is\r\n // detectable instead of silently 404ing. `addRoutesRegisteredCheck` is\r\n // keyed by name, so re-running on restart is idempotent.\r\n health.addRoutesRegisteredCheck(() => router.routeCount());\r\n log.info(\"http\", \"routes\", `${router.routeCount()} route(s) registered`);\r\n\r\n try {\r\n // We can use the url of the server\r\n await this.http.listen({\r\n port: httpConfig.port,\r\n host: httpConfig.host || \"localhost\",\r\n });\r\n\r\n const baseUrl = config.get(\"app.baseUrl\");\r\n\r\n log.success(`http`, \"connection\", `Server ready at ${baseUrl}`);\r\n } catch (error) {\r\n devLogError(\"Error while starting http server\", error);\r\n\r\n // A failed listen()/port-bind at boot means the app can't serve — fatal.\r\n // devLogError above is the dev-server console UI and bypasses the logger\r\n // pipeline, so also route it through `log.fatal` to reach Sentry/file,\r\n // then `await log.flush()` to drain buffered/async channels before exit.\r\n await log.fatal(\"http\", \"connection\", error);\r\n await log.flush();\r\n\r\n process.exit(1); // stop the process, exit with error\r\n }\r\n\r\n this.active = true;\r\n }\r\n\r\n /**\r\n * Restart — needs a fresh Fastify instance since `start()` now\r\n * re-runs `router.scan()`, and re-scanning the same Fastify would\r\n * register duplicate route handlers.\r\n */\r\n public async restart(): Promise<void> {\r\n await this.shutdown();\r\n await this.boot();\r\n await this.start();\r\n }\r\n\r\n /**\r\n * Shutdown HTTP server\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n const server = getHttpServer();\r\n\r\n if (server) {\r\n const timeout = config.get(\"http.gracefulShutdown.timeout\", DEFAULT_SHUTDOWN_TIMEOUT);\r\n const drained = await closeServerWithTimeout(server, timeout);\r\n\r\n if (!drained) {\r\n log.warn(\r\n \"http\",\r\n \"shutdown\",\r\n `In-flight requests did not drain within ${timeout}ms; closing anyway`,\r\n );\r\n }\r\n }\r\n\r\n this.active = false;\r\n }\r\n\r\n /**\r\n * Override shouldRestart to handle routes.ts specially\r\n * routes.ts changes should NOT restart the server (use HMR instead)\r\n * Now receives config file paths directly from layer-executor\r\n */\r\n public shouldRestart(changedFiles: string[]): boolean {\r\n // Only restart for config changes, not routes\r\n return changedFiles.some((file) => {\r\n const relativePath = file.replace(/\\\\/g, \"/\");\r\n return this.watchedFiles.includes(relativePath);\r\n });\r\n }\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"http-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/http-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { colors } from \"@mongez/copper\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { Application } from \"../application\";\r\nimport { devLogError } from \"../dev-server/dev-logger\";\r\nimport { health } from \"../http/health\";\r\nimport { registerHttpPlugins } from \"../http/plugins\";\r\nimport { closeServerWithTimeout, FastifyInstance, getHttpServer, startHttpServer } from \"../http/server\";\r\nimport { router } from \"../router/router\";\r\nimport { Environment } from \"../utils\";\r\nimport { setBaseUrl } from \"../utils/urls\";\r\nimport { container } from \"./../container\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\nfunction environmentColor(environment: Environment) {\r\n switch (environment) {\r\n case \"development\":\r\n return colors.magentaBright(environment);\r\n case \"test\":\r\n return colors.yellowBright(environment);\r\n case \"production\":\r\n return colors.greenBright(environment);\r\n default:\r\n return colors.white(environment);\r\n }\r\n}\r\n\r\n/**\r\n * Default time to wait for in-flight requests to drain on shutdown before the\r\n * HTTP server is force-closed. Override via `http.gracefulShutdown.timeout`.\r\n */\r\nconst DEFAULT_SHUTDOWN_TIMEOUT = 10_000;\r\n\r\n/**\r\n * HTTP Connector\r\n * Manages HTTP server (Fastify) lifecycle\r\n */\r\nexport class HttpConnector extends BaseConnector {\r\n public readonly name = \"http\";\r\n public readonly priority = ConnectorPriority.HTTP;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Late;\r\n\r\n /**\r\n * Files that trigger HTTP server restart\r\n * Note: routes.ts changes will be handled by HMR with wildcard routing\r\n * Connectors receive config file paths directly (not .env) thanks to layer-executor\r\n */\r\n protected readonly watchedFiles = [\"src/config/http.ts\", \"src/config/http.tsx\"];\r\n\r\n /**\r\n * Fastify Server instance\r\n */\r\n protected http?: FastifyInstance;\r\n\r\n /**\r\n * Boot the connector — construction only (create Fastify, register\r\n * plugins, populate container). Route scanning is deferred to\r\n * `start()` so it reads the router after app code has registered.\r\n */\r\n public async boot() {\r\n const httpConfig = config.get(\"http\");\r\n\r\n if (!httpConfig) return;\r\n\r\n const port = httpConfig.port;\r\n log.info(\r\n `http`,\r\n \"connection\",\r\n `Starting http server on port ${port} in ${environmentColor(Application.environment)} mode`,\r\n );\r\n\r\n this.http = startHttpServer(httpConfig.serverOptions);\r\n\r\n container.set(\"http.server\", this.http);\r\n\r\n await registerHttpPlugins(this.http);\r\n\r\n const baseUrl = config.get(\"app.baseUrl\");\r\n\r\n // update base url\r\n setBaseUrl(baseUrl);\r\n\r\n // Liveness/readiness endpoints — registered on Fastify before start() scans\r\n // the app router, so they exist by the time the server listens.\r\n this.registerHealthRoutes();\r\n }\r\n\r\n /**\r\n * Register the built-in liveness (`/health`) and readiness (`/ready`)\r\n * endpoints directly on the Fastify instance — infra routes, kept off the app\r\n * router so they're immune to HMR and never collide with route scanning. Opt\r\n * out via `http.health.enabled = false`; rename via `http.health.path` /\r\n * `http.health.readinessPath`.\r\n */\r\n private registerHealthRoutes(): void {\r\n if (!this.http) {\r\n return;\r\n }\r\n\r\n const healthConfig = config.get(\"http.health\");\r\n\r\n if (healthConfig?.enabled === false) {\r\n return;\r\n }\r\n\r\n const livenessPath = healthConfig?.path ?? \"/health\";\r\n const readinessPath = healthConfig?.readinessPath ?? \"/ready\";\r\n\r\n this.http.get(livenessPath, async (_request: any, reply: any) => {\r\n const result = health.liveness();\r\n\r\n return reply.code(result.status === \"ok\" ? 200 : 503).send(result);\r\n });\r\n\r\n this.http.get(readinessPath, async (_request: any, reply: any) => {\r\n const result = await health.readiness();\r\n\r\n return reply.code(result.status === \"ok\" ? 200 : 503).send(result);\r\n });\r\n }\r\n\r\n /**\r\n * Initialize HTTP server — bind app-registered routes to Fastify\r\n * then listen. Scanning here (not in `boot`) lets HTTP boot before\r\n * app code without losing routes.\r\n */\r\n public async start(): Promise<void> {\r\n const httpConfig = config.get(\"http\");\r\n\r\n if (!httpConfig || !this.http) return;\r\n\r\n if (Application.runtimeStrategy === \"development\") {\r\n router.scanDevServer(this.http);\r\n } else {\r\n router.scan(this.http);\r\n }\r\n\r\n // Surface the route table as a readiness signal + a boot log, so an empty\r\n // or partial route surface (e.g. a route module that failed to register) is\r\n // detectable instead of silently 404ing. `addRoutesRegisteredCheck` is\r\n // keyed by name, so re-running on restart is idempotent.\r\n health.addRoutesRegisteredCheck(() => router.routeCount());\r\n log.info(\"http\", \"routes\", `${router.routeCount()} route(s) registered`);\r\n\r\n try {\r\n // We can use the url of the server\r\n await this.http.listen({\r\n port: httpConfig.port,\r\n host: httpConfig.host || \"localhost\",\r\n });\r\n\r\n const baseUrl = config.get(\"app.baseUrl\");\r\n\r\n log.success(`http`, \"connection\", `Server ready at ${baseUrl}`);\r\n } catch (error) {\r\n devLogError(\"Error while starting http server\", error);\r\n\r\n // A failed listen()/port-bind at boot means the app can't serve — fatal.\r\n // devLogError above is the dev-server console UI and bypasses the logger\r\n // pipeline, so also route it through `log.fatal` to reach Sentry/file,\r\n // then `await log.flush()` to drain buffered/async channels before exit.\r\n await log.fatal(\"http\", \"connection\", error);\r\n await log.flush();\r\n\r\n process.exit(1); // stop the process, exit with error\r\n }\r\n\r\n this.active = true;\r\n }\r\n\r\n /**\r\n * Restart — needs a fresh Fastify instance since `start()` now\r\n * re-runs `router.scan()`, and re-scanning the same Fastify would\r\n * register duplicate route handlers.\r\n */\r\n public async restart(): Promise<void> {\r\n await this.shutdown();\r\n await this.boot();\r\n await this.start();\r\n }\r\n\r\n /**\r\n * Shutdown HTTP server\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n const server = getHttpServer();\r\n\r\n if (server) {\r\n const timeout = config.get(\"http.gracefulShutdown.timeout\", DEFAULT_SHUTDOWN_TIMEOUT);\r\n const drained = await closeServerWithTimeout(server, timeout);\r\n\r\n if (!drained) {\r\n log.warn(\r\n \"http\",\r\n \"shutdown\",\r\n `In-flight requests did not drain within ${timeout}ms; closing anyway`,\r\n );\r\n }\r\n }\r\n\r\n this.active = false;\r\n }\r\n\r\n /**\r\n * Override shouldRestart to handle routes.ts specially\r\n * routes.ts changes should NOT restart the server (use HMR instead)\r\n * Now receives config file paths directly from layer-executor\r\n */\r\n public shouldRestart(changedFiles: string[]): boolean {\r\n // Only restart for config changes, not routes\r\n return changedFiles.some((file) => {\r\n const relativePath = file.replace(/\\\\/g, \"/\");\r\n return this.watchedFiles.includes(relativePath);\r\n });\r\n }\r\n}\r\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
2
2
  import { BaseConnector } from "./base-connector.mjs";
3
3
  import { setLogConfigurations } from "../logger/logger.mjs";
4
4
  import "../logger/index.mjs";
5
- import config from "@mongez/config";
5
+ import baseConfig from "@mongez/config";
6
6
  import { log } from "@warlock.js/logger";
7
7
 
8
8
  //#region ../@warlock.js/core/src/connectors/logger-connector.ts
@@ -22,7 +22,7 @@ var LoggerConnector = class extends BaseConnector {
22
22
  * Initialize logger configurations
23
23
  */
24
24
  async start() {
25
- const logConfig = config.get("log");
25
+ const logConfig = baseConfig.get("log");
26
26
  if (!logConfig) return;
27
27
  try {
28
28
  setLogConfigurations(logConfig);
@@ -1 +1 @@
1
- {"version":3,"file":"logger-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/logger-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { setLogConfigurations } from \"../logger\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Logger Connector\r\n * Manages logger lifecycle and ensures synchronous flushing on termination\r\n */\r\nexport class LoggerConnector extends BaseConnector {\r\n public readonly name = \"logger\";\r\n public readonly priority = ConnectorPriority.LOGGER;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger logger restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/log.ts\", \"src/config/log.tsx\"];\r\n\r\n /**\r\n * Initialize logger configurations\r\n */\r\n public async start(): Promise<void> {\r\n const logConfig = config.get(\"log\");\r\n\r\n if (!logConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n setLogConfigurations(logConfig);\r\n this.active = true;\r\n } catch (error) {\r\n console.error(\"Failed to initialize logger:\", error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown logger and flush messages synchronously\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n log.flushSync();\r\n this.active = false;\r\n } catch (error) {\r\n console.error(\"Failed to flush logger:\", error);\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;AAUA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW,CAAC,qBAAqB,oBAAoB;;;;;CAK5E,MAAa,QAAuB;EAClC,MAAM,YAAY,OAAO,IAAI,KAAK;EAElC,IAAI,CAAC,WACH;EAGF,IAAI;GACF,qBAAqB,SAAS;GAC9B,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GACF,IAAI,UAAU;GACd,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,2BAA2B,KAAK;GAC9C,MAAM;EACR;CACF;AACF"}
1
+ {"version":3,"file":"logger-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/logger-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { setLogConfigurations } from \"../logger\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Logger Connector\r\n * Manages logger lifecycle and ensures synchronous flushing on termination\r\n */\r\nexport class LoggerConnector extends BaseConnector {\r\n public readonly name = \"logger\";\r\n public readonly priority = ConnectorPriority.LOGGER;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger logger restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/log.ts\", \"src/config/log.tsx\"];\r\n\r\n /**\r\n * Initialize logger configurations\r\n */\r\n public async start(): Promise<void> {\r\n const logConfig = config.get(\"log\");\r\n\r\n if (!logConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n setLogConfigurations(logConfig);\r\n this.active = true;\r\n } catch (error) {\r\n console.error(\"Failed to initialize logger:\", error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown logger and flush messages synchronously\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n log.flushSync();\r\n this.active = false;\r\n } catch (error) {\r\n console.error(\"Failed to flush logger:\", error);\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;AAUA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW,CAAC,qBAAqB,oBAAoB;;;;;CAK5E,MAAa,QAAuB;EAClC,MAAM,YAAYA,WAAO,IAAI,KAAK;EAElC,IAAI,CAAC,WACH;EAGF,IAAI;GACF,qBAAqB,SAAS;GAC9B,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GACF,IAAI,UAAU;GACd,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,2BAA2B,KAAK;GAC9C,MAAM;EACR;CACF;AACF"}
@@ -3,7 +3,7 @@ import { BaseConnector } from "./base-connector.mjs";
3
3
  import { setMailConfigurations } from "../mail/config.mjs";
4
4
  import { closeAllMailers } from "../mail/mailer-pool.mjs";
5
5
  import "../mail/index.mjs";
6
- import config from "@mongez/config";
6
+ import baseConfig from "@mongez/config";
7
7
 
8
8
  //#region ../@warlock.js/core/src/connectors/mail-connector.ts
9
9
  /**
@@ -26,7 +26,7 @@ var MailerConnector = class extends BaseConnector {
26
26
  * Initialize mailer configurations
27
27
  */
28
28
  async start() {
29
- const mailConfig = config.get("mail");
29
+ const mailConfig = baseConfig.get("mail");
30
30
  if (!mailConfig) return;
31
31
  try {
32
32
  setMailConfigurations(mailConfig);
@@ -1 +1 @@
1
- {"version":3,"file":"mail-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/mail-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { closeAllMailers, setMailConfigurations } from \"../mail\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Mailer Connector\r\n * Manages mailer lifecycle and ensures graceful pool shutdown\r\n */\r\nexport class MailerConnector extends BaseConnector {\r\n public readonly name = \"mailer\";\r\n public readonly priority = ConnectorPriority.MAILER;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger mailer restart\r\n */\r\n protected readonly watchedFiles = [\".env\", \"src/config/mail.ts\", \"src/config/mail.tsx\"];\r\n\r\n /**\r\n * Initialize mailer configurations\r\n */\r\n public async start(): Promise<void> {\r\n const mailConfig = config.get(\"mail\");\r\n\r\n if (!mailConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n setMailConfigurations(mailConfig);\r\n this.active = true;\r\n } catch (error) {\r\n console.error(\"Failed to initialize mailer:\", error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown mailer pool\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n closeAllMailers();\r\n this.active = false;\r\n } catch (error) {\r\n console.error(\"Failed to close all mailers:\", error);\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;AASA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW;GAAC;GAAQ;GAAsB;EAAqB;;;;;CAKtF,MAAa,QAAuB;EAClC,MAAM,aAAa,OAAO,IAAI,MAAM;EAEpC,IAAI,CAAC,YACH;EAGF,IAAI;GACF,sBAAsB,UAAU;GAChC,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GACF,gBAAgB;GAChB,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD,MAAM;EACR;CACF;AACF"}
1
+ {"version":3,"file":"mail-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/mail-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { closeAllMailers, setMailConfigurations } from \"../mail\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Mailer Connector\r\n * Manages mailer lifecycle and ensures graceful pool shutdown\r\n */\r\nexport class MailerConnector extends BaseConnector {\r\n public readonly name = \"mailer\";\r\n public readonly priority = ConnectorPriority.MAILER;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger mailer restart\r\n */\r\n protected readonly watchedFiles = [\".env\", \"src/config/mail.ts\", \"src/config/mail.tsx\"];\r\n\r\n /**\r\n * Initialize mailer configurations\r\n */\r\n public async start(): Promise<void> {\r\n const mailConfig = config.get(\"mail\");\r\n\r\n if (!mailConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n setMailConfigurations(mailConfig);\r\n this.active = true;\r\n } catch (error) {\r\n console.error(\"Failed to initialize mailer:\", error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown mailer pool\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n closeAllMailers();\r\n this.active = false;\r\n } catch (error) {\r\n console.error(\"Failed to close all mailers:\", error);\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;AASA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW;GAAC;GAAQ;GAAsB;EAAqB;;;;;CAKtF,MAAa,QAAuB;EAClC,MAAM,aAAaA,WAAO,IAAI,MAAM;EAEpC,IAAI,CAAC,YACH;EAGF,IAAI;GACF,sBAAsB,UAAU;GAChC,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GACF,gBAAgB;GAChB,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD,MAAM;EACR;CACF;AACF"}
@@ -1,6 +1,6 @@
1
1
  import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
2
2
  import { BaseConnector } from "./base-connector.mjs";
3
- import config from "@mongez/config";
3
+ import baseConfig from "@mongez/config";
4
4
  import { log } from "@warlock.js/logger";
5
5
 
6
6
  //#region ../@warlock.js/core/src/connectors/notifications-connector.ts
@@ -28,7 +28,7 @@ var NotificationsConnector = class extends BaseConnector {
28
28
  * Register the notifications configuration with the package.
29
29
  */
30
30
  async start() {
31
- const notificationsConfig = config.get("notifications");
31
+ const notificationsConfig = baseConfig.get("notifications");
32
32
  if (!notificationsConfig) return;
33
33
  const { setNotificationConfig } = await import("@warlock.js/notifications");
34
34
  setNotificationConfig(notificationsConfig);
@@ -1 +1 @@
1
- {"version":3,"file":"notifications-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/notifications-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport { BaseConnector } from \"./base-connector\";\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\n\n/**\n * Notifications Connector\n *\n * Wires `@warlock.js/notifications` from `src/config/notifications.ts` at boot:\n * reads the exported config object and hands it to the package's\n * `setNotificationConfig`. Config files stay declarative — they export the\n * config, the connector performs the side-effect.\n *\n * The package is lazy-imported (only when a notifications config is present),\n * so core carries no hard dependency on it — the same pattern as the herald\n * connector with `@warlock.js/herald`.\n */\nexport class NotificationsConnector extends BaseConnector {\n public readonly name = \"notifications\";\n public readonly priority = ConnectorPriority.NOTIFICATIONS;\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\n\n /**\n * Files that trigger a notifications restart\n */\n protected readonly watchedFiles = [\"src/config/notifications.ts\"];\n\n /**\n * Register the notifications configuration with the package.\n */\n public async start(): Promise<void> {\n const notificationsConfig = config.get(\"notifications\");\n\n if (!notificationsConfig) {\n return;\n }\n\n const { setNotificationConfig } = await import(\"@warlock.js/notifications\");\n\n setNotificationConfig(notificationsConfig);\n this.active = true;\n\n log.info(\"notifications\", \"configured\", \"Notifications wired from config/notifications.ts\");\n }\n\n /**\n * Nothing to tear down — the package holds no external connection of its own\n * (the optional queue worker + its broker own their lifecycle). Clear the\n * active flag so a dev restart re-registers from the (possibly changed) config.\n */\n public async shutdown(): Promise<void> {\n if (!this.active) {\n return;\n }\n\n this.active = false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiBA,IAAa,yBAAb,cAA4C,cAAc;;;cACjC;;;sBAOW,CAAC,6BAA6B;;;;;CAKhE,MAAa,QAAuB;EAClC,MAAM,sBAAsB,OAAO,IAAI,eAAe;EAEtD,IAAI,CAAC,qBACH;EAGF,MAAM,EAAE,0BAA0B,MAAM,OAAO;EAE/C,sBAAsB,mBAAmB;EACzC,KAAK,SAAS;EAEd,IAAI,KAAK,iBAAiB,cAAc,kDAAkD;CAC5F;;;;;;CAOA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,KAAK,SAAS;CAChB;AACF"}
1
+ {"version":3,"file":"notifications-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/notifications-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport { BaseConnector } from \"./base-connector\";\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\n\n/**\n * Notifications Connector\n *\n * Wires `@warlock.js/notifications` from `src/config/notifications.ts` at boot:\n * reads the exported config object and hands it to the package's\n * `setNotificationConfig`. Config files stay declarative — they export the\n * config, the connector performs the side-effect.\n *\n * The package is lazy-imported (only when a notifications config is present),\n * so core carries no hard dependency on it — the same pattern as the herald\n * connector with `@warlock.js/herald`.\n */\nexport class NotificationsConnector extends BaseConnector {\n public readonly name = \"notifications\";\n public readonly priority = ConnectorPriority.NOTIFICATIONS;\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\n\n /**\n * Files that trigger a notifications restart\n */\n protected readonly watchedFiles = [\"src/config/notifications.ts\"];\n\n /**\n * Register the notifications configuration with the package.\n */\n public async start(): Promise<void> {\n const notificationsConfig = config.get(\"notifications\");\n\n if (!notificationsConfig) {\n return;\n }\n\n const { setNotificationConfig } = await import(\"@warlock.js/notifications\");\n\n setNotificationConfig(notificationsConfig);\n this.active = true;\n\n log.info(\"notifications\", \"configured\", \"Notifications wired from config/notifications.ts\");\n }\n\n /**\n * Nothing to tear down — the package holds no external connection of its own\n * (the optional queue worker + its broker own their lifecycle). Clear the\n * active flag so a dev restart re-registers from the (possibly changed) config.\n */\n public async shutdown(): Promise<void> {\n if (!this.active) {\n return;\n }\n\n this.active = false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiBA,IAAa,yBAAb,cAA4C,cAAc;;;cACjC;;;sBAOW,CAAC,6BAA6B;;;;;CAKhE,MAAa,QAAuB;EAClC,MAAM,sBAAsBA,WAAO,IAAI,eAAe;EAEtD,IAAI,CAAC,qBACH;EAGF,MAAM,EAAE,0BAA0B,MAAM,OAAO;EAE/C,sBAAsB,mBAAmB;EACzC,KAAK,SAAS;EAEd,IAAI,KAAK,iBAAiB,cAAc,kDAAkD;CAC5F;;;;;;CAOA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,KAAK,SAAS;CAChB;AACF"}