@geekmidas/cli 10.0.0-alpha.32 → 10.0.0-alpha.34

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 (57) hide show
  1. package/dist/{config-URVD4bTj.cjs → config-DMpzmsQL.cjs} +2 -2
  2. package/dist/{config-URVD4bTj.cjs.map → config-DMpzmsQL.cjs.map} +1 -1
  3. package/dist/{config-BH3Ki69F.mjs → config-Du8AQJRK.mjs} +2 -2
  4. package/dist/{config-BH3Ki69F.mjs.map → config-Du8AQJRK.mjs.map} +1 -1
  5. package/dist/config.cjs +2 -2
  6. package/dist/config.d.cts +2 -2
  7. package/dist/config.d.mts +2 -2
  8. package/dist/config.mjs +2 -2
  9. package/dist/discover-CMxesskG.mjs.map +1 -1
  10. package/dist/discover-CroTIm0K.cjs.map +1 -1
  11. package/dist/{github-BrDmlm1x.mjs → github-DN-92LWP.mjs} +3 -3
  12. package/dist/{github-BrDmlm1x.mjs.map → github-DN-92LWP.mjs.map} +1 -1
  13. package/dist/{github-B2fis34P.cjs → github-JhvrmjQp.cjs} +3 -3
  14. package/dist/{github-B2fis34P.cjs.map → github-JhvrmjQp.cjs.map} +1 -1
  15. package/dist/{index-p89EzILa.d.mts → index-CAp22ul5.d.cts} +2 -2
  16. package/dist/{index-p89EzILa.d.mts.map → index-CAp22ul5.d.cts.map} +1 -1
  17. package/dist/{index-rU9u761a.d.cts → index-DxXMtQNT.d.mts} +2 -2
  18. package/dist/{index-rU9u761a.d.cts.map → index-DxXMtQNT.d.mts.map} +1 -1
  19. package/dist/index.cjs +125 -81
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.mjs +126 -82
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/{migrate-CnPtWnkR.mjs → migrate-BbhXxQer.mjs} +4 -4
  24. package/dist/{migrate-CnPtWnkR.mjs.map → migrate-BbhXxQer.mjs.map} +1 -1
  25. package/dist/{migrate-BiasgAIN.cjs → migrate-u1oRHz6K.cjs} +4 -4
  26. package/dist/{migrate-BiasgAIN.cjs.map → migrate-u1oRHz6K.cjs.map} +1 -1
  27. package/dist/openapi.cjs +1 -1
  28. package/dist/openapi.d.cts +1 -1
  29. package/dist/openapi.d.mts +1 -1
  30. package/dist/openapi.mjs +1 -1
  31. package/dist/{ready-DXtNfk7v.cjs → ready-CXhoutix.cjs} +108 -25
  32. package/dist/ready-CXhoutix.cjs.map +1 -0
  33. package/dist/{ready-CvP3JVEw.mjs → ready-D1BCiaYU.mjs} +106 -29
  34. package/dist/ready-D1BCiaYU.mjs.map +1 -0
  35. package/dist/reconcile/public.d.cts +1 -1
  36. package/dist/reconcile/public.d.mts +1 -1
  37. package/dist/{types-CzK6hsXP.d.mts → types-BTiu5kwo.d.mts} +26 -1
  38. package/dist/{types-CzK6hsXP.d.mts.map → types-BTiu5kwo.d.mts.map} +1 -1
  39. package/dist/{types-DOOAevjG.d.cts → types-Bj_FpeTc.d.cts} +26 -1
  40. package/dist/{types-DOOAevjG.d.cts.map → types-Bj_FpeTc.d.cts.map} +1 -1
  41. package/dist/vitest.cjs +1 -1
  42. package/dist/vitest.mjs +1 -1
  43. package/dist/workspace/index.cjs +1 -1
  44. package/dist/workspace/index.d.cts +2 -2
  45. package/dist/workspace/index.d.mts +2 -2
  46. package/dist/workspace/index.mjs +1 -1
  47. package/dist/{workspace-Bav3TVrP.cjs → workspace-CAJk6UmC.cjs} +11 -4
  48. package/dist/{workspace-Bav3TVrP.cjs.map → workspace-CAJk6UmC.cjs.map} +1 -1
  49. package/dist/{workspace-T4IVGSoB.mjs → workspace-CsL76tpc.mjs} +11 -4
  50. package/dist/{workspace-T4IVGSoB.mjs.map → workspace-CsL76tpc.mjs.map} +1 -1
  51. package/dist/{workspace-C97QUCIf.mjs → workspace-DB2YHgOl.mjs} +4 -3
  52. package/dist/{workspace-C97QUCIf.mjs.map → workspace-DB2YHgOl.mjs.map} +1 -1
  53. package/dist/{workspace-BhiMkRuA.cjs → workspace-LKFnEBX8.cjs} +4 -3
  54. package/dist/{workspace-BhiMkRuA.cjs.map → workspace-LKFnEBX8.cjs.map} +1 -1
  55. package/package.json +14 -14
  56. package/dist/ready-CvP3JVEw.mjs.map +0 -1
  57. package/dist/ready-DXtNfk7v.cjs.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env -S npx tsx
2
2
  import { n as __require, t as __exportAll } from "./rolldown-runtime-BhDjJH2R.mjs";
3
3
  import { c as isPartitionedRoutes, i as ConstructGenerator, t as discover } from "./discover-CMxesskG.mjs";
4
- import { a as loadConfig, c as parseModuleConfig, i as loadAppConfig, l as appKey, r as getAppNameFromCwd, s as loadWorkspaceConfig, u as derivedApps } from "./config-BH3Ki69F.mjs";
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-T4IVGSoB.mjs";
4
+ import { a as loadConfig, c as parseModuleConfig, i as loadAppConfig, l as appKey, r as getAppNameFromCwd, s as loadWorkspaceConfig, u as derivedApps } from "./config-Du8AQJRK.mjs";
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-CsL76tpc.mjs";
6
6
  import { c as getKeyPath, i as setCustomSecret, n as readStageSecrets, o as toEmbeddableSecrets, r as secretsExist, s as writeStageSecrets, t as maskPassword } from "./storage-BjTLjDDp.mjs";
7
- import { _ as findAvailablePort, b as loadSecretsForApp, c as applyPostgres, d as cacheBackendFor, f as eventsBackendFor, g as createEntryWrapper, h as createCredentialsPreload, i as reconcileWorkspace, l as resourceName, m as storageBackendFor, n as constructGlobs, o as COMPOSE_PATH, p as providerOf, r as derivedContainers, s as LOCAL_CA_PATH, t as backendsOf, u as rootSite, v as isPortAvailable, x as prepareEntryCredentials, y as loadEnvFiles } from "./workspace-C97QUCIf.mjs";
7
+ import { _ as findAvailablePort, b as loadSecretsForApp, c as applyPostgres, d as cacheBackendFor, f as eventsBackendFor, g as createEntryWrapper, h as createCredentialsPreload, i as reconcileWorkspace, l as resourceName, m as storageBackendFor, n as constructGlobs, o as COMPOSE_PATH, p as providerOf, r as derivedContainers, s as LOCAL_CA_PATH, t as backendsOf, u as rootSite, v as isPortAvailable, x as prepareEntryCredentials, y as loadEnvFiles } from "./workspace-DB2YHgOl.mjs";
8
8
  import { n as EndpointGenerator, r as runtimeFor } from "./OpenApiTsGenerator-hDINScnz.mjs";
9
9
  import { generateOpenApi, openapiCommand, resolveOpenApiConfig } from "./openapi.mjs";
10
- import { a as cacheBackendsIn, i as writeTestHarness, n as TEST_READY_FILE, o as driversFor, r as TEST_MANIFEST_ENV, t as TEST_READY_ENV } from "./ready-CvP3JVEw.mjs";
10
+ import { a as writeTestHarness, i as TEST_MANIFEST_ENV, n as TEST_READY_FILE, o as cacheBackendsIn, s as driversFor, t as TEST_READY_ENV } from "./ready-D1BCiaYU.mjs";
11
11
  import { i as withRoutes, r as withCompute } from "./emit-Bzq7JsMP.mjs";
12
12
  import { a as createStageSecrets, c as generateServiceCredentials, i as writeDockerEnvFromSecrets, l as rotateServicePassword, o as generateConnectionUrls, r as generateFullstackCustomSecrets, s as generateSecurePassword, t as reconcileMissingSecrets } from "./reconcile-yNq6Shau.mjs";
13
13
  import { createRequire } from "node:module";
@@ -19,7 +19,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
19
19
  import { homedir } from "node:os";
20
20
  import { basename, dirname, isAbsolute, join, parse, relative, resolve } from "node:path";
21
21
  import { execFile, execSync, spawn } from "node:child_process";
22
- import { cacheTable, canonicalId, cloudName, cookieDomain, dependentsOf, migrationFolder, provideKey, provisionOrder, scopedName, serviceKey } from "@geekmidas/manifest";
22
+ import { cacheTable, canonicalId, cloudName, cookieDomain, dependentsOf, kebabCase, migrationFolder, provideKey, provisionOrder, scopedName, serviceKey } from "@geekmidas/manifest";
23
23
  import fg from "fast-glob";
24
24
  import chokidar from "chokidar";
25
25
  import { createCipheriv, createHash, randomBytes } from "node:crypto";
@@ -37,7 +37,7 @@ import { Subscriber } from "@geekmidas/constructs/subscribers";
37
37
  import { Topic } from "@geekmidas/constructs/topic";
38
38
  import { lookup } from "node:dns/promises";
39
39
  //#region package.json
40
- var version = "10.0.0-alpha.32";
40
+ var version = "10.0.0-alpha.34";
41
41
  //#endregion
42
42
  //#region src/auth/credentials.ts
43
43
  /**
@@ -1087,9 +1087,9 @@ async function workspaceDevCommand(workspace, options) {
1087
1087
  ...reconciled.env
1088
1088
  };
1089
1089
  if (options.migrate || options.seed) {
1090
- const { prepareDevDatabases } = await import("./migrate-CnPtWnkR.mjs");
1090
+ const { prepareDevDatabases } = await import("./migrate-BbhXxQer.mjs");
1091
1091
  await prepareDevDatabases(workspace, reconciled.env, { seed: !!options.seed });
1092
- } else await import("./migrate-CnPtWnkR.mjs").then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
1092
+ } else await import("./migrate-BbhXxQer.mjs").then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
1093
1093
  logger$10.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
1094
1094
  });
1095
1095
  const appUrls = {};
@@ -3102,6 +3102,7 @@ const PROVISIONERS = {
3102
3102
  context.deferred.push(...statementsFor({
3103
3103
  id: declaration.id,
3104
3104
  database: postgres.databaseName,
3105
+ ownsDatabase: true,
3105
3106
  runtime,
3106
3107
  owner,
3107
3108
  ...reads ? { reader: readerRole(runtime) } : {},
@@ -3337,6 +3338,7 @@ function statementsFor(options) {
3337
3338
  owner,
3338
3339
  ...reader ? { reader } : {},
3339
3340
  schema,
3341
+ ...options.ownsDatabase ? { database } : {},
3340
3342
  passwords: {
3341
3343
  runtime: derivedPassword(context, runtime),
3342
3344
  owner: derivedPassword(context, owner),
@@ -8635,7 +8637,27 @@ functions it called on the way.
8635
8637
  ${database ? "gkm test # starts services, injects secrets, then runs vitest" : "gkm test"}
8636
8638
  \`\`\`
8637
8639
 
8638
- Run tests through \`gkm test\`, not \`vitest\` directly${database ? " — it is what starts the database and injects the secrets the suite needs" : ""}.`;
8640
+ Run tests through \`gkm test\`, not \`vitest\` directly${database ? " — it is what starts the database and injects the secrets the suite needs" : ""}.${database ? `
8641
+
8642
+ **Factories, one per database.** \`test/factories/<construct>.ts\` at the
8643
+ project root — \`database.ts\` for \`Database\` — exports
8644
+ \`createFactory(db)\`. A feature test gets each by service name, on that
8645
+ test's transaction — the one \`db.get\` returns and its endpoints use — so
8646
+ ask for it rather than importing and building one. Sign in the way a person
8647
+ does, through \`browser.signIn\`:
8648
+
8649
+ \`\`\`typescript
8650
+ it('reads a user', async ({ browser, db, factories }) => {
8651
+ const factory = await factories.get('database');
8652
+ const ada = await factory.insert('users', { email: 'ada@example.com' });
8653
+
8654
+ await browser.signIn(ada.email);
8655
+ // … act through browser.api …
8656
+
8657
+ const app = await db.get('database');
8658
+ // … assert on what was written …
8659
+ });
8660
+ \`\`\`` : ""}`;
8639
8661
  }
8640
8662
  //#endregion
8641
8663
  //#region src/init/dependencies.ts
@@ -8763,26 +8785,26 @@ function loadPackageJson() {
8763
8785
  * Run: pnpm --filter @geekmidas/cli sync-versions
8764
8786
  */
8765
8787
  const GEEKMIDAS_VERSIONS = {
8766
- "@geekmidas/audit": "~10.0.0-alpha.32",
8767
- "@geekmidas/auth": "~10.0.0-alpha.32",
8768
- "@geekmidas/cache": "~10.0.0-alpha.32",
8769
- "@geekmidas/client": "~10.0.0-alpha.32",
8770
- "@geekmidas/cloud": "~10.0.0-alpha.32",
8771
- "@geekmidas/constructs": "~10.0.0-alpha.32",
8772
- "@geekmidas/db": "~10.0.0-alpha.32",
8773
- "@geekmidas/emailkit": "~10.0.0-alpha.32",
8774
- "@geekmidas/envkit": "~10.0.0-alpha.32",
8775
- "@geekmidas/errors": "~10.0.0-alpha.32",
8776
- "@geekmidas/events": "~10.0.0-alpha.32",
8777
- "@geekmidas/logger": "~10.0.0-alpha.32",
8778
- "@geekmidas/manifest": "~10.0.0-alpha.32",
8779
- "@geekmidas/rate-limit": "~10.0.0-alpha.32",
8780
- "@geekmidas/schema": "~10.0.0-alpha.32",
8781
- "@geekmidas/services": "~10.0.0-alpha.32",
8782
- "@geekmidas/storage": "~10.0.0-alpha.32",
8783
- "@geekmidas/studio": "~10.0.0-alpha.32",
8784
- "@geekmidas/telescope": "~10.0.0-alpha.32",
8785
- "@geekmidas/testkit": "~10.0.0-alpha.32",
8788
+ "@geekmidas/audit": "~10.0.0-alpha.34",
8789
+ "@geekmidas/auth": "~10.0.0-alpha.34",
8790
+ "@geekmidas/cache": "~10.0.0-alpha.34",
8791
+ "@geekmidas/client": "~10.0.0-alpha.34",
8792
+ "@geekmidas/cloud": "~10.0.0-alpha.34",
8793
+ "@geekmidas/constructs": "~10.0.0-alpha.34",
8794
+ "@geekmidas/db": "~10.0.0-alpha.34",
8795
+ "@geekmidas/emailkit": "~10.0.0-alpha.34",
8796
+ "@geekmidas/envkit": "~10.0.0-alpha.34",
8797
+ "@geekmidas/errors": "~10.0.0-alpha.34",
8798
+ "@geekmidas/events": "~10.0.0-alpha.34",
8799
+ "@geekmidas/logger": "~10.0.0-alpha.34",
8800
+ "@geekmidas/manifest": "~10.0.0-alpha.34",
8801
+ "@geekmidas/rate-limit": "~10.0.0-alpha.34",
8802
+ "@geekmidas/schema": "~10.0.0-alpha.34",
8803
+ "@geekmidas/services": "~10.0.0-alpha.34",
8804
+ "@geekmidas/storage": "~10.0.0-alpha.34",
8805
+ "@geekmidas/studio": "~10.0.0-alpha.34",
8806
+ "@geekmidas/telescope": "~10.0.0-alpha.34",
8807
+ "@geekmidas/testkit": "~10.0.0-alpha.34",
8786
8808
  "@geekmidas/cli": `~${loadPackageJson().version}`
8787
8809
  };
8788
8810
  //#endregion
@@ -10358,6 +10380,18 @@ function rootConstructDependencies(options) {
10358
10380
  };
10359
10381
  }
10360
10382
  /**
10383
+ * What `test/factories/` imports at the root: the factory and faker, and
10384
+ * Kysely's types where the root does not already install it for the
10385
+ * constructs.
10386
+ */
10387
+ function rootFactoryDependencies(options) {
10388
+ return {
10389
+ "@geekmidas/testkit": GEEKMIDAS_VERSIONS["@geekmidas/testkit"],
10390
+ "@faker-js/faker": DEPENDENCY_VERSIONS["@faker-js/faker"],
10391
+ ...options.template === "fullstack" ? {} : { kysely: DEPENDENCY_VERSIONS.kysely }
10392
+ };
10393
+ }
10394
+ /**
10361
10395
  * Generate monorepo root files (pnpm-workspace.yaml, root package.json, etc.)
10362
10396
  */
10363
10397
  function generateMonorepoFiles(options, _template) {
@@ -10396,6 +10430,7 @@ function generateMonorepoFiles(options, _template) {
10396
10430
  turbo: DEPENDENCY_VERSIONS["turbo"],
10397
10431
  typescript: TOOLCHAIN_VERSIONS["typescript"],
10398
10432
  vitest: TOOLCHAIN_VERSIONS["vitest"],
10433
+ ...options.constructs.database ? rootFactoryDependencies(options) : {},
10399
10434
  ...deploy.devDependencies
10400
10435
  }
10401
10436
  };
@@ -11976,9 +12011,9 @@ function generateSourceFiles(options, template) {
11976
12011
  //#endregion
11977
12012
  //#region src/init/generators/test.ts
11978
12013
  /**
11979
- * Generate test infrastructure files when database is enabled.
11980
- * Includes transaction-isolated test config,
11981
- * factory system with builders/seeds, and an example spec.
12014
+ * Generate test infrastructure files when database is enabled: the
12015
+ * transaction-isolated test config and an example spec, in the app. The
12016
+ * factory is the project's — see {@link generateTestFactoryFiles}.
11982
12017
  */
11983
12018
  function generateTestFiles(options, _template) {
11984
12019
  if (!options.constructs.database) return [];
@@ -11986,10 +12021,9 @@ function generateTestFiles(options, _template) {
11986
12021
  const schema = !options.monorepo ? "../src/constructs/database.ts" : `@${options.name}/constructs/database.ts`;
11987
12022
  db.urlKey;
11988
12023
  db.ownerUrlKey;
11989
- return [
11990
- {
11991
- path: "test/config.ts",
11992
- content: `import { it as itVitest } from 'vitest';
12024
+ return [{
12025
+ path: "test/config.ts",
12026
+ content: `import { it as itVitest } from 'vitest';
11993
12027
  import { wrapVitestKyselyTransaction } from '@geekmidas/testkit/kysely';
11994
12028
  import { type Database, database } from '${schema}';
11995
12029
 
@@ -11999,17 +12033,56 @@ export const it = wrapVitestKyselyTransaction<Database>(itVitest, {
11999
12033
  connection: database,
12000
12034
  });
12001
12035
  `
12002
- },
12003
- {
12004
- path: "test/factory/index.ts",
12005
- content: `import type { Kysely } from 'kysely';
12036
+ }, {
12037
+ path: "test/example.spec.ts",
12038
+ content: `import { describe, expect } from 'vitest';
12039
+ import { it } from './config.ts';
12040
+
12041
+ describe('example', () => {
12042
+ it('should have a working test setup', async ({ trx }) => {
12043
+ // trx is a Kysely transaction; everything in it is rolled back after the
12044
+ // test
12045
+ expect(trx).toBeDefined();
12046
+ });
12047
+ });
12048
+ `
12049
+ }];
12050
+ }
12051
+ /**
12052
+ * The database's test factory, at the project root:
12053
+ * `test/factories/<construct>.ts`.
12054
+ *
12055
+ * A factory belongs to a database, not to an app, so there is one per database
12056
+ * for the whole project. `gkm test` finds it by that name and hands every
12057
+ * feature test \`factories.get('database')\`, built on the test's transaction.
12058
+ */
12059
+ function generateTestFactoryFiles(options) {
12060
+ if (!options.constructs.database) return [];
12061
+ const db = databaseFor();
12062
+ const schema = options.monorepo && options.template === "fullstack" ? `@${options.name}/constructs/database.ts` : options.monorepo ? `../../${options.apiPath}/src/constructs/database.ts` : "../../src/constructs/database.ts";
12063
+ return [{
12064
+ path: `test/factories/${kebabCase(db.id)}.ts`,
12065
+ content: `import type { Kysely } from 'kysely';
12006
12066
  import { KyselyFactory } from '@geekmidas/testkit/kysely';
12007
12067
  import type { Database } from '${schema}';
12008
- import { usersBuilder } from './users.ts';
12068
+
12069
+ const usersBuilder = KyselyFactory.createBuilder<Database, 'users'>(
12070
+ 'users',
12071
+ ({ faker }) => ({
12072
+ id: faker.string.uuid(),
12073
+ name: faker.person.fullName(),
12074
+ email: faker.internet.email(),
12075
+ createdAt: new Date(),
12076
+ }),
12077
+ );
12009
12078
 
12010
12079
  const builders = { users: usersBuilder };
12011
12080
  const seeds = {};
12012
12081
 
12082
+ /**
12083
+ * This database's factory. \`gkm test\` builds it on each feature test's
12084
+ * transaction and hands it over as \`factories.get('${serviceKey(db.id)}')\`.
12085
+ */
12013
12086
  export function createFactory(db: Kysely<Database>) {
12014
12087
  return new KyselyFactory<Database, typeof builders, typeof seeds>(
12015
12088
  builders,
@@ -12020,38 +12093,7 @@ export function createFactory(db: Kysely<Database>) {
12020
12093
 
12021
12094
  export type Factory = ReturnType<typeof createFactory>;
12022
12095
  `
12023
- },
12024
- {
12025
- path: "test/factory/users.ts",
12026
- content: `import { KyselyFactory } from '@geekmidas/testkit/kysely';
12027
- import type { Database } from '${schema}';
12028
-
12029
- export const usersBuilder = KyselyFactory.createBuilder<Database, 'users'>(
12030
- 'users',
12031
- ({ faker }) => ({
12032
- id: faker.string.uuid(),
12033
- name: faker.person.fullName(),
12034
- email: faker.internet.email(),
12035
- createdAt: new Date(),
12036
- }),
12037
- );
12038
- `
12039
- },
12040
- {
12041
- path: "test/example.spec.ts",
12042
- content: `import { describe, expect } from 'vitest';
12043
- import { it } from './config.ts';
12044
-
12045
- describe('example', () => {
12046
- it('should have a working test setup', async ({ trx }) => {
12047
- // trx is a Kysely transaction; everything in it is rolled back after the
12048
- // test
12049
- expect(trx).toBeDefined();
12050
- });
12051
- });
12052
- `
12053
- }
12054
- ];
12096
+ }];
12055
12097
  }
12056
12098
  //#endregion
12057
12099
  //#region src/init/generators/ui.ts
@@ -14521,7 +14563,8 @@ async function initCommand(projectName, options = {}) {
14521
14563
  ...generateGithubFiles(templateOptions),
14522
14564
  ...generateMonorepoFiles(templateOptions, baseTemplate),
14523
14565
  ...generateRootConstructs(templateOptions),
14524
- ...generateModelsPackage(templateOptions)
14566
+ ...generateModelsPackage(templateOptions),
14567
+ ...generateTestFactoryFiles(templateOptions)
14525
14568
  ] : [];
14526
14569
  const webAppFiles = isFullstack ? frontendFramework === "tanstack-start" ? generateTanStackWebFiles(templateOptions) : frontendFramework === "expo" ? generateExpoAppFiles(templateOptions) : generateWebAppFiles(templateOptions) : [];
14527
14570
  const authAppFiles = isFullstack ? generateAuthAppFiles(templateOptions) : [];
@@ -14984,7 +15027,7 @@ var NoStoredSecrets = class extends Error {
14984
15027
  }
14985
15028
  };
14986
15029
  async function reconcile(secrets, workspace, stage) {
14987
- const { derivedContainers } = await import("./workspace-C97QUCIf.mjs").then((n) => n.a);
15030
+ const { derivedContainers } = await import("./workspace-DB2YHgOl.mjs").then((n) => n.a);
14988
15031
  const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
14989
15032
  return result ? {
14990
15033
  secrets: result.secrets,
@@ -15328,7 +15371,8 @@ async function testCommand(options = {}) {
15328
15371
  patterns: constructGlobs(workspace),
15329
15372
  cacheBackend: backendsOf(workspace).cache,
15330
15373
  stage: TEST_STAGE,
15331
- env: finalCredentials
15374
+ env: finalCredentials,
15375
+ factories: join(workspace.root, workspace.test.factories ?? "test/factories")
15332
15376
  }) : void 0;
15333
15377
  if (options.prepare) {
15334
15378
  console.log(manifestPath ? ` 🧪 Test harness written beside ${manifestPath}` : " 🧪 Nothing to prepare: this project declares no constructs");
@@ -15382,7 +15426,7 @@ async function testCommand(options = {}) {
15382
15426
  * starts without the reference data the app needs.
15383
15427
  */
15384
15428
  async function migrateTestStage(workspace, env) {
15385
- const { migrateAndSeed } = await import("./migrate-CnPtWnkR.mjs");
15429
+ const { migrateAndSeed } = await import("./migrate-BbhXxQer.mjs");
15386
15430
  const { discover } = await import("./discover-CMxesskG.mjs").then((n) => n.n);
15387
15431
  const sources = {};
15388
15432
  const manifest = await discover({
@@ -15827,7 +15871,7 @@ program.command("migrate").description("Apply each database construct's migratio
15827
15871
  try {
15828
15872
  const globalOptions = program.opts();
15829
15873
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
15830
- const { migrateCommand } = await import("./migrate-CnPtWnkR.mjs");
15874
+ const { migrateCommand } = await import("./migrate-BbhXxQer.mjs");
15831
15875
  await migrateCommand({
15832
15876
  ...options,
15833
15877
  ...construct ? { construct } : {}
@@ -15841,7 +15885,7 @@ program.command("seed").description("Migrate, then run each database construct's
15841
15885
  try {
15842
15886
  const globalOptions = program.opts();
15843
15887
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
15844
- const { seedCommand } = await import("./migrate-CnPtWnkR.mjs");
15888
+ const { seedCommand } = await import("./migrate-BbhXxQer.mjs");
15845
15889
  await seedCommand({
15846
15890
  ...options,
15847
15891
  ...construct ? { construct } : {}
@@ -15855,7 +15899,7 @@ program.command("migration").description("Write a construct's next migration: an
15855
15899
  try {
15856
15900
  const globalOptions = program.opts();
15857
15901
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
15858
- const { migrationCommand } = await import("./migrate-CnPtWnkR.mjs");
15902
+ const { migrationCommand } = await import("./migrate-BbhXxQer.mjs");
15859
15903
  await migrationCommand({
15860
15904
  construct,
15861
15905
  ...name ? { name } : {}
@@ -16023,7 +16067,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
16023
16067
  console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
16024
16068
  process.exit(1);
16025
16069
  }
16026
- const { derivedContainers } = await import("./workspace-C97QUCIf.mjs").then((n) => n.a);
16070
+ const { derivedContainers } = await import("./workspace-DB2YHgOl.mjs").then((n) => n.a);
16027
16071
  const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
16028
16072
  if (!result) {
16029
16073
  console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);
@@ -16082,7 +16126,7 @@ program.command("deploy:github").description("Let GitHub Actions deploy a stage:
16082
16126
  try {
16083
16127
  const globalOptions = program.opts();
16084
16128
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16085
- const { deployGithubCommand } = await import("./github-BrDmlm1x.mjs");
16129
+ const { deployGithubCommand } = await import("./github-DN-92LWP.mjs");
16086
16130
  await deployGithubCommand(options);
16087
16131
  } catch (error) {
16088
16132
  console.error(formatError(error));