@geekmidas/cli 1.10.30 → 1.10.31

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 (135) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/{CachedStateProvider-37pG1HBx.cjs → CachedStateProvider-3couMAQk.cjs} +1 -1
  3. package/dist/CachedStateProvider-C4QqvlPE.mjs +3 -0
  4. package/dist/{CachedStateProvider-C8A-cCm5.mjs → CachedStateProvider-CQr31ups.mjs} +1 -1
  5. package/dist/{CachedStateProvider-C8A-cCm5.mjs.map → CachedStateProvider-CQr31ups.mjs.map} +1 -1
  6. package/dist/{CachedStateProvider-CxsXOKkg.cjs → CachedStateProvider-Cyn17x3x.cjs} +1 -1
  7. package/dist/{CachedStateProvider-CxsXOKkg.cjs.map → CachedStateProvider-Cyn17x3x.cjs.map} +1 -1
  8. package/dist/{HostingerProvider-5KYmwoK2.cjs → HostingerProvider-C5oLa7N7.cjs} +1 -1
  9. package/dist/{HostingerProvider-5KYmwoK2.cjs.map → HostingerProvider-C5oLa7N7.cjs.map} +1 -1
  10. package/dist/{HostingerProvider-ANWchdiK.mjs → HostingerProvider-YvCg3Mus.mjs} +1 -1
  11. package/dist/{HostingerProvider-ANWchdiK.mjs.map → HostingerProvider-YvCg3Mus.mjs.map} +1 -1
  12. package/dist/{LocalStateProvider-Dp0KkRcw.mjs → LocalStateProvider-BciOhGR0.mjs} +1 -1
  13. package/dist/{LocalStateProvider-Dp0KkRcw.mjs.map → LocalStateProvider-BciOhGR0.mjs.map} +1 -1
  14. package/dist/{LocalStateProvider-CLifRC0Y.cjs → LocalStateProvider-DI6n11UM.cjs} +1 -1
  15. package/dist/{LocalStateProvider-CLifRC0Y.cjs.map → LocalStateProvider-DI6n11UM.cjs.map} +1 -1
  16. package/dist/{Route53Provider-QoPgcXxn.mjs → Route53Provider-CYlDOrYO.mjs} +1 -1
  17. package/dist/{Route53Provider-QoPgcXxn.mjs.map → Route53Provider-CYlDOrYO.mjs.map} +1 -1
  18. package/dist/{Route53Provider-owQQ4pn6.cjs → Route53Provider-DISZ6E8f.cjs} +1 -1
  19. package/dist/{Route53Provider-owQQ4pn6.cjs.map → Route53Provider-DISZ6E8f.cjs.map} +1 -1
  20. package/dist/{SSMStateProvider-CT8tjl9o.cjs → SSMStateProvider-BljH5efc.cjs} +1 -1
  21. package/dist/{SSMStateProvider-CT8tjl9o.cjs.map → SSMStateProvider-BljH5efc.cjs.map} +1 -1
  22. package/dist/{SSMStateProvider-CksOTB8M.mjs → SSMStateProvider-DXT1dIdI.mjs} +1 -1
  23. package/dist/{SSMStateProvider-CksOTB8M.mjs.map → SSMStateProvider-DXT1dIdI.mjs.map} +1 -1
  24. package/dist/{backup-provisioner-BEXoHTuC.mjs → backup-provisioner-CCUcj28C.mjs} +1 -1
  25. package/dist/{backup-provisioner-BEXoHTuC.mjs.map → backup-provisioner-CCUcj28C.mjs.map} +1 -1
  26. package/dist/{backup-provisioner-C4noe75O.cjs → backup-provisioner-CpirEvO1.cjs} +1 -1
  27. package/dist/{backup-provisioner-C4noe75O.cjs.map → backup-provisioner-CpirEvO1.cjs.map} +1 -1
  28. package/dist/{bundler-BG6P249p.cjs → bundler-CLOenWgi.cjs} +2 -2
  29. package/dist/{bundler-BG6P249p.cjs.map → bundler-CLOenWgi.cjs.map} +1 -1
  30. package/dist/{bundler-c6QvGUBM.mjs → bundler-E5VcXsPH.mjs} +2 -2
  31. package/dist/{bundler-c6QvGUBM.mjs.map → bundler-E5VcXsPH.mjs.map} +1 -1
  32. package/dist/client-generator-CUVVtAOo.mjs +23 -0
  33. package/dist/client-generator-CUVVtAOo.mjs.map +1 -0
  34. package/dist/client-generator-D-T4ypQo.cjs +35 -0
  35. package/dist/client-generator-D-T4ypQo.cjs.map +1 -0
  36. package/dist/{config-jsRYHOHU.mjs → config-B62g483e.mjs} +2 -2
  37. package/dist/{config-jsRYHOHU.mjs.map → config-B62g483e.mjs.map} +1 -1
  38. package/dist/{config-D3ORuiUs.cjs → config-Cuo8vFsp.cjs} +2 -2
  39. package/dist/{config-D3ORuiUs.cjs.map → config-Cuo8vFsp.cjs.map} +1 -1
  40. package/dist/config.cjs +2 -2
  41. package/dist/config.d.cts +1 -1
  42. package/dist/config.d.mts +2 -2
  43. package/dist/config.mjs +2 -2
  44. package/dist/deploy/sniffer-worker.cjs +2 -0
  45. package/dist/deploy/sniffer-worker.cjs.map +1 -1
  46. package/dist/deploy/sniffer-worker.mjs +2 -0
  47. package/dist/deploy/sniffer-worker.mjs.map +1 -1
  48. package/dist/dokploy-api-BPYkG-ZZ.cjs +3 -0
  49. package/dist/dokploy-api-BiSzWM4v.mjs +3 -0
  50. package/dist/{dokploy-api-Dvyq-LsM.cjs → dokploy-api-CqOIKHme.cjs} +1 -1
  51. package/dist/{dokploy-api-Dvyq-LsM.cjs.map → dokploy-api-CqOIKHme.cjs.map} +1 -1
  52. package/dist/{dokploy-api-BIT0683o.mjs → dokploy-api-sfZFlWuE.mjs} +1 -1
  53. package/dist/{dokploy-api-BIT0683o.mjs.map → dokploy-api-sfZFlWuE.mjs.map} +1 -1
  54. package/dist/{encryption-CipsS0KW.cjs → encryption-BVS7Vmzs.cjs} +1 -1
  55. package/dist/encryption-Bd_m4q3g.mjs +3 -0
  56. package/dist/{encryption-DSkIlEZ6.mjs → encryption-CO5Q4Bhf.mjs} +1 -1
  57. package/dist/{encryption-DSkIlEZ6.mjs.map → encryption-CO5Q4Bhf.mjs.map} +1 -1
  58. package/dist/{encryption-DgKS-Dv9.cjs → encryption-MfXAiFTm.cjs} +1 -1
  59. package/dist/{encryption-DgKS-Dv9.cjs.map → encryption-MfXAiFTm.cjs.map} +1 -1
  60. package/dist/{index-CY-ieuRp.d.mts → index-C-_rW4KF.d.mts} +3 -33
  61. package/dist/index-C-_rW4KF.d.mts.map +1 -0
  62. package/dist/{index-BkibYzso.d.cts → index-C3t5VL4R.d.cts} +2 -32
  63. package/dist/index-C3t5VL4R.d.cts.map +1 -0
  64. package/dist/index.cjs +94 -379
  65. package/dist/index.cjs.map +1 -1
  66. package/dist/index.mjs +70 -355
  67. package/dist/index.mjs.map +1 -1
  68. package/dist/{openapi-CTARkkkn.mjs → openapi-DHq5r17U.mjs} +6 -41
  69. package/dist/openapi-DHq5r17U.mjs.map +1 -0
  70. package/dist/{openapi-react-query-C4UdILaI.mjs → openapi-react-query-COpH7Mmz.mjs} +1 -1
  71. package/dist/{openapi-react-query-C4UdILaI.mjs.map → openapi-react-query-COpH7Mmz.mjs.map} +1 -1
  72. package/dist/{openapi-react-query-DYbBq-WJ.cjs → openapi-react-query-CxyQTTdF.cjs} +1 -1
  73. package/dist/{openapi-react-query-DYbBq-WJ.cjs.map → openapi-react-query-CxyQTTdF.cjs.map} +1 -1
  74. package/dist/openapi-react-query.cjs +1 -1
  75. package/dist/openapi-react-query.mjs +1 -1
  76. package/dist/{openapi-ClA8lIhO.cjs → openapi-w-_smBTO.cjs} +6 -53
  77. package/dist/openapi-w-_smBTO.cjs.map +1 -0
  78. package/dist/openapi.cjs +4 -3
  79. package/dist/openapi.d.mts +1 -1
  80. package/dist/openapi.mjs +4 -3
  81. package/dist/{reconcile-CZtzdrnc.cjs → reconcile-C8KIy4Uy.cjs} +1 -1
  82. package/dist/{reconcile-CZtzdrnc.cjs.map → reconcile-C8KIy4Uy.cjs.map} +1 -1
  83. package/dist/{reconcile-DAAKa0YR.mjs → reconcile-D423q2QW.mjs} +1 -1
  84. package/dist/{reconcile-DAAKa0YR.mjs.map → reconcile-D423q2QW.mjs.map} +1 -1
  85. package/dist/sniffer-BqSVVrWA.mjs +356 -0
  86. package/dist/sniffer-BqSVVrWA.mjs.map +1 -0
  87. package/dist/sniffer-CBhzByiY.cjs +386 -0
  88. package/dist/sniffer-CBhzByiY.cjs.map +1 -0
  89. package/dist/sniffer-Cpq_cbyz.mjs +4 -0
  90. package/dist/sniffer-eZ13G10M.cjs +4 -0
  91. package/dist/sync-B2CN_KS5.cjs +4 -0
  92. package/dist/{sync-DGXXSk2v.cjs → sync-BWY6yoUG.cjs} +1 -1
  93. package/dist/{sync-DGXXSk2v.cjs.map → sync-BWY6yoUG.cjs.map} +1 -1
  94. package/dist/{sync-D_NowTkZ.mjs → sync-Dc-QA4Mx.mjs} +1 -1
  95. package/dist/{sync-D_NowTkZ.mjs.map → sync-Dc-QA4Mx.mjs.map} +1 -1
  96. package/dist/{sync-COnAugP-.mjs → sync-fzT5WX_y.mjs} +1 -1
  97. package/dist/{types-OszPdw9m.d.mts → types-BqAbYt5a.d.mts} +1 -1
  98. package/dist/{types-OszPdw9m.d.mts.map → types-BqAbYt5a.d.mts.map} +1 -1
  99. package/dist/workspace/index.cjs +1 -1
  100. package/dist/workspace/index.d.cts +2 -2
  101. package/dist/workspace/index.d.mts +3 -3
  102. package/dist/workspace/index.mjs +1 -1
  103. package/dist/{workspace-D4z4A4cq.mjs → workspace-Bi4X7Yzy.mjs} +1 -6
  104. package/dist/{workspace-D4z4A4cq.mjs.map → workspace-Bi4X7Yzy.mjs.map} +1 -1
  105. package/dist/{workspace-4SP3Gx4Y.cjs → workspace-CGYykWfn.cjs} +1 -6
  106. package/dist/{workspace-4SP3Gx4Y.cjs.map → workspace-CGYykWfn.cjs.map} +1 -1
  107. package/package.json +2 -2
  108. package/src/__tests__/openapi.spec.ts +0 -315
  109. package/src/build/__tests__/manifests.spec.ts +66 -0
  110. package/src/build/index.ts +54 -1
  111. package/src/deploy/__tests__/__fixtures__/env-parsers/optional-env-parser.ts +21 -0
  112. package/src/deploy/__tests__/sniffer.spec.ts +123 -0
  113. package/src/deploy/sniffer-worker.ts +2 -1
  114. package/src/deploy/sniffer.ts +86 -12
  115. package/src/docker/compose.ts +2 -0
  116. package/src/index.ts +8 -0
  117. package/src/init/generators/monorepo.ts +15 -1
  118. package/src/init/index.ts +2 -4
  119. package/src/init/versions.ts +1 -1
  120. package/src/openapi.ts +1 -35
  121. package/src/types.ts +7 -0
  122. package/src/workspace/__tests__/client-generator.spec.ts +1 -485
  123. package/src/workspace/client-generator.ts +1 -145
  124. package/src/workspace/index.ts +0 -1
  125. package/src/workspace/schema.ts +0 -9
  126. package/src/workspace/types.ts +0 -29
  127. package/dist/CachedStateProvider-CC0DyO09.mjs +0 -3
  128. package/dist/dokploy-api-BOx71j6F.cjs +0 -3
  129. package/dist/dokploy-api-BZGk-lkD.mjs +0 -3
  130. package/dist/encryption-Db2zvGqM.mjs +0 -3
  131. package/dist/index-BkibYzso.d.cts.map +0 -1
  132. package/dist/index-CY-ieuRp.d.mts.map +0 -1
  133. package/dist/openapi-CTARkkkn.mjs.map +0 -1
  134. package/dist/openapi-ClA8lIhO.cjs.map +0 -1
  135. package/dist/sync-D1Pa30oV.cjs +0 -4
package/dist/index.mjs CHANGED
@@ -1,16 +1,18 @@
1
1
  #!/usr/bin/env -S npx tsx
2
2
  import { __require } from "./chunk-Duj1WY3L.mjs";
3
- import { getAppBuildOrder, getDependencyEnvVars, getDeployTargetError, isDeployTargetSupported } from "./workspace-D4z4A4cq.mjs";
4
- import { getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceAppInfo, loadWorkspaceConfig, parseModuleConfig } from "./config-jsRYHOHU.mjs";
3
+ import { getAppBuildOrder, getDependencyEnvVars, getDeployTargetError, isDeployTargetSupported } from "./workspace-Bi4X7Yzy.mjs";
4
+ import { getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceAppInfo, loadWorkspaceConfig, parseModuleConfig } from "./config-B62g483e.mjs";
5
5
  import { getCredentialsPath, getDokployCredentials, getDokployRegistryId, getDokployToken, removeDokployCredentials, storeDokployCredentials, storeDokployRegistryId } from "./credentials-s1kLcIzK.mjs";
6
6
  import { createStageSecrets, generateConnectionUrls, generateDbPassword, generateDbUrl, generateFullstackCustomSecrets, generateLocalStackCredentials, generatePgBossUrl, generateSecurePassword, generateServiceCredentials, rotateServicePassword, writeDockerEnvFromSecrets } from "./fullstack-secrets-P84v8zWn.mjs";
7
7
  import { getKeyPath, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, writeStageSecrets } from "./storage-dbb9RyBl.mjs";
8
- import { ConstructGenerator, EndpointGenerator, OPENAPI_OUTPUT_PATH, generateOpenApi, isPartitionedRoutes, normalizeRoutes, openapiCommand, resolveOpenApiConfig } from "./openapi-CTARkkkn.mjs";
9
- import { DokployApi } from "./dokploy-api-BIT0683o.mjs";
10
- import { encryptSecrets } from "./encryption-DSkIlEZ6.mjs";
11
- import { CachedStateProvider } from "./CachedStateProvider-C8A-cCm5.mjs";
12
- import { generateReactQueryCommand } from "./openapi-react-query-C4UdILaI.mjs";
13
- import { isSSMConfigured, pullSecrets, pushSecrets } from "./sync-D_NowTkZ.mjs";
8
+ import { isPartitionedRoutes } from "./client-generator-CUVVtAOo.mjs";
9
+ import { ConstructGenerator, EndpointGenerator, OPENAPI_OUTPUT_PATH, generateOpenApi, openapiCommand, resolveOpenApiConfig } from "./openapi-DHq5r17U.mjs";
10
+ import { DokployApi } from "./dokploy-api-sfZFlWuE.mjs";
11
+ import { encryptSecrets } from "./encryption-CO5Q4Bhf.mjs";
12
+ import { sniffAllApps, sniffAppEnvironment } from "./sniffer-BqSVVrWA.mjs";
13
+ import { CachedStateProvider } from "./CachedStateProvider-CQr31ups.mjs";
14
+ import { generateReactQueryCommand } from "./openapi-react-query-COpH7Mmz.mjs";
15
+ import { isSSMConfigured, pullSecrets, pushSecrets } from "./sync-Dc-QA4Mx.mjs";
14
16
  import { createRequire } from "node:module";
15
17
  import { copyFileSync, existsSync, readFileSync, unlinkSync } from "node:fs";
16
18
  import { basename, dirname, join, parse, relative, resolve } from "node:path";
@@ -30,12 +32,11 @@ import { Function } from "@geekmidas/constructs/functions";
30
32
  import { Subscriber } from "@geekmidas/constructs/subscribers";
31
33
  import { Client } from "pg";
32
34
  import { lookup } from "node:dns/promises";
33
- import { fileURLToPath, pathToFileURL } from "node:url";
34
35
  import prompts from "prompts";
35
36
 
36
37
  //#region package.json
37
38
  var name = "@geekmidas/cli";
38
- var version = "1.10.29";
39
+ var version = "1.10.30";
39
40
  var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
40
41
  var private$1 = false;
41
42
  var type = "module";
@@ -138,7 +139,7 @@ const logger$14 = console;
138
139
  * Validate Dokploy token by making a test API call
139
140
  */
140
141
  async function validateDokployToken(endpoint, token) {
141
- const { DokployApi: DokployApi$1 } = await import("./dokploy-api-BZGk-lkD.mjs");
142
+ const { DokployApi: DokployApi$1 } = await import("./dokploy-api-BiSzWM4v.mjs");
142
143
  const api = new DokployApi$1({
143
144
  baseUrl: endpoint,
144
145
  token
@@ -2202,18 +2203,25 @@ async function buildCommand(options) {
2202
2203
  }
2203
2204
  const rootOutputDir = join(process.cwd(), ".gkm");
2204
2205
  await mkdir(rootOutputDir, { recursive: true });
2206
+ let optionalVarSet;
2207
+ if (options.markOptional && config$1.envParser) try {
2208
+ const { _sniffEnvParser } = await import("./sniffer-Cpq_cbyz.mjs");
2209
+ const sniffed = await _sniffEnvParser(config$1.envParser, process.cwd(), process.cwd());
2210
+ if (sniffed.optionalEnvVars.length > 0) optionalVarSet = new Set(sniffed.optionalEnvVars);
2211
+ } catch {}
2205
2212
  let result = {};
2206
2213
  for (const provider of resolved.providers) {
2207
- const providerResult = await buildForProvider(provider, buildContext, rootOutputDir, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, allEndpoints, allFunctions, allCrons, allSubscribers, resolved.enableOpenApi, options.skipBundle ?? false, options.stage);
2214
+ const providerResult = await buildForProvider(provider, buildContext, rootOutputDir, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, allEndpoints, allFunctions, allCrons, allSubscribers, resolved.enableOpenApi, options.skipBundle ?? false, options.stage, optionalVarSet);
2208
2215
  if (providerResult.masterKey) result = providerResult;
2209
2216
  }
2217
+ await generateOpenApi(config$1, { bustCache: true });
2210
2218
  return result;
2211
2219
  }
2212
- async function buildForProvider(provider, context, rootOutputDir, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, endpoints, functions, crons, subscribers, enableOpenApi, skipBundle, stage) {
2220
+ async function buildForProvider(provider, context, rootOutputDir, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, endpoints, functions, crons, subscribers, enableOpenApi, skipBundle, stage, optionalVarSet) {
2213
2221
  const outputDir = join(process.cwd(), ".gkm", provider);
2214
2222
  await mkdir(outputDir, { recursive: true });
2215
2223
  logger$9.log(`\nGenerating handlers for provider: ${provider}`);
2216
- const [routes, functionInfos, cronInfos, subscriberInfos] = await Promise.all([
2224
+ const [rawRoutes, rawFunctions, rawCrons, rawSubscribers] = await Promise.all([
2217
2225
  endpointGenerator.build(context, endpoints, outputDir, {
2218
2226
  provider,
2219
2227
  enableOpenApi
@@ -2222,6 +2230,23 @@ async function buildForProvider(provider, context, rootOutputDir, endpointGenera
2222
2230
  cronGenerator.build(context, crons, outputDir, { provider }),
2223
2231
  subscriberGenerator.build(context, subscribers, outputDir, { provider })
2224
2232
  ]);
2233
+ const markEnv = optionalVarSet ? (vars) => vars?.map((v) => optionalVarSet.has(v) ? `${v}?` : v) : (vars) => vars;
2234
+ const routes = rawRoutes.map((r) => ({
2235
+ ...r,
2236
+ environment: markEnv(r.environment)
2237
+ }));
2238
+ const functionInfos = rawFunctions.map((f) => ({
2239
+ ...f,
2240
+ environment: markEnv(f.environment)
2241
+ }));
2242
+ const cronInfos = rawCrons.map((c) => ({
2243
+ ...c,
2244
+ environment: markEnv(c.environment)
2245
+ }));
2246
+ const subscriberInfos = rawSubscribers.map((s) => ({
2247
+ ...s,
2248
+ environment: markEnv(s.environment)
2249
+ }));
2225
2250
  logger$9.log(`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers for ${provider}`);
2226
2251
  const manifestRoutes = assembleManifestField(routes, endpoints);
2227
2252
  const manifestFunctions = assembleManifestField(functionInfos, functions);
@@ -2243,7 +2268,7 @@ async function buildForProvider(provider, context, rootOutputDir, endpointGenera
2243
2268
  let masterKey;
2244
2269
  if (context.production?.bundle && !skipBundle) {
2245
2270
  logger$9.log(`\n📦 Bundling production server...`);
2246
- const { bundleServer } = await import("./bundler-c6QvGUBM.mjs");
2271
+ const { bundleServer } = await import("./bundler-E5VcXsPH.mjs");
2247
2272
  const allConstructs = [
2248
2273
  ...endpoints.map((e) => e.construct),
2249
2274
  ...functions.map((f) => f.construct),
@@ -2341,6 +2366,7 @@ async function workspaceBuildCommand(workspace, options) {
2341
2366
  });
2342
2367
  }
2343
2368
  logger$9.log(`\n✅ Workspace build complete!`);
2369
+ await openapiCommand({ cwd: workspace.root });
2344
2370
  logger$9.log(`\n📋 Build Summary:`);
2345
2371
  for (const result of results) {
2346
2372
  const icon = result.type === "backend" ? "⚙️" : "🌐";
@@ -2569,11 +2595,11 @@ async function createDnsProvider(options) {
2569
2595
  if (isDnsProvider(config$1.provider)) return config$1.provider;
2570
2596
  const provider = config$1.provider;
2571
2597
  if (provider === "hostinger") {
2572
- const { HostingerProvider } = await import("./HostingerProvider-ANWchdiK.mjs");
2598
+ const { HostingerProvider } = await import("./HostingerProvider-YvCg3Mus.mjs");
2573
2599
  return new HostingerProvider();
2574
2600
  }
2575
2601
  if (provider === "route53") {
2576
- const { Route53Provider } = await import("./Route53Provider-QoPgcXxn.mjs");
2602
+ const { Route53Provider } = await import("./Route53Provider-CYlDOrYO.mjs");
2577
2603
  const route53Config = config$1;
2578
2604
  return new Route53Provider({
2579
2605
  region: route53Config.region,
@@ -3123,6 +3149,7 @@ services:
3123
3149
  restart: unless-stopped
3124
3150
  environment:
3125
3151
  MP_SMTP_AUTH: \${SMTP_USER:-${imageName}}:\${SMTP_PASS:-${imageName}}
3152
+ MP_SMTP_AUTH_ALLOW_INSECURE: true
3126
3153
  ports:
3127
3154
  - "\${MAILPIT_PORT:-8025}:8025" # Web UI / API
3128
3155
  - "\${SMTP_PORT:-1025}:1025" # SMTP
@@ -3287,6 +3314,7 @@ services:
3287
3314
  restart: unless-stopped
3288
3315
  environment:
3289
3316
  MP_SMTP_AUTH: \${SMTP_USER:-${workspace.name}}:\${SMTP_PASS:-${workspace.name}}
3317
+ MP_SMTP_AUTH_ALLOW_INSECURE: true
3290
3318
  ports:
3291
3319
  - "\${MAILPIT_PORT:-8025}:8025" # Web UI / API
3292
3320
  - "\${SMTP_PORT:-1025}:1025" # SMTP
@@ -5042,20 +5070,20 @@ function isStateProvider(value) {
5042
5070
  async function createStateProvider(options) {
5043
5071
  const { config: config$1, workspaceRoot, workspaceName } = options;
5044
5072
  if (!config$1) {
5045
- const { LocalStateProvider } = await import("./LocalStateProvider-Dp0KkRcw.mjs");
5073
+ const { LocalStateProvider } = await import("./LocalStateProvider-BciOhGR0.mjs");
5046
5074
  return new LocalStateProvider(workspaceRoot);
5047
5075
  }
5048
5076
  if (isStateProvider(config$1.provider)) return config$1.provider;
5049
5077
  const provider = config$1.provider;
5050
5078
  if (provider === "local") {
5051
- const { LocalStateProvider } = await import("./LocalStateProvider-Dp0KkRcw.mjs");
5079
+ const { LocalStateProvider } = await import("./LocalStateProvider-BciOhGR0.mjs");
5052
5080
  return new LocalStateProvider(workspaceRoot);
5053
5081
  }
5054
5082
  if (provider === "ssm") {
5055
5083
  if (!workspaceName) throw new Error("Workspace name is required for SSM state provider. Set \"name\" in gkm.config.ts.");
5056
- const { LocalStateProvider } = await import("./LocalStateProvider-Dp0KkRcw.mjs");
5057
- const { SSMStateProvider } = await import("./SSMStateProvider-CksOTB8M.mjs");
5058
- const { CachedStateProvider: CachedStateProvider$1 } = await import("./CachedStateProvider-CC0DyO09.mjs");
5084
+ const { LocalStateProvider } = await import("./LocalStateProvider-BciOhGR0.mjs");
5085
+ const { SSMStateProvider } = await import("./SSMStateProvider-DXT1dIdI.mjs");
5086
+ const { CachedStateProvider: CachedStateProvider$1 } = await import("./CachedStateProvider-C4QqvlPE.mjs");
5059
5087
  const ssmConfig = config$1;
5060
5088
  const local = new LocalStateProvider(workspaceRoot);
5061
5089
  const ssm = SSMStateProvider.create({
@@ -5165,326 +5193,6 @@ function generateSecretsReport(encryptedApps, sniffedApps) {
5165
5193
  };
5166
5194
  }
5167
5195
 
5168
- //#endregion
5169
- //#region src/deploy/sniffer.ts
5170
- const __filename = fileURLToPath(import.meta.url);
5171
- const __dirname = dirname(__filename);
5172
- /**
5173
- * Resolve the tsx package path from the CLI package's dependencies.
5174
- * This ensures tsx is available regardless of whether the target project has it installed.
5175
- */
5176
- function resolveTsxPath() {
5177
- const require$2 = createRequire(import.meta.url);
5178
- return require$2.resolve("tsx");
5179
- }
5180
- /**
5181
- * Resolve the path to a sniffer helper file.
5182
- * Handles both dev (.ts with tsx) and production (.mjs from dist).
5183
- *
5184
- * In production: sniffer.ts is bundled into dist/index.mjs, but sniffer helper
5185
- * files are output to dist/deploy/ as standalone modules for subprocess loading.
5186
- *
5187
- * In development: All files are in src/deploy/ and loaded via tsx.
5188
- */
5189
- function resolveSnifferFile(baseName) {
5190
- const deployMjsPath = resolve(__dirname, "deploy", `${baseName}.mjs`);
5191
- if (existsSync(deployMjsPath)) return deployMjsPath;
5192
- const mjsPath = resolve(__dirname, `${baseName}.mjs`);
5193
- if (existsSync(mjsPath)) return mjsPath;
5194
- const tsPath = resolve(__dirname, `${baseName}.ts`);
5195
- if (existsSync(tsPath)) return tsPath;
5196
- return tsPath;
5197
- }
5198
- /**
5199
- * Get required environment variables for an app.
5200
- *
5201
- * Detection strategy (in order):
5202
- * 1. Frontend apps: Returns empty (no server secrets)
5203
- * 2. Apps with `requiredEnv`: Uses explicit list from config
5204
- * 3. Entry apps: Imports entry file in subprocess to capture config.parse() calls
5205
- * 4. Route-based apps: Loads route files and calls getEnvironment() on each construct
5206
- * 5. Apps with `envParser` (no routes): Runs SnifferEnvironmentParser to detect usage
5207
- * 6. Apps with neither: Returns empty
5208
- *
5209
- * This function handles "fire and forget" async operations gracefully,
5210
- * capturing errors and unhandled rejections without failing the build.
5211
- *
5212
- * @param app - The normalized app configuration
5213
- * @param appName - The name of the app
5214
- * @param workspacePath - Absolute path to the workspace root
5215
- * @param options - Optional configuration for sniffing behavior
5216
- * @returns The sniffed environment with required variables
5217
- */
5218
- async function sniffAppEnvironment(app, appName, workspacePath, options = {}) {
5219
- const { logWarnings = true } = options;
5220
- if (app.type === "frontend") {
5221
- const depVars = (app.dependencies ?? []).map((dep) => `NEXT_PUBLIC_${dep.toUpperCase()}_URL`);
5222
- if (app.config) {
5223
- const sniffedVars = [];
5224
- const configPaths = [];
5225
- if (app.config.client) configPaths.push(app.config.client);
5226
- if (app.config.server) configPaths.push(app.config.server);
5227
- for (const configPath of configPaths) {
5228
- const result = await sniffEntryFile(configPath, app.path, workspacePath);
5229
- if (logWarnings && result.error) console.warn(`[sniffer] ${appName}: Config file "${configPath}" threw error during sniffing (env vars still captured): ${result.error.message}`);
5230
- sniffedVars.push(...result.envVars);
5231
- }
5232
- const allVars = [...new Set([...depVars, ...sniffedVars])];
5233
- return {
5234
- appName,
5235
- requiredEnvVars: allVars
5236
- };
5237
- }
5238
- return {
5239
- appName,
5240
- requiredEnvVars: depVars
5241
- };
5242
- }
5243
- if (app.entry) {
5244
- const result = await sniffEntryFile(app.entry, app.path, workspacePath);
5245
- if (logWarnings && result.error) console.warn(`[sniffer] ${appName}: Entry file threw error during sniffing (env vars still captured): ${result.error.message}`);
5246
- return {
5247
- appName,
5248
- requiredEnvVars: result.envVars
5249
- };
5250
- }
5251
- if (app.routes) {
5252
- const result = await sniffRouteFiles(normalizeRoutes(app.routes), app.path, workspacePath);
5253
- if (logWarnings && result.error) console.warn(`[sniffer] ${appName}: Route sniffing threw error (env vars still captured): ${result.error.message}`);
5254
- return {
5255
- appName,
5256
- requiredEnvVars: result.envVars
5257
- };
5258
- }
5259
- if (app.envParser) {
5260
- const result = await sniffEnvParser(app.envParser, app.path, workspacePath);
5261
- if (logWarnings) {
5262
- if (result.error) console.warn(`[sniffer] ${appName}: envParser threw error during sniffing (env vars still captured): ${result.error.message}`);
5263
- if (result.unhandledRejections.length > 0) console.warn(`[sniffer] ${appName}: Fire-and-forget rejections during sniffing (suppressed): ${result.unhandledRejections.map((e) => e.message).join(", ")}`);
5264
- }
5265
- return {
5266
- appName,
5267
- requiredEnvVars: result.envVars
5268
- };
5269
- }
5270
- return {
5271
- appName,
5272
- requiredEnvVars: []
5273
- };
5274
- }
5275
- /**
5276
- * Sniff an entry file by importing it in a subprocess.
5277
- *
5278
- * Entry apps call `config.parse()` at module load time. To capture which
5279
- * env vars are accessed, we:
5280
- * 1. Spawn a subprocess with a module loader hook
5281
- * 2. The loader intercepts `@geekmidas/envkit` and replaces EnvironmentParser
5282
- * with SnifferEnvironmentParser
5283
- * 3. Import the entry file (triggers config.parse())
5284
- * 4. Capture and return the accessed env var names
5285
- *
5286
- * This approach provides process isolation - each app is sniffed in its own
5287
- * subprocess, preventing module cache pollution.
5288
- *
5289
- * @param entryPath - Relative path to the entry file (e.g., './src/index.ts')
5290
- * @param appPath - The app's path relative to workspace (e.g., 'apps/auth')
5291
- * @param workspacePath - Absolute path to workspace root
5292
- * @returns EntrySniffResult with env vars and optional error
5293
- */
5294
- async function sniffEntryFile(entryPath, appPath, workspacePath) {
5295
- const fullEntryPath = resolve(workspacePath, appPath, entryPath);
5296
- const loaderPath = resolveSnifferFile("sniffer-loader");
5297
- const workerPath = resolveSnifferFile("sniffer-worker");
5298
- return new Promise((resolvePromise) => {
5299
- const child = spawn("node", [
5300
- "--import",
5301
- loaderPath,
5302
- workerPath,
5303
- fullEntryPath
5304
- ], {
5305
- cwd: resolve(workspacePath, appPath),
5306
- stdio: [
5307
- "ignore",
5308
- "pipe",
5309
- "pipe"
5310
- ],
5311
- env: {
5312
- ...process.env,
5313
- NODE_OPTIONS: "--import=tsx"
5314
- }
5315
- });
5316
- let stdout$1 = "";
5317
- let stderr = "";
5318
- child.stdout.on("data", (data) => {
5319
- stdout$1 += data.toString();
5320
- });
5321
- child.stderr.on("data", (data) => {
5322
- stderr += data.toString();
5323
- });
5324
- child.on("close", (code) => {
5325
- try {
5326
- const jsonMatch = stdout$1.match(/\{[^{}]*"envVars"[^{}]*\}[^{]*$/);
5327
- if (jsonMatch) {
5328
- const result = JSON.parse(jsonMatch[0]);
5329
- resolvePromise({
5330
- envVars: result.envVars || [],
5331
- error: result.error ? new Error(result.error) : void 0
5332
- });
5333
- return;
5334
- }
5335
- } catch {}
5336
- resolvePromise({
5337
- envVars: [],
5338
- error: new Error(`Failed to sniff entry file (exit code ${code}): ${stderr || stdout$1 || "No output"}`)
5339
- });
5340
- });
5341
- child.on("error", (err) => {
5342
- resolvePromise({
5343
- envVars: [],
5344
- error: err
5345
- });
5346
- });
5347
- });
5348
- }
5349
- /**
5350
- * Sniff route files by loading constructs and calling getEnvironment().
5351
- *
5352
- * Route-based apps have endpoints, functions, crons, and subscribers that
5353
- * use services. Each service's register() method accesses environment variables.
5354
- *
5355
- * This runs in a subprocess with tsx loader to properly handle TypeScript
5356
- * compilation and path alias resolution (e.g., `src/...` imports).
5357
- *
5358
- * @param routes - Glob pattern(s) for route files
5359
- * @param appPath - The app's path relative to workspace (e.g., 'apps/api')
5360
- * @param workspacePath - Absolute path to workspace root
5361
- * @returns EntrySniffResult with env vars and optional error
5362
- */
5363
- async function sniffRouteFiles(routes, appPath, workspacePath) {
5364
- const fullAppPath = resolve(workspacePath, appPath);
5365
- const workerPath = resolveSnifferFile("sniffer-routes-worker");
5366
- const tsxPath = resolveTsxPath();
5367
- const routesArray = Array.isArray(routes) ? routes : [routes];
5368
- const pattern = routesArray[0];
5369
- if (!pattern) return {
5370
- envVars: [],
5371
- error: new Error("No route patterns provided")
5372
- };
5373
- return new Promise((resolvePromise) => {
5374
- const child = spawn("node", [
5375
- "--import",
5376
- tsxPath,
5377
- workerPath,
5378
- fullAppPath,
5379
- pattern
5380
- ], {
5381
- cwd: fullAppPath,
5382
- stdio: [
5383
- "ignore",
5384
- "pipe",
5385
- "pipe"
5386
- ],
5387
- env: { ...process.env }
5388
- });
5389
- let stdout$1 = "";
5390
- let stderr = "";
5391
- child.stdout.on("data", (data) => {
5392
- stdout$1 += data.toString();
5393
- });
5394
- child.stderr.on("data", (data) => {
5395
- stderr += data.toString();
5396
- });
5397
- child.on("close", (code) => {
5398
- if (stderr) stderr.split("\n").filter((line) => line.trim()).forEach((line) => console.warn(line));
5399
- try {
5400
- const jsonMatch = stdout$1.match(/\{[^{}]*"envVars"[^{}]*\}[^{]*$/);
5401
- if (jsonMatch) {
5402
- const result = JSON.parse(jsonMatch[0]);
5403
- resolvePromise({
5404
- envVars: result.envVars || [],
5405
- error: result.error ? new Error(result.error) : void 0
5406
- });
5407
- return;
5408
- }
5409
- } catch {}
5410
- resolvePromise({
5411
- envVars: [],
5412
- error: new Error(`Failed to sniff route files (exit code ${code}): ${stderr || stdout$1 || "No output"}`)
5413
- });
5414
- });
5415
- child.on("error", (err) => {
5416
- resolvePromise({
5417
- envVars: [],
5418
- error: err
5419
- });
5420
- });
5421
- });
5422
- }
5423
- /**
5424
- * Run the SnifferEnvironmentParser on an envParser module to detect
5425
- * which environment variables it accesses.
5426
- *
5427
- * This function handles "fire and forget" async operations by using
5428
- * the shared sniffWithFireAndForget utility from @geekmidas/envkit.
5429
- *
5430
- * @param envParserPath - The envParser config (e.g., './src/config/env#envParser')
5431
- * @param appPath - The app's path relative to workspace
5432
- * @param workspacePath - Absolute path to workspace root
5433
- * @returns SniffResult with env vars and any errors encountered
5434
- */
5435
- async function sniffEnvParser(envParserPath, appPath, workspacePath) {
5436
- const [modulePath, exportName = "default"] = envParserPath.split("#");
5437
- if (!modulePath) return {
5438
- envVars: [],
5439
- unhandledRejections: []
5440
- };
5441
- const fullPath = resolve(workspacePath, appPath, modulePath);
5442
- let SnifferEnvironmentParser;
5443
- let sniffWithFireAndForget;
5444
- try {
5445
- const envkitModule = await import("@geekmidas/envkit/sniffer");
5446
- SnifferEnvironmentParser = envkitModule.SnifferEnvironmentParser;
5447
- sniffWithFireAndForget = envkitModule.sniffWithFireAndForget;
5448
- } catch (error) {
5449
- const message = error instanceof Error ? error.message : String(error);
5450
- console.warn(`[sniffer] Failed to import SnifferEnvironmentParser: ${message}`);
5451
- return {
5452
- envVars: [],
5453
- unhandledRejections: []
5454
- };
5455
- }
5456
- const sniffer = new SnifferEnvironmentParser();
5457
- return sniffWithFireAndForget(sniffer, async () => {
5458
- const moduleUrl = pathToFileURL(fullPath).href;
5459
- const module = await import(moduleUrl);
5460
- const envParser = module[exportName];
5461
- if (typeof envParser !== "function") {
5462
- console.warn(`[sniffer] Export "${exportName}" from "${modulePath}" is not a function`);
5463
- return;
5464
- }
5465
- const result = envParser(sniffer);
5466
- if (result && typeof result.parse === "function") try {
5467
- result.parse();
5468
- } catch {}
5469
- });
5470
- }
5471
- /**
5472
- * Sniff environment requirements for multiple apps.
5473
- *
5474
- * @param apps - Map of app name to app config
5475
- * @param workspacePath - Absolute path to workspace root
5476
- * @param options - Optional configuration for sniffing behavior
5477
- * @returns Map of app name to sniffed environment
5478
- */
5479
- async function sniffAllApps(apps, workspacePath, options = {}) {
5480
- const results = /* @__PURE__ */ new Map();
5481
- for (const [appName, app] of Object.entries(apps)) {
5482
- const sniffed = await sniffAppEnvironment(app, appName, workspacePath, options);
5483
- results.set(appName, sniffed);
5484
- }
5485
- return results;
5486
- }
5487
-
5488
5196
  //#endregion
5489
5197
  //#region src/deploy/index.ts
5490
5198
  const logger$3 = console;
@@ -6154,7 +5862,7 @@ async function workspaceDeployCommand(workspace, options) {
6154
5862
  }
6155
5863
  if (workspace.deploy?.backups && provisionedPostgres) {
6156
5864
  logger$3.log("\n💾 Provisioning backup destination...");
6157
- const { provisionBackupDestination } = await import("./backup-provisioner-BEXoHTuC.mjs");
5865
+ const { provisionBackupDestination } = await import("./backup-provisioner-CCUcj28C.mjs");
6158
5866
  const backupState = await provisionBackupDestination({
6159
5867
  api,
6160
5868
  projectId: project.projectId,
@@ -6806,7 +6514,7 @@ const GEEKMIDAS_VERSIONS = {
6806
6514
  "@geekmidas/cache": "~1.1.0",
6807
6515
  "@geekmidas/client": "~4.0.4",
6808
6516
  "@geekmidas/cloud": "~1.0.0",
6809
- "@geekmidas/constructs": "~3.0.6",
6517
+ "@geekmidas/constructs": "~3.0.7",
6810
6518
  "@geekmidas/db": "~1.0.1",
6811
6519
  "@geekmidas/emailkit": "~1.0.0",
6812
6520
  "@geekmidas/envkit": "~1.0.4",
@@ -8068,7 +7776,7 @@ export default defineWorkspace({
8068
7776
  schema: 'zod',
8069
7777
  },
8070
7778
  },`;
8071
- if (services.db || services.cache || services.mail) {
7779
+ if (services.db || services.cache || services.mail || services.storage || services.events) {
8072
7780
  config$1 += `
8073
7781
  services: {`;
8074
7782
  if (services.db) config$1 += `
@@ -8077,6 +7785,10 @@ export default defineWorkspace({
8077
7785
  cache: true,`;
8078
7786
  if (services.mail) config$1 += `
8079
7787
  mail: true,`;
7788
+ if (services.storage) config$1 += `
7789
+ storage: true,`;
7790
+ if (services.events) config$1 += `
7791
+ events: '${services.events}',`;
8080
7792
  config$1 += `
8081
7793
  },`;
8082
7794
  }
@@ -11306,7 +11018,7 @@ async function initCommand(projectName, options = {}) {
11306
11018
  "mail",
11307
11019
  "storage"
11308
11020
  ] : answers.services || [];
11309
- const eventsBackend = options.yes ? isFullstack ? "pgboss" : void 0 : answers.eventsBackend;
11021
+ const eventsBackend = options.yes ? "pgboss" : answers.eventsBackend;
11310
11022
  const services = {
11311
11023
  db: servicesArray.includes("db"),
11312
11024
  cache: servicesArray.includes("cache"),
@@ -12235,7 +11947,7 @@ program.command("setup").description("Setup development environment (secrets, Do
12235
11947
  process.exit(1);
12236
11948
  }
12237
11949
  });
12238
- program.command("build").description("Build handlers from endpoints, functions, and crons").option("--provider <provider>", "Target provider for generated handlers (aws, server)").option("--providers <providers>", "[DEPRECATED] Use --provider instead. Target providers for generated handlers (comma-separated)").option("--enable-openapi", "Enable OpenAPI documentation generation for server builds").option("--production", "Build for production (no dev tools, bundled output)").option("--skip-bundle", "Skip bundling step in production build").option("--stage <stage>", "Inject encrypted secrets for deployment stage").action(async (options) => {
11950
+ program.command("build").description("Build handlers from endpoints, functions, and crons").option("--provider <provider>", "Target provider for generated handlers (aws, server)").option("--providers <providers>", "[DEPRECATED] Use --provider instead. Target providers for generated handlers (comma-separated)").option("--enable-openapi", "Enable OpenAPI documentation generation for server builds").option("--production", "Build for production (no dev tools, bundled output)").option("--skip-bundle", "Skip bundling step in production build").option("--stage <stage>", "Inject encrypted secrets for deployment stage").option("--mark-optional", "Suffix optional env vars with ? in manifest envVars field (e.g. PORT?)").action(async (options) => {
12239
11951
  try {
12240
11952
  const globalOptions = program.opts();
12241
11953
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
@@ -12246,7 +11958,8 @@ program.command("build").description("Build handlers from endpoints, functions,
12246
11958
  enableOpenApi: options.enableOpenapi || false,
12247
11959
  production: options.production || false,
12248
11960
  skipBundle: options.skipBundle || false,
12249
- stage: options.stage
11961
+ stage: options.stage,
11962
+ markOptional: options.markOptional || false
12250
11963
  });
12251
11964
  } else if (options.providers) {
12252
11965
  const providerList = [...new Set(options.providers.split(",").map((p) => p.trim()))];
@@ -12255,13 +11968,15 @@ program.command("build").description("Build handlers from endpoints, functions,
12255
11968
  enableOpenApi: options.enableOpenapi || false,
12256
11969
  production: options.production || false,
12257
11970
  skipBundle: options.skipBundle || false,
12258
- stage: options.stage
11971
+ stage: options.stage,
11972
+ markOptional: options.markOptional || false
12259
11973
  });
12260
11974
  } else await buildCommand({
12261
11975
  enableOpenApi: options.enableOpenapi || false,
12262
11976
  production: options.production || false,
12263
11977
  skipBundle: options.skipBundle || false,
12264
- stage: options.stage
11978
+ stage: options.stage,
11979
+ markOptional: options.markOptional || false
12265
11980
  });
12266
11981
  } catch (error) {
12267
11982
  console.error(formatError(error));
@@ -12436,8 +12151,8 @@ program.command("secrets:push").description("Push secrets to remote provider (SS
12436
12151
  const globalOptions = program.opts();
12437
12152
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
12438
12153
  const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await import("./config.mjs");
12439
- const { pushSecrets: pushSecrets$1 } = await import("./sync-COnAugP-.mjs");
12440
- const { reconcileMissingSecrets } = await import("./reconcile-DAAKa0YR.mjs");
12154
+ const { pushSecrets: pushSecrets$1 } = await import("./sync-fzT5WX_y.mjs");
12155
+ const { reconcileMissingSecrets } = await import("./reconcile-D423q2QW.mjs");
12441
12156
  const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1 } = await import("./storage-Cs4WBsc4.mjs");
12442
12157
  const { workspace } = await loadWorkspaceConfig$1();
12443
12158
  const secrets = await readStageSecrets$1(options.stage, workspace.root);
@@ -12461,9 +12176,9 @@ program.command("secrets:pull").description("Pull secrets from remote provider (
12461
12176
  const globalOptions = program.opts();
12462
12177
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
12463
12178
  const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await import("./config.mjs");
12464
- const { pullSecrets: pullSecrets$1 } = await import("./sync-COnAugP-.mjs");
12179
+ const { pullSecrets: pullSecrets$1 } = await import("./sync-fzT5WX_y.mjs");
12465
12180
  const { writeStageSecrets: writeStageSecrets$1 } = await import("./storage-Cs4WBsc4.mjs");
12466
- const { reconcileMissingSecrets } = await import("./reconcile-DAAKa0YR.mjs");
12181
+ const { reconcileMissingSecrets } = await import("./reconcile-D423q2QW.mjs");
12467
12182
  const { workspace } = await loadWorkspaceConfig$1();
12468
12183
  let secrets = await pullSecrets$1(options.stage, workspace);
12469
12184
  if (!secrets) {
@@ -12488,7 +12203,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
12488
12203
  const globalOptions = program.opts();
12489
12204
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
12490
12205
  const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await import("./config.mjs");
12491
- const { reconcileMissingSecrets } = await import("./reconcile-DAAKa0YR.mjs");
12206
+ const { reconcileMissingSecrets } = await import("./reconcile-D423q2QW.mjs");
12492
12207
  const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1 } = await import("./storage-Cs4WBsc4.mjs");
12493
12208
  const { workspace } = await loadWorkspaceConfig$1();
12494
12209
  const secrets = await readStageSecrets$1(options.stage, workspace.root);