@geekmidas/cli 10.0.0-alpha.44 → 10.0.0-alpha.46

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 (80) hide show
  1. package/README.md +144 -183
  2. package/dist/{OpenApiTsGenerator-B4Kj_qNU.cjs → OpenApiTsGenerator-BN0PIZxd.cjs} +17 -71
  3. package/dist/OpenApiTsGenerator-BN0PIZxd.cjs.map +1 -0
  4. package/dist/{OpenApiTsGenerator-CEh3EKN3.mjs → OpenApiTsGenerator-BzIGy8KE.mjs} +17 -71
  5. package/dist/OpenApiTsGenerator-BzIGy8KE.mjs.map +1 -0
  6. package/dist/{config-CJ-PAb7M.cjs → config-CsYSyUya.cjs} +3 -3
  7. package/dist/{config-CJ-PAb7M.cjs.map → config-CsYSyUya.cjs.map} +1 -1
  8. package/dist/{config-5watB1D0.mjs → config-D8J5rrTb.mjs} +3 -3
  9. package/dist/{config-5watB1D0.mjs.map → config-D8J5rrTb.mjs.map} +1 -1
  10. package/dist/config.cjs +2 -2
  11. package/dist/config.d.cts +2 -2
  12. package/dist/config.d.mts +2 -2
  13. package/dist/config.mjs +2 -2
  14. package/dist/{discover-BLhf7V_J.mjs → discover-Cf2jAcgF.mjs} +4 -56
  15. package/dist/discover-Cf2jAcgF.mjs.map +1 -0
  16. package/dist/{discover-B0f_kuNN.cjs → discover-DXNviAh-.cjs} +3 -79
  17. package/dist/discover-DXNviAh-.cjs.map +1 -0
  18. package/dist/{emit-Bzq7JsMP.mjs → emit-C1e8qD08.mjs} +12 -43
  19. package/dist/emit-C1e8qD08.mjs.map +1 -0
  20. package/dist/{emit-BdoPFjZf.cjs → emit-Dmc1nvdS.cjs} +11 -54
  21. package/dist/emit-Dmc1nvdS.cjs.map +1 -0
  22. package/dist/{github-D5MthUlR.mjs → github-BfpadQWQ.mjs} +3 -3
  23. package/dist/{github-D5MthUlR.mjs.map → github-BfpadQWQ.mjs.map} +1 -1
  24. package/dist/{github-BAr8WGkR.cjs → github-BrI1tv6u.cjs} +3 -3
  25. package/dist/{github-BAr8WGkR.cjs.map → github-BrI1tv6u.cjs.map} +1 -1
  26. package/dist/{index-B3PeGOQp.d.cts → index-BQhJXpaQ.d.mts} +2 -2
  27. package/dist/{index-B3PeGOQp.d.cts.map → index-BQhJXpaQ.d.mts.map} +1 -1
  28. package/dist/{index-BOyaGcCm.d.mts → index-DHJePE0y.d.cts} +2 -2
  29. package/dist/{index-BOyaGcCm.d.mts.map → index-DHJePE0y.d.cts.map} +1 -1
  30. package/dist/index.cjs +395 -660
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.mjs +397 -662
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/{migrate-BRklCm7b.mjs → migrate-B3opyC3o.mjs} +5 -5
  35. package/dist/{migrate-BRklCm7b.mjs.map → migrate-B3opyC3o.mjs.map} +1 -1
  36. package/dist/{migrate-PJi4b1ga.cjs → migrate-Dp5HFzuQ.cjs} +5 -5
  37. package/dist/{migrate-PJi4b1ga.cjs.map → migrate-Dp5HFzuQ.cjs.map} +1 -1
  38. package/dist/openapi.cjs +2 -2
  39. package/dist/openapi.d.cts +1 -1
  40. package/dist/openapi.d.mts +1 -1
  41. package/dist/openapi.mjs +2 -2
  42. package/dist/{ready-3RfHxdA0.cjs → ready-L7I68yXf.cjs} +67 -8
  43. package/dist/ready-L7I68yXf.cjs.map +1 -0
  44. package/dist/{ready-ZqOuNvKD.mjs → ready-V6Ou6-B6.mjs} +49 -8
  45. package/dist/ready-V6Ou6-B6.mjs.map +1 -0
  46. package/dist/reconcile/public.cjs +2 -4
  47. package/dist/reconcile/public.d.cts +6 -10
  48. package/dist/reconcile/public.d.cts.map +1 -1
  49. package/dist/reconcile/public.d.mts +6 -10
  50. package/dist/reconcile/public.d.mts.map +1 -1
  51. package/dist/reconcile/public.mjs +3 -3
  52. package/dist/{types-0R124hrY.d.mts → types-BbrNu83u.d.mts} +14 -109
  53. package/dist/{types-0R124hrY.d.mts.map → types-BbrNu83u.d.mts.map} +1 -1
  54. package/dist/{types-DfdYe31u.d.cts → types-DNqEsctD.d.cts} +14 -109
  55. package/dist/{types-DfdYe31u.d.cts.map → types-DNqEsctD.d.cts.map} +1 -1
  56. package/dist/vitest.cjs +1 -1
  57. package/dist/vitest.mjs +1 -1
  58. package/dist/workspace/index.cjs +1 -1
  59. package/dist/workspace/index.d.cts +2 -2
  60. package/dist/workspace/index.d.mts +2 -2
  61. package/dist/workspace/index.mjs +1 -1
  62. package/dist/{workspace-BKytVCzb.mjs → workspace-CHEC80sp.mjs} +6 -7
  63. package/dist/workspace-CHEC80sp.mjs.map +1 -0
  64. package/dist/{workspace-dV6f-3vv.cjs → workspace-D9z2ymBW.cjs} +11 -12
  65. package/dist/workspace-D9z2ymBW.cjs.map +1 -0
  66. package/dist/{workspace-RYSYtHP7.cjs → workspace-DEibcoBe.cjs} +11 -25
  67. package/dist/{workspace-RYSYtHP7.cjs.map → workspace-DEibcoBe.cjs.map} +1 -1
  68. package/dist/{workspace-DOmIhiau.mjs → workspace-DNzWgM1J.mjs} +11 -25
  69. package/dist/{workspace-DOmIhiau.mjs.map → workspace-DNzWgM1J.mjs.map} +1 -1
  70. package/package.json +14 -14
  71. package/dist/OpenApiTsGenerator-B4Kj_qNU.cjs.map +0 -1
  72. package/dist/OpenApiTsGenerator-CEh3EKN3.mjs.map +0 -1
  73. package/dist/discover-B0f_kuNN.cjs.map +0 -1
  74. package/dist/discover-BLhf7V_J.mjs.map +0 -1
  75. package/dist/emit-BdoPFjZf.cjs.map +0 -1
  76. package/dist/emit-Bzq7JsMP.mjs.map +0 -1
  77. package/dist/ready-3RfHxdA0.cjs.map +0 -1
  78. package/dist/ready-ZqOuNvKD.mjs.map +0 -1
  79. package/dist/workspace-BKytVCzb.mjs.map +0 -1
  80. package/dist/workspace-dV6f-3vv.cjs.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env -S npx tsx
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
4
- const require_discover = require("./discover-B0f_kuNN.cjs");
5
- const require_config = require("./config-CJ-PAb7M.cjs");
6
- const require_workspace = require("./workspace-RYSYtHP7.cjs");
4
+ const require_discover = require("./discover-DXNviAh-.cjs");
5
+ const require_config = require("./config-CsYSyUya.cjs");
6
+ const require_workspace = require("./workspace-DEibcoBe.cjs");
7
7
  const require_storage = require("./storage-CSGoC3bK.cjs");
8
8
  const require_store = require("./store-DQgxT_WR.cjs");
9
- const require_workspace$1 = require("./workspace-dV6f-3vv.cjs");
10
- const require_OpenApiTsGenerator = require("./OpenApiTsGenerator-B4Kj_qNU.cjs");
9
+ const require_workspace$1 = require("./workspace-D9z2ymBW.cjs");
10
+ const require_OpenApiTsGenerator = require("./OpenApiTsGenerator-BN0PIZxd.cjs");
11
11
  const require_openapi = require("./openapi.cjs");
12
- const require_ready = require("./ready-3RfHxdA0.cjs");
13
- const require_emit = require("./emit-BdoPFjZf.cjs");
12
+ const require_ready = require("./ready-L7I68yXf.cjs");
13
+ const require_emit = require("./emit-Dmc1nvdS.cjs");
14
14
  let commander = require("commander");
15
15
  let node_process = require("node:process");
16
16
  let node_readline_promises = require("node:readline/promises");
@@ -46,7 +46,7 @@ let _geekmidas_constructs_queue = require("@geekmidas/constructs/queue");
46
46
  let _geekmidas_constructs_topic = require("@geekmidas/constructs/topic");
47
47
  let node_dns_promises = require("node:dns/promises");
48
48
  //#region package.json
49
- var version = "10.0.0-alpha.44";
49
+ var version = "10.0.0-alpha.46";
50
50
  //#endregion
51
51
  //#region src/auth/credentials.ts
52
52
  /**
@@ -180,7 +180,7 @@ async function getHostingerToken(options) {
180
180
  }
181
181
  //#endregion
182
182
  //#region src/auth/index.ts
183
- const logger$13 = console;
183
+ const logger$12 = console;
184
184
  /**
185
185
  * Validate Dokploy token by making a test API call
186
186
  */
@@ -247,52 +247,52 @@ async function prompt$1(message, hidden = false) {
247
247
  async function loginCommand(options) {
248
248
  const { provider, token: providedToken, endpoint: providedEndpoint } = options;
249
249
  if (provider === "dokploy") {
250
- logger$13.log("\n🔐 Logging in to Dokploy...\n");
250
+ logger$12.log("\n🔐 Logging in to Dokploy...\n");
251
251
  let endpoint = providedEndpoint;
252
252
  if (!endpoint) endpoint = await prompt$1("Dokploy URL (e.g., https://dokploy.example.com): ");
253
253
  endpoint = endpoint.replace(/\/$/, "");
254
254
  try {
255
255
  new URL(endpoint);
256
256
  } catch {
257
- logger$13.error("Invalid URL format");
257
+ logger$12.error("Invalid URL format");
258
258
  process.exit(1);
259
259
  }
260
260
  let token = providedToken;
261
261
  if (!token) {
262
- logger$13.log(`\nGenerate a token at: ${endpoint}/settings/profile\n`);
262
+ logger$12.log(`\nGenerate a token at: ${endpoint}/settings/profile\n`);
263
263
  token = await prompt$1("API Token: ", true);
264
264
  }
265
265
  if (!token) {
266
- logger$13.error("Token is required");
266
+ logger$12.error("Token is required");
267
267
  process.exit(1);
268
268
  }
269
- logger$13.log("\nValidating credentials...");
269
+ logger$12.log("\nValidating credentials...");
270
270
  if (!await validateDokployToken(endpoint, token)) {
271
- logger$13.error("\n✗ Invalid credentials. Please check your token and try again.");
271
+ logger$12.error("\n✗ Invalid credentials. Please check your token and try again.");
272
272
  process.exit(1);
273
273
  }
274
274
  await storeDokployCredentials(token, endpoint);
275
- logger$13.log("\n✓ Successfully logged in to Dokploy!");
276
- logger$13.log(` Endpoint: ${endpoint}`);
277
- logger$13.log(` Credentials stored in: ${getCredentialsPath()}`);
278
- logger$13.log("\nYou can now use deploy commands without setting DOKPLOY_API_TOKEN.");
275
+ logger$12.log("\n✓ Successfully logged in to Dokploy!");
276
+ logger$12.log(` Endpoint: ${endpoint}`);
277
+ logger$12.log(` Credentials stored in: ${getCredentialsPath()}`);
278
+ logger$12.log("\nYou can now use deploy commands without setting DOKPLOY_API_TOKEN.");
279
279
  }
280
280
  if (provider === "hostinger") {
281
- logger$13.log("\n🔐 Logging in to Hostinger...\n");
281
+ logger$12.log("\n🔐 Logging in to Hostinger...\n");
282
282
  let token = providedToken;
283
283
  if (!token) {
284
- logger$13.log("\nGenerate a token at: https://hpanel.hostinger.com/profile/api\n");
284
+ logger$12.log("\nGenerate a token at: https://hpanel.hostinger.com/profile/api\n");
285
285
  token = await prompt$1("API Token: ", true);
286
286
  }
287
287
  if (!token) {
288
- logger$13.error("Token is required");
288
+ logger$12.error("Token is required");
289
289
  process.exit(1);
290
290
  }
291
291
  await storeHostingerToken(token);
292
- logger$13.log("\n✓ Hostinger token stored.");
293
- logger$13.log(` Credentials stored in: ${getCredentialsPath()}`);
294
- logger$13.log(" Not validated here: every DNS endpoint is scoped to a domain, so the\n first deploy that touches DNS is where a bad token reports itself.");
295
- logger$13.log("\nYou can now use it as a DNS provider without setting HOSTINGER_API_TOKEN.");
292
+ logger$12.log("\n✓ Hostinger token stored.");
293
+ logger$12.log(` Credentials stored in: ${getCredentialsPath()}`);
294
+ logger$12.log(" Not validated here: every DNS endpoint is scoped to a domain, so the\n first deploy that touches DNS is where a bad token reports itself.");
295
+ logger$12.log("\nYou can now use it as a DNS provider without setting HOSTINGER_API_TOKEN.");
296
296
  }
297
297
  }
298
298
  /**
@@ -301,27 +301,27 @@ async function loginCommand(options) {
301
301
  async function logoutCommand(options) {
302
302
  const { provider = "dokploy" } = options;
303
303
  if (provider === "all") {
304
- if (await removeDokployCredentials()) logger$13.log("\n✓ Logged out from all services");
305
- else logger$13.log("\nNo stored credentials found");
304
+ if (await removeDokployCredentials()) logger$12.log("\n✓ Logged out from all services");
305
+ else logger$12.log("\nNo stored credentials found");
306
306
  return;
307
307
  }
308
308
  if (provider === "dokploy") {
309
- if (await removeDokployCredentials()) logger$13.log("\n✓ Logged out from Dokploy");
310
- else logger$13.log("\nNo Dokploy credentials found");
309
+ if (await removeDokployCredentials()) logger$12.log("\n✓ Logged out from Dokploy");
310
+ else logger$12.log("\nNo Dokploy credentials found");
311
311
  }
312
312
  }
313
313
  /**
314
314
  * Show current login status
315
315
  */
316
316
  async function whoamiCommand() {
317
- logger$13.log("\n📋 Current credentials:\n");
317
+ logger$12.log("\n📋 Current credentials:\n");
318
318
  const dokploy = await getDokployCredentials();
319
319
  if (dokploy) {
320
- logger$13.log(" Dokploy:");
321
- logger$13.log(` Endpoint: ${dokploy.endpoint}`);
322
- logger$13.log(` Token: ${maskToken(dokploy.token)}`);
323
- } else logger$13.log(" Dokploy: Not logged in");
324
- logger$13.log(`\n Credentials file: ${getCredentialsPath()}`);
320
+ logger$12.log(" Dokploy:");
321
+ logger$12.log(` Endpoint: ${dokploy.endpoint}`);
322
+ logger$12.log(` Token: ${maskToken(dokploy.token)}`);
323
+ } else logger$12.log(" Dokploy: Not logged in");
324
+ logger$12.log(`\n Credentials file: ${getCredentialsPath()}`);
325
325
  }
326
326
  /**
327
327
  * Mask a token for display
@@ -331,85 +331,14 @@ function maskToken(token) {
331
331
  return `${token.slice(0, 4)}...${token.slice(-4)}`;
332
332
  }
333
333
  //#endregion
334
- //#region src/build/providerResolver.ts
335
- /**
336
- * Resolves provider configuration from the new simplified system
337
- * to the internal legacy format for backward compatibility
338
- */
339
- function resolveProviders(config, options) {
340
- const providers = [];
341
- let enableOpenApi = options.enableOpenApi || false;
342
- if (options.providers) return {
343
- providers: options.providers,
344
- enableOpenApi
345
- };
346
- if (options.provider) {
347
- const resolvedProviders = resolveMainProvider(options.provider, config.providers);
348
- providers.push(...resolvedProviders.providers);
349
- enableOpenApi = resolvedProviders.enableOpenApi || enableOpenApi;
350
- } else if (config.providers) {
351
- const resolvedProviders = resolveAllConfiguredProviders(config.providers);
352
- providers.push(...resolvedProviders.providers);
353
- enableOpenApi = resolvedProviders.enableOpenApi || enableOpenApi;
354
- } else providers.push("aws-apigatewayv2", "aws-lambda");
355
- return {
356
- providers: [...new Set(providers)],
357
- enableOpenApi
358
- };
359
- }
360
- function resolveMainProvider(mainProvider, providersConfig) {
361
- const providers = [];
362
- let enableOpenApi = false;
363
- if (mainProvider === "aws") {
364
- const awsConfig = providersConfig?.aws;
365
- if (awsConfig?.apiGateway) {
366
- if (isEnabled(awsConfig.apiGateway.v1)) providers.push("aws-apigatewayv1");
367
- if (isEnabled(awsConfig.apiGateway.v2)) providers.push("aws-apigatewayv2");
368
- } else providers.push("aws-apigatewayv2");
369
- if (awsConfig?.lambda) {
370
- if (isEnabled(awsConfig.lambda.functions) || isEnabled(awsConfig.lambda.crons)) providers.push("aws-lambda");
371
- } else providers.push("aws-lambda");
372
- } else if (mainProvider === "server") {
373
- providers.push("server");
374
- const serverConfig = providersConfig?.server;
375
- if (typeof serverConfig === "object" && serverConfig?.enableOpenApi) enableOpenApi = true;
376
- }
377
- return {
378
- providers,
379
- enableOpenApi
380
- };
381
- }
382
- function resolveAllConfiguredProviders(providersConfig) {
383
- const providers = [];
384
- let enableOpenApi = false;
385
- if (providersConfig.aws) {
386
- const awsProviders = resolveMainProvider("aws", providersConfig);
387
- providers.push(...awsProviders.providers);
388
- }
389
- if (providersConfig.server && isEnabled(providersConfig.server)) {
390
- providers.push("server");
391
- if (typeof providersConfig.server === "object" && providersConfig.server.enableOpenApi) enableOpenApi = true;
392
- }
393
- return {
394
- providers,
395
- enableOpenApi
396
- };
397
- }
398
- function isEnabled(config) {
399
- if (config === void 0) return false;
400
- if (typeof config === "boolean") return config;
401
- return config.enabled !== false;
402
- }
403
- //#endregion
404
334
  //#region src/workspace/client-generator.ts
405
335
  /**
406
336
  * Normalize routes to an array of patterns.
407
- * Handles string, string[], and PartitionedRoutes (extracts paths).
337
+ * Handles a glob or a list of them.
408
338
  * @internal Exported for use in dev command
409
339
  */
410
340
  function normalizeRoutes(routes) {
411
341
  if (!routes) return [];
412
- if (require_discover.isPartitionedRoutes(routes)) return Array.isArray(routes.paths) ? routes.paths : [routes.paths];
413
342
  return Array.isArray(routes) ? routes : [routes];
414
343
  }
415
344
  //#endregion
@@ -428,7 +357,7 @@ function normalizeRoutes(routes) {
428
357
  * trade than one that tells you what to type. Caddy's own `caddy trust` draws
429
358
  * the line in the same place.
430
359
  */
431
- const logger$12 = console;
360
+ const logger$11 = console;
432
361
  const run = (0, node_util.promisify)(node_child_process.execFile);
433
362
  /**
434
363
  * How each platform is told about a new authority.
@@ -480,15 +409,15 @@ async function trustCommand(options = {}) {
480
409
  const certificate = (0, node_path.join)(workspace.root, require_workspace$1.LOCAL_CA_PATH);
481
410
  if (!(0, node_fs.existsSync)(certificate)) throw new NoLocalAuthority(certificate);
482
411
  const { describe, steps } = installation(process.platform, certificate);
483
- logger$12.log(`\n🔐 Trusting the local authority in ${describe}`);
484
- logger$12.log(` ${certificate}\n`);
412
+ logger$11.log(`\n🔐 Trusting the local authority in ${describe}`);
413
+ logger$11.log(` ${certificate}\n`);
485
414
  if (options.dryRun) {
486
- for (const [command, args] of steps) logger$12.log(` ${command} ${args.join(" ")}`);
415
+ for (const [command, args] of steps) logger$11.log(` ${command} ${args.join(" ")}`);
487
416
  return;
488
417
  }
489
- logger$12.log(" This needs an admin password.\n");
418
+ logger$11.log(" This needs an admin password.\n");
490
419
  for (const [command, args] of steps) await run(command, args, { stdio: "inherit" });
491
- logger$12.log("\n✅ Local https addresses are trusted. Restart your browser.\n");
420
+ logger$11.log("\n✅ Local https addresses are trusted. Restart your browser.\n");
492
421
  }
493
422
  /**
494
423
  * Trust the authority if this machine lacks it and its owner agrees.
@@ -505,7 +434,7 @@ async function ensureTrusted(root, url, options = {}) {
505
434
  if (await isTrusted(url)) return;
506
435
  if (!options.assumeYes) {
507
436
  if (!process.stdin.isTTY) {
508
- logger$12.log(" Local https addresses are not trusted here. Run \"gkm trust\", or \"gkm setup --yes\".");
437
+ logger$11.log(" Local https addresses are not trusted here. Run \"gkm trust\", or \"gkm setup --yes\".");
509
438
  return;
510
439
  }
511
440
  if (await declined(root)) return;
@@ -517,7 +446,7 @@ async function ensureTrusted(root, url, options = {}) {
517
446
  });
518
447
  if (!install) {
519
448
  await recordDeclined(root);
520
- logger$12.log(" Skipped. Run \"gkm trust\" later.");
449
+ logger$11.log(" Skipped. Run \"gkm trust\" later.");
521
450
  return;
522
451
  }
523
452
  }
@@ -1067,7 +996,7 @@ function closeFakes(served) {
1067
996
  }
1068
997
  //#endregion
1069
998
  //#region src/exec/index.ts
1070
- const logger$11 = console;
999
+ const logger$10 = console;
1071
1000
  /** `gkm exec` was given nothing to run. */
1072
1001
  var NoCommandSpecified = class extends Error {
1073
1002
  constructor() {
@@ -1090,17 +1019,17 @@ async function execCommand(commandArgs, options = {}) {
1090
1019
  const cwd = options.cwd ?? process.cwd();
1091
1020
  if (!commandArgs[0]) throw new NoCommandSpecified();
1092
1021
  const defaultEnv = require_workspace$1.loadEnvFiles(".env");
1093
- if (defaultEnv.loaded.length > 0) logger$11.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1022
+ if (defaultEnv.loaded.length > 0) logger$10.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1094
1023
  const { credentials, secretsJsonPath, appName } = await require_workspace$1.prepareEntryCredentials({ cwd });
1095
- if (appName) logger$11.log(`📦 App: ${appName}`);
1024
+ if (appName) logger$10.log(`📦 App: ${appName}`);
1096
1025
  const secretCount = Object.keys(credentials).filter((k) => k !== "PORT").length;
1097
- if (secretCount > 0) logger$11.log(`🔐 Loaded ${secretCount} secret(s)`);
1026
+ if (secretCount > 0) logger$10.log(`🔐 Loaded ${secretCount} secret(s)`);
1098
1027
  const preloadDir = (0, node_path.join)(cwd, ".gkm");
1099
1028
  await (0, node_fs_promises.mkdir)(preloadDir, { recursive: true });
1100
1029
  const preloadPath = (0, node_path.join)(preloadDir, "credentials-preload.mjs");
1101
1030
  await require_workspace$1.createCredentialsPreload(preloadPath, secretsJsonPath);
1102
1031
  const [cmd, ...args] = commandArgs;
1103
- logger$11.log(`🚀 Running: ${[cmd, ...args].join(" ")}`);
1032
+ logger$10.log(`🚀 Running: ${[cmd, ...args].join(" ")}`);
1104
1033
  const nodeOptions = [(process.env.NODE_OPTIONS ?? "").replace(/--import[= ]\S+/g, "").trim(), `--import=${preloadPath}`].filter(Boolean).join(" ");
1105
1034
  const child = (0, node_child_process.spawn)(cmd, args, {
1106
1035
  cwd,
@@ -1114,7 +1043,7 @@ async function execCommand(commandArgs, options = {}) {
1114
1043
  const exitCode = await new Promise((resolve) => {
1115
1044
  child.on("close", (code) => resolve(code ?? 0));
1116
1045
  child.on("error", (error) => {
1117
- logger$11.error(`Failed to run command: ${error.message}`);
1046
+ logger$10.error(`Failed to run command: ${error.message}`);
1118
1047
  resolve(1);
1119
1048
  });
1120
1049
  });
@@ -1122,7 +1051,7 @@ async function execCommand(commandArgs, options = {}) {
1122
1051
  }
1123
1052
  //#endregion
1124
1053
  //#region src/dev/index.ts
1125
- const logger$10 = console;
1054
+ const logger$9 = console;
1126
1055
  /**
1127
1056
  * Normalize telescope configuration
1128
1057
  * @internal Exported for testing
@@ -1187,39 +1116,36 @@ function normalizeHooksConfig(config, cwd = process.cwd()) {
1187
1116
  return { serverHooksPath: (0, node_path.resolve)(cwd, serverPath) };
1188
1117
  }
1189
1118
  /**
1190
- * Normalize production configuration
1119
+ * What a `--production` build is.
1120
+ *
1121
+ * A server runs its worker's background work itself — queues polled, crons
1122
+ * scheduled, subscribers drained — so the production entry wires all three.
1123
+ * The build writes their files on every server build, empty when there is
1124
+ * nothing, so including them costs an app without any nothing.
1125
+ *
1191
1126
  * @internal Exported for testing
1192
1127
  */
1193
- function normalizeProductionConfig(cliProduction, configProduction) {
1128
+ function normalizeProductionConfig(cliProduction) {
1194
1129
  if (!cliProduction) return;
1195
- const config = configProduction ?? {};
1196
1130
  return {
1197
1131
  enabled: true,
1198
- bundle: config.bundle ?? true,
1199
- minify: config.minify ?? true,
1200
- healthCheck: config.healthCheck ?? "/health",
1201
- gracefulShutdown: config.gracefulShutdown ?? true,
1202
- external: config.external ?? [],
1203
- subscribers: config.subscribers ?? "exclude",
1204
- openapi: config.openapi ?? false,
1205
- optimizedHandlers: config.optimizedHandlers ?? true
1132
+ bundle: true,
1133
+ minify: true,
1134
+ healthCheck: "/health",
1135
+ gracefulShutdown: true,
1136
+ external: [],
1137
+ subscribers: "include",
1138
+ openapi: false,
1139
+ optimizedHandlers: true
1206
1140
  };
1207
1141
  }
1208
- /**
1209
- * Get production config from GkmConfig
1210
- * @internal
1211
- */
1212
- function getProductionConfigFromGkm(config) {
1213
- const serverConfig = config.providers?.server;
1214
- if (typeof serverConfig === "object") return serverConfig.production;
1215
- }
1216
1142
  /** Read by the generated server: no subscriber is subscribed or polled. */
1217
1143
  const SUBSCRIBERS_ENV = "GKM_SUBSCRIBERS";
1218
1144
  async function devCommand(options) {
1219
1145
  if (options.subscribers === false) process.env[SUBSCRIBERS_ENV] = "off";
1220
1146
  if (options.entry) return entryDevCommand(options);
1221
1147
  const defaultEnv = require_workspace$1.loadEnvFiles(".env");
1222
- if (defaultEnv.loaded.length > 0) logger$10.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1148
+ if (defaultEnv.loaded.length > 0) logger$9.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1223
1149
  const appConfig = await require_config.loadAppConfig().catch((error) => {
1224
1150
  if (error instanceof require_config.NotInAnApp || error instanceof require_config.NotABackendApp) return;
1225
1151
  throw error;
@@ -1235,7 +1161,7 @@ async function devCommand(options) {
1235
1161
  const workspaceAppPort = appConfig.app.port;
1236
1162
  const workspace = appConfig.workspace;
1237
1163
  if (appConfig.app.entry) {
1238
- logger$10.log(`📄 Using entry point: ${appConfig.app.entry}`);
1164
+ logger$9.log(`📄 Using entry point: ${appConfig.app.entry}`);
1239
1165
  return entryDevCommand({
1240
1166
  ...options,
1241
1167
  entry: appConfig.app.entry,
@@ -1245,19 +1171,18 @@ async function devCommand(options) {
1245
1171
  }
1246
1172
  if (config.env) {
1247
1173
  const { loaded, missing } = require_workspace$1.loadEnvFiles(config.env, appRoot);
1248
- if (loaded.length > 0) logger$10.log(`📦 Loaded env: ${loaded.join(", ")}`);
1249
- if (missing.length > 0) logger$10.warn(`⚠️ Missing env files: ${missing.join(", ")}`);
1174
+ if (loaded.length > 0) logger$9.log(`📦 Loaded env: ${loaded.join(", ")}`);
1175
+ if (missing.length > 0) logger$9.warn(`⚠️ Missing env files: ${missing.join(", ")}`);
1250
1176
  }
1251
- const resolved = resolveProviders(config, { provider: "server" });
1252
1177
  const telescope = normalizeTelescopeConfig(config.telescope);
1253
1178
  const studio = normalizeStudioConfig(config.studio);
1254
1179
  const hooks = normalizeHooksConfig(config.hooks, appRoot);
1255
- const enableOpenApi = require_openapi.resolveOpenApiConfig(config).enabled || resolved.enableOpenApi;
1180
+ const enableOpenApi = require_openapi.resolveOpenApiConfig(config).enabled;
1256
1181
  const build = (bustCache = false) => quietly(() => buildApp({
1257
1182
  config,
1258
1183
  workspaceRoot: workspace?.root ?? secretsRoot,
1259
1184
  appRoot,
1260
- providers: ["server"],
1185
+ target: "server",
1261
1186
  enableOpenApi,
1262
1187
  cacheBackend: require_workspace$1.cacheBackendFor(require_workspace$1.providerOf(workspace ?? config)),
1263
1188
  telescope,
@@ -1278,8 +1203,8 @@ async function devCommand(options) {
1278
1203
  ...options.fake ? { fake: true } : {}
1279
1204
  });
1280
1205
  if (reconciled.changed && reconciled.plan.containers.length > 0) {
1281
- logger$10.log(`🐳 Services: ${reconciled.plan.containers.join(", ")}`);
1282
- for (const [container, address] of Object.entries(reconciled.addresses)) logger$10.log(` ${container}: ${address}`);
1206
+ logger$9.log(`🐳 Services: ${reconciled.plan.containers.join(", ")}`);
1207
+ for (const [container, address] of Object.entries(reconciled.addresses)) logger$9.log(` ${container}: ${address}`);
1283
1208
  }
1284
1209
  Object.assign(appSecrets, reconciled.env);
1285
1210
  const own = reconciled.plan.resources.find((r) => (r.kind === "rest-api" || r.kind === "site") && require_config.appKey(r.id) === workspaceAppName);
@@ -1292,7 +1217,7 @@ async function devCommand(options) {
1292
1217
  secretsJsonPath = (0, node_path.join)(secretsDir, secretsFileName);
1293
1218
  await (0, node_fs_promises.writeFile)(secretsJsonPath, JSON.stringify(appSecrets, null, 2));
1294
1219
  }
1295
- const devServer = new DevServer(resolved.providers[0], options.port ?? workspaceAppPort ?? 3e3, options.portExplicit ?? workspaceAppPort !== void 0, enableOpenApi, telescope, studio, runtime, appRoot, secretsJsonPath, initial.selfServing !== void 0);
1220
+ const devServer = new DevServer(options.port ?? workspaceAppPort ?? 3e3, options.portExplicit ?? workspaceAppPort !== void 0, enableOpenApi, telescope, studio, runtime, appRoot, secretsJsonPath, initial.selfServing !== void 0);
1296
1221
  devServer.label = workspaceAppName ?? "server";
1297
1222
  devServer.publicUrl = publicUrl;
1298
1223
  await devServer.start();
@@ -1313,11 +1238,11 @@ async function devCommand(options) {
1313
1238
  cwd: appRoot
1314
1239
  });
1315
1240
  watcher.on("error", (error) => {
1316
- logger$10.error("❌ Watcher error:", error);
1241
+ logger$9.error("❌ Watcher error:", error);
1317
1242
  });
1318
1243
  let rebuildTimeout = null;
1319
1244
  watcher.on("change", async (path) => {
1320
- logger$10.log(`🔄 ${path} changed — rebuilding`);
1245
+ logger$9.log(`🔄 ${path} changed — rebuilding`);
1321
1246
  if (rebuildTimeout) clearTimeout(rebuildTimeout);
1322
1247
  rebuildTimeout = setTimeout(async () => {
1323
1248
  try {
@@ -1326,8 +1251,8 @@ async function devCommand(options) {
1326
1251
  await devServer.restart();
1327
1252
  } catch (error) {
1328
1253
  const err = error;
1329
- logger$10.error(`❌ Rebuild failed: ${err.message}`);
1330
- if (err.stack) logger$10.error(err.stack);
1254
+ logger$9.error(`❌ Rebuild failed: ${err.message}`);
1255
+ if (err.stack) logger$9.error(err.stack);
1331
1256
  }
1332
1257
  }, 300);
1333
1258
  });
@@ -1335,9 +1260,9 @@ async function devCommand(options) {
1335
1260
  const shutdown = () => {
1336
1261
  if (isShuttingDown) return;
1337
1262
  isShuttingDown = true;
1338
- logger$10.log("\n🛑 Shutting down...");
1263
+ logger$9.log("\n🛑 Shutting down...");
1339
1264
  Promise.all([watcher.close(), devServer.stop()]).catch((err) => {
1340
- logger$10.error("Error during shutdown:", err);
1265
+ logger$9.error("Error during shutdown:", err);
1341
1266
  }).finally(() => {
1342
1267
  process.exit(0);
1343
1268
  });
@@ -1539,7 +1464,7 @@ async function workspaceDevCommand(workspace, options) {
1539
1464
  const frontendApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "web");
1540
1465
  const conflicts = checkPortConflicts(workspace);
1541
1466
  if (conflicts.length > 0) {
1542
- for (const conflict of conflicts) logger$10.error(`❌ Port conflict: Apps "${conflict.app1}" and "${conflict.app2}" both use port ${conflict.port}`);
1467
+ for (const conflict of conflicts) logger$9.error(`❌ Port conflict: Apps "${conflict.app1}" and "${conflict.app2}" both use port ${conflict.port}`);
1543
1468
  throw new Error("Port conflicts detected. Please assign unique ports to each app.");
1544
1469
  }
1545
1470
  if (frontendApps.length > 0) {
@@ -1548,10 +1473,10 @@ async function workspaceDevCommand(workspace, options) {
1548
1473
  for (const result of validationResults) {
1549
1474
  if (!result.valid) {
1550
1475
  hasErrors = true;
1551
- logger$10.error(`\n❌ Frontend app "${result.appName}" validation failed:`);
1552
- for (const error of result.errors) logger$10.error(` • ${error}`);
1476
+ logger$9.error(`\n❌ Frontend app "${result.appName}" validation failed:`);
1477
+ for (const error of result.errors) logger$9.error(` • ${error}`);
1553
1478
  }
1554
- for (const warning of result.warnings) logger$10.warn(` ⚠️ ${result.appName}: ${warning}`);
1479
+ for (const warning of result.warnings) logger$9.warn(` ⚠️ ${result.appName}: ${warning}`);
1555
1480
  }
1556
1481
  if (hasErrors) throw new Error("Frontend app validation failed. Fix the issues above and try again.");
1557
1482
  }
@@ -1561,20 +1486,20 @@ async function workspaceDevCommand(workspace, options) {
1561
1486
  ...options.fake ? { fake: true } : {}
1562
1487
  });
1563
1488
  if (reconciled.changed && reconciled.plan.containers.length > 0) {
1564
- logger$10.log(`🐳 Services: ${reconciled.plan.containers.join(", ")}`);
1565
- for (const [container, address] of Object.entries(reconciled.addresses)) logger$10.log(` ${container}: ${address}`);
1489
+ logger$9.log(`🐳 Services: ${reconciled.plan.containers.join(", ")}`);
1490
+ for (const [container, address] of Object.entries(reconciled.addresses)) logger$9.log(` ${container}: ${address}`);
1566
1491
  }
1567
1492
  const secretsEnv = {
1568
1493
  ...rawSecrets,
1569
1494
  ...reconciled.env
1570
1495
  };
1571
1496
  const fakes = options.fake ? await serveFakes(reconciled.fakes, reconciled.ports) : [];
1572
- for (const { id, port } of fakes) logger$10.log(`🎭 ${id} fake: http://localhost:${port}`);
1497
+ for (const { id, port } of fakes) logger$9.log(`🎭 ${id} fake: http://localhost:${port}`);
1573
1498
  if (options.migrate || options.seed) {
1574
- const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-PJi4b1ga.cjs"));
1499
+ const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-Dp5HFzuQ.cjs"));
1575
1500
  await prepareDevDatabases(workspace, reconciled.env, { seed: !!options.seed });
1576
- } else await Promise.resolve().then(() => require("./migrate-PJi4b1ga.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
1577
- logger$10.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
1501
+ } else await Promise.resolve().then(() => require("./migrate-Dp5HFzuQ.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
1502
+ logger$9.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
1578
1503
  });
1579
1504
  const appUrls = {};
1580
1505
  for (const resource of reconciled.plan.resources) {
@@ -1595,11 +1520,11 @@ async function workspaceDevCommand(workspace, options) {
1595
1520
  else {
1596
1521
  const { filters, unpackaged } = turboFilters(workspace);
1597
1522
  turboFilter = filters.flatMap((name) => ["--filter", name]);
1598
- if (unpackaged.length > 0) logger$10.warn(`⚠️ No package.json with a name for: ${unpackaged.join(", ")} — turbo cannot run ${unpackaged.length === 1 ? "it" : "them"}.`);
1523
+ if (unpackaged.length > 0) logger$9.warn(`⚠️ No package.json with a name for: ${unpackaged.join(", ")} — turbo cannot run ${unpackaged.length === 1 ? "it" : "them"}.`);
1599
1524
  }
1600
1525
  const buildOrder = require_workspace.getAppBuildOrder(workspace);
1601
1526
  const width = Math.max(...buildOrder.map((name) => name.length));
1602
- logger$10.log(`\n${workspace.name}: ${appCount} app(s)`);
1527
+ logger$9.log(`\n${workspace.name}: ${appCount} app(s)`);
1603
1528
  for (const appName of buildOrder) {
1604
1529
  const app = workspace.apps[appName];
1605
1530
  if (!app) continue;
@@ -1607,14 +1532,14 @@ async function workspaceDevCommand(workspace, options) {
1607
1532
  const own = reconciled.plan.resources.find((r) => r.kind === "mobile-app" && require_config.appKey(r.id) === appName);
1608
1533
  const scheme = own ? reconciled.env[own.envKey] : void 0;
1609
1534
  const device = Object.entries(reconciled.env).find(([key]) => key.endsWith("_DEVICE_URL"))?.[1];
1610
- logger$10.log(` ${appName.padEnd(width)} ${scheme ? `${scheme}://` : "mobile"}${device ? ` — devices reach ${new URL(device).hostname}` : ""}`);
1535
+ logger$9.log(` ${appName.padEnd(width)} ${scheme ? `${scheme}://` : "mobile"}${device ? ` — devices reach ${new URL(device).hostname}` : ""}`);
1611
1536
  continue;
1612
1537
  }
1613
1538
  const local = `http://localhost:${app.port}`;
1614
1539
  const url = Object.entries(appUrls).find(([id]) => require_config.appKey(id) === appName)?.[1];
1615
- logger$10.log(` ${appName.padEnd(width)} ${url ? `${url} -> ${local}` : local}`);
1540
+ logger$9.log(` ${appName.padEnd(width)} ${url ? `${url} -> ${local}` : local}`);
1616
1541
  }
1617
- logger$10.log("");
1542
+ logger$9.log("");
1618
1543
  const configFiles = [
1619
1544
  "gkm.config.ts",
1620
1545
  "gkm.config.js",
@@ -1661,7 +1586,7 @@ async function workspaceDevCommand(workspace, options) {
1661
1586
  const shutdown = () => {
1662
1587
  if (isShuttingDown) return;
1663
1588
  isShuttingDown = true;
1664
- logger$10.log("\n🛑 Shutting down workspace...");
1589
+ logger$9.log("\n🛑 Shutting down workspace...");
1665
1590
  closeFakes(fakes);
1666
1591
  const pid = turboProcess.pid;
1667
1592
  if (pid) try {
@@ -1686,7 +1611,7 @@ async function workspaceDevCommand(workspace, options) {
1686
1611
  process.on("SIGTERM", shutdown);
1687
1612
  return new Promise((resolve, reject) => {
1688
1613
  turboProcess.on("error", (error) => {
1689
- logger$10.error("❌ Turbo error:", error);
1614
+ logger$9.error("❌ Turbo error:", error);
1690
1615
  reject(error);
1691
1616
  });
1692
1617
  turboProcess.on("exit", (code) => {
@@ -1705,11 +1630,11 @@ async function entryDevCommand(options) {
1705
1630
  const entryPath = (0, node_path.resolve)(process.cwd(), entry);
1706
1631
  if (!(0, node_fs.existsSync)(entryPath)) throw new Error(`Entry file not found: ${entryPath}`);
1707
1632
  const defaultEnv = require_workspace$1.loadEnvFiles(".env");
1708
- if (defaultEnv.loaded.length > 0) logger$10.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1633
+ if (defaultEnv.loaded.length > 0) logger$9.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1709
1634
  const { credentials, resolvedPort, secretsJsonPath, appName } = await require_workspace$1.prepareEntryCredentials({ explicitPort: options.portExplicit ? options.port : void 0 });
1710
- if (appName) logger$10.log(`📦 App: ${appName} (port ${resolvedPort})`);
1711
- logger$10.log(`🚀 Starting entry file: ${entry} on port ${resolvedPort}`);
1712
- if (Object.keys(credentials).length > 1) logger$10.log(`🔐 Loaded ${Object.keys(credentials).length - 1} secret(s) + PORT`);
1635
+ if (appName) logger$9.log(`📦 App: ${appName} (port ${resolvedPort})`);
1636
+ logger$9.log(`🚀 Starting entry file: ${entry} on port ${resolvedPort}`);
1637
+ if (Object.keys(credentials).length > 1) logger$9.log(`🔐 Loaded ${Object.keys(credentials).length - 1} secret(s) + PORT`);
1713
1638
  const wrapperDir = (0, node_path.join)(process.cwd(), ".gkm");
1714
1639
  await (0, node_fs_promises.mkdir)(wrapperDir, { recursive: true });
1715
1640
  const wrapperPath = (0, node_path.join)(wrapperDir, "entry-wrapper.ts");
@@ -1720,7 +1645,7 @@ async function entryDevCommand(options) {
1720
1645
  const shutdown = () => {
1721
1646
  if (isShuttingDown) return;
1722
1647
  isShuttingDown = true;
1723
- logger$10.log("\n🛑 Shutting down...");
1648
+ logger$9.log("\n🛑 Shutting down...");
1724
1649
  runner.stop();
1725
1650
  process.exit(0);
1726
1651
  };
@@ -1756,14 +1681,14 @@ var EntryRunner = class {
1756
1681
  });
1757
1682
  let restartTimeout = null;
1758
1683
  this.watcher.on("change", (path) => {
1759
- logger$10.log(`📝 File changed: ${path}`);
1684
+ logger$9.log(`📝 File changed: ${path}`);
1760
1685
  if (restartTimeout) clearTimeout(restartTimeout);
1761
1686
  restartTimeout = setTimeout(async () => {
1762
- logger$10.log("🔄 Restarting...");
1687
+ logger$9.log("🔄 Restarting...");
1763
1688
  await this.restart();
1764
1689
  }, 300);
1765
1690
  });
1766
- logger$10.log(`👀 Watching for changes in: ${watchDir}`);
1691
+ logger$9.log(`👀 Watching for changes in: ${watchDir}`);
1767
1692
  }
1768
1693
  }
1769
1694
  async runProcess() {
@@ -1778,17 +1703,17 @@ var EntryRunner = class {
1778
1703
  });
1779
1704
  this.isRunning = true;
1780
1705
  this.childProcess.on("error", (error) => {
1781
- logger$10.error("❌ Process error:", error);
1706
+ logger$9.error("❌ Process error:", error);
1782
1707
  });
1783
1708
  this.childProcess.on("exit", (code) => {
1784
- if (code !== null && code !== 0 && code !== 143) logger$10.error(`❌ Process exited with code ${code}`);
1709
+ if (code !== null && code !== 0 && code !== 143) logger$9.error(`❌ Process exited with code ${code}`);
1785
1710
  this.isRunning = false;
1786
1711
  });
1787
1712
  await new Promise((resolve) => setTimeout(resolve, 500));
1788
1713
  if (this.isRunning) {
1789
- logger$10.log("");
1790
- logger$10.log(` \x1b[32m✓ Ready\x1b[0m at \x1b[36mhttp://localhost:${this.port}\x1b[0m`);
1791
- logger$10.log("");
1714
+ logger$9.log("");
1715
+ logger$9.log(` \x1b[32m✓ Ready\x1b[0m at \x1b[36mhttp://localhost:${this.port}\x1b[0m`);
1716
+ logger$9.log("");
1792
1717
  }
1793
1718
  }
1794
1719
  async restart() {
@@ -1966,7 +1891,6 @@ function listenerOn(port) {
1966
1891
  }
1967
1892
  }
1968
1893
  var DevServer = class {
1969
- provider;
1970
1894
  requestedPort;
1971
1895
  portExplicit;
1972
1896
  enableOpenApi;
@@ -1980,8 +1904,7 @@ var DevServer = class {
1980
1904
  isRunning = false;
1981
1905
  actualPort;
1982
1906
  startTime = Date.now();
1983
- constructor(provider, requestedPort, portExplicit, enableOpenApi, telescope, studio, runtime = "node", appRoot = process.cwd(), secretsJsonPath, selfServing = false) {
1984
- this.provider = provider;
1907
+ constructor(requestedPort, portExplicit, enableOpenApi, telescope, studio, runtime = "node", appRoot = process.cwd(), secretsJsonPath, selfServing = false) {
1985
1908
  this.requestedPort = requestedPort;
1986
1909
  this.portExplicit = portExplicit;
1987
1910
  this.enableOpenApi = enableOpenApi;
@@ -2008,9 +1931,9 @@ var DevServer = class {
2008
1931
  this.actualPort = this.requestedPort;
2009
1932
  } else {
2010
1933
  this.actualPort = await require_workspace$1.findAvailablePort(this.requestedPort);
2011
- if (this.actualPort !== this.requestedPort) logger$10.log(`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`);
1934
+ if (this.actualPort !== this.requestedPort) logger$9.log(`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`);
2012
1935
  }
2013
- const serverEntryPath = (0, node_path.join)(this.appRoot, ".gkm", this.provider, "server.ts");
1936
+ const serverEntryPath = (0, node_path.join)(this.appRoot, ".gkm", "server", "server.ts");
2014
1937
  await this.createServerEntry();
2015
1938
  this.serverProcess = (0, node_child_process.spawn)(...tsxCommand(this.appRoot, [
2016
1939
  serverEntryPath,
@@ -2027,10 +1950,10 @@ var DevServer = class {
2027
1950
  });
2028
1951
  this.isRunning = true;
2029
1952
  this.serverProcess.on("error", (error) => {
2030
- logger$10.error("❌ Server error:", error);
1953
+ logger$9.error("❌ Server error:", error);
2031
1954
  });
2032
1955
  this.serverProcess.on("exit", (code, signal) => {
2033
- if (code !== null && code !== 0 && signal !== "SIGTERM") logger$10.error(`❌ Server exited with code ${code}`);
1956
+ if (code !== null && code !== 0 && signal !== "SIGTERM") logger$9.error(`❌ Server exited with code ${code}`);
2034
1957
  this.isRunning = false;
2035
1958
  });
2036
1959
  await new Promise((resolve) => setTimeout(resolve, 1e3));
@@ -2038,13 +1961,13 @@ var DevServer = class {
2038
1961
  const local = `http://localhost:${this.actualPort}`;
2039
1962
  const address = this.publicUrl ? `${this.publicUrl} -> ${local}` : local;
2040
1963
  const seconds = ((Date.now() - this.startTime) / 1e3).toFixed(1);
2041
- logger$10.log(`\x1b[32m✓\x1b[0m ${this.label} ready in ${seconds}s ${address}`);
1964
+ logger$9.log(`\x1b[32m✓\x1b[0m ${this.label} ready in ${seconds}s ${address}`);
2042
1965
  const tools = this.selfServing ? [] : [
2043
1966
  ...this.enableOpenApi ? ["docs /__docs"] : [],
2044
1967
  ...this.telescope ? [`telescope ${this.telescope.path}`] : [],
2045
1968
  ...this.studio ? [`studio ${this.studio.path}`] : []
2046
1969
  ];
2047
- if (tools.length > 0) logger$10.log(` ${tools.join(" · ")}`);
1970
+ if (tools.length > 0) logger$9.log(` ${tools.join(" · ")}`);
2048
1971
  }
2049
1972
  }
2050
1973
  async stop() {
@@ -2082,7 +2005,7 @@ var DevServer = class {
2082
2005
  }
2083
2006
  async createServerEntry() {
2084
2007
  const { writeFile: fsWriteFile } = await import("node:fs/promises");
2085
- await fsWriteFile((0, node_path.join)(this.appRoot, ".gkm", this.provider, "server.ts"), generateServerEntryContent({
2008
+ await fsWriteFile((0, node_path.join)(this.appRoot, ".gkm", "server", "server.ts"), generateServerEntryContent({
2086
2009
  secretsJsonPath: this.secretsJsonPath,
2087
2010
  runtime: this.runtime,
2088
2011
  enableOpenApi: this.enableOpenApi,
@@ -2094,22 +2017,22 @@ var DevServer = class {
2094
2017
  //#region src/generators/CronGenerator.ts
2095
2018
  var CronGenerator = class extends require_discover.ConstructGenerator {
2096
2019
  async build(context, constructs, outputDir, options) {
2097
- const provider = options?.provider || "aws-lambda";
2020
+ const target = options?.target ?? "aws";
2098
2021
  const logger = console;
2099
2022
  const cronInfos = [];
2100
- if (provider === "server") {
2023
+ if (target === "server") {
2101
2024
  await this.generateServerCronsFile(outputDir, constructs);
2102
2025
  logger.log(`Generated server crons file with ${constructs.length} crons`);
2103
2026
  return cronInfos;
2104
2027
  }
2105
- if (constructs.length === 0 || provider !== "aws-lambda") return cronInfos;
2028
+ if (constructs.length === 0) return cronInfos;
2106
2029
  const cronsDir = (0, node_path.join)(outputDir, "crons");
2107
2030
  await (0, node_fs_promises.mkdir)(cronsDir, { recursive: true });
2108
2031
  for (const { key, construct, path } of constructs) {
2109
2032
  const handlerFile = await this.generateCronHandler(cronsDir, path.relative, key, context, construct.owner);
2110
2033
  cronInfos.push({
2111
2034
  name: key,
2112
- handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
2035
+ handler: (0, node_path.relative)(options?.root ?? process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
2113
2036
  schedule: construct.schedule || "rate(1 hour)",
2114
2037
  timeout: construct.timeout,
2115
2038
  memorySize: construct.memorySize,
@@ -2299,17 +2222,17 @@ var FunctionGenerator = class extends require_discover.ConstructGenerator {
2299
2222
  return _geekmidas_constructs_functions.Function.isFunction(value);
2300
2223
  }
2301
2224
  async build(context, constructs, outputDir, options) {
2302
- const provider = options?.provider || "aws-lambda";
2225
+ const target = options?.target ?? "aws";
2303
2226
  const logger = console;
2304
2227
  const functionInfos = [];
2305
- if (constructs.length === 0 || provider !== "aws-lambda") return functionInfos;
2228
+ if (constructs.length === 0 || target === "server") return functionInfos;
2306
2229
  const functionsDir = (0, node_path.join)(outputDir, "functions");
2307
2230
  await (0, node_fs_promises.mkdir)(functionsDir, { recursive: true });
2308
2231
  for (const { key, construct, path } of constructs) {
2309
2232
  const handlerFile = await this.generateFunctionHandler(functionsDir, path.relative, key, context, construct.owner);
2310
2233
  functionInfos.push({
2311
2234
  name: key,
2312
- handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
2235
+ handler: (0, node_path.relative)(options?.root ?? process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
2313
2236
  timeout: construct.timeout,
2314
2237
  memorySize: construct.memorySize,
2315
2238
  environment: await construct.getEnvironment({ markOptional: context.markOptional }),
@@ -2353,22 +2276,22 @@ var QueueGenerator = class extends require_discover.ConstructGenerator {
2353
2276
  return _geekmidas_constructs_queue.Queue.isQueue(value);
2354
2277
  }
2355
2278
  async build(context, constructs, outputDir, options) {
2356
- const provider = options?.provider || "aws-lambda";
2279
+ const target = options?.target ?? "aws";
2357
2280
  const logger = console;
2358
2281
  const queueInfos = [];
2359
- if (provider === "server") {
2282
+ if (target === "server") {
2360
2283
  await this.generateServerQueuesFile(outputDir, constructs);
2361
2284
  logger.log(`Generated server queues file with ${constructs.length} queues (polling mode)`);
2362
2285
  return queueInfos;
2363
2286
  }
2364
- if (constructs.length === 0 || provider !== "aws-lambda") return queueInfos;
2287
+ if (constructs.length === 0) return queueInfos;
2365
2288
  const queuesDir = (0, node_path.join)(outputDir, "queues");
2366
2289
  await (0, node_fs_promises.mkdir)(queuesDir, { recursive: true });
2367
2290
  for (const { key, construct, path } of constructs) {
2368
2291
  const handlerFile = await this.generateQueueHandler(queuesDir, path.relative, key, context, construct.owner);
2369
2292
  queueInfos.push({
2370
2293
  name: construct.name,
2371
- handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
2294
+ handler: (0, node_path.relative)(options?.root ?? process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
2372
2295
  batchSize: construct.batchSize,
2373
2296
  fifo: construct.fifo,
2374
2297
  timeout: construct.timeout,
@@ -2534,217 +2457,6 @@ var TopicGenerator = class extends require_discover.ConstructGenerator {
2534
2457
  }
2535
2458
  };
2536
2459
  //#endregion
2537
- //#region src/build/manifests.ts
2538
- const logger$9 = console;
2539
- function isPartitioned(field) {
2540
- return !Array.isArray(field);
2541
- }
2542
- /**
2543
- * Serialize a manifest field to a TypeScript string.
2544
- * Flat arrays serialize as JSON arrays, partitioned fields as objects of arrays.
2545
- */
2546
- function serializeField(field, indent = 2) {
2547
- if (Array.isArray(field)) return JSON.stringify(field, null, indent);
2548
- return `{\n${Object.entries(field).map(([key, value]) => ` ${JSON.stringify(key)}: ${JSON.stringify(value, null, indent)}`).join(",\n")},\n }`;
2549
- }
2550
- /**
2551
- * Count total items across a manifest field (flat or partitioned).
2552
- */
2553
- function countItems(field) {
2554
- if (Array.isArray(field)) return field.length;
2555
- return Object.values(field).reduce((sum, arr) => sum + arr.length, 0);
2556
- }
2557
- /**
2558
- * Generate derived types for a construct field.
2559
- * @param fieldName - The field name in the manifest (e.g., 'routes')
2560
- * @param typeName - The exported type name (e.g., 'Route')
2561
- * @param partitioned - Whether this field is partitioned
2562
- */
2563
- function generateDerivedType(fieldName, typeName, partitioned) {
2564
- if (partitioned) {
2565
- const partitionTypeName = `${typeName}Partition`;
2566
- return [`export type ${partitionTypeName} = keyof typeof manifest.${fieldName};`, `export type ${typeName}<P extends ${partitionTypeName} = ${partitionTypeName}> = (typeof manifest.${fieldName})[P][number];`].join("\n");
2567
- }
2568
- return `export type ${typeName} = (typeof manifest.${fieldName})[number];`;
2569
- }
2570
- /** A manifest field as a flat list, whether or not it is partitioned. */
2571
- function flatten(field) {
2572
- return Array.isArray(field) ? field : Object.values(field).flat();
2573
- }
2574
- async function generateAwsManifest(outputDir, routes, functions, crons, subscribers, queues = [], topics = [], constructs = {}, backends = {}) {
2575
- const manifestDir = (0, node_path.join)(outputDir, "manifest");
2576
- await (0, node_fs_promises.mkdir)(manifestDir, { recursive: true });
2577
- const awsRoutes = filterAllRoutes(routes);
2578
- const routesPartitioned = isPartitioned(awsRoutes);
2579
- const functionsPartitioned = isPartitioned(functions);
2580
- const cronsPartitioned = isPartitioned(crons);
2581
- const subscribersPartitioned = isPartitioned(subscribers);
2582
- const queuesPartitioned = isPartitioned(queues);
2583
- const topicsPartitioned = isPartitioned(topics);
2584
- const awsConstructs = require_emit.withCompute(require_emit.withRoutes(constructs, flatten(awsRoutes), { perRoute: true }), {
2585
- functions: flatten(functions),
2586
- crons: flatten(crons),
2587
- queues: flatten(queues),
2588
- subscribers: flatten(subscribers)
2589
- });
2590
- const content = `export const manifest = {
2591
- routes: ${serializeField(awsRoutes)},
2592
- functions: ${serializeField(functions)},
2593
- crons: ${serializeField(crons)},
2594
- subscribers: ${serializeField(subscribers)},
2595
- queues: ${serializeField(queues)},
2596
- topics: ${serializeField(topics)},
2597
- } as const;
2598
-
2599
- /**
2600
- * What the application declares, as opposed to what this build generated.
2601
- *
2602
- * Discovery imports application code, so it runs once here rather than in every
2603
- * consumer — a deploy config calling it would evaluate the whole runtime graph
2604
- * inside its own toolchain.
2605
- */
2606
- export const constructs = ${JSON.stringify(awsConstructs, null, 2)} as const;
2607
-
2608
- /**
2609
- * Where the backends that are config rather than declaration resolved to.
2610
- *
2611
- * Recorded because they were answered twice: once by the build, which registers
2612
- * exactly one cache driver, and once by a deploy, which told the provisioner
2613
- * something else — leaving the running code with a URL it had no driver for.
2614
- */
2615
- export const backends = ${JSON.stringify(backends, null, 2)} as const;
2616
-
2617
- // Derived types
2618
- ${generateDerivedType("routes", "Route", routesPartitioned)}
2619
- ${generateDerivedType("functions", "Function", functionsPartitioned)}
2620
- ${generateDerivedType("crons", "Cron", cronsPartitioned)}
2621
- ${generateDerivedType("subscribers", "Subscriber", subscribersPartitioned)}
2622
- ${generateDerivedType("queues", "Queue", queuesPartitioned)}
2623
- ${generateDerivedType("topics", "Topic", topicsPartitioned)}
2624
-
2625
- export type ConstructId = keyof typeof constructs;
2626
- export type Construct<Id extends ConstructId> = (typeof constructs)[Id];
2627
-
2628
- // Useful union types
2629
- export type Authorizer = Route['authorizer'];
2630
- export type HttpMethod = Route['method'];
2631
- export type RoutePath = Route['path'];
2632
- `;
2633
- const manifestPath = (0, node_path.join)(manifestDir, "aws.ts");
2634
- await (0, node_fs_promises.writeFile)(manifestPath, content);
2635
- logger$9.log(`Generated AWS manifest with ${countItems(awsRoutes)} routes, ${countItems(functions)} functions, ${countItems(crons)} crons, ${countItems(subscribers)} subscribers, ${countItems(queues)} queues, ${countItems(topics)} topics`);
2636
- logger$9.log(`Manifest: ${(0, node_path.relative)(process.cwd(), manifestPath)}`);
2637
- }
2638
- async function generateServerManifest(outputDir, appInfo, routes, subscribers, queues = [], topics = [], constructs = {}, backends = {}) {
2639
- const manifestDir = (0, node_path.join)(outputDir, "manifest");
2640
- await (0, node_fs_promises.mkdir)(manifestDir, { recursive: true });
2641
- const serverRoutes = mapRouteMetadata(filterAllRoutes(routes));
2642
- const serverSubscribers = mapSubscriberMetadata(subscribers);
2643
- const serverQueues = mapQueueMetadata(queues);
2644
- const serverTopics = mapTopicMetadata(topics);
2645
- const routesPartitioned = isPartitioned(serverRoutes);
2646
- const subscribersPartitioned = isPartitioned(serverSubscribers);
2647
- const queuesPartitioned = isPartitioned(serverQueues);
2648
- const topicsPartitioned = isPartitioned(serverTopics);
2649
- const content = `export const manifest = {
2650
- app: ${JSON.stringify(appInfo, null, 2)},
2651
- routes: ${serializeField(serverRoutes)},
2652
- subscribers: ${serializeField(serverSubscribers)},
2653
- queues: ${serializeField(serverQueues)},
2654
- topics: ${serializeField(serverTopics)},
2655
- } as const;
2656
-
2657
- /**
2658
- * What the application declares, as opposed to what this build generated.
2659
- *
2660
- * Discovery imports application code, so it runs once in the build rather than
2661
- * in every consumer — a deploy config calling it would evaluate the whole
2662
- * runtime graph inside its own toolchain.
2663
- */
2664
- export const constructs = ${JSON.stringify(constructs, null, 2)} as const;
2665
-
2666
- /**
2667
- * Where the backends that are config rather than declaration resolved to.
2668
- *
2669
- * Recorded because they were answered twice: once by the build, which registers
2670
- * exactly one cache driver, and once by a deploy, which told the provisioner
2671
- * something else — leaving the running code with a URL it had no driver for.
2672
- */
2673
- export const backends = ${JSON.stringify(backends, null, 2)} as const;
2674
-
2675
- // Derived types
2676
- ${generateDerivedType("routes", "Route", routesPartitioned)}
2677
- ${generateDerivedType("subscribers", "Subscriber", subscribersPartitioned)}
2678
- ${generateDerivedType("queues", "Queue", queuesPartitioned)}
2679
- ${generateDerivedType("topics", "Topic", topicsPartitioned)}
2680
-
2681
- export type ConstructId = keyof typeof constructs;
2682
- export type Construct<Id extends ConstructId> = (typeof constructs)[Id];
2683
-
2684
- // Useful union types
2685
- export type Authorizer = Route['authorizer'];
2686
- export type HttpMethod = Route['method'];
2687
- export type RoutePath = Route['path'];
2688
- `;
2689
- const manifestPath = (0, node_path.join)(manifestDir, "server.ts");
2690
- await (0, node_fs_promises.writeFile)(manifestPath, content);
2691
- logger$9.log(`Generated server manifest with ${countItems(serverRoutes)} routes, ${countItems(serverSubscribers)} subscribers, ${countItems(serverQueues)} queues, ${countItems(serverTopics)} topics`);
2692
- logger$9.log(`Manifest: ${(0, node_path.relative)(process.cwd(), manifestPath)}`);
2693
- }
2694
- /**
2695
- * Filter out 'ALL' method routes from a manifest field (flat or partitioned).
2696
- */
2697
- function filterAllRoutes(routes) {
2698
- if (Array.isArray(routes)) return routes.filter((r) => r.method !== "ALL");
2699
- const result = {};
2700
- for (const [partition, partitionRoutes] of Object.entries(routes)) result[partition] = partitionRoutes.filter((r) => r.method !== "ALL");
2701
- return result;
2702
- }
2703
- /**
2704
- * Map routes to server metadata (path, method, authorizer only).
2705
- */
2706
- function mapRouteMetadata(routes) {
2707
- const mapFn = (r) => ({
2708
- path: r.path,
2709
- method: r.method,
2710
- authorizer: r.authorizer
2711
- });
2712
- if (Array.isArray(routes)) return routes.map(mapFn);
2713
- const result = {};
2714
- for (const [partition, partitionRoutes] of Object.entries(routes)) result[partition] = partitionRoutes.map(mapFn);
2715
- return result;
2716
- }
2717
- /**
2718
- * Map subscribers to server metadata (name, subscribedEvents only).
2719
- */
2720
- function mapSubscriberMetadata(subscribers) {
2721
- const mapFn = (s) => ({
2722
- name: s.name,
2723
- subscribedEvents: s.subscribedEvents
2724
- });
2725
- if (Array.isArray(subscribers)) return subscribers.map(mapFn);
2726
- const result = {};
2727
- for (const [partition, partitionSubs] of Object.entries(subscribers)) result[partition] = partitionSubs.map(mapFn);
2728
- return result;
2729
- }
2730
- function mapQueueMetadata(queues) {
2731
- const mapFn = (q) => ({ name: q.name });
2732
- if (Array.isArray(queues)) return queues.map(mapFn);
2733
- const result = {};
2734
- for (const [partition, partitionQueues] of Object.entries(queues)) result[partition] = partitionQueues.map(mapFn);
2735
- return result;
2736
- }
2737
- function mapTopicMetadata(topics) {
2738
- const mapFn = (t) => ({
2739
- name: t.name,
2740
- events: t.events
2741
- });
2742
- if (Array.isArray(topics)) return topics.map(mapFn);
2743
- const result = {};
2744
- for (const [partition, partitionTopics] of Object.entries(topics)) result[partition] = partitionTopics.map(mapFn);
2745
- return result;
2746
- }
2747
- //#endregion
2748
2460
  //#region src/build/owners.ts
2749
2461
  /**
2750
2462
  * What a generated entry imports its runtime from, read off the discovered
@@ -2814,27 +2526,6 @@ function restApis(declared) {
2814
2526
  function servedSurface(declared, workspaceRoot, appRoot) {
2815
2527
  return restApis(declared).find((d) => (0, node_path.resolve)(workspaceRoot, d.path) === (0, node_path.resolve)(appRoot));
2816
2528
  }
2817
- /**
2818
- * Check if any construct across the given arrays has a non-undefined partition.
2819
- * When true, the manifest should use the partitioned shape for that construct type.
2820
- */
2821
- function hasPartitions(constructs) {
2822
- return constructs.some((c) => c.partition !== void 0);
2823
- }
2824
- /**
2825
- * Group an info array by partition, using the partition values from
2826
- * the corresponding construct array. Both arrays must be the same length
2827
- * and in the same order.
2828
- */
2829
- function groupInfosByPartition(infos, constructs) {
2830
- const groups = {};
2831
- for (let i = 0; i < infos.length; i++) {
2832
- const partition = constructs[i]?.partition ?? "default";
2833
- if (!groups[partition]) groups[partition] = [];
2834
- groups[partition].push(infos[i]);
2835
- }
2836
- return groups;
2837
- }
2838
2529
  //#endregion
2839
2530
  //#region src/build/surfaceEntry.ts
2840
2531
  /** Whether a construct serves itself, asked of the construct. */
@@ -2911,6 +2602,24 @@ function rootGkmConfig(workspace) {
2911
2602
  constructs: require_workspace.allConstructGlobs(workspace)
2912
2603
  };
2913
2604
  }
2605
+ /** Directories under `.gkm/` that the removed per-provider builds wrote. */
2606
+ const SUPERSEDED_OUTPUT = [
2607
+ "aws-apigatewayv1",
2608
+ "aws-apigatewayv2",
2609
+ "aws-lambda"
2610
+ ];
2611
+ /** Whether `--provider` named something a build can target. */
2612
+ function isMainProvider(value) {
2613
+ return value === "aws" || value === "server";
2614
+ }
2615
+ var UnknownBuildProvider = class extends Error {
2616
+ provider;
2617
+ constructor(provider) {
2618
+ super(`'${provider}' is not a build target. Pass --provider aws or --provider server, or leave it out to build for where gkm.config.ts deploys.`);
2619
+ this.provider = provider;
2620
+ this.name = "UnknownBuildProvider";
2621
+ }
2622
+ };
2914
2623
  async function buildCommand(options) {
2915
2624
  const loadedConfig = await require_config.loadWorkspaceConfig();
2916
2625
  if (loadedConfig.type === "workspace") {
@@ -2924,25 +2633,62 @@ async function buildCommand(options) {
2924
2633
  }
2925
2634
  }
2926
2635
  const config = loadedConfig.type !== "workspace" ? await require_config.loadConfig() : (0, node_path.resolve)(process.cwd()) === (0, node_path.resolve)(loadedConfig.workspace.root) ? rootGkmConfig(loadedConfig.workspace) : (await require_config.loadAppConfig()).gkmConfig;
2927
- const resolved = resolveProviders(config, options);
2928
- const cacheBackend = require_workspace$1.cacheBackendFor(require_workspace$1.providerOf(loadedConfig.workspace));
2929
- const productionConfigFromGkm = getProductionConfigFromGkm(config);
2930
- const production = normalizeProductionConfig(options.production ?? false, productionConfigFromGkm);
2636
+ const target = options.provider ?? require_workspace$1.providerOf(loadedConfig.workspace);
2637
+ const workspaceRoot = loadedConfig.workspace.root;
2638
+ const appRoot = process.cwd();
2639
+ const output = await buildOneApp({
2640
+ config,
2641
+ options,
2642
+ workspace: loadedConfig.workspace,
2643
+ appRoot,
2644
+ target
2645
+ });
2646
+ if ((0, node_path.resolve)(appRoot) === (0, node_path.resolve)(workspaceRoot)) await writeManifest({
2647
+ workspaceRoot,
2648
+ target,
2649
+ builds: output.built ? [output.built] : [],
2650
+ constructs: await declaredIn(config, workspaceRoot),
2651
+ backends: backendsOf(loadedConfig.workspace)
2652
+ });
2653
+ return output;
2654
+ }
2655
+ /** What the workspace declares, read through a config's globs. */
2656
+ async function declaredIn(config, cwd) {
2657
+ return require_discover.discover({
2658
+ patterns: config.constructs,
2659
+ cwd
2660
+ });
2661
+ }
2662
+ /**
2663
+ * The backend choices the manifest records — answered by the deploy target,
2664
+ * the same place reconcile and the build's drivers read them.
2665
+ */
2666
+ function backendsOf(workspace) {
2667
+ return {
2668
+ cache: require_workspace$1.cacheBackendFor(require_workspace$1.providerOf(workspace)),
2669
+ email: "ses"
2670
+ };
2671
+ }
2672
+ /** One app's build, from its config and the command's options. */
2673
+ async function buildOneApp(input) {
2674
+ const { config, options, workspace, appRoot, target } = input;
2675
+ const cacheBackend = require_workspace$1.cacheBackendFor(require_workspace$1.providerOf(workspace));
2676
+ const production = normalizeProductionConfig(options.production ?? false);
2931
2677
  if (production) logger$8.log(`🏭 Building for PRODUCTION`);
2932
- logger$8.log(`Building with providers: ${resolved.providers.join(", ")}`);
2678
+ logger$8.log(`Building for ${target}`);
2933
2679
  logger$8.log(`Loading constructs from: ${formatRoutes(config.constructs)}`);
2934
2680
  const telescope = production ? void 0 : normalizeTelescopeConfig(config.telescope);
2935
2681
  if (telescope) logger$8.log(`🔭 Telescope enabled at ${telescope.path}`);
2936
2682
  const studio = production ? void 0 : normalizeStudioConfig(config.studio);
2937
2683
  if (studio) logger$8.log(`🗄️ Studio enabled at ${studio.path}`);
2938
- const hooks = normalizeHooksConfig(config.hooks);
2684
+ const hooks = normalizeHooksConfig(config.hooks, appRoot);
2939
2685
  if (hooks) logger$8.log(`🪝 Server hooks enabled`);
2940
2686
  return buildApp({
2941
2687
  config,
2942
- workspaceRoot: loadedConfig.workspace.root,
2943
- appRoot: process.cwd(),
2944
- providers: resolved.providers,
2945
- enableOpenApi: resolved.enableOpenApi,
2688
+ workspaceRoot: workspace.root,
2689
+ appRoot,
2690
+ target,
2691
+ enableOpenApi: options.enableOpenApi ?? false,
2946
2692
  cacheBackend,
2947
2693
  production,
2948
2694
  telescope,
@@ -2954,6 +2700,33 @@ async function buildCommand(options) {
2954
2700
  });
2955
2701
  }
2956
2702
  /**
2703
+ * Write the application's manifest: every declared construct, with what each
2704
+ * app generated folded into it.
2705
+ *
2706
+ * The manifest belongs to the whole application, so only the root writes it —
2707
+ * once, after every app has built, from the constructs the workspace declares.
2708
+ * An app's own build generates its handlers and nothing else.
2709
+ */
2710
+ async function writeManifest(input) {
2711
+ const { workspaceRoot, target, builds, constructs, backends } = input;
2712
+ const manifestDir = (0, node_path.join)(workspaceRoot, ".gkm", "manifest");
2713
+ await (0, node_fs_promises.mkdir)(manifestDir, { recursive: true });
2714
+ await (0, node_fs_promises.rm)((0, node_path.join)(manifestDir, `${target === "aws" ? "server" : "aws"}.ts`), { force: true });
2715
+ const withServed = builds.reduce((manifest, build) => require_emit.withRoutes(manifest, build.routes.filter((route) => route.method !== "ALL"), {
2716
+ perRoute: true,
2717
+ ...build.surface ? { surface: build.surface } : {}
2718
+ }), constructs);
2719
+ const folded = require_emit.withCompute(withServed, {
2720
+ functions: builds.flatMap((build) => build.functions),
2721
+ crons: builds.flatMap((build) => build.crons),
2722
+ queues: builds.flatMap((build) => build.queues),
2723
+ subscribers: builds.flatMap((build) => build.subscribers)
2724
+ });
2725
+ const path = (0, node_path.join)(manifestDir, `${target}.ts`);
2726
+ await (0, node_fs_promises.writeFile)(path, require_emit.manifestModule(folded, backends));
2727
+ logger$8.log(`Manifest: ${(0, node_path.relative)(process.cwd(), path)}`);
2728
+ }
2729
+ /**
2957
2730
  * Turn one app's constructs into its generated entry.
2958
2731
  *
2959
2732
  * `gkm build` and `gkm dev` both run this. They used to be two copies of it,
@@ -2962,8 +2735,8 @@ async function buildCommand(options) {
2962
2735
  * dev did not, and failed on exactly the apps the build had learned to handle.
2963
2736
  */
2964
2737
  async function buildApp(input) {
2965
- const { config, workspaceRoot, appRoot, providers, enableOpenApi, cacheBackend, production, telescope, studio, hooks, bustCache = false } = input;
2966
- const constructGlobs = typeof config.constructs === "string" || Array.isArray(config.constructs) ? config.constructs : void 0;
2738
+ const { config, workspaceRoot, appRoot, target, enableOpenApi, cacheBackend, production, telescope, studio, hooks, bustCache = false } = input;
2739
+ const constructGlobs = config.constructs;
2967
2740
  const constructSources = {};
2968
2741
  const declared = constructGlobs ? await require_discover.discover({
2969
2742
  patterns: constructGlobs,
@@ -3029,50 +2802,58 @@ async function buildApp(input) {
3029
2802
  logger$8.log("No endpoints, functions, crons, subscribers, queues, or topics found to process");
3030
2803
  return {};
3031
2804
  }
3032
- const rootOutputDir = (0, node_path.join)(appRoot, ".gkm");
3033
- await (0, node_fs_promises.mkdir)(rootOutputDir, { recursive: true });
3034
- let result = {};
3035
- for (const provider of providers) {
3036
- const providerResult = await buildForProvider(provider, buildContext, appRoot, declared, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, queueGenerator, topicGenerator, allEndpoints, allFunctions, allCrons, allSubscribers, allQueues, allTopics, enableOpenApi, input.skipBundle ?? false, input.stage);
3037
- if (providerResult.masterKey) result = providerResult;
3038
- }
2805
+ const result = await buildForTarget(target, buildContext, appRoot, workspaceRoot, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, queueGenerator, topicGenerator, allEndpoints, allFunctions, allCrons, allSubscribers, allQueues, allTopics, enableOpenApi, input.skipBundle ?? false, input.stage);
3039
2806
  await require_openapi.generateOpenApi(allEndpoints.map(({ construct }) => construct), { openapi: config.openapi });
3040
2807
  return result;
3041
2808
  }
3042
- async function buildForProvider(provider, context, appRoot, discovered, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, queueGenerator, topicGenerator, endpoints, functions, crons, subscribers, queues, topics, enableOpenApi, skipBundle, stage) {
3043
- const rootOutputDir = (0, node_path.join)(appRoot, ".gkm");
3044
- const outputDir = (0, node_path.join)(rootOutputDir, provider);
2809
+ async function buildForTarget(target, context, appRoot, workspaceRoot, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, queueGenerator, topicGenerator, endpoints, functions, crons, subscribers, queues, topics, enableOpenApi, skipBundle, stage) {
2810
+ const outputDir = (0, node_path.join)(appRoot, ".gkm", target);
2811
+ await Promise.all([...SUPERSEDED_OUTPUT.map((dir) => (0, node_path.join)(appRoot, ".gkm", dir)), ...appRoot === workspaceRoot ? [] : [(0, node_path.join)(appRoot, ".gkm", "manifest")]].map((dir) => (0, node_fs_promises.rm)(dir, {
2812
+ recursive: true,
2813
+ force: true
2814
+ })));
2815
+ if (target === "aws") await (0, node_fs_promises.rm)(outputDir, {
2816
+ recursive: true,
2817
+ force: true
2818
+ });
3045
2819
  await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
3046
- logger$8.log(`\nGenerating handlers for provider: ${provider}`);
2820
+ logger$8.log(`\nGenerating handlers for ${target}`);
2821
+ const options = {
2822
+ target,
2823
+ root: workspaceRoot
2824
+ };
3047
2825
  const [routes, functionInfos, cronInfos, subscriberInfos, queueInfos, topicInfos] = await Promise.all([
3048
2826
  endpointGenerator.build(context, endpoints, outputDir, {
3049
- provider,
2827
+ ...options,
3050
2828
  enableOpenApi
3051
2829
  }),
3052
- functionGenerator.build(context, functions, outputDir, { provider }),
3053
- cronGenerator.build(context, crons, outputDir, { provider }),
3054
- subscriberGenerator.build(context, subscribers, outputDir, { provider }),
3055
- queueGenerator.build(context, queues, outputDir, { provider }),
3056
- topicGenerator.build(context, topics, outputDir, { provider })
2830
+ functionGenerator.build(context, functions, outputDir, options),
2831
+ cronGenerator.build(context, crons, outputDir, options),
2832
+ subscriberGenerator.build(context, subscribers, outputDir, options),
2833
+ queueGenerator.build(context, queues, outputDir, options),
2834
+ topicGenerator.build(context, topics, outputDir, options)
3057
2835
  ]);
3058
- logger$8.log(`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers, ${queueInfos.length} queues, ${topicInfos.length} topics for ${provider}`);
3059
- const manifestRoutes = assembleManifestField(routes, endpoints);
3060
- const manifestFunctions = assembleManifestField(functionInfos, functions);
3061
- const manifestCrons = assembleManifestField(cronInfos, crons);
3062
- const manifestQueues = assembleManifestField(queueInfos, queues);
3063
- const manifestTopics = assembleManifestField(topicInfos, topics);
3064
- const manifestSubscribers = assembleManifestField(subscriberInfos, subscribers);
3065
- if (provider === "server") {
3066
- const serverRouteField = assembleManifestField(await Promise.all(endpoints.map(async ({ construct }) => ({
3067
- path: construct._path,
3068
- method: construct.method,
3069
- handler: "",
3070
- authorizer: construct.authorizer?.name ?? "none"
3071
- }))), endpoints);
3072
- await generateServerManifest(rootOutputDir, {
3073
- handler: (0, node_path.relative)(appRoot, (0, node_path.join)(outputDir, "app.ts")),
3074
- endpoints: (0, node_path.relative)(appRoot, (0, node_path.join)(outputDir, "endpoints.ts"))
3075
- }, serverRouteField, manifestSubscribers, manifestQueues, manifestTopics);
2836
+ logger$8.log(`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers, ${queueInfos.length} queues, ${topicInfos.length} topics for ${target}`);
2837
+ const fields = {
2838
+ ...context.surface ? { surface: context.surface.id } : {},
2839
+ functions: functionInfos,
2840
+ crons: cronInfos,
2841
+ queues: queueInfos,
2842
+ subscribers: subscriberInfos
2843
+ };
2844
+ if (target === "server") {
2845
+ const handler = (0, node_path.relative)(workspaceRoot, (0, node_path.join)(outputDir, "app.ts"));
2846
+ const built = {
2847
+ ...fields,
2848
+ routes: await Promise.all(endpoints.map(async ({ construct }) => ({
2849
+ path: construct._path,
2850
+ method: construct.method,
2851
+ handler,
2852
+ environment: await construct.getEnvironment({ markOptional: context.markOptional }),
2853
+ dependencies: construct.constructs,
2854
+ authorizer: construct.authorizer?.name ?? "none"
2855
+ })))
2856
+ };
3076
2857
  let masterKey;
3077
2858
  if (context.production?.bundle && !skipBundle) {
3078
2859
  logger$8.log(`\n📦 Bundling production server...`);
@@ -3099,12 +2880,15 @@ async function buildForProvider(provider, context, appRoot, discovered, endpoint
3099
2880
  logger$8.log(` Deploy with: GKM_MASTER_KEY=${masterKey}`);
3100
2881
  }
3101
2882
  }
3102
- return { masterKey };
3103
- } else await generateAwsManifest(rootOutputDir, manifestRoutes, manifestFunctions, manifestCrons, manifestSubscribers, manifestQueues, manifestTopics, discovered, {
3104
- cache: context.cacheBackend,
3105
- email: context.emailBackend
3106
- });
3107
- return {};
2883
+ return {
2884
+ masterKey,
2885
+ built
2886
+ };
2887
+ }
2888
+ return { built: {
2889
+ ...fields,
2890
+ routes
2891
+ } };
3108
2892
  }
3109
2893
  /**
3110
2894
  * Detect available package manager.
@@ -3126,8 +2910,8 @@ function detectPackageManager$2() {
3126
2910
  *
3127
2911
  * @internal Exported for testing
3128
2912
  */
3129
- function getTurboCommand(pm, filters = []) {
3130
- const filterArgs = (typeof filters === "string" ? [filters] : filters).map((f) => ` --filter=${f}`).join("");
2913
+ function getTurboCommand(pm, filters = [], { only = false } = {}) {
2914
+ const filterArgs = (typeof filters === "string" ? [filters] : filters).map((f) => ` --filter=${f}`).join("") + (only ? " --only" : "");
3131
2915
  switch (pm) {
3132
2916
  case "pnpm": return `pnpm exec turbo run build${filterArgs}`;
3133
2917
  case "yarn": return `yarn turbo run build${filterArgs}`;
@@ -3147,10 +2931,11 @@ function getTurboCommand(pm, filters = []) {
3147
2931
  *
3148
2932
  * @internal Exported for testing
3149
2933
  */
3150
- function turboFilters(workspace) {
2934
+ function turboFilters(workspace, { exclude } = {}) {
3151
2935
  const filters = [];
3152
2936
  const unpackaged = [];
3153
- for (const appName of Object.keys(workspace.apps)) {
2937
+ for (const [appName, app] of Object.entries(workspace.apps)) {
2938
+ if (app.type === exclude) continue;
3154
2939
  const name = appPackageName(workspace, appName);
3155
2940
  if (name) filters.push(name);
3156
2941
  else unpackaged.push(appName);
@@ -3189,31 +2974,59 @@ async function workspaceBuildCommand(workspace, options) {
3189
2974
  if (options.production) logger$8.log(` 🏭 Production mode enabled`);
3190
2975
  const buildOrder = require_workspace.getAppBuildOrder(workspace);
3191
2976
  logger$8.log(` Build order: ${buildOrder.join(" → ")}`);
3192
- const pm = detectPackageManager$2();
3193
- logger$8.log(`\n📦 Using ${pm} with Turbo for parallel builds...\n`);
3194
2977
  try {
3195
- const { filters, unpackaged } = turboFilters(workspace);
3196
- if (unpackaged.length > 0) throw new Error(`No package.json for workspace app(s): ${unpackaged.join(", ")}. Each app needs one — turbo builds packages, and gkm reads the name back to know which app it is building.`);
3197
- const turboCommand = getTurboCommand(pm, filters);
3198
- logger$8.log(`Running: ${turboCommand}`);
3199
- await new Promise((resolve, reject) => {
3200
- const child = (0, node_child_process.spawn)(turboCommand, {
3201
- shell: true,
3202
- cwd: workspace.root,
3203
- stdio: "inherit",
3204
- env: {
3205
- ...process.env,
3206
- NODE_ENV: options.production ? "production" : "development"
3207
- }
3208
- });
3209
- child.on("close", (code) => {
3210
- if (code === 0) resolve();
3211
- else reject(/* @__PURE__ */ new Error(`Turbo build failed with exit code ${code}`));
3212
- });
3213
- child.on("error", (err) => {
3214
- reject(err);
2978
+ const target = options.provider ?? require_workspace$1.providerOf(workspace);
2979
+ const builds = [];
2980
+ for (const appName of buildOrder) {
2981
+ const app = workspace.apps[appName];
2982
+ const config = require_workspace.getAppGkmConfig(workspace, appName);
2983
+ if (!app || app.type !== "backend" || !config) continue;
2984
+ logger$8.log(`\n⚙️ ${appName}`);
2985
+ const output = await buildOneApp({
2986
+ config,
2987
+ options,
2988
+ workspace,
2989
+ appRoot: (0, node_path.join)(workspace.root, app.path),
2990
+ target
3215
2991
  });
2992
+ if (output.built) builds.push(output.built);
2993
+ }
2994
+ await writeManifest({
2995
+ workspaceRoot: workspace.root,
2996
+ target,
2997
+ builds,
2998
+ constructs: await require_discover.discover({
2999
+ patterns: require_workspace.allConstructGlobs(workspace),
3000
+ cwd: workspace.root
3001
+ }),
3002
+ backends: backendsOf(workspace)
3216
3003
  });
3004
+ const { filters, unpackaged } = turboFilters(workspace, { exclude: "backend" });
3005
+ if (unpackaged.length > 0) throw new Error(`No package.json for workspace app(s): ${unpackaged.join(", ")}. Each app needs one — turbo builds packages, and gkm reads the name back to know which app it is building.`);
3006
+ const pm = detectPackageManager$2();
3007
+ const turboCommand = getTurboCommand(pm, filters, { only: true });
3008
+ if (filters.length > 0) {
3009
+ logger$8.log(`\n📦 Using ${pm} with Turbo for the other apps...\n`);
3010
+ logger$8.log(`Running: ${turboCommand}`);
3011
+ await new Promise((resolve, reject) => {
3012
+ const child = (0, node_child_process.spawn)(turboCommand, {
3013
+ shell: true,
3014
+ cwd: workspace.root,
3015
+ stdio: "inherit",
3016
+ env: {
3017
+ ...process.env,
3018
+ NODE_ENV: options.production ? "production" : "development"
3019
+ }
3020
+ });
3021
+ child.on("close", (code) => {
3022
+ if (code === 0) resolve();
3023
+ else reject(/* @__PURE__ */ new Error(`Turbo build failed with exit code ${code}`));
3024
+ });
3025
+ child.on("error", (err) => {
3026
+ reject(err);
3027
+ });
3028
+ });
3029
+ }
3217
3030
  for (const [appName, app] of apps) {
3218
3031
  const outputPath = getAppOutputPath(workspace, appName, app);
3219
3032
  results.push({
@@ -3256,23 +3069,11 @@ function getAppOutputPath(workspace, _appName, app) {
3256
3069
  }
3257
3070
  return (0, node_path.join)(appPath, ".gkm");
3258
3071
  }
3259
- /**
3260
- * Format routes for logging, handling PartitionedRoutes.
3261
- */
3072
+ /** Format routes for logging. */
3262
3073
  function formatRoutes(routes) {
3263
- if (require_discover.isPartitionedRoutes(routes)) return `${Array.isArray(routes.paths) ? routes.paths.join(", ") : routes.paths} (partitioned)`;
3264
3074
  return Array.isArray(routes) ? routes.join(", ") : routes;
3265
3075
  }
3266
3076
  /**
3267
- * Assemble a ManifestField from build infos and constructs.
3268
- * If any construct has a partition, returns a Record<string, T[]>.
3269
- * Otherwise, returns a flat T[].
3270
- */
3271
- function assembleManifestField(infos, constructs) {
3272
- if (!hasPartitions(constructs)) return infos;
3273
- return groupInfosByPartition(infos, constructs);
3274
- }
3275
- /**
3276
3077
  * Format a fatal error for display.
3277
3078
  * Always includes the full stack trace since these are process-ending errors.
3278
3079
  */
@@ -5424,9 +5225,8 @@ async function dockerCommand(options) {
5424
5225
  logger$6.log("📦 Detected workspace configuration");
5425
5226
  return workspaceDockerCommand(loadedConfig.workspace);
5426
5227
  }
5427
- const config = await require_config.loadConfig();
5428
- const dockerConfig = resolveDockerConfig(config);
5429
- const healthCheckPath = (typeof config.providers?.server === "object" ? config.providers.server : void 0)?.production?.healthCheck ?? "/health";
5228
+ const dockerConfig = resolveDockerConfig(await require_config.loadConfig());
5229
+ const healthCheckPath = "/health";
5430
5230
  const useSlim = options.slim === true;
5431
5231
  if (useSlim) {
5432
5232
  const distDir = (0, node_path.join)(process.cwd(), ".gkm", "server", "dist");
@@ -7432,6 +7232,10 @@ async function workspaceDeployCommand(configured, options) {
7432
7232
  } else logger$4.log(` Deploying all apps: ${appsToDeployNames.join(", ")}`);
7433
7233
  const dokployApps = appsToDeployNames.filter((name) => {
7434
7234
  const target = workspace.apps[name].resolvedDeployTarget;
7235
+ if (target === "sst") {
7236
+ logger$4.log(` ⚠️ Skipping ${name}: it deploys with SST — run \`gkm build && sst deploy --stage ${stage}\``);
7237
+ return false;
7238
+ }
7435
7239
  if (!require_workspace.isDeployTargetSupported(target)) {
7436
7240
  logger$4.log(` ⚠️ Skipping ${name}: ${require_workspace.getDeployTargetError(target, name)}`);
7437
7241
  return false;
@@ -7952,66 +7756,6 @@ async function createApi(endpoint) {
7952
7756
  });
7953
7757
  }
7954
7758
  /**
7955
- * Update gkm.config.ts with Dokploy configuration
7956
- */
7957
- /**
7958
- * Whether the file's `dokploy` block is more than a flat literal.
7959
- *
7960
- * A spread, a `process.env`, a ternary or a nested object all defeat the
7961
- * single-level regex below — the first two by being expressions it would
7962
- * stringify away, the last by ending the match at the wrong brace.
7963
- */
7964
- function unsafeToRewrite(content) {
7965
- const start = content.indexOf("dokploy:");
7966
- if (start === -1) return false;
7967
- const block = content.slice(start, content.indexOf("\n },", start) + 1);
7968
- return /\.\.\.|process\.env|\?\s|`|\{[^}]*\{/s.test(block);
7969
- }
7970
- async function updateConfig(config, cwd = process.cwd()) {
7971
- const configPath = (0, node_path.join)(cwd, "gkm.config.ts");
7972
- if (!(0, node_fs.existsSync)(configPath)) {
7973
- logger$3.warn("\n gkm.config.ts not found. Add this configuration manually:\n");
7974
- logger$3.log(` providers: {`);
7975
- logger$3.log(` dokploy: {`);
7976
- logger$3.log(` endpoint: '${config.endpoint}',`);
7977
- logger$3.log(` projectId: '${config.projectId}',`);
7978
- logger$3.log(` applicationId: '${config.applicationId}',`);
7979
- logger$3.log(` },`);
7980
- logger$3.log(` },`);
7981
- return;
7982
- }
7983
- const content = await (0, node_fs_promises.readFile)(configPath, "utf-8");
7984
- if (unsafeToRewrite(content)) {
7985
- logger$3.warn("\n gkm.config.ts holds a dokploy block this cannot safely rewrite —\n it contains an expression or a nested object. Leaving it alone.");
7986
- logger$3.log(`\n Discovered, if you want them written down:`);
7987
- logger$3.log(` projectId: '${config.projectId}'`);
7988
- logger$3.log(` applicationId: '${config.applicationId}'`);
7989
- if (config.registryId) logger$3.log(` registryId: '${config.registryId}'`);
7990
- return;
7991
- }
7992
- if (content.includes("dokploy:") && content.includes("applicationId:")) {
7993
- logger$3.log("\n Dokploy config already exists in gkm.config.ts");
7994
- logger$3.log(" Updating with new values...");
7995
- }
7996
- const registryLine = config.registryId ? `\n\t\t\tregistryId: '${config.registryId}',` : "";
7997
- const dokployConfigStr = `dokploy: {
7998
- endpoint: '${config.endpoint}',
7999
- projectId: '${config.projectId}',
8000
- applicationId: '${config.applicationId}',${registryLine}
8001
- }`;
8002
- let newContent;
8003
- if (content.includes("providers:")) {
8004
- if (content.includes("dokploy:")) newContent = content.replace(/dokploy:\s*\{[^}]*\}/s, dokployConfigStr);
8005
- else newContent = content.replace(/providers:\s*\{/, `providers: {\n\t\t${dokployConfigStr},`);
8006
- } else newContent = content.replace(/}\s*\)\s*;?\s*$/, `
8007
- providers: {
8008
- ${dokployConfigStr},
8009
- },
8010
- });`);
8011
- await (0, node_fs_promises.writeFile)(configPath, newContent);
8012
- logger$3.log("\n ✓ Updated gkm.config.ts with Dokploy configuration");
8013
- }
8014
- /**
8015
7759
  * Initialize Dokploy deployment configuration
8016
7760
  */
8017
7761
  async function deployInitCommand(options) {
@@ -8064,7 +7808,6 @@ async function deployInitCommand(options) {
8064
7808
  projectId,
8065
7809
  applicationId: application.applicationId
8066
7810
  };
8067
- await updateConfig(config);
8068
7811
  logger$3.log(`\n✅ Dokploy deployment initialized!`);
8069
7812
  logger$3.log(`\n📋 Configuration:`);
8070
7813
  logger$3.log(` Project ID: ${projectId}`);
@@ -9334,26 +9077,26 @@ function loadPackageJson() {
9334
9077
  * Run: pnpm --filter @geekmidas/cli sync-versions
9335
9078
  */
9336
9079
  const GEEKMIDAS_VERSIONS = {
9337
- "@geekmidas/audit": "~10.0.0-alpha.44",
9338
- "@geekmidas/auth": "~10.0.0-alpha.44",
9339
- "@geekmidas/cache": "~10.0.0-alpha.44",
9340
- "@geekmidas/client": "~10.0.0-alpha.44",
9341
- "@geekmidas/cloud": "~10.0.0-alpha.44",
9342
- "@geekmidas/constructs": "~10.0.0-alpha.44",
9343
- "@geekmidas/db": "~10.0.0-alpha.44",
9344
- "@geekmidas/emailkit": "~10.0.0-alpha.44",
9345
- "@geekmidas/envkit": "~10.0.0-alpha.44",
9346
- "@geekmidas/errors": "~10.0.0-alpha.44",
9347
- "@geekmidas/events": "~10.0.0-alpha.44",
9348
- "@geekmidas/logger": "~10.0.0-alpha.44",
9349
- "@geekmidas/manifest": "~10.0.0-alpha.44",
9350
- "@geekmidas/rate-limit": "~10.0.0-alpha.44",
9351
- "@geekmidas/schema": "~10.0.0-alpha.44",
9352
- "@geekmidas/services": "~10.0.0-alpha.44",
9353
- "@geekmidas/storage": "~10.0.0-alpha.44",
9354
- "@geekmidas/studio": "~10.0.0-alpha.44",
9355
- "@geekmidas/telescope": "~10.0.0-alpha.44",
9356
- "@geekmidas/testkit": "~10.0.0-alpha.44",
9080
+ "@geekmidas/audit": "~10.0.0-alpha.46",
9081
+ "@geekmidas/auth": "~10.0.0-alpha.46",
9082
+ "@geekmidas/cache": "~10.0.0-alpha.46",
9083
+ "@geekmidas/client": "~10.0.0-alpha.46",
9084
+ "@geekmidas/cloud": "~10.0.0-alpha.46",
9085
+ "@geekmidas/constructs": "~10.0.0-alpha.46",
9086
+ "@geekmidas/db": "~10.0.0-alpha.46",
9087
+ "@geekmidas/emailkit": "~10.0.0-alpha.46",
9088
+ "@geekmidas/envkit": "~10.0.0-alpha.46",
9089
+ "@geekmidas/errors": "~10.0.0-alpha.46",
9090
+ "@geekmidas/events": "~10.0.0-alpha.46",
9091
+ "@geekmidas/logger": "~10.0.0-alpha.46",
9092
+ "@geekmidas/manifest": "~10.0.0-alpha.46",
9093
+ "@geekmidas/rate-limit": "~10.0.0-alpha.46",
9094
+ "@geekmidas/schema": "~10.0.0-alpha.46",
9095
+ "@geekmidas/services": "~10.0.0-alpha.46",
9096
+ "@geekmidas/storage": "~10.0.0-alpha.46",
9097
+ "@geekmidas/studio": "~10.0.0-alpha.46",
9098
+ "@geekmidas/telescope": "~10.0.0-alpha.46",
9099
+ "@geekmidas/testkit": "~10.0.0-alpha.46",
9357
9100
  "@geekmidas/cli": `~${loadPackageJson().version}`
9358
9101
  };
9359
9102
  //#endregion
@@ -10880,7 +10623,7 @@ function deployPackage(options) {
10880
10623
  case "sst": {
10881
10624
  const v = GEEKMIDAS_VERSIONS;
10882
10625
  return {
10883
- scripts: perStage(options, (stage) => `gkm build --provider aws && sst deploy --stage ${stage}`),
10626
+ scripts: perStage(options, (stage) => `gkm build && sst deploy --stage ${stage}`),
10884
10627
  dependencies: {
10885
10628
  "@geekmidas/cloud": v["@geekmidas/cloud"],
10886
10629
  "@geekmidas/db": v["@geekmidas/db"],
@@ -10945,7 +10688,7 @@ export default $config({
10945
10688
 
10946
10689
  async run() {
10947
10690
  const { App, fromManifest, Stack } = await import('@geekmidas/cloud/sst');
10948
- // Written by \`gkm build --provider aws\`. Imported rather than discovered,
10691
+ // Written by \`gkm build\`. Imported rather than discovered,
10949
10692
  // so SST's toolchain never evaluates the application's own modules.
10950
10693
  const { backends, constructs } = await import('./.gkm/manifest/aws.js');
10951
10694
 
@@ -11183,8 +10926,11 @@ coverage/
11183
10926
  ${isSst ? "\n# SST\n.sst/\n" : ""}`;
11184
10927
  const tsConfig = {
11185
10928
  compilerOptions: {
10929
+ paths: {
10930
+ ...isFullstack ? { [`@${options.name}/constructs/*`]: ["./constructs/*"] } : {},
10931
+ [`@${options.name}/manifest`]: [`./.gkm/manifest/${isSst ? "aws" : "server"}.ts`]
10932
+ },
11186
10933
  ...isFullstack ? {
11187
- paths: { [`@${options.name}/constructs/*`]: ["./constructs/*"] },
11188
10934
  allowImportingTsExtensions: true,
11189
10935
  noEmit: true
11190
10936
  } : {},
@@ -11325,7 +11071,7 @@ export default defineWorkspace({
11325
11071
  // \`production-${options.name}-database\` on Dokploy and on AWS alike.
11326
11072
  name: '${options.name}',
11327
11073
  ${stagesBlock(options.stages)}
11328
-
11074
+ ${deployBlock(options)}
11329
11075
  // Every kind, in every app. A declared database is why a Postgres exists, a
11330
11076
  // declared bucket is why MinIO does, a declared topic is why a broker does —
11331
11077
  // none of it listed here. It is also where the apps come from: a
@@ -11343,6 +11089,18 @@ ${workspaceConstructsGlobs(options.routesStructure, (0, node_path.dirname)(optio
11343
11089
  `;
11344
11090
  }
11345
11091
  /**
11092
+ * Where it deploys, when that is not the default Dokploy: what a bare
11093
+ * `gkm build` builds for, and which backends a cache or a broker resolves to.
11094
+ */
11095
+ function deployBlock(options) {
11096
+ if (options.deployTarget !== "sst") return "";
11097
+ return `
11098
+ // Deployed with \`sst deploy\`, from the manifest \`gkm build\` writes to
11099
+ // \`.gkm/manifest/aws.ts\`. Each construct becomes a managed AWS resource.
11100
+ deploy: { default: 'sst' },
11101
+ `;
11102
+ }
11103
+ /**
11346
11104
  * Where a deployed stage's secrets live. On AWS that is SSM in the stage's own
11347
11105
  * account, which the deploy job reaches with the role it already assumed; a
11348
11106
  * server target keeps the encrypted local file, the default.
@@ -11368,7 +11126,7 @@ function secretsStore(options) {
11368
11126
  */
11369
11127
  function generateRootConstructs(options) {
11370
11128
  if (!options.monorepo || options.template !== "fullstack") return [];
11371
- const { name, frontendFramework } = options;
11129
+ const { frontendFramework } = options;
11372
11130
  const { cache, uploads, mail } = options.constructs;
11373
11131
  const db = databaseFor();
11374
11132
  const files = [];
@@ -12128,7 +11886,7 @@ const serverlessTemplate = {
12128
11886
  },
12129
11887
  scripts: {
12130
11888
  dev: "gkm dev",
12131
- build: "gkm build --provider aws-apigatewayv2",
11889
+ build: "gkm build --provider aws",
12132
11890
  test: "vitest",
12133
11891
  "test:once": "vitest run",
12134
11892
  typecheck: "tsc --noEmit",
@@ -12137,7 +11895,7 @@ const serverlessTemplate = {
12137
11895
  "fmt:check": "biome format ."
12138
11896
  },
12139
11897
  files: (options) => {
12140
- const { loggerType, routesStructure, name } = options;
11898
+ const { loggerType, routesStructure } = options;
12141
11899
  const loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';
12142
11900
 
12143
11901
  export const logger = createLogger();
@@ -12422,10 +12180,6 @@ export const telescope = new Telescope({
12422
12180
  */
12423
12181
  const OPENAPI_OUTPUT_PATH = "./.gkm/openapi/api.ts";
12424
12182
  /**
12425
- * Endpoints output path (generated by gkm dev/build)
12426
- */
12427
- const ENDPOINTS_OUTPUT_PATH = "./.gkm/server/endpoints.ts";
12428
- /**
12429
12183
  * All available templates
12430
12184
  */
12431
12185
  const templates = {
@@ -12638,10 +12392,7 @@ function generatePackageJson(options, template) {
12638
12392
  private: true,
12639
12393
  type: "module",
12640
12394
  ...!monorepo && options.packageManager === "pnpm" ? { packageManager: PNPM_VERSION } : {},
12641
- exports: {
12642
- "./client": OPENAPI_OUTPUT_PATH,
12643
- "./endpoints": ENDPOINTS_OUTPUT_PATH
12644
- },
12395
+ exports: { "./client": OPENAPI_OUTPUT_PATH },
12645
12396
  scripts,
12646
12397
  dependencies: sortObject(dependencies),
12647
12398
  devDependencies: sortObject(devDependencies)
@@ -15367,7 +15118,7 @@ function printNextSteps(projectName, options, pkgManager) {
15367
15118
  }
15368
15119
  if (options.deployTarget === "sst") {
15369
15120
  console.log("🚀 Deployment (AWS, through SST):");
15370
- for (const stage of deployed) console.log(` ${getRunCommand(pkgManager, `deploy:${stage}`)} # gkm build --provider aws, then sst deploy`);
15121
+ for (const stage of deployed) console.log(` ${getRunCommand(pkgManager, `deploy:${stage}`)} # gkm build, then sst deploy`);
15371
15122
  console.log(` Uses your AWS credentials, in ${options.region}.`);
15372
15123
  if (options.constructs.mail) console.log(" Set MAIL_FROM to a sender verified in SES first.");
15373
15124
  console.log("");
@@ -16102,8 +15853,8 @@ function testDatabases(reconciled) {
16102
15853
  * starts without the reference data the app needs.
16103
15854
  */
16104
15855
  async function migrateTestStage(workspace, env) {
16105
- const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-PJi4b1ga.cjs"));
16106
- const { discover } = await Promise.resolve().then(() => require("./discover-B0f_kuNN.cjs")).then((n) => n.discover_exports);
15856
+ const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-Dp5HFzuQ.cjs"));
15857
+ const { discover } = await Promise.resolve().then(() => require("./discover-DXNviAh-.cjs")).then((n) => n.discover_exports);
16107
15858
  const sources = {};
16108
15859
  const manifest = await discover({
16109
15860
  patterns: require_workspace$1.constructGlobs(workspace),
@@ -16468,29 +16219,13 @@ program.command("setup").description("Reconcile declared constructs — containe
16468
16219
  process.exit(1);
16469
16220
  }
16470
16221
  });
16471
- program.command("build").description("Build handlers and the manifest from declared constructs").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) => {
16222
+ program.command("build").description("Build handlers and the manifest from declared constructs").option("--provider <provider>", "Build for aws or server (default: where gkm.config.ts deploys)").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) => {
16472
16223
  try {
16473
16224
  const globalOptions = program.opts();
16474
16225
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16475
- if (options.provider) {
16476
- if (!["aws", "server"].includes(options.provider)) process.exit(1);
16477
- await buildCommand({
16478
- provider: options.provider,
16479
- enableOpenApi: options.enableOpenapi || false,
16480
- production: options.production || false,
16481
- skipBundle: options.skipBundle || false,
16482
- stage: options.stage,
16483
- markOptional: options.markOptional || false
16484
- });
16485
- } else if (options.providers) await buildCommand({
16486
- providers: [...new Set(options.providers.split(",").map((p) => p.trim()))],
16487
- enableOpenApi: options.enableOpenapi || false,
16488
- production: options.production || false,
16489
- skipBundle: options.skipBundle || false,
16490
- stage: options.stage,
16491
- markOptional: options.markOptional || false
16492
- });
16493
- else await buildCommand({
16226
+ if (options.provider !== void 0 && !isMainProvider(options.provider)) throw new UnknownBuildProvider(options.provider);
16227
+ await buildCommand({
16228
+ ...options.provider ? { provider: options.provider } : {},
16494
16229
  enableOpenApi: options.enableOpenapi || false,
16495
16230
  production: options.production || false,
16496
16231
  skipBundle: options.skipBundle || false,
@@ -16549,7 +16284,7 @@ program.command("migrate").description("Apply each database construct's migratio
16549
16284
  try {
16550
16285
  const globalOptions = program.opts();
16551
16286
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16552
- const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-PJi4b1ga.cjs"));
16287
+ const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-Dp5HFzuQ.cjs"));
16553
16288
  await migrateCommand({
16554
16289
  ...options,
16555
16290
  ...construct ? { construct } : {}
@@ -16563,7 +16298,7 @@ program.command("seed").description("Migrate, then run each database construct's
16563
16298
  try {
16564
16299
  const globalOptions = program.opts();
16565
16300
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16566
- const { seedCommand } = await Promise.resolve().then(() => require("./migrate-PJi4b1ga.cjs"));
16301
+ const { seedCommand } = await Promise.resolve().then(() => require("./migrate-Dp5HFzuQ.cjs"));
16567
16302
  await seedCommand({
16568
16303
  ...options,
16569
16304
  ...construct ? { construct } : {}
@@ -16577,7 +16312,7 @@ program.command("migration").description("Write a construct's next migration: an
16577
16312
  try {
16578
16313
  const globalOptions = program.opts();
16579
16314
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16580
- const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-PJi4b1ga.cjs"));
16315
+ const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-Dp5HFzuQ.cjs"));
16581
16316
  await migrationCommand({
16582
16317
  construct,
16583
16318
  ...name ? { name } : {}
@@ -16716,7 +16451,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
16716
16451
  console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
16717
16452
  process.exit(1);
16718
16453
  }
16719
- const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-dV6f-3vv.cjs")).then((n) => n.workspace_exports);
16454
+ const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-D9z2ymBW.cjs")).then((n) => n.workspace_exports);
16720
16455
  const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
16721
16456
  if (!result) {
16722
16457
  console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);
@@ -16775,7 +16510,7 @@ program.command("deploy:github").description("Let GitHub Actions deploy a stage:
16775
16510
  try {
16776
16511
  const globalOptions = program.opts();
16777
16512
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16778
- const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-BAr8WGkR.cjs"));
16513
+ const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-BrI1tv6u.cjs"));
16779
16514
  await deployGithubCommand(options);
16780
16515
  } catch (error) {
16781
16516
  console.error(formatError(error));