@geekmidas/cli 10.0.0-alpha.72 → 10.0.0-alpha.73

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 (191) hide show
  1. package/dist/{OpenApiTsGenerator-BlP53kf2.cjs → EndpointGenerator-CP6sBvQV.cjs} +4 -510
  2. package/dist/EndpointGenerator-CP6sBvQV.cjs.map +1 -0
  3. package/dist/{OpenApiTsGenerator-Dv0gT2DL.mjs → EndpointGenerator-DftalLYg.mjs} +3 -509
  4. package/dist/EndpointGenerator-DftalLYg.mjs.map +1 -0
  5. package/dist/{LegacyStateStore-NSHEinQi.mjs → LegacyStateStore-DTo7z924.mjs} +2 -2
  6. package/dist/{LegacyStateStore-NSHEinQi.mjs.map → LegacyStateStore-DTo7z924.mjs.map} +1 -1
  7. package/dist/{LegacyStateStore-Dd5IwiyC.cjs → LegacyStateStore-D_78eaHM.cjs} +2 -2
  8. package/dist/{LegacyStateStore-Dd5IwiyC.cjs.map → LegacyStateStore-D_78eaHM.cjs.map} +1 -1
  9. package/dist/{LocalStateStore-DTylG4T4.cjs → LocalStateStore-BhrlQIXD.cjs} +2 -2
  10. package/dist/{LocalStateStore-DTylG4T4.cjs.map → LocalStateStore-BhrlQIXD.cjs.map} +1 -1
  11. package/dist/{LocalStateStore-DUoG2wA_.mjs → LocalStateStore-CNjgkRk4.mjs} +2 -2
  12. package/dist/{LocalStateStore-DUoG2wA_.mjs.map → LocalStateStore-CNjgkRk4.mjs.map} +1 -1
  13. package/dist/OpenApiTsGenerator-CKBCckKz.cjs +514 -0
  14. package/dist/OpenApiTsGenerator-CKBCckKz.cjs.map +1 -0
  15. package/dist/OpenApiTsGenerator-nu1r1NgB.mjs +509 -0
  16. package/dist/OpenApiTsGenerator-nu1r1NgB.mjs.map +1 -0
  17. package/dist/{S3StateStore-Dxob3PNA.mjs → S3StateStore-g2P7T_Mo.mjs} +2 -2
  18. package/dist/{S3StateStore-Dxob3PNA.mjs.map → S3StateStore-g2P7T_Mo.mjs.map} +1 -1
  19. package/dist/{S3StateStore-D7hrU-sy.cjs → S3StateStore-oCxRs6HM.cjs} +2 -2
  20. package/dist/{S3StateStore-D7hrU-sy.cjs.map → S3StateStore-oCxRs6HM.cjs.map} +1 -1
  21. package/dist/{SSMStateStore-Dvl4A8Up.mjs → SSMStateStore-CYenunmK.mjs} +2 -2
  22. package/dist/{SSMStateStore-Dvl4A8Up.mjs.map → SSMStateStore-CYenunmK.mjs.map} +1 -1
  23. package/dist/{SSMStateStore-DGIKJ4NN.cjs → SSMStateStore-DXp0m7XI.cjs} +2 -2
  24. package/dist/{SSMStateStore-DGIKJ4NN.cjs.map → SSMStateStore-DXp0m7XI.cjs.map} +1 -1
  25. package/dist/SubscriberGenerator-Bixm28fN.cjs +461 -0
  26. package/dist/SubscriberGenerator-Bixm28fN.cjs.map +1 -0
  27. package/dist/SubscriberGenerator-DZk_pKDh.mjs +432 -0
  28. package/dist/SubscriberGenerator-DZk_pKDh.mjs.map +1 -0
  29. package/dist/{add-XTLU19_E.mjs → add-BiPlBUq3.mjs} +4 -4
  30. package/dist/{add-XTLU19_E.mjs.map → add-BiPlBUq3.mjs.map} +1 -1
  31. package/dist/{add-DeC2Kyyv.cjs → add-C1ojB2Yy.cjs} +4 -4
  32. package/dist/{add-DeC2Kyyv.cjs.map → add-C1ojB2Yy.cjs.map} +1 -1
  33. package/dist/{bundler-CNTVLCCA.mjs → bundler-C2LZoLdP.mjs} +6 -6
  34. package/dist/bundler-C2LZoLdP.mjs.map +1 -0
  35. package/dist/{bundler-CEaR6Dpb.cjs → bundler-C35h0WKt.cjs} +6 -6
  36. package/dist/bundler-C35h0WKt.cjs.map +1 -0
  37. package/dist/{cli-D1arS0p1.mjs → cli-BfdfyTF6.mjs} +4 -4
  38. package/dist/{cli-D1arS0p1.mjs.map → cli-BfdfyTF6.mjs.map} +1 -1
  39. package/dist/{cli-MMgBrHx7.cjs → cli-DJVL2sL9.cjs} +4 -4
  40. package/dist/{cli-MMgBrHx7.cjs.map → cli-DJVL2sL9.cjs.map} +1 -1
  41. package/dist/{compose-T3hnnjKZ.mjs → compose-9II-0IsK.mjs} +221 -64
  42. package/dist/compose-9II-0IsK.mjs.map +1 -0
  43. package/dist/{compose-B-MME-4C.cjs → compose-CNnw8meq.cjs} +223 -66
  44. package/dist/compose-CNnw8meq.cjs.map +1 -0
  45. package/dist/{config-BN6iXvyR.d.mts → config-B8OR_TrO.d.mts} +3 -3
  46. package/dist/{config-BN6iXvyR.d.mts.map → config-B8OR_TrO.d.mts.map} +1 -1
  47. package/dist/{config-j9zBKaEG.d.cts → config-RLuR2o9A.d.cts} +3 -3
  48. package/dist/{config-j9zBKaEG.d.cts.map → config-RLuR2o9A.d.cts.map} +1 -1
  49. package/dist/config.cjs +4 -1
  50. package/dist/config.cjs.map +1 -1
  51. package/dist/config.d.cts +3 -3
  52. package/dist/config.d.mts +3 -3
  53. package/dist/config.mjs +4 -1
  54. package/dist/config.mjs.map +1 -1
  55. package/dist/{credentialSchemas-BmYxnEz_.mjs → credentialSchemas-BJqRJNK4.mjs} +2 -2
  56. package/dist/{credentialSchemas-BmYxnEz_.mjs.map → credentialSchemas-BJqRJNK4.mjs.map} +1 -1
  57. package/dist/{credentialSchemas-BcNL1N5R.cjs → credentialSchemas-DCR4Wd1W.cjs} +2 -2
  58. package/dist/{credentialSchemas-BcNL1N5R.cjs.map → credentialSchemas-DCR4Wd1W.cjs.map} +1 -1
  59. package/dist/deploy/public.cjs +7 -7
  60. package/dist/deploy/public.d.cts +4 -4
  61. package/dist/deploy/public.d.cts.map +1 -1
  62. package/dist/deploy/public.d.mts +4 -4
  63. package/dist/deploy/public.d.mts.map +1 -1
  64. package/dist/deploy/public.mjs +7 -7
  65. package/dist/deploy/sniffer-routes-worker.cjs +2 -2
  66. package/dist/deploy/sniffer-routes-worker.mjs +2 -2
  67. package/dist/{deploy-CZE0m6jd.cjs → deploy-BitZLdnY.cjs} +12 -6
  68. package/dist/deploy-BitZLdnY.cjs.map +1 -0
  69. package/dist/{deploy-ClC53rc6.mjs → deploy-nmov4j0B.mjs} +12 -6
  70. package/dist/deploy-nmov4j0B.mjs.map +1 -0
  71. package/dist/{discover-Buwf1z4P.mjs → discover-BPelzeGW.mjs} +21 -2
  72. package/dist/discover-BPelzeGW.mjs.map +1 -0
  73. package/dist/{discover-B_IkPukx.d.cts → discover-CU0paUyH.d.cts} +10 -1
  74. package/dist/discover-CU0paUyH.d.cts.map +1 -0
  75. package/dist/{discover-B4VjaFJk.cjs → discover-D1It5r_h.cjs} +21 -2
  76. package/dist/discover-D1It5r_h.cjs.map +1 -0
  77. package/dist/{discover-B6yPpvRV.d.mts → discover-DFiJxwfv.d.mts} +10 -1
  78. package/dist/discover-DFiJxwfv.d.mts.map +1 -0
  79. package/dist/{dokploy-D1UwQKm3.mjs → dokploy-CZ1vZt21.mjs} +2 -2
  80. package/dist/{dokploy-D1UwQKm3.mjs.map → dokploy-CZ1vZt21.mjs.map} +1 -1
  81. package/dist/{dokploy-lwmH05zr.cjs → dokploy-Ce_VTytN.cjs} +2 -2
  82. package/dist/{dokploy-lwmH05zr.cjs.map → dokploy-Ce_VTytN.cjs.map} +1 -1
  83. package/dist/{encryption-D05sNwED.cjs → encryption-CDGRdcMr.cjs} +2 -2
  84. package/dist/{encryption-D05sNwED.cjs.map → encryption-CDGRdcMr.cjs.map} +1 -1
  85. package/dist/{encryption-DcrxWl1s.mjs → encryption-CmfPICSN.mjs} +2 -2
  86. package/dist/{encryption-DcrxWl1s.mjs.map → encryption-CmfPICSN.mjs.map} +1 -1
  87. package/dist/{engine-DmQS3XHX.mjs → engine-B37qBO5W.mjs} +117 -17
  88. package/dist/engine-B37qBO5W.mjs.map +1 -0
  89. package/dist/{engine-Cry1vwMz.cjs → engine-DL2-PW6m.cjs} +117 -17
  90. package/dist/engine-DL2-PW6m.cjs.map +1 -0
  91. package/dist/{github-BchWoiVx.cjs → github-C6qF8kHg.cjs} +2 -2
  92. package/dist/{github-BchWoiVx.cjs.map → github-C6qF8kHg.cjs.map} +1 -1
  93. package/dist/{github-CqYOP8cI.mjs → github-hjHHm7jM.mjs} +2 -2
  94. package/dist/{github-CqYOP8cI.mjs.map → github-hjHHm7jM.mjs.map} +1 -1
  95. package/dist/{index-DvoxuTqR.d.mts → index-DHyTqGG3.d.mts} +2 -2
  96. package/dist/{index-Bk3NY6DN.d.cts.map → index-DHyTqGG3.d.mts.map} +1 -1
  97. package/dist/{index-Bk3NY6DN.d.cts → index-Dg-UZ4Hm.d.cts} +2 -2
  98. package/dist/{index-DvoxuTqR.d.mts.map → index-Dg-UZ4Hm.d.cts.map} +1 -1
  99. package/dist/index.cjs +113 -468
  100. package/dist/index.cjs.map +1 -1
  101. package/dist/index.mjs +107 -462
  102. package/dist/index.mjs.map +1 -1
  103. package/dist/{migrate-guck0NJK.mjs → migrate-CFFC3esE.mjs} +3 -3
  104. package/dist/{migrate-guck0NJK.mjs.map → migrate-CFFC3esE.mjs.map} +1 -1
  105. package/dist/{migrate-qKeGYq21.cjs → migrate-kA_j1TPK.cjs} +3 -3
  106. package/dist/{migrate-qKeGYq21.cjs.map → migrate-kA_j1TPK.cjs.map} +1 -1
  107. package/dist/openapi.cjs +3 -2
  108. package/dist/openapi.cjs.map +1 -1
  109. package/dist/openapi.d.cts +1 -1
  110. package/dist/openapi.d.mts +1 -1
  111. package/dist/openapi.mjs +2 -1
  112. package/dist/openapi.mjs.map +1 -1
  113. package/dist/{ready-B-7LayMF.cjs → ready-BIuMw6wH.cjs} +9 -297
  114. package/dist/ready-BIuMw6wH.cjs.map +1 -0
  115. package/dist/{ready-ULc5BTOb.mjs → ready-C0U0NYfB.mjs} +6 -288
  116. package/dist/ready-C0U0NYfB.mjs.map +1 -0
  117. package/dist/reconcile/public.cjs +1 -1
  118. package/dist/reconcile/public.d.cts +2 -2
  119. package/dist/reconcile/public.d.mts +2 -2
  120. package/dist/reconcile/public.mjs +1 -1
  121. package/dist/{resolve-BsXEXAUz.mjs → resolve-CV4eQkDa.mjs} +3 -3
  122. package/dist/{resolve-BsXEXAUz.mjs.map → resolve-CV4eQkDa.mjs.map} +1 -1
  123. package/dist/{resolve-wEjEvbJ5.cjs → resolve-E5RfY0bm.cjs} +3 -3
  124. package/dist/{resolve-wEjEvbJ5.cjs.map → resolve-E5RfY0bm.cjs.map} +1 -1
  125. package/dist/{rollback-Bk91csFg.mjs → rollback-C-V-Rf4a.mjs} +4 -4
  126. package/dist/{rollback-Bk91csFg.mjs.map → rollback-C-V-Rf4a.mjs.map} +1 -1
  127. package/dist/{rollback-DmcU-efZ.cjs → rollback-QGwomD64.cjs} +4 -4
  128. package/dist/{rollback-DmcU-efZ.cjs.map → rollback-QGwomD64.cjs.map} +1 -1
  129. package/dist/{runtime-DHJhe4QI.d.mts → runtime-CWYLIeCU.d.mts} +2 -2
  130. package/dist/{runtime-CYAO4iZG.d.cts.map → runtime-CWYLIeCU.d.mts.map} +1 -1
  131. package/dist/{runtime-CYAO4iZG.d.cts → runtime-CmuQOT6A.d.cts} +2 -2
  132. package/dist/{runtime-DHJhe4QI.d.mts.map → runtime-CmuQOT6A.d.cts.map} +1 -1
  133. package/dist/sandbox/credentials-worker.cjs +2 -2
  134. package/dist/sandbox/credentials-worker.mjs +2 -2
  135. package/dist/sandbox/discover-worker.cjs +6 -3
  136. package/dist/sandbox/discover-worker.cjs.map +1 -1
  137. package/dist/sandbox/discover-worker.mjs +6 -3
  138. package/dist/sandbox/discover-worker.mjs.map +1 -1
  139. package/dist/sandbox/migrate-worker.cjs +1 -1
  140. package/dist/sandbox/migrate-worker.mjs +1 -1
  141. package/dist/{sniffer-vAXsU_4G.mjs → sniffer-BFmdZpZ2.mjs} +6 -6
  142. package/dist/{sniffer-vAXsU_4G.mjs.map → sniffer-BFmdZpZ2.mjs.map} +1 -1
  143. package/dist/{sniffer-DpHpFZBD.cjs → sniffer-C-T7dSMN.cjs} +6 -6
  144. package/dist/{sniffer-DpHpFZBD.cjs.map → sniffer-C-T7dSMN.cjs.map} +1 -1
  145. package/dist/{state-CCuTJNRH.cjs → state-DMjFPOhf.cjs} +942 -22
  146. package/dist/state-DMjFPOhf.cjs.map +1 -0
  147. package/dist/{state-BJFherj1.mjs → state-DtS2HEfi.mjs} +877 -17
  148. package/dist/state-DtS2HEfi.mjs.map +1 -0
  149. package/dist/target/public.cjs +1 -1
  150. package/dist/target/public.d.cts +2 -2
  151. package/dist/target/public.d.mts +2 -2
  152. package/dist/target/public.mjs +1 -1
  153. package/dist/{terminal-CFO3xWoF.cjs → terminal-BL5E0xbR.cjs} +2 -2
  154. package/dist/{terminal-CFO3xWoF.cjs.map → terminal-BL5E0xbR.cjs.map} +1 -1
  155. package/dist/{terminal-C6TBo_SA.mjs → terminal-BdvrmkaC.mjs} +2 -2
  156. package/dist/{terminal-C6TBo_SA.mjs.map → terminal-BdvrmkaC.mjs.map} +1 -1
  157. package/dist/{types-DkG5WW8l.d.mts → types-BLdCL4fB.d.mts} +17 -1
  158. package/dist/types-BLdCL4fB.d.mts.map +1 -0
  159. package/dist/{types-BD1jgA85.d.cts → types-DwCQCkC-.d.cts} +17 -1
  160. package/dist/types-DwCQCkC-.d.cts.map +1 -0
  161. package/dist/vitest.cjs +1 -1
  162. package/dist/vitest.mjs +1 -1
  163. package/dist/workspace/index.d.cts +2 -2
  164. package/dist/workspace/index.d.mts +2 -2
  165. package/dist/workspace-C7NqCsQF.mjs.map +1 -1
  166. package/dist/workspace-vdrcRI-m.cjs.map +1 -1
  167. package/package.json +15 -15
  168. package/dist/OpenApiTsGenerator-BlP53kf2.cjs.map +0 -1
  169. package/dist/OpenApiTsGenerator-Dv0gT2DL.mjs.map +0 -1
  170. package/dist/bundler-CEaR6Dpb.cjs.map +0 -1
  171. package/dist/bundler-CNTVLCCA.mjs.map +0 -1
  172. package/dist/compose-B-MME-4C.cjs.map +0 -1
  173. package/dist/compose-T3hnnjKZ.mjs.map +0 -1
  174. package/dist/deploy-CZE0m6jd.cjs.map +0 -1
  175. package/dist/deploy-ClC53rc6.mjs.map +0 -1
  176. package/dist/discover-B4VjaFJk.cjs.map +0 -1
  177. package/dist/discover-B6yPpvRV.d.mts.map +0 -1
  178. package/dist/discover-B_IkPukx.d.cts.map +0 -1
  179. package/dist/discover-Buwf1z4P.mjs.map +0 -1
  180. package/dist/engine-Cry1vwMz.cjs.map +0 -1
  181. package/dist/engine-DmQS3XHX.mjs.map +0 -1
  182. package/dist/fakes-C9RiT6XG.mjs +0 -125
  183. package/dist/fakes-C9RiT6XG.mjs.map +0 -1
  184. package/dist/fakes-zW-jNAbQ.cjs +0 -148
  185. package/dist/fakes-zW-jNAbQ.cjs.map +0 -1
  186. package/dist/ready-B-7LayMF.cjs.map +0 -1
  187. package/dist/ready-ULc5BTOb.mjs.map +0 -1
  188. package/dist/state-BJFherj1.mjs.map +0 -1
  189. package/dist/state-CCuTJNRH.cjs.map +0 -1
  190. package/dist/types-BD1jgA85.d.cts.map +0 -1
  191. package/dist/types-DkG5WW8l.d.mts.map +0 -1
@@ -1,16 +1,19 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
2
2
  const require_run = require("./run-fVZ-rLnc.cjs");
3
- const require_discover = require("./discover-B4VjaFJk.cjs");
3
+ const require_discover = require("./discover-D1It5r_h.cjs");
4
4
  const require_derive = require("./derive-DAbo49sm.cjs");
5
5
  const require_workspace = require("./workspace-vdrcRI-m.cjs");
6
6
  const require_config = require("./config.cjs");
7
- const require_resolve = require("./resolve-wEjEvbJ5.cjs");
8
- const require_fakes = require("./fakes-zW-jNAbQ.cjs");
7
+ const require_EndpointGenerator = require("./EndpointGenerator-CP6sBvQV.cjs");
8
+ const require_resolve = require("./resolve-E5RfY0bm.cjs");
9
+ const require_SubscriberGenerator = require("./SubscriberGenerator-Bixm28fN.cjs");
9
10
  let node_path = require("node:path");
10
11
  let node_fs = require("node:fs");
11
12
  let node_fs_promises = require("node:fs/promises");
12
13
  let node_os = require("node:os");
13
14
  let node_util = require("node:util");
15
+ let _geekmidas_constructs_crons = require("@geekmidas/constructs/crons");
16
+ let _geekmidas_constructs_queue = require("@geekmidas/constructs/queue");
14
17
  let _geekmidas_manifest = require("@geekmidas/manifest");
15
18
  let node_net = require("node:net");
16
19
  let node_child_process = require("node:child_process");
@@ -1005,11 +1008,11 @@ function providerOf(workspace) {
1005
1008
  * would be worse than a slower one.
1006
1009
  */
1007
1010
  function cacheBackendFor(on) {
1008
- return require_fakes.DEFAULT_CACHE[on];
1011
+ return require_SubscriberGenerator.DEFAULT_CACHE[on];
1009
1012
  }
1010
1013
  /** Where a declared bucket lives on a target. */
1011
1014
  function storageBackendFor(on) {
1012
- return require_fakes.DEFAULT_STORAGE[on];
1015
+ return require_SubscriberGenerator.DEFAULT_STORAGE[on];
1013
1016
  }
1014
1017
  /**
1015
1018
  * Which broker carries declared queues and topics on a target.
@@ -1018,7 +1021,7 @@ function storageBackendFor(on) {
1018
1021
  * `Queue` has no events at all, whatever the target.
1019
1022
  */
1020
1023
  function eventsBackendFor(on) {
1021
- return require_fakes.DEFAULT_EVENTS[on];
1024
+ return require_SubscriberGenerator.DEFAULT_EVENTS[on];
1022
1025
  }
1023
1026
  //#endregion
1024
1027
  //#region src/docker/templates.ts
@@ -1538,11 +1541,37 @@ CMD ["node", "${appPath}/server.js"]
1538
1541
  * @internal Exported for testing
1539
1542
  */
1540
1543
  function generateBackendDockerfile(options) {
1544
+ return gkmBundleDockerfile(options, {
1545
+ title: "Backend Dockerfile",
1546
+ bundle: "server.mjs",
1547
+ as: "server.mjs",
1548
+ expose: true
1549
+ });
1550
+ }
1551
+ /** The port a worker answers its health check on, inside its container. */
1552
+ const WORKER_PORT = 3e3;
1553
+ /**
1554
+ * A Worker's image: the same build as its host app's backend — a pruned
1555
+ * slice, `gkm build --provider server --production` in the image, with the
1556
+ * encrypted credentials from the `gkm_credentials` secret — and a runner that
1557
+ * is the worker's bundle alone. It publishes nothing: its one route is the
1558
+ * health check the HEALTHCHECK asks.
1559
+ * @internal Exported for testing
1560
+ */
1561
+ function generateWorkerDockerfile(options) {
1562
+ return gkmBundleDockerfile(options, {
1563
+ title: `Worker Dockerfile (${options.worker})`,
1564
+ bundle: options.bundle,
1565
+ as: "worker.mjs",
1566
+ expose: false
1567
+ });
1568
+ }
1569
+ function gkmBundleDockerfile(options, runner) {
1541
1570
  const { port, healthCheckPath = "/health" } = options;
1542
1571
  const { app } = layout(options);
1543
1572
  const externals = externalsStages(options, app);
1544
1573
  return `# syntax=docker/dockerfile:1
1545
- # Backend Dockerfile: a turbo-pruned slice, bundled by gkm build in the image
1574
+ # ${runner.title}: a turbo-pruned slice, bundled by gkm build in the image
1546
1575
 
1547
1576
  ${prunerStage(options)}
1548
1577
 
@@ -1563,8 +1592,8 @@ RUN apk add --no-cache tini
1563
1592
  RUN addgroup --system --gid 1001 nodejs && \\
1564
1593
  adduser --system --uid 1001 hono
1565
1594
 
1566
- # The bundled server
1567
- COPY --from=builder --chown=hono:nodejs ${app}/.gkm/server/dist/server.mjs ./${externals.copy}
1595
+ # The bundled ${runner.as === "server.mjs" ? "server" : "worker"}
1596
+ COPY --from=builder --chown=hono:nodejs ${app}/.gkm/server/dist/${runner.bundle} ./${runner.as === runner.bundle ? "" : runner.as}${externals.copy}
1568
1597
 
1569
1598
  ENV NODE_ENV=production
1570
1599
  ENV PORT=${port}
@@ -1573,11 +1602,9 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \\
1573
1602
  CMD wget -qO- http://localhost:${port}${healthCheckPath} > /dev/null 2>&1 || exit 1
1574
1603
 
1575
1604
  USER hono
1576
-
1577
- EXPOSE ${port}
1578
-
1605
+ ${runner.expose ? `\nEXPOSE ${port}\n` : ""}
1579
1606
  ENTRYPOINT ["/sbin/tini", "--"]
1580
- CMD ["node", "server.mjs"]
1607
+ CMD ["node", "${runner.as}"]
1581
1608
  `;
1582
1609
  }
1583
1610
  /**
@@ -2264,7 +2291,7 @@ function resourceName(id, kind, stage, localStage) {
2264
2291
  * broker the project selected, which is why the backend is an argument here
2265
2292
  * rather than a second pass that adds containers after the fact.
2266
2293
  */
2267
- function containerFor(kind, events = DEFAULT_EVENTS, cache = require_fakes.DEFAULT_CACHE.aws, derived = false, edge = true) {
2294
+ function containerFor(kind, events = DEFAULT_EVENTS, cache = require_SubscriberGenerator.DEFAULT_CACHE.aws, derived = false, edge = true) {
2268
2295
  if (EVENT_KINDS[kind]) return EVENT_CONTAINERS[events] ?? CONTAINERS.database;
2269
2296
  if (kind === "file-server") return edge ? "caddy" : CONTAINERS.objects;
2270
2297
  if (kind === "cache") {
@@ -2285,7 +2312,7 @@ function planFor(manifest, stage, order, options = {}) {
2285
2312
  const resources = [];
2286
2313
  const fakes = {};
2287
2314
  const events = options.events ?? "pgboss";
2288
- const cache = options.cache ?? require_fakes.DEFAULT_CACHE.aws;
2315
+ const cache = options.cache ?? require_SubscriberGenerator.DEFAULT_CACHE.aws;
2289
2316
  for (const id of order) {
2290
2317
  const declaration = manifest[id];
2291
2318
  if (!declaration) continue;
@@ -2986,6 +3013,36 @@ function appEnvKeys(manifest, appName, runnables = {}) {
2986
3013
  for (const key of other.provides ?? []) keys.add(key);
2987
3014
  }
2988
3015
  }
3016
+ addEdgeKeys(manifest, edges, keys);
3017
+ if (declaration.kind === "site" || declaration.kind === "mobile-app") for (const key of Object.keys((0, _geekmidas_manifest.publicEnvFor)(declaration, manifest))) keys.add(key);
3018
+ return keys;
3019
+ }
3020
+ /**
3021
+ * The keys a Worker's own process reads: what the worker and everything built
3022
+ * from it declared an edge to, the broker its crons schedule through, and the
3023
+ * address of every queue and topic — which of them its consumers and
3024
+ * subscribers are bound to is only known once a build has found them, so a
3025
+ * process that runs them is handed each carrier's.
3026
+ *
3027
+ * `undefined` when no worker has that id.
3028
+ */
3029
+ function workerEnvKeys(manifest, workerId, runnables = {}) {
3030
+ const declaration = manifest[workerId];
3031
+ if (declaration?.kind !== "worker") return void 0;
3032
+ const keys = /* @__PURE__ */ new Set([
3033
+ ...declaration.provides ?? [],
3034
+ ...declaration.requires ?? [],
3035
+ "EVENT_PUBLISHER_CONNECTION_STRING"
3036
+ ]);
3037
+ for (const other of Object.values(manifest)) {
3038
+ if (other.kind !== "queue" && other.kind !== "topic") continue;
3039
+ for (const key of other.provides ?? []) keys.add(key);
3040
+ }
3041
+ addEdgeKeys(manifest, [...(0, _geekmidas_manifest.dependenciesOf)(declaration).map((edge) => edge.target), ...runnables[workerId] ?? []], keys);
3042
+ return keys;
3043
+ }
3044
+ /** What each construct an edge reaches hands the process that reaches it. */
3045
+ function addEdgeKeys(manifest, edges, keys) {
2989
3046
  for (const id of edges) {
2990
3047
  const target = manifest[id];
2991
3048
  if (!target) continue;
@@ -3002,8 +3059,6 @@ function appEnvKeys(manifest, appName, runnables = {}) {
3002
3059
  keys.add("AWS_REGION");
3003
3060
  }
3004
3061
  }
3005
- if (declaration.kind === "site" || declaration.kind === "mobile-app") for (const key of Object.keys((0, _geekmidas_manifest.publicEnvFor)(declaration, manifest))) keys.add(key);
3006
- return keys;
3007
3062
  }
3008
3063
  /** One compose service per app the workspace runs, behind the apps profile. */
3009
3064
  function appServices(workspace, manifest, containers, runnables = {}, fakes = {}) {
@@ -4467,7 +4522,7 @@ async function reconcileWorkspace(workspace, options) {
4467
4522
  runnables
4468
4523
  });
4469
4524
  const manifest = options.manifest ?? discovered;
4470
- const fakes = fakesApply(options.stage, options.fake) ? await require_fakes.readFakes(workspace.root, manifest) : {};
4525
+ const fakes = fakesApply(options.stage, options.fake) ? await require_SubscriberGenerator.readFakes(workspace.root, manifest) : {};
4471
4526
  const result = await reconcile({
4472
4527
  root: workspace.root,
4473
4528
  project: workspace.name,
@@ -4534,6 +4589,707 @@ function localAddress(port) {
4534
4589
  return `http://localhost:${port}`;
4535
4590
  }
4536
4591
  //#endregion
4592
+ //#region src/generators/CronGenerator.ts
4593
+ var CronGenerator = class extends require_discover.ConstructGenerator {
4594
+ async build(context, constructs, outputDir, options) {
4595
+ const target = options?.target ?? "aws";
4596
+ const logger = console;
4597
+ const cronInfos = [];
4598
+ if (target === "server") {
4599
+ await this.generateServerCronsFile(outputDir, constructs);
4600
+ logger.log(`Generated server crons file with ${constructs.length} crons`);
4601
+ return cronInfos;
4602
+ }
4603
+ if (constructs.length === 0) return cronInfos;
4604
+ const cronsDir = (0, node_path.join)(outputDir, "crons");
4605
+ await (0, node_fs_promises.mkdir)(cronsDir, { recursive: true });
4606
+ for (const { key, construct, path } of constructs) {
4607
+ const handlerFile = await this.generateCronHandler(cronsDir, path.relative, key, context, construct.owner);
4608
+ cronInfos.push({
4609
+ name: key,
4610
+ handler: (0, node_path.relative)(options?.root ?? process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
4611
+ schedule: construct.schedule || "rate(1 hour)",
4612
+ timeout: construct.timeout,
4613
+ memorySize: construct.memorySize,
4614
+ environment: await construct.getEnvironment({ markOptional: context.markOptional }),
4615
+ dependencies: construct.constructs
4616
+ });
4617
+ logger.log(`Generated cron handler: ${key}`);
4618
+ }
4619
+ return cronInfos;
4620
+ }
4621
+ isConstruct(value) {
4622
+ return _geekmidas_constructs_crons.Cron.isCron(value);
4623
+ }
4624
+ /**
4625
+ * The crons file a server entry imports.
4626
+ *
4627
+ * Shaped after `generateServerSubscribersFile`: one module, every cron, a
4628
+ * `setupCrons` the generated entry calls beside `setupSubscribers`.
4629
+ *
4630
+ * It picks its scheduler from what the process can reach. With a Postgres it
4631
+ * uses pg-boss, whose schedules live in the database — so a deployment
4632
+ * running four replicas fires each job once, which is the thing a timer in
4633
+ * every process gets wrong and does not report. With no database it falls
4634
+ * back to timers and says plainly that it is doing so.
4635
+ */
4636
+ async generateServerCronsFile(outputDir, crons) {
4637
+ await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
4638
+ const cronsPath = (0, node_path.join)(outputDir, "crons.ts");
4639
+ if (crons.length === 0) {
4640
+ await (0, node_fs_promises.writeFile)(cronsPath, `/**
4641
+ * Generated cron setup — this app declares none.
4642
+ */
4643
+ import type { EnvironmentParser } from '@geekmidas/envkit';
4644
+ import type { Logger } from '@geekmidas/logger';
4645
+
4646
+ export async function setupCrons(
4647
+ _envParser: EnvironmentParser<any>,
4648
+ _logger: Logger,
4649
+ ): Promise<void> {}
4650
+
4651
+ export function cronsStatus(): { failed: string[]; connections: unknown[] } {
4652
+ return { failed: [], connections: [] };
4653
+ }
4654
+
4655
+ export async function stopCrons(): Promise<void> {}
4656
+ `);
4657
+ return cronsPath;
4658
+ }
4659
+ const importsByFile = /* @__PURE__ */ new Map();
4660
+ for (const { path, key } of crons) {
4661
+ const importPath = (0, node_path.relative)((0, node_path.dirname)(cronsPath), path.relative).replace(/\.ts$/, ".js");
4662
+ if (!importsByFile.has(importPath)) importsByFile.set(importPath, []);
4663
+ importsByFile.get(importPath)?.push(key);
4664
+ }
4665
+ const content = `/**
4666
+ * Generated cron setup.
4667
+ *
4668
+ * Schedules every cron this app declares, in the process that serves it.
4669
+ *
4670
+ * The schedule lives in Postgres, through pg-boss, in the database the worker
4671
+ * named with \`.database(db)\`. That is what makes running several replicas
4672
+ * safe: each job fires once, where a timer in every process fires it once per
4673
+ * replica and reports nothing.
4674
+ *
4675
+ * No connection string appears here. The construct that owns the database is
4676
+ * the only thing that knows its key, and it is resolved through service
4677
+ * discovery like any other dependency.
4678
+ */
4679
+ import type { EnvironmentParser } from '@geekmidas/envkit';
4680
+ import type { Logger } from '@geekmidas/logger';
4681
+ import { runCron, scheduleInProcess, toCronExpression } from '@geekmidas/constructs/crons';
4682
+ import { ServiceDiscovery } from '@geekmidas/services';
4683
+ ${Array.from(importsByFile.entries()).map(([importPath, exports]) => `import { ${exports.join(", ")} } from '${importPath}';`).join("\n")}
4684
+
4685
+ const crons = [
4686
+ ${crons.map(({ key }) => ` { name: '${key}', cron: ${key} }`).join(",\n")}
4687
+ ];
4688
+
4689
+ type Stoppable = { stop: () => Promise<void> | void };
4690
+ const running: Stoppable[] = [];
4691
+ // What a worker's health check reads: the crons that cannot be scheduled, and
4692
+ // the broker connection the schedule is kept through.
4693
+ const failed: string[] = [];
4694
+ const connections: import('@geekmidas/events').EventConnection[] = [];
4695
+
4696
+ export async function setupCrons(
4697
+ envParser: EnvironmentParser<any>,
4698
+ logger: Logger,
4699
+ ): Promise<void> {
4700
+ if (crons.length === 0) {
4701
+ return;
4702
+ }
4703
+
4704
+ const serviceDiscovery = ServiceDiscovery.getInstance(envParser);
4705
+
4706
+ // Resolved once per cron rather than per firing: registering services on
4707
+ // every tick would reconnect a database every minute.
4708
+ const prepared = [];
4709
+ for (const { name, cron } of crons) {
4710
+ try {
4711
+ const schedule = toCronExpression(cron.schedule);
4712
+ const services = cron.services.length > 0
4713
+ ? await serviceDiscovery.register(cron.services)
4714
+ : {};
4715
+
4716
+ prepared.push({ name, cron, schedule, services });
4717
+ } catch (error) {
4718
+ // An unrepresentable schedule is a build-time mistake, and failing the
4719
+ // process for it would take the HTTP server down with it.
4720
+ logger.error({ err: error, cron: name }, 'Cron has no runnable schedule, skipping');
4721
+ failed.push(name);
4722
+ }
4723
+ }
4724
+
4725
+ const run = async (entry: (typeof prepared)[number]) => {
4726
+ try {
4727
+ // The cron's own function, the way its Lambda would run it — services,
4728
+ // the worker's database as \`db\`, its events. It used to call a
4729
+ // \`handler\` a Cron does not have, so every firing logged a failure.
4730
+ await runCron(entry.cron, serviceDiscovery);
4731
+ } catch (error) {
4732
+ logger.error({ err: error, cron: entry.name }, 'Cron failed');
4733
+ }
4734
+ };
4735
+
4736
+ // The app's one pg-boss: the events broker's, as the broker's role, in the
4737
+ // broker's schema. A server fires its own crons, and a process scheduling in
4738
+ // memory fires each job once per replica — so the schedule lives in
4739
+ // Postgres. It used to be a second pg-boss on the worker's database, as the
4740
+ // runtime role, which can neither create a schema nor use the broker's.
4741
+ const { url, devPid } = envParser
4742
+ .create((get) => ({
4743
+ url: get('EVENT_PUBLISHER_CONNECTION_STRING').string().optional(),
4744
+ // Set by \`gkm dev\` on the server it starts, and by nothing deployed.
4745
+ devPid: get('GKM_DEV_PID').string().optional(),
4746
+ }))
4747
+ .parse();
4748
+
4749
+ if (!url?.startsWith('pgboss://')) {
4750
+ // \`gkm dev\` on a target whose crons are infrastructure once deployed —
4751
+ // EventBridge rules on AWS — has no broker to keep a schedule in. It is one
4752
+ // process, so a timer fires each job once, which is all pg-boss is for
4753
+ // here. Only there: a deployed server firing by timer fires once per
4754
+ // replica, so outside dev this stays the error below.
4755
+ if (devPid) {
4756
+ for (const entry of prepared) {
4757
+ running.push(scheduleInProcess(entry.schedule, () => run(entry)));
4758
+ logger.info({ cron: entry.name, schedule: entry.schedule }, 'Cron scheduled in this process');
4759
+ }
4760
+ return;
4761
+ }
4762
+
4763
+ logger.error(
4764
+ { crons: prepared.map(({ name }) => name) },
4765
+ 'These crons have nowhere to keep their schedule. On a server they are ' +
4766
+ 'scheduled through the pg-boss events broker ' +
4767
+ '(EVENT_PUBLISHER_CONNECTION_STRING), and ' +
4768
+ (url ? 'the broker configured is not pg-boss.' : 'none is configured.'),
4769
+ );
4770
+ failed.push(...prepared.map(({ name }) => name));
4771
+ return;
4772
+ }
4773
+
4774
+ // Through the registered pg-boss driver, which the entry registers for a
4775
+ // server whose broker is pg-boss. Naming \`@geekmidas/events/pgboss\` here
4776
+ // made every bundle with a cron resolve pg-boss, whatever its broker.
4777
+ const { EventConnectionFactory } = await import('@geekmidas/events');
4778
+ const connection = (await EventConnectionFactory.fromConnectionString(
4779
+ url,
4780
+ )) as import('@geekmidas/events').EventConnection & { instance?: any };
4781
+ const boss = connection.instance!;
4782
+
4783
+ // What this app declares now. Anything else under the prefix belonged to a
4784
+ // cron since renamed or deleted, and would keep firing at a handler that has
4785
+ // gone.
4786
+ //
4787
+ // The prefix is \`cron.\` rather than \`cron:\`: pg-boss accepts
4788
+ // alphanumerics, underscores, hyphens, periods and slashes in a queue name,
4789
+ // and rejects a colon outright.
4790
+ const declared = new Set(prepared.map(({ name }) => \`cron.\${name}\`));
4791
+ for (const existing of await boss.getSchedules()) {
4792
+ if (existing.name.startsWith('cron.') && !declared.has(existing.name)) {
4793
+ await boss.unschedule(existing.name);
4794
+ logger.info({ cron: existing.name }, 'Removed a schedule nothing declares');
4795
+ }
4796
+ }
4797
+
4798
+ for (const entry of prepared) {
4799
+ const queue = \`cron.\${entry.name}\`;
4800
+ await boss.createQueue(queue);
4801
+ // UTC, so this agrees with the schedule a deploy target would have made.
4802
+ await boss.schedule(queue, entry.schedule, undefined, { tz: 'UTC' });
4803
+ await boss.work(queue, () => run(entry));
4804
+
4805
+ logger.info({ cron: entry.name, schedule: entry.schedule }, 'Cron scheduled');
4806
+ }
4807
+
4808
+ running.push({ stop: () => connection.close() });
4809
+ connections.push(connection);
4810
+ logger.info({ count: prepared.length }, 'Crons scheduled');
4811
+ }
4812
+
4813
+ /** The crons that cannot be scheduled, and the connection that schedules the rest. */
4814
+ export function cronsStatus(): {
4815
+ failed: string[];
4816
+ connections: import('@geekmidas/events').EventConnection[];
4817
+ } {
4818
+ return { failed: [...failed], connections: [...connections] };
4819
+ }
4820
+
4821
+ /**
4822
+ * Stop scheduling, let a firing in flight finish, and close the broker
4823
+ * connection — pg-boss's graceful stop does all three. The caller bounds it.
4824
+ */
4825
+ export async function stopCrons(): Promise<void> {
4826
+ const open = [...running];
4827
+ running.length = 0;
4828
+ connections.length = 0;
4829
+ await Promise.all(open.map((r) => r.stop()));
4830
+ }
4831
+ `;
4832
+ await (0, node_fs_promises.writeFile)(cronsPath, content);
4833
+ return cronsPath;
4834
+ }
4835
+ async generateCronHandler(outputDir, sourceFile, exportName, context, owner) {
4836
+ const handlerFileName = `${exportName}.ts`;
4837
+ const handlerPath = (0, node_path.join)(outputDir, handlerFileName);
4838
+ const importPath = (0, node_path.relative)((0, node_path.dirname)(handlerPath), sourceFile).replace(/\.ts$/, ".js");
4839
+ const runtime = require_EndpointGenerator.runtimeFor(context, (0, node_path.dirname)(handlerPath), owner);
4840
+ const content = `import { AWSScheduledFunction } from '@geekmidas/constructs/aws';
4841
+ import { ${exportName} } from '${importPath}';
4842
+ ${runtime.imports}
4843
+ ${context.storageDrivers?.imports ?? ""}
4844
+ ${runtime.bindings}
4845
+ ${context.storageDrivers?.setup ? `\n// The handler registers the drivers its target needs.\n${context.storageDrivers.setup}\n` : ""}
4846
+ const adapter = new AWSScheduledFunction(envParser, ${exportName});
4847
+
4848
+ export const handler = adapter.handler;
4849
+ `;
4850
+ await (0, node_fs_promises.writeFile)(handlerPath, content);
4851
+ return handlerPath;
4852
+ }
4853
+ };
4854
+ //#endregion
4855
+ //#region src/generators/QueueGenerator.ts
4856
+ /**
4857
+ * Generates the runtime for queue consumers (`worker.queue(…)`).
4858
+ *
4859
+ * - **server** (`gkm dev`): a single `queues.ts` exposing `setupQueues()` that
4860
+ * polls each queue in-process, alongside the Hono server, through the queue's
4861
+ * own connection string — pg-boss by default, SQS on the AWS emulator.
4862
+ * - **aws-lambda**: one handler file per queue wrapping `AWSLambdaQueue`, backed
4863
+ * by an SQS event-source mapping.
4864
+ */
4865
+ var QueueGenerator = class extends require_discover.ConstructGenerator {
4866
+ isConstruct(value) {
4867
+ return _geekmidas_constructs_queue.Queue.isQueue(value);
4868
+ }
4869
+ async build(context, constructs, outputDir, options) {
4870
+ const target = options?.target ?? "aws";
4871
+ const logger = console;
4872
+ const queueInfos = [];
4873
+ if (target === "server") {
4874
+ await this.generateServerQueuesFile(outputDir, constructs);
4875
+ logger.log(`Generated server queues file with ${constructs.length} queues (polling mode)`);
4876
+ return queueInfos;
4877
+ }
4878
+ if (constructs.length === 0) return queueInfos;
4879
+ const queuesDir = (0, node_path.join)(outputDir, "queues");
4880
+ await (0, node_fs_promises.mkdir)(queuesDir, { recursive: true });
4881
+ for (const { key, construct, path } of constructs) {
4882
+ const handlerFile = await this.generateQueueHandler(queuesDir, path.relative, key, context, construct.owner);
4883
+ queueInfos.push({
4884
+ name: construct.name,
4885
+ handler: (0, node_path.relative)(options?.root ?? process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
4886
+ batchSize: construct.batchSize,
4887
+ fifo: construct.fifo,
4888
+ timeout: construct.timeout,
4889
+ environment: await construct.getEnvironment({ markOptional: context.markOptional }),
4890
+ dependencies: construct.constructs
4891
+ });
4892
+ logger.log(`Generated queue handler: ${key}`);
4893
+ }
4894
+ return queueInfos;
4895
+ }
4896
+ async generateQueueHandler(outputDir, sourceFile, exportName, context, owner) {
4897
+ const handlerPath = (0, node_path.join)(outputDir, `${exportName}.ts`);
4898
+ const importPath = (0, node_path.relative)((0, node_path.dirname)(handlerPath), sourceFile).replace(/\.ts$/, ".js");
4899
+ const runtime = require_EndpointGenerator.runtimeFor(context, (0, node_path.dirname)(handlerPath), owner);
4900
+ const content = `import { AWSLambdaQueue } from '@geekmidas/constructs/aws';
4901
+ import { ${exportName} } from '${importPath}';
4902
+ ${runtime.imports}
4903
+ ${context.storageDrivers?.imports ?? ""}
4904
+ ${runtime.bindings}
4905
+ ${context.storageDrivers?.setup ? `\n// The handler registers the drivers its target needs.\n${context.storageDrivers.setup}\n` : ""}
4906
+ const adapter = new AWSLambdaQueue(envParser, ${exportName});
4907
+
4908
+ export const handler = adapter.handler;
4909
+ `;
4910
+ await (0, node_fs_promises.writeFile)(handlerPath, content);
4911
+ return handlerPath;
4912
+ }
4913
+ async generateServerQueuesFile(outputDir, queues) {
4914
+ await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
4915
+ const queuesPath = (0, node_path.join)(outputDir, "queues.ts");
4916
+ if (queues.length === 0) {
4917
+ await (0, node_fs_promises.writeFile)(queuesPath, `/**
4918
+ * Generated queues setup — this app declares none.
4919
+ */
4920
+ import type { EnvironmentParser } from '@geekmidas/envkit';
4921
+ import type { Logger } from '@geekmidas/logger';
4922
+
4923
+ export async function setupQueues(
4924
+ _envParser: EnvironmentParser<any>,
4925
+ _logger: Logger,
4926
+ ): Promise<void> {}
4927
+
4928
+ export function queuesStatus(): { failed: string[]; connections: unknown[] } {
4929
+ return { failed: [], connections: [] };
4930
+ }
4931
+
4932
+ export async function stopQueues(): Promise<void> {}
4933
+ `);
4934
+ return queuesPath;
4935
+ }
4936
+ const importsByFile = /* @__PURE__ */ new Map();
4937
+ for (const { path, key } of queues) {
4938
+ const importPath = (0, node_path.relative)((0, node_path.dirname)(queuesPath), path.relative).replace(/\.ts$/, ".js");
4939
+ if (!importsByFile.has(importPath)) importsByFile.set(importPath, []);
4940
+ importsByFile.get(importPath)?.push(key);
4941
+ }
4942
+ const content = `/**
4943
+ * Generated queue consumers setup.
4944
+ *
4945
+ * Each queue's one consumer polls its own queue, through the queue's own
4946
+ * connection string — the one its producers publish on. SQS cannot push, so
4947
+ * this is a poller on every transport: pg-boss locally by default, the SQS
4948
+ * queue on the AWS emulator.
4949
+ *
4950
+ * Deployed on Lambda, a queue's consumer is an SQS event source instead.
4951
+ */
4952
+ import type { EnvironmentParser } from '@geekmidas/envkit';
4953
+ import type { Logger } from '@geekmidas/logger';
4954
+ import { EventConnectionFactory, Subscriber } from '@geekmidas/events';
4955
+ import type { EventConnection } from '@geekmidas/events';
4956
+ import { ServiceDiscovery } from '@geekmidas/services';
4957
+ ${Array.from(importsByFile.entries()).map(([importPath, exports]) => `import { ${exports.join(", ")} } from '${importPath}';`).join("\n")}
4958
+
4959
+ const queues = [
4960
+ ${queues.map(({ key, construct }) => ` { queue: ${key}, connectionKey: '${(0, _geekmidas_manifest.provideKey)(construct.id, "publisherConnectionString")}' },`).join("\n")}
4961
+ ];
4962
+
4963
+ // What was opened, and what could not be: a worker's health check reads both,
4964
+ // and its shutdown closes what was opened.
4965
+ const connections = new Map<string, EventConnection>();
4966
+ const failed: string[] = [];
4967
+
4968
+ export async function setupQueues(
4969
+ envParser: EnvironmentParser<any>,
4970
+ logger: Logger,
4971
+ ): Promise<void> {
4972
+ const serviceDiscovery = ServiceDiscovery.getInstance(envParser);
4973
+
4974
+ for (const { queue, connectionKey } of queues) {
4975
+ const connectionString = process.env[connectionKey];
4976
+ if (!connectionString) {
4977
+ logger.error({ queue: queue.name, connectionKey }, 'No connection string for this queue');
4978
+ failed.push(queue.name);
4979
+ continue;
4980
+ }
4981
+
4982
+ try {
4983
+ let connection = connections.get(connectionString);
4984
+ if (!connection) {
4985
+ connection = await EventConnectionFactory.fromConnectionString(connectionString);
4986
+ connections.set(connectionString, connection);
4987
+ }
4988
+ const eventSubscriber = await Subscriber.fromConnection(connection);
4989
+ const services = queue.services.length > 0
4990
+ ? await serviceDiscovery.register(queue.services)
4991
+ : {};
4992
+ // The queue's database — the worker's, or its own — handed over as \`db\`.
4993
+ const db = queue.databaseService
4994
+ ? (await serviceDiscovery.register([queue.databaseService]))[
4995
+ queue.databaseService.serviceName
4996
+ ]
4997
+ : undefined;
4998
+
4999
+ // A queue's messages carry one type — its own name.
5000
+ await eventSubscriber.subscribe([queue.name], async (message) => {
5001
+ try {
5002
+ const validation = await queue.messageSchema['~standard'].validate(message.payload);
5003
+ if (validation.issues) {
5004
+ logger.error({ issues: validation.issues, queue: queue.name }, 'Queue message failed validation');
5005
+ return;
5006
+ }
5007
+
5008
+ await queue.handler({
5009
+ messages: [validation.value],
5010
+ services: services,
5011
+ logger: queue.logger,
5012
+ db,
5013
+ } as any);
5014
+ } catch (error) {
5015
+ logger.error({ err: error, queue: queue.name }, 'Failed to process queue message');
5016
+ // Rethrown so the transport keeps the message for a retry.
5017
+ throw error;
5018
+ }
5019
+ });
5020
+ logger.info({ queue: queue.name }, 'Queue consumer started polling');
5021
+ } catch (error) {
5022
+ logger.error({ err: error, queue: queue.name }, 'Failed to set up queue consumer');
5023
+ failed.push(queue.name);
5024
+ }
5025
+ }
5026
+ }
5027
+
5028
+ /** The consumers that could not start, and the connections that did. */
5029
+ export function queuesStatus(): { failed: string[]; connections: EventConnection[] } {
5030
+ return { failed: [...failed], connections: [...connections.values()] };
5031
+ }
5032
+
5033
+ /**
5034
+ * Stop polling, let the messages in flight finish, and close each broker
5035
+ * connection — pg-boss's graceful stop does all three. The caller bounds it.
5036
+ */
5037
+ export async function stopQueues(): Promise<void> {
5038
+ const open = [...connections.values()];
5039
+ connections.clear();
5040
+ await Promise.all(open.map((connection) => connection.close()));
5041
+ }
5042
+ `;
5043
+ await (0, node_fs_promises.writeFile)(queuesPath, content);
5044
+ return queuesPath;
5045
+ }
5046
+ };
5047
+ //#endregion
5048
+ //#region src/generators/WorkerGenerator.ts
5049
+ /**
5050
+ * A worker whose topic subscribers would have to be pushed to over HTTP.
5051
+ *
5052
+ * On SNS a subscriber is an HTTP endpoint SNS delivers to, and a worker's
5053
+ * process serves nothing but its health check. A server target's broker is
5054
+ * pg-boss, where each subscriber polls a queue of its own, so this is only
5055
+ * reached by building server images for a project that deploys to AWS — where
5056
+ * a subscriber is a Lambda instead.
5057
+ */
5058
+ var WorkerSubscribersNeedPush = class extends Error {
5059
+ worker;
5060
+ subscribers;
5061
+ constructor(worker, subscribers) {
5062
+ super(`The worker '${worker}' runs topic subscribers (${subscribers.join(", ")}), and this build's broker is SNS, which pushes each event to its subscriber over HTTP. A worker image serves only its health check. Deploy to a server target, whose broker is pg-boss and whose subscribers poll, or to AWS, where each subscriber is a Lambda.`);
5063
+ this.worker = worker;
5064
+ this.subscribers = subscribers;
5065
+ this.name = "WorkerSubscribersNeedPush";
5066
+ }
5067
+ };
5068
+ /** Where a worker's generated entry lives, under an app's `.gkm/server`. */
5069
+ function workerEntryDir(serverDir, workerId) {
5070
+ return (0, node_path.join)(serverDir, "workers", require_derive.appKey(workerId));
5071
+ }
5072
+ /** The file a worker's bundle is written to, beside the server's. */
5073
+ function workerBundleName(workerId) {
5074
+ return `worker-${require_derive.appKey(workerId)}.mjs`;
5075
+ }
5076
+ /**
5077
+ * A Worker's production entry: the process that runs its crons, its queue
5078
+ * consumers and its topic subscribers, and answers nothing but a health check.
5079
+ *
5080
+ * It is the server's runtime without the server. The `crons.ts`, `queues.ts`
5081
+ * and `subscribers.ts` it starts are the files `gkm dev` starts — written by
5082
+ * the same generators, given only this worker's constructs — so a consumer
5083
+ * runs the same code in development and in the image. What it adds is the
5084
+ * process around them: drivers, a health check that says when a consumer or
5085
+ * the broker is down, and a shutdown that drains.
5086
+ */
5087
+ var WorkerGenerator = class {
5088
+ generators;
5089
+ constructor(generators = {
5090
+ cron: new CronGenerator(),
5091
+ queue: new QueueGenerator(),
5092
+ subscriber: new require_SubscriberGenerator.SubscriberGenerator()
5093
+ }) {
5094
+ this.generators = generators;
5095
+ }
5096
+ /** Write the worker's files; returns its entry, `worker.ts`. */
5097
+ async build(input) {
5098
+ const { context, workerId, outputDir } = input;
5099
+ if (input.subscribers.length > 0 && context.eventsBackends?.includes("sns")) throw new WorkerSubscribersNeedPush(workerId, input.subscribers.map(({ key }) => key));
5100
+ await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
5101
+ const options = { target: "server" };
5102
+ await Promise.all([
5103
+ this.generators.cron.build(context, input.crons, outputDir, options),
5104
+ this.generators.queue.build(context, input.queues, outputDir, options),
5105
+ this.generators.subscriber.build(context, input.subscribers, outputDir, options)
5106
+ ]);
5107
+ await (0, node_fs_promises.writeFile)((0, node_path.join)(outputDir, "app.ts"), workerApp(context, workerId, outputDir));
5108
+ await (0, node_fs_promises.writeFile)((0, node_path.join)(outputDir, "telemetry.ts"), require_EndpointGenerator.generateTelemetryModule(context.telemetry ? {
5109
+ ...context.telemetry,
5110
+ serviceName: workerId
5111
+ } : void 0));
5112
+ const entry = (0, node_path.join)(outputDir, "worker.ts");
5113
+ await (0, node_fs_promises.writeFile)(entry, workerEntry(context.production?.healthCheck ?? "/health"));
5114
+ return entry;
5115
+ }
5116
+ };
5117
+ /**
5118
+ * `app.ts`: the worker's runtime — its logger and environment parser off the
5119
+ * Worker construct, the drivers its target needs, and a `startWorker` that
5120
+ * starts every cron, consumer and subscriber it owns.
5121
+ */
5122
+ function workerApp(context, workerId, outputDir) {
5123
+ const runtime = require_EndpointGenerator.runtimeFor(context, outputDir, workerId);
5124
+ return `/**
5125
+ * Generated worker runtime for ${workerId}.
5126
+ * Generated by 'gkm build --production'.
5127
+ */
5128
+ import { setupCrons, cronsStatus, stopCrons } from './crons.js';
5129
+ import { setupQueues, queuesStatus, stopQueues } from './queues.js';
5130
+ import { setupSubscribers, subscribersStatus, stopSubscribers } from './subscribers.js';
5131
+ ${runtime.imports}
5132
+ ${context.storageDrivers?.imports ?? ""}
5133
+
5134
+ ${runtime.bindings}
5135
+
5136
+ ${context.storageDrivers?.setup ? `// The entry point registers the drivers its target needs.
5137
+ ${context.storageDrivers.setup}
5138
+ ` : ""}
5139
+ // Who this worker is to Postgres: application_name on every connection.
5140
+ process.env.GKM_APP_NAME ??= ${JSON.stringify(workerId)};
5141
+
5142
+ export { logger };
5143
+
5144
+ /** What the health check answers, and why. */
5145
+ export interface WorkerHealth {
5146
+ healthy: boolean;
5147
+ /** The crons, queues and subscribers that could not start. */
5148
+ failed: string[];
5149
+ /** How many broker connections did not answer. */
5150
+ down: number;
5151
+ }
5152
+
5153
+ /** Whether one broker connection answers: open, and — on pg-boss — a query. */
5154
+ async function answers(connection: unknown): Promise<boolean> {
5155
+ const c = connection as {
5156
+ isConnected?: () => boolean;
5157
+ instance?: { getDb?: () => { executeSql: (sql: string) => Promise<unknown> } };
5158
+ };
5159
+ if (c.isConnected && !c.isConnected()) return false;
5160
+ const db = c.instance?.getDb?.();
5161
+ if (!db) return true;
5162
+ try {
5163
+ await Promise.race([
5164
+ db.executeSql('select 1'),
5165
+ new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), 2000).unref()),
5166
+ ]);
5167
+ return true;
5168
+ } catch {
5169
+ return false;
5170
+ }
5171
+ }
5172
+
5173
+ /** Start everything this worker runs. */
5174
+ export async function startWorker(): Promise<{
5175
+ health: () => Promise<WorkerHealth>;
5176
+ stop: () => Promise<void>;
5177
+ }> {
5178
+ // An app object with no routes: on a server target nothing is pushed to a
5179
+ // subscriber, so there is nothing to mount.
5180
+ const noRoutes = { post: () => undefined };
5181
+
5182
+ await setupSubscribers(noRoutes, envParser, logger).catch((error) => {
5183
+ logger.error({ err: error }, 'Failed to start subscribers');
5184
+ });
5185
+ await setupQueues(envParser, logger).catch((error) => {
5186
+ logger.error({ err: error }, 'Failed to start queue consumers');
5187
+ });
5188
+ await setupCrons(envParser, logger).catch((error) => {
5189
+ logger.error({ err: error }, 'Failed to schedule crons');
5190
+ });
5191
+
5192
+ const statuses = () => [subscribersStatus(), queuesStatus(), cronsStatus()];
5193
+
5194
+ return {
5195
+ async health() {
5196
+ const all = statuses();
5197
+ const failed = all.flatMap((s) => s.failed);
5198
+ const alive = await Promise.all(
5199
+ all.flatMap((s) => s.connections as unknown[]).map(answers),
5200
+ );
5201
+ const down = alive.filter((ok) => !ok).length;
5202
+ return { healthy: failed.length === 0 && down === 0, failed, down };
5203
+ },
5204
+ // Each stops pulling, waits for what it has in flight, and closes its
5205
+ // broker connection. Together, so one slow handler does not hold the
5206
+ // others' connections open.
5207
+ async stop() {
5208
+ await Promise.all([stopSubscribers(), stopQueues(), stopCrons()]);
5209
+ },
5210
+ };
5211
+ }
5212
+ `;
5213
+ }
5214
+ /**
5215
+ * `worker.ts`: the process. Health first, so the container answers while the
5216
+ * consumers connect; then the worker; then a shutdown that drains.
5217
+ */
5218
+ function workerEntry(healthCheck) {
5219
+ return `#!/usr/bin/env node
5220
+ /**
5221
+ * Production worker entry point.
5222
+ * Generated by 'gkm build --production'.
5223
+ *
5224
+ * Runs this worker's crons, queue consumers and topic subscribers, and serves
5225
+ * one route: ${healthCheck}, on PORT — 200 when every consumer started and
5226
+ * every broker connection answers, 503 otherwise.
5227
+ *
5228
+ * On SIGTERM it stops pulling messages and scheduling crons, lets the handlers
5229
+ * in flight finish, closes its broker connections and database pools, and
5230
+ * exits 0 — or 1, at GKM_SHUTDOWN_TIMEOUT_MS (8s by default, under Docker's
5231
+ * 10s stop timeout).
5232
+ */
5233
+ import { createServer } from 'node:http';
5234
+ import { runShutdownHooks } from '@geekmidas/constructs';
5235
+ import { startTelemetry } from './telemetry.js';
5236
+
5237
+ // Before the worker is imported, so the libraries it loads are instrumented.
5238
+ await startTelemetry({ ignorePaths: [${JSON.stringify(healthCheck)}] });
5239
+
5240
+ const { startWorker, logger } = await import('./app.js');
5241
+
5242
+ const port = Number(process.env.PORT) || 3000;
5243
+
5244
+ let worker: Awaited<ReturnType<typeof startWorker>> | undefined;
5245
+ let stopping = false;
5246
+
5247
+ const server = createServer((req, res) => {
5248
+ const path = (req.url ?? '/').split('?')[0];
5249
+ if (path !== ${JSON.stringify(healthCheck)} || (req.method !== 'GET' && req.method !== 'HEAD')) {
5250
+ res.writeHead(404).end();
5251
+ return;
5252
+ }
5253
+ const answer = (status: number, body: unknown) => {
5254
+ res.writeHead(status, { 'content-type': 'application/json' });
5255
+ res.end(JSON.stringify(body));
5256
+ };
5257
+ if (stopping) return answer(503, { status: 'stopping' });
5258
+ if (!worker) return answer(503, { status: 'starting' });
5259
+ worker.health().then(
5260
+ (health) => answer(health.healthy ? 200 : 503, { status: health.healthy ? 'ok' : 'unhealthy', ...health }),
5261
+ (error) => answer(503, { status: 'unhealthy', error: String(error) }),
5262
+ );
5263
+ });
5264
+ server.listen(port);
5265
+
5266
+ const shutdown = async () => {
5267
+ if (stopping) return;
5268
+ stopping = true;
5269
+ const deadline = Number(process.env.GKM_SHUTDOWN_TIMEOUT_MS) || 8000;
5270
+ logger.info({ deadline }, 'Graceful shutdown initiated');
5271
+ setTimeout(() => {
5272
+ logger.warn({ deadline }, 'Shutdown deadline reached, exiting');
5273
+ process.exit(1);
5274
+ }, deadline).unref();
5275
+
5276
+ // Nothing new is pulled or scheduled; what is in flight finishes.
5277
+ await worker?.stop().catch((error) => logger.error({ err: error }, 'Failed to stop the worker'));
5278
+ // Then what the handlers used: database pools.
5279
+ await runShutdownHooks((error) => logger.error({ err: error }, 'Shutdown hook failed'));
5280
+ server.close();
5281
+ logger.info('Worker stopped');
5282
+ process.exit(0);
5283
+ };
5284
+
5285
+ process.on('SIGTERM', shutdown);
5286
+ process.on('SIGINT', shutdown);
5287
+
5288
+ worker = await startWorker();
5289
+ logger.info({ port }, 'Worker started');
5290
+ `;
5291
+ }
5292
+ //#endregion
4537
5293
  //#region src/secrets/encryption.ts
4538
5294
  var encryption_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
4539
5295
  encryptSecrets: () => encryptSecrets,
@@ -4586,6 +5342,74 @@ function keyFingerprint(masterKey) {
4586
5342
  return (0, node_crypto.createHash)("sha256").update(masterKey).digest("hex").slice(0, 8);
4587
5343
  }
4588
5344
  //#endregion
5345
+ //#region src/build/workers.ts
5346
+ /** A worker with background work and no backend app to build it from. */
5347
+ var WorkerHasNoApp = class extends Error {
5348
+ worker;
5349
+ constructor(worker) {
5350
+ super(`The worker '${worker}' has crons, queues or subscribers, and the workspace has no backend app that builds a server to carry its entry. Declare a RestApi whose app holds the worker's code.`);
5351
+ this.worker = worker;
5352
+ this.name = "WorkerHasNoApp";
5353
+ }
5354
+ };
5355
+ /** A worker whose service name an app already has. */
5356
+ var WorkerNameTaken = class extends Error {
5357
+ worker;
5358
+ service;
5359
+ constructor(worker, service) {
5360
+ super(`The worker '${worker}' runs as the service '${service}', and an app is already called that. Rename the worker — new Worker('${worker}Worker') — so each container has a name of its own.`);
5361
+ this.worker = worker;
5362
+ this.service = service;
5363
+ this.name = "WorkerNameTaken";
5364
+ }
5365
+ };
5366
+ /**
5367
+ * The workers a workspace deploys — each one that has background work — and
5368
+ * the app each is built from.
5369
+ *
5370
+ * The host is the backend app whose directory holds the most of the worker's
5371
+ * files; one whose work sits outside every app (a shared `jobs/` directory)
5372
+ * is built by the first backend, by name, that generates a server. An app
5373
+ * with its own entry is never one — gkm's generators do not build it — and a
5374
+ * surface that serves itself, an auth server, only when it holds the work.
5375
+ *
5376
+ * @param background Each worker's files, from discovery's `background`.
5377
+ */
5378
+ function workerUnits(workspace, manifest, background) {
5379
+ const hosts = Object.entries(workspace.apps).filter(([, app]) => app.type === "backend" && !app.entry).map(([name, app]) => {
5380
+ const surface = Object.entries(manifest).find(([id, d]) => d.kind === "rest-api" && require_derive.appKey(id) === name)?.[1];
5381
+ return {
5382
+ name,
5383
+ root: (0, node_path.isAbsolute)(app.path) ? app.path : (0, node_path.join)(workspace.root, app.path),
5384
+ generated: !(surface?.kind === "rest-api" && surface.endpoints.length > 0)
5385
+ };
5386
+ }).sort((a, b) => a.name.localeCompare(b.name));
5387
+ const units = [];
5388
+ for (const [id, declaration] of Object.entries(manifest)) {
5389
+ if (declaration.kind !== "worker") continue;
5390
+ const files = background[id] ?? [];
5391
+ if (files.length === 0) continue;
5392
+ const name = require_derive.appKey(id);
5393
+ if (workspace.apps[name]) throw new WorkerNameTaken(id, name);
5394
+ const ranked = hosts.map((host) => ({
5395
+ host,
5396
+ holds: files.filter((file) => isUnder(file, host.root)).length
5397
+ })).sort((a, b) => b.holds - a.holds || Number(b.host.generated) - Number(a.host.generated));
5398
+ const host = ranked[0]?.host;
5399
+ if (!host || ranked[0].holds === 0 && !host.generated) throw new WorkerHasNoApp(id);
5400
+ units.push({
5401
+ id,
5402
+ name,
5403
+ app: host.name
5404
+ });
5405
+ }
5406
+ return units.sort((a, b) => a.name.localeCompare(b.name));
5407
+ }
5408
+ function isUnder(file, dir) {
5409
+ const rel = (0, node_path.relative)(dir, file);
5410
+ return rel !== "" && !rel.startsWith("..") && !(0, node_path.isAbsolute)(rel) ? !rel.startsWith(`..${node_path.sep}`) : false;
5411
+ }
5412
+ //#endregion
4589
5413
  //#region src/deploy/devServices.ts
4590
5414
  /**
4591
5415
  * Mail and object storage on a deployed stage: real ones, or — only when
@@ -5043,7 +5867,7 @@ async function dockerCommand(options) {
5043
5867
  const cwd = options.cwd ?? process.cwd();
5044
5868
  const loaded = await require_config.loadWorkspaceConfig(cwd);
5045
5869
  const names = loaded.type === "single" ? Object.fromEntries(Object.keys(loaded.workspace.apps).map((name) => [name, resolveDockerConfig(loaded.raw).imageName])) : {};
5046
- const result = await workspaceDockerCommand(loaded.workspace, loaded.manifest, names);
5870
+ const result = await workspaceDockerCommand(loaded.workspace, loaded.manifest, names, loaded.background);
5047
5871
  if (options.build) for (const app of result.apps) await buildDockerImage(app, result.buildRoot, options);
5048
5872
  if (options.push) for (const app of result.apps) await pushDockerImage(app.imageName, options, result.buildRoot);
5049
5873
  return result;
@@ -5095,7 +5919,7 @@ async function pushDockerImage(imageName, options, cwd) {
5095
5919
  * Generate Dockerfiles for all apps in a workspace.
5096
5920
  * @internal Exported for testing
5097
5921
  */
5098
- async function workspaceDockerCommand(workspace, manifest, imageNames = {}) {
5922
+ async function workspaceDockerCommand(workspace, manifest, imageNames = {}, background = {}) {
5099
5923
  const results = [];
5100
5924
  const layout = imageLayout(workspace);
5101
5925
  logger$1.log(`\n🐳 Generating Dockerfiles for workspace: ${workspace.name}`);
@@ -5125,6 +5949,24 @@ async function workspaceDockerCommand(workspace, manifest, imageNames = {}) {
5125
5949
  imageName: imageNames[appName] ?? appName
5126
5950
  });
5127
5951
  }
5952
+ for (const worker of manifest ? workerUnits(workspace, manifest, background) : []) {
5953
+ logger$1.log(`\n 📄 Generating Dockerfile for ${worker.name} (worker ${worker.id}, built from ${worker.app})`);
5954
+ const dockerfile = workerDockerfile(worker, workspace.apps[worker.app], {
5955
+ layout,
5956
+ workspaceRoot: workspace.root
5957
+ });
5958
+ const path = workerDockerfileOf(worker.name);
5959
+ const dockerfilePath = (0, node_path.join)(workspace.root, path);
5960
+ await (0, node_fs_promises.mkdir)((0, node_path.dirname)(dockerfilePath), { recursive: true });
5961
+ await (0, node_fs_promises.writeFile)(dockerfilePath, dockerfile);
5962
+ logger$1.log(` Generated: ${path}`);
5963
+ results.push({
5964
+ appName: worker.name,
5965
+ type: "backend",
5966
+ dockerfile: dockerfilePath,
5967
+ imageName: imageNames[worker.name] ?? worker.name
5968
+ });
5969
+ }
5128
5970
  const dockerignorePath = await ensureDockerignore(layout.buildRoot);
5129
5971
  logger$1.log(`\n Ensured: ${dockerignorePath}`);
5130
5972
  const composePath = await writeConstructsCompose(workspace);
@@ -5164,6 +6006,24 @@ function appDockerfile(appName, app, options) {
5164
6006
  healthCheckPath: "/health"
5165
6007
  });
5166
6008
  }
6009
+ /** Where `gkm docker` writes a worker's Dockerfile. */
6010
+ function workerDockerfileOf(worker) {
6011
+ return `.gkm/docker/Dockerfile.${worker}`;
6012
+ }
6013
+ /**
6014
+ * A Worker's Dockerfile: its host app's build, and the worker's bundle as the
6015
+ * runner — see `generateWorkerDockerfile`.
6016
+ */
6017
+ function workerDockerfile(worker, host, options) {
6018
+ return generateWorkerDockerfile({
6019
+ ...appImageOptions(options.layout, worker.app, host, options.workspaceRoot),
6020
+ imageName: worker.name,
6021
+ port: WORKER_PORT,
6022
+ worker: worker.id,
6023
+ bundle: workerBundleName(worker.id),
6024
+ healthCheckPath: "/health"
6025
+ });
6026
+ }
5167
6027
  /**
5168
6028
  * A site's Dockerfile, with an `ARG` for every key its bundler inlines.
5169
6029
  *
@@ -5401,7 +6261,7 @@ async function deployDocker(options) {
5401
6261
  const cwd = options.cwd ?? process.cwd();
5402
6262
  const docker = {
5403
6263
  cwd,
5404
- dockerfile: (0, node_path.join)(cwd, dockerfileOf(config.appName ?? imageName, options.appPath ?? ".")),
6264
+ dockerfile: (0, node_path.join)(cwd, options.dockerfile ?? dockerfileOf(config.appName ?? imageName, options.appPath ?? ".")),
5405
6265
  ...options.signal ? { signal: options.signal } : {},
5406
6266
  ...options.stdio ? { stdio: options.stdio } : {}
5407
6267
  };
@@ -5733,6 +6593,12 @@ function setPostgresBackupId(state, backupId) {
5733
6593
  if (state.backups) state.backups.postgresBackupId = backupId;
5734
6594
  }
5735
6595
  //#endregion
6596
+ Object.defineProperty(exports, "CronGenerator", {
6597
+ enumerable: true,
6598
+ get: function() {
6599
+ return CronGenerator;
6600
+ }
6601
+ });
5736
6602
  Object.defineProperty(exports, "DEFAULT_IMAGES", {
5737
6603
  enumerable: true,
5738
6604
  get: function() {
@@ -5787,6 +6653,12 @@ Object.defineProperty(exports, "NoDomainForStage", {
5787
6653
  return NoDomainForStage;
5788
6654
  }
5789
6655
  });
6656
+ Object.defineProperty(exports, "QueueGenerator", {
6657
+ enumerable: true,
6658
+ get: function() {
6659
+ return QueueGenerator;
6660
+ }
6661
+ });
5790
6662
  Object.defineProperty(exports, "STORAGE_KEY_PAIR", {
5791
6663
  enumerable: true,
5792
6664
  get: function() {
@@ -5805,6 +6677,18 @@ Object.defineProperty(exports, "UnknownDevService", {
5805
6677
  return UnknownDevService;
5806
6678
  }
5807
6679
  });
6680
+ Object.defineProperty(exports, "WORKER_PORT", {
6681
+ enumerable: true,
6682
+ get: function() {
6683
+ return WORKER_PORT;
6684
+ }
6685
+ });
6686
+ Object.defineProperty(exports, "WorkerGenerator", {
6687
+ enumerable: true,
6688
+ get: function() {
6689
+ return WorkerGenerator;
6690
+ }
6691
+ });
5808
6692
  Object.defineProperty(exports, "appDockerfile", {
5809
6693
  enumerable: true,
5810
6694
  get: function() {
@@ -6381,6 +7265,42 @@ Object.defineProperty(exports, "withGeneratedSecrets", {
6381
7265
  return withGeneratedSecrets;
6382
7266
  }
6383
7267
  });
7268
+ Object.defineProperty(exports, "workerBundleName", {
7269
+ enumerable: true,
7270
+ get: function() {
7271
+ return workerBundleName;
7272
+ }
7273
+ });
7274
+ Object.defineProperty(exports, "workerDockerfile", {
7275
+ enumerable: true,
7276
+ get: function() {
7277
+ return workerDockerfile;
7278
+ }
7279
+ });
7280
+ Object.defineProperty(exports, "workerDockerfileOf", {
7281
+ enumerable: true,
7282
+ get: function() {
7283
+ return workerDockerfileOf;
7284
+ }
7285
+ });
7286
+ Object.defineProperty(exports, "workerEntryDir", {
7287
+ enumerable: true,
7288
+ get: function() {
7289
+ return workerEntryDir;
7290
+ }
7291
+ });
7292
+ Object.defineProperty(exports, "workerEnvKeys", {
7293
+ enumerable: true,
7294
+ get: function() {
7295
+ return workerEnvKeys;
7296
+ }
7297
+ });
7298
+ Object.defineProperty(exports, "workerUnits", {
7299
+ enumerable: true,
7300
+ get: function() {
7301
+ return workerUnits;
7302
+ }
7303
+ });
6384
7304
  Object.defineProperty(exports, "workspace_exports", {
6385
7305
  enumerable: true,
6386
7306
  get: function() {
@@ -6388,4 +7308,4 @@ Object.defineProperty(exports, "workspace_exports", {
6388
7308
  }
6389
7309
  });
6390
7310
 
6391
- //# sourceMappingURL=state-CCuTJNRH.cjs.map
7311
+ //# sourceMappingURL=state-DMjFPOhf.cjs.map