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

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 (32) hide show
  1. package/bin/gkm.mjs +9 -1
  2. package/bin/owning-tsconfig-jsx-register.mjs +18 -0
  3. package/bin/owning-tsconfig-jsx.mjs +108 -0
  4. package/dist/backends-B9V2XD2M.cjs +82 -0
  5. package/dist/backends-B9V2XD2M.cjs.map +1 -0
  6. package/dist/backends-CSuLl0YP.mjs +59 -0
  7. package/dist/backends-CSuLl0YP.mjs.map +1 -0
  8. package/dist/encryption-C7OGMve_.cjs +91 -0
  9. package/dist/encryption-C7OGMve_.cjs.map +1 -0
  10. package/dist/encryption-DyQnPsZN.mjs +90 -0
  11. package/dist/encryption-DyQnPsZN.mjs.map +1 -0
  12. package/dist/index.cjs +131 -51
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.mjs +123 -43
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/{migrate-Dp5HFzuQ.cjs → migrate-BgEY9pdP.cjs} +2 -2
  17. package/dist/{migrate-Dp5HFzuQ.cjs.map → migrate-BgEY9pdP.cjs.map} +1 -1
  18. package/dist/{migrate-B3opyC3o.mjs → migrate-DhxTIA0z.mjs} +2 -2
  19. package/dist/{migrate-B3opyC3o.mjs.map → migrate-DhxTIA0z.mjs.map} +1 -1
  20. package/dist/{ready-V6Ou6-B6.mjs → ready-WfT-eWlm.mjs} +2 -1
  21. package/dist/{ready-V6Ou6-B6.mjs.map → ready-WfT-eWlm.mjs.map} +1 -1
  22. package/dist/{ready-L7I68yXf.cjs → ready-lr2Fm-ep.cjs} +2 -1
  23. package/dist/{ready-L7I68yXf.cjs.map → ready-lr2Fm-ep.cjs.map} +1 -1
  24. package/dist/vitest.cjs +1 -1
  25. package/dist/vitest.mjs +1 -1
  26. package/dist/{workspace-CHEC80sp.mjs → workspace-cb6U29EL.mjs} +56 -77
  27. package/dist/workspace-cb6U29EL.mjs.map +1 -0
  28. package/dist/{workspace-D9z2ymBW.cjs → workspace-vafrzZTC.cjs} +60 -99
  29. package/dist/workspace-vafrzZTC.cjs.map +1 -0
  30. package/package.json +14 -14
  31. package/dist/workspace-CHEC80sp.mjs.map +0 -1
  32. package/dist/workspace-D9z2ymBW.cjs.map +0 -1
@@ -4,7 +4,8 @@ import { c as loadWorkspaceAppInfo, f as appKey, l as loadWorkspaceConfig, r as
4
4
  import { E as TEST_STAGE, t as allConstructGlobs } from "./workspace-DNzWgM1J.mjs";
5
5
  import { i as toEmbeddableSecrets } from "./storage-BzaUxmqe.mjs";
6
6
  import { i as FileSecretsStore, n as secretsStoreFor } from "./store-DeGATCS-.mjs";
7
- import { d as DEFAULT_EVENTS$1, f as DEFAULT_STORAGE, l as readFakes, u as DEFAULT_CACHE } from "./ready-V6Ou6-B6.mjs";
7
+ import { l as readFakes, u as DEFAULT_CACHE } from "./ready-WfT-eWlm.mjs";
8
+ import { n as eventsBackendFor, r as providerOf, t as cacheBackendFor } from "./backends-CSuLl0YP.mjs";
8
9
  import { existsSync } from "node:fs";
9
10
  import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
10
11
  import { networkInterfaces } from "node:os";
@@ -14,6 +15,7 @@ import { DEFAULT_POSTGRES_VERSION, cacheTable, cookieDomain, dependenciesOf, dep
14
15
  import { createServer } from "node:net";
15
16
  import { config } from "dotenv";
16
17
  import { createHash } from "node:crypto";
18
+ import { formatKeyring } from "@geekmidas/constructs/encryption";
17
19
  import { ownerRole, readerRole, roleStatements } from "@geekmidas/db/pg/roles";
18
20
  import * as snsUrl from "@geekmidas/events/sns/url";
19
21
  import * as sqsUrl from "@geekmidas/events/sqs/url";
@@ -246,61 +248,6 @@ async function prepareEntryCredentials(options) {
246
248
  };
247
249
  }
248
250
  //#endregion
249
- //#region src/workspace/backends.ts
250
- /**
251
- * Which backend each declared kind resolves to — decided by where the project
252
- * deploys, and by nothing else.
253
- *
254
- * These used to be read out of a `services:` block, where one key answered two
255
- * questions: *does this exist* and *what backs it*. The first is the manifest's
256
- * — a declared `Cache` is why there is a cache — and the second is the deploy
257
- * target's, because the right cache for a Lambda is not the right cache for a
258
- * box already running Postgres. With both answered elsewhere there was nothing
259
- * left for the block to say, so it is gone and these read the target.
260
- *
261
- * Mail has no answer here at all: every provider speaks SMTP, so the provider
262
- * is whichever one the stage's mail URL points at.
263
- */
264
- /**
265
- * Which family of defaults a workspace's deploy target belongs to.
266
- *
267
- * One question, asked once: **does this target run containers the project
268
- * controls?** Dokploy and a bare server do, so a bucket or a cache can live
269
- * beside the app; AWS, Vercel and Cloudflare do not, so the default has to be
270
- * something managed. That is the whole of the distinction, and it is why
271
- * `MainProvider` is the right axis rather than the deploy target's own name —
272
- * three targets share one answer.
273
- *
274
- * An AWS deploy names `deploy.default: 'sst'`, because it goes through SST.
275
- */
276
- function providerOf(workspace) {
277
- const target = workspace.deploy?.default;
278
- return target === "dokploy" || target === "server" ? "server" : "aws";
279
- }
280
- /**
281
- * The cache backend a target implies.
282
- *
283
- * The same answer locally and deployed: a local `gkm dev` for an AWS app still
284
- * uses the Upstash protocol, because a backend that differed between the two
285
- * would be worse than a slower one.
286
- */
287
- function cacheBackendFor(on) {
288
- return DEFAULT_CACHE[on];
289
- }
290
- /** Where a declared bucket lives on a target. */
291
- function storageBackendFor(on) {
292
- return DEFAULT_STORAGE[on];
293
- }
294
- /**
295
- * Which broker carries declared queues and topics on a target.
296
- *
297
- * Only consulted when something declares one; a project with no `Topic` or
298
- * `Queue` has no events at all, whatever the target.
299
- */
300
- function eventsBackendFor(on) {
301
- return DEFAULT_EVENTS$1[on];
302
- }
303
- //#endregion
304
251
  //#region src/reconcile/containers.ts
305
252
  /**
306
253
  * What gkm knows about each container it can derive.
@@ -360,7 +307,8 @@ const PORTS = {
360
307
  }, {
361
308
  key: "minio-console",
362
309
  inside: 9001,
363
- label: "minio console"
310
+ label: "minio console",
311
+ web: true
364
312
  }],
365
313
  mailpit: [{
366
314
  key: "mailpit",
@@ -369,7 +317,8 @@ const PORTS = {
369
317
  }, {
370
318
  key: "mailpit-web",
371
319
  inside: 8025,
372
- label: "mailpit inbox"
320
+ label: "mailpit inbox",
321
+ web: true
373
322
  }],
374
323
  redis: [{
375
324
  key: "redis",
@@ -388,7 +337,8 @@ const PORTS = {
388
337
  }, {
389
338
  key: "rabbitmq-management",
390
339
  inside: 15672,
391
- label: "rabbitmq console"
340
+ label: "rabbitmq console",
341
+ web: true
392
342
  }],
393
343
  localstack: [{
394
344
  key: "localstack",
@@ -420,6 +370,29 @@ function portsOf(container, fakes = {}) {
420
370
  }];
421
371
  return PORTS[container] ?? [];
422
372
  }
373
+ /**
374
+ * Every port the containers publish — not only the one an app connects to.
375
+ *
376
+ * The consoles and the inbox are most of why these are real containers, and an
377
+ * inbox nobody can find is an inbox nobody opens: a sign-in link gets fished
378
+ * out of `docker ps` instead.
379
+ */
380
+ function serviceAddresses(containers, ports, fakes = {}) {
381
+ return containers.flatMap((container) => portsOf(container, fakes).flatMap((port) => {
382
+ const assigned = ports[port.key];
383
+ if (assigned === void 0) return [];
384
+ return [{
385
+ container,
386
+ label: port.label,
387
+ address: port.web ? `http://localhost:${assigned}` : `localhost:${assigned}`
388
+ }];
389
+ }));
390
+ }
391
+ /** The lines `gkm dev` and `gkm setup` print under the services heading. */
392
+ function describeServices(services) {
393
+ const width = Math.max(0, ...services.map(({ label }) => label.length));
394
+ return services.map(({ label, address }) => ` ${label.padEnd(width)} ${address}`);
395
+ }
423
396
  /** The key a container's primary port is allocated under. */
424
397
  function primaryPortKey(container) {
425
398
  return portsOf(container)[0]?.key ?? container;
@@ -745,6 +718,7 @@ const CACHE_CONTAINERS = {
745
718
  const CONTAINERLESS = {
746
719
  secret: true,
747
720
  credential: true,
721
+ encryption: true,
748
722
  "rest-api": true,
749
723
  site: true,
750
724
  "mobile-app": true,
@@ -1209,6 +1183,7 @@ function workerBroker(plan, ports) {
1209
1183
  */
1210
1184
  function urlFor(resource, plan, ports, project, addresses = {}) {
1211
1185
  if (resource.kind === "secret") return localSecret(project, plan, resource);
1186
+ if (resource.kind === "encryption") return localKeyring(project, plan, resource);
1212
1187
  if (resource.kind === "mobile-app") return schemeBase(project, resource.scheme);
1213
1188
  if (resource.kind === "credential") return void 0;
1214
1189
  if (resource.kind === "external-api") {
@@ -1384,6 +1359,24 @@ var UnprovisionedEventsBackend = class extends Error {
1384
1359
  }
1385
1360
  };
1386
1361
  /**
1362
+ * The keyring an `Encryption` construct resolves to locally.
1363
+ *
1364
+ * Derived like a secret — stable across restarts, distinct per project, stage
1365
+ * and construct, never written to disk — so what `gkm dev` encrypted yesterday
1366
+ * still opens today. One key, because nothing local is worth rotating: a
1367
+ * server stage's keyring is generated and rotated in its secrets instead.
1368
+ */
1369
+ function localKeyring(project, plan, resource) {
1370
+ const derive = (purpose) => createHash("sha256").update(`${project}:${plan.stage}:${resource.id}:${purpose}`).digest();
1371
+ return formatKeyring({
1372
+ keys: [{
1373
+ id: "k1",
1374
+ key: derive("k1")
1375
+ }],
1376
+ index: derive("index")
1377
+ });
1378
+ }
1379
+ /**
1387
1380
  * The value a secret resolves to locally.
1388
1381
  *
1389
1382
  * A hash of what identifies it, so it is stable, distinct per project, stage
@@ -2715,7 +2708,7 @@ async function reconcile(options) {
2715
2708
  caddyfile,
2716
2709
  postgres: postgresStatements(plan, project).map((statement) => statement.create).join(";\n")
2717
2710
  });
2718
- const addresses = addressesFor(plan.containers, ports);
2711
+ const services = serviceAddresses(plan.containers, ports, plan.fakes);
2719
2712
  const lan = plan.resources.some((r) => r.kind === "mobile-app") ? options.lanAddress === void 0 ? lanAddress() : options.lanAddress ?? void 0 : void 0;
2720
2713
  const env = envFor(plan, {
2721
2714
  ports,
@@ -2731,7 +2724,7 @@ async function reconcile(options) {
2731
2724
  plan,
2732
2725
  compose,
2733
2726
  ports,
2734
- addresses,
2727
+ services,
2735
2728
  env,
2736
2729
  provisioned: [],
2737
2730
  fakes: options.fakes ?? {},
@@ -2803,20 +2796,6 @@ async function observedPorts(docker, composePath, containers, fakes) {
2803
2796
  }
2804
2797
  return observed;
2805
2798
  }
2806
- /**
2807
- * Where each container can be reached on this machine.
2808
- *
2809
- * The primary port only — a container's console is for a human to open, not
2810
- * something an app connects to.
2811
- */
2812
- function addressesFor(containers, ports) {
2813
- const addresses = {};
2814
- for (const container of containers) {
2815
- const port = ports[primaryPortKey(container)];
2816
- if (port !== void 0) addresses[container] = `localhost:${port}`;
2817
- }
2818
- return addresses;
2819
- }
2820
2799
  /** Write a file only when its content would change, so mtimes stay meaningful. */
2821
2800
  /**
2822
2801
  * Remove the routes of stages this project no longer reconciles.
@@ -2989,6 +2968,6 @@ function localAddress(port) {
2989
2968
  return `http://localhost:${port}`;
2990
2969
  }
2991
2970
  //#endregion
2992
- export { createEntryWrapper as C, loadSecretsForApp as D, loadEnvFiles as E, prepareEntryCredentials as O, createCredentialsPreload as S, isPortAvailable as T, primaryPortKey as _, reconcileWorkspace as a, providerOf as b, LOCAL_CA_PATH as c, postgresDatabaseNames as d, quoteIdentifier as f, fakeKey as g, rootSite as h, derivedContainers as i, forgetState as l, resourceName as m, backendsOf as n, workspace_exports as o, pgClient as p, constructGlobs as r, COMPOSE_PATH as s, FAKE_ENV as t, applyPostgres as u, cacheBackendFor as v, findAvailablePort as w, storageBackendFor as x, eventsBackendFor as y };
2971
+ export { loadEnvFiles as C, isPortAvailable as S, prepareEntryCredentials as T, fakeKey as _, reconcileWorkspace as a, createEntryWrapper as b, LOCAL_CA_PATH as c, postgresDatabaseNames as d, quoteIdentifier as f, describeServices as g, rootSite as h, derivedContainers as i, forgetState as l, resourceName as m, backendsOf as n, workspace_exports as o, pgClient as p, constructGlobs as r, COMPOSE_PATH as s, FAKE_ENV as t, applyPostgres as u, primaryPortKey as v, loadSecretsForApp as w, findAvailablePort as x, createCredentialsPreload as y };
2993
2972
 
2994
- //# sourceMappingURL=workspace-CHEC80sp.mjs.map
2973
+ //# sourceMappingURL=workspace-cb6U29EL.mjs.map