@geekmidas/cli 10.0.0-alpha.27 → 10.0.0-alpha.28

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 (46) hide show
  1. package/dist/{HostingerProvider-BY26bWwB.mjs → HostingerProvider-Btxpto71.mjs} +2 -2
  2. package/dist/{HostingerProvider-BY26bWwB.mjs.map → HostingerProvider-Btxpto71.mjs.map} +1 -1
  3. package/dist/{bundler-mwH7WOb1.mjs → bundler-D5RcGmVM.mjs} +2 -2
  4. package/dist/{bundler-mwH7WOb1.mjs.map → bundler-D5RcGmVM.mjs.map} +1 -1
  5. package/dist/{config-7R_-WyHq.cjs → config-BTFLHfRb.cjs} +2 -2
  6. package/dist/{config-7R_-WyHq.cjs.map → config-BTFLHfRb.cjs.map} +1 -1
  7. package/dist/{config-DXrrYvob.mjs → config-Dqxa-_Ge.mjs} +2 -2
  8. package/dist/{config-DXrrYvob.mjs.map → config-Dqxa-_Ge.mjs.map} +1 -1
  9. package/dist/config.cjs +1 -1
  10. package/dist/config.mjs +1 -1
  11. package/dist/deploy/sniffer-loader.cjs +1 -1
  12. package/dist/{discover-B_HtYJCr.cjs → discover-BTh87DOO.cjs} +24 -2
  13. package/dist/{discover-B_HtYJCr.cjs.map → discover-BTh87DOO.cjs.map} +1 -1
  14. package/dist/{discover-0fhCbnk0.mjs → discover-CXGlQHm1.mjs} +24 -2
  15. package/dist/{discover-0fhCbnk0.mjs.map → discover-CXGlQHm1.mjs.map} +1 -1
  16. package/dist/{github-CQflOKKV.cjs → github-BUCXEl2v.cjs} +5 -5
  17. package/dist/{github-CQflOKKV.cjs.map → github-BUCXEl2v.cjs.map} +1 -1
  18. package/dist/{github-Ba5kXEJo.mjs → github-zkzu-ka2.mjs} +3 -3
  19. package/dist/{github-Ba5kXEJo.mjs.map → github-zkzu-ka2.mjs.map} +1 -1
  20. package/dist/index.cjs +740 -655
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.mjs +735 -652
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/{openapi-3NLVvtz-.mjs → openapi-D-Lk5Hr5.mjs} +3 -3
  25. package/dist/{openapi-3NLVvtz-.mjs.map → openapi-D-Lk5Hr5.mjs.map} +1 -1
  26. package/dist/{openapi-rhJdy2GC.cjs → openapi-K4H5tHzA.cjs} +3 -3
  27. package/dist/{openapi-rhJdy2GC.cjs.map → openapi-K4H5tHzA.cjs.map} +1 -1
  28. package/dist/openapi.cjs +1 -1
  29. package/dist/openapi.mjs +1 -1
  30. package/dist/reconcile/public.cjs +1 -1
  31. package/dist/reconcile/public.d.cts +12 -0
  32. package/dist/reconcile/public.d.cts.map +1 -1
  33. package/dist/reconcile/public.d.mts +12 -0
  34. package/dist/reconcile/public.d.mts.map +1 -1
  35. package/dist/reconcile/public.mjs +1 -1
  36. package/dist/{workspace-DgeVgxmm.cjs → workspace-Cv48QwPK.cjs} +128 -9
  37. package/dist/workspace-Cv48QwPK.cjs.map +1 -0
  38. package/dist/{workspace-CUmR_k4J.mjs → workspace-cBobQVoA.mjs} +124 -11
  39. package/dist/workspace-cBobQVoA.mjs.map +1 -0
  40. package/package.json +14 -14
  41. package/dist/transfer-BV00TxZv.mjs +0 -122
  42. package/dist/transfer-BV00TxZv.mjs.map +0 -1
  43. package/dist/transfer-BYIn7z8m.cjs +0 -151
  44. package/dist/transfer-BYIn7z8m.cjs.map +0 -1
  45. package/dist/workspace-CUmR_k4J.mjs.map +0 -1
  46. package/dist/workspace-DgeVgxmm.cjs.map +0 -1
@@ -1,13 +1,13 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-BhDjJH2R.mjs";
2
- import { a as DEFAULT_EVENTS$1, i as DEFAULT_CACHE, o as DEFAULT_STORAGE, t as discover } from "./discover-0fhCbnk0.mjs";
3
- import { l as appKey, o as loadWorkspaceAppInfo, r as getAppNameFromCwd, s as loadWorkspaceConfig } from "./config-DXrrYvob.mjs";
2
+ import { a as DEFAULT_EVENTS$1, i as DEFAULT_CACHE, o as DEFAULT_STORAGE, t as discover } from "./discover-CXGlQHm1.mjs";
3
+ import { l as appKey, o as loadWorkspaceAppInfo, r as getAppNameFromCwd, s as loadWorkspaceConfig } from "./config-Dqxa-_Ge.mjs";
4
4
  import { E as TEST_STAGE, t as allConstructGlobs } from "./workspace-T4IVGSoB.mjs";
5
5
  import { n as readStageSecrets, o as toEmbeddableSecrets, r as secretsExist } from "./storage-TP0x118M.mjs";
6
6
  import { existsSync } from "node:fs";
7
7
  import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
8
8
  import { dirname, join, resolve } from "node:path";
9
9
  import { execFile } from "node:child_process";
10
- import { DEFAULT_POSTGRES_VERSION, cacheTable, cookieDomain, dependentsOf, provideKey, providedKeyFor, provisionOrder, publicEnvFor } from "@geekmidas/manifest";
10
+ import { DEFAULT_POSTGRES_VERSION, cacheTable, cookieDomain, dependenciesOf, dependentsOf, provideKey, providedKeyFor, provisionOrder, publicEnvFor } from "@geekmidas/manifest";
11
11
  import { createServer } from "node:net";
12
12
  import { config } from "dotenv";
13
13
  import { createHash } from "node:crypto";
@@ -515,11 +515,16 @@ function portOf(address) {
515
515
  */
516
516
  function hostFor(resource, project) {
517
517
  return [
518
- resource.name,
518
+ resource.root && project ? stageOf(resource) : resource.name,
519
519
  project,
520
520
  LOCAL_TLD
521
521
  ].filter(Boolean).join(".");
522
522
  }
523
+ /** The stage a resource's name carries, or nothing for the local stage's. */
524
+ function stageOf(resource) {
525
+ const base = resource.id.toLowerCase();
526
+ return resource.name === base ? void 0 : resource.name.slice(base.length + 1);
527
+ }
523
528
  /**
524
529
  * The static root config, which only ever imports.
525
530
  *
@@ -586,6 +591,49 @@ const GENERATED = `# Generated by gkm from the construct manifest — do not edi
586
591
  # from code; a browser needs the root trusted once.
587
592
  `;
588
593
  //#endregion
594
+ //#region src/workspace/rootSite.ts
595
+ /**
596
+ * Which site the base domain points at — deployed and locally alike.
597
+ *
598
+ * Three rules, in order, and the last one is the point:
599
+ *
600
+ * 1. **One site** — it is the root. Unambiguous, so nothing has to be said.
601
+ * 2. **Named `web`** — the convention wins, because people already rely on it.
602
+ * 3. **Declared `root: true`** — the site says so itself.
603
+ *
604
+ * Anything else throws. It used to take the *first* site it iterated, and that
605
+ * order came from the manifest, which is built in glob traversal order — so two
606
+ * sites with neither named `web` meant renaming a file could move the root
607
+ * domain, silently.
608
+ *
609
+ * One rule for both targets: deployed the root site gets the base domain, and
610
+ * locally it gets the project's bare host behind the edge. Before this was
611
+ * shared, the local edge put every site on a subdomain, so what a developer
612
+ * browsed was not the shape production served.
613
+ *
614
+ * @returns the root site's name, or `undefined` when there are no sites
615
+ * @throws {AmbiguousRootSite} when several sites could be the root and none says it is
616
+ */
617
+ function rootSite(sites) {
618
+ if (sites.length === 0) return void 0;
619
+ if (sites.length === 1) return sites[0].name;
620
+ if (sites.some(({ name }) => name === "web")) return "web";
621
+ const declared = sites.filter(({ root }) => root === true);
622
+ if (declared.length === 1) return declared[0].name;
623
+ throw new AmbiguousRootSite(sites.map(({ name }) => name), declared.length > 1);
624
+ }
625
+ /** Several sites could hold the base domain, and none of them says it does. */
626
+ var AmbiguousRootSite = class extends Error {
627
+ sites;
628
+ tooMany;
629
+ constructor(sites, tooMany = false) {
630
+ super(tooMany ? `More than one site declares \`root: true\` — ${sites.join(", ")}. The base domain points at one of them.` : `${sites.length} sites and nothing says which holds the base domain: ${sites.join(", ")}. Name one of them \`web\`, or declare \`root: true\` on the one the base domain points at. It used to be whichever the glob reached first, which is not a thing to decide a hostname.`);
631
+ this.sites = sites;
632
+ this.tooMany = tooMany;
633
+ this.name = "AmbiguousRootSite";
634
+ }
635
+ };
636
+ //#endregion
589
637
  //#region src/reconcile/plan.ts
590
638
  /**
591
639
  * The reconcile plan — what a manifest wants to exist, for one stage.
@@ -793,6 +841,15 @@ function planFor(manifest, stage, order, options = {}) {
793
841
  for (const resource of placeless) resource.of = only.id;
794
842
  }
795
843
  }
844
+ const sites = resources.filter((r) => r.kind === "site");
845
+ const root = rootSite(sites.map((r) => {
846
+ const declared = manifest[r.id];
847
+ return {
848
+ name: appKey(r.id),
849
+ ...declared?.kind === "site" && declared.root ? { root: true } : {}
850
+ };
851
+ }));
852
+ for (const site of sites) if (appKey(site.id) === root) site.root = true;
796
853
  const workerBroker = events === "pgboss" && Object.values(manifest).some((d) => d?.kind === "worker") && resources.some((r) => r.kind === "database");
797
854
  return {
798
855
  stage,
@@ -1276,14 +1333,67 @@ function inNetworkEnv(workspace, manifest) {
1276
1333
  });
1277
1334
  return Object.fromEntries(Object.entries(env).map(([key, value]) => [key, rewrite(value)]));
1278
1335
  }
1336
+ /**
1337
+ * The keys one app's environment may hold: what its own declaration provides
1338
+ * and requires, and what each construct it has an edge to provides.
1339
+ *
1340
+ * The edges, not the manifest. Every app used to be handed every key the
1341
+ * workspace resolved — a web app got the database's owner URL and the auth
1342
+ * server's signing secret, and the API got the auth server's database — which
1343
+ * is exactly what a declared edge exists to rule out. A deploy composes an
1344
+ * app's environment from its edges; so does this.
1345
+ *
1346
+ * One hop: a surface an app calls is reached over HTTP, so its URL is the
1347
+ * app's business and its database is not. A site also gets the public
1348
+ * variant of each key its bundle inlines (`NEXT_PUBLIC_API_URL`), and a surface
1349
+ * the edges of the workers whose crons and subscribers its server runs.
1350
+ *
1351
+ * `undefined` for an app no declaration describes, which gets nothing but its
1352
+ * port.
1353
+ */
1354
+ function appEnvKeys(manifest, appName, runnables = {}) {
1355
+ const entry = Object.entries(manifest).find(([id, d]) => (d.kind === "rest-api" || d.kind === "site") && appKey(id) === appName);
1356
+ if (!entry) return void 0;
1357
+ const [id, declaration] = entry;
1358
+ const keys = /* @__PURE__ */ new Set([
1359
+ ...declaration.provides ?? [],
1360
+ ...declaration.requires ?? [],
1361
+ ...declaration.kind === "rest-api" ? declaration.endpoints.flatMap((endpoint) => endpoint.requires ?? []) : []
1362
+ ]);
1363
+ const edges = [...dependenciesOf(declaration).map((edge) => edge.target), ...runnables[id] ?? []];
1364
+ if (declaration.kind === "rest-api" && declaration.endpoints.length === 0) for (const [otherId, other] of Object.entries(manifest)) {
1365
+ if (other.kind !== "worker") continue;
1366
+ edges.push(...dependenciesOf(other).map((edge) => edge.target), ...runnables[otherId] ?? []);
1367
+ keys.add("EVENT_PUBLISHER_CONNECTION_STRING");
1368
+ keys.add("EVENT_SUBSCRIBER_CONNECTION_STRING");
1369
+ }
1370
+ for (const id of edges) {
1371
+ const target = manifest[id];
1372
+ if (!target) continue;
1373
+ for (const key of target.provides ?? []) keys.add(key);
1374
+ if (target.kind === "queue" || target.kind === "topic") {
1375
+ keys.add("EVENT_PUBLISHER_CONNECTION_STRING");
1376
+ keys.add("EVENT_SUBSCRIBER_CONNECTION_STRING");
1377
+ }
1378
+ if (target.kind === "objects") {
1379
+ keys.add("AWS_ACCESS_KEY_ID");
1380
+ keys.add("AWS_SECRET_ACCESS_KEY");
1381
+ keys.add("AWS_REGION");
1382
+ }
1383
+ }
1384
+ if (declaration.kind === "site") for (const key of Object.keys(publicEnvFor(declaration, manifest))) keys.add(key);
1385
+ return keys;
1386
+ }
1279
1387
  /** One compose service per app the workspace runs, behind the apps profile. */
1280
- function appServices(workspace, manifest, containers) {
1388
+ function appServices(workspace, manifest, containers, runnables = {}) {
1281
1389
  const env = inNetworkEnv(workspace, manifest);
1282
1390
  const services = {};
1283
1391
  for (const [name, app] of Object.entries(workspace.apps)) {
1284
1392
  if (app.type === "mobile" || !app.port) continue;
1285
1393
  const key = appKey(name);
1286
1394
  const health = app.type === "web" ? "/" : "/health";
1395
+ const allowed = appEnvKeys(manifest, name, runnables);
1396
+ const own = Object.fromEntries(Object.entries(env).filter(([envKey]) => allowed?.has(envKey)));
1287
1397
  services[key] = {
1288
1398
  image: `${key}:\${TAG:-latest}`,
1289
1399
  build: {
@@ -1295,7 +1405,7 @@ function appServices(workspace, manifest, containers) {
1295
1405
  environment: {
1296
1406
  NODE_ENV: "production",
1297
1407
  PORT: String(app.port),
1298
- ...env
1408
+ ...own
1299
1409
  },
1300
1410
  ...containers.some((c) => c !== "caddy") ? { depends_on: containers.filter((c) => c !== "caddy") } : {},
1301
1411
  healthcheck: {
@@ -2500,10 +2610,13 @@ async function derivedContainers(workspace, stage, manifest) {
2500
2610
  * stays a pure-ish function of its inputs and the store keeps its single owner.
2501
2611
  */
2502
2612
  async function reconcileWorkspace(workspace, options) {
2503
- const manifest = options.manifest ?? await discover({
2613
+ const runnables = {};
2614
+ const discovered = await discover({
2504
2615
  patterns: constructGlobs(workspace),
2505
- cwd: workspace.root
2616
+ cwd: workspace.root,
2617
+ runnables
2506
2618
  });
2619
+ const manifest = options.manifest ?? discovered;
2507
2620
  const result = await reconcile({
2508
2621
  root: workspace.root,
2509
2622
  project: workspace.name,
@@ -2513,7 +2626,7 @@ async function reconcileWorkspace(workspace, options) {
2513
2626
  ...backendsOf(workspace),
2514
2627
  saved: await loadPortState(workspace.root),
2515
2628
  addresses: surfaceAddresses(workspace, manifest),
2516
- apps: (containers) => appServices(workspace, manifest, containers),
2629
+ apps: (containers) => appServices(workspace, manifest, containers, runnables),
2517
2630
  ...options.start === void 0 ? {} : { start: options.start }
2518
2631
  });
2519
2632
  await savePortState(workspace.root, { ...result.ports });
@@ -2550,6 +2663,6 @@ function localAddress(port) {
2550
2663
  return `http://localhost:${port}`;
2551
2664
  }
2552
2665
  //#endregion
2553
- export { isPortAvailable as _, workspace_exports as a, prepareEntryCredentials as b, applyPostgres as c, eventsBackendFor as d, providerOf as f, findAvailablePort as g, createEntryWrapper as h, reconcileWorkspace as i, resourceName as l, createCredentialsPreload as m, constructGlobs as n, COMPOSE_PATH as o, storageBackendFor as p, derivedContainers as r, LOCAL_CA_PATH as s, backendsOf as t, cacheBackendFor as u, loadEnvFiles as v, loadSecretsForApp as y };
2666
+ export { findAvailablePort as _, workspace_exports as a, loadSecretsForApp as b, applyPostgres as c, cacheBackendFor as d, eventsBackendFor as f, createEntryWrapper as g, createCredentialsPreload as h, reconcileWorkspace as i, resourceName as l, storageBackendFor as m, constructGlobs as n, COMPOSE_PATH as o, providerOf as p, derivedContainers as r, LOCAL_CA_PATH as s, backendsOf as t, rootSite as u, isPortAvailable as v, prepareEntryCredentials as x, loadEnvFiles as y };
2554
2667
 
2555
- //# sourceMappingURL=workspace-CUmR_k4J.mjs.map
2668
+ //# sourceMappingURL=workspace-cBobQVoA.mjs.map