@warlock.js/core 4.9.2 → 4.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/esm/application/application.d.mts +19 -0
- package/esm/application/application.d.mts.map +1 -1
- package/esm/application/application.mjs +25 -0
- package/esm/application/application.mjs.map +1 -1
- package/esm/application/boot-signal.d.mts +77 -0
- package/esm/application/boot-signal.d.mts.map +1 -0
- package/esm/application/boot-signal.mjs +64 -0
- package/esm/application/boot-signal.mjs.map +1 -0
- package/esm/application/index.d.mts +1 -0
- package/esm/application/index.mjs +2 -1
- package/esm/bootstrap.mjs +2 -2
- package/esm/bootstrap.mjs.map +1 -1
- package/esm/cli/cli-commands.manager.mjs +3 -3
- package/esm/cli/cli-commands.manager.mjs.map +1 -1
- package/esm/cli/cli-commands.utils.mjs +57 -1
- package/esm/cli/cli-commands.utils.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/module.generator.mjs +1 -1
- package/esm/cli/commands/generate/generators/module.generator.mjs.map +1 -1
- package/esm/cli/commands/start-production.command.mjs +4 -25
- package/esm/cli/commands/start-production.command.mjs.map +1 -1
- package/esm/cli/types.d.mts +6 -1
- package/esm/cli/types.d.mts.map +1 -1
- package/esm/config/config-setter.d.mts +27 -0
- package/esm/config/config-setter.d.mts.map +1 -0
- package/esm/config/config-setter.mjs +10 -0
- package/esm/config/config-setter.mjs.map +1 -0
- package/esm/config/index.mjs +1 -0
- package/esm/connectors/http-connector.d.mts.map +1 -1
- package/esm/connectors/http-connector.mjs +2 -1
- package/esm/connectors/http-connector.mjs.map +1 -1
- package/esm/connectors/storage.connector.d.mts +11 -5
- package/esm/connectors/storage.connector.d.mts.map +1 -1
- package/esm/connectors/storage.connector.mjs +11 -5
- package/esm/connectors/storage.connector.mjs.map +1 -1
- package/esm/dev-server/loader/load-hook.mjs +1 -1
- package/esm/generations/stubs.mjs +1 -1
- package/esm/generations/stubs.mjs.map +1 -1
- package/esm/http/index.d.mts +1 -0
- package/esm/http/index.mjs +1 -0
- package/esm/http/port-preflight.d.mts +34 -0
- package/esm/http/port-preflight.d.mts.map +1 -0
- package/esm/http/port-preflight.mjs +66 -0
- package/esm/http/port-preflight.mjs.map +1 -0
- package/esm/http/response.d.mts +17 -2
- package/esm/http/response.d.mts.map +1 -1
- package/esm/http/response.mjs +36 -2
- package/esm/http/response.mjs.map +1 -1
- package/esm/index.d.mts +6 -2
- package/esm/index.mjs +6 -2
- package/esm/production/assert-generated-imports.mjs +94 -0
- package/esm/production/assert-generated-imports.mjs.map +1 -0
- package/esm/production/production-builder.mjs +29 -4
- package/esm/production/production-builder.mjs.map +1 -1
- package/esm/production/production-supervisor.mjs +108 -0
- package/esm/production/production-supervisor.mjs.map +1 -0
- package/esm/storage/storage.d.mts +16 -0
- package/esm/storage/storage.d.mts.map +1 -1
- package/esm/storage/storage.mjs +24 -1
- package/esm/storage/storage.mjs.map +1 -1
- package/esm/tests/index.d.mts +2 -1
- package/esm/tests/index.mjs +1 -0
- package/esm/tests/start-http-development-server.d.mts +15 -2
- package/esm/tests/start-http-development-server.d.mts.map +1 -1
- package/esm/tests/start-http-development-server.mjs +43 -16
- package/esm/tests/start-http-development-server.mjs.map +1 -1
- package/esm/tests/test-helpers.d.mts.map +1 -1
- package/esm/tests/test-helpers.mjs +2 -1
- package/esm/tests/test-helpers.mjs.map +1 -1
- package/esm/tests/test-server-port-channel.d.mts +27 -0
- package/esm/tests/test-server-port-channel.d.mts.map +1 -0
- package/esm/tests/test-server-port-channel.mjs +32 -0
- package/esm/tests/test-server-port-channel.mjs.map +1 -0
- package/esm/utils/load-environment.mjs +59 -0
- package/esm/utils/load-environment.mjs.map +1 -0
- package/llms-full.txt +113 -7
- package/llms.txt +1 -1
- package/package.json +13 -13
- package/skills/run-app/SKILL.md +63 -0
- package/skills/send-response/SKILL.md +23 -4
- package/skills/test-http/SKILL.md +27 -3
|
@@ -30,6 +30,62 @@ async function displayStartupBanner({ environment }) {
|
|
|
30
30
|
console.log();
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
+
* Announce that the production server is up — printed on **stdout**, and only
|
|
34
|
+
* after the child process reported a completed boot.
|
|
35
|
+
*
|
|
36
|
+
* Stdout is the channel a supervisor or CI gate greps to decide the service is
|
|
37
|
+
* healthy, so nothing optimistic may be written to it: this function is the
|
|
38
|
+
* single place allowed to say "started", and it is called from exactly one
|
|
39
|
+
* place, the `warlock:ready` handler in the `start` command.
|
|
40
|
+
*/
|
|
41
|
+
async function displayProductionReadyBanner({ bootDurationMs } = {}) {
|
|
42
|
+
const version = await getWarlockVersion();
|
|
43
|
+
const duration = bootDurationMs ? colors.dim(` in ${bootDurationMs}ms`) : "";
|
|
44
|
+
console.log(` ⚡ ${colors.bold(colors.greenBright("Warlock.js"))} ${colors.dim(`v${version}`)} ${colors.green("✔")} production server started${duration}`);
|
|
45
|
+
console.log();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Report that the production server died before it ever served anything.
|
|
49
|
+
*
|
|
50
|
+
* Written to **both** streams on purpose. Stderr is where a human and a log
|
|
51
|
+
* collector look; stdout is where a supervisor that greps for the success
|
|
52
|
+
* banner looks, and it must find a failure there rather than silence — silence
|
|
53
|
+
* on stdout is what let a boot failure be recorded as a healthy start.
|
|
54
|
+
*/
|
|
55
|
+
function displayProductionStartFailure(exitCode) {
|
|
56
|
+
const lines = [
|
|
57
|
+
"",
|
|
58
|
+
` ${colors.red("✖")} ${colors.bold("warlock start")} failed — the server never finished booting`,
|
|
59
|
+
` ${colors.dim(`the application process exited with code ${exitCode}`)}`,
|
|
60
|
+
` ${colors.dim("the cause is printed above, in the application's own output")}`,
|
|
61
|
+
""
|
|
62
|
+
];
|
|
63
|
+
for (const line of lines) {
|
|
64
|
+
console.error(line);
|
|
65
|
+
console.log(line);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Note that a running child has not reported readiness yet.
|
|
70
|
+
*
|
|
71
|
+
* Emitted on **stderr** only. The process may be perfectly healthy — an older
|
|
72
|
+
* bundle has no readiness signal at all — so saying anything on stdout would be
|
|
73
|
+
* the very false-green this channel exists to prevent.
|
|
74
|
+
*
|
|
75
|
+
* The wording offers the likely causes rather than asserting one. It cannot
|
|
76
|
+
* distinguish an old bundle from a slow boot from a boot that is about to fail,
|
|
77
|
+
* and an earlier version claimed "the bundle predates readiness reporting" —
|
|
78
|
+
* which was simply wrong when a current bundle was mid-crash, and sent the
|
|
79
|
+
* reader after the wrong thing.
|
|
80
|
+
*/
|
|
81
|
+
function displayMissingReadinessNotice(waitedMs) {
|
|
82
|
+
console.error();
|
|
83
|
+
console.error(` ${colors.yellow("!")} still running after ${Math.round(waitedMs / 1e3)}s with no readiness signal`);
|
|
84
|
+
console.error(` ${colors.dim("either the boot is still in progress, or this bundle was built")}`);
|
|
85
|
+
console.error(` ${colors.dim("before readiness reporting — re-run")} ${colors.cyan("warlock build")} ${colors.dim("if the banner never appears")}`);
|
|
86
|
+
console.error();
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
33
89
|
* Display command execution header
|
|
34
90
|
*/
|
|
35
91
|
function displayExecutingCommand(commandName) {
|
|
@@ -213,5 +269,5 @@ function displayCommandHelp(command) {
|
|
|
213
269
|
}
|
|
214
270
|
|
|
215
271
|
//#endregion
|
|
216
|
-
export { displayBootError, displayCommandError, displayCommandHelp, displayCommandNotFound, displayCommandSuccess, displayExecutingCommand, displayHelp, displayMissingCommand, displayMissingOptions, displayStartupBanner, displayWarlockVersionInTerminal, isMatchingCommandName };
|
|
272
|
+
export { displayBootError, displayCommandError, displayCommandHelp, displayCommandNotFound, displayCommandSuccess, displayExecutingCommand, displayHelp, displayMissingCommand, displayMissingOptions, displayMissingReadinessNotice, displayProductionReadyBanner, displayProductionStartFailure, displayStartupBanner, displayWarlockVersionInTerminal, isMatchingCommandName };
|
|
217
273
|
//# sourceMappingURL=cli-commands.utils.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-commands.utils.mjs","names":[],"sources":["../../../../../../../core/src/cli/cli-commands.utils.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport { Environment } from \"../utils\";\nimport { getWarlockVersion } from \"../utils/framework-vesion\";\n\nexport function isMatchingCommandName(commandName: string, targetingCommandName: string) {\n return commandName.split(\" \")[0] === targetingCommandName;\n}\n\n/**\n * Display the Warlock.js version banner\n */\nexport async function displayWarlockVersionInTerminal() {\n const version = await getWarlockVersion();\n console.log(`⚡ ${colors.bold(\"Warlock.js\")} ${colors.greenBright(`v${version}`)}`);\n}\n\ntype StartBannerOptions = {\n environment: Environment;\n};\n\nfunction getTextColorMethod(environment: Environment) {\n switch (environment) {\n case \"development\":\n return colors.yellowBright;\n case \"production\":\n return colors.greenBright;\n case \"test\":\n return colors.blueBright;\n default:\n return colors.whiteBright;\n }\n}\n\n/**\n * Display CLI startup banner\n */\nexport async function displayStartupBanner({ environment }: StartBannerOptions) {\n const version = await getWarlockVersion();\n const textColorMethod = getTextColorMethod(environment);\n console.log(` ⚡ ${colors.bold(textColorMethod(\"Warlock.js\"))} ${colors.dim(`v${version}`)}`);\n console.log();\n}\n\n/**\n * Display command execution header\n */\nexport function displayExecutingCommand(commandName: string) {\n console.log(` ${colors.cyan(\"›\")} Running ${colors.bold(colors.white(commandName))}...`);\n console.log();\n}\n\n/**\n * Display command not found error with optional suggestions\n */\nexport function displayCommandNotFound(commandName: string, suggestions?: string[]) {\n console.log();\n console.log(` ${colors.red(\"✖\")} Command ${colors.magenta(commandName)} not found`);\n\n if (suggestions && suggestions.length > 0) {\n console.log();\n console.log(` ${colors.yellow(\"Did you mean?\")}`);\n suggestions.forEach((suggestion) => {\n console.log(` ${colors.cyan(\"→\")} ${colors.white(suggestion)}`);\n });\n }\n\n console.log();\n console.log(\n ` ${colors.dim(\"Run\")} ${colors.cyan(\"warlock --help\")} ${colors.dim(\"to see available commands\")}`,\n );\n console.log();\n}\n\n/**\n * Display missing command error\n */\nexport function displayMissingCommand() {\n console.log();\n console.log(` ${colors.red(\"✖\")} No command specified`);\n console.log(\n ` ${colors.dim(\"Run\")} ${colors.cyan(\"warlock --help\")} ${colors.dim(\"to see available commands\")}`,\n );\n console.log();\n}\n\n/**\n * Display command success message\n */\nexport function displayCommandSuccess(commandName: string, durationMs?: number) {\n const duration = durationMs ? colors.dim(` (${durationMs}ms)`) : \"\";\n console.log();\n console.log(\n ` ${colors.green(\"✔\")} ${colors.bold(commandName)} completed successfully${duration}`,\n );\n console.log();\n}\n\n/**\n * Display command error message\n */\nexport function displayCommandError(commandName: string, error: Error) {\n console.log();\n console.log(` ${colors.red(\"✖\")} ${colors.bold(commandName)} failed`);\n console.log(` ${colors.dim(error.message)}`);\n console.log();\n}\n\n/**\n * Display a FATAL boot/preload failure and exit information.\n *\n * Preload failures — a bad import in a config file, a connector that throws\n * on startup, a missing module export — happen BEFORE the command's run loop\n * exists, so there is nothing to recover into: they are always fatal. Unlike\n * `displayCommandError`, this prints the full stack (not just `error.message`)\n * because the stack names the exact file + line of the offending import, which\n * is the single most useful clue when a config file pulls in a broken module.\n *\n * Surfacing this loudly is the difference between a clear error and a silent\n * hang: an unhandled preload rejection used to escape while the already-started\n * loader worker thread kept the process alive, leaving `warlock dev` frozen\n * just after the banner with no message at all.\n *\n * @example\n * // SyntaxError: The requested module '@warlock.js/cascade' does not\n * // provide an export named 'belongsTo'\n * // at src/app/.../permission.model.ts:2\n */\nexport function displayBootError(commandName: string, error: Error) {\n console.log();\n console.log(` ${colors.red(\"✖\")} ${colors.bold(commandName)} failed to start`);\n console.log(` ${colors.red(error.message)}`);\n if (error.stack) {\n console.log();\n console.log(colors.dim(error.stack));\n }\n console.log();\n}\n\n/**\n * Display missing required options error\n */\nexport function displayMissingOptions(options: { name: string; text: string }[]) {\n console.log();\n console.log(` ${colors.red(\"✖\")} Missing required options:`);\n options.forEach((opt) => {\n console.log(` ${colors.yellow(opt.text)} ${colors.dim(`(--${opt.name})`)}`);\n });\n console.log();\n}\n\n/**\n * Command info for help display\n */\nexport type HelpCommandInfo = {\n name: string;\n alias?: string;\n description?: string;\n source: \"framework\" | \"plugin\" | \"project\";\n};\n\n/**\n * Display global help with all commands grouped by source\n */\nexport async function displayHelp(commands: HelpCommandInfo[]) {\n const version = await getWarlockVersion();\n\n console.log();\n console.log(\n ` ⚡ ${colors.bold(colors.yellowBright(\"Warlock.js\"))} CLI ${colors.dim(`v${version}`)}`,\n );\n console.log();\n console.log(\n ` ${colors.bold(\"Usage:\")} ${colors.cyan(\"warlock\")} ${colors.dim(\"<command>\")} ${colors.dim(\"[options]\")}`,\n );\n console.log();\n\n // Group by source\n const grouped: Record<string, HelpCommandInfo[]> = {\n framework: [],\n plugin: [],\n project: [],\n };\n\n commands.forEach((cmd) => {\n grouped[cmd.source]?.push(cmd);\n });\n\n // Display each group\n const groupLabels: Record<string, string> = {\n framework: \"Framework Commands\",\n plugin: \"Plugin Commands\",\n project: \"Project Commands\",\n };\n\n for (const [source, cmds] of Object.entries(grouped)) {\n if (cmds.length === 0) continue;\n\n console.log(` ${colors.bold(colors.white(groupLabels[source]))}`);\n console.log();\n\n // Find max name length for alignment\n const maxLen = Math.max(...cmds.map((c) => c.name.length + (c.alias ? c.alias.length + 4 : 0)));\n\n cmds.forEach((cmd) => {\n const aliasStr = cmd.alias ? colors.dim(` (${cmd.alias})`) : \"\";\n const nameWithAlias = cmd.name + (cmd.alias ? ` (${cmd.alias})` : \"\");\n const padding = \" \".repeat(maxLen - nameWithAlias.length + 2);\n // const desc = cmd.description || colors.dim(\"No description\");\n const desc = cmd.description || \"\";\n console.log(` ${colors.cyan(cmd.name)}${aliasStr}${padding}${desc}`);\n });\n console.log();\n }\n\n // Display global flags\n console.log(` ${colors.bold(colors.white(\"Global Flags\"))}`);\n console.log();\n\n const globalFlags = [\n { flag: \"--help, -h\", description: \"Show help for a command\" },\n { flag: \"--version, -v\", description: \"Show Warlock version\" },\n { flag: \"--no-cache\", description: \"Force reload without cache\" },\n { flag: \"--warm-cache\", description: \"Pre-cache all project commands\" },\n ];\n\n const maxFlagLen = Math.max(...globalFlags.map((f) => f.flag.length));\n\n globalFlags.forEach(({ flag, description }) => {\n const padding = \" \".repeat(maxFlagLen - flag.length + 2);\n console.log(` ${colors.yellow(flag)}${padding}${description}`);\n });\n console.log();\n\n console.log(\n ` ${colors.dim(\"Run\")} ${colors.cyan(\"warlock <command> --help\")} ${colors.dim(\"for command-specific help\")}`,\n );\n console.log();\n}\n\n/**\n * Display help for a specific command\n */\nexport function displayCommandHelp(command: {\n name: string;\n alias?: string;\n description?: string;\n options?: { name: string; text: string; description?: string; required?: boolean }[];\n}) {\n console.log();\n console.log(\n ` ${colors.bold(colors.cyan(command.name))}${command.alias ? colors.dim(` (${command.alias})`) : \"\"}`,\n );\n\n if (command.description) {\n console.log(` ${command.description}`);\n }\n console.log();\n\n if (command.options && command.options.length > 0) {\n console.log(` ${colors.bold(\"Options:\")}`);\n console.log();\n\n const maxLen = Math.max(...command.options.map((o) => o.text.length));\n\n command.options.forEach((opt) => {\n const padding = \" \".repeat(maxLen - opt.text.length + 2);\n const required = opt.required ? colors.red(\" (required)\") : \"\";\n const desc = opt.description || \"\";\n console.log(` ${colors.green(opt.text)}${padding}${desc}${required}`);\n });\n console.log();\n } else {\n console.log(` ${colors.dim(\"No options available\")}`);\n console.log();\n }\n}\n"],"mappings":";;;;AAIA,SAAgB,sBAAsB,aAAqB,sBAA8B;CACvF,OAAO,YAAY,MAAM,GAAG,CAAC,CAAC,OAAO;AACvC;;;;AAKA,eAAsB,kCAAkC;CACtD,MAAM,UAAU,MAAM,kBAAkB;CACxC,QAAQ,IAAI,KAAK,OAAO,KAAK,YAAY,EAAE,GAAG,OAAO,YAAY,IAAI,SAAS,GAAG;AACnF;AAMA,SAAS,mBAAmB,aAA0B;CACpD,QAAQ,aAAR;EACE,KAAK,eACH,OAAO,OAAO;EAChB,KAAK,cACH,OAAO,OAAO;EAChB,KAAK,QACH,OAAO,OAAO;EAChB,SACE,OAAO,OAAO;CAClB;AACF;;;;AAKA,eAAsB,qBAAqB,EAAE,eAAmC;CAC9E,MAAM,UAAU,MAAM,kBAAkB;CACxC,MAAM,kBAAkB,mBAAmB,WAAW;CACtD,QAAQ,IAAI,OAAO,OAAO,KAAK,gBAAgB,YAAY,CAAC,EAAE,GAAG,OAAO,IAAI,IAAI,SAAS,GAAG;CAC5F,QAAQ,IAAI;AACd;;;;AAKA,SAAgB,wBAAwB,aAAqB;CAC3D,QAAQ,IAAI,KAAK,OAAO,KAAK,GAAG,EAAE,WAAW,OAAO,KAAK,OAAO,MAAM,WAAW,CAAC,EAAE,IAAI;CACxF,QAAQ,IAAI;AACd;;;;AAKA,SAAgB,uBAAuB,aAAqB,aAAwB;CAClF,QAAQ,IAAI;CACZ,QAAQ,IAAI,KAAK,OAAO,IAAI,GAAG,EAAE,WAAW,OAAO,QAAQ,WAAW,EAAE,WAAW;CAEnF,IAAI,eAAe,YAAY,SAAS,GAAG;EACzC,QAAQ,IAAI;EACZ,QAAQ,IAAI,KAAK,OAAO,OAAO,eAAe,GAAG;EACjD,YAAY,SAAS,eAAe;GAClC,QAAQ,IAAI,OAAO,OAAO,KAAK,GAAG,EAAE,GAAG,OAAO,MAAM,UAAU,GAAG;EACnE,CAAC;CACH;CAEA,QAAQ,IAAI;CACZ,QAAQ,IACN,KAAK,OAAO,IAAI,KAAK,EAAE,GAAG,OAAO,KAAK,gBAAgB,EAAE,GAAG,OAAO,IAAI,2BAA2B,GACnG;CACA,QAAQ,IAAI;AACd;;;;AAKA,SAAgB,wBAAwB;CACtC,QAAQ,IAAI;CACZ,QAAQ,IAAI,KAAK,OAAO,IAAI,GAAG,EAAE,sBAAsB;CACvD,QAAQ,IACN,KAAK,OAAO,IAAI,KAAK,EAAE,GAAG,OAAO,KAAK,gBAAgB,EAAE,GAAG,OAAO,IAAI,2BAA2B,GACnG;CACA,QAAQ,IAAI;AACd;;;;AAKA,SAAgB,sBAAsB,aAAqB,YAAqB;CAC9E,MAAM,WAAW,aAAa,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI;CACjE,QAAQ,IAAI;CACZ,QAAQ,IACN,KAAK,OAAO,MAAM,GAAG,EAAE,GAAG,OAAO,KAAK,WAAW,EAAE,yBAAyB,UAC9E;CACA,QAAQ,IAAI;AACd;;;;AAKA,SAAgB,oBAAoB,aAAqB,OAAc;CACrE,QAAQ,IAAI;CACZ,QAAQ,IAAI,KAAK,OAAO,IAAI,GAAG,EAAE,GAAG,OAAO,KAAK,WAAW,EAAE,QAAQ;CACrE,QAAQ,IAAI,KAAK,OAAO,IAAI,MAAM,OAAO,GAAG;CAC5C,QAAQ,IAAI;AACd;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,iBAAiB,aAAqB,OAAc;CAClE,QAAQ,IAAI;CACZ,QAAQ,IAAI,KAAK,OAAO,IAAI,GAAG,EAAE,GAAG,OAAO,KAAK,WAAW,EAAE,iBAAiB;CAC9E,QAAQ,IAAI,KAAK,OAAO,IAAI,MAAM,OAAO,GAAG;CAC5C,IAAI,MAAM,OAAO;EACf,QAAQ,IAAI;EACZ,QAAQ,IAAI,OAAO,IAAI,MAAM,KAAK,CAAC;CACrC;CACA,QAAQ,IAAI;AACd;;;;AAKA,SAAgB,sBAAsB,SAA2C;CAC/E,QAAQ,IAAI;CACZ,QAAQ,IAAI,KAAK,OAAO,IAAI,GAAG,EAAE,2BAA2B;CAC5D,QAAQ,SAAS,QAAQ;EACvB,QAAQ,IAAI,QAAQ,OAAO,OAAO,IAAI,IAAI,EAAE,GAAG,OAAO,IAAI,MAAM,IAAI,KAAK,EAAE,GAAG;CAChF,CAAC;CACD,QAAQ,IAAI;AACd;;;;AAeA,eAAsB,YAAY,UAA6B;CAC7D,MAAM,UAAU,MAAM,kBAAkB;CAExC,QAAQ,IAAI;CACZ,QAAQ,IACN,OAAO,OAAO,KAAK,OAAO,aAAa,YAAY,CAAC,EAAE,OAAO,OAAO,IAAI,IAAI,SAAS,GACvF;CACA,QAAQ,IAAI;CACZ,QAAQ,IACN,KAAK,OAAO,KAAK,QAAQ,EAAE,GAAG,OAAO,KAAK,SAAS,EAAE,GAAG,OAAO,IAAI,WAAW,EAAE,GAAG,OAAO,IAAI,WAAW,GAC3G;CACA,QAAQ,IAAI;CAGZ,MAAM,UAA6C;EACjD,WAAW,CAAC;EACZ,QAAQ,CAAC;EACT,SAAS,CAAC;CACZ;CAEA,SAAS,SAAS,QAAQ;EACxB,QAAQ,IAAI,OAAO,EAAE,KAAK,GAAG;CAC/B,CAAC;CAGD,MAAM,cAAsC;EAC1C,WAAW;EACX,QAAQ;EACR,SAAS;CACX;CAEA,KAAK,MAAM,CAAC,QAAQ,SAAS,OAAO,QAAQ,OAAO,GAAG;EACpD,IAAI,KAAK,WAAW,GAAG;EAEvB,QAAQ,IAAI,KAAK,OAAO,KAAK,OAAO,MAAM,YAAY,OAAO,CAAC,GAAG;EACjE,QAAQ,IAAI;EAGZ,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,KAAK,MAAM,EAAE,KAAK,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,IAAI,EAAE,CAAC;EAE9F,KAAK,SAAS,QAAQ;GACpB,MAAM,WAAW,IAAI,QAAQ,OAAO,IAAI,KAAK,IAAI,MAAM,EAAE,IAAI;GAC7D,MAAM,gBAAgB,IAAI,QAAQ,IAAI,QAAQ,KAAK,IAAI,MAAM,KAAK;GAClE,MAAM,UAAU,IAAI,OAAO,SAAS,cAAc,SAAS,CAAC;GAE5D,MAAM,OAAO,IAAI,eAAe;GAChC,QAAQ,IAAI,OAAO,OAAO,KAAK,IAAI,IAAI,IAAI,WAAW,UAAU,MAAM;EACxE,CAAC;EACD,QAAQ,IAAI;CACd;CAGA,QAAQ,IAAI,KAAK,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC,GAAG;CAC5D,QAAQ,IAAI;CAEZ,MAAM,cAAc;EAClB;GAAE,MAAM;GAAc,aAAa;EAA0B;EAC7D;GAAE,MAAM;GAAiB,aAAa;EAAuB;EAC7D;GAAE,MAAM;GAAc,aAAa;EAA6B;EAChE;GAAE,MAAM;GAAgB,aAAa;EAAiC;CACxE;CAEA,MAAM,aAAa,KAAK,IAAI,GAAG,YAAY,KAAK,MAAM,EAAE,KAAK,MAAM,CAAC;CAEpE,YAAY,SAAS,EAAE,MAAM,kBAAkB;EAC7C,MAAM,UAAU,IAAI,OAAO,aAAa,KAAK,SAAS,CAAC;EACvD,QAAQ,IAAI,OAAO,OAAO,OAAO,IAAI,IAAI,UAAU,aAAa;CAClE,CAAC;CACD,QAAQ,IAAI;CAEZ,QAAQ,IACN,KAAK,OAAO,IAAI,KAAK,EAAE,GAAG,OAAO,KAAK,0BAA0B,EAAE,GAAG,OAAO,IAAI,2BAA2B,GAC7G;CACA,QAAQ,IAAI;AACd;;;;AAKA,SAAgB,mBAAmB,SAKhC;CACD,QAAQ,IAAI;CACZ,QAAQ,IACN,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ,IAAI,CAAC,IAAI,QAAQ,QAAQ,OAAO,IAAI,KAAK,QAAQ,MAAM,EAAE,IAAI,IACpG;CAEA,IAAI,QAAQ,aACV,QAAQ,IAAI,KAAK,QAAQ,aAAa;CAExC,QAAQ,IAAI;CAEZ,IAAI,QAAQ,WAAW,QAAQ,QAAQ,SAAS,GAAG;EACjD,QAAQ,IAAI,KAAK,OAAO,KAAK,UAAU,GAAG;EAC1C,QAAQ,IAAI;EAEZ,MAAM,SAAS,KAAK,IAAI,GAAG,QAAQ,QAAQ,KAAK,MAAM,EAAE,KAAK,MAAM,CAAC;EAEpE,QAAQ,QAAQ,SAAS,QAAQ;GAC/B,MAAM,UAAU,IAAI,OAAO,SAAS,IAAI,KAAK,SAAS,CAAC;GACvD,MAAM,WAAW,IAAI,WAAW,OAAO,IAAI,aAAa,IAAI;GAC5D,MAAM,OAAO,IAAI,eAAe;GAChC,QAAQ,IAAI,OAAO,OAAO,MAAM,IAAI,IAAI,IAAI,UAAU,OAAO,UAAU;EACzE,CAAC;EACD,QAAQ,IAAI;CACd,OAAO;EACL,QAAQ,IAAI,KAAK,OAAO,IAAI,sBAAsB,GAAG;EACrD,QAAQ,IAAI;CACd;AACF"}
|
|
1
|
+
{"version":3,"file":"cli-commands.utils.mjs","names":[],"sources":["../../../../../../../core/src/cli/cli-commands.utils.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport { Environment } from \"../utils\";\nimport { getWarlockVersion } from \"../utils/framework-vesion\";\n\nexport function isMatchingCommandName(commandName: string, targetingCommandName: string) {\n return commandName.split(\" \")[0] === targetingCommandName;\n}\n\n/**\n * Display the Warlock.js version banner\n */\nexport async function displayWarlockVersionInTerminal() {\n const version = await getWarlockVersion();\n console.log(`⚡ ${colors.bold(\"Warlock.js\")} ${colors.greenBright(`v${version}`)}`);\n}\n\ntype StartBannerOptions = {\n environment: Environment;\n};\n\nfunction getTextColorMethod(environment: Environment) {\n switch (environment) {\n case \"development\":\n return colors.yellowBright;\n case \"production\":\n return colors.greenBright;\n case \"test\":\n return colors.blueBright;\n default:\n return colors.whiteBright;\n }\n}\n\n/**\n * Display CLI startup banner\n */\nexport async function displayStartupBanner({ environment }: StartBannerOptions) {\n const version = await getWarlockVersion();\n const textColorMethod = getTextColorMethod(environment);\n console.log(` ⚡ ${colors.bold(textColorMethod(\"Warlock.js\"))} ${colors.dim(`v${version}`)}`);\n console.log();\n}\n\ntype ProductionReadyBannerOptions = {\n bootDurationMs?: number;\n};\n\n/**\n * Announce that the production server is up — printed on **stdout**, and only\n * after the child process reported a completed boot.\n *\n * Stdout is the channel a supervisor or CI gate greps to decide the service is\n * healthy, so nothing optimistic may be written to it: this function is the\n * single place allowed to say \"started\", and it is called from exactly one\n * place, the `warlock:ready` handler in the `start` command.\n */\nexport async function displayProductionReadyBanner({\n bootDurationMs,\n}: ProductionReadyBannerOptions = {}) {\n const version = await getWarlockVersion();\n const duration = bootDurationMs ? colors.dim(` in ${bootDurationMs}ms`) : \"\";\n\n console.log(\n ` ⚡ ${colors.bold(colors.greenBright(\"Warlock.js\"))} ${colors.dim(`v${version}`)} ${colors.green(\"✔\")} production server started${duration}`,\n );\n console.log();\n}\n\n/**\n * Report that the production server died before it ever served anything.\n *\n * Written to **both** streams on purpose. Stderr is where a human and a log\n * collector look; stdout is where a supervisor that greps for the success\n * banner looks, and it must find a failure there rather than silence — silence\n * on stdout is what let a boot failure be recorded as a healthy start.\n */\nexport function displayProductionStartFailure(exitCode: number) {\n const lines = [\n \"\",\n ` ${colors.red(\"✖\")} ${colors.bold(\"warlock start\")} failed — the server never finished booting`,\n ` ${colors.dim(`the application process exited with code ${exitCode}`)}`,\n ` ${colors.dim(\"the cause is printed above, in the application's own output\")}`,\n \"\",\n ];\n\n for (const line of lines) {\n console.error(line);\n console.log(line);\n }\n}\n\n/**\n * Note that a running child has not reported readiness yet.\n *\n * Emitted on **stderr** only. The process may be perfectly healthy — an older\n * bundle has no readiness signal at all — so saying anything on stdout would be\n * the very false-green this channel exists to prevent.\n *\n * The wording offers the likely causes rather than asserting one. It cannot\n * distinguish an old bundle from a slow boot from a boot that is about to fail,\n * and an earlier version claimed \"the bundle predates readiness reporting\" —\n * which was simply wrong when a current bundle was mid-crash, and sent the\n * reader after the wrong thing.\n */\nexport function displayMissingReadinessNotice(waitedMs: number) {\n console.error();\n console.error(\n ` ${colors.yellow(\"!\")} still running after ${Math.round(waitedMs / 1000)}s with no readiness signal`,\n );\n console.error(` ${colors.dim(\"either the boot is still in progress, or this bundle was built\")}`);\n console.error(\n ` ${colors.dim(\"before readiness reporting — re-run\")} ${colors.cyan(\"warlock build\")} ${colors.dim(\"if the banner never appears\")}`,\n );\n console.error();\n}\n\n/**\n * Display command execution header\n */\nexport function displayExecutingCommand(commandName: string) {\n console.log(` ${colors.cyan(\"›\")} Running ${colors.bold(colors.white(commandName))}...`);\n console.log();\n}\n\n/**\n * Display command not found error with optional suggestions\n */\nexport function displayCommandNotFound(commandName: string, suggestions?: string[]) {\n console.log();\n console.log(` ${colors.red(\"✖\")} Command ${colors.magenta(commandName)} not found`);\n\n if (suggestions && suggestions.length > 0) {\n console.log();\n console.log(` ${colors.yellow(\"Did you mean?\")}`);\n suggestions.forEach((suggestion) => {\n console.log(` ${colors.cyan(\"→\")} ${colors.white(suggestion)}`);\n });\n }\n\n console.log();\n console.log(\n ` ${colors.dim(\"Run\")} ${colors.cyan(\"warlock --help\")} ${colors.dim(\"to see available commands\")}`,\n );\n console.log();\n}\n\n/**\n * Display missing command error\n */\nexport function displayMissingCommand() {\n console.log();\n console.log(` ${colors.red(\"✖\")} No command specified`);\n console.log(\n ` ${colors.dim(\"Run\")} ${colors.cyan(\"warlock --help\")} ${colors.dim(\"to see available commands\")}`,\n );\n console.log();\n}\n\n/**\n * Display command success message\n */\nexport function displayCommandSuccess(commandName: string, durationMs?: number) {\n const duration = durationMs ? colors.dim(` (${durationMs}ms)`) : \"\";\n console.log();\n console.log(\n ` ${colors.green(\"✔\")} ${colors.bold(commandName)} completed successfully${duration}`,\n );\n console.log();\n}\n\n/**\n * Display command error message\n */\nexport function displayCommandError(commandName: string, error: Error) {\n console.log();\n console.log(` ${colors.red(\"✖\")} ${colors.bold(commandName)} failed`);\n console.log(` ${colors.dim(error.message)}`);\n console.log();\n}\n\n/**\n * Display a FATAL boot/preload failure and exit information.\n *\n * Preload failures — a bad import in a config file, a connector that throws\n * on startup, a missing module export — happen BEFORE the command's run loop\n * exists, so there is nothing to recover into: they are always fatal. Unlike\n * `displayCommandError`, this prints the full stack (not just `error.message`)\n * because the stack names the exact file + line of the offending import, which\n * is the single most useful clue when a config file pulls in a broken module.\n *\n * Surfacing this loudly is the difference between a clear error and a silent\n * hang: an unhandled preload rejection used to escape while the already-started\n * loader worker thread kept the process alive, leaving `warlock dev` frozen\n * just after the banner with no message at all.\n *\n * @example\n * // SyntaxError: The requested module '@warlock.js/cascade' does not\n * // provide an export named 'belongsTo'\n * // at src/app/.../permission.model.ts:2\n */\nexport function displayBootError(commandName: string, error: Error) {\n console.log();\n console.log(` ${colors.red(\"✖\")} ${colors.bold(commandName)} failed to start`);\n console.log(` ${colors.red(error.message)}`);\n if (error.stack) {\n console.log();\n console.log(colors.dim(error.stack));\n }\n console.log();\n}\n\n/**\n * Display missing required options error\n */\nexport function displayMissingOptions(options: { name: string; text: string }[]) {\n console.log();\n console.log(` ${colors.red(\"✖\")} Missing required options:`);\n options.forEach((opt) => {\n console.log(` ${colors.yellow(opt.text)} ${colors.dim(`(--${opt.name})`)}`);\n });\n console.log();\n}\n\n/**\n * Command info for help display\n */\nexport type HelpCommandInfo = {\n name: string;\n alias?: string;\n description?: string;\n source: \"framework\" | \"plugin\" | \"project\";\n};\n\n/**\n * Display global help with all commands grouped by source\n */\nexport async function displayHelp(commands: HelpCommandInfo[]) {\n const version = await getWarlockVersion();\n\n console.log();\n console.log(\n ` ⚡ ${colors.bold(colors.yellowBright(\"Warlock.js\"))} CLI ${colors.dim(`v${version}`)}`,\n );\n console.log();\n console.log(\n ` ${colors.bold(\"Usage:\")} ${colors.cyan(\"warlock\")} ${colors.dim(\"<command>\")} ${colors.dim(\"[options]\")}`,\n );\n console.log();\n\n // Group by source\n const grouped: Record<string, HelpCommandInfo[]> = {\n framework: [],\n plugin: [],\n project: [],\n };\n\n commands.forEach((cmd) => {\n grouped[cmd.source]?.push(cmd);\n });\n\n // Display each group\n const groupLabels: Record<string, string> = {\n framework: \"Framework Commands\",\n plugin: \"Plugin Commands\",\n project: \"Project Commands\",\n };\n\n for (const [source, cmds] of Object.entries(grouped)) {\n if (cmds.length === 0) continue;\n\n console.log(` ${colors.bold(colors.white(groupLabels[source]))}`);\n console.log();\n\n // Find max name length for alignment\n const maxLen = Math.max(...cmds.map((c) => c.name.length + (c.alias ? c.alias.length + 4 : 0)));\n\n cmds.forEach((cmd) => {\n const aliasStr = cmd.alias ? colors.dim(` (${cmd.alias})`) : \"\";\n const nameWithAlias = cmd.name + (cmd.alias ? ` (${cmd.alias})` : \"\");\n const padding = \" \".repeat(maxLen - nameWithAlias.length + 2);\n // const desc = cmd.description || colors.dim(\"No description\");\n const desc = cmd.description || \"\";\n console.log(` ${colors.cyan(cmd.name)}${aliasStr}${padding}${desc}`);\n });\n console.log();\n }\n\n // Display global flags\n console.log(` ${colors.bold(colors.white(\"Global Flags\"))}`);\n console.log();\n\n const globalFlags = [\n { flag: \"--help, -h\", description: \"Show help for a command\" },\n { flag: \"--version, -v\", description: \"Show Warlock version\" },\n { flag: \"--no-cache\", description: \"Force reload without cache\" },\n { flag: \"--warm-cache\", description: \"Pre-cache all project commands\" },\n ];\n\n const maxFlagLen = Math.max(...globalFlags.map((f) => f.flag.length));\n\n globalFlags.forEach(({ flag, description }) => {\n const padding = \" \".repeat(maxFlagLen - flag.length + 2);\n console.log(` ${colors.yellow(flag)}${padding}${description}`);\n });\n console.log();\n\n console.log(\n ` ${colors.dim(\"Run\")} ${colors.cyan(\"warlock <command> --help\")} ${colors.dim(\"for command-specific help\")}`,\n );\n console.log();\n}\n\n/**\n * Display help for a specific command\n */\nexport function displayCommandHelp(command: {\n name: string;\n alias?: string;\n description?: string;\n options?: { name: string; text: string; description?: string; required?: boolean }[];\n}) {\n console.log();\n console.log(\n ` ${colors.bold(colors.cyan(command.name))}${command.alias ? colors.dim(` (${command.alias})`) : \"\"}`,\n );\n\n if (command.description) {\n console.log(` ${command.description}`);\n }\n console.log();\n\n if (command.options && command.options.length > 0) {\n console.log(` ${colors.bold(\"Options:\")}`);\n console.log();\n\n const maxLen = Math.max(...command.options.map((o) => o.text.length));\n\n command.options.forEach((opt) => {\n const padding = \" \".repeat(maxLen - opt.text.length + 2);\n const required = opt.required ? colors.red(\" (required)\") : \"\";\n const desc = opt.description || \"\";\n console.log(` ${colors.green(opt.text)}${padding}${desc}${required}`);\n });\n console.log();\n } else {\n console.log(` ${colors.dim(\"No options available\")}`);\n console.log();\n }\n}\n"],"mappings":"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"}
|
|
@@ -51,7 +51,7 @@ import { guarded } from "app/shared/utils/router";
|
|
|
51
51
|
// router.get("/${name.kebab}", listController);
|
|
52
52
|
`;
|
|
53
53
|
await putFileAsync(path.join(modulePath, "routes.ts"), routesContent);
|
|
54
|
-
const localesContent = `import { groupedTranslations } from "@
|
|
54
|
+
const localesContent = `import { groupedTranslations } from "@warlock.js/core";
|
|
55
55
|
|
|
56
56
|
groupedTranslations("${name.camel}", {
|
|
57
57
|
// Add your translations here
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.generator.mjs","names":[],"sources":["../../../../../../../../../../core/src/cli/commands/generate/generators/module.generator.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\r\nimport path from \"node:path\";\r\nimport { appPath } from \"../../../../utils\";\r\nimport type { CommandActionData } from \"../../../types\";\r\nimport {\r\n crudCreateControllerStub,\r\n crudCreateSchemaStub,\r\n crudCreateServiceStub,\r\n crudDeleteControllerStub,\r\n crudDeleteServiceStub,\r\n crudGetServiceStub,\r\n crudListControllerStub,\r\n crudListServiceStub,\r\n crudModelStub,\r\n crudRepositoryStub,\r\n crudResourceStub,\r\n crudRoutesStub,\r\n crudSeedStub,\r\n crudShowControllerStub,\r\n crudUpdateControllerStub,\r\n crudUpdateSchemaStub,\r\n crudUpdateServiceStub,\r\n} from \"../templates/stubs\";\r\nimport { pluralName, singularName } from \"../utils/name-parser\";\r\nimport { moduleExists } from \"../utils/path-resolver\";\r\nimport { ensureDirectoryAsync, putFileAsync, setDryRun } from \"../utils/writer\";\r\nimport { createMigrationFile } from \"./migration.generator\";\r\n\r\nexport async function generateModule(data: CommandActionData): Promise<void> {\r\n const moduleName = data.args[0];\r\n\r\n if (!moduleName) {\r\n console.log(colors.red(\"Error: Module name is required\"));\r\n console.log(colors.yellow(\"Usage: warlock generate.module <name> [options]\"));\r\n console.log(colors.yellow(\"Example: warlock generate.module products\"));\r\n console.log(colors.yellow(\" warlock generate.module products --minimal\"));\r\n process.exit(1);\r\n }\r\n\r\n const name = pluralName(moduleName);\r\n const force = data.options.force || data.options.f;\r\n setDryRun(Boolean(data.options.dryRun));\r\n\r\n // Full CRUD is the default; --minimal (-m) opts down to a bare skeleton.\r\n const minimal = data.options.minimal || data.options.m;\r\n const withCrud = !minimal;\r\n\r\n // Check if module already exists\r\n if ((await moduleExists(name.kebab)) && !force) {\r\n console.log(colors.red(`Error: Module \"${name.kebab}\" already exists`));\r\n console.log(colors.yellow(\"Use --force to overwrite\"));\r\n process.exit(1);\r\n }\r\n\r\n const modulePath = appPath(name.kebab);\r\n\r\n // Create module directory structure\r\n const directories = [\r\n \"controllers\",\r\n \"services\",\r\n \"models\",\r\n \"repositories\",\r\n \"schema\",\r\n \"resources\",\r\n \"events\",\r\n \"types\",\r\n \"utils\",\r\n ];\r\n\r\n for (const dir of directories) {\r\n await ensureDirectoryAsync(path.join(modulePath, dir));\r\n }\r\n\r\n // Create main.ts\r\n const mainContent = `// You may use this file as a custom entry point to be executed when the app starts.\r\n// it runs only once, and you don't need to import the routes.ts file, it will be imported automatically.\r\n// Use it to regsiter or boot up any custom logic for this module.\r\n`;\r\n await putFileAsync(path.join(modulePath, \"main.ts\"), mainContent);\r\n\r\n // Create routes.ts\r\n const routesContent = withCrud\r\n ? crudRoutesStub(name)\r\n : `import { router } from \"@warlock.js/core\";\r\nimport { guarded } from \"app/shared/utils/router\";\r\n\r\n// Define your routes here\r\n// Example:\r\n// router.get(\"/${name.kebab}\", listController);\r\n`;\r\n await putFileAsync(path.join(modulePath, \"routes.ts\"), routesContent);\r\n\r\n // Create utils/locales.ts\r\n const localesContent = `import { groupedTranslations } from \"@mongez/localization\";\r\n\r\ngroupedTranslations(\"${name.camel}\", {\r\n // Add your translations here\r\n // Example:\r\n // welcome: {\r\n // en: \"Welcome\",\r\n // ar: \"Ù…Ø±ØØ¨Ø§\",\r\n // },\r\n});\r\n`;\r\n await putFileAsync(path.join(modulePath, \"utils\", \"locales.ts\"), localesContent);\r\n\r\n // Full CRUD scaffold (the default) unless --minimal was passed\r\n if (withCrud) {\r\n const entity = singularName(moduleName);\r\n\r\n // Create controllers\r\n await putFileAsync(\r\n path.join(modulePath, \"controllers\", `create-${entity.kebab}.controller.ts`),\r\n crudCreateControllerStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"controllers\", `update-${entity.kebab}.controller.ts`),\r\n crudUpdateControllerStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"controllers\", `list-${name.kebab}.controller.ts`),\r\n crudListControllerStub(name),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"controllers\", `get-${entity.kebab}.controller.ts`),\r\n crudShowControllerStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"controllers\", `delete-${entity.kebab}.controller.ts`),\r\n crudDeleteControllerStub(entity),\r\n );\r\n\r\n // Create schema files — each exports both the schema value and its\r\n // inferred type; controllers import them directly (no requests/ alias).\r\n await putFileAsync(\r\n path.join(modulePath, \"schema\", `create-${entity.kebab}.schema.ts`),\r\n crudCreateSchemaStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"schema\", `update-${entity.kebab}.schema.ts`),\r\n crudUpdateSchemaStub(entity),\r\n );\r\n\r\n // Create model\r\n await ensureDirectoryAsync(path.join(modulePath, \"models\", entity.kebab));\r\n await putFileAsync(\r\n path.join(modulePath, \"models\", entity.kebab, `${entity.kebab}.model.ts`),\r\n crudModelStub(entity),\r\n );\r\n\r\n // Create model index\r\n await putFileAsync(\r\n path.join(modulePath, \"models\", entity.kebab, \"index.ts\"),\r\n `export * from \"./${entity.kebab}.model\";\\n`,\r\n );\r\n\r\n // Create migrations folder\r\n await ensureDirectoryAsync(path.join(modulePath, \"models\", entity.kebab, \"migrations\"));\r\n\r\n // Create resource\r\n await putFileAsync(\r\n path.join(modulePath, \"resources\", `${entity.kebab}.resource.ts`),\r\n crudResourceStub(name),\r\n );\r\n\r\n // Create repository\r\n await putFileAsync(\r\n path.join(modulePath, \"repositories\", `${name.kebab}.repository.ts`),\r\n crudRepositoryStub(name),\r\n );\r\n\r\n // Create services\r\n await putFileAsync(\r\n path.join(modulePath, \"services\", `create-${entity.kebab}.service.ts`),\r\n crudCreateServiceStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"services\", `update-${entity.kebab}.service.ts`),\r\n crudUpdateServiceStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"services\", `list-${name.kebab}.service.ts`),\r\n crudListServiceStub(name),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"services\", `get-${entity.kebab}.service.ts`),\r\n crudGetServiceStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"services\", `delete-${entity.kebab}.service.ts`),\r\n crudDeleteServiceStub(entity),\r\n );\r\n\r\n // Create seeds\r\n await ensureDirectoryAsync(path.join(modulePath, \"seeds\"));\r\n await putFileAsync(path.join(modulePath, \"seeds\", `${name.kebab}.seed.ts`), crudSeedStub(name));\r\n\r\n // Create migration\r\n await createMigrationFile(name.kebab, entity.kebab);\r\n }\r\n\r\n console.log(colors.cyan(`\\n✨ Module \"${name.kebab}\" generated successfully!`));\r\n\r\n if (withCrud) {\r\n console.log(colors.gray(`\\n📦 CRUD scaffold created with:`));\r\n console.log(colors.gray(` - List, Get, Create, Update & Delete controllers`));\r\n console.log(colors.gray(` - Repository`));\r\n console.log(colors.gray(` - Validation schemas in schema/`));\r\n console.log(colors.gray(` - Model with resource`));\r\n console.log(colors.gray(` - Routes configured`));\r\n console.log(colors.gray(`\\nNext steps:`));\r\n console.log(\r\n colors.gray(` 1. Update model schema in models/${name.kebab}/${name.kebab}.model.ts`),\r\n );\r\n console.log(colors.gray(` 2. Update schema rules in schema/*.schema.ts`));\r\n console.log(\r\n colors.gray(` 3. Create migration: warlock generate.model ${name.kebab}/${name.kebab}`),\r\n );\r\n } else {\r\n console.log(colors.gray(`\\nNext steps:`));\r\n console.log(colors.gray(` 1. Define routes in ${name.kebab}/routes.ts`));\r\n console.log(\r\n colors.gray(` 2. Create controllers: warlock generate.controller ${name.kebab}/<name>`),\r\n );\r\n console.log(colors.gray(` 3. Create models: warlock generate.model ${name.kebab}/<name>`));\r\n console.log(colors.gray(`\\nTip: omit --minimal to generate a full CRUD scaffold`));\r\n }\r\n}\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"module.generator.mjs","names":[],"sources":["../../../../../../../../../../core/src/cli/commands/generate/generators/module.generator.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\r\nimport path from \"node:path\";\r\nimport { appPath } from \"../../../../utils\";\r\nimport type { CommandActionData } from \"../../../types\";\r\nimport {\r\n crudCreateControllerStub,\r\n crudCreateSchemaStub,\r\n crudCreateServiceStub,\r\n crudDeleteControllerStub,\r\n crudDeleteServiceStub,\r\n crudGetServiceStub,\r\n crudListControllerStub,\r\n crudListServiceStub,\r\n crudModelStub,\r\n crudRepositoryStub,\r\n crudResourceStub,\r\n crudRoutesStub,\r\n crudSeedStub,\r\n crudShowControllerStub,\r\n crudUpdateControllerStub,\r\n crudUpdateSchemaStub,\r\n crudUpdateServiceStub,\r\n} from \"../templates/stubs\";\r\nimport { pluralName, singularName } from \"../utils/name-parser\";\r\nimport { moduleExists } from \"../utils/path-resolver\";\r\nimport { ensureDirectoryAsync, putFileAsync, setDryRun } from \"../utils/writer\";\r\nimport { createMigrationFile } from \"./migration.generator\";\r\n\r\nexport async function generateModule(data: CommandActionData): Promise<void> {\r\n const moduleName = data.args[0];\r\n\r\n if (!moduleName) {\r\n console.log(colors.red(\"Error: Module name is required\"));\r\n console.log(colors.yellow(\"Usage: warlock generate.module <name> [options]\"));\r\n console.log(colors.yellow(\"Example: warlock generate.module products\"));\r\n console.log(colors.yellow(\" warlock generate.module products --minimal\"));\r\n process.exit(1);\r\n }\r\n\r\n const name = pluralName(moduleName);\r\n const force = data.options.force || data.options.f;\r\n setDryRun(Boolean(data.options.dryRun));\r\n\r\n // Full CRUD is the default; --minimal (-m) opts down to a bare skeleton.\r\n const minimal = data.options.minimal || data.options.m;\r\n const withCrud = !minimal;\r\n\r\n // Check if module already exists\r\n if ((await moduleExists(name.kebab)) && !force) {\r\n console.log(colors.red(`Error: Module \"${name.kebab}\" already exists`));\r\n console.log(colors.yellow(\"Use --force to overwrite\"));\r\n process.exit(1);\r\n }\r\n\r\n const modulePath = appPath(name.kebab);\r\n\r\n // Create module directory structure\r\n const directories = [\r\n \"controllers\",\r\n \"services\",\r\n \"models\",\r\n \"repositories\",\r\n \"schema\",\r\n \"resources\",\r\n \"events\",\r\n \"types\",\r\n \"utils\",\r\n ];\r\n\r\n for (const dir of directories) {\r\n await ensureDirectoryAsync(path.join(modulePath, dir));\r\n }\r\n\r\n // Create main.ts\r\n const mainContent = `// You may use this file as a custom entry point to be executed when the app starts.\r\n// it runs only once, and you don't need to import the routes.ts file, it will be imported automatically.\r\n// Use it to regsiter or boot up any custom logic for this module.\r\n`;\r\n await putFileAsync(path.join(modulePath, \"main.ts\"), mainContent);\r\n\r\n // Create routes.ts\r\n const routesContent = withCrud\r\n ? crudRoutesStub(name)\r\n : `import { router } from \"@warlock.js/core\";\r\nimport { guarded } from \"app/shared/utils/router\";\r\n\r\n// Define your routes here\r\n// Example:\r\n// router.get(\"/${name.kebab}\", listController);\r\n`;\r\n await putFileAsync(path.join(modulePath, \"routes.ts\"), routesContent);\r\n\r\n // Create utils/locales.ts\r\n const localesContent = `import { groupedTranslations } from \"@warlock.js/core\";\r\n\r\ngroupedTranslations(\"${name.camel}\", {\r\n // Add your translations here\r\n // Example:\r\n // welcome: {\r\n // en: \"Welcome\",\r\n // ar: \"Ù…Ø±ØØ¨Ø§\",\r\n // },\r\n});\r\n`;\r\n await putFileAsync(path.join(modulePath, \"utils\", \"locales.ts\"), localesContent);\r\n\r\n // Full CRUD scaffold (the default) unless --minimal was passed\r\n if (withCrud) {\r\n const entity = singularName(moduleName);\r\n\r\n // Create controllers\r\n await putFileAsync(\r\n path.join(modulePath, \"controllers\", `create-${entity.kebab}.controller.ts`),\r\n crudCreateControllerStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"controllers\", `update-${entity.kebab}.controller.ts`),\r\n crudUpdateControllerStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"controllers\", `list-${name.kebab}.controller.ts`),\r\n crudListControllerStub(name),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"controllers\", `get-${entity.kebab}.controller.ts`),\r\n crudShowControllerStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"controllers\", `delete-${entity.kebab}.controller.ts`),\r\n crudDeleteControllerStub(entity),\r\n );\r\n\r\n // Create schema files — each exports both the schema value and its\r\n // inferred type; controllers import them directly (no requests/ alias).\r\n await putFileAsync(\r\n path.join(modulePath, \"schema\", `create-${entity.kebab}.schema.ts`),\r\n crudCreateSchemaStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"schema\", `update-${entity.kebab}.schema.ts`),\r\n crudUpdateSchemaStub(entity),\r\n );\r\n\r\n // Create model\r\n await ensureDirectoryAsync(path.join(modulePath, \"models\", entity.kebab));\r\n await putFileAsync(\r\n path.join(modulePath, \"models\", entity.kebab, `${entity.kebab}.model.ts`),\r\n crudModelStub(entity),\r\n );\r\n\r\n // Create model index\r\n await putFileAsync(\r\n path.join(modulePath, \"models\", entity.kebab, \"index.ts\"),\r\n `export * from \"./${entity.kebab}.model\";\\n`,\r\n );\r\n\r\n // Create migrations folder\r\n await ensureDirectoryAsync(path.join(modulePath, \"models\", entity.kebab, \"migrations\"));\r\n\r\n // Create resource\r\n await putFileAsync(\r\n path.join(modulePath, \"resources\", `${entity.kebab}.resource.ts`),\r\n crudResourceStub(name),\r\n );\r\n\r\n // Create repository\r\n await putFileAsync(\r\n path.join(modulePath, \"repositories\", `${name.kebab}.repository.ts`),\r\n crudRepositoryStub(name),\r\n );\r\n\r\n // Create services\r\n await putFileAsync(\r\n path.join(modulePath, \"services\", `create-${entity.kebab}.service.ts`),\r\n crudCreateServiceStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"services\", `update-${entity.kebab}.service.ts`),\r\n crudUpdateServiceStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"services\", `list-${name.kebab}.service.ts`),\r\n crudListServiceStub(name),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"services\", `get-${entity.kebab}.service.ts`),\r\n crudGetServiceStub(entity),\r\n );\r\n\r\n await putFileAsync(\r\n path.join(modulePath, \"services\", `delete-${entity.kebab}.service.ts`),\r\n crudDeleteServiceStub(entity),\r\n );\r\n\r\n // Create seeds\r\n await ensureDirectoryAsync(path.join(modulePath, \"seeds\"));\r\n await putFileAsync(path.join(modulePath, \"seeds\", `${name.kebab}.seed.ts`), crudSeedStub(name));\r\n\r\n // Create migration\r\n await createMigrationFile(name.kebab, entity.kebab);\r\n }\r\n\r\n console.log(colors.cyan(`\\n✨ Module \"${name.kebab}\" generated successfully!`));\r\n\r\n if (withCrud) {\r\n console.log(colors.gray(`\\n📦 CRUD scaffold created with:`));\r\n console.log(colors.gray(` - List, Get, Create, Update & Delete controllers`));\r\n console.log(colors.gray(` - Repository`));\r\n console.log(colors.gray(` - Validation schemas in schema/`));\r\n console.log(colors.gray(` - Model with resource`));\r\n console.log(colors.gray(` - Routes configured`));\r\n console.log(colors.gray(`\\nNext steps:`));\r\n console.log(\r\n colors.gray(` 1. Update model schema in models/${name.kebab}/${name.kebab}.model.ts`),\r\n );\r\n console.log(colors.gray(` 2. Update schema rules in schema/*.schema.ts`));\r\n console.log(\r\n colors.gray(` 3. Create migration: warlock generate.model ${name.kebab}/${name.kebab}`),\r\n );\r\n } else {\r\n console.log(colors.gray(`\\nNext steps:`));\r\n console.log(colors.gray(` 1. Define routes in ${name.kebab}/routes.ts`));\r\n console.log(\r\n colors.gray(` 2. Create controllers: warlock generate.controller ${name.kebab}/<name>`),\r\n );\r\n console.log(colors.gray(` 3. Create models: warlock generate.model ${name.kebab}/<name>`));\r\n console.log(colors.gray(`\\nTip: omit --minimal to generate a full CRUD scaffold`));\r\n }\r\n}\r\n"],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { command } from "../cli-command.mjs";
|
|
2
|
-
import { displayStartupBanner } from "../cli-commands.utils.mjs";
|
|
3
2
|
import { resolveBuildConfig } from "../../production/resolve-build-config.mjs";
|
|
4
|
-
import {
|
|
3
|
+
import { superviseProductionProcess } from "../../production/production-supervisor.mjs";
|
|
5
4
|
|
|
6
5
|
//#region ../core/src/cli/commands/start-production.command.ts
|
|
7
6
|
const startProductionCommand = command({
|
|
@@ -9,9 +8,6 @@ const startProductionCommand = command({
|
|
|
9
8
|
description: "Start production server",
|
|
10
9
|
persistent: true,
|
|
11
10
|
preload: { warlockConfig: true },
|
|
12
|
-
preAction: async () => {
|
|
13
|
-
displayStartupBanner({ environment: "production" });
|
|
14
|
-
},
|
|
15
11
|
action: async () => {
|
|
16
12
|
const { entryPath, sourcemap } = resolveBuildConfig();
|
|
17
13
|
const nodeArgs = [];
|
|
@@ -22,26 +18,9 @@ const startProductionCommand = command({
|
|
|
22
18
|
const extraArgs = process.argv.slice(startIndex + 1);
|
|
23
19
|
nodeArgs.push(...extraArgs);
|
|
24
20
|
}
|
|
25
|
-
console.
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
cwd: process.cwd(),
|
|
29
|
-
env: process.env,
|
|
30
|
-
detached: false
|
|
31
|
-
});
|
|
32
|
-
let isShuttingDown = false;
|
|
33
|
-
const forwardSignal = (signal) => {
|
|
34
|
-
if (isShuttingDown) return;
|
|
35
|
-
isShuttingDown = true;
|
|
36
|
-
child.kill(signal);
|
|
37
|
-
};
|
|
38
|
-
process.on("SIGTERM", () => forwardSignal("SIGTERM"));
|
|
39
|
-
process.on("SIGINT", () => {
|
|
40
|
-
isShuttingDown = true;
|
|
41
|
-
});
|
|
42
|
-
child.on("exit", (code) => {
|
|
43
|
-
process.exit(code ?? 0);
|
|
44
|
-
});
|
|
21
|
+
console.error(`🚀 Starting production server...\n`);
|
|
22
|
+
const { exitCode } = await superviseProductionProcess({ nodeArgs });
|
|
23
|
+
process.exit(exitCode);
|
|
45
24
|
}
|
|
46
25
|
});
|
|
47
26
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start-production.command.mjs","names":[],"sources":["../../../../../../../../core/src/cli/commands/start-production.command.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"start-production.command.mjs","names":[],"sources":["../../../../../../../../core/src/cli/commands/start-production.command.ts"],"sourcesContent":["import { superviseProductionProcess } from \"../../production/production-supervisor\";\nimport { resolveBuildConfig } from \"../../production/resolve-build-config\";\nimport { command } from \"../cli-command\";\n\nexport const startProductionCommand = command({\n name: \"start\",\n description: \"Start production server\",\n persistent: true,\n preload: {\n warlockConfig: true,\n },\n action: async () => {\n const { entryPath, sourcemap } = resolveBuildConfig();\n\n // Build node args\n const nodeArgs: string[] = [];\n\n // Enable source maps if configured\n if (sourcemap !== false) {\n nodeArgs.push(\"--enable-source-maps\");\n }\n\n // Add entry file\n nodeArgs.push(entryPath);\n\n // Pass through any additional flags after \"start\" command\n // process.argv = [node, cli.ts, start, ...extra]\n const startIndex = process.argv.findIndex((arg) => arg === \"start\");\n if (startIndex !== -1 && startIndex < process.argv.length - 1) {\n const extraArgs = process.argv.slice(startIndex + 1);\n nodeArgs.push(...extraArgs);\n }\n\n // Progress goes to stderr, never stdout. Stdout carries exactly one claim —\n // \"started\" — so that whatever greps it cannot mistake an intention for an\n // outcome. The banner that used to print here, in `preAction`, printed\n // before the child had even been spawned.\n console.error(`🚀 Starting production server...\\n`);\n\n const { exitCode } = await superviseProductionProcess({ nodeArgs });\n\n process.exit(exitCode);\n },\n});\n"],"mappings":";;;;;AAIA,MAAa,yBAAyB,QAAQ;CAC5C,MAAM;CACN,aAAa;CACb,YAAY;CACZ,SAAS,EACP,eAAe,KACjB;CACA,QAAQ,YAAY;EAClB,MAAM,EAAE,WAAW,cAAc,mBAAmB;EAGpD,MAAM,WAAqB,CAAC;EAG5B,IAAI,cAAc,OAChB,SAAS,KAAK,sBAAsB;EAItC,SAAS,KAAK,SAAS;EAIvB,MAAM,aAAa,QAAQ,KAAK,WAAW,QAAQ,QAAQ,OAAO;EAClE,IAAI,eAAe,MAAM,aAAa,QAAQ,KAAK,SAAS,GAAG;GAC7D,MAAM,YAAY,QAAQ,KAAK,MAAM,aAAa,CAAC;GACnD,SAAS,KAAK,GAAG,SAAS;EAC5B;EAMA,QAAQ,MAAM,oCAAoC;EAElD,MAAM,EAAE,aAAa,MAAM,2BAA2B,EAAE,SAAS,CAAC;EAElE,QAAQ,KAAK,QAAQ;CACvB;AACF,CAAC"}
|
package/esm/cli/types.d.mts
CHANGED
|
@@ -76,7 +76,12 @@ type CLICommandPreload = {
|
|
|
76
76
|
environemnt?: "production" | "development" | "test";
|
|
77
77
|
/**
|
|
78
78
|
* Whether to load environment variables from .env files.
|
|
79
|
-
*
|
|
79
|
+
*
|
|
80
|
+
* @deprecated No longer read — env is loaded for every command that declares
|
|
81
|
+
* a preload block, before `warlock.config.ts` is evaluated. It has to be:
|
|
82
|
+
* config files call `env()` in their module body, and loading config first
|
|
83
|
+
* resolved every one of those calls to its default. Setting this flag is
|
|
84
|
+
* harmless and does nothing; remove it. Dropped at 5.0.
|
|
80
85
|
*/
|
|
81
86
|
env?: boolean;
|
|
82
87
|
/**
|
package/esm/cli/types.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../../../../../core/src/cli/types.ts"],"mappings":";;;;;AAgB4B;AAY5B;;;;KAZY,gBAAA;;;;AAwBK;AAsBjB;;;;;;KAlCY,iBAAA;EAuDV;;;;EAlDA,IAAA;
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../../../../../core/src/cli/types.ts"],"mappings":";;;;;AAgB4B;AAY5B;;;;KAZY,gBAAA;;;;AAwBK;AAsBjB;;;;;;KAlCY,iBAAA;EAuDV;;;;EAlDA,IAAA;EAiFA;;;AAA0B;AAgB5B;EA1FE,OAAA,EAAS,MAAM;AAAA;;;;;;;;;;AAiIP;AAGV;;;;;;;;;KA9GY,iBAAA;EAuHA;;;;;EAjHV,MAAA;EAiHiE;;AAAO;EA5GxE,QAAA;EAkI2B;;;EA7H3B,aAAA;EAsKQ;;;EAjKR,eAAA,GAAkB,eAAA;EA6HlB;;;EAxHA,WAAA;EAyIU;;;;;;;;;EA9HV,GAAA;;;;;EAMA,SAAA;;;;;;;;EASA,UAAA,GAAa,aAAa;AAAA;;;;;;;;;;;;;;KAgBhB,gBAAA;;;;;EAKV,IAAA;;;;;EAMA,IAAA;;;;;EAMA,KAAA;;;;EAKA,WAAA;;;;;EAMA,IAAA;;;;EAKA,YAAA;;;;;EAMA,QAAA;AAAA;AAAA,KAGU,wBAAA,GAA2B,IAAI,CAAC,gBAAA;EAC1C,IAAA;EACA,KAAA;AAAA;;;;;KAOU,gBAAA,IAAoB,IAAA,EAAM,iBAAA,YAA6B,OAAO;;;;;;;;;;;;;;;;;;;;;KAsB9D,iBAAA;;;;;EAKV,IAAA;;;;;EAMA,KAAA;;;;EAKA,WAAA;;;;;EAMA,OAAA,GAAU,iBAAA;;;;;;EAOV,UAAA;;;;;EAMA,SAAA,GAAY,gBAAA;;;;;EAMZ,MAAA,EAAQ,gBAAA;;;;;EAMR,OAAA,GAAU,gBAAA;AAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ConfigRegistry } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region ../core/src/config/config-setter.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Register a config group under its name.
|
|
6
|
+
*
|
|
7
|
+
* The write side of the config store, kept separate from the `config` accessor
|
|
8
|
+
* on purpose: `config` is a read-only surface and widening it would invite app
|
|
9
|
+
* code to mutate configuration at runtime. Registration is a boot-time act.
|
|
10
|
+
*
|
|
11
|
+
* Exported chiefly so the production build's generated config loader has a
|
|
12
|
+
* specifier the consuming app actually declares — `@warlock.js/core` — rather
|
|
13
|
+
* than `@mongez/config`, which is core's dependency and not the app's.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { setConfig } from "@warlock.js/core";
|
|
18
|
+
* import databaseConfig from "../../src/config/database";
|
|
19
|
+
*
|
|
20
|
+
* setConfig("database", databaseConfig);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
declare function setConfig<K extends keyof ConfigRegistry>(name: K, value: ConfigRegistry[K]): void;
|
|
24
|
+
declare function setConfig(name: string, value: unknown): void;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { setConfig };
|
|
27
|
+
//# sourceMappingURL=config-setter.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-setter.d.mts","names":[],"sources":["../../../../../../../core/src/config/config-setter.ts"],"mappings":";;;;;AAsBA;;;;;;;;;;;;;;;;;iBAAgB,SAAA,iBAA0B,cAAA,EAAgB,IAAA,EAAM,CAAA,EAAG,KAAA,EAAO,cAAA,CAAe,CAAA;AAAA,iBACzE,SAAA,CAAU,IAAA,UAAc,KAAc"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-setter.mjs","names":[],"sources":["../../../../../../../core/src/config/config-setter.ts"],"sourcesContent":["import baseConfig from \"@mongez/config\";\nimport type { ConfigRegistry } from \"./types\";\n\n/**\n * Register a config group under its name.\n *\n * The write side of the config store, kept separate from the `config` accessor\n * on purpose: `config` is a read-only surface and widening it would invite app\n * code to mutate configuration at runtime. Registration is a boot-time act.\n *\n * Exported chiefly so the production build's generated config loader has a\n * specifier the consuming app actually declares — `@warlock.js/core` — rather\n * than `@mongez/config`, which is core's dependency and not the app's.\n *\n * @example\n * ```typescript\n * import { setConfig } from \"@warlock.js/core\";\n * import databaseConfig from \"../../src/config/database\";\n *\n * setConfig(\"database\", databaseConfig);\n * ```\n */\nexport function setConfig<K extends keyof ConfigRegistry>(name: K, value: ConfigRegistry[K]): void;\nexport function setConfig(name: string, value: unknown): void;\nexport function setConfig(name: string, value: unknown): void {\n baseConfig.set(name, value);\n}\n"],"mappings":";;;AAwBA,SAAgB,UAAU,MAAc,OAAsB;CAC5D,OAAW,IAAI,MAAM,KAAK;AAC5B"}
|
package/esm/config/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-connector.d.mts","names":[],"sources":["../../../../../../../core/src/connectors/http-connector.ts"],"mappings":";;;;;;;AAsCA;;cAAa,aAAA,SAAsB,aAAA;EAAA,SACjB,IAAA;EAAA,SACA,QAAA,GAAQ,iBAAA,CAAA,IAAA;EAAA,SACR,cAAA,GAAc,uBAAA,CAAA,IAAA;EAmBb;;;;;EAAA,mBAZE,YAAA;EAV2B;;;EAAA,UAepC,IAAA,GAAO,eAAA;EAbO;;;;;EAoBX,IAAA,IAAI,OAAA;EAPP;;;;;;;EAAA,QA0CF,oBAAA;
|
|
1
|
+
{"version":3,"file":"http-connector.d.mts","names":[],"sources":["../../../../../../../core/src/connectors/http-connector.ts"],"mappings":";;;;;;;AAsCA;;cAAa,aAAA,SAAsB,aAAA;EAAA,SACjB,IAAA;EAAA,SACA,QAAA,GAAQ,iBAAA,CAAA,IAAA;EAAA,SACR,cAAA,GAAc,uBAAA,CAAA,IAAA;EAmBb;;;;;EAAA,mBAZE,YAAA;EAV2B;;;EAAA,UAepC,IAAA,GAAO,eAAA;EAbO;;;;;EAoBX,IAAA,IAAI,OAAA;EAPP;;;;;;;EAAA,QA0CF,oBAAA;EAmFgB;;;;;EAnDX,KAAA,IAAS,OAAA;EAwFqB;;;;;EArC9B,OAAA,IAAW,OAAA;;;;EASX,QAAA,IAAY,OAAA;;;;;;EA4BlB,aAAA,CAAc,YAAA;AAAA"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { setBaseUrl } from "../utils/urls.mjs";
|
|
2
2
|
import { container } from "../container/index.mjs";
|
|
3
|
+
import { Application } from "../application/application.mjs";
|
|
3
4
|
import { router } from "../router/router.mjs";
|
|
4
5
|
import { registerHttpPlugins } from "../http/plugins.mjs";
|
|
5
6
|
import { closeServerWithTimeout, getHttpServer, startHttpServer } from "../http/server.mjs";
|
|
6
|
-
import { Application } from "../application/application.mjs";
|
|
7
7
|
import "../application/index.mjs";
|
|
8
8
|
import { health } from "../http/health.mjs";
|
|
9
9
|
import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
|
|
@@ -94,6 +94,7 @@ var HttpConnector = class extends BaseConnector {
|
|
|
94
94
|
port: httpConfig.port,
|
|
95
95
|
host: httpConfig.host || "localhost"
|
|
96
96
|
});
|
|
97
|
+
Application.setServedPort(httpConfig.port);
|
|
97
98
|
const baseUrl = config.get("app.baseUrl");
|
|
98
99
|
log.success(`http`, "connection", `Server ready at ${baseUrl}`);
|
|
99
100
|
} catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-connector.mjs","names":[],"sources":["../../../../../../../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":";;;;;;;;;;;;;;;;AAeA,SAAS,iBAAiB,aAA0B;CAClD,QAAQ,aAAR;EACE,KAAK,eACH,OAAO,OAAO,cAAc,WAAW;EACzC,KAAK,QACH,OAAO,OAAO,aAAa,WAAW;EACxC,KAAK,cACH,OAAO,OAAO,YAAY,WAAW;EACvC,SACE,OAAO,OAAO,MAAM,WAAW;CACnC;AACF;;;;;AAMA,MAAM,2BAA2B;;;;;AAMjC,IAAa,gBAAb,cAAmC,cAAc;;;cACxB;;;sBASW,CAAC,sBAAsB,qBAAqB;;;;;;;CAY9E,MAAa,OAAO;EAClB,MAAM,aAAa,OAAO,IAAI,MAAM;EAEpC,IAAI,CAAC,YAAY;EAEjB,MAAM,OAAO,WAAW;EACxB,IAAI,KACF,QACA,cACA,gCAAgC,KAAK,MAAM,iBAAiB,YAAY,WAAW,EAAE,MACvF;EAEA,KAAK,OAAO,gBAAgB,WAAW,aAAa;EAEpD,UAAU,IAAI,eAAe,KAAK,IAAI;EAEtC,MAAM,oBAAoB,KAAK,IAAI;EAKnC,WAHgB,OAAO,IAAI,aAGV,CAAC;EAIlB,KAAK,qBAAqB;CAC5B;;;;;;;;CASA,AAAQ,uBAA6B;EACnC,IAAI,CAAC,KAAK,MACR;EAGF,MAAM,eAAe,OAAO,IAAI,aAAa;EAE7C,IAAI,cAAc,YAAY,OAC5B;EAGF,MAAM,eAAe,cAAc,QAAQ;EAC3C,MAAM,gBAAgB,cAAc,iBAAiB;EAErD,KAAK,KAAK,IAAI,cAAc,OAAO,UAAe,UAAe;GAC/D,MAAM,SAAS,OAAO,SAAS;GAE/B,OAAO,MAAM,KAAK,OAAO,WAAW,OAAO,MAAM,GAAG,CAAC,CAAC,KAAK,MAAM;EACnE,CAAC;EAED,KAAK,KAAK,IAAI,eAAe,OAAO,UAAe,UAAe;GAChE,MAAM,SAAS,MAAM,OAAO,UAAU;GAEtC,OAAO,MAAM,KAAK,OAAO,WAAW,OAAO,MAAM,GAAG,CAAC,CAAC,KAAK,MAAM;EACnE,CAAC;CACH;;;;;;CAOA,MAAa,QAAuB;EAClC,MAAM,aAAa,OAAO,IAAI,MAAM;EAEpC,IAAI,CAAC,cAAc,CAAC,KAAK,MAAM;EAE/B,IAAI,YAAY,oBAAoB,eAClC,OAAO,cAAc,KAAK,IAAI;OAE9B,OAAO,KAAK,KAAK,IAAI;EAOvB,OAAO,+BAA+B,OAAO,WAAW,CAAC;EACzD,IAAI,KAAK,QAAQ,UAAU,GAAG,OAAO,WAAW,EAAE,qBAAqB;EAEvE,IAAI;GAEF,MAAM,KAAK,KAAK,OAAO;IACrB,MAAM,WAAW;IACjB,MAAM,WAAW,QAAQ;GAC3B,CAAC;GAED,MAAM,UAAU,OAAO,IAAI,aAAa;GAExC,IAAI,QAAQ,QAAQ,cAAc,mBAAmB,SAAS;EAChE,SAAS,OAAO;GACd,YAAY,oCAAoC,KAAK;GAMrD,MAAM,IAAI,MAAM,QAAQ,cAAc,KAAK;GAC3C,MAAM,IAAI,MAAM;GAEhB,QAAQ,KAAK,CAAC;EAChB;EAEA,KAAK,SAAS;CAChB;;;;;;CAOA,MAAa,UAAyB;EACpC,MAAM,KAAK,SAAS;EACpB,MAAM,KAAK,KAAK;EAChB,MAAM,KAAK,MAAM;CACnB;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,MAAM,SAAS,cAAc;EAE7B,IAAI,QAAQ;GACV,MAAM,UAAU,OAAO,IAAI,iCAAiC,wBAAwB;GAGpF,IAAI,CAAC,MAFiB,uBAAuB,QAAQ,OAAO,GAG1D,IAAI,KACF,QACA,YACA,2CAA2C,QAAQ,mBACrD;EAEJ;EAEA,KAAK,SAAS;CAChB;;;;;;CAOA,AAAO,cAAc,cAAiC;EAEpD,OAAO,aAAa,MAAM,SAAS;GACjC,MAAM,eAAe,KAAK,QAAQ,OAAO,GAAG;GAC5C,OAAO,KAAK,aAAa,SAAS,YAAY;EAChD,CAAC;CACH;AACF"}
|
|
1
|
+
{"version":3,"file":"http-connector.mjs","names":[],"sources":["../../../../../../../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 Application.setServedPort(httpConfig.port);\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":";;;;;;;;;;;;;;;;AAeA,SAAS,iBAAiB,aAA0B;CAClD,QAAQ,aAAR;EACE,KAAK,eACH,OAAO,OAAO,cAAc,WAAW;EACzC,KAAK,QACH,OAAO,OAAO,aAAa,WAAW;EACxC,KAAK,cACH,OAAO,OAAO,YAAY,WAAW;EACvC,SACE,OAAO,OAAO,MAAM,WAAW;CACnC;AACF;;;;;AAMA,MAAM,2BAA2B;;;;;AAMjC,IAAa,gBAAb,cAAmC,cAAc;;;cACxB;;;sBASW,CAAC,sBAAsB,qBAAqB;;;;;;;CAY9E,MAAa,OAAO;EAClB,MAAM,aAAa,OAAO,IAAI,MAAM;EAEpC,IAAI,CAAC,YAAY;EAEjB,MAAM,OAAO,WAAW;EACxB,IAAI,KACF,QACA,cACA,gCAAgC,KAAK,MAAM,iBAAiB,YAAY,WAAW,EAAE,MACvF;EAEA,KAAK,OAAO,gBAAgB,WAAW,aAAa;EAEpD,UAAU,IAAI,eAAe,KAAK,IAAI;EAEtC,MAAM,oBAAoB,KAAK,IAAI;EAKnC,WAHgB,OAAO,IAAI,aAGV,CAAC;EAIlB,KAAK,qBAAqB;CAC5B;;;;;;;;CASA,AAAQ,uBAA6B;EACnC,IAAI,CAAC,KAAK,MACR;EAGF,MAAM,eAAe,OAAO,IAAI,aAAa;EAE7C,IAAI,cAAc,YAAY,OAC5B;EAGF,MAAM,eAAe,cAAc,QAAQ;EAC3C,MAAM,gBAAgB,cAAc,iBAAiB;EAErD,KAAK,KAAK,IAAI,cAAc,OAAO,UAAe,UAAe;GAC/D,MAAM,SAAS,OAAO,SAAS;GAE/B,OAAO,MAAM,KAAK,OAAO,WAAW,OAAO,MAAM,GAAG,CAAC,CAAC,KAAK,MAAM;EACnE,CAAC;EAED,KAAK,KAAK,IAAI,eAAe,OAAO,UAAe,UAAe;GAChE,MAAM,SAAS,MAAM,OAAO,UAAU;GAEtC,OAAO,MAAM,KAAK,OAAO,WAAW,OAAO,MAAM,GAAG,CAAC,CAAC,KAAK,MAAM;EACnE,CAAC;CACH;;;;;;CAOA,MAAa,QAAuB;EAClC,MAAM,aAAa,OAAO,IAAI,MAAM;EAEpC,IAAI,CAAC,cAAc,CAAC,KAAK,MAAM;EAE/B,IAAI,YAAY,oBAAoB,eAClC,OAAO,cAAc,KAAK,IAAI;OAE9B,OAAO,KAAK,KAAK,IAAI;EAOvB,OAAO,+BAA+B,OAAO,WAAW,CAAC;EACzD,IAAI,KAAK,QAAQ,UAAU,GAAG,OAAO,WAAW,EAAE,qBAAqB;EAEvE,IAAI;GAEF,MAAM,KAAK,KAAK,OAAO;IACrB,MAAM,WAAW;IACjB,MAAM,WAAW,QAAQ;GAC3B,CAAC;GAED,YAAY,cAAc,WAAW,IAAI;GAEzC,MAAM,UAAU,OAAO,IAAI,aAAa;GAExC,IAAI,QAAQ,QAAQ,cAAc,mBAAmB,SAAS;EAChE,SAAS,OAAO;GACd,YAAY,oCAAoC,KAAK;GAMrD,MAAM,IAAI,MAAM,QAAQ,cAAc,KAAK;GAC3C,MAAM,IAAI,MAAM;GAEhB,QAAQ,KAAK,CAAC;EAChB;EAEA,KAAK,SAAS;CAChB;;;;;;CAOA,MAAa,UAAyB;EACpC,MAAM,KAAK,SAAS;EACpB,MAAM,KAAK,KAAK;EAChB,MAAM,KAAK,MAAM;CACnB;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,MAAM,SAAS,cAAc;EAE7B,IAAI,QAAQ;GACV,MAAM,UAAU,OAAO,IAAI,iCAAiC,wBAAwB;GAGpF,IAAI,CAAC,MAFiB,uBAAuB,QAAQ,OAAO,GAG1D,IAAI,KACF,QACA,YACA,2CAA2C,QAAQ,mBACrD;EAEJ;EAEA,KAAK,SAAS;CAChB;;;;;;CAOA,AAAO,cAAc,cAAiC;EAEpD,OAAO,aAAa,MAAM,SAAS;GACjC,MAAM,eAAe,KAAK,QAAQ,OAAO,GAAG;GAC5C,OAAO,KAAK,aAAa,SAAS,YAAY;EAChD,CAAC;CACH;AACF"}
|
|
@@ -15,14 +15,20 @@ declare class StorageConnector extends BaseConnector {
|
|
|
15
15
|
*/
|
|
16
16
|
protected readonly watchedFiles: string[];
|
|
17
17
|
/**
|
|
18
|
-
* Initialize
|
|
18
|
+
* Initialize storage.
|
|
19
19
|
*
|
|
20
20
|
* Unlike its siblings (database, cache, herald), this connector does NOT
|
|
21
21
|
* early-return when `config.get("storage")` is absent. Storage is
|
|
22
|
-
* intentionally always-on: `storage.init()`
|
|
23
|
-
*
|
|
24
|
-
* works out of the box even when a project ships no
|
|
25
|
-
* A config-presence guard here would break that
|
|
22
|
+
* intentionally always-on: `storage.init()` registers a built-in `local`
|
|
23
|
+
* driver rooted at `uploadsPath()` before reading configured drivers, so file
|
|
24
|
+
* storage works out of the box even when a project ships no
|
|
25
|
+
* `src/config/storage.ts`. A config-presence guard here would break that.
|
|
26
|
+
*
|
|
27
|
+
* That fallback is real as of 4.11.0. Until then this comment described it
|
|
28
|
+
* and nothing implemented it, so every app without `src/config/storage.ts`
|
|
29
|
+
* died at boot with `Storage driver "local" is not configured` — a decision
|
|
30
|
+
* to skip the guard, taken on the authority of behaviour nobody had written.
|
|
31
|
+
* See `Storage.registerBuiltInLocalDriver`.
|
|
26
32
|
*/
|
|
27
33
|
start(): Promise<void>;
|
|
28
34
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.connector.d.mts","names":[],"sources":["../../../../../../../core/src/connectors/storage.connector.ts"],"mappings":";;;;;;AASA;;cAAa,gBAAA,SAAyB,aAAA;EAAA,SACpB,IAAA;EAAA,SACA,QAAA,GAAQ,iBAAA,CAAA,OAAA;EAAA,SACR,cAAA,GAAc,uBAAA,CAAA,KAAA;
|
|
1
|
+
{"version":3,"file":"storage.connector.d.mts","names":[],"sources":["../../../../../../../core/src/connectors/storage.connector.ts"],"mappings":";;;;;;AASA;;cAAa,gBAAA,SAAyB,aAAA;EAAA,SACpB,IAAA;EAAA,SACA,QAAA,GAAQ,iBAAA,CAAA,OAAA;EAAA,SACR,cAAA,GAAc,uBAAA,CAAA,KAAA;EAiCL;;;EAAA,mBA5BN,YAAA;EARiB;;;;;;;;;;;;;;AAoCJ;;EAVnB,KAAA,IAAS,OAAA;;;;EAUT,QAAA,IAAY,OAAA;AAAA"}
|
|
@@ -18,14 +18,20 @@ var StorageConnector = class extends BaseConnector {
|
|
|
18
18
|
this.watchedFiles = ["src/config/storage.ts", "src/config/storage.tsx"];
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
* Initialize
|
|
21
|
+
* Initialize storage.
|
|
22
22
|
*
|
|
23
23
|
* Unlike its siblings (database, cache, herald), this connector does NOT
|
|
24
24
|
* early-return when `config.get("storage")` is absent. Storage is
|
|
25
|
-
* intentionally always-on: `storage.init()`
|
|
26
|
-
*
|
|
27
|
-
* works out of the box even when a project ships no
|
|
28
|
-
* A config-presence guard here would break that
|
|
25
|
+
* intentionally always-on: `storage.init()` registers a built-in `local`
|
|
26
|
+
* driver rooted at `uploadsPath()` before reading configured drivers, so file
|
|
27
|
+
* storage works out of the box even when a project ships no
|
|
28
|
+
* `src/config/storage.ts`. A config-presence guard here would break that.
|
|
29
|
+
*
|
|
30
|
+
* That fallback is real as of 4.11.0. Until then this comment described it
|
|
31
|
+
* and nothing implemented it, so every app without `src/config/storage.ts`
|
|
32
|
+
* died at boot with `Storage driver "local" is not configured` — a decision
|
|
33
|
+
* to skip the guard, taken on the authority of behaviour nobody had written.
|
|
34
|
+
* See `Storage.registerBuiltInLocalDriver`.
|
|
29
35
|
*/
|
|
30
36
|
async start() {
|
|
31
37
|
await loadS3();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.connector.mjs","names":[],"sources":["../../../../../../../core/src/connectors/storage.connector.ts"],"sourcesContent":["import { storage } from \"../storage\";\nimport { loadS3 } from \"../storage/drivers/cloud-driver\";\nimport { BaseConnector } from \"./base-connector\";\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\n\n/**\n * Cache Connector\n * Manages cache engine connection lifecycle\n */\nexport class StorageConnector extends BaseConnector {\n public readonly name = \"storage\";\n public readonly priority = ConnectorPriority.STORAGE;\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\n\n /**\n * Files that trigger cache restart\n */\n protected readonly watchedFiles = [\"src/config/storage.ts\", \"src/config/storage.tsx\"];\n\n /**\n * Initialize
|
|
1
|
+
{"version":3,"file":"storage.connector.mjs","names":[],"sources":["../../../../../../../core/src/connectors/storage.connector.ts"],"sourcesContent":["import { storage } from \"../storage\";\nimport { loadS3 } from \"../storage/drivers/cloud-driver\";\nimport { BaseConnector } from \"./base-connector\";\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\n\n/**\n * Cache Connector\n * Manages cache engine connection lifecycle\n */\nexport class StorageConnector extends BaseConnector {\n public readonly name = \"storage\";\n public readonly priority = ConnectorPriority.STORAGE;\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\n\n /**\n * Files that trigger cache restart\n */\n protected readonly watchedFiles = [\"src/config/storage.ts\", \"src/config/storage.tsx\"];\n\n /**\n * Initialize storage.\n *\n * Unlike its siblings (database, cache, herald), this connector does NOT\n * early-return when `config.get(\"storage\")` is absent. Storage is\n * intentionally always-on: `storage.init()` registers a built-in `local`\n * driver rooted at `uploadsPath()` before reading configured drivers, so file\n * storage works out of the box even when a project ships no\n * `src/config/storage.ts`. A config-presence guard here would break that.\n *\n * That fallback is real as of 4.11.0. Until then this comment described it\n * and nothing implemented it, so every app without `src/config/storage.ts`\n * died at boot with `Storage driver \"local\" is not configured` — a decision\n * to skip the guard, taken on the authority of behaviour nobody had written.\n * See `Storage.registerBuiltInLocalDriver`.\n */\n public async start(): Promise<void> {\n await loadS3();\n await storage.init();\n\n this.active = true;\n }\n\n /**\n * Shutdown cache connection\n */\n public async shutdown(): Promise<void> {\n if (!this.active) {\n return;\n }\n\n storage.reset();\n\n this.active = false;\n }\n}\n"],"mappings":";;;;;;;;;;;AASA,IAAa,mBAAb,cAAsC,cAAc;;;cAC3B;;;sBAOW,CAAC,yBAAyB,wBAAwB;;;;;;;;;;;;;;;;;;CAkBpF,MAAa,QAAuB;EAClC,MAAM,OAAO;EACb,MAAM,QAAQ,KAAK;EAEnB,KAAK,SAAS;CAChB;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,QAAQ,MAAM;EAEd,KAAK,SAAS;CAChB;AACF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TranspileCache, cacheKey } from "./transpile-cache.mjs";
|
|
2
2
|
import { sourceSlug } from "./source-slug.mjs";
|
|
3
|
-
import { transformSync } from "esbuild";
|
|
4
3
|
import { readFileSync } from "node:fs";
|
|
4
|
+
import { transformSync } from "esbuild";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
|
|
7
7
|
//#region ../core/src/dev-server/loader/load-hook.ts
|
|
@@ -280,7 +280,7 @@ export default {
|
|
|
280
280
|
},
|
|
281
281
|
} as SocketOptions;
|
|
282
282
|
`;
|
|
283
|
-
const communicatorsConfigStub = `import { env } from "@
|
|
283
|
+
const communicatorsConfigStub = `import { env } from "@warlock.js/core";
|
|
284
284
|
import type { BrokerConfigurations, RabbitMQClientOptions } from "@warlock.js/herald";
|
|
285
285
|
|
|
286
286
|
const heraldConfigurations: BrokerConfigurations<RabbitMQClientOptions> = {
|