@zintrust/core 0.1.41 → 0.1.42

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 (193) hide show
  1. package/package.json +17 -1
  2. package/src/boot/bootstrap.js +27 -11
  3. package/src/boot/registry/runtime.d.ts.map +1 -1
  4. package/src/boot/registry/runtime.js +11 -0
  5. package/src/cli/CLI.d.ts.map +1 -1
  6. package/src/cli/CLI.js +12 -0
  7. package/src/cli/commands/ConfigCommand.d.ts.map +1 -1
  8. package/src/cli/commands/ConfigCommand.js +3 -5
  9. package/src/cli/commands/D1LearnCommand.d.ts +9 -0
  10. package/src/cli/commands/D1LearnCommand.d.ts.map +1 -0
  11. package/src/cli/commands/D1LearnCommand.js +143 -0
  12. package/src/cli/commands/D1MigrateCommand.d.ts.map +1 -1
  13. package/src/cli/commands/D1MigrateCommand.js +55 -16
  14. package/src/cli/commands/InitContainerCommand.d.ts.map +1 -1
  15. package/src/cli/commands/InitContainerCommand.js +21 -6
  16. package/src/cli/commands/InitEcosystemCommand.d.ts +6 -0
  17. package/src/cli/commands/InitEcosystemCommand.d.ts.map +1 -0
  18. package/src/cli/commands/InitEcosystemCommand.js +51 -0
  19. package/src/cli/commands/MigrateCommand.d.ts.map +1 -1
  20. package/src/cli/commands/MigrateCommand.js +78 -36
  21. package/src/cli/commands/MigrateWorkerCommand.d.ts.map +1 -1
  22. package/src/cli/commands/MigrateWorkerCommand.js +36 -2
  23. package/src/cli/commands/PutCommand.d.ts +6 -0
  24. package/src/cli/commands/PutCommand.d.ts.map +1 -0
  25. package/src/cli/commands/PutCommand.js +173 -0
  26. package/src/cli/commands/QueueRecoveryCommand.d.ts.map +1 -1
  27. package/src/cli/commands/QueueRecoveryCommand.js +113 -14
  28. package/src/cli/commands/ScheduleListCommand.d.ts +6 -0
  29. package/src/cli/commands/ScheduleListCommand.d.ts.map +1 -0
  30. package/src/cli/commands/ScheduleListCommand.js +62 -0
  31. package/src/cli/commands/ScheduleRunCommand.d.ts +6 -0
  32. package/src/cli/commands/ScheduleRunCommand.d.ts.map +1 -0
  33. package/src/cli/commands/ScheduleRunCommand.js +32 -0
  34. package/src/cli/commands/ScheduleStartCommand.d.ts +6 -0
  35. package/src/cli/commands/ScheduleStartCommand.d.ts.map +1 -0
  36. package/src/cli/commands/ScheduleStartCommand.js +40 -0
  37. package/src/cli/commands/SecretsCommand.d.ts.map +1 -1
  38. package/src/cli/commands/SecretsCommand.js +2 -2
  39. package/src/cli/commands/schedule/ScheduleCliSupport.d.ts +6 -0
  40. package/src/cli/commands/schedule/ScheduleCliSupport.d.ts.map +1 -0
  41. package/src/cli/commands/schedule/ScheduleCliSupport.js +55 -0
  42. package/src/cli/config/ConfigManager.d.ts.map +1 -1
  43. package/src/cli/config/ConfigManager.js +8 -1
  44. package/src/cli/d1/D1SqlMigrations.d.ts.map +1 -1
  45. package/src/cli/d1/D1SqlMigrations.js +11 -1
  46. package/src/cli/d1/WranglerConfig.d.ts.map +1 -1
  47. package/src/cli/d1/WranglerConfig.js +34 -2
  48. package/src/cli/services/VersionChecker.d.ts.map +1 -1
  49. package/src/cli/services/VersionChecker.js +5 -1
  50. package/src/cli/utils/DatabaseCliUtils.d.ts.map +1 -1
  51. package/src/cli/utils/DatabaseCliUtils.js +6 -1
  52. package/src/cli/utils/EnvFileLoader.d.ts.map +1 -1
  53. package/src/cli/utils/EnvFileLoader.js +33 -14
  54. package/src/cli.d.ts +5 -0
  55. package/src/cli.d.ts.map +1 -0
  56. package/src/cli.js +4 -0
  57. package/src/collections/index.d.ts +2 -2
  58. package/src/collections/index.d.ts.map +1 -1
  59. package/src/collections/index.js +1 -1
  60. package/src/common/RemoteSignedJson.d.ts.map +1 -1
  61. package/src/common/RemoteSignedJson.js +49 -23
  62. package/src/common/utility.d.ts.map +1 -1
  63. package/src/common/utility.js +2 -6
  64. package/src/config/cloudflare.d.ts.map +1 -1
  65. package/src/config/cloudflare.js +19 -8
  66. package/src/config/env.js +2 -2
  67. package/src/helper/index.d.ts +225 -0
  68. package/src/helper/index.d.ts.map +1 -0
  69. package/src/helper/index.js +347 -0
  70. package/src/index.d.ts +3 -6
  71. package/src/index.d.ts.map +1 -1
  72. package/src/index.js +7 -9
  73. package/src/migrations/MigrationDiscovery.d.ts.map +1 -1
  74. package/src/migrations/MigrationDiscovery.js +2 -1
  75. package/src/orm/DatabaseAdapter.d.ts +1 -0
  76. package/src/orm/DatabaseAdapter.d.ts.map +1 -1
  77. package/src/orm/SchemaStatemenWriter.d.ts +15 -0
  78. package/src/orm/SchemaStatemenWriter.d.ts.map +1 -0
  79. package/src/orm/SchemaStatemenWriter.js +78 -0
  80. package/src/orm/adapters/D1Adapter.d.ts.map +1 -1
  81. package/src/orm/adapters/D1Adapter.js +52 -2
  82. package/src/orm/adapters/D1RemoteAdapter.d.ts.map +1 -1
  83. package/src/orm/adapters/D1RemoteAdapter.js +137 -89
  84. package/src/orm/adapters/MySQLProxyAdapter.d.ts.map +1 -1
  85. package/src/orm/adapters/MySQLProxyAdapter.js +100 -81
  86. package/src/orm/adapters/PostgreSQLProxyAdapter.d.ts.map +1 -1
  87. package/src/orm/adapters/PostgreSQLProxyAdapter.js +26 -10
  88. package/src/orm/adapters/SqlProxyAdapterUtils.d.ts.map +1 -1
  89. package/src/orm/adapters/SqlProxyAdapterUtils.js +2 -1
  90. package/src/orm/adapters/SqlProxyRegistryMode.d.ts +12 -0
  91. package/src/orm/adapters/SqlProxyRegistryMode.d.ts.map +1 -0
  92. package/src/orm/adapters/SqlProxyRegistryMode.js +24 -0
  93. package/src/orm/adapters/SqlServerProxyAdapter.d.ts +3 -0
  94. package/src/orm/adapters/SqlServerProxyAdapter.d.ts.map +1 -1
  95. package/src/orm/adapters/SqlServerProxyAdapter.js +125 -117
  96. package/src/orm/migrations/MigrationStore.js +1 -1
  97. package/src/proxy/ProxyRequestParsing.d.ts +9 -0
  98. package/src/proxy/ProxyRequestParsing.d.ts.map +1 -0
  99. package/src/proxy/ProxyRequestParsing.js +16 -0
  100. package/src/proxy/RequestValidator.d.ts.map +1 -1
  101. package/src/proxy/RequestValidator.js +2 -1
  102. package/src/proxy/SigningService.js +2 -2
  103. package/src/proxy/SqlProxyDbOverrides.d.ts +17 -0
  104. package/src/proxy/SqlProxyDbOverrides.d.ts.map +1 -0
  105. package/src/proxy/SqlProxyDbOverrides.js +1 -0
  106. package/src/proxy/SqlProxyServerDeps.d.ts +12 -0
  107. package/src/proxy/SqlProxyServerDeps.d.ts.map +1 -0
  108. package/src/proxy/SqlProxyServerDeps.js +9 -0
  109. package/src/proxy/StatementPayloadValidator.d.ts +13 -0
  110. package/src/proxy/StatementPayloadValidator.d.ts.map +1 -0
  111. package/src/proxy/StatementPayloadValidator.js +18 -0
  112. package/src/proxy/StatementRegistryLoader.d.ts +2 -0
  113. package/src/proxy/StatementRegistryLoader.d.ts.map +1 -0
  114. package/src/proxy/StatementRegistryLoader.js +36 -0
  115. package/src/proxy/StatementRegistryResolver.d.ts +15 -0
  116. package/src/proxy/StatementRegistryResolver.d.ts.map +1 -0
  117. package/src/proxy/StatementRegistryResolver.js +34 -0
  118. package/src/proxy/d1/ZintrustD1Proxy.d.ts +2 -1
  119. package/src/proxy/d1/ZintrustD1Proxy.d.ts.map +1 -1
  120. package/src/proxy/d1/ZintrustD1Proxy.js +2 -1
  121. package/src/proxy/isMutatingSql.d.ts +2 -0
  122. package/src/proxy/isMutatingSql.d.ts.map +1 -0
  123. package/src/proxy/isMutatingSql.js +12 -0
  124. package/src/proxy/kv/ZintrustKvProxy.d.ts +2 -1
  125. package/src/proxy/kv/ZintrustKvProxy.d.ts.map +1 -1
  126. package/src/proxy/kv/ZintrustKvProxy.js +2 -1
  127. package/src/proxy/mysql/MySqlProxyServer.d.ts +2 -8
  128. package/src/proxy/mysql/MySqlProxyServer.d.ts.map +1 -1
  129. package/src/proxy/mysql/MySqlProxyServer.js +84 -51
  130. package/src/proxy/postgres/PostgresProxyServer.d.ts +2 -8
  131. package/src/proxy/postgres/PostgresProxyServer.d.ts.map +1 -1
  132. package/src/proxy/postgres/PostgresProxyServer.js +86 -48
  133. package/src/proxy/smtp/SmtpProxyServer.d.ts.map +1 -1
  134. package/src/proxy/smtp/SmtpProxyServer.js +6 -5
  135. package/src/proxy/sqlserver/SqlServerProxyServer.d.ts +2 -8
  136. package/src/proxy/sqlserver/SqlServerProxyServer.d.ts.map +1 -1
  137. package/src/proxy/sqlserver/SqlServerProxyServer.js +84 -49
  138. package/src/proxy.d.ts +4 -0
  139. package/src/proxy.d.ts.map +1 -0
  140. package/src/proxy.js +3 -0
  141. package/src/scheduler/Schedule.d.ts +36 -0
  142. package/src/scheduler/Schedule.d.ts.map +1 -0
  143. package/src/scheduler/Schedule.js +197 -0
  144. package/src/scheduler/ScheduleHttpGateway.d.ts +8 -0
  145. package/src/scheduler/ScheduleHttpGateway.d.ts.map +1 -0
  146. package/src/scheduler/ScheduleHttpGateway.js +196 -0
  147. package/src/scheduler/ScheduleRunner.d.ts +6 -0
  148. package/src/scheduler/ScheduleRunner.d.ts.map +1 -1
  149. package/src/scheduler/ScheduleRunner.js +166 -29
  150. package/src/scheduler/SchedulerRuntime.d.ts +15 -0
  151. package/src/scheduler/SchedulerRuntime.d.ts.map +1 -0
  152. package/src/scheduler/SchedulerRuntime.js +79 -0
  153. package/src/scheduler/cron/Cron.d.ts +19 -0
  154. package/src/scheduler/cron/Cron.d.ts.map +1 -0
  155. package/src/scheduler/cron/Cron.js +200 -0
  156. package/src/scheduler/leader/SchedulerLeader.d.ts +14 -0
  157. package/src/scheduler/leader/SchedulerLeader.d.ts.map +1 -0
  158. package/src/scheduler/leader/SchedulerLeader.js +187 -0
  159. package/src/scheduler/state/ScheduleStateStore.d.ts +27 -0
  160. package/src/scheduler/state/ScheduleStateStore.d.ts.map +1 -0
  161. package/src/scheduler/state/ScheduleStateStore.js +27 -0
  162. package/src/scheduler/types.d.ts +10 -0
  163. package/src/scheduler/types.d.ts.map +1 -1
  164. package/src/schedules/index.d.ts +1 -0
  165. package/src/schedules/index.d.ts.map +1 -1
  166. package/src/schedules/index.js +1 -0
  167. package/src/schedules/job-tracking-cleanup.d.ts +4 -0
  168. package/src/schedules/job-tracking-cleanup.d.ts.map +1 -0
  169. package/src/schedules/job-tracking-cleanup.js +116 -0
  170. package/src/schedules/log-cleanup.d.ts +1 -2
  171. package/src/schedules/log-cleanup.d.ts.map +1 -1
  172. package/src/schedules/log-cleanup.js +12 -15
  173. package/src/security/Sanitizer.d.ts.map +1 -1
  174. package/src/security/Sanitizer.js +1 -9
  175. package/src/security/SignedRequest.d.ts.map +1 -1
  176. package/src/security/SignedRequest.js +2 -2
  177. package/src/templates/docker/docker-compose.ecosystem.yml.tpl +301 -0
  178. package/src/templates/docker/docker-compose.schedules.yml.tpl +84 -0
  179. package/src/templates/project/basic/app/Schedules/index.ts.tpl +0 -0
  180. package/src/templates/project/basic/config/database.ts.tpl +1 -1
  181. package/src/toolkit/Secrets/Manifest.d.ts.map +1 -1
  182. package/src/toolkit/Secrets/Manifest.js +5 -7
  183. package/src/tools/mail/drivers/Smtp.d.ts.map +1 -1
  184. package/src/tools/mail/drivers/Smtp.js +7 -1
  185. package/src/tools/queue/JobReconciliationRunner.d.ts.map +1 -1
  186. package/src/tools/queue/JobReconciliationRunner.js +7 -39
  187. package/src/tools/queue/JobRecoveryDaemon.d.ts.map +1 -1
  188. package/src/tools/queue/JobRecoveryDaemon.js +116 -18
  189. package/src/tools/queue/JobStateTracker.d.ts +10 -1
  190. package/src/tools/queue/JobStateTracker.d.ts.map +1 -1
  191. package/src/tools/queue/JobStateTracker.js +24 -2
  192. package/src/tools/queue/JobStateTrackerDbPersistence.d.ts.map +1 -1
  193. package/src/tools/queue/JobStateTrackerDbPersistence.js +93 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/core",
3
- "version": "0.1.41",
3
+ "version": "0.1.42",
4
4
  "description": "Production-grade TypeScript backend framework for JavaScript",
5
5
  "homepage": "https://zintrust.com",
6
6
  "repository": {
@@ -22,6 +22,22 @@
22
22
  "types": "./src/start.d.ts",
23
23
  "import": "./src/start.js"
24
24
  },
25
+ "./cli": {
26
+ "types": "./src/cli.d.ts",
27
+ "import": "./src/cli.js"
28
+ },
29
+ "./proxy": {
30
+ "types": "./src/proxy.d.ts",
31
+ "import": "./src/proxy.js"
32
+ },
33
+ "./collections": {
34
+ "types": "./src/collections/index.d.ts",
35
+ "import": "./src/collections/index.js"
36
+ },
37
+ "./helper": {
38
+ "types": "./src/helper/index.d.ts",
39
+ "import": "./src/helper/index.js"
40
+ },
25
41
  "./node": {
26
42
  "types": "./src/node.d.ts",
27
43
  "import": "./src/node.js"
@@ -37,29 +37,45 @@ const logBootstrapErrorDetails = (error) => {
37
37
  // best-effort logging
38
38
  }
39
39
  };
40
- const startSchedulesIfNeeded = async (app) => {
40
+ const startSchedulesIfNeeded = async (application) => {
41
41
  try {
42
+ if (Env.getBool('SCHEDULES_ENABLED', false) === false)
43
+ return;
42
44
  const runtime = appConfig.detectRuntime();
43
45
  if (runtime !== 'nodejs' && runtime !== 'fargate')
44
46
  return;
45
- const { create: createScheduleRunner } = await import('../scheduler/ScheduleRunner.js');
46
- const schedules = await import('../schedules/index.js');
47
- const runner = createScheduleRunner();
48
- for (const schedule of Object.values(schedules)) {
49
- // Each schedule is expected to export a default ISchedule
50
- // @ts-ignore
51
- runner.register(schedule);
47
+ const { SchedulerRuntime } = await import('../scheduler/SchedulerRuntime.js');
48
+ const coreSchedules = await import('../schedules/index.js');
49
+ let appSchedules = {};
50
+ try {
51
+ const appSchedulesModuleId = '@app/' + 'Schedules';
52
+ appSchedules = (await import(appSchedulesModuleId));
53
+ }
54
+ catch {
55
+ /* v8 ignore next */
56
+ appSchedules = {};
52
57
  }
53
- runner.start();
58
+ const isSchedule = (value) => {
59
+ if (value === null || value === undefined || typeof value !== 'object')
60
+ return false;
61
+ return ('name' in value &&
62
+ typeof value.name === 'string' &&
63
+ value.name.trim().length > 0);
64
+ };
65
+ const coreScheduleEntries = Object.values(coreSchedules).filter(isSchedule);
66
+ const appScheduleEntries = Object.values(appSchedules).filter(isSchedule);
67
+ SchedulerRuntime.registerMany(coreScheduleEntries, 'core');
68
+ SchedulerRuntime.registerMany(appScheduleEntries, 'app');
69
+ SchedulerRuntime.start();
54
70
  // Add shutdown hook to stop schedules gracefully
55
- const shutdownManager = app.getContainer().get('shutdownManager');
71
+ const shutdownManager = application.getContainer().get('shutdownManager');
56
72
  if ((typeof shutdownManager === 'object' || typeof shutdownManager === 'function') &&
57
73
  shutdownManager !== null &&
58
74
  'add' in shutdownManager &&
59
75
  typeof shutdownManager.add === 'function') {
60
76
  shutdownManager.add(async () => {
61
77
  const scheduleTimeoutMs = Env.getInt('SCHEDULE_SHUTDOWN_TIMEOUT_MS', 30000);
62
- await runner.stop(scheduleTimeoutMs);
78
+ await SchedulerRuntime.stop(scheduleTimeoutMs);
63
79
  });
64
80
  }
65
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../src/boot/registry/runtime.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAOvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AA+I9C,eAAO,MAAM,8BAA8B,GAAI,iBAAiB,gBAAgB,KAAG,IA4BlF,CAAC;AA+KF,eAAO,MAAM,eAAe,GAAI,QAAQ;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,EAAE,gBAAgB,CAAC;IAClC,SAAS,EAAE,MAAM,OAAO,CAAC;IACzB,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACrC,KAAG;IAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAsE7D,CAAC"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../src/boot/registry/runtime.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAOvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AA+I9C,eAAO,MAAM,8BAA8B,GAAI,iBAAiB,gBAAgB,KAAG,IA4BlF,CAAC;AAyLF,eAAO,MAAM,eAAe,GAAI,QAAQ;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,EAAE,gBAAgB,CAAC;IAClC,SAAS,EAAE,MAAM,OAAO,CAAC;IACzB,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACrC,KAAG;IAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAuE7D,CAAC"}
@@ -293,6 +293,16 @@ const initializeQueueHttpGateway = async (router) => {
293
293
  Logger.warn('Failed to register Queue HTTP gateway routes', error);
294
294
  }
295
295
  };
296
+ const initializeScheduleHttpGateway = async (router) => {
297
+ try {
298
+ const { ScheduleHttpGateway } = await import('../../scheduler/ScheduleHttpGateway.js');
299
+ ScheduleHttpGateway.create().registerRoutes(router);
300
+ Logger.info('Schedule HTTP gateway route registered at /api/_sys/schedule/rpc');
301
+ }
302
+ catch (error) {
303
+ Logger.warn('Failed to register Schedule HTTP gateway routes', error);
304
+ }
305
+ };
296
306
  export const createLifecycle = (params) => {
297
307
  const boot = async () => {
298
308
  if (params.getBooted())
@@ -324,6 +334,7 @@ export const createLifecycle = (params) => {
324
334
  await initializeWorkers(params.router);
325
335
  await initializeQueueMonitor(params.router);
326
336
  await initializeQueueHttpGateway(params.router);
337
+ await initializeScheduleHttpGateway(params.router);
327
338
  }
328
339
  // Register service providers
329
340
  // Bootstrap services
@@ -1 +1 @@
1
- {"version":3,"file":"CLI.d.ts","sourceRoot":"","sources":["../../../src/cli/CLI.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA2DH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,MAAM,WAAW,IAAI;IACnB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,UAAU,IAAI,OAAO,CAAC;CACvB;AAiPD;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG;cACJ,IAAI;EAed,CAAC"}
1
+ {"version":3,"file":"CLI.d.ts","sourceRoot":"","sources":["../../../src/cli/CLI.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,MAAM,WAAW,IAAI;IACnB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,UAAU,IAAI,OAAO,CAAC;CACvB;AAuPD;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG;cACJ,IAAI;EAed,CAAC"}
package/src/cli/CLI.js CHANGED
@@ -8,6 +8,7 @@ import { ConfigCommand } from './commands/ConfigCommand.js';
8
8
  import { ContainerProxiesCommand } from './commands/ContainerProxiesCommand.js';
9
9
  import { ContainerWorkersCommand } from './commands/ContainerWorkersCommand.js';
10
10
  import { AddMigrationCommand, CreateCommand, CreateMigrationCommand, } from './commands/CreateCommand.js';
11
+ import { D1LearnCommand } from './commands/D1LearnCommand.js';
11
12
  import { D1MigrateCommand } from './commands/D1MigrateCommand.js';
12
13
  import { DbSeedCommand } from './commands/DbSeedCommand.js';
13
14
  import { DebugCommand } from './commands/DebugCommand.js';
@@ -17,6 +18,7 @@ import { DeployContainerWorkersCommand } from './commands/DeployContainerWorkers
17
18
  import { DoctorArchitectureCommand } from './commands/DoctorArchitectureCommand.js';
18
19
  import { FixCommand } from './commands/FixCommand.js';
19
20
  import { InitContainerCommand } from './commands/InitContainerCommand.js';
21
+ import { InitEcosystemCommand } from './commands/InitEcosystemCommand.js';
20
22
  import { InitProducerCommand } from './commands/InitProducerCommand.js';
21
23
  import { InitProxyCommand } from './commands/InitProxyCommand.js';
22
24
  import { JwtDevCommand } from './commands/JwtDevCommand.js';
@@ -34,12 +36,16 @@ import { PostgresProxyCommand } from './commands/PostgresProxyCommand.js';
34
36
  import { PrepareCommand } from './commands/PrepareCommand.js';
35
37
  import { ProxyCommand } from './commands/ProxyCommand.js';
36
38
  import { PublishCommand } from './commands/PublishCommand.js';
39
+ import { PutCommand } from './commands/PutCommand.js';
37
40
  import { QACommand } from './commands/QACommand.js';
38
41
  import { QueueCommand } from './commands/QueueCommand.js';
39
42
  import { QueueRecoveryCommand } from './commands/QueueRecoveryCommand.js';
40
43
  import { RedisProxyCommand } from './commands/RedisProxyCommand.js';
41
44
  import { ResourceControlCommand } from './commands/ResourceControlCommand.js';
42
45
  import { RoutesCommand } from './commands/RoutesCommand.js';
46
+ import { ScheduleListCommand } from './commands/ScheduleListCommand.js';
47
+ import { ScheduleRunCommand } from './commands/ScheduleRunCommand.js';
48
+ import { ScheduleStartCommand } from './commands/ScheduleStartCommand.js';
43
49
  import { SecretsCommand } from './commands/SecretsCommand.js';
44
50
  import { SimulateCommand } from './commands/SimulateCommand.js';
45
51
  import { SmtpProxyCommand } from './commands/SmtpProxyCommand.js';
@@ -71,6 +77,7 @@ const buildCommandRegistry = () => {
71
77
  InitContainerCommand.create(),
72
78
  InitProxyCommand.create(),
73
79
  InitProducerCommand.create(),
80
+ InitEcosystemCommand.create(),
74
81
  DoctorArchitectureCommand.create(),
75
82
  AddCommand.create(),
76
83
  CreateCommand.create(),
@@ -79,12 +86,16 @@ const buildCommandRegistry = () => {
79
86
  StartCommand.create(),
80
87
  QueueCommand.create(),
81
88
  QueueRecoveryCommand.create(),
89
+ ScheduleListCommand.create(),
90
+ ScheduleRunCommand.create(),
91
+ ScheduleStartCommand.create(),
82
92
  BroadcastWorkCommand.create(),
83
93
  NotificationWorkCommand.create(),
84
94
  ResourceControlCommand,
85
95
  MigrateWorkerCommand.create(),
86
96
  MigrateCommand.create(),
87
97
  DbSeedCommand.create(),
98
+ D1LearnCommand.create(),
88
99
  D1MigrateCommand.create(),
89
100
  DebugCommand.create(),
90
101
  SecretsCommand.create(),
@@ -93,6 +104,7 @@ const buildCommandRegistry = () => {
93
104
  ContainerProxiesCommand.create(),
94
105
  PluginCommand.create(),
95
106
  PublishCommand.create(),
107
+ PutCommand.create(),
96
108
  DeployCommand.create(),
97
109
  DeployContainerWorkersCommand.create(),
98
110
  DeployContainerProxiesCommand.create(),
@@ -1 +1 @@
1
- {"version":3,"file":"ConfigCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/ConfigCommand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAmVrE;;GAEG;AACH,eAAO,MAAM,aAAa;IACxB;;OAEG;cACO,YAAY;EAsEtB,CAAC"}
1
+ {"version":3,"file":"ConfigCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/ConfigCommand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAiVrE;;GAEG;AACH,eAAO,MAAM,aAAa;IACxB;;OAEG;cACO,YAAY;EAsEtB,CAAC"}
@@ -8,6 +8,7 @@ import { ConfigValidator } from '../config/ConfigValidator.js';
8
8
  import { ErrorHandler } from '../ErrorHandler.js';
9
9
  import { PromptHelper } from '../PromptHelper.js';
10
10
  import { Logger } from '../../config/logger.js';
11
+ import { isArray, isObject } from '../../helper/index.js';
11
12
  import chalk from 'chalk';
12
13
  const addOptions = (command) => {
13
14
  command.argument('[action]', 'Action: get, set, list, reset, edit, export');
@@ -225,9 +226,8 @@ const handleEdit = async (cmd, manager) => {
225
226
  const handleExport = (cmd, manager) => {
226
227
  cmd.info(typeof manager.export === 'function' ? manager.export() : '{}');
227
228
  };
228
- const isUnknownArray = (value) => Array.isArray(value);
229
229
  const getArg = (args, index) => {
230
- if (!isUnknownArray(args))
230
+ if (!isArray(args))
231
231
  return undefined;
232
232
  const value = args[index];
233
233
  return typeof value === 'string' ? value : undefined;
@@ -236,9 +236,7 @@ const executeConfig = async (cmd, options) => {
236
236
  const typedCmd = cmd;
237
237
  const command = cmd.getCommand();
238
238
  const toRecord = (value) => {
239
- if (value === null || typeof value !== 'object' || Array.isArray(value))
240
- return {};
241
- return value;
239
+ return isObject(value) ? value : {};
242
240
  };
243
241
  const commandOpts = typeof command.opts === 'function' ? toRecord(command.opts()) : {};
244
242
  const mergedOptions = {
@@ -0,0 +1,9 @@
1
+ /**
2
+ * D1 Learn Command
3
+ * Runs a command in "learning mode" to capture D1 SQL statements for the registry.
4
+ */
5
+ import { type IBaseCommand } from '../BaseCommand';
6
+ export declare const D1LearnCommand: Readonly<{
7
+ create(): IBaseCommand;
8
+ }>;
9
+ //# sourceMappingURL=D1LearnCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"D1LearnCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/D1LearnCommand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAgGvF,eAAO,MAAM,cAAc;cACf,YAAY;EAiEtB,CAAC"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * D1 Learn Command
3
+ * Runs a command in "learning mode" to capture D1 SQL statements for the registry.
4
+ */
5
+ import { BaseCommand } from '../BaseCommand.js';
6
+ import { Logger } from '../../config/logger.js';
7
+ import { ErrorFactory } from '../../exceptions/ZintrustError.js';
8
+ import { isNonEmptyString, isObject } from '../../helper/index.js';
9
+ import * as fs from '../../node-singletons/fs.js';
10
+ import { StatementRegistryBuild } from '../../orm/SchemaStatemenWriter.js';
11
+ import { spawn } from 'node:child_process';
12
+ const LEARN_FILE = 'storage/d1-learned.jsonl';
13
+ const isRecord = (value) => isObject(value);
14
+ const coerceStringRegistry = (value) => {
15
+ if (!isRecord(value))
16
+ return {};
17
+ const out = {};
18
+ for (const [k, v] of Object.entries(value)) {
19
+ if (isNonEmptyString(v))
20
+ out[k] = v;
21
+ }
22
+ return out;
23
+ };
24
+ const readExistingRegistryFile = async (outputFile) => {
25
+ try {
26
+ await fs.stat(outputFile);
27
+ const existingContent = await fs.readFile(outputFile, 'utf-8');
28
+ const existingJson = JSON.parse(existingContent);
29
+ if (isRecord(existingJson) && 'queries' in existingJson) {
30
+ return coerceStringRegistry(existingJson['queries']);
31
+ }
32
+ return coerceStringRegistry(existingJson);
33
+ }
34
+ catch {
35
+ return {};
36
+ }
37
+ };
38
+ const cleanLearnFile = async () => {
39
+ try {
40
+ await fs.rm(LEARN_FILE, { force: true });
41
+ }
42
+ catch {
43
+ // ignore
44
+ }
45
+ };
46
+ const parseLearnedFile = async () => {
47
+ try {
48
+ const content = await fs.readFile(LEARN_FILE, 'utf-8');
49
+ return StatementRegistryBuild.fromJsonl(content);
50
+ }
51
+ catch (err) {
52
+ if (err.code === 'ENOENT') {
53
+ return {};
54
+ }
55
+ throw err;
56
+ }
57
+ };
58
+ const runLearner = async (cmd, args) => {
59
+ return new Promise((resolve, reject) => {
60
+ Logger.info(`Starting learner: ${cmd} ${args.join(' ')}`);
61
+ Logger.info(`Capturing queries to ${LEARN_FILE}...`);
62
+ const child = spawn(cmd, args, {
63
+ stdio: 'inherit',
64
+ env: {
65
+ ...process.env,
66
+ ZT_D1_LEARN_FILE: LEARN_FILE,
67
+ D1_REMOTE_MODE: 'sql',
68
+ },
69
+ });
70
+ child.on('close', (code) => {
71
+ // Allow code 0 or 1 (tests fail sometimes but still run queries)
72
+ // Actually, we resolve regardless so we can harvest what ran
73
+ if (code === 0) {
74
+ resolve();
75
+ }
76
+ else {
77
+ // We log error but resolve to process partial results
78
+ Logger.error(`Command exited with code ${code}`);
79
+ resolve();
80
+ }
81
+ });
82
+ child.on('error', (err) => {
83
+ reject(err);
84
+ });
85
+ });
86
+ };
87
+ export const D1LearnCommand = Object.freeze({
88
+ create() {
89
+ const cmd = BaseCommand.create({
90
+ name: 'd1:learn',
91
+ description: 'Run a command to learn D1 queries and generate a statement registry',
92
+ addOptions: (c) => {
93
+ c.argument('<command>', 'The command to run (e.g. "npm test")')
94
+ .option('-o, --output <file>', 'Output JSON file (default: d1-statements.json)')
95
+ .option('-a, --append', 'Append to existing output file instead of overwriting');
96
+ },
97
+ async execute(options) {
98
+ const learnOptions = options;
99
+ // In BaseCommand, positional arguments are stored in options.args array
100
+ // We defined .argument('<command>') so it's the first element.
101
+ const commandStr = options.args && options.args.length > 0 ? options.args[0] : '';
102
+ if (commandStr === '') {
103
+ Logger.error('Missing command argument');
104
+ return;
105
+ }
106
+ const outputFile = learnOptions.output ?? 'd1-statements.json';
107
+ const append = learnOptions.append === true;
108
+ // 1. Prepare
109
+ await cleanLearnFile();
110
+ const parts = commandStr.split(' ');
111
+ const cmdExe = parts[0];
112
+ const args = parts.slice(1);
113
+ // 2. Run command
114
+ try {
115
+ await runLearner(cmdExe, args);
116
+ }
117
+ catch (err) {
118
+ throw ErrorFactory.createCliError(`Learner failed to start: ${err.message}`);
119
+ }
120
+ // 3. Process results
121
+ const learned = await parseLearnedFile();
122
+ const count = Object.keys(learned).length;
123
+ if (count === 0) {
124
+ Logger.warn('No D1 queries were captured.');
125
+ return;
126
+ }
127
+ Logger.info(`Captured ${count} unique queries.`);
128
+ // 4. Merge with existing if needed
129
+ let finalMap = learned;
130
+ if (append) {
131
+ const existingMap = await readExistingRegistryFile(outputFile);
132
+ finalMap = StatementRegistryBuild.merge(existingMap, learned);
133
+ }
134
+ // 5. Output
135
+ // One-line JSON is easiest to paste into `wrangler secret put ZT_D1_STATEMENTS_JSON`.
136
+ const outputContent = StatementRegistryBuild.toStatementsJson(finalMap);
137
+ await fs.writeFile(outputFile, outputContent);
138
+ Logger.info(`Registry written to ${outputFile}`);
139
+ },
140
+ });
141
+ return cmd;
142
+ },
143
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"D1MigrateCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/D1MigrateCommand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAyDrE;;;GAGG;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB;IAC3B;;OAEG;cACO,YAAY;EAwBtB,CAAC"}
1
+ {"version":3,"file":"D1MigrateCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/D1MigrateCommand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,kBAAkB,CAAC;AA8GrE;;;GAGG;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB;IAC3B;;OAEG;cACO,YAAY;EAyBtB,CAAC"}
@@ -1,9 +1,13 @@
1
1
  import { BaseCommand } from '../BaseCommand.js';
2
+ import { D1SqlMigrations } from '../d1/D1SqlMigrations.js';
3
+ import { WranglerConfig } from '../d1/WranglerConfig.js';
2
4
  import { WranglerD1 } from '../d1/WranglerD1.js';
3
5
  import { resolveNpmPath } from '../../common/index.js';
4
6
  import { appConfig } from '../../config/app.js';
7
+ import { databaseConfig } from '../../config/database.js';
5
8
  import { Logger } from '../../config/logger.js';
6
9
  import { ErrorFactory } from '../../exceptions/ZintrustError.js';
10
+ import * as path from '../../node-singletons/path.js';
7
11
  const RESOLVED_VOID = Promise.resolve();
8
12
  const runWrangler = async (cmd, args) => {
9
13
  // Back-compat entrypoint for tests; we only use this for D1 migrations apply.
@@ -13,30 +17,64 @@ const runWrangler = async (cmd, args) => {
13
17
  await RESOLVED_VOID;
14
18
  return WranglerD1.applyMigrations({ cmd, dbName, isLocal });
15
19
  };
16
- const executeD1Migrate = async (cmd, options) => {
20
+ const getDbName = (options) => {
21
+ const value = options['database'];
22
+ return typeof value === 'string' && value.trim() !== '' ? value : 'zintrust_db';
23
+ };
24
+ const buildExecutionContext = (options) => {
25
+ const isWorkerCommand = process.argv.includes('d1:migrate:worker');
17
26
  const isLocal = options['local'] === true || options['remote'] !== true;
18
- const dbName = typeof options['database'] === 'string' && options['database'].trim() !== ''
19
- ? options['database']
20
- : 'zintrust_db';
21
- cmd.info(`Running D1 migrations for ${dbName} (${isLocal ? 'local' : 'remote'})...`);
27
+ const dbName = getDbName(options);
28
+ const projectRoot = process.cwd();
29
+ const migrationsRelDir = isWorkerCommand
30
+ ? path.join('database', 'migrations', 'd1')
31
+ : WranglerConfig.getD1MigrationsDir(projectRoot, dbName);
32
+ const sourceMigrationsDir = isWorkerCommand
33
+ ? path.join('packages', 'workers', 'migrations')
34
+ : databaseConfig.migrations.directory;
35
+ return {
36
+ isLocal,
37
+ dbName,
38
+ projectRoot,
39
+ migrationsRelDir,
40
+ sourceMigrationsDir,
41
+ outputDir: path.join(projectRoot, migrationsRelDir),
42
+ };
43
+ };
44
+ const handleMigrationError = (cmd, error) => {
45
+ Logger.error('D1 Migration failed', error);
46
+ ErrorFactory.createCliError('D1 Migration failed', error);
47
+ const err = error;
48
+ if (err.stdout !== undefined && err.stdout.length > 0)
49
+ cmd.info(err.stdout.toString());
50
+ if (err.stderr !== undefined && err.stderr.length > 0) {
51
+ const stderr = err.stderr.toString();
52
+ Logger.error('Wrangler stderr', stderr);
53
+ ErrorFactory.createCliError('Wrangler stderr', stderr);
54
+ }
55
+ throw error;
56
+ };
57
+ const executeD1Migrate = async (cmd, options) => {
58
+ const ctx = buildExecutionContext(options);
59
+ cmd.info(`Running D1 migrations for ${ctx.dbName} (${ctx.isLocal ? 'local' : 'remote'})...`);
60
+ cmd.info(`Generating D1 SQL migrations into ${ctx.migrationsRelDir}...`);
22
61
  await RESOLVED_VOID;
23
62
  try {
24
- const output = WranglerD1.applyMigrations({ cmd, dbName, isLocal });
63
+ const generated = await D1SqlMigrations.compileAndWrite({
64
+ projectRoot: ctx.projectRoot,
65
+ globalDir: ctx.sourceMigrationsDir,
66
+ extension: databaseConfig.migrations.extension,
67
+ includeGlobal: true,
68
+ outputDir: ctx.outputDir,
69
+ });
70
+ cmd.info(`Generated ${generated.length} SQL migration file(s).`);
71
+ const output = WranglerD1.applyMigrations({ cmd, dbName: ctx.dbName, isLocal: ctx.isLocal });
25
72
  if (output !== '')
26
73
  cmd.info(output);
27
74
  cmd.info('✓ D1 migrations completed successfully');
28
75
  }
29
76
  catch (error) {
30
- Logger.error('D1 Migration failed', error);
31
- ErrorFactory.createCliError('D1 Migration failed', error);
32
- const err = error;
33
- if (err.stdout !== undefined && err.stdout.length > 0)
34
- cmd.info(err.stdout.toString());
35
- if (err.stderr !== undefined && err.stderr.length > 0)
36
- Logger.error('Wrangler stderr', err.stderr.toString());
37
- if (err.stderr !== undefined && err.stderr.length > 0)
38
- ErrorFactory.createCliError('Wrangler stderr', err.stderr.toString());
39
- throw error;
77
+ handleMigrationError(cmd, error);
40
78
  }
41
79
  };
42
80
  /**
@@ -60,6 +98,7 @@ export const D1MigrateCommand = Object.freeze({
60
98
  const cmd = BaseCommand.create({
61
99
  name: 'd1:migrate',
62
100
  description: 'Run Cloudflare D1 migrations',
101
+ aliases: ['d1:migrate:worker'],
63
102
  addOptions,
64
103
  execute: async (options) => executeD1Migrate(cmd, options),
65
104
  });
@@ -1 +1 @@
1
- {"version":3,"file":"InitContainerCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/InitContainerCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAoNlE,eAAO,MAAM,oBAAoB;cACrB,YAAY;EAkBtB,CAAC"}
1
+ {"version":3,"file":"InitContainerCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/InitContainerCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAmOlE,eAAO,MAAM,oBAAoB;cACrB,YAAY;EAkBtB,CAAC"}
@@ -76,6 +76,22 @@ services:
76
76
  - DB_DATABASE_MYSQL=\${DB_DATABASE_MYSQL:-zintrust}
77
77
  - DB_USERNAME_MYSQL=\${DB_USERNAME_MYSQL:-zintrust}
78
78
  - DB_PASSWORD_MYSQL=\${DB_PASSWORD_MYSQL:-secret}
79
+
80
+ # Cloudflare D1
81
+ - D1_DATABASE_ID=\${D1_DATABASE_ID}
82
+ - D1_ACCOUNT_ID=\${D1_ACCOUNT_ID}
83
+ - D1_API_TOKEN=\${D1_API_TOKEN}
84
+ - D1_REMOTE_URL=\${D1_REMOTE_URL}
85
+ - D1_REMOTE_KEY_ID=\${D1_REMOTE_KEY_ID}
86
+ - D1_REMOTE_SECRET=\${D1_REMOTE_SECRET}
87
+
88
+ # Cloudflare KV
89
+ - KV_NAMESPACE_ID=\${KV_NAMESPACE_ID}
90
+ - KV_ACCOUNT_ID=\${KV_ACCOUNT_ID}
91
+ - KV_API_TOKEN=\${KV_API_TOKEN}
92
+ - KV_REMOTE_URL=\${KV_REMOTE_URL}
93
+ - KV_REMOTE_KEY_ID=\${KV_REMOTE_KEY_ID}
94
+ - KV_REMOTE_SECRET=\${KV_REMOTE_SECRET}
79
95
  ports:
80
96
  - '7772:7772'
81
97
 
@@ -101,7 +117,7 @@ RUN apk add --no-cache python3 make g++
101
117
  COPY package.json package-lock.json ./
102
118
 
103
119
  # Install dependencies (including dev dependencies needed for build)
104
- RUN --mount=type=cache,target=/root/.npm \
120
+ RUN --mount=type=cache,target=/root/.npm,id=zintrust-npm-cache,sharing=locked \
105
121
  npm config set fetch-retries 5 \
106
122
  && npm config set fetch-retry-mintimeout 20000 \
107
123
  && npm config set fetch-retry-maxtimeout 120000 \
@@ -112,7 +128,7 @@ COPY . .
112
128
 
113
129
  # Build TypeScript to JavaScript
114
130
  ARG BUILD_VARIANT=full
115
- RUN --mount=type=cache,target=/root/.npm npm run build:dk
131
+ RUN --mount=type=cache,target=/root/.npm,id=zintrust-npm-cache,sharing=locked npm run build:dk
116
132
 
117
133
  # Runtime Stage - Production image
118
134
  FROM node:20-alpine AS runtime
@@ -131,11 +147,10 @@ RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
131
147
  COPY package.json package-lock.json ./
132
148
 
133
149
  # Install only production dependencies (requires build tools for native modules)
134
- RUN --mount=type=cache,target=/root/.npm \
150
+ RUN --mount=type=cache,target=/root/.npm,id=zintrust-npm-cache,sharing=locked \
135
151
  apk add --no-cache --virtual .build-deps python3 make g++ \
136
152
  && npm ci --omit=dev \
137
- && apk del .build-deps \
138
- && npm cache clean --force
153
+ && apk del .build-deps
139
154
 
140
155
  # Copy compiled code from builder stage
141
156
  COPY --from=builder /app/dist ./dist
@@ -157,7 +172,7 @@ EXPOSE 7772
157
172
  # Start application (compiled JS; no tsx needed in runtime)
158
173
  CMD ["node", "dist/src/boot/bootstrap.js"]
159
174
  `;
160
- const backupSuffix = () => new Date().toISOString().replace(/[:.]/g, '-');
175
+ const backupSuffix = () => new Date().toISOString().replaceAll(/[:.]/g, '-');
161
176
  const backupFileIfExists = (filePath) => {
162
177
  if (!existsSync(filePath))
163
178
  return;
@@ -0,0 +1,6 @@
1
+ import { type IBaseCommand } from '../BaseCommand';
2
+ export declare const InitEcosystemCommand: Readonly<{
3
+ create(): IBaseCommand;
4
+ }>;
5
+ export default InitEcosystemCommand;
6
+ //# sourceMappingURL=InitEcosystemCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InitEcosystemCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/InitEcosystemCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAoDlE,eAAO,MAAM,oBAAoB;cACrB,YAAY;EAOtB,CAAC;AAEH,eAAe,oBAAoB,CAAC"}
@@ -0,0 +1,51 @@
1
+ import { BaseCommand } from '../BaseCommand.js';
2
+ import { PromptHelper } from '../PromptHelper.js';
3
+ import { Logger } from '../../config/logger.js';
4
+ import { copyFileSync, existsSync, readFileSync, writeFileSync } from '../../node-singletons/fs.js';
5
+ import { join } from '../../node-singletons/path.js';
6
+ import { fileURLToPath } from '../../node-singletons/url.js';
7
+ const backupSuffix = () => new Date().toISOString().replaceAll(/[:.]/g, '-');
8
+ const backupFileIfExists = (filePath) => {
9
+ if (!existsSync(filePath))
10
+ return;
11
+ const backupPath = `${filePath}.bak.${backupSuffix()}`;
12
+ copyFileSync(filePath, backupPath);
13
+ Logger.info(`🗂️ Backup created: ${backupPath}`);
14
+ };
15
+ const readTemplate = (relPathFromThisModule) => {
16
+ const absPath = fileURLToPath(new URL(relPathFromThisModule, import.meta.url));
17
+ return readFileSync(absPath, 'utf-8');
18
+ };
19
+ const TEMPLATE_ECOSYSTEM = readTemplate('../../templates/docker/docker-compose.ecosystem.yml.tpl');
20
+ const TEMPLATE_SCHEDULES = readTemplate('../../templates/docker/docker-compose.schedules.yml.tpl');
21
+ const writeScaffoldFile = async (cwd, fileName, content) => {
22
+ const outPath = join(cwd, fileName);
23
+ let shouldWrite = true;
24
+ if (existsSync(outPath)) {
25
+ shouldWrite = await PromptHelper.confirm(`${fileName} already exists. Overwrite?`, false);
26
+ }
27
+ if (!shouldWrite) {
28
+ Logger.info(`Skipped ${fileName}`);
29
+ return;
30
+ }
31
+ backupFileIfExists(outPath);
32
+ writeFileSync(outPath, content);
33
+ Logger.info(`✅ Created ${fileName}`);
34
+ };
35
+ const execute = async () => {
36
+ const cwd = process.cwd();
37
+ await writeScaffoldFile(cwd, 'docker-compose.ecosystem.yml', TEMPLATE_ECOSYSTEM);
38
+ await writeScaffoldFile(cwd, 'docker-compose.schedules.yml', TEMPLATE_SCHEDULES);
39
+ Logger.info('✅ Ecosystem scaffolding complete.');
40
+ Logger.info('Next: docker compose -f docker-compose.ecosystem.yml up -d');
41
+ };
42
+ export const InitEcosystemCommand = Object.freeze({
43
+ create() {
44
+ return BaseCommand.create({
45
+ name: 'init:ecosystem',
46
+ description: 'Scaffold docker-compose.ecosystem.yml and docker-compose.schedules.yml',
47
+ execute,
48
+ });
49
+ },
50
+ });
51
+ export default InitEcosystemCommand;
@@ -1 +1 @@
1
- {"version":3,"file":"MigrateCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/MigrateCommand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,kBAAkB,CAAC;AA6ZrE;;GAEG;AACH,eAAO,MAAM,cAAc;IACzB;;OAEG;cACO,YAAY;EAUtB,CAAC"}
1
+ {"version":3,"file":"MigrateCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/MigrateCommand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,kBAAkB,CAAC;AA0erE;;GAEG;AACH,eAAO,MAAM,cAAc;IACzB;;OAEG;cACO,YAAY;EAUtB,CAAC"}