@geekmidas/cli 10.0.0-alpha.51 → 10.0.0-alpha.53

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 (29) hide show
  1. package/dist/{backends-B9V2XD2M.cjs → backends-D5aDWxuA.cjs} +2 -2
  2. package/dist/{backends-B9V2XD2M.cjs.map → backends-D5aDWxuA.cjs.map} +1 -1
  3. package/dist/{backends-CSuLl0YP.mjs → backends-Dfeu5Dgc.mjs} +2 -2
  4. package/dist/{backends-CSuLl0YP.mjs.map → backends-Dfeu5Dgc.mjs.map} +1 -1
  5. package/dist/{encryption-DRCXp-U4.mjs → encryption-O-XdeNxe.mjs} +2 -2
  6. package/dist/{encryption-DRCXp-U4.mjs.map → encryption-O-XdeNxe.mjs.map} +1 -1
  7. package/dist/{encryption-Bt8SHRI6.cjs → encryption-tB4LqLKN.cjs} +2 -2
  8. package/dist/{encryption-Bt8SHRI6.cjs.map → encryption-tB4LqLKN.cjs.map} +1 -1
  9. package/dist/index.cjs +96 -42
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.mjs +96 -42
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/{migrate-soUQtku3.mjs → migrate-CHQyNzj-.mjs} +2 -2
  14. package/dist/{migrate-soUQtku3.mjs.map → migrate-CHQyNzj-.mjs.map} +1 -1
  15. package/dist/{migrate-dx4I0epp.cjs → migrate-SDIRUyY5.cjs} +2 -2
  16. package/dist/{migrate-dx4I0epp.cjs.map → migrate-SDIRUyY5.cjs.map} +1 -1
  17. package/dist/{ready-WfT-eWlm.mjs → ready-C8wG_d0v.mjs} +21 -5
  18. package/dist/ready-C8wG_d0v.mjs.map +1 -0
  19. package/dist/{ready-lr2Fm-ep.cjs → ready-VkNwfJu7.cjs} +20 -4
  20. package/dist/ready-VkNwfJu7.cjs.map +1 -0
  21. package/dist/vitest.cjs +1 -1
  22. package/dist/vitest.mjs +1 -1
  23. package/dist/{workspace-GBzR_hID.cjs → workspace-P_V5t4Uk.cjs} +3 -3
  24. package/dist/{workspace-GBzR_hID.cjs.map → workspace-P_V5t4Uk.cjs.map} +1 -1
  25. package/dist/{workspace-Dp2zK_Nk.mjs → workspace-qcva2dTt.mjs} +3 -3
  26. package/dist/{workspace-Dp2zK_Nk.mjs.map → workspace-qcva2dTt.mjs.map} +1 -1
  27. package/package.json +14 -14
  28. package/dist/ready-WfT-eWlm.mjs.map +0 -1
  29. package/dist/ready-lr2Fm-ep.cjs.map +0 -1
package/dist/index.mjs CHANGED
@@ -5,11 +5,11 @@ import { d as parseModuleConfig, f as appKey, l as loadWorkspaceConfig, n as Not
5
5
  import { D as assertDeployedStage, E as TEST_STAGE, O as deployedProblems, T as InvalidStages, a as getAppBuildOrder, b as getDeployTargetError, k as stageProblems, m as stripPublicPrefix, o as getAppGkmConfig, p as getPublicEnvPrefix, t as allConstructGlobs, x as isDeployTargetSupported } from "./workspace-bOsks1uk.mjs";
6
6
  import { a as withCustomSecret, i as toEmbeddableSecrets, n as maskPassword, t as initStageSecrets } from "./storage-BzaUxmqe.mjs";
7
7
  import { a as getKeyPath, i as FileSecretsStore, n as secretsStoreFor } from "./store-DeGATCS-.mjs";
8
- import { C as loadEnvFiles, S as isPortAvailable, T as prepareEntryCredentials, _ as fakeKey, a as reconcileWorkspace, b as createEntryWrapper, c as LOCAL_CA_PATH, d as postgresDatabaseNames, f as quoteIdentifier, g as describeServices, h as rootSite, i as derivedContainers, l as forgetState, m as resourceName, n as backendsOf$1, p as pgClient, r as constructGlobs, s as COMPOSE_PATH, t as FAKE_ENV, u as applyPostgres, v as primaryPortKey, w as loadSecretsForApp, x as findAvailablePort, y as createCredentialsPreload } from "./workspace-Dp2zK_Nk.mjs";
8
+ import { C as loadEnvFiles, S as isPortAvailable, T as prepareEntryCredentials, _ as fakeKey, a as reconcileWorkspace, b as createEntryWrapper, c as LOCAL_CA_PATH, d as postgresDatabaseNames, f as quoteIdentifier, g as describeServices, h as rootSite, i as derivedContainers, l as forgetState, m as resourceName, n as backendsOf$1, p as pgClient, r as constructGlobs, s as COMPOSE_PATH, t as FAKE_ENV, u as applyPostgres, v as primaryPortKey, w as loadSecretsForApp, x as findAvailablePort, y as createCredentialsPreload } from "./workspace-qcva2dTt.mjs";
9
9
  import { n as EndpointGenerator, r as runtimeFor } from "./OpenApiTsGenerator-BzIGy8KE.mjs";
10
10
  import { generateOpenApi, openapiCommand, resolveOpenApiConfig } from "./openapi.mjs";
11
- import { a as writeTestHarness, c as driversFor, i as TEST_MANIFEST_ENV, n as TEST_READY_FILE, o as SubscriberGenerator, s as cacheBackendsIn, t as TEST_READY_ENV } from "./ready-WfT-eWlm.mjs";
12
- import { i as storageBackendFor, n as eventsBackendFor, r as providerOf, t as cacheBackendFor } from "./backends-CSuLl0YP.mjs";
11
+ import { a as writeTestHarness, c as driversFor, i as TEST_MANIFEST_ENV, n as TEST_READY_FILE, o as SubscriberGenerator, s as cacheBackendsIn, t as TEST_READY_ENV } from "./ready-C8wG_d0v.mjs";
12
+ import { i as storageBackendFor, n as eventsBackendFor, r as providerOf, t as cacheBackendFor } from "./backends-Dfeu5Dgc.mjs";
13
13
  import { n as withCompute, r as withRoutes, t as manifestModule } from "./emit-C1e8qD08.mjs";
14
14
  import { createRequire } from "node:module";
15
15
  import { Command } from "commander";
@@ -42,7 +42,7 @@ import { Queue } from "@geekmidas/constructs/queue";
42
42
  import { Topic } from "@geekmidas/constructs/topic";
43
43
  import { lookup } from "node:dns/promises";
44
44
  //#region package.json
45
- var version = "10.0.0-alpha.51";
45
+ var version = "10.0.0-alpha.53";
46
46
  //#endregion
47
47
  //#region src/auth/credentials.ts
48
48
  /**
@@ -567,7 +567,8 @@ var UnsupportedPlatform = class extends Error {
567
567
  * So the holder is asked who it is. Every app process gkm starts is tagged with
568
568
  * {@link APP_TAG_ENV} — the workspace and the app — and children inherit it, so
569
569
  * whatever actually binds the port (`next-server`, a Metro worker, the tsx
570
- * server) carries it. A held port whose holder carries this app's tag is a
570
+ * server) carries it — or, when its own can't be read, one of its parents does.
571
+ * A held port whose holder carries this app's tag is a
571
572
  * leftover, and is refused; anything else — untagged, another workspace's,
572
573
  * unreadable — is not ours, and the app moves to the next free port.
573
574
  *
@@ -625,13 +626,32 @@ function holderOf(port) {
625
626
  const pid = Number(out.match(/^p(\d+)/m)?.[1]);
626
627
  if (!pid) return void 0;
627
628
  const command = out.match(/^c(.+)$/m)?.[1];
628
- const tag = tagOf(pid);
629
+ const tag = lineageTagOf(pid);
629
630
  return {
630
631
  pid,
631
632
  ...command ? { command } : {},
632
633
  ...tag ? { tag } : {}
633
634
  };
634
635
  }
636
+ /** How far up a holder's parents to look before calling it untagged. */
637
+ const MAX_ANCESTORS = 8;
638
+ /**
639
+ * The tag of `pid`, or of its nearest parent that has one.
640
+ *
641
+ * A process can hide the tag it inherited: `next-server` renames itself, which
642
+ * on macOS overwrites the memory `ps eww` reads its environment from, so `ps`
643
+ * shows only its title. Its parent, the `next dev` gkm started, still carries
644
+ * the tag. A child is only ever started by its parent, so a tagged parent makes
645
+ * the holder this app's.
646
+ */
647
+ function lineageTagOf(pid) {
648
+ let current = pid;
649
+ for (let depth = 0; current && current > 1; depth += 1) {
650
+ const tag = tagOf(current);
651
+ if (tag || depth === MAX_ANCESTORS) return tag;
652
+ current = parentOf(current);
653
+ }
654
+ }
635
655
  function tagOf(pid) {
636
656
  const prefix = `${APP_TAG_ENV}=`;
637
657
  try {
@@ -653,6 +673,26 @@ function tagOf(pid) {
653
673
  return;
654
674
  }
655
675
  }
676
+ function parentOf(pid) {
677
+ try {
678
+ const ppid = Number(execFileSync("ps", [
679
+ "-o",
680
+ "ppid=",
681
+ "-p",
682
+ String(pid)
683
+ ], {
684
+ encoding: "utf8",
685
+ stdio: [
686
+ "ignore",
687
+ "pipe",
688
+ "ignore"
689
+ ]
690
+ }).trim());
691
+ return ppid > 0 ? ppid : void 0;
692
+ } catch {
693
+ return;
694
+ }
695
+ }
656
696
  /** The ports apps were given before, by app name. */
657
697
  async function savedAppPorts(root) {
658
698
  try {
@@ -1725,9 +1765,9 @@ async function workspaceDevCommand(configured, options) {
1725
1765
  for (const { id, port } of fakes) logger$9.log(`🎭 ${id} fake: http://localhost:${port}`);
1726
1766
  logger$9.log(options.migrate || options.seed ? "🗄️ Migrating the databases" : "🗄️ Checking for pending migrations");
1727
1767
  if (options.migrate || options.seed) {
1728
- const { prepareDevDatabases } = await import("./migrate-soUQtku3.mjs");
1768
+ const { prepareDevDatabases } = await import("./migrate-CHQyNzj-.mjs");
1729
1769
  await prepareDevDatabases(workspace, reconciled.env, { seed: !!options.seed });
1730
- } else await import("./migrate-soUQtku3.mjs").then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
1770
+ } else await import("./migrate-CHQyNzj-.mjs").then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
1731
1771
  logger$9.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
1732
1772
  });
1733
1773
  const appUrls = {};
@@ -2310,7 +2350,7 @@ var CronGenerator = class extends ConstructGenerator {
2310
2350
  */
2311
2351
  import type { EnvironmentParser } from '@geekmidas/envkit';
2312
2352
  import type { Logger } from '@geekmidas/logger';
2313
- import { toCronExpression } from '@geekmidas/constructs/crons';
2353
+ import { runCron, scheduleInProcess, toCronExpression } from '@geekmidas/constructs/crons';
2314
2354
  import { ServiceDiscovery } from '@geekmidas/services';
2315
2355
  ${Array.from(importsByFile.entries()).map(([importPath, exports]) => `import { ${exports.join(", ")} } from '${importPath}';`).join("\n")}
2316
2356
 
@@ -2351,11 +2391,10 @@ export async function setupCrons(
2351
2391
 
2352
2392
  const run = async (entry: (typeof prepared)[number]) => {
2353
2393
  try {
2354
- await entry.cron.handler({
2355
- input: undefined,
2356
- services: entry.services,
2357
- logger: entry.cron.logger,
2358
- });
2394
+ // The cron's own function, the way its Lambda would run it — services,
2395
+ // the worker's database as \`db\`, its events. It used to call a
2396
+ // \`handler\` a Cron does not have, so every firing logged a failure.
2397
+ await runCron(entry.cron, serviceDiscovery);
2359
2398
  } catch (error) {
2360
2399
  logger.error({ error, cron: entry.name }, 'Cron failed');
2361
2400
  }
@@ -2366,13 +2405,28 @@ export async function setupCrons(
2366
2405
  // memory fires each job once per replica — so the schedule lives in
2367
2406
  // Postgres. It used to be a second pg-boss on the worker's database, as the
2368
2407
  // runtime role, which can neither create a schema nor use the broker's.
2369
- const { url } = envParser
2408
+ const { url, devPid } = envParser
2370
2409
  .create((get) => ({
2371
2410
  url: get('EVENT_PUBLISHER_CONNECTION_STRING').string().optional(),
2411
+ // Set by \`gkm dev\` on the server it starts, and by nothing deployed.
2412
+ devPid: get('GKM_DEV_PID').string().optional(),
2372
2413
  }))
2373
2414
  .parse();
2374
2415
 
2375
2416
  if (!url?.startsWith('pgboss://')) {
2417
+ // \`gkm dev\` on a target whose crons are infrastructure once deployed —
2418
+ // EventBridge rules on AWS — has no broker to keep a schedule in. It is one
2419
+ // process, so a timer fires each job once, which is all pg-boss is for
2420
+ // here. Only there: a deployed server firing by timer fires once per
2421
+ // replica, so outside dev this stays the error below.
2422
+ if (devPid) {
2423
+ for (const entry of prepared) {
2424
+ running.push(scheduleInProcess(entry.schedule, () => run(entry)));
2425
+ logger.info({ cron: entry.name, schedule: entry.schedule }, 'Cron scheduled in this process');
2426
+ }
2427
+ return;
2428
+ }
2429
+
2376
2430
  logger.error(
2377
2431
  { crons: prepared.map(({ name }) => name) },
2378
2432
  'These crons have nowhere to keep their schedule. On a server they are ' +
@@ -9314,26 +9368,26 @@ function loadPackageJson() {
9314
9368
  * Run: pnpm --filter @geekmidas/cli sync-versions
9315
9369
  */
9316
9370
  const GEEKMIDAS_VERSIONS = {
9317
- "@geekmidas/audit": "~10.0.0-alpha.51",
9318
- "@geekmidas/auth": "~10.0.0-alpha.51",
9319
- "@geekmidas/cache": "~10.0.0-alpha.51",
9320
- "@geekmidas/client": "~10.0.0-alpha.51",
9321
- "@geekmidas/cloud": "~10.0.0-alpha.51",
9322
- "@geekmidas/constructs": "~10.0.0-alpha.51",
9323
- "@geekmidas/db": "~10.0.0-alpha.51",
9324
- "@geekmidas/emailkit": "~10.0.0-alpha.51",
9325
- "@geekmidas/envkit": "~10.0.0-alpha.51",
9326
- "@geekmidas/errors": "~10.0.0-alpha.51",
9327
- "@geekmidas/events": "~10.0.0-alpha.51",
9328
- "@geekmidas/logger": "~10.0.0-alpha.51",
9329
- "@geekmidas/manifest": "~10.0.0-alpha.51",
9330
- "@geekmidas/rate-limit": "~10.0.0-alpha.51",
9331
- "@geekmidas/schema": "~10.0.0-alpha.51",
9332
- "@geekmidas/services": "~10.0.0-alpha.51",
9333
- "@geekmidas/storage": "~10.0.0-alpha.51",
9334
- "@geekmidas/studio": "~10.0.0-alpha.51",
9335
- "@geekmidas/telescope": "~10.0.0-alpha.51",
9336
- "@geekmidas/testkit": "~10.0.0-alpha.51",
9371
+ "@geekmidas/audit": "~10.0.0-alpha.53",
9372
+ "@geekmidas/auth": "~10.0.0-alpha.53",
9373
+ "@geekmidas/cache": "~10.0.0-alpha.53",
9374
+ "@geekmidas/client": "~10.0.0-alpha.53",
9375
+ "@geekmidas/cloud": "~10.0.0-alpha.53",
9376
+ "@geekmidas/constructs": "~10.0.0-alpha.53",
9377
+ "@geekmidas/db": "~10.0.0-alpha.53",
9378
+ "@geekmidas/emailkit": "~10.0.0-alpha.53",
9379
+ "@geekmidas/envkit": "~10.0.0-alpha.53",
9380
+ "@geekmidas/errors": "~10.0.0-alpha.53",
9381
+ "@geekmidas/events": "~10.0.0-alpha.53",
9382
+ "@geekmidas/logger": "~10.0.0-alpha.53",
9383
+ "@geekmidas/manifest": "~10.0.0-alpha.53",
9384
+ "@geekmidas/rate-limit": "~10.0.0-alpha.53",
9385
+ "@geekmidas/schema": "~10.0.0-alpha.53",
9386
+ "@geekmidas/services": "~10.0.0-alpha.53",
9387
+ "@geekmidas/storage": "~10.0.0-alpha.53",
9388
+ "@geekmidas/studio": "~10.0.0-alpha.53",
9389
+ "@geekmidas/telescope": "~10.0.0-alpha.53",
9390
+ "@geekmidas/testkit": "~10.0.0-alpha.53",
9337
9391
  "@geekmidas/cli": `~${loadPackageJson().version}`
9338
9392
  };
9339
9393
  //#endregion
@@ -16076,7 +16130,7 @@ function testDatabases(reconciled) {
16076
16130
  * starts without the reference data the app needs.
16077
16131
  */
16078
16132
  async function migrateTestStage(workspace, env) {
16079
- const { migrateAndSeed } = await import("./migrate-soUQtku3.mjs");
16133
+ const { migrateAndSeed } = await import("./migrate-CHQyNzj-.mjs");
16080
16134
  const { discover } = await import("./discover-Cf2jAcgF.mjs").then((n) => n.n);
16081
16135
  const sources = {};
16082
16136
  const manifest = await discover({
@@ -16507,7 +16561,7 @@ program.command("migrate").description("Apply each database construct's migratio
16507
16561
  try {
16508
16562
  const globalOptions = program.opts();
16509
16563
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16510
- const { migrateCommand } = await import("./migrate-soUQtku3.mjs");
16564
+ const { migrateCommand } = await import("./migrate-CHQyNzj-.mjs");
16511
16565
  await migrateCommand({
16512
16566
  ...options,
16513
16567
  ...construct ? { construct } : {}
@@ -16521,7 +16575,7 @@ program.command("seed").description("Migrate, then run each database construct's
16521
16575
  try {
16522
16576
  const globalOptions = program.opts();
16523
16577
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16524
- const { seedCommand } = await import("./migrate-soUQtku3.mjs");
16578
+ const { seedCommand } = await import("./migrate-CHQyNzj-.mjs");
16525
16579
  await seedCommand({
16526
16580
  ...options,
16527
16581
  ...construct ? { construct } : {}
@@ -16535,7 +16589,7 @@ program.command("migration").description("Write a construct's next migration: an
16535
16589
  try {
16536
16590
  const globalOptions = program.opts();
16537
16591
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16538
- const { migrationCommand } = await import("./migrate-soUQtku3.mjs");
16592
+ const { migrationCommand } = await import("./migrate-CHQyNzj-.mjs");
16539
16593
  await migrationCommand({
16540
16594
  construct,
16541
16595
  ...name ? { name } : {}
@@ -16633,7 +16687,7 @@ program.command("encryption:rotate").description("Add a new current key to an En
16633
16687
  try {
16634
16688
  const globalOptions = program.opts();
16635
16689
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16636
- const { encryptionRotateCommand } = await import("./encryption-DRCXp-U4.mjs");
16690
+ const { encryptionRotateCommand } = await import("./encryption-O-XdeNxe.mjs");
16637
16691
  await encryptionRotateCommand(construct, options);
16638
16692
  } catch (error) {
16639
16693
  console.error(formatError(error));
@@ -16644,7 +16698,7 @@ program.command("encryption:retire").description("Remove an old key from an Encr
16644
16698
  try {
16645
16699
  const globalOptions = program.opts();
16646
16700
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16647
- const { encryptionRetireCommand } = await import("./encryption-DRCXp-U4.mjs");
16701
+ const { encryptionRetireCommand } = await import("./encryption-O-XdeNxe.mjs");
16648
16702
  await encryptionRetireCommand(construct, key, options);
16649
16703
  } catch (error) {
16650
16704
  console.error(formatError(error));
@@ -16696,7 +16750,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
16696
16750
  console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
16697
16751
  process.exit(1);
16698
16752
  }
16699
- const { derivedContainers } = await import("./workspace-Dp2zK_Nk.mjs").then((n) => n.o);
16753
+ const { derivedContainers } = await import("./workspace-qcva2dTt.mjs").then((n) => n.o);
16700
16754
  const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
16701
16755
  if (!result) {
16702
16756
  console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);