@warlock.js/core 4.1.5 → 4.1.6

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 (63) hide show
  1. package/esm/config/config-getter.mjs +5 -5
  2. package/esm/config/config-getter.mjs.map +1 -1
  3. package/esm/config/config-loader.mjs +2 -2
  4. package/esm/config/config-loader.mjs.map +1 -1
  5. package/esm/connectors/cache-connector.mjs +2 -2
  6. package/esm/connectors/cache-connector.mjs.map +1 -1
  7. package/esm/connectors/database-connector.mjs +2 -2
  8. package/esm/connectors/database-connector.mjs.map +1 -1
  9. package/esm/connectors/herald-connector.mjs +2 -2
  10. package/esm/connectors/herald-connector.mjs.map +1 -1
  11. package/esm/connectors/http-connector.mjs +5 -5
  12. package/esm/connectors/http-connector.mjs.map +1 -1
  13. package/esm/connectors/logger-connector.mjs +2 -2
  14. package/esm/connectors/logger-connector.mjs.map +1 -1
  15. package/esm/connectors/mail-connector.mjs +2 -2
  16. package/esm/connectors/mail-connector.mjs.map +1 -1
  17. package/esm/connectors/socket-connector.mjs +3 -3
  18. package/esm/connectors/socket-connector.mjs.map +1 -1
  19. package/esm/dev-server/health-checker/workers/eslint-health.worker.d.mts +1 -0
  20. package/esm/dev-server/health-checker/workers/ts-health.worker.d.mts +1 -0
  21. package/esm/dev-server/loader/hook-thread.d.mts +48 -0
  22. package/esm/dev-server/loader/hook-thread.d.mts.map +1 -0
  23. package/esm/dev-server/loader/hook-thread.mjs +47 -0
  24. package/esm/dev-server/loader/hook-thread.mjs.map +1 -0
  25. package/esm/dev-server/loader/load-hook.d.mts +58 -0
  26. package/esm/dev-server/loader/load-hook.d.mts.map +1 -0
  27. package/esm/dev-server/loader/load-hook.mjs +86 -0
  28. package/esm/dev-server/loader/load-hook.mjs.map +1 -0
  29. package/esm/dev-server/loader/own-resolver.mjs +69 -0
  30. package/esm/dev-server/loader/own-resolver.mjs.map +1 -0
  31. package/esm/dev-server/loader/resolve-capture.mjs +43 -0
  32. package/esm/dev-server/loader/resolve-capture.mjs.map +1 -0
  33. package/esm/dev-server/loader/resolve-hook.d.mts +41 -0
  34. package/esm/dev-server/loader/resolve-hook.d.mts.map +1 -0
  35. package/esm/dev-server/loader/resolve-hook.mjs +87 -0
  36. package/esm/dev-server/loader/resolve-hook.mjs.map +1 -0
  37. package/esm/dev-server/loader/source-slug.mjs +22 -0
  38. package/esm/dev-server/loader/source-slug.mjs.map +1 -0
  39. package/esm/dev-server/loader/transpile-cache.mjs +163 -1
  40. package/esm/dev-server/loader/transpile-cache.mjs.map +1 -1
  41. package/esm/dev-server/loader/version-registry.mjs +45 -0
  42. package/esm/dev-server/loader/version-registry.mjs.map +1 -0
  43. package/esm/http/config.mjs +2 -2
  44. package/esm/http/config.mjs.map +1 -1
  45. package/esm/http/createHttpApplication.mjs +2 -2
  46. package/esm/http/createHttpApplication.mjs.map +1 -1
  47. package/esm/http/middleware/idempotency.middleware.mjs +5 -5
  48. package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
  49. package/esm/http/middleware/inject-request-context.mjs +2 -2
  50. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  51. package/esm/http/middleware/maintenance.middleware.mjs +4 -4
  52. package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
  53. package/esm/http/plugins.mjs +9 -9
  54. package/esm/http/plugins.mjs.map +1 -1
  55. package/esm/http/response.mjs +5 -5
  56. package/esm/http/response.mjs.map +1 -1
  57. package/esm/http/server.mjs +2 -2
  58. package/esm/http/server.mjs.map +1 -1
  59. package/esm/utils/paths.mjs +2 -2
  60. package/esm/utils/paths.mjs.map +1 -1
  61. package/esm/validation/validateAll.mjs +2 -2
  62. package/esm/validation/validateAll.mjs.map +1 -1
  63. package/package.json +27 -9
@@ -0,0 +1,45 @@
1
+ //#region ../../@warlock.js/core/src/dev-server/loader/version-registry.ts
2
+ /**
3
+ * Version registry for the ESM loader hook.
4
+ *
5
+ * Lives in the hook worker thread. The main thread sends bump messages via
6
+ * MessageChannel; each bump increments the monotonic counter for that path,
7
+ * which causes `resolve()` to produce a new URL — Node sees a fresh module.
8
+ *
9
+ * Monotonic integers are used instead of timestamps so there is no clock-drift
10
+ * risk and the version is trivial to reason about during debugging.
11
+ *
12
+ * @example
13
+ * // Hook worker receives a bump from the file watcher:
14
+ * bumpVersion("/abs/path/to/user.model.ts");
15
+ * // → getVersion returns 1, resolve() appends ?v=1 to the URL
16
+ */
17
+ const versionMap = /* @__PURE__ */ new Map();
18
+ /**
19
+ * Normalize a filesystem path to a single canonical form so the main thread
20
+ * (which often holds forward-slash paths from posix-style joins) and the
21
+ * hook worker (which gets backslash paths from `fileURLToPath` on Windows)
22
+ * agree on map keys.
23
+ */
24
+ function normalizeKey(absolutePath) {
25
+ return absolutePath.replace(/\\/g, "/").toLowerCase();
26
+ }
27
+ /**
28
+ * Increment the version counter for the given absolute path.
29
+ * Called when the file watcher detects a change.
30
+ */
31
+ function bumpVersion(absolutePath) {
32
+ const key = normalizeKey(absolutePath);
33
+ versionMap.set(key, (versionMap.get(key) ?? 0) + 1);
34
+ }
35
+ /**
36
+ * Return the current version counter for the given absolute path.
37
+ * Returns 0 for paths not yet seen (first import).
38
+ */
39
+ function getVersion(absolutePath) {
40
+ return versionMap.get(normalizeKey(absolutePath)) ?? 0;
41
+ }
42
+
43
+ //#endregion
44
+ export { bumpVersion, getVersion };
45
+ //# sourceMappingURL=version-registry.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-registry.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/dev-server/loader/version-registry.ts"],"sourcesContent":["/**\n * Version registry for the ESM loader hook.\n *\n * Lives in the hook worker thread. The main thread sends bump messages via\n * MessageChannel; each bump increments the monotonic counter for that path,\n * which causes `resolve()` to produce a new URL — Node sees a fresh module.\n *\n * Monotonic integers are used instead of timestamps so there is no clock-drift\n * risk and the version is trivial to reason about during debugging.\n *\n * @example\n * // Hook worker receives a bump from the file watcher:\n * bumpVersion(\"/abs/path/to/user.model.ts\");\n * // → getVersion returns 1, resolve() appends ?v=1 to the URL\n */\n\nconst versionMap = new Map<string, number>();\n\n/**\n * Normalize a filesystem path to a single canonical form so the main thread\n * (which often holds forward-slash paths from posix-style joins) and the\n * hook worker (which gets backslash paths from `fileURLToPath` on Windows)\n * agree on map keys.\n */\nfunction normalizeKey(absolutePath: string): string {\n return absolutePath.replace(/\\\\/g, \"/\").toLowerCase();\n}\n\n/**\n * Increment the version counter for the given absolute path.\n * Called when the file watcher detects a change.\n */\nexport function bumpVersion(absolutePath: string): void {\n const key = normalizeKey(absolutePath);\n versionMap.set(key, (versionMap.get(key) ?? 0) + 1);\n}\n\n/**\n * Return the current version counter for the given absolute path.\n * Returns 0 for paths not yet seen (first import).\n */\nexport function getVersion(absolutePath: string): number {\n return versionMap.get(normalizeKey(absolutePath)) ?? 0;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,MAAM,6BAAa,IAAI,IAAoB;;;;;;;AAQ3C,SAAS,aAAa,cAA8B;CAClD,OAAO,aAAa,QAAQ,OAAO,GAAG,EAAE,YAAY;AACtD;;;;;AAMA,SAAgB,YAAY,cAA4B;CACtD,MAAM,MAAM,aAAa,YAAY;CACrC,WAAW,IAAI,MAAM,WAAW,IAAI,GAAG,KAAK,KAAK,CAAC;AACpD;;;;;AAMA,SAAgB,WAAW,cAA8B;CACvD,OAAO,WAAW,IAAI,aAAa,YAAY,CAAC,KAAK;AACvD"}
@@ -1,4 +1,4 @@
1
- import config from "@mongez/config";
1
+ import baseConfig from "@mongez/config";
2
2
  import { get } from "@mongez/reinforcements";
3
3
 
4
4
  //#region ../../@warlock.js/core/src/http/config.ts
@@ -18,7 +18,7 @@ const defaultHttpConfigurations = {
18
18
  * Get http configurations for the given key
19
19
  */
20
20
  function httpConfig(key) {
21
- return config.get(`http.${key}`, get(defaultHttpConfigurations, key));
21
+ return baseConfig.get(`http.${key}`, get(defaultHttpConfigurations, key));
22
22
  }
23
23
 
24
24
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"config.mjs","names":[],"sources":["../../../../../../@warlock.js/core/src/http/config.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { get } from \"@mongez/reinforcements\";\nimport type { HttpConfigurations } from \"./types\";\n\n/**\n * Default http configurations\n */\nexport const defaultHttpConfigurations: HttpConfigurations = {\n port: 3000,\n host: \"0.0.0.0\",\n middleware: {\n all: [],\n only: {\n middleware: [],\n },\n except: {\n middleware: [],\n },\n },\n};\n\n/**\n * Get http configurations for the given key\n */\nexport function httpConfig(key: string): any {\n return config.get(`http.${key}`, get(defaultHttpConfigurations, key));\n}\n"],"mappings":";;;;;;;AAOA,MAAa,4BAAgD;CAC3D,MAAM;CACN,MAAM;CACN,YAAY;EACV,KAAK,CAAC;EACN,MAAM,EACJ,YAAY,CAAC,EACf;EACA,QAAQ,EACN,YAAY,CAAC,EACf;CACF;AACF;;;;AAKA,SAAgB,WAAW,KAAkB;CAC3C,OAAO,OAAO,IAAI,QAAQ,OAAO,IAAI,2BAA2B,GAAG,CAAC;AACtE"}
1
+ {"version":3,"file":"config.mjs","names":["config"],"sources":["../../../../../../@warlock.js/core/src/http/config.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { get } from \"@mongez/reinforcements\";\nimport type { HttpConfigurations } from \"./types\";\n\n/**\n * Default http configurations\n */\nexport const defaultHttpConfigurations: HttpConfigurations = {\n port: 3000,\n host: \"0.0.0.0\",\n middleware: {\n all: [],\n only: {\n middleware: [],\n },\n except: {\n middleware: [],\n },\n },\n};\n\n/**\n * Get http configurations for the given key\n */\nexport function httpConfig(key: string): any {\n return config.get(`http.${key}`, get(defaultHttpConfigurations, key));\n}\n"],"mappings":";;;;;;;AAOA,MAAa,4BAAgD;CAC3D,MAAM;CACN,MAAM;CACN,YAAY;EACV,KAAK,CAAC;EACN,MAAM,EACJ,YAAY,CAAC,EACf;EACA,QAAQ,EACN,YAAY,CAAC,EACf;CACF;AACF;;;;AAKA,SAAgB,WAAW,KAAkB;CAC3C,OAAOA,WAAO,IAAI,QAAQ,OAAO,IAAI,2BAA2B,GAAG,CAAC;AACtE"}
@@ -4,7 +4,7 @@ import { router } from "../router/router.mjs";
4
4
  import "../router/index.mjs";
5
5
  import { registerHttpPlugins } from "./plugins.mjs";
6
6
  import { getHttpServer, startHttpServer } from "./server.mjs";
7
- import config from "@mongez/config";
7
+ import baseConfig from "@mongez/config";
8
8
  import { log } from "@warlock.js/logger";
9
9
 
10
10
  //#region ../../@warlock.js/core/src/http/createHttpApplication.ts
@@ -19,7 +19,7 @@ async function createHttpApplication() {
19
19
  port,
20
20
  host: httpConfig("host")
21
21
  });
22
- const baseUrl = config.get("app.baseUrl");
22
+ const baseUrl = baseConfig.get("app.baseUrl");
23
23
  setBaseUrl(baseUrl);
24
24
  log.success("http", "server", `Server is listening on ${baseUrl}`);
25
25
  } catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"createHttpApplication.mjs","names":[],"sources":["../../../../../../@warlock.js/core/src/http/createHttpApplication.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport { router } from \"../router\";\nimport { setBaseUrl } from \"../utils/urls\";\nimport { httpConfig } from \"./config\";\nimport { registerHttpPlugins } from \"./plugins\";\nimport { getHttpServer, startHttpServer } from \"./server\";\n\nexport async function createHttpApplication() {\n const server = startHttpServer();\n\n await registerHttpPlugins(server);\n\n router.scan(server);\n\n const port = httpConfig(\"port\");\n\n try {\n log.info(\"http\", \"server\", \"Connecting to the server\");\n // 👇🏻 We can use the url of the server\n await server.listen({\n port,\n host: httpConfig(\"host\"),\n });\n\n const baseUrl = config.get(\"app.baseUrl\");\n\n // update base url\n setBaseUrl(baseUrl);\n\n log.success(\"http\", \"server\", `Server is listening on ${baseUrl}`);\n } catch (error) {\n log.error(\"http\", \"server\", error);\n\n process.exit(1); // stop the process, exit with error\n }\n}\n\nexport async function stopHttpApplication() {\n log.info(\"http\", \"server\", \"Stopping the server\");\n const server = getHttpServer();\n\n await server?.close();\n\n log.success(\"http\", \"server\", \"Server is stopped\");\n}\n"],"mappings":";;;;;;;;;;AAQA,eAAsB,wBAAwB;CAC5C,MAAM,SAAS,gBAAgB;CAE/B,MAAM,oBAAoB,MAAM;CAEhC,OAAO,KAAK,MAAM;CAElB,MAAM,OAAO,WAAW,MAAM;CAE9B,IAAI;EACF,IAAI,KAAK,QAAQ,UAAU,0BAA0B;EAErD,MAAM,OAAO,OAAO;GAClB;GACA,MAAM,WAAW,MAAM;EACzB,CAAC;EAED,MAAM,UAAU,OAAO,IAAI,aAAa;EAGxC,WAAW,OAAO;EAElB,IAAI,QAAQ,QAAQ,UAAU,0BAA0B,SAAS;CACnE,SAAS,OAAO;EACd,IAAI,MAAM,QAAQ,UAAU,KAAK;EAEjC,QAAQ,KAAK,CAAC;CAChB;AACF;AAEA,eAAsB,sBAAsB;CAC1C,IAAI,KAAK,QAAQ,UAAU,qBAAqB;CAGhD,MAFe,cAEJ,GAAG,MAAM;CAEpB,IAAI,QAAQ,QAAQ,UAAU,mBAAmB;AACnD"}
1
+ {"version":3,"file":"createHttpApplication.mjs","names":["config"],"sources":["../../../../../../@warlock.js/core/src/http/createHttpApplication.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport { router } from \"../router\";\nimport { setBaseUrl } from \"../utils/urls\";\nimport { httpConfig } from \"./config\";\nimport { registerHttpPlugins } from \"./plugins\";\nimport { getHttpServer, startHttpServer } from \"./server\";\n\nexport async function createHttpApplication() {\n const server = startHttpServer();\n\n await registerHttpPlugins(server);\n\n router.scan(server);\n\n const port = httpConfig(\"port\");\n\n try {\n log.info(\"http\", \"server\", \"Connecting to the server\");\n // 👇🏻 We can use the url of the server\n await server.listen({\n port,\n host: httpConfig(\"host\"),\n });\n\n const baseUrl = config.get(\"app.baseUrl\");\n\n // update base url\n setBaseUrl(baseUrl);\n\n log.success(\"http\", \"server\", `Server is listening on ${baseUrl}`);\n } catch (error) {\n log.error(\"http\", \"server\", error);\n\n process.exit(1); // stop the process, exit with error\n }\n}\n\nexport async function stopHttpApplication() {\n log.info(\"http\", \"server\", \"Stopping the server\");\n const server = getHttpServer();\n\n await server?.close();\n\n log.success(\"http\", \"server\", \"Server is stopped\");\n}\n"],"mappings":";;;;;;;;;;AAQA,eAAsB,wBAAwB;CAC5C,MAAM,SAAS,gBAAgB;CAE/B,MAAM,oBAAoB,MAAM;CAEhC,OAAO,KAAK,MAAM;CAElB,MAAM,OAAO,WAAW,MAAM;CAE9B,IAAI;EACF,IAAI,KAAK,QAAQ,UAAU,0BAA0B;EAErD,MAAM,OAAO,OAAO;GAClB;GACA,MAAM,WAAW,MAAM;EACzB,CAAC;EAED,MAAM,UAAUA,WAAO,IAAI,aAAa;EAGxC,WAAW,OAAO;EAElB,IAAI,QAAQ,QAAQ,UAAU,0BAA0B,SAAS;CACnE,SAAS,OAAO;EACd,IAAI,MAAM,QAAQ,UAAU,KAAK;EAEjC,QAAQ,KAAK,CAAC;CAChB;AACF;AAEA,eAAsB,sBAAsB;CAC1C,IAAI,KAAK,QAAQ,UAAU,qBAAqB;CAGhD,MAFe,cAEJ,GAAG,MAAM;CAEpB,IAAI,QAAQ,QAAQ,UAAU,mBAAmB;AACnD"}
@@ -1,7 +1,7 @@
1
1
  import { t } from "./inject-request-context.mjs";
2
2
  import { HttpErrorCodes } from "../error-codes.mjs";
3
3
  import { buildIdempotencyCacheKey, hashBody, isValidIdempotencyKey } from "./utils/idempotency-key.mjs";
4
- import config from "@mongez/config";
4
+ import baseConfig from "@mongez/config";
5
5
  import { cache } from "@warlock.js/cache";
6
6
 
7
7
  //#region ../../@warlock.js/core/src/http/middleware/idempotency.middleware.ts
@@ -43,10 +43,10 @@ const DEFAULT_METHODS = [
43
43
  */
44
44
  function idempotencyMiddleware(options = {}) {
45
45
  return async (request, response) => {
46
- const headerName = options.headerName || config.get("http.idempotency.headerName", "Idempotency-Key");
47
- const methods = options.methods || config.get("http.idempotency.methods", DEFAULT_METHODS);
48
- const ttl = options.ttl || config.get("http.idempotency.ttl", 86400);
49
- const driverName = options.driver || config.get("http.idempotency.driver");
46
+ const headerName = options.headerName || baseConfig.get("http.idempotency.headerName", "Idempotency-Key");
47
+ const methods = options.methods || baseConfig.get("http.idempotency.methods", DEFAULT_METHODS);
48
+ const ttl = options.ttl || baseConfig.get("http.idempotency.ttl", 86400);
49
+ const driverName = options.driver || baseConfig.get("http.idempotency.driver");
50
50
  if (!methods.includes(request.method.toUpperCase())) return;
51
51
  const idempotencyKey = request.header(headerName.toLowerCase());
52
52
  if (!idempotencyKey) return;
@@ -1 +1 @@
1
- {"version":3,"file":"idempotency.middleware.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/http/middleware/idempotency.middleware.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { cache } from \"@warlock.js/cache\";\nimport type { Middleware } from \"../../router\";\nimport { HttpErrorCodes } from \"../error-codes\";\nimport type { Response } from \"../response\";\nimport { t } from \"./inject-request-context\";\nimport {\n buildIdempotencyCacheKey,\n hashBody,\n isValidIdempotencyKey,\n} from \"./utils/idempotency-key\";\n\n/**\n * Options for the idempotency middleware.\n */\nexport type IdempotencyOptions = {\n /**\n * Cache TTL in seconds. Falls back to `http.idempotency.ttl`, then `86400` (24h).\n */\n ttl?: number;\n /**\n * Header name carrying the client's key. Falls back to\n * `http.idempotency.headerName`, then `\"Idempotency-Key\"`.\n */\n headerName?: string;\n /**\n * HTTP methods eligible for idempotency. Falls back to\n * `http.idempotency.methods`, then `[\"POST\",\"PUT\",\"PATCH\",\"DELETE\"]`.\n * Safe methods (GET/HEAD) are skipped regardless.\n */\n methods?: string[];\n /**\n * Cache driver name. Falls back to `http.idempotency.driver`, then the\n * default driver of the cache manager.\n */\n driver?: string;\n};\n\ntype CachedResponse = {\n status: number;\n body: unknown;\n bodyHash: string;\n contentType?: string;\n};\n\nconst DEFAULT_METHODS = [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"];\n\n/**\n * Dedupe non-idempotent writes by an `Idempotency-Key` header — same key,\n * same body, within TTL → cached replay; same key, different body → 422\n * `IdempotencyKeyConflict`.\n *\n * **Must run after `authMiddleware`** — the cache key is scoped per-user\n * (`idem:{userType}:{userId}:{key}`) so user A can't replay user B's key.\n * Anonymous requests fall back to IP scope.\n *\n * The replay sets `Idempotent-Replay: true` on the response for easy\n * client-side / observability detection.\n *\n * Eligible methods default to POST/PUT/PATCH/DELETE. GET/HEAD pass through\n * even with the header set (RFC: safe methods are already idempotent).\n *\n * @example\n * import { authMiddleware } from \"@warlock.js/auth\";\n * import { middleware } from \"@warlock.js/core\";\n *\n * router.post(\"/orders\", createOrderController, {\n * middleware: [authMiddleware(\"client\"), middleware.idempotency()],\n * });\n *\n * router.post(\"/ai/summarize\", summarizeController, {\n * middleware: [\n * authMiddleware(\"client\"),\n * middleware.idempotency({ ttl: 60 * 60 }), // 1h is enough for client retries\n * ],\n * });\n */\nexport function idempotencyMiddleware(options: IdempotencyOptions = {}): Middleware {\n return async (request, response) => {\n const headerName =\n options.headerName ||\n config.get(\"http.idempotency.headerName\", \"Idempotency-Key\");\n const methods =\n options.methods || config.get(\"http.idempotency.methods\", DEFAULT_METHODS);\n const ttl = options.ttl || config.get(\"http.idempotency.ttl\", 86400);\n const driverName = options.driver || config.get(\"http.idempotency.driver\");\n\n if (!methods.includes(request.method.toUpperCase())) return;\n\n const idempotencyKey = request.header(headerName.toLowerCase());\n\n if (!idempotencyKey) return;\n\n if (!isValidIdempotencyKey(idempotencyKey)) {\n return response.badRequest({\n error: t(\"http.idempotencyKeyInvalid\"),\n errorCode: HttpErrorCodes.IdempotencyKeyInvalid,\n });\n }\n\n const cacheDriver = driverName ? await cache.use(driverName) : cache;\n const cacheKey = buildIdempotencyCacheKey(request, idempotencyKey);\n const bodyHash = hashBody(request.body);\n\n const cached = (await cacheDriver.get(cacheKey)) as CachedResponse | null;\n\n if (cached) {\n if (cached.bodyHash !== bodyHash) {\n return response.unprocessableEntity({\n error: t(\"http.idempotencyKeyConflict\"),\n errorCode: HttpErrorCodes.IdempotencyKeyConflict,\n });\n }\n\n response.header(\"Idempotent-Replay\", \"true\");\n\n return response.replay({\n status: cached.status,\n body: cached.body,\n contentType: cached.contentType,\n });\n }\n\n response.onSent((sentResponse: Response) => {\n // Don't cache server errors — clients should be able to retry past a 5xx.\n // 4xx are deterministic outcomes of the request, so caching is fine.\n if (sentResponse.statusCode >= 500) return;\n\n const sentContentType = sentResponse.contentType;\n\n cacheDriver.set(\n cacheKey,\n {\n status: sentResponse.statusCode,\n body: sentResponse.parsedBody,\n bodyHash,\n contentType: typeof sentContentType === \"string\" ? sentContentType : undefined,\n },\n ttl,\n );\n });\n };\n}\n"],"mappings":";;;;;;;AA6CA,MAAM,kBAAkB;CAAC;CAAQ;CAAO;CAAS;AAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCzD,SAAgB,sBAAsB,UAA8B,CAAC,GAAe;CAClF,OAAO,OAAO,SAAS,aAAa;EAClC,MAAM,aACJ,QAAQ,cACR,OAAO,IAAI,+BAA+B,iBAAiB;EAC7D,MAAM,UACJ,QAAQ,WAAW,OAAO,IAAI,4BAA4B,eAAe;EAC3E,MAAM,MAAM,QAAQ,OAAO,OAAO,IAAI,wBAAwB,KAAK;EACnE,MAAM,aAAa,QAAQ,UAAU,OAAO,IAAI,yBAAyB;EAEzE,IAAI,CAAC,QAAQ,SAAS,QAAQ,OAAO,YAAY,CAAC,GAAG;EAErD,MAAM,iBAAiB,QAAQ,OAAO,WAAW,YAAY,CAAC;EAE9D,IAAI,CAAC,gBAAgB;EAErB,IAAI,CAAC,sBAAsB,cAAc,GACvC,OAAO,SAAS,WAAW;GACzB,OAAO,EAAE,4BAA4B;GACrC;EACF,CAAC;EAGH,MAAM,cAAc,aAAa,MAAM,MAAM,IAAI,UAAU,IAAI;EAC/D,MAAM,WAAW,yBAAyB,SAAS,cAAc;EACjE,MAAM,WAAW,SAAS,QAAQ,IAAI;EAEtC,MAAM,SAAU,MAAM,YAAY,IAAI,QAAQ;EAE9C,IAAI,QAAQ;GACV,IAAI,OAAO,aAAa,UACtB,OAAO,SAAS,oBAAoB;IAClC,OAAO,EAAE,6BAA6B;IACtC;GACF,CAAC;GAGH,SAAS,OAAO,qBAAqB,MAAM;GAE3C,OAAO,SAAS,OAAO;IACrB,QAAQ,OAAO;IACf,MAAM,OAAO;IACb,aAAa,OAAO;GACtB,CAAC;EACH;EAEA,SAAS,QAAQ,iBAA2B;GAG1C,IAAI,aAAa,cAAc,KAAK;GAEpC,MAAM,kBAAkB,aAAa;GAErC,YAAY,IACV,UACA;IACE,QAAQ,aAAa;IACrB,MAAM,aAAa;IACnB;IACA,aAAa,OAAO,oBAAoB,WAAW,kBAAkB;GACvE,GACA,GACF;EACF,CAAC;CACH;AACF"}
1
+ {"version":3,"file":"idempotency.middleware.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/http/middleware/idempotency.middleware.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { cache } from \"@warlock.js/cache\";\nimport type { Middleware } from \"../../router\";\nimport { HttpErrorCodes } from \"../error-codes\";\nimport type { Response } from \"../response\";\nimport { t } from \"./inject-request-context\";\nimport {\n buildIdempotencyCacheKey,\n hashBody,\n isValidIdempotencyKey,\n} from \"./utils/idempotency-key\";\n\n/**\n * Options for the idempotency middleware.\n */\nexport type IdempotencyOptions = {\n /**\n * Cache TTL in seconds. Falls back to `http.idempotency.ttl`, then `86400` (24h).\n */\n ttl?: number;\n /**\n * Header name carrying the client's key. Falls back to\n * `http.idempotency.headerName`, then `\"Idempotency-Key\"`.\n */\n headerName?: string;\n /**\n * HTTP methods eligible for idempotency. Falls back to\n * `http.idempotency.methods`, then `[\"POST\",\"PUT\",\"PATCH\",\"DELETE\"]`.\n * Safe methods (GET/HEAD) are skipped regardless.\n */\n methods?: string[];\n /**\n * Cache driver name. Falls back to `http.idempotency.driver`, then the\n * default driver of the cache manager.\n */\n driver?: string;\n};\n\ntype CachedResponse = {\n status: number;\n body: unknown;\n bodyHash: string;\n contentType?: string;\n};\n\nconst DEFAULT_METHODS = [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"];\n\n/**\n * Dedupe non-idempotent writes by an `Idempotency-Key` header — same key,\n * same body, within TTL → cached replay; same key, different body → 422\n * `IdempotencyKeyConflict`.\n *\n * **Must run after `authMiddleware`** — the cache key is scoped per-user\n * (`idem:{userType}:{userId}:{key}`) so user A can't replay user B's key.\n * Anonymous requests fall back to IP scope.\n *\n * The replay sets `Idempotent-Replay: true` on the response for easy\n * client-side / observability detection.\n *\n * Eligible methods default to POST/PUT/PATCH/DELETE. GET/HEAD pass through\n * even with the header set (RFC: safe methods are already idempotent).\n *\n * @example\n * import { authMiddleware } from \"@warlock.js/auth\";\n * import { middleware } from \"@warlock.js/core\";\n *\n * router.post(\"/orders\", createOrderController, {\n * middleware: [authMiddleware(\"client\"), middleware.idempotency()],\n * });\n *\n * router.post(\"/ai/summarize\", summarizeController, {\n * middleware: [\n * authMiddleware(\"client\"),\n * middleware.idempotency({ ttl: 60 * 60 }), // 1h is enough for client retries\n * ],\n * });\n */\nexport function idempotencyMiddleware(options: IdempotencyOptions = {}): Middleware {\n return async (request, response) => {\n const headerName =\n options.headerName ||\n config.get(\"http.idempotency.headerName\", \"Idempotency-Key\");\n const methods =\n options.methods || config.get(\"http.idempotency.methods\", DEFAULT_METHODS);\n const ttl = options.ttl || config.get(\"http.idempotency.ttl\", 86400);\n const driverName = options.driver || config.get(\"http.idempotency.driver\");\n\n if (!methods.includes(request.method.toUpperCase())) return;\n\n const idempotencyKey = request.header(headerName.toLowerCase());\n\n if (!idempotencyKey) return;\n\n if (!isValidIdempotencyKey(idempotencyKey)) {\n return response.badRequest({\n error: t(\"http.idempotencyKeyInvalid\"),\n errorCode: HttpErrorCodes.IdempotencyKeyInvalid,\n });\n }\n\n const cacheDriver = driverName ? await cache.use(driverName) : cache;\n const cacheKey = buildIdempotencyCacheKey(request, idempotencyKey);\n const bodyHash = hashBody(request.body);\n\n const cached = (await cacheDriver.get(cacheKey)) as CachedResponse | null;\n\n if (cached) {\n if (cached.bodyHash !== bodyHash) {\n return response.unprocessableEntity({\n error: t(\"http.idempotencyKeyConflict\"),\n errorCode: HttpErrorCodes.IdempotencyKeyConflict,\n });\n }\n\n response.header(\"Idempotent-Replay\", \"true\");\n\n return response.replay({\n status: cached.status,\n body: cached.body,\n contentType: cached.contentType,\n });\n }\n\n response.onSent((sentResponse: Response) => {\n // Don't cache server errors — clients should be able to retry past a 5xx.\n // 4xx are deterministic outcomes of the request, so caching is fine.\n if (sentResponse.statusCode >= 500) return;\n\n const sentContentType = sentResponse.contentType;\n\n cacheDriver.set(\n cacheKey,\n {\n status: sentResponse.statusCode,\n body: sentResponse.parsedBody,\n bodyHash,\n contentType: typeof sentContentType === \"string\" ? sentContentType : undefined,\n },\n ttl,\n );\n });\n };\n}\n"],"mappings":";;;;;;;AA6CA,MAAM,kBAAkB;CAAC;CAAQ;CAAO;CAAS;AAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCzD,SAAgB,sBAAsB,UAA8B,CAAC,GAAe;CAClF,OAAO,OAAO,SAAS,aAAa;EAClC,MAAM,aACJ,QAAQ,cACRA,WAAO,IAAI,+BAA+B,iBAAiB;EAC7D,MAAM,UACJ,QAAQ,WAAWA,WAAO,IAAI,4BAA4B,eAAe;EAC3E,MAAM,MAAM,QAAQ,OAAOA,WAAO,IAAI,wBAAwB,KAAK;EACnE,MAAM,aAAa,QAAQ,UAAUA,WAAO,IAAI,yBAAyB;EAEzE,IAAI,CAAC,QAAQ,SAAS,QAAQ,OAAO,YAAY,CAAC,GAAG;EAErD,MAAM,iBAAiB,QAAQ,OAAO,WAAW,YAAY,CAAC;EAE9D,IAAI,CAAC,gBAAgB;EAErB,IAAI,CAAC,sBAAsB,cAAc,GACvC,OAAO,SAAS,WAAW;GACzB,OAAO,EAAE,4BAA4B;GACrC;EACF,CAAC;EAGH,MAAM,cAAc,aAAa,MAAM,MAAM,IAAI,UAAU,IAAI;EAC/D,MAAM,WAAW,yBAAyB,SAAS,cAAc;EACjE,MAAM,WAAW,SAAS,QAAQ,IAAI;EAEtC,MAAM,SAAU,MAAM,YAAY,IAAI,QAAQ;EAE9C,IAAI,QAAQ;GACV,IAAI,OAAO,aAAa,UACtB,OAAO,SAAS,oBAAoB;IAClC,OAAO,EAAE,6BAA6B;IACtC;GACF,CAAC;GAGH,SAAS,OAAO,qBAAqB,MAAM;GAE3C,OAAO,SAAS,OAAO;IACrB,QAAQ,OAAO;IACf,MAAM,OAAO;IACb,aAAa,OAAO;GACtB,CAAC;EACH;EAEA,SAAS,QAAQ,iBAA2B;GAG1C,IAAI,aAAa,cAAc,KAAK;GAEpC,MAAM,kBAAkB,aAAa;GAErC,YAAY,IACV,UACA;IACE,QAAQ,aAAa;IACrB,MAAM,aAAa;IACnB;IACA,aAAa,OAAO,oBAAoB,WAAW,kBAAkB;GACvE,GACA,GACF;EACF,CAAC;CACH;AACF"}
@@ -2,7 +2,7 @@ import { environment } from "../../utils/environment.mjs";
2
2
  import { requestContext, useRequestStore } from "../context/request-context.mjs";
3
3
  import "../../utils/index.mjs";
4
4
  import { BadRequestError, ForbiddenError, HttpError, ResourceNotFoundError, ServerError, UnAuthorizedError } from "../errors/errors.mjs";
5
- import config from "@mongez/config";
5
+ import baseConfig from "@mongez/config";
6
6
  import { trans } from "@mongez/localization";
7
7
  import { DatabaseWriterValidationError } from "@warlock.js/cascade";
8
8
  import { contextManager } from "@warlock.js/context";
@@ -22,7 +22,7 @@ import { contextManager } from "@warlock.js/context";
22
22
  * Skip when `http.requestId.enabled` is explicitly false.
23
23
  */
24
24
  function stampRequestIdHeader(request, response) {
25
- const requestIdConfig = config.get("http.requestId", {});
25
+ const requestIdConfig = baseConfig.get("http.requestId", {});
26
26
  if (requestIdConfig.enabled === false) return;
27
27
  const headerName = requestIdConfig.header || "X-Request-Id";
28
28
  response.header(headerName, request.id);
@@ -1 +1 @@
1
- {"version":3,"file":"inject-request-context.mjs","names":["requestContextInstance"],"sources":["../../../../../../../@warlock.js/core/src/http/middleware/inject-request-context.ts"],"sourcesContent":["/**\r\n * Request Context Middleware\r\n *\r\n * Creates a unified context for each request using the ContextManager.\r\n * All framework contexts (request, storage, database) are available throughout the request lifecycle.\r\n */\r\nimport { trans } from \"@mongez/localization\";\r\nimport { GenericObject } from \"@mongez/reinforcements\";\r\nimport { DatabaseWriterValidationError } from \"@warlock.js/cascade\";\r\nimport { contextManager } from \"@warlock.js/context\";\r\nimport config from \"@mongez/config\";\r\nimport { environment } from \"../../utils\";\r\nimport {\r\n requestContext as requestContextInstance,\r\n useRequestStore,\r\n} from \"../context/request-context\";\r\nimport {\r\n BadRequestError,\r\n ForbiddenError,\r\n HttpError,\r\n ResourceNotFoundError,\r\n ServerError,\r\n UnAuthorizedError,\r\n} from \"../errors\";\r\nimport { type Request } from \"../request\";\r\nimport { type Response } from \"../response\";\r\nimport { type ReturnedResponse } from \"./../types\";\r\n\r\n// Contexts are now registered in core/context/init-contexts.ts via initializeContexts()\r\n\r\n/**\r\n * Echo `request.id` back as a response header so the FE / proxies / log\r\n * aggregators can correlate by the same value the server logs against.\r\n *\r\n * Reads the header name from `http.requestId.header` (default `X-Request-Id`).\r\n * Skip when `http.requestId.enabled` is explicitly false.\r\n */\r\nfunction stampRequestIdHeader(request: Request, response: Response) {\r\n const requestIdConfig = config.get(\"http.requestId\", {} as Record<string, any>);\r\n\r\n if (requestIdConfig.enabled === false) return;\r\n\r\n const headerName = requestIdConfig.header || \"X-Request-Id\";\r\n\r\n response.header(headerName, request.id);\r\n}\r\n\r\n/**\r\n * Create request store and execute middleware + handler\r\n *\r\n * Runs all registered contexts together using ContextManager.\r\n */\r\nexport function createRequestStore(\r\n request: Request<any>,\r\n response: Response,\r\n): Promise<ReturnedResponse> {\r\n stampRequestIdHeader(request, response);\r\n\r\n // Build all context stores using the immutable API\r\n // Each context defines its own store initialization via buildStore()\r\n const httpContextStore = contextManager.buildStores({ request, response });\r\n\r\n // Run all contexts together!\r\n return contextManager.runAll(httpContextStore, async () => {\r\n try {\r\n // Run middleware chain\r\n const result = await request.runMiddleware();\r\n\r\n if (result) {\r\n return result as ReturnedResponse;\r\n }\r\n\r\n // Execute route handler\r\n request.trigger(\"executingAction\", request.route);\r\n\r\n const handler = request.getHandler();\r\n\r\n request.log(\"Executing Handler\", \"info\");\r\n\r\n const output = await handler(request, response);\r\n\r\n request.log(\"Handler Executed Successfully\", \"success\");\r\n\r\n request.trigger(\"executedAction\", request.route);\r\n\r\n return output as ReturnedResponse;\r\n } catch (error: any) {\r\n request.log(`${error.constructor.name}: Request failed: ${error.message}`, \"error\");\r\n return handleRequestError(error, response);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Handle request errors\r\n * @internal\r\n */\r\nfunction handleRequestError(error: any, response: Response): ReturnedResponse {\r\n if (error instanceof HttpError) {\r\n const payload: GenericObject = {\r\n error: error.message,\r\n };\r\n if (error.payload) {\r\n payload.payload = error.payload;\r\n }\r\n\r\n if (environment() === \"development\") {\r\n payload.stack = error.stack;\r\n }\r\n\r\n return response.setStatusCode(error.status).send(payload);\r\n }\r\n\r\n if (error instanceof ResourceNotFoundError) {\r\n return response.notFound({\r\n error: error.message,\r\n ...error.payload,\r\n });\r\n }\r\n\r\n if (error instanceof UnAuthorizedError) {\r\n return response.unauthorized({\r\n error: error.message,\r\n ...error.payload,\r\n });\r\n }\r\n\r\n if (error instanceof ForbiddenError) {\r\n return response.forbidden({\r\n error: error.message,\r\n ...error.payload,\r\n });\r\n }\r\n\r\n if (error instanceof BadRequestError) {\r\n return response.badRequest({\r\n error: error.message,\r\n ...error.payload,\r\n });\r\n }\r\n\r\n if (error instanceof DatabaseWriterValidationError) {\r\n return response.badRequest({\r\n errors: error.errors,\r\n });\r\n }\r\n\r\n if (error instanceof ServerError) {\r\n return response.serverError({\r\n error: error.message,\r\n ...error.payload,\r\n });\r\n }\r\n\r\n console.log(error);\r\n\r\n return response.badRequest({\r\n error: error.message,\r\n ...error.payload,\r\n });\r\n}\r\n\r\n/**\r\n * Translate a keyword (uses request context for locale)\r\n */\r\nexport function t(keyword: string, placeholders?: any) {\r\n return (\r\n requestContextInstance.getRequest()?.trans(keyword, placeholders) ||\r\n trans(keyword, placeholders)\r\n );\r\n}\r\n\r\n/**\r\n * Get or compute a value from the request cache\r\n *\r\n * If the value exists in request, return it.\r\n * Otherwise, execute callback, store result in request, and return it.\r\n */\r\nexport async function fromRequest<T>(\r\n key: string,\r\n callback: (request?: Request) => Promise<T>,\r\n): Promise<T> {\r\n const { request } = useRequestStore();\r\n\r\n if (!request) return await callback();\r\n\r\n if (request[key]) return request[key];\r\n\r\n request[key] = await callback(request);\r\n\r\n return request[key];\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAS,qBAAqB,SAAkB,UAAoB;CAClE,MAAM,kBAAkB,OAAO,IAAI,kBAAkB,CAAC,CAAwB;CAE9E,IAAI,gBAAgB,YAAY,OAAO;CAEvC,MAAM,aAAa,gBAAgB,UAAU;CAE7C,SAAS,OAAO,YAAY,QAAQ,EAAE;AACxC;;;;;;AAOA,SAAgB,mBACd,SACA,UAC2B;CAC3B,qBAAqB,SAAS,QAAQ;CAItC,MAAM,mBAAmB,eAAe,YAAY;EAAE;EAAS;CAAS,CAAC;CAGzE,OAAO,eAAe,OAAO,kBAAkB,YAAY;EACzD,IAAI;GAEF,MAAM,SAAS,MAAM,QAAQ,cAAc;GAE3C,IAAI,QACF,OAAO;GAIT,QAAQ,QAAQ,mBAAmB,QAAQ,KAAK;GAEhD,MAAM,UAAU,QAAQ,WAAW;GAEnC,QAAQ,IAAI,qBAAqB,MAAM;GAEvC,MAAM,SAAS,MAAM,QAAQ,SAAS,QAAQ;GAE9C,QAAQ,IAAI,iCAAiC,SAAS;GAEtD,QAAQ,QAAQ,kBAAkB,QAAQ,KAAK;GAE/C,OAAO;EACT,SAAS,OAAY;GACnB,QAAQ,IAAI,GAAG,MAAM,YAAY,KAAK,oBAAoB,MAAM,WAAW,OAAO;GAClF,OAAO,mBAAmB,OAAO,QAAQ;EAC3C;CACF,CAAC;AACH;;;;;AAMA,SAAS,mBAAmB,OAAY,UAAsC;CAC5E,IAAI,iBAAiB,WAAW;EAC9B,MAAM,UAAyB,EAC7B,OAAO,MAAM,QACf;EACA,IAAI,MAAM,SACR,QAAQ,UAAU,MAAM;EAG1B,IAAI,YAAY,MAAM,eACpB,QAAQ,QAAQ,MAAM;EAGxB,OAAO,SAAS,cAAc,MAAM,MAAM,EAAE,KAAK,OAAO;CAC1D;CAEA,IAAI,iBAAiB,uBACnB,OAAO,SAAS,SAAS;EACvB,OAAO,MAAM;EACb,GAAG,MAAM;CACX,CAAC;CAGH,IAAI,iBAAiB,mBACnB,OAAO,SAAS,aAAa;EAC3B,OAAO,MAAM;EACb,GAAG,MAAM;CACX,CAAC;CAGH,IAAI,iBAAiB,gBACnB,OAAO,SAAS,UAAU;EACxB,OAAO,MAAM;EACb,GAAG,MAAM;CACX,CAAC;CAGH,IAAI,iBAAiB,iBACnB,OAAO,SAAS,WAAW;EACzB,OAAO,MAAM;EACb,GAAG,MAAM;CACX,CAAC;CAGH,IAAI,iBAAiB,+BACnB,OAAO,SAAS,WAAW,EACzB,QAAQ,MAAM,OAChB,CAAC;CAGH,IAAI,iBAAiB,aACnB,OAAO,SAAS,YAAY;EAC1B,OAAO,MAAM;EACb,GAAG,MAAM;CACX,CAAC;CAGH,QAAQ,IAAI,KAAK;CAEjB,OAAO,SAAS,WAAW;EACzB,OAAO,MAAM;EACb,GAAG,MAAM;CACX,CAAC;AACH;;;;AAKA,SAAgB,EAAE,SAAiB,cAAoB;CACrD,OACEA,eAAuB,WAAW,GAAG,MAAM,SAAS,YAAY,KAChE,MAAM,SAAS,YAAY;AAE/B;;;;;;;AAQA,eAAsB,YACpB,KACA,UACY;CACZ,MAAM,EAAE,YAAY,gBAAgB;CAEpC,IAAI,CAAC,SAAS,OAAO,MAAM,SAAS;CAEpC,IAAI,QAAQ,MAAM,OAAO,QAAQ;CAEjC,QAAQ,OAAO,MAAM,SAAS,OAAO;CAErC,OAAO,QAAQ;AACjB"}
1
+ {"version":3,"file":"inject-request-context.mjs","names":["config","requestContextInstance"],"sources":["../../../../../../../@warlock.js/core/src/http/middleware/inject-request-context.ts"],"sourcesContent":["/**\r\n * Request Context Middleware\r\n *\r\n * Creates a unified context for each request using the ContextManager.\r\n * All framework contexts (request, storage, database) are available throughout the request lifecycle.\r\n */\r\nimport { trans } from \"@mongez/localization\";\r\nimport { GenericObject } from \"@mongez/reinforcements\";\r\nimport { DatabaseWriterValidationError } from \"@warlock.js/cascade\";\r\nimport { contextManager } from \"@warlock.js/context\";\r\nimport config from \"@mongez/config\";\r\nimport { environment } from \"../../utils\";\r\nimport {\r\n requestContext as requestContextInstance,\r\n useRequestStore,\r\n} from \"../context/request-context\";\r\nimport {\r\n BadRequestError,\r\n ForbiddenError,\r\n HttpError,\r\n ResourceNotFoundError,\r\n ServerError,\r\n UnAuthorizedError,\r\n} from \"../errors\";\r\nimport { type Request } from \"../request\";\r\nimport { type Response } from \"../response\";\r\nimport { type ReturnedResponse } from \"./../types\";\r\n\r\n// Contexts are now registered in core/context/init-contexts.ts via initializeContexts()\r\n\r\n/**\r\n * Echo `request.id` back as a response header so the FE / proxies / log\r\n * aggregators can correlate by the same value the server logs against.\r\n *\r\n * Reads the header name from `http.requestId.header` (default `X-Request-Id`).\r\n * Skip when `http.requestId.enabled` is explicitly false.\r\n */\r\nfunction stampRequestIdHeader(request: Request, response: Response) {\r\n const requestIdConfig = config.get(\"http.requestId\", {} as Record<string, any>);\r\n\r\n if (requestIdConfig.enabled === false) return;\r\n\r\n const headerName = requestIdConfig.header || \"X-Request-Id\";\r\n\r\n response.header(headerName, request.id);\r\n}\r\n\r\n/**\r\n * Create request store and execute middleware + handler\r\n *\r\n * Runs all registered contexts together using ContextManager.\r\n */\r\nexport function createRequestStore(\r\n request: Request<any>,\r\n response: Response,\r\n): Promise<ReturnedResponse> {\r\n stampRequestIdHeader(request, response);\r\n\r\n // Build all context stores using the immutable API\r\n // Each context defines its own store initialization via buildStore()\r\n const httpContextStore = contextManager.buildStores({ request, response });\r\n\r\n // Run all contexts together!\r\n return contextManager.runAll(httpContextStore, async () => {\r\n try {\r\n // Run middleware chain\r\n const result = await request.runMiddleware();\r\n\r\n if (result) {\r\n return result as ReturnedResponse;\r\n }\r\n\r\n // Execute route handler\r\n request.trigger(\"executingAction\", request.route);\r\n\r\n const handler = request.getHandler();\r\n\r\n request.log(\"Executing Handler\", \"info\");\r\n\r\n const output = await handler(request, response);\r\n\r\n request.log(\"Handler Executed Successfully\", \"success\");\r\n\r\n request.trigger(\"executedAction\", request.route);\r\n\r\n return output as ReturnedResponse;\r\n } catch (error: any) {\r\n request.log(`${error.constructor.name}: Request failed: ${error.message}`, \"error\");\r\n return handleRequestError(error, response);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Handle request errors\r\n * @internal\r\n */\r\nfunction handleRequestError(error: any, response: Response): ReturnedResponse {\r\n if (error instanceof HttpError) {\r\n const payload: GenericObject = {\r\n error: error.message,\r\n };\r\n if (error.payload) {\r\n payload.payload = error.payload;\r\n }\r\n\r\n if (environment() === \"development\") {\r\n payload.stack = error.stack;\r\n }\r\n\r\n return response.setStatusCode(error.status).send(payload);\r\n }\r\n\r\n if (error instanceof ResourceNotFoundError) {\r\n return response.notFound({\r\n error: error.message,\r\n ...error.payload,\r\n });\r\n }\r\n\r\n if (error instanceof UnAuthorizedError) {\r\n return response.unauthorized({\r\n error: error.message,\r\n ...error.payload,\r\n });\r\n }\r\n\r\n if (error instanceof ForbiddenError) {\r\n return response.forbidden({\r\n error: error.message,\r\n ...error.payload,\r\n });\r\n }\r\n\r\n if (error instanceof BadRequestError) {\r\n return response.badRequest({\r\n error: error.message,\r\n ...error.payload,\r\n });\r\n }\r\n\r\n if (error instanceof DatabaseWriterValidationError) {\r\n return response.badRequest({\r\n errors: error.errors,\r\n });\r\n }\r\n\r\n if (error instanceof ServerError) {\r\n return response.serverError({\r\n error: error.message,\r\n ...error.payload,\r\n });\r\n }\r\n\r\n console.log(error);\r\n\r\n return response.badRequest({\r\n error: error.message,\r\n ...error.payload,\r\n });\r\n}\r\n\r\n/**\r\n * Translate a keyword (uses request context for locale)\r\n */\r\nexport function t(keyword: string, placeholders?: any) {\r\n return (\r\n requestContextInstance.getRequest()?.trans(keyword, placeholders) ||\r\n trans(keyword, placeholders)\r\n );\r\n}\r\n\r\n/**\r\n * Get or compute a value from the request cache\r\n *\r\n * If the value exists in request, return it.\r\n * Otherwise, execute callback, store result in request, and return it.\r\n */\r\nexport async function fromRequest<T>(\r\n key: string,\r\n callback: (request?: Request) => Promise<T>,\r\n): Promise<T> {\r\n const { request } = useRequestStore();\r\n\r\n if (!request) return await callback();\r\n\r\n if (request[key]) return request[key];\r\n\r\n request[key] = await callback(request);\r\n\r\n return request[key];\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAS,qBAAqB,SAAkB,UAAoB;CAClE,MAAM,kBAAkBA,WAAO,IAAI,kBAAkB,CAAC,CAAwB;CAE9E,IAAI,gBAAgB,YAAY,OAAO;CAEvC,MAAM,aAAa,gBAAgB,UAAU;CAE7C,SAAS,OAAO,YAAY,QAAQ,EAAE;AACxC;;;;;;AAOA,SAAgB,mBACd,SACA,UAC2B;CAC3B,qBAAqB,SAAS,QAAQ;CAItC,MAAM,mBAAmB,eAAe,YAAY;EAAE;EAAS;CAAS,CAAC;CAGzE,OAAO,eAAe,OAAO,kBAAkB,YAAY;EACzD,IAAI;GAEF,MAAM,SAAS,MAAM,QAAQ,cAAc;GAE3C,IAAI,QACF,OAAO;GAIT,QAAQ,QAAQ,mBAAmB,QAAQ,KAAK;GAEhD,MAAM,UAAU,QAAQ,WAAW;GAEnC,QAAQ,IAAI,qBAAqB,MAAM;GAEvC,MAAM,SAAS,MAAM,QAAQ,SAAS,QAAQ;GAE9C,QAAQ,IAAI,iCAAiC,SAAS;GAEtD,QAAQ,QAAQ,kBAAkB,QAAQ,KAAK;GAE/C,OAAO;EACT,SAAS,OAAY;GACnB,QAAQ,IAAI,GAAG,MAAM,YAAY,KAAK,oBAAoB,MAAM,WAAW,OAAO;GAClF,OAAO,mBAAmB,OAAO,QAAQ;EAC3C;CACF,CAAC;AACH;;;;;AAMA,SAAS,mBAAmB,OAAY,UAAsC;CAC5E,IAAI,iBAAiB,WAAW;EAC9B,MAAM,UAAyB,EAC7B,OAAO,MAAM,QACf;EACA,IAAI,MAAM,SACR,QAAQ,UAAU,MAAM;EAG1B,IAAI,YAAY,MAAM,eACpB,QAAQ,QAAQ,MAAM;EAGxB,OAAO,SAAS,cAAc,MAAM,MAAM,EAAE,KAAK,OAAO;CAC1D;CAEA,IAAI,iBAAiB,uBACnB,OAAO,SAAS,SAAS;EACvB,OAAO,MAAM;EACb,GAAG,MAAM;CACX,CAAC;CAGH,IAAI,iBAAiB,mBACnB,OAAO,SAAS,aAAa;EAC3B,OAAO,MAAM;EACb,GAAG,MAAM;CACX,CAAC;CAGH,IAAI,iBAAiB,gBACnB,OAAO,SAAS,UAAU;EACxB,OAAO,MAAM;EACb,GAAG,MAAM;CACX,CAAC;CAGH,IAAI,iBAAiB,iBACnB,OAAO,SAAS,WAAW;EACzB,OAAO,MAAM;EACb,GAAG,MAAM;CACX,CAAC;CAGH,IAAI,iBAAiB,+BACnB,OAAO,SAAS,WAAW,EACzB,QAAQ,MAAM,OAChB,CAAC;CAGH,IAAI,iBAAiB,aACnB,OAAO,SAAS,YAAY;EAC1B,OAAO,MAAM;EACb,GAAG,MAAM;CACX,CAAC;CAGH,QAAQ,IAAI,KAAK;CAEjB,OAAO,SAAS,WAAW;EACzB,OAAO,MAAM;EACb,GAAG,MAAM;CACX,CAAC;AACH;;;;AAKA,SAAgB,EAAE,SAAiB,cAAoB;CACrD,OACEC,eAAuB,WAAW,GAAG,MAAM,SAAS,YAAY,KAChE,MAAM,SAAS,YAAY;AAE/B;;;;;;;AAQA,eAAsB,YACpB,KACA,UACY;CACZ,MAAM,EAAE,YAAY,gBAAgB;CAEpC,IAAI,CAAC,SAAS,OAAO,MAAM,SAAS;CAEpC,IAAI,QAAQ,MAAM,OAAO,QAAQ;CAEjC,QAAQ,OAAO,MAAM,SAAS,OAAO;CAErC,OAAO,QAAQ;AACjB"}
@@ -1,6 +1,6 @@
1
1
  import { t } from "./inject-request-context.mjs";
2
2
  import { HttpErrorCodes } from "../error-codes.mjs";
3
- import config from "@mongez/config";
3
+ import baseConfig from "@mongez/config";
4
4
 
5
5
  //#region ../../@warlock.js/core/src/http/middleware/maintenance.middleware.ts
6
6
  function isAllowlisted(path, patterns) {
@@ -31,10 +31,10 @@ function isAllowlisted(path, patterns) {
31
31
  */
32
32
  function maintenanceMiddleware(options = {}) {
33
33
  return (request, response) => {
34
- if (!config.get("http.maintenance.enabled", false)) return;
35
- const allowlist = options.allowlist || config.get("http.maintenance.allowlist", ["/health"]);
34
+ if (!baseConfig.get("http.maintenance.enabled", false)) return;
35
+ const allowlist = options.allowlist || baseConfig.get("http.maintenance.allowlist", ["/health"]);
36
36
  if (isAllowlisted(request.path, allowlist)) return;
37
- const retryAfter = options.retryAfter || config.get("http.maintenance.retryAfter", 60);
37
+ const retryAfter = options.retryAfter || baseConfig.get("http.maintenance.retryAfter", 60);
38
38
  response.header("Retry-After", retryAfter);
39
39
  return response.serviceUnavailable({
40
40
  error: options.errorMessage || t("http.maintenance"),
@@ -1 +1 @@
1
- {"version":3,"file":"maintenance.middleware.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/http/middleware/maintenance.middleware.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport type { Middleware } from \"../../router\";\nimport { HttpErrorCodes } from \"../error-codes\";\nimport { t } from \"./inject-request-context\";\n\n/**\n * Options for the maintenance middleware.\n */\nexport type MaintenanceOptions = {\n /**\n * Path prefixes (ending in `*`) or exact paths to bypass even when\n * maintenance is on. Falls back to `http.maintenance.allowlist`, then\n * `[\"/health\"]`.\n *\n * @example\n * allowlist: [\"/health\", \"/admin/*\", \"/webhooks/stripe\"]\n */\n allowlist?: string[];\n /**\n * Seconds advertised in the `Retry-After` header. Falls back to\n * `http.maintenance.retryAfter`, then `60`.\n */\n retryAfter?: number;\n /**\n * Override the default error message.\n */\n errorMessage?: string;\n};\n\nfunction isAllowlisted(path: string, patterns: string[]) {\n return patterns.some((pattern) => {\n if (pattern.endsWith(\"*\")) {\n return path.startsWith(pattern.slice(0, -1));\n }\n\n return path === pattern;\n });\n}\n\n/**\n * Return 503 + `Retry-After` for every request when `http.maintenance.enabled`\n * is true, except for paths matching the allowlist.\n *\n * Designed for app-wide registration via `http.middleware.all`. Toggled via\n * config — flipping the flag requires a restart (no runtime hot-flip yet).\n * Allowlist defaults to `[\"/health\"]` so health checks still pass during\n * planned downtime.\n *\n * @example\n * // src/config/http.ts\n * import { middleware } from \"@warlock.js/core\";\n *\n * export default {\n * maintenance: { enabled: env(\"MAINTENANCE_MODE\") === \"true\" },\n * middleware: {\n * all: [middleware.maintenance({ allowlist: [\"/health\", \"/admin/*\"] })],\n * },\n * };\n */\nexport function maintenanceMiddleware(options: MaintenanceOptions = {}): Middleware {\n return (request, response) => {\n const enabled = config.get(\"http.maintenance.enabled\", false);\n\n if (!enabled) return;\n\n const allowlist =\n options.allowlist || config.get(\"http.maintenance.allowlist\", [\"/health\"]);\n\n if (isAllowlisted(request.path, allowlist)) return;\n\n const retryAfter =\n options.retryAfter || config.get(\"http.maintenance.retryAfter\", 60);\n\n response.header(\"Retry-After\", retryAfter);\n\n return response.serviceUnavailable({\n error: options.errorMessage || t(\"http.maintenance\"),\n errorCode: HttpErrorCodes.Maintenance,\n });\n };\n}\n"],"mappings":";;;;;AA6BA,SAAS,cAAc,MAAc,UAAoB;CACvD,OAAO,SAAS,MAAM,YAAY;EAChC,IAAI,QAAQ,SAAS,GAAG,GACtB,OAAO,KAAK,WAAW,QAAQ,MAAM,GAAG,EAAE,CAAC;EAG7C,OAAO,SAAS;CAClB,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,sBAAsB,UAA8B,CAAC,GAAe;CAClF,QAAQ,SAAS,aAAa;EAG5B,IAAI,CAFY,OAAO,IAAI,4BAA4B,KAE5C,GAAG;EAEd,MAAM,YACJ,QAAQ,aAAa,OAAO,IAAI,8BAA8B,CAAC,SAAS,CAAC;EAE3E,IAAI,cAAc,QAAQ,MAAM,SAAS,GAAG;EAE5C,MAAM,aACJ,QAAQ,cAAc,OAAO,IAAI,+BAA+B,EAAE;EAEpE,SAAS,OAAO,eAAe,UAAU;EAEzC,OAAO,SAAS,mBAAmB;GACjC,OAAO,QAAQ,gBAAgB,EAAE,kBAAkB;GACnD;EACF,CAAC;CACH;AACF"}
1
+ {"version":3,"file":"maintenance.middleware.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/http/middleware/maintenance.middleware.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport type { Middleware } from \"../../router\";\nimport { HttpErrorCodes } from \"../error-codes\";\nimport { t } from \"./inject-request-context\";\n\n/**\n * Options for the maintenance middleware.\n */\nexport type MaintenanceOptions = {\n /**\n * Path prefixes (ending in `*`) or exact paths to bypass even when\n * maintenance is on. Falls back to `http.maintenance.allowlist`, then\n * `[\"/health\"]`.\n *\n * @example\n * allowlist: [\"/health\", \"/admin/*\", \"/webhooks/stripe\"]\n */\n allowlist?: string[];\n /**\n * Seconds advertised in the `Retry-After` header. Falls back to\n * `http.maintenance.retryAfter`, then `60`.\n */\n retryAfter?: number;\n /**\n * Override the default error message.\n */\n errorMessage?: string;\n};\n\nfunction isAllowlisted(path: string, patterns: string[]) {\n return patterns.some((pattern) => {\n if (pattern.endsWith(\"*\")) {\n return path.startsWith(pattern.slice(0, -1));\n }\n\n return path === pattern;\n });\n}\n\n/**\n * Return 503 + `Retry-After` for every request when `http.maintenance.enabled`\n * is true, except for paths matching the allowlist.\n *\n * Designed for app-wide registration via `http.middleware.all`. Toggled via\n * config — flipping the flag requires a restart (no runtime hot-flip yet).\n * Allowlist defaults to `[\"/health\"]` so health checks still pass during\n * planned downtime.\n *\n * @example\n * // src/config/http.ts\n * import { middleware } from \"@warlock.js/core\";\n *\n * export default {\n * maintenance: { enabled: env(\"MAINTENANCE_MODE\") === \"true\" },\n * middleware: {\n * all: [middleware.maintenance({ allowlist: [\"/health\", \"/admin/*\"] })],\n * },\n * };\n */\nexport function maintenanceMiddleware(options: MaintenanceOptions = {}): Middleware {\n return (request, response) => {\n const enabled = config.get(\"http.maintenance.enabled\", false);\n\n if (!enabled) return;\n\n const allowlist =\n options.allowlist || config.get(\"http.maintenance.allowlist\", [\"/health\"]);\n\n if (isAllowlisted(request.path, allowlist)) return;\n\n const retryAfter =\n options.retryAfter || config.get(\"http.maintenance.retryAfter\", 60);\n\n response.header(\"Retry-After\", retryAfter);\n\n return response.serviceUnavailable({\n error: options.errorMessage || t(\"http.maintenance\"),\n errorCode: HttpErrorCodes.Maintenance,\n });\n };\n}\n"],"mappings":";;;;;AA6BA,SAAS,cAAc,MAAc,UAAoB;CACvD,OAAO,SAAS,MAAM,YAAY;EAChC,IAAI,QAAQ,SAAS,GAAG,GACtB,OAAO,KAAK,WAAW,QAAQ,MAAM,GAAG,EAAE,CAAC;EAG7C,OAAO,SAAS;CAClB,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,sBAAsB,UAA8B,CAAC,GAAe;CAClF,QAAQ,SAAS,aAAa;EAG5B,IAAI,CAFYA,WAAO,IAAI,4BAA4B,KAE5C,GAAG;EAEd,MAAM,YACJ,QAAQ,aAAaA,WAAO,IAAI,8BAA8B,CAAC,SAAS,CAAC;EAE3E,IAAI,cAAc,QAAQ,MAAM,SAAS,GAAG;EAE5C,MAAM,aACJ,QAAQ,cAAcA,WAAO,IAAI,+BAA+B,EAAE;EAEpE,SAAS,OAAO,eAAe,UAAU;EAEzC,OAAO,SAAS,mBAAmB;GACjC,OAAO,QAAQ,gBAAgB,EAAE,kBAAkB;GACnD;EACF,CAAC;CACH;AACF"}
@@ -1,6 +1,6 @@
1
1
  import { rootPath } from "../utils/paths.mjs";
2
2
  import "../utils/index.mjs";
3
- import config from "@mongez/config";
3
+ import baseConfig from "@mongez/config";
4
4
  import fastifyMultipart from "@fastify/multipart";
5
5
 
6
6
  //#region ../../@warlock.js/core/src/http/plugins.ts
@@ -10,25 +10,25 @@ const defaultCorsOptions = {
10
10
  };
11
11
  async function registerHttpPlugins(server) {
12
12
  server.register(import("@fastify/rate-limit"), {
13
- max: config.get("http.rateLimit.max", 60),
14
- timeWindow: config.get("http.rateLimit.duration", 60 * 1e3)
13
+ max: baseConfig.get("http.rateLimit.max", 60),
14
+ timeWindow: baseConfig.get("http.rateLimit.duration", 60 * 1e3)
15
15
  });
16
16
  const corsOptions = {
17
- ...config.get("http.cors", {}),
17
+ ...baseConfig.get("http.cors", {}),
18
18
  ...defaultCorsOptions
19
19
  };
20
20
  server.register(import("@fastify/cors"), corsOptions);
21
21
  server.register(fastifyMultipart, {
22
22
  attachFieldsToBody: true,
23
- limits: { fileSize: config.get("http.fileUploadLimit", 10 * 1024 * 1024) }
23
+ limits: { fileSize: baseConfig.get("http.fileUploadLimit", 10 * 1024 * 1024) }
24
24
  });
25
25
  server.register(import("@fastify/static"), {
26
- root: config.get("storage.publicRoot", rootPath("public")),
27
- prefix: config.get("storage.publicPrefix", "/public/")
26
+ root: baseConfig.get("storage.publicRoot", rootPath("public")),
27
+ prefix: baseConfig.get("storage.publicPrefix", "/public/")
28
28
  });
29
29
  server.register(import("@fastify/cookie"), {
30
- secret: config.get("http.cookies.secret"),
31
- parseOptions: config.get("http.cookies.options", {})
30
+ secret: baseConfig.get("http.cookies.secret"),
31
+ parseOptions: baseConfig.get("http.cookies.options", {})
32
32
  });
33
33
  }
34
34
 
@@ -1 +1 @@
1
- {"version":3,"file":"plugins.mjs","names":[],"sources":["../../../../../../@warlock.js/core/src/http/plugins.ts"],"sourcesContent":["import type { FastifyCorsOptions } from \"@fastify/cors\";\nimport fastifyMultipart from \"@fastify/multipart\";\nimport config from \"@mongez/config\";\nimport { rootPath } from \"../utils\";\nimport type { FastifyInstance } from \"./server\";\n\nconst defaultCorsOptions: FastifyCorsOptions = {\n origin: \"*\",\n methods: \"*\",\n};\n\nexport async function registerHttpPlugins(server: FastifyInstance) {\n // 👇🏻 register rate-limit plugin\n server.register(import(\"@fastify/rate-limit\"), {\n // max requests per time window\n max: config.get(\"http.rateLimit.max\", 60),\n // maximum time that is will allow max requests\n timeWindow: config.get(\"http.rateLimit.duration\", 60 * 1000),\n });\n\n // 👇🏻 register cors plugin\n const corsOptions: FastifyCorsOptions | undefined = {\n ...config.get(\"http.cors\", {}),\n ...defaultCorsOptions,\n };\n\n server.register(import(\"@fastify/cors\"), corsOptions);\n\n // 👇🏻 import multipart plugin\n server.register(fastifyMultipart, {\n attachFieldsToBody: true,\n limits: {\n // file size could be up to 10MB\n fileSize: config.get(\"http.fileUploadLimit\", 10 * 1024 * 1024),\n },\n });\n\n server.register(import(\"@fastify/static\"), {\n root: config.get(\"storage.publicRoot\", rootPath(\"public\")),\n prefix: config.get(\"storage.publicPrefix\", \"/public/\"),\n });\n\n // 👇🏻 register cookie plugin\n server.register(import(\"@fastify/cookie\"), {\n secret: config.get(\"http.cookies.secret\"), // Optional: allow signed cookies\n parseOptions: config.get(\"http.cookies.options\", {}),\n });\n}\n"],"mappings":";;;;;;AAMA,MAAM,qBAAyC;CAC7C,QAAQ;CACR,SAAS;AACX;AAEA,eAAsB,oBAAoB,QAAyB;CAEjE,OAAO,SAAS,OAAO,wBAAwB;EAE7C,KAAK,OAAO,IAAI,sBAAsB,EAAE;EAExC,YAAY,OAAO,IAAI,2BAA2B,KAAK,GAAI;CAC7D,CAAC;CAGD,MAAM,cAA8C;EAClD,GAAG,OAAO,IAAI,aAAa,CAAC,CAAC;EAC7B,GAAG;CACL;CAEA,OAAO,SAAS,OAAO,kBAAkB,WAAW;CAGpD,OAAO,SAAS,kBAAkB;EAChC,oBAAoB;EACpB,QAAQ,EAEN,UAAU,OAAO,IAAI,wBAAwB,KAAK,OAAO,IAAI,EAC/D;CACF,CAAC;CAED,OAAO,SAAS,OAAO,oBAAoB;EACzC,MAAM,OAAO,IAAI,sBAAsB,SAAS,QAAQ,CAAC;EACzD,QAAQ,OAAO,IAAI,wBAAwB,UAAU;CACvD,CAAC;CAGD,OAAO,SAAS,OAAO,oBAAoB;EACzC,QAAQ,OAAO,IAAI,qBAAqB;EACxC,cAAc,OAAO,IAAI,wBAAwB,CAAC,CAAC;CACrD,CAAC;AACH"}
1
+ {"version":3,"file":"plugins.mjs","names":["config"],"sources":["../../../../../../@warlock.js/core/src/http/plugins.ts"],"sourcesContent":["import type { FastifyCorsOptions } from \"@fastify/cors\";\nimport fastifyMultipart from \"@fastify/multipart\";\nimport config from \"@mongez/config\";\nimport { rootPath } from \"../utils\";\nimport type { FastifyInstance } from \"./server\";\n\nconst defaultCorsOptions: FastifyCorsOptions = {\n origin: \"*\",\n methods: \"*\",\n};\n\nexport async function registerHttpPlugins(server: FastifyInstance) {\n // 👇🏻 register rate-limit plugin\n server.register(import(\"@fastify/rate-limit\"), {\n // max requests per time window\n max: config.get(\"http.rateLimit.max\", 60),\n // maximum time that is will allow max requests\n timeWindow: config.get(\"http.rateLimit.duration\", 60 * 1000),\n });\n\n // 👇🏻 register cors plugin\n const corsOptions: FastifyCorsOptions | undefined = {\n ...config.get(\"http.cors\", {}),\n ...defaultCorsOptions,\n };\n\n server.register(import(\"@fastify/cors\"), corsOptions);\n\n // 👇🏻 import multipart plugin\n server.register(fastifyMultipart, {\n attachFieldsToBody: true,\n limits: {\n // file size could be up to 10MB\n fileSize: config.get(\"http.fileUploadLimit\", 10 * 1024 * 1024),\n },\n });\n\n server.register(import(\"@fastify/static\"), {\n root: config.get(\"storage.publicRoot\", rootPath(\"public\")),\n prefix: config.get(\"storage.publicPrefix\", \"/public/\"),\n });\n\n // 👇🏻 register cookie plugin\n server.register(import(\"@fastify/cookie\"), {\n secret: config.get(\"http.cookies.secret\"), // Optional: allow signed cookies\n parseOptions: config.get(\"http.cookies.options\", {}),\n });\n}\n"],"mappings":";;;;;;AAMA,MAAM,qBAAyC;CAC7C,QAAQ;CACR,SAAS;AACX;AAEA,eAAsB,oBAAoB,QAAyB;CAEjE,OAAO,SAAS,OAAO,wBAAwB;EAE7C,KAAKA,WAAO,IAAI,sBAAsB,EAAE;EAExC,YAAYA,WAAO,IAAI,2BAA2B,KAAK,GAAI;CAC7D,CAAC;CAGD,MAAM,cAA8C;EAClD,GAAGA,WAAO,IAAI,aAAa,CAAC,CAAC;EAC7B,GAAG;CACL;CAEA,OAAO,SAAS,OAAO,kBAAkB,WAAW;CAGpD,OAAO,SAAS,kBAAkB;EAChC,oBAAoB;EACpB,QAAQ,EAEN,UAAUA,WAAO,IAAI,wBAAwB,KAAK,OAAO,IAAI,EAC/D;CACF,CAAC;CAED,OAAO,SAAS,OAAO,oBAAoB;EACzC,MAAMA,WAAO,IAAI,sBAAsB,SAAS,QAAQ,CAAC;EACzD,QAAQA,WAAO,IAAI,wBAAwB,UAAU;CACvD,CAAC;CAGD,OAAO,SAAS,OAAO,oBAAoB;EACzC,QAAQA,WAAO,IAAI,qBAAqB;EACxC,cAAcA,WAAO,IAAI,wBAAwB,CAAC,CAAC;CACrD,CAAC;AACH"}
@@ -1,7 +1,7 @@
1
1
  import { StorageFile } from "../storage/storage-file.mjs";
2
2
  import "../storage/index.mjs";
3
3
  import { renderReact } from "../react/index.mjs";
4
- import config from "@mongez/config";
4
+ import baseConfig from "@mongez/config";
5
5
  import { log } from "@warlock.js/logger";
6
6
  import path from "path";
7
7
  import { isIterable, isPlainObject, isScalar } from "@mongez/supportive-is";
@@ -175,7 +175,7 @@ var Response = class Response {
175
175
  * Make a log message
176
176
  */
177
177
  log(message, level = "info") {
178
- if (!config.get("http.log")) return;
178
+ if (!baseConfig.get("http.log")) return;
179
179
  log.log({
180
180
  module: "response",
181
181
  action: this.route.method + " " + this.route.path.replace("/*", "") + `:${this.request.id}`,
@@ -561,7 +561,7 @@ var Response = class Response {
561
561
  */
562
562
  cookie(name, value, options = {}) {
563
563
  const { raw, ...cookieOptions } = options;
564
- const defaultOptions = config.get("http.cookies.options", {});
564
+ const defaultOptions = baseConfig.get("http.cookies.options", {});
565
565
  const serializedValue = raw ? String(value) : JSON.stringify(value);
566
566
  this.baseResponse.setCookie(name, serializedValue, {
567
567
  ...defaultOptions,
@@ -576,7 +576,7 @@ var Response = class Response {
576
576
  * response.clearCookie('token', { path: '/' });
577
577
  */
578
578
  clearCookie(name, options) {
579
- const defaultOptions = config.get("http.cookies.options", {});
579
+ const defaultOptions = baseConfig.get("http.cookies.options", {});
580
580
  this.baseResponse.clearCookie(name, {
581
581
  ...defaultOptions,
582
582
  ...options
@@ -832,7 +832,7 @@ var Response = class Response {
832
832
  * Mark the response as failed
833
833
  */
834
834
  failedSchema(result) {
835
- const { errors, inputKey, inputError, status } = config.get("validation.response", {
835
+ const { errors, inputKey, inputError, status } = baseConfig.get("validation.response", {
836
836
  errors: "errors",
837
837
  inputKey: "input",
838
838
  inputError: "error",