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

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.
package/dist/index.cjs CHANGED
@@ -5,7 +5,7 @@ const require_discover = require("./discover-CroTIm0K.cjs");
5
5
  const require_config = require("./config-DgAHy8nY.cjs");
6
6
  const require_workspace = require("./workspace-CAJk6UmC.cjs");
7
7
  const require_storage = require("./storage-C2JC31V9.cjs");
8
- const require_workspace$1 = require("./workspace-CRjZkCTW.cjs");
8
+ const require_workspace$1 = require("./workspace-DUhLejv4.cjs");
9
9
  const require_OpenApiTsGenerator = require("./OpenApiTsGenerator-D1nhN98m.cjs");
10
10
  const require_openapi = require("./openapi.cjs");
11
11
  const require_ready = require("./ready-CXhoutix.cjs");
@@ -42,7 +42,7 @@ let _geekmidas_constructs_subscribers = require("@geekmidas/constructs/subscribe
42
42
  let _geekmidas_constructs_topic = require("@geekmidas/constructs/topic");
43
43
  let node_dns_promises = require("node:dns/promises");
44
44
  //#region package.json
45
- var version = "10.0.0-alpha.35";
45
+ var version = "10.0.0-alpha.37";
46
46
  //#endregion
47
47
  //#region src/auth/credentials.ts
48
48
  /**
@@ -1092,9 +1092,9 @@ async function workspaceDevCommand(workspace, options) {
1092
1092
  ...reconciled.env
1093
1093
  };
1094
1094
  if (options.migrate || options.seed) {
1095
- const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-nlvT-GnY.cjs"));
1095
+ const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-Cgga-OGi.cjs"));
1096
1096
  await prepareDevDatabases(workspace, reconciled.env, { seed: !!options.seed });
1097
- } else await Promise.resolve().then(() => require("./migrate-nlvT-GnY.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
1097
+ } else await Promise.resolve().then(() => require("./migrate-Cgga-OGi.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
1098
1098
  logger$10.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
1099
1099
  });
1100
1100
  const appUrls = {};
@@ -8809,26 +8809,26 @@ function loadPackageJson() {
8809
8809
  * Run: pnpm --filter @geekmidas/cli sync-versions
8810
8810
  */
8811
8811
  const GEEKMIDAS_VERSIONS = {
8812
- "@geekmidas/audit": "~10.0.0-alpha.35",
8813
- "@geekmidas/auth": "~10.0.0-alpha.35",
8814
- "@geekmidas/cache": "~10.0.0-alpha.35",
8815
- "@geekmidas/client": "~10.0.0-alpha.35",
8816
- "@geekmidas/cloud": "~10.0.0-alpha.35",
8817
- "@geekmidas/constructs": "~10.0.0-alpha.35",
8818
- "@geekmidas/db": "~10.0.0-alpha.35",
8819
- "@geekmidas/emailkit": "~10.0.0-alpha.35",
8820
- "@geekmidas/envkit": "~10.0.0-alpha.35",
8821
- "@geekmidas/errors": "~10.0.0-alpha.35",
8822
- "@geekmidas/events": "~10.0.0-alpha.35",
8823
- "@geekmidas/logger": "~10.0.0-alpha.35",
8824
- "@geekmidas/manifest": "~10.0.0-alpha.35",
8825
- "@geekmidas/rate-limit": "~10.0.0-alpha.35",
8826
- "@geekmidas/schema": "~10.0.0-alpha.35",
8827
- "@geekmidas/services": "~10.0.0-alpha.35",
8828
- "@geekmidas/storage": "~10.0.0-alpha.35",
8829
- "@geekmidas/studio": "~10.0.0-alpha.35",
8830
- "@geekmidas/telescope": "~10.0.0-alpha.35",
8831
- "@geekmidas/testkit": "~10.0.0-alpha.35",
8812
+ "@geekmidas/audit": "~10.0.0-alpha.37",
8813
+ "@geekmidas/auth": "~10.0.0-alpha.37",
8814
+ "@geekmidas/cache": "~10.0.0-alpha.37",
8815
+ "@geekmidas/client": "~10.0.0-alpha.37",
8816
+ "@geekmidas/cloud": "~10.0.0-alpha.37",
8817
+ "@geekmidas/constructs": "~10.0.0-alpha.37",
8818
+ "@geekmidas/db": "~10.0.0-alpha.37",
8819
+ "@geekmidas/emailkit": "~10.0.0-alpha.37",
8820
+ "@geekmidas/envkit": "~10.0.0-alpha.37",
8821
+ "@geekmidas/errors": "~10.0.0-alpha.37",
8822
+ "@geekmidas/events": "~10.0.0-alpha.37",
8823
+ "@geekmidas/logger": "~10.0.0-alpha.37",
8824
+ "@geekmidas/manifest": "~10.0.0-alpha.37",
8825
+ "@geekmidas/rate-limit": "~10.0.0-alpha.37",
8826
+ "@geekmidas/schema": "~10.0.0-alpha.37",
8827
+ "@geekmidas/services": "~10.0.0-alpha.37",
8828
+ "@geekmidas/storage": "~10.0.0-alpha.37",
8829
+ "@geekmidas/studio": "~10.0.0-alpha.37",
8830
+ "@geekmidas/telescope": "~10.0.0-alpha.37",
8831
+ "@geekmidas/testkit": "~10.0.0-alpha.37",
8832
8832
  "@geekmidas/cli": `~${loadPackageJson().version}`
8833
8833
  };
8834
8834
  //#endregion
@@ -9607,9 +9607,7 @@ import { EnvironmentParser } from '@geekmidas/envkit';
9607
9607
  * \`MobileApp\` construct's \`.dependsOn([api, auth])\` is where every value
9608
9608
  * here comes from, so none of it is written down.
9609
9609
  *
9610
- * - \`APP_SCHEME\`: the URL scheme for this stage — \`${scheme}\` deployed,
9611
- * \`${scheme}-dev\` locally, so a development build and the store build on
9612
- * one phone never answer each other's links.
9610
+ * - \`APP_SCHEME\`: the URL scheme — \`${scheme}\`, the same on every stage.
9613
9611
  * - \`EXPO_PUBLIC_API_URL\` / \`EXPO_PUBLIC_AUTH_URL\`: where the servers
9614
9612
  * answer. Locally that is their own port on \`localhost\`, which
9615
9613
  * \`config.ts\` points at the machine Metro was served from.
@@ -10920,7 +10918,7 @@ export const authDb = database.schema<Record<string, never>, 'AuthDb'>('AuthDb')
10920
10918
  files.push(usersMigration());
10921
10919
  files.push({
10922
10920
  path: "constructs/auth.ts",
10923
- content: `import { BetterAuth } from '@geekmidas/constructs/auth';
10921
+ content: `${frontendFramework === "expo" ? "import { expo } from '@better-auth/expo';\n" : ""}import { BetterAuth } from '@geekmidas/constructs/auth';
10924
10922
  import { authDb } from './database.ts';
10925
10923
 
10926
10924
  /**
@@ -10935,7 +10933,11 @@ import { authDb } from './database.ts';
10935
10933
  export const auth = new BetterAuth('Auth', {
10936
10934
  path: 'apps/auth',
10937
10935
  database: authDb,
10938
- basePath: '/api/auth',
10936
+ basePath: '/api/auth',${frontendFramework === "expo" ? `
10937
+ // The mobile app signs in through Better Auth's Expo plugin: it sends its
10938
+ // scheme as the origin, and this is what reads it. The construct refuses to
10939
+ // start without it once a MobileApp depends on this server.
10940
+ options: { plugins: [expo()] },` : ""}
10939
10941
  });
10940
10942
  `
10941
10943
  });
@@ -10974,7 +10976,7 @@ import { auth } from './auth.ts';
10974
10976
  * The mobile app — a construct like a site, which is what makes it an app.
10975
10977
  *
10976
10978
  * \`.dependsOn()\` is the single fact behind what a mobile app otherwise has
10977
- * written down by hand: its API and auth URLs, its URL scheme per stage, the
10979
+ * written down by hand: its API and auth URLs, its URL scheme, the
10978
10980
  * scheme in the auth server's trusted origins, Better Auth's Expo plugin, and
10979
10981
  * sign-in links a phone can open.
10980
10982
  */
@@ -15158,7 +15160,7 @@ var NoStoredSecrets = class extends Error {
15158
15160
  }
15159
15161
  };
15160
15162
  async function reconcile(secrets, workspace, stage) {
15161
- const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-CRjZkCTW.cjs")).then((n) => n.workspace_exports);
15163
+ const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-DUhLejv4.cjs")).then((n) => n.workspace_exports);
15162
15164
  const result = require_reconcile.reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
15163
15165
  return result ? {
15164
15166
  secrets: result.secrets,
@@ -15457,6 +15459,56 @@ function printSummary(workspace, stage) {
15457
15459
  logger$1.log("");
15458
15460
  }
15459
15461
  //#endregion
15462
+ //#region src/test/teardown.ts
15463
+ /**
15464
+ * Dropping the test stage's databases when a suite ends.
15465
+ *
15466
+ * Reconcile never drops — the line it draws is at data. The test stage's data
15467
+ * is the exception: every test runs in a transaction rolled back after it, so
15468
+ * nothing in these databases is anyone's, and a database kept between runs is
15469
+ * one whose migrations already ran — an edited migration is never applied to
15470
+ * it again. So each run starts from a database it created, and drops it when
15471
+ * the suite ends: the Vitest global setup's teardown.
15472
+ */
15473
+ /**
15474
+ * Drop the databases the last setup recorded, and forget the test stage's
15475
+ * reconcile, so the next run provisions them from nothing.
15476
+ *
15477
+ * A no-op when nothing is recorded — no run yet, or one already torn down —
15478
+ * so running it twice, or before a setup, is harmless.
15479
+ */
15480
+ async function dropTestDatabases(cwd, root, sql = require_workspace$1.pgClient) {
15481
+ const readyPath = (0, node_path.join)(cwd, require_ready.TEST_READY_FILE);
15482
+ const ready = await readReady(readyPath);
15483
+ const recorded = ready?.databases;
15484
+ if (!ready || !recorded) return [];
15485
+ const client = sql(recorded.port);
15486
+ for (const name of recorded.names) {
15487
+ if (!name.endsWith(`_test`)) throw new NotATestDatabase(name);
15488
+ await client.query(void 0, `DROP DATABASE IF EXISTS ${require_workspace$1.quoteIdentifier(name)} WITH (FORCE)`);
15489
+ }
15490
+ await require_workspace$1.forgetState(root, require_workspace.TEST_STAGE);
15491
+ const { databases: _dropped, ...rest } = ready;
15492
+ await (0, node_fs_promises.writeFile)(readyPath, JSON.stringify(rest, null, 2));
15493
+ return recorded.names;
15494
+ }
15495
+ async function readReady(path) {
15496
+ try {
15497
+ return JSON.parse(await (0, node_fs_promises.readFile)(path, "utf-8"));
15498
+ } catch {
15499
+ return;
15500
+ }
15501
+ }
15502
+ /** A name recorded for the test stage without the test stage's suffix. */
15503
+ var NotATestDatabase = class extends Error {
15504
+ database;
15505
+ constructor(database) {
15506
+ super(`Refusing to drop '${database}': only the test stage's databases (named '…_${require_workspace.TEST_STAGE}') are dropped after a suite. Delete ${require_ready.TEST_READY_FILE} if it was edited by hand.`);
15507
+ this.database = database;
15508
+ this.name = "NotATestDatabase";
15509
+ }
15510
+ };
15511
+ //#endregion
15460
15512
  //#region src/test/index.ts
15461
15513
  /**
15462
15514
  * Run tests with secrets, dependency URLs, and .env files loaded.
@@ -15465,6 +15517,10 @@ function printSummary(workspace, stage) {
15465
15517
  async function testCommand(options = {}) {
15466
15518
  const cwd = process.cwd();
15467
15519
  const stage = options.stage ?? await require_config.loadWorkspaceConfig(cwd).then((loaded) => loaded.workspace.stages.local).catch(() => void 0);
15520
+ if (options.teardown) {
15521
+ await teardown(cwd);
15522
+ return;
15523
+ }
15468
15524
  if (!stage) throw new NoStageToTest();
15469
15525
  console.log(`\n🧪 Running tests with ${stage} environment...\n`);
15470
15526
  if (options.autoSetup || Boolean(process.env.GKM_AUTO_SETUP)) {
@@ -15473,6 +15529,7 @@ async function testCommand(options = {}) {
15473
15529
  }
15474
15530
  const defaultEnv = require_workspace$1.loadEnvFiles(".env");
15475
15531
  if (defaultEnv.loaded.length > 0) console.log(` 📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
15532
+ if (!options.prepare) await teardown(cwd);
15476
15533
  const result = await require_workspace$1.prepareEntryCredentials({
15477
15534
  stage,
15478
15535
  startDocker: !options.prepare,
@@ -15513,7 +15570,8 @@ async function testCommand(options = {}) {
15513
15570
  const readyPath = (0, node_path.join)(cwd, require_ready.TEST_READY_FILE);
15514
15571
  await (0, node_fs_promises.writeFile)(readyPath, JSON.stringify({
15515
15572
  env: result.secretsJsonPath,
15516
- ...manifestPath ? { manifest: manifestPath } : {}
15573
+ ...manifestPath ? { manifest: manifestPath } : {},
15574
+ ...testDatabases(result.reconciled)
15517
15575
  }, null, 2));
15518
15576
  if (options.setup) {
15519
15577
  console.log(` 🧪 Test stage ready: ${require_ready.TEST_READY_FILE}`);
@@ -15552,12 +15610,29 @@ async function testCommand(options = {}) {
15552
15610
  });
15553
15611
  });
15554
15612
  }
15613
+ /** Drop what the last setup created — see `dropTestDatabases`. */
15614
+ async function teardown(cwd) {
15615
+ const dropped = await dropTestDatabases(cwd, await require_config.loadWorkspaceConfig(cwd).then((loaded) => loaded.workspace.root).catch(() => cwd));
15616
+ if (dropped.length > 0) console.log(` 🧹 Dropped ${dropped.join(", ")}`);
15617
+ }
15618
+ /**
15619
+ * The test stage's Postgres databases, to drop when the suite ends — those
15620
+ * the plan provisions, on the port the shared container answers.
15621
+ */
15622
+ function testDatabases(reconciled) {
15623
+ const port = reconciled?.ports[require_workspace$1.primaryPortKey("postgres")];
15624
+ const names = (reconciled?.plan.resources ?? []).filter((resource) => resource.kind === "database" && resource.provisions && resource.container === "postgres").map((resource) => resource.name);
15625
+ return port !== void 0 && names.length > 0 ? { databases: {
15626
+ port,
15627
+ names
15628
+ } } : {};
15629
+ }
15555
15630
  /**
15556
15631
  * Migrate the test stage just reconciled, then seed it: a test run never
15557
15632
  * starts without the reference data the app needs.
15558
15633
  */
15559
15634
  async function migrateTestStage(workspace, env) {
15560
- const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-nlvT-GnY.cjs"));
15635
+ const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-Cgga-OGi.cjs"));
15561
15636
  const { discover } = await Promise.resolve().then(() => require("./discover-CroTIm0K.cjs")).then((n) => n.discover_exports);
15562
15637
  const sources = {};
15563
15638
  const manifest = await discover({
@@ -15985,7 +16060,7 @@ program.command("exec").description("Run a command with secrets injected into Cr
15985
16060
  process.exit(1);
15986
16061
  }
15987
16062
  });
15988
- program.command("test").description("Run tests with secrets loaded from environment").option("--stage <stage>", "Stage to load secrets from (default: stages.local)").option("--run", "Run tests once without watch mode").option("--watch", "Enable watch mode").option("--coverage", "Generate coverage report").option("--ui", "Open Vitest UI").option("--auto-setup", "Generate a fresh stage (secrets + key) from the workspace config when none exists (for CI; also via GKM_AUTO_SETUP)").option("--prepare", "Write the test manifest and #test harness, then stop — for a typecheck that runs before the suite").option("--setup", "Reconcile, migrate and seed the test stage and write the harness, then stop — what @geekmidas/cli/vitest runs").argument("[pattern]", "Pattern to filter tests").action(async (pattern, options) => {
16063
+ program.command("test").description("Run tests with secrets loaded from environment").option("--stage <stage>", "Stage to load secrets from (default: stages.local)").option("--run", "Run tests once without watch mode").option("--watch", "Enable watch mode").option("--coverage", "Generate coverage report").option("--ui", "Open Vitest UI").option("--auto-setup", "Generate a fresh stage (secrets + key) from the workspace config when none exists (for CI; also via GKM_AUTO_SETUP)").option("--prepare", "Write the test manifest and #test harness, then stop — for a typecheck that runs before the suite").option("--setup", "Reconcile, migrate and seed the test stage and write the harness, then stop — what @geekmidas/cli/vitest runs").option("--teardown", "Drop the test stage's databases the last setup created, then stop — what @geekmidas/cli/vitest runs when the suite ends").argument("[pattern]", "Pattern to filter tests").action(async (pattern, options) => {
15989
16064
  try {
15990
16065
  const globalOptions = program.opts();
15991
16066
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
@@ -16002,7 +16077,7 @@ program.command("migrate").description("Apply each database construct's migratio
16002
16077
  try {
16003
16078
  const globalOptions = program.opts();
16004
16079
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16005
- const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-nlvT-GnY.cjs"));
16080
+ const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-Cgga-OGi.cjs"));
16006
16081
  await migrateCommand({
16007
16082
  ...options,
16008
16083
  ...construct ? { construct } : {}
@@ -16016,7 +16091,7 @@ program.command("seed").description("Migrate, then run each database construct's
16016
16091
  try {
16017
16092
  const globalOptions = program.opts();
16018
16093
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16019
- const { seedCommand } = await Promise.resolve().then(() => require("./migrate-nlvT-GnY.cjs"));
16094
+ const { seedCommand } = await Promise.resolve().then(() => require("./migrate-Cgga-OGi.cjs"));
16020
16095
  await seedCommand({
16021
16096
  ...options,
16022
16097
  ...construct ? { construct } : {}
@@ -16030,7 +16105,7 @@ program.command("migration").description("Write a construct's next migration: an
16030
16105
  try {
16031
16106
  const globalOptions = program.opts();
16032
16107
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16033
- const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-nlvT-GnY.cjs"));
16108
+ const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-Cgga-OGi.cjs"));
16034
16109
  await migrationCommand({
16035
16110
  construct,
16036
16111
  ...name ? { name } : {}
@@ -16198,7 +16273,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
16198
16273
  console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
16199
16274
  process.exit(1);
16200
16275
  }
16201
- const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-CRjZkCTW.cjs")).then((n) => n.workspace_exports);
16276
+ const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-DUhLejv4.cjs")).then((n) => n.workspace_exports);
16202
16277
  const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
16203
16278
  if (!result) {
16204
16279
  console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);