@warlock.js/core 4.2.11 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/esm/application/application.d.mts +126 -4
  3. package/esm/application/application.d.mts.map +1 -1
  4. package/esm/application/application.mjs +133 -0
  5. package/esm/application/application.mjs.map +1 -1
  6. package/esm/application/index.d.mts +1 -1
  7. package/esm/cli/commands/dev-server.command.mjs +4 -2
  8. package/esm/cli/commands/dev-server.command.mjs.map +1 -1
  9. package/esm/cli/commands/update.command.mjs +20 -0
  10. package/esm/cli/commands/update.command.mjs.map +1 -0
  11. package/esm/cli/framework-cli-commands.mjs +2 -0
  12. package/esm/cli/framework-cli-commands.mjs.map +1 -1
  13. package/esm/cli/types.d.mts +2 -1
  14. package/esm/cli/types.d.mts.map +1 -1
  15. package/esm/config/config-getter.mjs +5 -5
  16. package/esm/config/config-getter.mjs.map +1 -1
  17. package/esm/config/config-loader.mjs +2 -2
  18. package/esm/config/config-loader.mjs.map +1 -1
  19. package/esm/connectors/access-connector.mjs +2 -2
  20. package/esm/connectors/access-connector.mjs.map +1 -1
  21. package/esm/connectors/cache-connector.mjs +2 -2
  22. package/esm/connectors/cache-connector.mjs.map +1 -1
  23. package/esm/connectors/connectors-manager.d.mts.map +1 -1
  24. package/esm/connectors/connectors-manager.mjs +4 -1
  25. package/esm/connectors/connectors-manager.mjs.map +1 -1
  26. package/esm/connectors/database-connector.mjs +2 -2
  27. package/esm/connectors/database-connector.mjs.map +1 -1
  28. package/esm/connectors/herald-connector.mjs +2 -2
  29. package/esm/connectors/herald-connector.mjs.map +1 -1
  30. package/esm/connectors/http-connector.d.mts +8 -0
  31. package/esm/connectors/http-connector.d.mts.map +1 -1
  32. package/esm/connectors/http-connector.mjs +40 -7
  33. package/esm/connectors/http-connector.mjs.map +1 -1
  34. package/esm/connectors/logger-connector.mjs +2 -2
  35. package/esm/connectors/logger-connector.mjs.map +1 -1
  36. package/esm/connectors/mail-connector.mjs +2 -2
  37. package/esm/connectors/mail-connector.mjs.map +1 -1
  38. package/esm/connectors/notifications-connector.mjs +2 -2
  39. package/esm/connectors/notifications-connector.mjs.map +1 -1
  40. package/esm/connectors/socket-connector.mjs +3 -3
  41. package/esm/connectors/socket-connector.mjs.map +1 -1
  42. package/esm/dev-server/check-for-updates.mjs +59 -0
  43. package/esm/dev-server/check-for-updates.mjs.map +1 -0
  44. package/esm/dev-server/development-server.mjs +7 -0
  45. package/esm/dev-server/development-server.mjs.map +1 -1
  46. package/esm/dev-server/loader/transpile-cache.mjs +1 -1
  47. package/esm/http/config.mjs +2 -2
  48. package/esm/http/config.mjs.map +1 -1
  49. package/esm/http/createHttpApplication.mjs +2 -2
  50. package/esm/http/createHttpApplication.mjs.map +1 -1
  51. package/esm/http/health.d.mts +57 -0
  52. package/esm/http/health.d.mts.map +1 -0
  53. package/esm/http/health.mjs +75 -0
  54. package/esm/http/health.mjs.map +1 -0
  55. package/esm/http/index.d.mts +2 -1
  56. package/esm/http/index.mjs +2 -1
  57. package/esm/http/middleware/idempotency.middleware.mjs +5 -5
  58. package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
  59. package/esm/http/middleware/inject-request-context.mjs +2 -2
  60. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  61. package/esm/http/middleware/maintenance.middleware.mjs +4 -4
  62. package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
  63. package/esm/http/plugins.mjs +9 -9
  64. package/esm/http/plugins.mjs.map +1 -1
  65. package/esm/http/response.mjs +5 -5
  66. package/esm/http/response.mjs.map +1 -1
  67. package/esm/http/server.d.mts +16 -1
  68. package/esm/http/server.d.mts.map +1 -1
  69. package/esm/http/server.mjs +23 -3
  70. package/esm/http/server.mjs.map +1 -1
  71. package/esm/http/types.d.mts +45 -0
  72. package/esm/http/types.d.mts.map +1 -1
  73. package/esm/index.d.mts +7 -4
  74. package/esm/index.mjs +8 -5
  75. package/esm/production/production-builder.mjs +2 -2
  76. package/esm/production/production-builder.mjs.map +1 -1
  77. package/esm/updater/package-manager.mjs +32 -0
  78. package/esm/updater/package-manager.mjs.map +1 -0
  79. package/esm/updater/update-warlock-packages.mjs +134 -0
  80. package/esm/updater/update-warlock-packages.mjs.map +1 -0
  81. package/esm/utils/environment.d.mts +6 -1
  82. package/esm/utils/environment.d.mts.map +1 -1
  83. package/esm/utils/environment.mjs.map +1 -1
  84. package/esm/utils/index.d.mts +4 -2
  85. package/esm/utils/index.mjs +2 -0
  86. package/esm/utils/npm-registry.d.mts +24 -0
  87. package/esm/utils/npm-registry.d.mts.map +1 -0
  88. package/esm/utils/npm-registry.mjs +43 -0
  89. package/esm/utils/npm-registry.mjs.map +1 -0
  90. package/esm/utils/paths.mjs +2 -2
  91. package/esm/utils/paths.mjs.map +1 -1
  92. package/esm/utils/version-compare.d.mts +20 -0
  93. package/esm/utils/version-compare.d.mts.map +1 -0
  94. package/esm/utils/version-compare.mjs +70 -0
  95. package/esm/utils/version-compare.mjs.map +1 -0
  96. package/esm/validation/validateAll.mjs +2 -2
  97. package/esm/validation/validateAll.mjs.map +1 -1
  98. package/esm/warlock-config/types.d.mts +9 -0
  99. package/esm/warlock-config/types.d.mts.map +1 -1
  100. package/llms-full.txt +249 -2
  101. package/llms.txt +3 -1
  102. package/package.json +9 -9
  103. package/skills/health-checks/SKILL.md +98 -0
  104. package/skills/run-app/SKILL.md +3 -0
  105. package/skills/update-packages/SKILL.md +78 -0
  106. package/skills/use-app-context/SKILL.md +62 -2
@@ -1 +1 @@
1
- {"version":3,"file":"cache-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/cache-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { cache } from \"@warlock.js/cache\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Cache Connector\r\n * Manages cache engine connection lifecycle\r\n */\r\nexport class CacheConnector extends BaseConnector {\r\n public readonly name = \"cache\";\r\n public readonly priority = ConnectorPriority.CACHE;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger cache restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/cache.ts\", \"src/config/cache.tsx\"];\r\n\r\n /**\r\n * Initialize cache connection\r\n */\r\n public async start(): Promise<void> {\r\n const cacheConfig = config.get(\"cache\");\r\n\r\n if (!cacheConfig) return;\r\n\r\n cache.setCacheConfigurations(cacheConfig);\r\n\r\n await cache.init();\r\n\r\n this.active = true;\r\n }\r\n\r\n /**\r\n * Shutdown cache connection\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n // TODO: Implement actual cache disconnection\r\n // - Close all active connections\r\n // - Clean up resources\r\n\r\n this.active = false;\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;AASA,IAAa,iBAAb,cAAoC,cAAc;;;cACzB;;;sBAOW,CAAC,uBAAuB,sBAAsB;;;;;CAKhF,MAAa,QAAuB;EAClC,MAAM,cAAc,OAAO,IAAI,OAAO;EAEtC,IAAI,CAAC,aAAa;EAElB,MAAM,uBAAuB,WAAW;EAExC,MAAM,MAAM,KAAK;EAEjB,KAAK,SAAS;CAChB;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAOF,KAAK,SAAS;CAChB;AACF"}
1
+ {"version":3,"file":"cache-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/cache-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { cache } from \"@warlock.js/cache\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Cache Connector\r\n * Manages cache engine connection lifecycle\r\n */\r\nexport class CacheConnector extends BaseConnector {\r\n public readonly name = \"cache\";\r\n public readonly priority = ConnectorPriority.CACHE;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger cache restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/cache.ts\", \"src/config/cache.tsx\"];\r\n\r\n /**\r\n * Initialize cache connection\r\n */\r\n public async start(): Promise<void> {\r\n const cacheConfig = config.get(\"cache\");\r\n\r\n if (!cacheConfig) return;\r\n\r\n cache.setCacheConfigurations(cacheConfig);\r\n\r\n await cache.init();\r\n\r\n this.active = true;\r\n }\r\n\r\n /**\r\n * Shutdown cache connection\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n // TODO: Implement actual cache disconnection\r\n // - Close all active connections\r\n // - Clean up resources\r\n\r\n this.active = false;\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;AASA,IAAa,iBAAb,cAAoC,cAAc;;;cACzB;;;sBAOW,CAAC,uBAAuB,sBAAsB;;;;;CAKhF,MAAa,QAAuB;EAClC,MAAM,cAAcA,WAAO,IAAI,OAAO;EAEtC,IAAI,CAAC,aAAa;EAElB,MAAM,uBAAuB,WAAW;EAExC,MAAM,MAAM,KAAK;EAEjB,KAAK,SAAS;CAChB;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAOF,KAAK,SAAS;CAChB;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"connectors-manager.d.mts","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/connectors-manager.ts"],"mappings":";;;cAea,iBAAA;EAAA;;;EAAA,iBAIM,UAAA;EA8BF;;;;EA8B0C;;;EAvClD,QAAA,IAAY,UAAA,EAAY,SAAA;EAmEC;;;EA1DzB,IAAA,IAAQ,SAAA;EATR;;;EAgBM,KAAA,CAAM,eAAA,GAAkB,aAAA,KAAkB,OAAA;EAPxC;;;;;;;;;EA8BF,UAAA,CAAW,KAAA,EAAO,uBAAA,GAA0B,OAAA;EAiBX;;;EAAjC,YAAA,CAAa,kBAAA,EAAoB,aAAA,KAAkB,OAAA;EAWvC;;;EAAZ,QAAA,IAAY,OAAA;EA4Cd;;;;AAA2C;;;;EAzB/C,qBAAA;AAAA;AAAA,cAyBI,iBAAA,EAAiB,iBAA0B"}
1
+ {"version":3,"file":"connectors-manager.d.mts","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/connectors-manager.ts"],"mappings":";;;cAgBa,iBAAA;EAAA;;;EAAA,iBAIM,UAAA;EA8BF;;;;EA8B0C;;;EAvClD,QAAA,IAAY,UAAA,EAAY,SAAA;EAmEC;;;EA1DzB,IAAA,IAAQ,SAAA;EATR;;;EAgBM,KAAA,CAAM,eAAA,GAAkB,aAAA,KAAkB,OAAA;EAPxC;;;;;;;;;EA8BF,UAAA,CAAW,KAAA,EAAO,uBAAA,GAA0B,OAAA;EAiBX;;;EAAjC,YAAA,CAAa,kBAAA,EAAoB,aAAA,KAAkB,OAAA;EAWvC;;;EAAZ,QAAA,IAAY,OAAA;EAkDd;;;;AAA2C;;;;EAzB/C,qBAAA;AAAA;AAAA,cAyBI,iBAAA,EAAiB,iBAA0B"}
@@ -1,3 +1,5 @@
1
+ import { Application } from "../application/application.mjs";
2
+ import "../application/index.mjs";
1
3
  import { AccessConnector } from "./access-connector.mjs";
2
4
  import { CacheConnector } from "./cache-connector.mjs";
3
5
  import { HeraldConnector } from "./herald-connector.mjs";
@@ -74,7 +76,8 @@ var ConnectorsManager = class {
74
76
  * Shutdown all connectors
75
77
  */
76
78
  async shutdown() {
77
- for (const connector of this.connectors.reverse()) try {
79
+ await Application.runShutdownHooks();
80
+ for (const connector of [...this.connectors].reverse()) try {
78
81
  await connector.shutdown();
79
82
  } catch (error) {
80
83
  devServeLog(colors.redBright(`❌ Failed to shutdown ${connector.name}: ${error}`));
@@ -1 +1 @@
1
- {"version":3,"file":"connectors-manager.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/connectors-manager.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\r\nimport { devServeLog } from \"../dev-server/dev-logger\";\r\nimport { AccessConnector } from \"./access-connector\";\r\nimport { CacheConnector } from \"./cache-connector\";\r\nimport { DatabaseConnector } from \"./database-connector\";\r\nimport { HeraldConnector } from \"./herald-connector\";\r\nimport { HttpConnector } from \"./http-connector\";\r\nimport { LoggerConnector } from \"./logger-connector\";\r\nimport { MailerConnector } from \"./mail-connector\";\r\nimport { NotificationsConnector } from \"./notifications-connector\";\r\nimport { SocketConnector } from \"./socket-connector\";\r\nimport { StorageConnector } from \"./storage.connector\";\r\nimport { ConnectorLifecyclePhase } from \"./types\";\r\nimport type { Connector, ConnectorName } from \"./types\";\r\n\r\nexport class ConnectorsManager {\r\n /**\r\n * Connectors list\r\n */\r\n private readonly connectors: Connector[] = [];\r\n\r\n /**\r\n * Constructor\r\n */\r\n public constructor() {\r\n this.register(new LoggerConnector());\r\n this.register(new MailerConnector());\r\n this.register(new HttpConnector());\r\n this.register(new DatabaseConnector());\r\n this.register(new HeraldConnector());\r\n this.register(new CacheConnector());\r\n this.register(new StorageConnector());\r\n this.register(new SocketConnector());\r\n this.register(new NotificationsConnector());\r\n this.register(new AccessConnector());\r\n }\r\n\r\n /**\r\n * Register a connector\r\n */\r\n public register(...connectors: Connector[]): void {\r\n this.connectors.push(...connectors);\r\n // sort connectors by priority\r\n this.connectors.sort((a, b) => a.priority - b.priority);\r\n }\r\n\r\n /**\r\n * Get all connectors\r\n */\r\n public list(): Connector[] {\r\n return this.connectors;\r\n }\r\n\r\n /**\r\n * start all connectors\r\n */\r\n public async start(connectorsNames?: ConnectorName[]): Promise<void> {\r\n const connectorsList = connectorsNames\r\n ? this.connectors.filter((connector) => connectorsNames.includes(connector.name))\r\n : this.connectors;\r\n\r\n for (const connector of connectorsList) {\r\n await connector.boot();\r\n }\r\n\r\n for (const connector of connectorsList) {\r\n await connector.start();\r\n }\r\n }\r\n\r\n /**\r\n * Start all connectors in the given lifecycle phase.\r\n *\r\n * The production builder and dev preload split startup around app\r\n * code: early phase before app imports, late phase after. Within a\r\n * phase, all connectors `boot()` first, then all `start()`, so\r\n * cross-connector wiring inside the phase still works (e.g. socket\r\n * reads http's instance during its own boot).\r\n */\r\n public async startPhase(phase: ConnectorLifecyclePhase): Promise<void> {\r\n const phaseConnectors = this.connectors.filter(\r\n (connector) => connector.lifecyclePhase === phase,\r\n );\r\n\r\n for (const connector of phaseConnectors) {\r\n await connector.boot();\r\n }\r\n\r\n for (const connector of phaseConnectors) {\r\n await connector.start();\r\n }\r\n }\r\n\r\n /**\r\n * Start all connectors except the given ones\r\n */\r\n public async startWithout(excludedConnectors: ConnectorName[]): Promise<void> {\r\n await this.start(\r\n this.connectors\r\n .filter((connector) => !excludedConnectors.includes(connector.name))\r\n .map((connector) => connector.name),\r\n );\r\n }\r\n\r\n /**\r\n * Shutdown all connectors\r\n */\r\n public async shutdown(): Promise<void> {\r\n // shut down connectors in reverse order\r\n for (const connector of this.connectors.reverse()) {\r\n try {\r\n await connector.shutdown();\r\n } catch (error) {\r\n devServeLog(colors.redBright(`❌ Failed to shutdown ${connector.name}: ${error}`));\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown connectors on process kill\r\n *\r\n * Handles graceful shutdown for both Unix and Windows:\r\n * - SIGINT: Ctrl+C on Unix, also caught on Windows but unreliable in child processes\r\n * - SIGTERM: Termination signal (Unix primarily)\r\n * - beforeExit: Fires when Node.js empties its event loop (more reliable on Windows)\r\n */\r\n public shutdownOnProcessKill(): void {\r\n let isShuttingDown = false;\r\n\r\n const gracefulShutdown = async (signal: string) => {\r\n if (isShuttingDown) return;\r\n isShuttingDown = true;\r\n\r\n console.log(`\\nExiting...`);\r\n await this.shutdown();\r\n process.exit(0);\r\n };\r\n\r\n // Unix signals\r\n process.on(\"SIGINT\", () => gracefulShutdown(\"SIGINT\"));\r\n process.on(\"SIGTERM\", () => gracefulShutdown(\"SIGTERM\"));\r\n\r\n // Windows-specific: handle when process is about to exit\r\n // This is more reliable on Windows for spawned child processes\r\n if (process.platform === \"win32\") {\r\n // Handle Ctrl+C on Windows specifically\r\n process.on(\"SIGHUP\", () => gracefulShutdown(\"SIGHUP\"));\r\n }\r\n }\r\n}\r\n\r\nexport const connectorsManager = new ConnectorsManager();\r\n"],"mappings":";;;;;;;;;;;;;;AAeA,IAAa,oBAAb,MAA+B;;;;CAS7B,AAAO,cAAc;oBALsB,CAAC;EAM1C,KAAK,SAAS,IAAI,gBAAgB,CAAC;EACnC,KAAK,SAAS,IAAI,gBAAgB,CAAC;EACnC,KAAK,SAAS,IAAI,cAAc,CAAC;EACjC,KAAK,SAAS,IAAI,kBAAkB,CAAC;EACrC,KAAK,SAAS,IAAI,gBAAgB,CAAC;EACnC,KAAK,SAAS,IAAI,eAAe,CAAC;EAClC,KAAK,SAAS,IAAI,iBAAiB,CAAC;EACpC,KAAK,SAAS,IAAI,gBAAgB,CAAC;EACnC,KAAK,SAAS,IAAI,uBAAuB,CAAC;EAC1C,KAAK,SAAS,IAAI,gBAAgB,CAAC;CACrC;;;;CAKA,AAAO,SAAS,GAAG,YAA+B;EAChD,KAAK,WAAW,KAAK,GAAG,UAAU;EAElC,KAAK,WAAW,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;CACxD;;;;CAKA,AAAO,OAAoB;EACzB,OAAO,KAAK;CACd;;;;CAKA,MAAa,MAAM,iBAAkD;EACnE,MAAM,iBAAiB,kBACnB,KAAK,WAAW,QAAQ,cAAc,gBAAgB,SAAS,UAAU,IAAI,CAAC,IAC9E,KAAK;EAET,KAAK,MAAM,aAAa,gBACtB,MAAM,UAAU,KAAK;EAGvB,KAAK,MAAM,aAAa,gBACtB,MAAM,UAAU,MAAM;CAE1B;;;;;;;;;;CAWA,MAAa,WAAW,OAA+C;EACrE,MAAM,kBAAkB,KAAK,WAAW,QACrC,cAAc,UAAU,mBAAmB,KAC9C;EAEA,KAAK,MAAM,aAAa,iBACtB,MAAM,UAAU,KAAK;EAGvB,KAAK,MAAM,aAAa,iBACtB,MAAM,UAAU,MAAM;CAE1B;;;;CAKA,MAAa,aAAa,oBAAoD;EAC5E,MAAM,KAAK,MACT,KAAK,WACF,QAAQ,cAAc,CAAC,mBAAmB,SAAS,UAAU,IAAI,CAAC,CAAC,CACnE,KAAK,cAAc,UAAU,IAAI,CACtC;CACF;;;;CAKA,MAAa,WAA0B;EAErC,KAAK,MAAM,aAAa,KAAK,WAAW,QAAQ,GAC9C,IAAI;GACF,MAAM,UAAU,SAAS;EAC3B,SAAS,OAAO;GACd,YAAY,OAAO,UAAU,wBAAwB,UAAU,KAAK,IAAI,OAAO,CAAC;EAClF;CAEJ;;;;;;;;;CAUA,AAAO,wBAA8B;EACnC,IAAI,iBAAiB;EAErB,MAAM,mBAAmB,OAAO,WAAmB;GACjD,IAAI,gBAAgB;GACpB,iBAAiB;GAEjB,QAAQ,IAAI,cAAc;GAC1B,MAAM,KAAK,SAAS;GACpB,QAAQ,KAAK,CAAC;EAChB;EAGA,QAAQ,GAAG,gBAAgB,iBAAiB,QAAQ,CAAC;EACrD,QAAQ,GAAG,iBAAiB,iBAAiB,SAAS,CAAC;EAIvD,IAAI,QAAQ,aAAa,SAEvB,QAAQ,GAAG,gBAAgB,iBAAiB,QAAQ,CAAC;CAEzD;AACF;AAEA,MAAa,oBAAoB,IAAI,kBAAkB"}
1
+ {"version":3,"file":"connectors-manager.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/connectors-manager.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\r\nimport { Application } from \"../application\";\r\nimport { devServeLog } from \"../dev-server/dev-logger\";\r\nimport { AccessConnector } from \"./access-connector\";\r\nimport { CacheConnector } from \"./cache-connector\";\r\nimport { DatabaseConnector } from \"./database-connector\";\r\nimport { HeraldConnector } from \"./herald-connector\";\r\nimport { HttpConnector } from \"./http-connector\";\r\nimport { LoggerConnector } from \"./logger-connector\";\r\nimport { MailerConnector } from \"./mail-connector\";\r\nimport { NotificationsConnector } from \"./notifications-connector\";\r\nimport { SocketConnector } from \"./socket-connector\";\r\nimport { StorageConnector } from \"./storage.connector\";\r\nimport { ConnectorLifecyclePhase } from \"./types\";\r\nimport type { Connector, ConnectorName } from \"./types\";\r\n\r\nexport class ConnectorsManager {\r\n /**\r\n * Connectors list\r\n */\r\n private readonly connectors: Connector[] = [];\r\n\r\n /**\r\n * Constructor\r\n */\r\n public constructor() {\r\n this.register(new LoggerConnector());\r\n this.register(new MailerConnector());\r\n this.register(new HttpConnector());\r\n this.register(new DatabaseConnector());\r\n this.register(new HeraldConnector());\r\n this.register(new CacheConnector());\r\n this.register(new StorageConnector());\r\n this.register(new SocketConnector());\r\n this.register(new NotificationsConnector());\r\n this.register(new AccessConnector());\r\n }\r\n\r\n /**\r\n * Register a connector\r\n */\r\n public register(...connectors: Connector[]): void {\r\n this.connectors.push(...connectors);\r\n // sort connectors by priority\r\n this.connectors.sort((a, b) => a.priority - b.priority);\r\n }\r\n\r\n /**\r\n * Get all connectors\r\n */\r\n public list(): Connector[] {\r\n return this.connectors;\r\n }\r\n\r\n /**\r\n * start all connectors\r\n */\r\n public async start(connectorsNames?: ConnectorName[]): Promise<void> {\r\n const connectorsList = connectorsNames\r\n ? this.connectors.filter((connector) => connectorsNames.includes(connector.name))\r\n : this.connectors;\r\n\r\n for (const connector of connectorsList) {\r\n await connector.boot();\r\n }\r\n\r\n for (const connector of connectorsList) {\r\n await connector.start();\r\n }\r\n }\r\n\r\n /**\r\n * Start all connectors in the given lifecycle phase.\r\n *\r\n * The production builder and dev preload split startup around app\r\n * code: early phase before app imports, late phase after. Within a\r\n * phase, all connectors `boot()` first, then all `start()`, so\r\n * cross-connector wiring inside the phase still works (e.g. socket\r\n * reads http's instance during its own boot).\r\n */\r\n public async startPhase(phase: ConnectorLifecyclePhase): Promise<void> {\r\n const phaseConnectors = this.connectors.filter(\r\n (connector) => connector.lifecyclePhase === phase,\r\n );\r\n\r\n for (const connector of phaseConnectors) {\r\n await connector.boot();\r\n }\r\n\r\n for (const connector of phaseConnectors) {\r\n await connector.start();\r\n }\r\n }\r\n\r\n /**\r\n * Start all connectors except the given ones\r\n */\r\n public async startWithout(excludedConnectors: ConnectorName[]): Promise<void> {\r\n await this.start(\r\n this.connectors\r\n .filter((connector) => !excludedConnectors.includes(connector.name))\r\n .map((connector) => connector.name),\r\n );\r\n }\r\n\r\n /**\r\n * Shutdown all connectors\r\n */\r\n public async shutdown(): Promise<void> {\r\n // App-owned teardown runs first, while every connector (db, cache, http) is\r\n // still up, so cleanup hooks can use them. Idempotent + error-isolated.\r\n await Application.runShutdownHooks();\r\n\r\n // Shut down connectors in reverse priority order. Copy the list first —\r\n // `reverse()` mutates in place, so reversing the live array would corrupt\r\n // the order on a second shutdown pass.\r\n for (const connector of [...this.connectors].reverse()) {\r\n try {\r\n await connector.shutdown();\r\n } catch (error) {\r\n devServeLog(colors.redBright(`❌ Failed to shutdown ${connector.name}: ${error}`));\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown connectors on process kill\r\n *\r\n * Handles graceful shutdown for both Unix and Windows:\r\n * - SIGINT: Ctrl+C on Unix, also caught on Windows but unreliable in child processes\r\n * - SIGTERM: Termination signal (Unix primarily)\r\n * - beforeExit: Fires when Node.js empties its event loop (more reliable on Windows)\r\n */\r\n public shutdownOnProcessKill(): void {\r\n let isShuttingDown = false;\r\n\r\n const gracefulShutdown = async (signal: string) => {\r\n if (isShuttingDown) return;\r\n isShuttingDown = true;\r\n\r\n console.log(`\\nExiting...`);\r\n await this.shutdown();\r\n process.exit(0);\r\n };\r\n\r\n // Unix signals\r\n process.on(\"SIGINT\", () => gracefulShutdown(\"SIGINT\"));\r\n process.on(\"SIGTERM\", () => gracefulShutdown(\"SIGTERM\"));\r\n\r\n // Windows-specific: handle when process is about to exit\r\n // This is more reliable on Windows for spawned child processes\r\n if (process.platform === \"win32\") {\r\n // Handle Ctrl+C on Windows specifically\r\n process.on(\"SIGHUP\", () => gracefulShutdown(\"SIGHUP\"));\r\n }\r\n }\r\n}\r\n\r\nexport const connectorsManager = new ConnectorsManager();\r\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,IAAa,oBAAb,MAA+B;;;;CAS7B,AAAO,cAAc;oBALsB,CAAC;EAM1C,KAAK,SAAS,IAAI,gBAAgB,CAAC;EACnC,KAAK,SAAS,IAAI,gBAAgB,CAAC;EACnC,KAAK,SAAS,IAAI,cAAc,CAAC;EACjC,KAAK,SAAS,IAAI,kBAAkB,CAAC;EACrC,KAAK,SAAS,IAAI,gBAAgB,CAAC;EACnC,KAAK,SAAS,IAAI,eAAe,CAAC;EAClC,KAAK,SAAS,IAAI,iBAAiB,CAAC;EACpC,KAAK,SAAS,IAAI,gBAAgB,CAAC;EACnC,KAAK,SAAS,IAAI,uBAAuB,CAAC;EAC1C,KAAK,SAAS,IAAI,gBAAgB,CAAC;CACrC;;;;CAKA,AAAO,SAAS,GAAG,YAA+B;EAChD,KAAK,WAAW,KAAK,GAAG,UAAU;EAElC,KAAK,WAAW,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;CACxD;;;;CAKA,AAAO,OAAoB;EACzB,OAAO,KAAK;CACd;;;;CAKA,MAAa,MAAM,iBAAkD;EACnE,MAAM,iBAAiB,kBACnB,KAAK,WAAW,QAAQ,cAAc,gBAAgB,SAAS,UAAU,IAAI,CAAC,IAC9E,KAAK;EAET,KAAK,MAAM,aAAa,gBACtB,MAAM,UAAU,KAAK;EAGvB,KAAK,MAAM,aAAa,gBACtB,MAAM,UAAU,MAAM;CAE1B;;;;;;;;;;CAWA,MAAa,WAAW,OAA+C;EACrE,MAAM,kBAAkB,KAAK,WAAW,QACrC,cAAc,UAAU,mBAAmB,KAC9C;EAEA,KAAK,MAAM,aAAa,iBACtB,MAAM,UAAU,KAAK;EAGvB,KAAK,MAAM,aAAa,iBACtB,MAAM,UAAU,MAAM;CAE1B;;;;CAKA,MAAa,aAAa,oBAAoD;EAC5E,MAAM,KAAK,MACT,KAAK,WACF,QAAQ,cAAc,CAAC,mBAAmB,SAAS,UAAU,IAAI,CAAC,CAAC,CACnE,KAAK,cAAc,UAAU,IAAI,CACtC;CACF;;;;CAKA,MAAa,WAA0B;EAGrC,MAAM,YAAY,iBAAiB;EAKnC,KAAK,MAAM,aAAa,CAAC,GAAG,KAAK,UAAU,CAAC,CAAC,QAAQ,GACnD,IAAI;GACF,MAAM,UAAU,SAAS;EAC3B,SAAS,OAAO;GACd,YAAY,OAAO,UAAU,wBAAwB,UAAU,KAAK,IAAI,OAAO,CAAC;EAClF;CAEJ;;;;;;;;;CAUA,AAAO,wBAA8B;EACnC,IAAI,iBAAiB;EAErB,MAAM,mBAAmB,OAAO,WAAmB;GACjD,IAAI,gBAAgB;GACpB,iBAAiB;GAEjB,QAAQ,IAAI,cAAc;GAC1B,MAAM,KAAK,SAAS;GACpB,QAAQ,KAAK,CAAC;EAChB;EAGA,QAAQ,GAAG,gBAAgB,iBAAiB,QAAQ,CAAC;EACrD,QAAQ,GAAG,iBAAiB,iBAAiB,SAAS,CAAC;EAIvD,IAAI,QAAQ,aAAa,SAEvB,QAAQ,GAAG,gBAAgB,iBAAiB,QAAQ,CAAC;CAEzD;AACF;AAEA,MAAa,oBAAoB,IAAI,kBAAkB"}
@@ -1,7 +1,7 @@
1
1
  import { container } from "../container/index.mjs";
2
2
  import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
3
3
  import { BaseConnector } from "./base-connector.mjs";
4
- import config from "@mongez/config";
4
+ import baseConfig from "@mongez/config";
5
5
  import { connectToDatabase, dataSourceRegistry } from "@warlock.js/cascade";
6
6
 
7
7
  //#region ../@warlock.js/core/src/connectors/database-connector.ts
@@ -21,7 +21,7 @@ var DatabaseConnector = class extends BaseConnector {
21
21
  * Initialize database connection
22
22
  */
23
23
  async start() {
24
- const databaseConfig = config.get("database");
24
+ const databaseConfig = baseConfig.get("database");
25
25
  if (!databaseConfig) return;
26
26
  try {
27
27
  const source = await connectToDatabase(databaseConfig);
@@ -1 +1 @@
1
- {"version":3,"file":"database-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/database-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { connectToDatabase, dataSourceRegistry } from \"@warlock.js/cascade\";\r\nimport { container } from \"../container\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Database Connector\r\n * Manages database connection lifecycle using @warlock.js/cascade\r\n */\r\nexport class DatabaseConnector extends BaseConnector {\r\n public readonly name = \"database\";\r\n public readonly priority = ConnectorPriority.DATABASE;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger database restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/database.ts\", \"src/config/database.tsx\"];\r\n\r\n /**\r\n * Initialize database connection\r\n */\r\n public async start(): Promise<void> {\r\n const databaseConfig = config.get(\"database\");\r\n\r\n if (!databaseConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n const source = await connectToDatabase(databaseConfig);\r\n container.set(\"database.source\", source);\r\n this.active = true;\r\n } catch (error) {\r\n console.error(\"Failed to connect to database:\", error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown database connection\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n // Disconnect all registered data sources\r\n const dataSources = dataSourceRegistry.getAllDataSources();\r\n\r\n for (const dataSource of dataSources) {\r\n if (dataSource.driver.isConnected) {\r\n await dataSource.driver.disconnect();\r\n }\r\n }\r\n\r\n this.active = false;\r\n } catch (error) {\r\n console.error(\"Failed to disconnect from database:\", error);\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;AAUA,IAAa,oBAAb,cAAuC,cAAc;;;cAC5B;;;sBAOW,CAAC,0BAA0B,yBAAyB;;;;;CAKtF,MAAa,QAAuB;EAClC,MAAM,iBAAiB,OAAO,IAAI,UAAU;EAE5C,IAAI,CAAC,gBACH;EAGF,IAAI;GACF,MAAM,SAAS,MAAM,kBAAkB,cAAc;GACrD,UAAU,IAAI,mBAAmB,MAAM;GACvC,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,kCAAkC,KAAK;GACrD,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GAEF,MAAM,cAAc,mBAAmB,kBAAkB;GAEzD,KAAK,MAAM,cAAc,aACvB,IAAI,WAAW,OAAO,aACpB,MAAM,WAAW,OAAO,WAAW;GAIvC,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,uCAAuC,KAAK;GAC1D,MAAM;EACR;CACF;AACF"}
1
+ {"version":3,"file":"database-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/database-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { connectToDatabase, dataSourceRegistry } from \"@warlock.js/cascade\";\r\nimport { container } from \"../container\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Database Connector\r\n * Manages database connection lifecycle using @warlock.js/cascade\r\n */\r\nexport class DatabaseConnector extends BaseConnector {\r\n public readonly name = \"database\";\r\n public readonly priority = ConnectorPriority.DATABASE;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger database restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/database.ts\", \"src/config/database.tsx\"];\r\n\r\n /**\r\n * Initialize database connection\r\n */\r\n public async start(): Promise<void> {\r\n const databaseConfig = config.get(\"database\");\r\n\r\n if (!databaseConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n const source = await connectToDatabase(databaseConfig);\r\n container.set(\"database.source\", source);\r\n this.active = true;\r\n } catch (error) {\r\n console.error(\"Failed to connect to database:\", error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown database connection\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n // Disconnect all registered data sources\r\n const dataSources = dataSourceRegistry.getAllDataSources();\r\n\r\n for (const dataSource of dataSources) {\r\n if (dataSource.driver.isConnected) {\r\n await dataSource.driver.disconnect();\r\n }\r\n }\r\n\r\n this.active = false;\r\n } catch (error) {\r\n console.error(\"Failed to disconnect from database:\", error);\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;AAUA,IAAa,oBAAb,cAAuC,cAAc;;;cAC5B;;;sBAOW,CAAC,0BAA0B,yBAAyB;;;;;CAKtF,MAAa,QAAuB;EAClC,MAAM,iBAAiBA,WAAO,IAAI,UAAU;EAE5C,IAAI,CAAC,gBACH;EAGF,IAAI;GACF,MAAM,SAAS,MAAM,kBAAkB,cAAc;GACrD,UAAU,IAAI,mBAAmB,MAAM;GACvC,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,kCAAkC,KAAK;GACrD,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GAEF,MAAM,cAAc,mBAAmB,kBAAkB;GAEzD,KAAK,MAAM,cAAc,aACvB,IAAI,WAAW,OAAO,aACpB,MAAM,WAAW,OAAO,WAAW;GAIvC,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,uCAAuC,KAAK;GAC1D,MAAM;EACR;CACF;AACF"}
@@ -1,6 +1,6 @@
1
1
  import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
2
2
  import { BaseConnector } from "./base-connector.mjs";
3
- import config from "@mongez/config";
3
+ import baseConfig from "@mongez/config";
4
4
  import { log } from "@warlock.js/logger";
5
5
 
6
6
  //#region ../@warlock.js/core/src/connectors/herald-connector.ts
@@ -20,7 +20,7 @@ var HeraldConnector = class extends BaseConnector {
20
20
  * Initialize broker connection
21
21
  */
22
22
  async start() {
23
- const heraldConfig = config.get("herald");
23
+ const heraldConfig = baseConfig.get("herald");
24
24
  if (!heraldConfig) return;
25
25
  try {
26
26
  const { connectToBroker } = await import("@warlock.js/herald");
@@ -1 +1 @@
1
- {"version":3,"file":"herald-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/herald-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Herald Connector\r\n * Manages message broker connection lifecycle using @warlock.js/herald\r\n */\r\nexport class HeraldConnector extends BaseConnector {\r\n public readonly name = \"herald\";\r\n public readonly priority = ConnectorPriority.COMMUNICATOR;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger herald restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/herald.ts\"];\r\n\r\n /**\r\n * Initialize broker connection\r\n */\r\n public async start(): Promise<void> {\r\n const heraldConfig = config.get(\"herald\");\r\n\r\n if (!heraldConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n const { connectToBroker } = await import(\"@warlock.js/herald\");\r\n\r\n log.info(`herald.${heraldConfig.driver}`, \"connection\", \"Connecting to message broker\");\r\n await connectToBroker(heraldConfig);\r\n log.success(`herald.${heraldConfig.driver}`, \"connection\", \"Connected to message broker\");\r\n this.active = true;\r\n } catch (error) {\r\n // Boot-time broker connection failure is unrecoverable — `fatal` makes\r\n // \"page on fatal only\" alerting clean, aligned with the cascade and\r\n // cache drivers. Disconnect failures (shutdown path) stay at error.\r\n log.fatal(\r\n `herald.${heraldConfig.driver}`,\r\n \"connection\",\r\n \"Failed to connect to message broker\",\r\n );\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown broker connection\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n const { brokerRegistry } = await import(\"@warlock.js/herald\");\r\n\r\n // Disconnect all registered brokers\r\n const brokers = brokerRegistry.getAll();\r\n\r\n for (const broker of brokers) {\r\n if (broker.driver.isConnected) {\r\n await broker.driver.disconnect();\r\n }\r\n }\r\n\r\n // Clear the registry for clean restart\r\n brokerRegistry.clear();\r\n\r\n this.active = false;\r\n } catch (error) {\r\n log.error(\"herald\", \"shutdown\", \"Failed to disconnect from message broker\");\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;AASA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW,CAAC,sBAAsB;;;;;CAKzD,MAAa,QAAuB;EAClC,MAAM,eAAe,OAAO,IAAI,QAAQ;EAExC,IAAI,CAAC,cACH;EAGF,IAAI;GACF,MAAM,EAAE,oBAAoB,MAAM,OAAO;GAEzC,IAAI,KAAK,UAAU,aAAa,UAAU,cAAc,8BAA8B;GACtF,MAAM,gBAAgB,YAAY;GAClC,IAAI,QAAQ,UAAU,aAAa,UAAU,cAAc,6BAA6B;GACxF,KAAK,SAAS;EAChB,SAAS,OAAO;GAId,IAAI,MACF,UAAU,aAAa,UACvB,cACA,qCACF;GACA,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GACF,MAAM,EAAE,mBAAmB,MAAM,OAAO;GAGxC,MAAM,UAAU,eAAe,OAAO;GAEtC,KAAK,MAAM,UAAU,SACnB,IAAI,OAAO,OAAO,aAChB,MAAM,OAAO,OAAO,WAAW;GAKnC,eAAe,MAAM;GAErB,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,IAAI,MAAM,UAAU,YAAY,0CAA0C;GAC1E,MAAM;EACR;CACF;AACF"}
1
+ {"version":3,"file":"herald-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/herald-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Herald Connector\r\n * Manages message broker connection lifecycle using @warlock.js/herald\r\n */\r\nexport class HeraldConnector extends BaseConnector {\r\n public readonly name = \"herald\";\r\n public readonly priority = ConnectorPriority.COMMUNICATOR;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger herald restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/herald.ts\"];\r\n\r\n /**\r\n * Initialize broker connection\r\n */\r\n public async start(): Promise<void> {\r\n const heraldConfig = config.get(\"herald\");\r\n\r\n if (!heraldConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n const { connectToBroker } = await import(\"@warlock.js/herald\");\r\n\r\n log.info(`herald.${heraldConfig.driver}`, \"connection\", \"Connecting to message broker\");\r\n await connectToBroker(heraldConfig);\r\n log.success(`herald.${heraldConfig.driver}`, \"connection\", \"Connected to message broker\");\r\n this.active = true;\r\n } catch (error) {\r\n // Boot-time broker connection failure is unrecoverable — `fatal` makes\r\n // \"page on fatal only\" alerting clean, aligned with the cascade and\r\n // cache drivers. Disconnect failures (shutdown path) stay at error.\r\n log.fatal(\r\n `herald.${heraldConfig.driver}`,\r\n \"connection\",\r\n \"Failed to connect to message broker\",\r\n );\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown broker connection\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n const { brokerRegistry } = await import(\"@warlock.js/herald\");\r\n\r\n // Disconnect all registered brokers\r\n const brokers = brokerRegistry.getAll();\r\n\r\n for (const broker of brokers) {\r\n if (broker.driver.isConnected) {\r\n await broker.driver.disconnect();\r\n }\r\n }\r\n\r\n // Clear the registry for clean restart\r\n brokerRegistry.clear();\r\n\r\n this.active = false;\r\n } catch (error) {\r\n log.error(\"herald\", \"shutdown\", \"Failed to disconnect from message broker\");\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;AASA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW,CAAC,sBAAsB;;;;;CAKzD,MAAa,QAAuB;EAClC,MAAM,eAAeA,WAAO,IAAI,QAAQ;EAExC,IAAI,CAAC,cACH;EAGF,IAAI;GACF,MAAM,EAAE,oBAAoB,MAAM,OAAO;GAEzC,IAAI,KAAK,UAAU,aAAa,UAAU,cAAc,8BAA8B;GACtF,MAAM,gBAAgB,YAAY;GAClC,IAAI,QAAQ,UAAU,aAAa,UAAU,cAAc,6BAA6B;GACxF,KAAK,SAAS;EAChB,SAAS,OAAO;GAId,IAAI,MACF,UAAU,aAAa,UACvB,cACA,qCACF;GACA,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GACF,MAAM,EAAE,mBAAmB,MAAM,OAAO;GAGxC,MAAM,UAAU,eAAe,OAAO;GAEtC,KAAK,MAAM,UAAU,SACnB,IAAI,OAAO,OAAO,aAChB,MAAM,OAAO,OAAO,WAAW;GAKnC,eAAe,MAAM;GAErB,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,IAAI,MAAM,UAAU,YAAY,0CAA0C;GAC1E,MAAM;EACR;CACF;AACF"}
@@ -27,6 +27,14 @@ declare class HttpConnector extends BaseConnector {
27
27
  * `start()` so it reads the router after app code has registered.
28
28
  */
29
29
  boot(): Promise<void>;
30
+ /**
31
+ * Register the built-in liveness (`/health`) and readiness (`/ready`)
32
+ * endpoints directly on the Fastify instance — infra routes, kept off the app
33
+ * router so they're immune to HMR and never collide with route scanning. Opt
34
+ * out via `http.health.enabled = false`; rename via `http.health.path` /
35
+ * `http.health.readinessPath`.
36
+ */
37
+ private registerHealthRoutes;
30
38
  /**
31
39
  * Initialize HTTP server — bind app-registered routes to Fastify
32
40
  * then listen. Scanning here (not in `boot`) lets HTTP boot before
@@ -1 +1 @@
1
- {"version":3,"file":"http-connector.d.mts","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/http-connector.ts"],"mappings":";;;;;;;AA+BA;;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;;;;;EAoCG,KAAA,IAAS,OAAA;EA0CT;;;;;EAAA,OAAA,IAAW,OAAA;EA0BmB;AAAA;;EAjB9B,QAAA,IAAY,OAAA;;;;;;EAiBlB,aAAA,CAAc,YAAA;AAAA"}
1
+ {"version":3,"file":"http-connector.d.mts","names":[],"sources":["../../../../../../../@warlock.js/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;EA0EgB;;;;;EA1CX,KAAA,IAAS,OAAA;EA+EqB;;;;;EArC9B,OAAA,IAAW,OAAA;;;;EASX,QAAA,IAAY,OAAA;;;;;;EA4BlB,aAAA,CAAc,YAAA;AAAA"}
@@ -2,13 +2,14 @@ import { setBaseUrl } from "../utils/urls.mjs";
2
2
  import { container } from "../container/index.mjs";
3
3
  import { router } from "../router/router.mjs";
4
4
  import { registerHttpPlugins } from "../http/plugins.mjs";
5
- import { getHttpServer, startHttpServer } from "../http/server.mjs";
5
+ import { closeServerWithTimeout, getHttpServer, startHttpServer } from "../http/server.mjs";
6
6
  import { Application } from "../application/application.mjs";
7
7
  import "../application/index.mjs";
8
+ import { health } from "../http/health.mjs";
8
9
  import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
9
10
  import { BaseConnector } from "./base-connector.mjs";
10
11
  import { devLogError } from "../dev-server/dev-logger.mjs";
11
- import config from "@mongez/config";
12
+ import baseConfig from "@mongez/config";
12
13
  import { log } from "@warlock.js/logger";
13
14
  import { colors } from "@mongez/copper";
14
15
 
@@ -22,6 +23,11 @@ function environmentColor(environment) {
22
23
  }
23
24
  }
24
25
  /**
26
+ * Default time to wait for in-flight requests to drain on shutdown before the
27
+ * HTTP server is force-closed. Override via `http.gracefulShutdown.timeout`.
28
+ */
29
+ const DEFAULT_SHUTDOWN_TIMEOUT = 1e4;
30
+ /**
25
31
  * HTTP Connector
26
32
  * Manages HTTP server (Fastify) lifecycle
27
33
  */
@@ -39,14 +45,37 @@ var HttpConnector = class extends BaseConnector {
39
45
  * `start()` so it reads the router after app code has registered.
40
46
  */
41
47
  async boot() {
42
- const httpConfig = config.get("http");
48
+ const httpConfig = baseConfig.get("http");
43
49
  if (!httpConfig) return;
44
50
  const port = httpConfig.port;
45
51
  log.info(`http`, "connection", `Starting http server on port ${port} in ${environmentColor(Application.environment)} mode`);
46
52
  this.http = startHttpServer(httpConfig.serverOptions);
47
53
  container.set("http.server", this.http);
48
54
  await registerHttpPlugins(this.http);
49
- setBaseUrl(config.get("app.baseUrl"));
55
+ setBaseUrl(baseConfig.get("app.baseUrl"));
56
+ this.registerHealthRoutes();
57
+ }
58
+ /**
59
+ * Register the built-in liveness (`/health`) and readiness (`/ready`)
60
+ * endpoints directly on the Fastify instance — infra routes, kept off the app
61
+ * router so they're immune to HMR and never collide with route scanning. Opt
62
+ * out via `http.health.enabled = false`; rename via `http.health.path` /
63
+ * `http.health.readinessPath`.
64
+ */
65
+ registerHealthRoutes() {
66
+ if (!this.http) return;
67
+ const healthConfig = baseConfig.get("http.health");
68
+ if (healthConfig?.enabled === false) return;
69
+ const livenessPath = healthConfig?.path ?? "/health";
70
+ const readinessPath = healthConfig?.readinessPath ?? "/ready";
71
+ this.http.get(livenessPath, async (_request, reply) => {
72
+ const result = health.liveness();
73
+ return reply.code(result.status === "ok" ? 200 : 503).send(result);
74
+ });
75
+ this.http.get(readinessPath, async (_request, reply) => {
76
+ const result = await health.readiness();
77
+ return reply.code(result.status === "ok" ? 200 : 503).send(result);
78
+ });
50
79
  }
51
80
  /**
52
81
  * Initialize HTTP server — bind app-registered routes to Fastify
@@ -54,7 +83,7 @@ var HttpConnector = class extends BaseConnector {
54
83
  * app code without losing routes.
55
84
  */
56
85
  async start() {
57
- const httpConfig = config.get("http");
86
+ const httpConfig = baseConfig.get("http");
58
87
  if (!httpConfig || !this.http) return;
59
88
  if (Application.runtimeStrategy === "development") router.scanDevServer(this.http);
60
89
  else router.scan(this.http);
@@ -63,7 +92,7 @@ var HttpConnector = class extends BaseConnector {
63
92
  port: httpConfig.port,
64
93
  host: httpConfig.host || "localhost"
65
94
  });
66
- const baseUrl = config.get("app.baseUrl");
95
+ const baseUrl = baseConfig.get("app.baseUrl");
67
96
  log.success(`http`, "connection", `Server ready at ${baseUrl}`);
68
97
  } catch (error) {
69
98
  devLogError("Error while starting http server", error);
@@ -88,7 +117,11 @@ var HttpConnector = class extends BaseConnector {
88
117
  */
89
118
  async shutdown() {
90
119
  if (!this.active) return;
91
- getHttpServer()?.close();
120
+ const server = getHttpServer();
121
+ if (server) {
122
+ const timeout = baseConfig.get("http.gracefulShutdown.timeout", DEFAULT_SHUTDOWN_TIMEOUT);
123
+ if (!await closeServerWithTimeout(server, timeout)) log.warn("http", "shutdown", `In-flight requests did not drain within ${timeout}ms; closing anyway`);
124
+ }
92
125
  this.active = false;
93
126
  }
94
127
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"http-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/http-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { colors } from \"@mongez/copper\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { Application } from \"../application\";\r\nimport { devLogError } from \"../dev-server/dev-logger\";\r\nimport { registerHttpPlugins } from \"../http/plugins\";\r\nimport { 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 * 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\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 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 server?.close();\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":";;;;;;;;;;;;;;;AAcA,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,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;CACpB;;;;;;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;EAGvB,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;EAKF,AAFe,cAEV,CAAC,EAAE,MAAM;EAEd,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":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/http-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { colors } from \"@mongez/copper\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { Application } from \"../application\";\r\nimport { devLogError } from \"../dev-server/dev-logger\";\r\nimport { health } from \"../http/health\";\r\nimport { registerHttpPlugins } from \"../http/plugins\";\r\nimport { closeServerWithTimeout, FastifyInstance, getHttpServer, startHttpServer } from \"../http/server\";\r\nimport { router } from \"../router/router\";\r\nimport { Environment } from \"../utils\";\r\nimport { setBaseUrl } from \"../utils/urls\";\r\nimport { container } from \"./../container\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\nfunction environmentColor(environment: Environment) {\r\n switch (environment) {\r\n case \"development\":\r\n return colors.magentaBright(environment);\r\n case \"test\":\r\n return colors.yellowBright(environment);\r\n case \"production\":\r\n return colors.greenBright(environment);\r\n default:\r\n return colors.white(environment);\r\n }\r\n}\r\n\r\n/**\r\n * Default time to wait for in-flight requests to drain on shutdown before the\r\n * HTTP server is force-closed. Override via `http.gracefulShutdown.timeout`.\r\n */\r\nconst DEFAULT_SHUTDOWN_TIMEOUT = 10_000;\r\n\r\n/**\r\n * HTTP Connector\r\n * Manages HTTP server (Fastify) lifecycle\r\n */\r\nexport class HttpConnector extends BaseConnector {\r\n public readonly name = \"http\";\r\n public readonly priority = ConnectorPriority.HTTP;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Late;\r\n\r\n /**\r\n * Files that trigger HTTP server restart\r\n * Note: routes.ts changes will be handled by HMR with wildcard routing\r\n * Connectors receive config file paths directly (not .env) thanks to layer-executor\r\n */\r\n protected readonly watchedFiles = [\"src/config/http.ts\", \"src/config/http.tsx\"];\r\n\r\n /**\r\n * Fastify Server instance\r\n */\r\n protected http?: FastifyInstance;\r\n\r\n /**\r\n * Boot the connector — construction only (create Fastify, register\r\n * plugins, populate container). Route scanning is deferred to\r\n * `start()` so it reads the router after app code has registered.\r\n */\r\n public async boot() {\r\n const httpConfig = config.get(\"http\");\r\n\r\n if (!httpConfig) return;\r\n\r\n const port = httpConfig.port;\r\n log.info(\r\n `http`,\r\n \"connection\",\r\n `Starting http server on port ${port} in ${environmentColor(Application.environment)} mode`,\r\n );\r\n\r\n this.http = startHttpServer(httpConfig.serverOptions);\r\n\r\n container.set(\"http.server\", this.http);\r\n\r\n await registerHttpPlugins(this.http);\r\n\r\n const baseUrl = config.get(\"app.baseUrl\");\r\n\r\n // update base url\r\n setBaseUrl(baseUrl);\r\n\r\n // Liveness/readiness endpoints — registered on Fastify before start() scans\r\n // the app router, so they exist by the time the server listens.\r\n this.registerHealthRoutes();\r\n }\r\n\r\n /**\r\n * Register the built-in liveness (`/health`) and readiness (`/ready`)\r\n * endpoints directly on the Fastify instance — infra routes, kept off the app\r\n * router so they're immune to HMR and never collide with route scanning. Opt\r\n * out via `http.health.enabled = false`; rename via `http.health.path` /\r\n * `http.health.readinessPath`.\r\n */\r\n private registerHealthRoutes(): void {\r\n if (!this.http) {\r\n return;\r\n }\r\n\r\n const healthConfig = config.get(\"http.health\");\r\n\r\n if (healthConfig?.enabled === false) {\r\n return;\r\n }\r\n\r\n const livenessPath = healthConfig?.path ?? \"/health\";\r\n const readinessPath = healthConfig?.readinessPath ?? \"/ready\";\r\n\r\n this.http.get(livenessPath, async (_request, reply) => {\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, reply) => {\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 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,aAAaA,WAAO,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,WAHgBA,WAAO,IAAI,aAGV,CAAC;EAIlB,KAAK,qBAAqB;CAC5B;;;;;;;;CASA,AAAQ,uBAA6B;EACnC,IAAI,CAAC,KAAK,MACR;EAGF,MAAM,eAAeA,WAAO,IAAI,aAAa;EAE7C,IAAI,cAAc,YAAY,OAC5B;EAGF,MAAM,eAAe,cAAc,QAAQ;EAC3C,MAAM,gBAAgB,cAAc,iBAAiB;EAErD,KAAK,KAAK,IAAI,cAAc,OAAO,UAAU,UAAU;GACrD,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,UAAU,UAAU;GACtD,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,aAAaA,WAAO,IAAI,MAAM;EAEpC,IAAI,CAAC,cAAc,CAAC,KAAK,MAAM;EAE/B,IAAI,YAAY,oBAAoB,eAClC,OAAO,cAAc,KAAK,IAAI;OAE9B,OAAO,KAAK,KAAK,IAAI;EAGvB,IAAI;GAEF,MAAM,KAAK,KAAK,OAAO;IACrB,MAAM,WAAW;IACjB,MAAM,WAAW,QAAQ;GAC3B,CAAC;GAED,MAAM,UAAUA,WAAO,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,UAAUA,WAAO,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"}
@@ -2,7 +2,7 @@ import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
2
2
  import { BaseConnector } from "./base-connector.mjs";
3
3
  import { setLogConfigurations } from "../logger/logger.mjs";
4
4
  import "../logger/index.mjs";
5
- import config from "@mongez/config";
5
+ import baseConfig from "@mongez/config";
6
6
  import { log } from "@warlock.js/logger";
7
7
 
8
8
  //#region ../@warlock.js/core/src/connectors/logger-connector.ts
@@ -22,7 +22,7 @@ var LoggerConnector = class extends BaseConnector {
22
22
  * Initialize logger configurations
23
23
  */
24
24
  async start() {
25
- const logConfig = config.get("log");
25
+ const logConfig = baseConfig.get("log");
26
26
  if (!logConfig) return;
27
27
  try {
28
28
  setLogConfigurations(logConfig);
@@ -1 +1 @@
1
- {"version":3,"file":"logger-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/logger-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { setLogConfigurations } from \"../logger\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Logger Connector\r\n * Manages logger lifecycle and ensures synchronous flushing on termination\r\n */\r\nexport class LoggerConnector extends BaseConnector {\r\n public readonly name = \"logger\";\r\n public readonly priority = ConnectorPriority.LOGGER;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger logger restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/log.ts\", \"src/config/log.tsx\"];\r\n\r\n /**\r\n * Initialize logger configurations\r\n */\r\n public async start(): Promise<void> {\r\n const logConfig = config.get(\"log\");\r\n\r\n if (!logConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n setLogConfigurations(logConfig);\r\n this.active = true;\r\n } catch (error) {\r\n console.error(\"Failed to initialize logger:\", error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown logger and flush messages synchronously\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n log.flushSync();\r\n this.active = false;\r\n } catch (error) {\r\n console.error(\"Failed to flush logger:\", error);\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;AAUA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW,CAAC,qBAAqB,oBAAoB;;;;;CAK5E,MAAa,QAAuB;EAClC,MAAM,YAAY,OAAO,IAAI,KAAK;EAElC,IAAI,CAAC,WACH;EAGF,IAAI;GACF,qBAAqB,SAAS;GAC9B,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GACF,IAAI,UAAU;GACd,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,2BAA2B,KAAK;GAC9C,MAAM;EACR;CACF;AACF"}
1
+ {"version":3,"file":"logger-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/logger-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { setLogConfigurations } from \"../logger\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Logger Connector\r\n * Manages logger lifecycle and ensures synchronous flushing on termination\r\n */\r\nexport class LoggerConnector extends BaseConnector {\r\n public readonly name = \"logger\";\r\n public readonly priority = ConnectorPriority.LOGGER;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger logger restart\r\n */\r\n protected readonly watchedFiles = [\"src/config/log.ts\", \"src/config/log.tsx\"];\r\n\r\n /**\r\n * Initialize logger configurations\r\n */\r\n public async start(): Promise<void> {\r\n const logConfig = config.get(\"log\");\r\n\r\n if (!logConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n setLogConfigurations(logConfig);\r\n this.active = true;\r\n } catch (error) {\r\n console.error(\"Failed to initialize logger:\", error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown logger and flush messages synchronously\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n log.flushSync();\r\n this.active = false;\r\n } catch (error) {\r\n console.error(\"Failed to flush logger:\", error);\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;AAUA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW,CAAC,qBAAqB,oBAAoB;;;;;CAK5E,MAAa,QAAuB;EAClC,MAAM,YAAYA,WAAO,IAAI,KAAK;EAElC,IAAI,CAAC,WACH;EAGF,IAAI;GACF,qBAAqB,SAAS;GAC9B,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GACF,IAAI,UAAU;GACd,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,2BAA2B,KAAK;GAC9C,MAAM;EACR;CACF;AACF"}
@@ -3,7 +3,7 @@ import { BaseConnector } from "./base-connector.mjs";
3
3
  import { setMailConfigurations } from "../mail/config.mjs";
4
4
  import { closeAllMailers } from "../mail/mailer-pool.mjs";
5
5
  import "../mail/index.mjs";
6
- import config from "@mongez/config";
6
+ import baseConfig from "@mongez/config";
7
7
 
8
8
  //#region ../@warlock.js/core/src/connectors/mail-connector.ts
9
9
  /**
@@ -26,7 +26,7 @@ var MailerConnector = class extends BaseConnector {
26
26
  * Initialize mailer configurations
27
27
  */
28
28
  async start() {
29
- const mailConfig = config.get("mail");
29
+ const mailConfig = baseConfig.get("mail");
30
30
  if (!mailConfig) return;
31
31
  try {
32
32
  setMailConfigurations(mailConfig);
@@ -1 +1 @@
1
- {"version":3,"file":"mail-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/mail-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { closeAllMailers, setMailConfigurations } from \"../mail\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Mailer Connector\r\n * Manages mailer lifecycle and ensures graceful pool shutdown\r\n */\r\nexport class MailerConnector extends BaseConnector {\r\n public readonly name = \"mailer\";\r\n public readonly priority = ConnectorPriority.MAILER;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger mailer restart\r\n */\r\n protected readonly watchedFiles = [\".env\", \"src/config/mail.ts\", \"src/config/mail.tsx\"];\r\n\r\n /**\r\n * Initialize mailer configurations\r\n */\r\n public async start(): Promise<void> {\r\n const mailConfig = config.get(\"mail\");\r\n\r\n if (!mailConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n setMailConfigurations(mailConfig);\r\n this.active = true;\r\n } catch (error) {\r\n console.error(\"Failed to initialize mailer:\", error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown mailer pool\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n closeAllMailers();\r\n this.active = false;\r\n } catch (error) {\r\n console.error(\"Failed to close all mailers:\", error);\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;AASA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW;GAAC;GAAQ;GAAsB;EAAqB;;;;;CAKtF,MAAa,QAAuB;EAClC,MAAM,aAAa,OAAO,IAAI,MAAM;EAEpC,IAAI,CAAC,YACH;EAGF,IAAI;GACF,sBAAsB,UAAU;GAChC,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GACF,gBAAgB;GAChB,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD,MAAM;EACR;CACF;AACF"}
1
+ {"version":3,"file":"mail-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/mail-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { closeAllMailers, setMailConfigurations } from \"../mail\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Mailer Connector\r\n * Manages mailer lifecycle and ensures graceful pool shutdown\r\n */\r\nexport class MailerConnector extends BaseConnector {\r\n public readonly name = \"mailer\";\r\n public readonly priority = ConnectorPriority.MAILER;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\r\n\r\n /**\r\n * Files that trigger mailer restart\r\n */\r\n protected readonly watchedFiles = [\".env\", \"src/config/mail.ts\", \"src/config/mail.tsx\"];\r\n\r\n /**\r\n * Initialize mailer configurations\r\n */\r\n public async start(): Promise<void> {\r\n const mailConfig = config.get(\"mail\");\r\n\r\n if (!mailConfig) {\r\n return;\r\n }\r\n\r\n try {\r\n setMailConfigurations(mailConfig);\r\n this.active = true;\r\n } catch (error) {\r\n console.error(\"Failed to initialize mailer:\", error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown mailer pool\r\n */\r\n public async shutdown(): Promise<void> {\r\n if (!this.active) {\r\n return;\r\n }\r\n\r\n try {\r\n closeAllMailers();\r\n this.active = false;\r\n } catch (error) {\r\n console.error(\"Failed to close all mailers:\", error);\r\n throw error;\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;AASA,IAAa,kBAAb,cAAqC,cAAc;;;cAC1B;;;sBAOW;GAAC;GAAQ;GAAsB;EAAqB;;;;;CAKtF,MAAa,QAAuB;EAClC,MAAM,aAAaA,WAAO,IAAI,MAAM;EAEpC,IAAI,CAAC,YACH;EAGF,IAAI;GACF,sBAAsB,UAAU;GAChC,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD,MAAM;EACR;CACF;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI;GACF,gBAAgB;GAChB,KAAK,SAAS;EAChB,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD,MAAM;EACR;CACF;AACF"}
@@ -1,6 +1,6 @@
1
1
  import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
2
2
  import { BaseConnector } from "./base-connector.mjs";
3
- import config from "@mongez/config";
3
+ import baseConfig from "@mongez/config";
4
4
  import { log } from "@warlock.js/logger";
5
5
 
6
6
  //#region ../@warlock.js/core/src/connectors/notifications-connector.ts
@@ -28,7 +28,7 @@ var NotificationsConnector = class extends BaseConnector {
28
28
  * Register the notifications configuration with the package.
29
29
  */
30
30
  async start() {
31
- const notificationsConfig = config.get("notifications");
31
+ const notificationsConfig = baseConfig.get("notifications");
32
32
  if (!notificationsConfig) return;
33
33
  const { setNotificationConfig } = await import("@warlock.js/notifications");
34
34
  setNotificationConfig(notificationsConfig);
@@ -1 +1 @@
1
- {"version":3,"file":"notifications-connector.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/connectors/notifications-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport { BaseConnector } from \"./base-connector\";\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\n\n/**\n * Notifications Connector\n *\n * Wires `@warlock.js/notifications` from `src/config/notifications.ts` at boot:\n * reads the exported config object and hands it to the package's\n * `setNotificationConfig`. Config files stay declarative — they export the\n * config, the connector performs the side-effect.\n *\n * The package is lazy-imported (only when a notifications config is present),\n * so core carries no hard dependency on it — the same pattern as the herald\n * connector with `@warlock.js/herald`.\n */\nexport class NotificationsConnector extends BaseConnector {\n public readonly name = \"notifications\";\n public readonly priority = ConnectorPriority.NOTIFICATIONS;\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\n\n /**\n * Files that trigger a notifications restart\n */\n protected readonly watchedFiles = [\"src/config/notifications.ts\"];\n\n /**\n * Register the notifications configuration with the package.\n */\n public async start(): Promise<void> {\n const notificationsConfig = config.get(\"notifications\");\n\n if (!notificationsConfig) {\n return;\n }\n\n const { setNotificationConfig } = await import(\"@warlock.js/notifications\");\n\n setNotificationConfig(notificationsConfig);\n this.active = true;\n\n log.info(\"notifications\", \"configured\", \"Notifications wired from config/notifications.ts\");\n }\n\n /**\n * Nothing to tear down — the package holds no external connection of its own\n * (the optional queue worker + its broker own their lifecycle). Clear the\n * active flag so a dev restart re-registers from the (possibly changed) config.\n */\n public async shutdown(): Promise<void> {\n if (!this.active) {\n return;\n }\n\n this.active = false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiBA,IAAa,yBAAb,cAA4C,cAAc;;;cACjC;;;sBAOW,CAAC,6BAA6B;;;;;CAKhE,MAAa,QAAuB;EAClC,MAAM,sBAAsB,OAAO,IAAI,eAAe;EAEtD,IAAI,CAAC,qBACH;EAGF,MAAM,EAAE,0BAA0B,MAAM,OAAO;EAE/C,sBAAsB,mBAAmB;EACzC,KAAK,SAAS;EAEd,IAAI,KAAK,iBAAiB,cAAc,kDAAkD;CAC5F;;;;;;CAOA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,KAAK,SAAS;CAChB;AACF"}
1
+ {"version":3,"file":"notifications-connector.mjs","names":["config"],"sources":["../../../../../../../@warlock.js/core/src/connectors/notifications-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport { BaseConnector } from \"./base-connector\";\nimport { ConnectorLifecyclePhase, ConnectorPriority } from \"./types\";\n\n/**\n * Notifications Connector\n *\n * Wires `@warlock.js/notifications` from `src/config/notifications.ts` at boot:\n * reads the exported config object and hands it to the package's\n * `setNotificationConfig`. Config files stay declarative — they export the\n * config, the connector performs the side-effect.\n *\n * The package is lazy-imported (only when a notifications config is present),\n * so core carries no hard dependency on it — the same pattern as the herald\n * connector with `@warlock.js/herald`.\n */\nexport class NotificationsConnector extends BaseConnector {\n public readonly name = \"notifications\";\n public readonly priority = ConnectorPriority.NOTIFICATIONS;\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Early;\n\n /**\n * Files that trigger a notifications restart\n */\n protected readonly watchedFiles = [\"src/config/notifications.ts\"];\n\n /**\n * Register the notifications configuration with the package.\n */\n public async start(): Promise<void> {\n const notificationsConfig = config.get(\"notifications\");\n\n if (!notificationsConfig) {\n return;\n }\n\n const { setNotificationConfig } = await import(\"@warlock.js/notifications\");\n\n setNotificationConfig(notificationsConfig);\n this.active = true;\n\n log.info(\"notifications\", \"configured\", \"Notifications wired from config/notifications.ts\");\n }\n\n /**\n * Nothing to tear down — the package holds no external connection of its own\n * (the optional queue worker + its broker own their lifecycle). Clear the\n * active flag so a dev restart re-registers from the (possibly changed) config.\n */\n public async shutdown(): Promise<void> {\n if (!this.active) {\n return;\n }\n\n this.active = false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiBA,IAAa,yBAAb,cAA4C,cAAc;;;cACjC;;;sBAOW,CAAC,6BAA6B;;;;;CAKhE,MAAa,QAAuB;EAClC,MAAM,sBAAsBA,WAAO,IAAI,eAAe;EAEtD,IAAI,CAAC,qBACH;EAGF,MAAM,EAAE,0BAA0B,MAAM,OAAO;EAE/C,sBAAsB,mBAAmB;EACzC,KAAK,SAAS;EAEd,IAAI,KAAK,iBAAiB,cAAc,kDAAkD;CAC5F;;;;;;CAOA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,KAAK,SAAS;CAChB;AACF"}
@@ -1,7 +1,7 @@
1
1
  import { container } from "../container/index.mjs";
2
2
  import { ConnectorLifecyclePhase, ConnectorPriority } from "./types.mjs";
3
3
  import { BaseConnector } from "./base-connector.mjs";
4
- import config from "@mongez/config";
4
+ import baseConfig from "@mongez/config";
5
5
  import { log } from "@warlock.js/logger";
6
6
  import { createServer } from "http";
7
7
  import { createServer as createServer$1 } from "https";
@@ -39,7 +39,7 @@ var SocketConnector = class extends BaseConnector {
39
39
  * Boot the connector
40
40
  */
41
41
  async boot() {
42
- const socketConfig = config.get("socket");
42
+ const socketConfig = baseConfig.get("socket");
43
43
  if (!socketConfig) return;
44
44
  let SocketServer;
45
45
  try {
@@ -62,7 +62,7 @@ var SocketConnector = class extends BaseConnector {
62
62
  * Initialize Socket server
63
63
  */
64
64
  async start() {
65
- if (!config.get("socket") || !this.socket) return;
65
+ if (!baseConfig.get("socket") || !this.socket) return;
66
66
  log.success("socket", "connection", "Established Socket.IO server");
67
67
  this.active = true;
68
68
  }
@@ -1 +1 @@
1
- {"version":3,"file":"socket-connector.mjs","names":["createHttpsServer","createHttpServer"],"sources":["../../../../../../../@warlock.js/core/src/connectors/socket-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { createServer as createHttpServer } from \"http\";\r\nimport { createServer as createHttpsServer } from \"https\";\r\nimport type { Server } from \"socket.io\";\r\nimport { container } from \"../container\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorName, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Shown when a project enables sockets (a `socket` config is present) but the\r\n * optional `socket.io` peer is not installed.\r\n */\r\nconst SOCKET_INSTALL_INSTRUCTIONS = `\r\nRealtime socket server requires the socket.io package.\r\nInstall it with:\r\n\r\n warlock add socket\r\n\r\nOr manually:\r\n\r\n npm install socket.io\r\n pnpm add socket.io\r\n yarn add socket.io\r\n`.trim();\r\n\r\n/**\r\n * Socket Connector\r\n * Manages Socket server (Socket.IO) lifecycle\r\n */\r\nexport class SocketConnector extends BaseConnector {\r\n public readonly name: ConnectorName = \"socket\";\r\n public readonly priority = ConnectorPriority.SOCKET;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Late;\r\n\r\n /**\r\n * Files that trigger Socket 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/socket.ts\"];\r\n\r\n protected socket?: Server;\r\n\r\n /**\r\n * Boot the connector\r\n */\r\n public async boot() {\r\n const socketConfig = config.get(\"socket\");\r\n\r\n if (!socketConfig) return;\r\n\r\n // socket.io is an optional peer — load it lazily so projects that don't use\r\n // realtime sockets never need it installed (mirrors the mail/storage drivers).\r\n let SocketServer: typeof import(\"socket.io\").Server;\r\n try {\r\n ({ Server: SocketServer } = await import(\"socket.io\"));\r\n } catch {\r\n throw new Error(SOCKET_INSTALL_INSTRUCTIONS);\r\n }\r\n\r\n log.info(\"socket\", \"connection\", \"Starting Socket.IO server\");\r\n\r\n // now we have two cases\r\n // 1. http is used, then use it\r\n // 2. http is not used, then create a new server\r\n let server;\r\n if (container.has(\"http.server\")) {\r\n const fastify = container.get(\"http.server\");\r\n server = fastify.server;\r\n } else {\r\n server = socketConfig.ssl ? createHttpsServer() : createHttpServer();\r\n server.listen(socketConfig.port);\r\n }\r\n\r\n container.set(\"socket.rawServer\", server);\r\n\r\n this.socket = new SocketServer(server, socketConfig.options);\r\n\r\n container.set(\"socket\", this.socket);\r\n }\r\n\r\n /**\r\n * Initialize Socket server\r\n */\r\n public async start(): Promise<void> {\r\n const socketConfig = config.get(\"socket\");\r\n\r\n // `this.socket` is only set by boot() once a socket config is present —\r\n // use it (not a never-assigned field) to detect a successful boot.\r\n if (!socketConfig || !this.socket) return;\r\n\r\n log.success(\"socket\", \"connection\", \"Established Socket.IO server\");\r\n\r\n this.active = true;\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 if (container.has(\"socket\")) {\r\n const socket = container.get(\"socket\");\r\n socket.close();\r\n }\r\n\r\n if (container.has(\"socket.rawServer\")) {\r\n const server = container.get(\"socket.rawServer\");\r\n server.close();\r\n }\r\n\r\n this.active = false;\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAM,8BAA8B;;;;;;;;;;;EAWlC,KAAK;;;;;AAMP,IAAa,kBAAb,cAAqC,cAAc;;;cACX;;;sBASJ,CAAC,sBAAsB;;;;;CAOzD,MAAa,OAAO;EAClB,MAAM,eAAe,OAAO,IAAI,QAAQ;EAExC,IAAI,CAAC,cAAc;EAInB,IAAI;EACJ,IAAI;GACF,CAAC,CAAE,QAAQ,gBAAiB,MAAM,OAAO;EAC3C,QAAQ;GACN,MAAM,IAAI,MAAM,2BAA2B;EAC7C;EAEA,IAAI,KAAK,UAAU,cAAc,2BAA2B;EAK5D,IAAI;EACJ,IAAI,UAAU,IAAI,aAAa,GAE7B,SADgB,UAAU,IAAI,aACf,CAAC,CAAC;OACZ;GACL,SAAS,aAAa,MAAMA,eAAkB,IAAIC,aAAiB;GACnE,OAAO,OAAO,aAAa,IAAI;EACjC;EAEA,UAAU,IAAI,oBAAoB,MAAM;EAExC,KAAK,SAAS,IAAI,aAAa,QAAQ,aAAa,OAAO;EAE3D,UAAU,IAAI,UAAU,KAAK,MAAM;CACrC;;;;CAKA,MAAa,QAAuB;EAKlC,IAAI,CAJiB,OAAO,IAAI,QAIhB,KAAK,CAAC,KAAK,QAAQ;EAEnC,IAAI,QAAQ,UAAU,cAAc,8BAA8B;EAElE,KAAK,SAAS;CAChB;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI,UAAU,IAAI,QAAQ,GAExB,AADe,UAAU,IAAI,QACxB,CAAC,CAAC,MAAM;EAGf,IAAI,UAAU,IAAI,kBAAkB,GAElC,AADe,UAAU,IAAI,kBACxB,CAAC,CAAC,MAAM;EAGf,KAAK,SAAS;CAChB;AACF"}
1
+ {"version":3,"file":"socket-connector.mjs","names":["config","createHttpsServer","createHttpServer"],"sources":["../../../../../../../@warlock.js/core/src/connectors/socket-connector.ts"],"sourcesContent":["import config from \"@mongez/config\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport { createServer as createHttpServer } from \"http\";\r\nimport { createServer as createHttpsServer } from \"https\";\r\nimport type { Server } from \"socket.io\";\r\nimport { container } from \"../container\";\r\nimport { BaseConnector } from \"./base-connector\";\r\nimport { ConnectorLifecyclePhase, ConnectorName, ConnectorPriority } from \"./types\";\r\n\r\n/**\r\n * Shown when a project enables sockets (a `socket` config is present) but the\r\n * optional `socket.io` peer is not installed.\r\n */\r\nconst SOCKET_INSTALL_INSTRUCTIONS = `\r\nRealtime socket server requires the socket.io package.\r\nInstall it with:\r\n\r\n warlock add socket\r\n\r\nOr manually:\r\n\r\n npm install socket.io\r\n pnpm add socket.io\r\n yarn add socket.io\r\n`.trim();\r\n\r\n/**\r\n * Socket Connector\r\n * Manages Socket server (Socket.IO) lifecycle\r\n */\r\nexport class SocketConnector extends BaseConnector {\r\n public readonly name: ConnectorName = \"socket\";\r\n public readonly priority = ConnectorPriority.SOCKET;\r\n public readonly lifecyclePhase = ConnectorLifecyclePhase.Late;\r\n\r\n /**\r\n * Files that trigger Socket 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/socket.ts\"];\r\n\r\n protected socket?: Server;\r\n\r\n /**\r\n * Boot the connector\r\n */\r\n public async boot() {\r\n const socketConfig = config.get(\"socket\");\r\n\r\n if (!socketConfig) return;\r\n\r\n // socket.io is an optional peer — load it lazily so projects that don't use\r\n // realtime sockets never need it installed (mirrors the mail/storage drivers).\r\n let SocketServer: typeof import(\"socket.io\").Server;\r\n try {\r\n ({ Server: SocketServer } = await import(\"socket.io\"));\r\n } catch {\r\n throw new Error(SOCKET_INSTALL_INSTRUCTIONS);\r\n }\r\n\r\n log.info(\"socket\", \"connection\", \"Starting Socket.IO server\");\r\n\r\n // now we have two cases\r\n // 1. http is used, then use it\r\n // 2. http is not used, then create a new server\r\n let server;\r\n if (container.has(\"http.server\")) {\r\n const fastify = container.get(\"http.server\");\r\n server = fastify.server;\r\n } else {\r\n server = socketConfig.ssl ? createHttpsServer() : createHttpServer();\r\n server.listen(socketConfig.port);\r\n }\r\n\r\n container.set(\"socket.rawServer\", server);\r\n\r\n this.socket = new SocketServer(server, socketConfig.options);\r\n\r\n container.set(\"socket\", this.socket);\r\n }\r\n\r\n /**\r\n * Initialize Socket server\r\n */\r\n public async start(): Promise<void> {\r\n const socketConfig = config.get(\"socket\");\r\n\r\n // `this.socket` is only set by boot() once a socket config is present —\r\n // use it (not a never-assigned field) to detect a successful boot.\r\n if (!socketConfig || !this.socket) return;\r\n\r\n log.success(\"socket\", \"connection\", \"Established Socket.IO server\");\r\n\r\n this.active = true;\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 if (container.has(\"socket\")) {\r\n const socket = container.get(\"socket\");\r\n socket.close();\r\n }\r\n\r\n if (container.has(\"socket.rawServer\")) {\r\n const server = container.get(\"socket.rawServer\");\r\n server.close();\r\n }\r\n\r\n this.active = false;\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAM,8BAA8B;;;;;;;;;;;EAWlC,KAAK;;;;;AAMP,IAAa,kBAAb,cAAqC,cAAc;;;cACX;;;sBASJ,CAAC,sBAAsB;;;;;CAOzD,MAAa,OAAO;EAClB,MAAM,eAAeA,WAAO,IAAI,QAAQ;EAExC,IAAI,CAAC,cAAc;EAInB,IAAI;EACJ,IAAI;GACF,CAAC,CAAE,QAAQ,gBAAiB,MAAM,OAAO;EAC3C,QAAQ;GACN,MAAM,IAAI,MAAM,2BAA2B;EAC7C;EAEA,IAAI,KAAK,UAAU,cAAc,2BAA2B;EAK5D,IAAI;EACJ,IAAI,UAAU,IAAI,aAAa,GAE7B,SADgB,UAAU,IAAI,aACf,CAAC,CAAC;OACZ;GACL,SAAS,aAAa,MAAMC,eAAkB,IAAIC,aAAiB;GACnE,OAAO,OAAO,aAAa,IAAI;EACjC;EAEA,UAAU,IAAI,oBAAoB,MAAM;EAExC,KAAK,SAAS,IAAI,aAAa,QAAQ,aAAa,OAAO;EAE3D,UAAU,IAAI,UAAU,KAAK,MAAM;CACrC;;;;CAKA,MAAa,QAAuB;EAKlC,IAAI,CAJiBF,WAAO,IAAI,QAIhB,KAAK,CAAC,KAAK,QAAQ;EAEnC,IAAI,QAAQ,UAAU,cAAc,8BAA8B;EAElE,KAAK,SAAS;CAChB;;;;CAKA,MAAa,WAA0B;EACrC,IAAI,CAAC,KAAK,QACR;EAGF,IAAI,UAAU,IAAI,QAAQ,GAExB,AADe,UAAU,IAAI,QACxB,CAAC,CAAC,MAAM;EAGf,IAAI,UAAU,IAAI,kBAAkB,GAElC,AADe,UAAU,IAAI,kBACxB,CAAC,CAAC,MAAM;EAGf,KAAK,SAAS;CAChB;AACF"}
@@ -0,0 +1,59 @@
1
+ import { fetchLatestVersion } from "../utils/npm-registry.mjs";
2
+ import { isNewerVersion } from "../utils/version-compare.mjs";
3
+ import { getWarlockVersion } from "../utils/framework-vesion.mjs";
4
+ import { warlockConfigManager } from "../warlock-config/warlock-config.manager.mjs";
5
+ import "../warlock-config/index.mjs";
6
+ import { colors } from "@mongez/copper";
7
+
8
+ //#region ../@warlock.js/core/src/dev-server/check-for-updates.ts
9
+ /** The package whose version represents the whole (lockstep) family. */
10
+ const CORE_PACKAGE = "@warlock.js/core";
11
+ /** Where developers can read what changed between releases. */
12
+ const CHANGELOG_URL = "https://warlock.js.org/changelog/";
13
+ /**
14
+ * Check npm for a newer `@warlock.js/core` release and, if one exists, print
15
+ * a short non-blocking notice to the terminal. Because the whole family is
16
+ * released in lockstep, core's version stands in for every `@warlock.js/*`
17
+ * package, so a single lookup is enough.
18
+ *
19
+ * Designed to be called fire-and-forget right after the dev server is ready:
20
+ * it never throws, never blocks startup, and stays silent unless there is a
21
+ * genuinely newer version to report. Automatically skipped in CI, in
22
+ * non-interactive (non-TTY) shells, and when `devServer.checkForUpdates` is
23
+ * set to `false`.
24
+ */
25
+ async function checkForFrameworkUpdate() {
26
+ try {
27
+ if (!isUpdateCheckEnabled()) return;
28
+ if ((await warlockConfigManager.get("devServer"))?.checkForUpdates === false) return;
29
+ const currentVersion = await getWarlockVersion();
30
+ const latestVersion = await fetchLatestVersion(CORE_PACKAGE);
31
+ if (!latestVersion || !isNewerVersion(latestVersion, currentVersion)) return;
32
+ printUpdateNotice(currentVersion, latestVersion);
33
+ } catch {}
34
+ }
35
+ /**
36
+ * Whether an update check should run at all in the current environment.
37
+ * Mirrors npm's own update-notifier conventions: stay quiet in CI, in
38
+ * non-interactive shells, and when explicitly opted out via env.
39
+ */
40
+ function isUpdateCheckEnabled() {
41
+ if (process.env.CI) return false;
42
+ if (process.env.NO_UPDATE_NOTIFIER) return false;
43
+ if (!process.stdout.isTTY) return false;
44
+ return true;
45
+ }
46
+ /**
47
+ * Print the "update available" notice in the dev-logger's visual style.
48
+ */
49
+ function printUpdateNotice(currentVersion, latestVersion) {
50
+ console.log();
51
+ console.log(` ${colors.yellow("⚡")} ${colors.bold("A new version of Warlock.js is available")} ${colors.dim(currentVersion)} ${colors.dim("→")} ${colors.greenBright(latestVersion)}`);
52
+ console.log(` ${colors.dim("Run")} ${colors.cyan("npx warlock update")} ${colors.dim("to update all @warlock.js packages")}`);
53
+ console.log(` ${colors.dim("Changelog")} ${colors.cyan(CHANGELOG_URL)}`);
54
+ console.log();
55
+ }
56
+
57
+ //#endregion
58
+ export { checkForFrameworkUpdate };
59
+ //# sourceMappingURL=check-for-updates.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-for-updates.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/dev-server/check-for-updates.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport { getWarlockVersion } from \"../utils/framework-vesion\";\nimport { fetchLatestVersion } from \"../utils/npm-registry\";\nimport { isNewerVersion } from \"../utils/version-compare\";\nimport { warlockConfigManager } from \"../warlock-config\";\n\n/** The package whose version represents the whole (lockstep) family. */\nconst CORE_PACKAGE = \"@warlock.js/core\";\n\n/** Where developers can read what changed between releases. */\nconst CHANGELOG_URL = \"https://warlock.js.org/changelog/\";\n\n/**\n * Check npm for a newer `@warlock.js/core` release and, if one exists, print\n * a short non-blocking notice to the terminal. Because the whole family is\n * released in lockstep, core's version stands in for every `@warlock.js/*`\n * package, so a single lookup is enough.\n *\n * Designed to be called fire-and-forget right after the dev server is ready:\n * it never throws, never blocks startup, and stays silent unless there is a\n * genuinely newer version to report. Automatically skipped in CI, in\n * non-interactive (non-TTY) shells, and when `devServer.checkForUpdates` is\n * set to `false`.\n */\nexport async function checkForFrameworkUpdate(): Promise<void> {\n try {\n if (!isUpdateCheckEnabled()) {\n return;\n }\n\n const devServerConfig = await warlockConfigManager.get(\"devServer\");\n\n if (devServerConfig?.checkForUpdates === false) {\n return;\n }\n\n const currentVersion = await getWarlockVersion();\n const latestVersion = await fetchLatestVersion(CORE_PACKAGE);\n\n if (!latestVersion || !isNewerVersion(latestVersion, currentVersion)) {\n return;\n }\n\n printUpdateNotice(currentVersion, latestVersion);\n } catch {\n // An update check is a convenience — never let it disrupt the dev server.\n }\n}\n\n/**\n * Whether an update check should run at all in the current environment.\n * Mirrors npm's own update-notifier conventions: stay quiet in CI, in\n * non-interactive shells, and when explicitly opted out via env.\n */\nfunction isUpdateCheckEnabled(): boolean {\n if (process.env.CI) {\n return false;\n }\n\n if (process.env.NO_UPDATE_NOTIFIER) {\n return false;\n }\n\n if (!process.stdout.isTTY) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Print the \"update available\" notice in the dev-logger's visual style.\n */\nfunction printUpdateNotice(currentVersion: string, latestVersion: string): void {\n console.log();\n console.log(\n ` ${colors.yellow(\"⚡\")} ${colors.bold(\"A new version of Warlock.js is available\")} ` +\n `${colors.dim(currentVersion)} ${colors.dim(\"→\")} ${colors.greenBright(latestVersion)}`,\n );\n console.log(\n ` ${colors.dim(\"Run\")} ${colors.cyan(\"npx warlock update\")} ` +\n `${colors.dim(\"to update all @warlock.js packages\")}`,\n );\n console.log(` ${colors.dim(\"Changelog\")} ${colors.cyan(CHANGELOG_URL)}`);\n console.log();\n}\n"],"mappings":";;;;;;;;;AAOA,MAAM,eAAe;;AAGrB,MAAM,gBAAgB;;;;;;;;;;;;;AActB,eAAsB,0BAAyC;CAC7D,IAAI;EACF,IAAI,CAAC,qBAAqB,GACxB;EAKF,KAAI,MAF0B,qBAAqB,IAAI,WAAW,EAE/C,EAAE,oBAAoB,OACvC;EAGF,MAAM,iBAAiB,MAAM,kBAAkB;EAC/C,MAAM,gBAAgB,MAAM,mBAAmB,YAAY;EAE3D,IAAI,CAAC,iBAAiB,CAAC,eAAe,eAAe,cAAc,GACjE;EAGF,kBAAkB,gBAAgB,aAAa;CACjD,QAAQ,CAER;AACF;;;;;;AAOA,SAAS,uBAAgC;CACvC,IAAI,QAAQ,IAAI,IACd,OAAO;CAGT,IAAI,QAAQ,IAAI,oBACd,OAAO;CAGT,IAAI,CAAC,QAAQ,OAAO,OAClB,OAAO;CAGT,OAAO;AACT;;;;AAKA,SAAS,kBAAkB,gBAAwB,eAA6B;CAC9E,QAAQ,IAAI;CACZ,QAAQ,IACN,KAAK,OAAO,OAAO,GAAG,EAAE,GAAG,OAAO,KAAK,0CAA0C,EAAE,IAC9E,OAAO,IAAI,cAAc,EAAE,GAAG,OAAO,IAAI,GAAG,EAAE,GAAG,OAAO,YAAY,aAAa,GACxF;CACA,QAAQ,IACN,QAAQ,OAAO,IAAI,KAAK,EAAE,GAAG,OAAO,KAAK,oBAAoB,EAAE,GAC1D,OAAO,IAAI,oCAAoC,GACtD;CACA,QAAQ,IAAI,QAAQ,OAAO,IAAI,WAAW,EAAE,GAAG,OAAO,KAAK,aAAa,GAAG;CAC3E,QAAQ,IAAI;AACd"}
@@ -1,3 +1,5 @@
1
+ import { Application } from "../application/application.mjs";
2
+ import "../application/index.mjs";
1
3
  import { ConnectorLifecyclePhase } from "../connectors/types.mjs";
2
4
  import { devLogReady, devLogSection, devLogWarn, devServeLog } from "./dev-logger.mjs";
3
5
  import { connectorsManager } from "../connectors/connectors-manager.mjs";
@@ -42,6 +44,11 @@ var DevelopmentServer = class {
42
44
  this.running = true;
43
45
  const duration = performance.now() - startedAt;
44
46
  devLogReady(`Development Server is ready in ${colors.greenBright(parseDuration(duration))}`);
47
+ Application.markBooted({
48
+ environment: Application.environment,
49
+ runtimeStrategy: Application.runtimeStrategy,
50
+ bootDurationMs: duration
51
+ });
45
52
  const devServerConfig = await warlockConfigManager.get("devServer");
46
53
  const generateTypings = this.options.generateTypings ?? devServerConfig?.generateTypings ?? true;
47
54
  const healthCheckers = this.options.healthCheckers ?? devServerConfig?.healthCheckers ?? true;