@geekmidas/cli 10.0.0-alpha.37 → 10.0.0-alpha.39

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 (114) hide show
  1. package/README.md +27 -26
  2. package/dist/{HostingerProvider-GF6NAZAK.mjs → HostingerProvider-Bh6K7QYz.mjs} +2 -2
  3. package/dist/{HostingerProvider-GF6NAZAK.mjs.map → HostingerProvider-Bh6K7QYz.mjs.map} +1 -1
  4. package/dist/{OpenApiTsGenerator-D1nhN98m.cjs → OpenApiTsGenerator-CeEI4ll9.cjs} +3 -3
  5. package/dist/OpenApiTsGenerator-CeEI4ll9.cjs.map +1 -0
  6. package/dist/{OpenApiTsGenerator-hDINScnz.mjs → OpenApiTsGenerator-DQqOuSW8.mjs} +3 -3
  7. package/dist/OpenApiTsGenerator-DQqOuSW8.mjs.map +1 -0
  8. package/dist/{ssm-FxeSAt35.cjs → aws-DkHdTV-p.cjs} +7 -6
  9. package/dist/aws-DkHdTV-p.cjs.map +1 -0
  10. package/dist/{ssm-BKN1Cg4z.mjs → aws-DojzQnLd.mjs} +7 -6
  11. package/dist/aws-DojzQnLd.mjs.map +1 -0
  12. package/dist/{bundler-D9IPNvDt.mjs → bundler--fyybf1N.mjs} +13 -7
  13. package/dist/bundler--fyybf1N.mjs.map +1 -0
  14. package/dist/{bundler-CYF5mWi9.cjs → bundler-By6_sXiL.cjs} +12 -6
  15. package/dist/bundler-By6_sXiL.cjs.map +1 -0
  16. package/dist/{config-Dss1WwtH.mjs → config-5watB1D0.mjs} +95 -71
  17. package/dist/config-5watB1D0.mjs.map +1 -0
  18. package/dist/{config-DgAHy8nY.cjs → config-CJ-PAb7M.cjs} +116 -74
  19. package/dist/config-CJ-PAb7M.cjs.map +1 -0
  20. package/dist/config.cjs +6 -3
  21. package/dist/config.d.cts +40 -19
  22. package/dist/config.d.cts.map +1 -1
  23. package/dist/config.d.mts +40 -19
  24. package/dist/config.d.mts.map +1 -1
  25. package/dist/config.mjs +3 -3
  26. package/dist/{discover-CroTIm0K.cjs → discover-B0f_kuNN.cjs} +2 -1
  27. package/dist/{discover-CroTIm0K.cjs.map → discover-B0f_kuNN.cjs.map} +1 -1
  28. package/dist/{discover-CMxesskG.mjs → discover-BLhf7V_J.mjs} +2 -1
  29. package/dist/{discover-CMxesskG.mjs.map → discover-BLhf7V_J.mjs.map} +1 -1
  30. package/dist/{github-tZmMZ7td.cjs → github-BAr8WGkR.cjs} +10 -13
  31. package/dist/github-BAr8WGkR.cjs.map +1 -0
  32. package/dist/{github-C99BMxf0.mjs → github-D5MthUlR.mjs} +8 -11
  33. package/dist/github-D5MthUlR.mjs.map +1 -0
  34. package/dist/{index-CAp22ul5.d.cts → index-CLH1DgsO.d.cts} +2 -2
  35. package/dist/{index-CAp22ul5.d.cts.map → index-CLH1DgsO.d.cts.map} +1 -1
  36. package/dist/{index-DxXMtQNT.d.mts → index-CST2jOPH.d.mts} +2 -2
  37. package/dist/{index-DxXMtQNT.d.mts.map → index-CST2jOPH.d.mts.map} +1 -1
  38. package/dist/index.cjs +1015 -353
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.mjs +1003 -341
  41. package/dist/index.mjs.map +1 -1
  42. package/dist/{migrate-_2J3lFT5.mjs → migrate-BJR912RE.mjs} +9 -7
  43. package/dist/migrate-BJR912RE.mjs.map +1 -0
  44. package/dist/{migrate-Cgga-OGi.cjs → migrate-Bu8POqsR.cjs} +8 -6
  45. package/dist/migrate-Bu8POqsR.cjs.map +1 -0
  46. package/dist/openapi.cjs +2 -2
  47. package/dist/openapi.d.cts +1 -1
  48. package/dist/openapi.d.mts +1 -1
  49. package/dist/openapi.mjs +2 -2
  50. package/dist/{ready-CXhoutix.cjs → ready-B0WVtkjR.cjs} +96 -6
  51. package/dist/ready-B0WVtkjR.cjs.map +1 -0
  52. package/dist/{ready-D1BCiaYU.mjs → ready-BXmLS4VB.mjs} +92 -8
  53. package/dist/ready-BXmLS4VB.mjs.map +1 -0
  54. package/dist/reconcile/public.cjs +1 -1
  55. package/dist/reconcile/public.d.cts +1 -1
  56. package/dist/reconcile/public.d.mts +1 -1
  57. package/dist/reconcile/public.mjs +1 -1
  58. package/dist/reconcile--I7V4Klj.mjs +34 -0
  59. package/dist/reconcile--I7V4Klj.mjs.map +1 -0
  60. package/dist/reconcile-CuCQBa5-.cjs +34 -0
  61. package/dist/reconcile-CuCQBa5-.cjs.map +1 -0
  62. package/dist/storage-BzaUxmqe.mjs +124 -0
  63. package/dist/storage-BzaUxmqe.mjs.map +1 -0
  64. package/dist/storage-CSGoC3bK.cjs +152 -0
  65. package/dist/storage-CSGoC3bK.cjs.map +1 -0
  66. package/dist/store-DQgxT_WR.cjs +211 -0
  67. package/dist/store-DQgxT_WR.cjs.map +1 -0
  68. package/dist/store-DeGATCS-.mjs +182 -0
  69. package/dist/store-DeGATCS-.mjs.map +1 -0
  70. package/dist/{types-BTiu5kwo.d.mts → types-B0EVAF6U.d.mts} +24 -10
  71. package/dist/types-B0EVAF6U.d.mts.map +1 -0
  72. package/dist/{types-Bj_FpeTc.d.cts → types-CHKCUKM0.d.cts} +24 -10
  73. package/dist/types-CHKCUKM0.d.cts.map +1 -0
  74. package/dist/vitest.cjs +1 -1
  75. package/dist/vitest.mjs +1 -1
  76. package/dist/workspace/index.cjs +1 -1
  77. package/dist/workspace/index.d.cts +2 -2
  78. package/dist/workspace/index.d.mts +2 -2
  79. package/dist/workspace/index.mjs +1 -1
  80. package/dist/{workspace-BtXCL1C8.mjs → workspace-CrFbItPz.mjs} +111 -39
  81. package/dist/workspace-CrFbItPz.mjs.map +1 -0
  82. package/dist/{workspace-CsL76tpc.mjs → workspace-DOmIhiau.mjs} +2 -2
  83. package/dist/{workspace-CsL76tpc.mjs.map → workspace-DOmIhiau.mjs.map} +1 -1
  84. package/dist/{workspace-DUhLejv4.cjs → workspace-DZ1G4zow.cjs} +121 -37
  85. package/dist/workspace-DZ1G4zow.cjs.map +1 -0
  86. package/dist/{workspace-CAJk6UmC.cjs → workspace-RYSYtHP7.cjs} +2 -2
  87. package/dist/{workspace-CAJk6UmC.cjs.map → workspace-RYSYtHP7.cjs.map} +1 -1
  88. package/package.json +14 -14
  89. package/dist/OpenApiTsGenerator-D1nhN98m.cjs.map +0 -1
  90. package/dist/OpenApiTsGenerator-hDINScnz.mjs.map +0 -1
  91. package/dist/bundler-CYF5mWi9.cjs.map +0 -1
  92. package/dist/bundler-D9IPNvDt.mjs.map +0 -1
  93. package/dist/config-DgAHy8nY.cjs.map +0 -1
  94. package/dist/config-Dss1WwtH.mjs.map +0 -1
  95. package/dist/github-C99BMxf0.mjs.map +0 -1
  96. package/dist/github-tZmMZ7td.cjs.map +0 -1
  97. package/dist/migrate-Cgga-OGi.cjs.map +0 -1
  98. package/dist/migrate-_2J3lFT5.mjs.map +0 -1
  99. package/dist/ready-CXhoutix.cjs.map +0 -1
  100. package/dist/ready-D1BCiaYU.mjs.map +0 -1
  101. package/dist/reconcile-BxZTV2vl.cjs +0 -332
  102. package/dist/reconcile-BxZTV2vl.cjs.map +0 -1
  103. package/dist/reconcile-yNq6Shau.mjs +0 -279
  104. package/dist/reconcile-yNq6Shau.mjs.map +0 -1
  105. package/dist/ssm-BKN1Cg4z.mjs.map +0 -1
  106. package/dist/ssm-FxeSAt35.cjs.map +0 -1
  107. package/dist/storage-BjTLjDDp.mjs +0 -297
  108. package/dist/storage-BjTLjDDp.mjs.map +0 -1
  109. package/dist/storage-C2JC31V9.cjs +0 -344
  110. package/dist/storage-C2JC31V9.cjs.map +0 -1
  111. package/dist/types-BTiu5kwo.d.mts.map +0 -1
  112. package/dist/types-Bj_FpeTc.d.cts.map +0 -1
  113. package/dist/workspace-BtXCL1C8.mjs.map +0 -1
  114. package/dist/workspace-DUhLejv4.cjs.map +0 -1
@@ -1,8 +1,10 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
2
- const require_discover = require("./discover-CroTIm0K.cjs");
3
- const require_config = require("./config-DgAHy8nY.cjs");
4
- const require_workspace = require("./workspace-CAJk6UmC.cjs");
5
- const require_storage = require("./storage-C2JC31V9.cjs");
2
+ const require_discover = require("./discover-B0f_kuNN.cjs");
3
+ const require_config = require("./config-CJ-PAb7M.cjs");
4
+ const require_workspace = require("./workspace-RYSYtHP7.cjs");
5
+ const require_storage = require("./storage-CSGoC3bK.cjs");
6
+ const require_store = require("./store-DQgxT_WR.cjs");
7
+ const require_ready = require("./ready-B0WVtkjR.cjs");
6
8
  let node_fs = require("node:fs");
7
9
  let node_fs_promises = require("node:fs/promises");
8
10
  let node_os = require("node:os");
@@ -101,14 +103,12 @@ async function savePortState(workspaceRoot, ports) {
101
103
  * For workspace app: maps {APP}_DATABASE_URL → DATABASE_URL.
102
104
  * @internal Exported for testing
103
105
  */
104
- async function loadSecretsForApp(secretsRoot, stage, appName) {
106
+ async function loadSecretsForApp(store, stage, appName) {
105
107
  let secrets = {};
106
- if (require_storage.secretsExist(stage, secretsRoot)) {
107
- const stageSecrets = await require_storage.readStageSecrets(stage, secretsRoot);
108
- if (stageSecrets) {
109
- logger.log(`🔐 Loading secrets from stage: ${stage}`);
110
- secrets = require_storage.toEmbeddableSecrets(stageSecrets);
111
- }
108
+ const stageSecrets = await store.read(stage);
109
+ if (stageSecrets) {
110
+ logger.log(`🔐 Loading secrets from stage: ${stage}`);
111
+ secrets = require_storage.toEmbeddableSecrets(stageSecrets);
112
112
  }
113
113
  if (Object.keys(secrets).length === 0) return {};
114
114
  if (!appName) return secrets;
@@ -202,14 +202,15 @@ async function prepareEntryCredentials(options) {
202
202
  workspaceAppPort = appInfo.app.port;
203
203
  secretsRoot = appInfo.workspaceRoot;
204
204
  appName = appInfo.appName;
205
- } catch {
205
+ } catch (error) {
206
+ if (!(error instanceof require_config.NotInAnApp || error instanceof require_config.ConfigNotFound)) throw error;
206
207
  workspace = await require_config.loadWorkspaceConfig(cwd).then((loaded) => loaded.workspace).catch(() => void 0);
207
208
  secretsRoot = workspace?.root ?? findSecretsRoot(cwd);
208
- appName = require_config.getAppNameFromCwd(cwd) ?? void 0;
209
209
  }
210
210
  const resolvedPort = options.explicitPort ?? workspaceAppPort ?? 3e3;
211
211
  const stage = options.stage ?? workspace?.stages.local;
212
- const credentials = stage ? await loadSecretsForApp(secretsRoot, stage, appName) : {};
212
+ const store = stage ? workspace ? await require_store.secretsStoreFor(workspace, stage) : new require_store.FileSecretsStore(secretsRoot) : void 0;
213
+ const credentials = store && stage ? await loadSecretsForApp(store, stage, appName) : {};
213
214
  credentials.PORT = String(resolvedPort);
214
215
  if (appInfo?.app.type === "mobile") credentials.RCT_METRO_PORT = String(resolvedPort);
215
216
  const declaredKeys = [];
@@ -397,8 +398,23 @@ const PORTS = {
397
398
  label: "https edge"
398
399
  }]
399
400
  };
400
- /** The ports a container needs published. Empty for one gkm does not know. */
401
- function portsOf(container) {
401
+ /** The port key — and container name, for an image — of an API's fake. */
402
+ function fakeKey(id) {
403
+ return `${(0, _geekmidas_manifest.kebabCase)(id)}-fake`;
404
+ }
405
+ /**
406
+ * The ports a container needs published. Empty for one gkm does not know.
407
+ *
408
+ * `fakes` answers for the containers no table can: an external API's fake
409
+ * listens wherever its declaration says.
410
+ */
411
+ function portsOf(container, fakes = {}) {
412
+ const fake = fakes[container];
413
+ if (fake?.port !== void 0) return [{
414
+ key: container,
415
+ inside: fake.port,
416
+ label: `${fake.id} fake`
417
+ }];
402
418
  return PORTS[container] ?? [];
403
419
  }
404
420
  /** The key a container's primary port is allocated under. */
@@ -411,8 +427,9 @@ function primaryPortKey(container) {
411
427
  * What allocation is handed: it assigns ports to names and knows nothing about
412
428
  * what listens on them.
413
429
  */
414
- function portKeys(containers) {
415
- return [...containers].sort().flatMap((container) => portsOf(container).map((port) => port.key));
430
+ function portKeys(containers, fakes = {}) {
431
+ const keys = [...containers].sort().flatMap((container) => portsOf(container, fakes).map((port) => port.key));
432
+ return [.../* @__PURE__ */ new Set([...keys, ...Object.keys(fakes).sort()])];
416
433
  }
417
434
  /**
418
435
  * The named volume a container's data lives in.
@@ -694,7 +711,8 @@ const CONTAINERLESS = {
694
711
  credential: true,
695
712
  "rest-api": true,
696
713
  site: true,
697
- "mobile-app": true
714
+ "mobile-app": true,
715
+ "external-api": true
698
716
  };
699
717
  /**
700
718
  * Containers that cannot run alone.
@@ -714,7 +732,7 @@ const REQUIRES = { "redis-http": ["redis"] };
714
732
  const ROLES = {
715
733
  queue: "publisherConnectionString",
716
734
  topic: "publisherConnectionString",
717
- credential: "credential",
735
+ credential: "credentials",
718
736
  "mobile-app": "scheme"
719
737
  };
720
738
  /** The kinds whose container is the events backend's rather than their own. */
@@ -806,12 +824,25 @@ function containerFor(kind, events = DEFAULT_EVENTS, cache = require_discover.DE
806
824
  function planFor(manifest, stage, order, options = {}) {
807
825
  const containers = /* @__PURE__ */ new Set();
808
826
  const resources = [];
827
+ const fakes = {};
809
828
  const events = options.events ?? "pgboss";
810
829
  const cache = options.cache ?? require_discover.DEFAULT_CACHE.aws;
811
830
  for (const id of order) {
812
831
  const declaration = manifest[id];
813
832
  if (!declaration) continue;
814
- const container = containerFor(declaration.kind, events, cache, "of" in declaration && typeof declaration.of === "string", options.edge !== false);
833
+ const local = declaration.kind === "external-api" ? options.fakes?.[id] : void 0;
834
+ const fake = local && {
835
+ key: fakeKey(id),
836
+ ...local
837
+ };
838
+ if (fake) fakes[fake.key] = {
839
+ id,
840
+ ...fake.image ? {
841
+ image: fake.image,
842
+ port: fake.port
843
+ } : {}
844
+ };
845
+ const container = fake?.image ? fake.key : containerFor(declaration.kind, events, cache, "of" in declaration && typeof declaration.of === "string", options.edge !== false);
815
846
  if (!container && !CONTAINERLESS[declaration.kind]) continue;
816
847
  if (container) {
817
848
  containers.add(container);
@@ -831,6 +862,11 @@ function planFor(manifest, stage, order, options = {}) {
831
862
  ...declaration.scheme ? { scheme: declaration.scheme } : {}
832
863
  } : {},
833
864
  ...declaration.kind === "file-server" && declaration.open?.length ? { open: declaration.open } : {},
865
+ ...fake ? { fake: {
866
+ key: fake.key,
867
+ credentials: fake.credentials
868
+ } } : {},
869
+ ...declaration.kind === "external-api" && !fake ? { url: declaration.url } : {},
834
870
  ..."of" in declaration ? { of: declaration.of } : {},
835
871
  ..."schema" in declaration && declaration.schema ? { schema: declaration.schema } : {},
836
872
  ..."version" in declaration && declaration.version ? { version: declaration.version } : {},
@@ -867,6 +903,7 @@ function planFor(manifest, stage, order, options = {}) {
867
903
  cache,
868
904
  containers: [...containers],
869
905
  resources,
906
+ ...Object.keys(fakes).length ? { fakes } : {},
870
907
  ...workerBroker ? { workerBroker: true } : {}
871
908
  };
872
909
  }
@@ -990,6 +1027,7 @@ function envFor(plan, options) {
990
1027
  const owner = ownerUrl(resource, plan, options.ports, options.project ?? "");
991
1028
  if (owner) env[(0, _geekmidas_manifest.provideKey)(resource.id, "ownerUrl")] = owner;
992
1029
  }
1030
+ if (resource.kind === "external-api" && url && resource.fake) env[(0, _geekmidas_manifest.provideKey)(resource.id, "credentials")] = resource.fake.credentials;
993
1031
  if (resource.kind === "email" && url) {
994
1032
  env[(0, _geekmidas_manifest.provideKey)(resource.id, "from")] = options.mailFrom ?? `noreply@${LOCAL_HOST}`;
995
1033
  const inbox = options.ports[MAILPIT_INBOX_PORT];
@@ -1139,6 +1177,14 @@ function urlFor(resource, plan, ports, project, addresses = {}) {
1139
1177
  if (resource.kind === "secret") return localSecret(project, plan, resource);
1140
1178
  if (resource.kind === "mobile-app") return (0, _geekmidas_manifest.schemeBase)(project, resource.scheme);
1141
1179
  if (resource.kind === "credential") return void 0;
1180
+ if (resource.kind === "external-api") {
1181
+ if (!resource.fake) return resource.url === void 0 ? void 0 : (0, _geekmidas_manifest.externalApiUrl)({
1182
+ id: resource.id,
1183
+ url: resource.url
1184
+ }, plan.stage);
1185
+ const port = ports[resource.fake.key];
1186
+ return port === void 0 ? void 0 : `http://${LOCAL_HOST}:${port}`;
1187
+ }
1142
1188
  if (resource.kind === "rest-api" || resource.kind === "site") {
1143
1189
  const address = addresses[resource.id];
1144
1190
  const edge = plan.containers.includes("caddy") ? ports[primaryPortKey("caddy")] : void 0;
@@ -1339,20 +1385,21 @@ function dockerfileOf(appName, path) {
1339
1385
  * two containers listening on the same port inside cannot be confused — and is
1340
1386
  * rewritten to `<container>:<inside>`.
1341
1387
  */
1342
- function inNetworkEnv(workspace, manifest) {
1388
+ function inNetworkEnv(workspace, manifest, fakes = {}) {
1343
1389
  const plan = planFor(manifest, workspace.stages.local, (0, _geekmidas_manifest.provisionOrder)(manifest), {
1344
1390
  localStage: workspace.stages.local,
1345
- ...backendsOf(workspace)
1391
+ ...backendsOf(workspace),
1392
+ fakes
1346
1393
  });
1347
1394
  const placeholders = {};
1348
1395
  const targets = /* @__PURE__ */ new Map();
1349
1396
  let next = 49152;
1350
- for (const container of [...plan.containers].sort()) for (const port of portsOf(container)) {
1397
+ for (const container of [...plan.containers].sort()) for (const port of portsOf(container, plan.fakes)) {
1351
1398
  placeholders[port.key] = next;
1352
1399
  targets.set(next, `${container}:${port.inside}`);
1353
1400
  next += 1;
1354
1401
  }
1355
- for (const key of portKeys(plan.containers)) placeholders[key] ??= next++;
1402
+ for (const key of portKeys(plan.containers, plan.fakes)) placeholders[key] ??= next++;
1356
1403
  const env = envFor(plan, {
1357
1404
  ports: placeholders,
1358
1405
  project: workspace.name,
@@ -1415,8 +1462,8 @@ function appEnvKeys(manifest, appName, runnables = {}) {
1415
1462
  return keys;
1416
1463
  }
1417
1464
  /** One compose service per app the workspace runs, behind the apps profile. */
1418
- function appServices(workspace, manifest, containers, runnables = {}) {
1419
- const env = inNetworkEnv(workspace, manifest);
1465
+ function appServices(workspace, manifest, containers, runnables = {}, fakes = {}) {
1466
+ const env = inNetworkEnv(workspace, manifest, fakes);
1420
1467
  const services = {};
1421
1468
  for (const [name, app] of Object.entries(workspace.apps)) {
1422
1469
  if (app.type === "mobile" || !app.port) continue;
@@ -1570,9 +1617,15 @@ function composeFor(plan, options) {
1570
1617
  const volumes = {};
1571
1618
  for (const container of [...plan.containers].sort()) {
1572
1619
  const declared = container === "postgres" ? plan.resources.find((r) => r.version)?.version : void 0;
1573
- const image = declared ? postgresImage(declared) : DEFAULT_IMAGES[container];
1620
+ const fake = plan.fakes?.[container];
1621
+ const image = declared ? postgresImage(declared) : fake?.image ?? DEFAULT_IMAGES[container];
1574
1622
  if (!image) throw new UnknownContainer(container);
1575
- services[container] = define(container, image, publish(container, options.ports));
1623
+ const published = publish(container, options.ports, plan.fakes);
1624
+ services[container] = fake ? {
1625
+ image,
1626
+ restart: "unless-stopped",
1627
+ ports: published
1628
+ } : define(container, image, published);
1576
1629
  const volume = volumeOf(container);
1577
1630
  if (volume) volumes[volume] = {};
1578
1631
  }
@@ -1791,8 +1844,8 @@ function define(container, image, published) {
1791
1844
  * from the container's first, so MinIO's console cannot land on whatever was
1792
1845
  * allocated to the next container.
1793
1846
  */
1794
- function publish(container, ports) {
1795
- return portsOf(container).map((port) => {
1847
+ function publish(container, ports, fakes) {
1848
+ return portsOf(container, fakes).map((port) => {
1796
1849
  const assigned = ports[port.key];
1797
1850
  if (assigned === void 0) throw new UnassignedPort(port.key);
1798
1851
  return `${assigned}:${port.inside}`;
@@ -2478,11 +2531,12 @@ async function reconcile(options) {
2478
2531
  events: options.events,
2479
2532
  cache: options.cache,
2480
2533
  extraContainers: options.extraContainers,
2534
+ ...options.fakes ? { fakes: options.fakes } : {},
2481
2535
  ...options.edge === void 0 ? {} : { edge: options.edge }
2482
2536
  });
2483
2537
  const composePath = (0, node_path.join)(root, COMPOSE_PATH);
2484
- const observed = await observedPorts(docker, composePath, plan.containers);
2485
- const ports = await allocate(project, portKeys(plan.containers), {
2538
+ const observed = await observedPorts(docker, composePath, plan.containers, plan.fakes);
2539
+ const ports = await allocate(project, portKeys(plan.containers, plan.fakes), {
2486
2540
  ...options.saved,
2487
2541
  ...observed
2488
2542
  }, probe);
@@ -2515,6 +2569,7 @@ async function reconcile(options) {
2515
2569
  addresses,
2516
2570
  env,
2517
2571
  provisioned: [],
2572
+ fakes: options.fakes ?? {},
2518
2573
  hash,
2519
2574
  changed: false
2520
2575
  };
@@ -2570,9 +2625,9 @@ async function create(plan, ports, sql, buckets, project) {
2570
2625
  * Keyed the same way allocation keys them, so the two merge without either
2571
2626
  * knowing about the other.
2572
2627
  */
2573
- async function observedPorts(docker, composePath, containers) {
2628
+ async function observedPorts(docker, composePath, containers, fakes) {
2574
2629
  const observed = {};
2575
- for (const container of containers) for (const port of portsOf(container)) {
2630
+ for (const container of containers) for (const port of portsOf(container, fakes)) {
2576
2631
  const running = await docker.publishedPort(composePath, container, port.inside);
2577
2632
  if (running !== void 0) observed[port.key] = running;
2578
2633
  }
@@ -2628,9 +2683,11 @@ async function write(path, content) {
2628
2683
  * same state, differing only in the stage they pass.
2629
2684
  */
2630
2685
  var workspace_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
2686
+ FAKE_ENV: () => FAKE_ENV,
2631
2687
  backendsOf: () => backendsOf,
2632
2688
  constructGlobs: () => constructGlobs,
2633
2689
  derivedContainers: () => derivedContainers,
2690
+ fakesApply: () => fakesApply,
2634
2691
  metroPorts: () => metroPorts,
2635
2692
  reconcileWorkspace: () => reconcileWorkspace,
2636
2693
  surfaceAddresses: () => surfaceAddresses
@@ -2673,6 +2730,19 @@ async function derivedContainers(workspace, stage, manifest) {
2673
2730
  }).containers;
2674
2731
  }
2675
2732
  /**
2733
+ * Set by `gkm dev --fake` for the apps it starts. Each app's own `gkm dev`
2734
+ * reconciles too, and must answer the way the workspace did.
2735
+ */
2736
+ const FAKE_ENV = "GKM_FAKE";
2737
+ /**
2738
+ * Whether external APIs are faked: always for `gkm test`, and for `gkm dev`
2739
+ * only when asked — by `--fake`, or by the workspace that started this app
2740
+ * with it. Never for anything acting on a deployed stage.
2741
+ */
2742
+ function fakesApply(stage, fake, env = process.env) {
2743
+ return fake === true || stage === "test" || env["GKM_FAKE"] === "1";
2744
+ }
2745
+ /**
2676
2746
  * Reconcile a workspace for one stage.
2677
2747
  *
2678
2748
  * Ports are loaded and saved around the call rather than inside it, so the loop
@@ -2686,6 +2756,7 @@ async function reconcileWorkspace(workspace, options) {
2686
2756
  runnables
2687
2757
  });
2688
2758
  const manifest = options.manifest ?? discovered;
2759
+ const fakes = fakesApply(options.stage, options.fake) ? await require_ready.readFakes(workspace.root, manifest) : {};
2689
2760
  const result = await reconcile({
2690
2761
  root: workspace.root,
2691
2762
  project: workspace.name,
@@ -2696,7 +2767,8 @@ async function reconcileWorkspace(workspace, options) {
2696
2767
  saved: await loadPortState(workspace.root),
2697
2768
  addresses: surfaceAddresses(workspace, manifest),
2698
2769
  metroPorts: metroPorts(workspace, manifest),
2699
- apps: (containers) => appServices(workspace, manifest, containers, runnables),
2770
+ fakes,
2771
+ apps: (containers) => appServices(workspace, manifest, containers, runnables, fakes),
2700
2772
  ...options.start === void 0 ? {} : { start: options.start }
2701
2773
  });
2702
2774
  await savePortState(workspace.root, { ...result.ports });
@@ -2753,6 +2825,12 @@ Object.defineProperty(exports, "COMPOSE_PATH", {
2753
2825
  return COMPOSE_PATH;
2754
2826
  }
2755
2827
  });
2828
+ Object.defineProperty(exports, "FAKE_ENV", {
2829
+ enumerable: true,
2830
+ get: function() {
2831
+ return FAKE_ENV;
2832
+ }
2833
+ });
2756
2834
  Object.defineProperty(exports, "LOCAL_CA_PATH", {
2757
2835
  enumerable: true,
2758
2836
  get: function() {
@@ -2807,6 +2885,12 @@ Object.defineProperty(exports, "eventsBackendFor", {
2807
2885
  return eventsBackendFor;
2808
2886
  }
2809
2887
  });
2888
+ Object.defineProperty(exports, "fakeKey", {
2889
+ enumerable: true,
2890
+ get: function() {
2891
+ return fakeKey;
2892
+ }
2893
+ });
2810
2894
  Object.defineProperty(exports, "findAvailablePort", {
2811
2895
  enumerable: true,
2812
2896
  get: function() {
@@ -2898,4 +2982,4 @@ Object.defineProperty(exports, "workspace_exports", {
2898
2982
  }
2899
2983
  });
2900
2984
 
2901
- //# sourceMappingURL=workspace-DUhLejv4.cjs.map
2985
+ //# sourceMappingURL=workspace-DZ1G4zow.cjs.map