gencow 0.1.200 → 0.1.201

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.
@@ -15,17 +15,21 @@ export function readProjectAppTargets(cwd = process.cwd()) {
15
15
  }
16
16
  const gencowJsonPath = resolveProjectMetadataPath(projectDir, resolve);
17
17
  if (!existsSync(gencowJsonPath)) {
18
- return { appId: null, prodApp: null };
18
+ return { appId: null, invalid: false, prodApp: null };
19
19
  }
20
20
 
21
21
  try {
22
22
  const gencowJson = JSON.parse(readFileSync(gencowJsonPath, "utf8"));
23
+ if (!gencowJson || typeof gencowJson !== "object" || Array.isArray(gencowJson)) {
24
+ return { appId: null, invalid: true, prodApp: null };
25
+ }
23
26
  return {
24
27
  appId: gencowJson.appId || gencowJson.appName || null,
28
+ invalid: false,
25
29
  prodApp: gencowJson.prodApp || null,
26
30
  };
27
31
  } catch {
28
- return { appId: null, prodApp: null };
32
+ return { appId: null, invalid: true, prodApp: null };
29
33
  }
30
34
  }
31
35
 
@@ -52,15 +56,18 @@ export function resolveCloudAppTarget(restArgs, options = {}) {
52
56
  }
53
57
 
54
58
  const projectTargets = readProjectAppTargets(cwd);
59
+ if (projectTargets.invalid) {
60
+ return { error: "MIGRATION_PROJECT_CONFIG_INVALID" };
61
+ }
55
62
  if (!appId) {
56
63
  appId = envTarget === "prod" ? projectTargets.prodApp : projectTargets.appId;
57
64
  }
58
65
 
59
66
  if (envTarget === "prod") {
60
- if (!projectTargets.prodApp) {
67
+ if (!projectTargets.prodApp && !explicitApp) {
61
68
  return { error: missingProdMessage };
62
69
  }
63
- if (explicitApp && appId !== projectTargets.prodApp) {
70
+ if (explicitApp && projectTargets.prodApp && appId !== projectTargets.prodApp) {
64
71
  return { error: missingProdMessage };
65
72
  }
66
73
  }
@@ -5,7 +5,11 @@ import {
5
5
  formatAuthSchemaConflictMessage,
6
6
  } from "./auth-schema-provenance-guard.mjs";
7
7
  import { loadToolingRuntime } from "./tooling-runtime.mjs";
8
- import { getCliInvocationSelection, resolveProjectSelection, selectCodegenClient } from "./project-context.mjs";
8
+ import {
9
+ getCliInvocationSelection,
10
+ resolveProjectSelection,
11
+ selectCodegenClient,
12
+ } from "./project-context.mjs";
9
13
 
10
14
  export { formatAuthSchemaConflictMessage } from "./auth-schema-provenance-guard.mjs";
11
15
 
@@ -187,19 +191,20 @@ export async function runCodegenWithReporting({
187
191
  outDir = resolveCodegenArtifactsDir(cwd),
188
192
  publishDir = resolveCodegenPublishDir(cwd, config),
189
193
  resolvePathImpl = resolve,
190
- serverPublishDir = resolveCodegenServerPublishDir(cwd, config),
194
+ serverPublishDir,
191
195
  successImpl,
192
196
  }) {
193
197
  const bundled = await (loadCodegenBundleImpl ?? loadCodegenBundleDefault)();
194
198
 
195
199
  const codegenResolved = resolveCodegenConfig(config);
200
+ const effectiveServerPublishDir = serverPublishDir ?? resolveCodegenServerPublishDir(cwd, config);
196
201
  const result = await bundled.runCodegen({
197
202
  projectRoot: cwd,
198
203
  rootDir: resolveBackendRootDir(config),
199
204
  schema: config.schema,
200
205
  outDir,
201
206
  finalOutDir: publishDir,
202
- serverPublishDir: codegenResolved.serverOutDir ?? undefined,
207
+ serverPublishDir,
203
208
  cloudFeatures: config.cloudFeatures,
204
209
  authSchema: codegenResolved.authSchema
205
210
  ? { emitRelations: codegenResolved.authSchemaEmitRelations }
@@ -213,7 +218,7 @@ export async function runCodegenWithReporting({
213
218
  cwd,
214
219
  publishDir,
215
220
  resolvePathImpl,
216
- serverPublishDir,
221
+ serverPublishDir: effectiveServerPublishDir,
217
222
  successImpl,
218
223
  });
219
224
  logCodegenDiagnostics(logImpl, result.diagnostics, diagnosticsColors);
@@ -288,7 +293,12 @@ export function createCodegenCommand(deps) {
288
293
  }
289
294
  const declaredCodegenClients = getDeclaredCodegenClients(config);
290
295
  const explicitSelection = explicitTarget ?? getCliInvocationSelection()?.target ?? null;
291
- if (Array.isArray(config?.clients) && config.clients.length > 0 && declaredCodegenClients.length === 0 && !outdir) {
296
+ if (
297
+ Array.isArray(config?.clients) &&
298
+ config.clients.length > 0 &&
299
+ declaredCodegenClients.length === 0 &&
300
+ !outdir
301
+ ) {
292
302
  deps.errorImpl(
293
303
  "No declared codegen client found. Add clients[*].codegen.outDir or pass --outdir for a one-off output.",
294
304
  );
@@ -336,7 +346,6 @@ export function createCodegenCommand(deps) {
336
346
  outDir: artifactsDir,
337
347
  publishDir,
338
348
  resolvePathImpl: deps.resolvePathImpl,
339
- serverPublishDir,
340
349
  successImpl: deps.successImpl,
341
350
  });
342
351
  deps.successImpl("Codegen completed successfully.");
@@ -36,7 +36,7 @@ export function resolveDbCloudTarget(args, gencowJson = null) {
36
36
  platformUrl = gencowJson.platformUrl || null;
37
37
  if (isProd) {
38
38
  const prodApp = gencowJson.prodApp || null;
39
- const appId = prodApp && (!explicitAppId || explicitAppId === prodApp) ? prodApp : null;
39
+ const appId = prodApp ? (!explicitAppId || explicitAppId === prodApp ? prodApp : null) : explicitAppId;
40
40
  return { appId, isProd, platformUrl };
41
41
  }
42
42
  return { appId: explicitAppId || gencowJson.appId || gencowJson.appName || null, isProd, platformUrl };
@@ -17,6 +17,8 @@ export async function writeCanonicalDeployBundle({
17
17
  backendRoot,
18
18
  dependencyAuditManifest,
19
19
  existsSyncImpl,
20
+ generatedServerPublishDir,
21
+ generatedServerRelativeDir,
20
22
  cpSyncImpl,
21
23
  generatorVersion,
22
24
  lockfileSelection,
@@ -43,12 +45,13 @@ export async function writeCanonicalDeployBundle({
43
45
  canonicalBackendDir: bundleBackendRoot,
44
46
  })
45
47
  : null;
46
- const canonicalBundleProjectConfig = hasSelectedProjectConfigFile && projectConfig
47
- ? canonicalizeBundleProjectConfig(projectConfig, {
48
- backendDir: backendRoot,
49
- canonicalBackendDir: bundleBackendRoot,
50
- })
51
- : null;
48
+ const canonicalBundleProjectConfig =
49
+ hasSelectedProjectConfigFile && projectConfig
50
+ ? canonicalizeBundleProjectConfig(projectConfig, {
51
+ backendDir: backendRoot,
52
+ canonicalBackendDir: bundleBackendRoot,
53
+ })
54
+ : null;
52
55
  const envExcludes = buildBackendEnvExcludePatterns(
53
56
  canonicalBundleProjectConfig ?? canonicalManifestConfig ?? { rootDir: `./${bundleBackendRoot}` },
54
57
  );
@@ -58,6 +61,20 @@ export async function writeCanonicalDeployBundle({
58
61
  rmSyncImpl(bundleStagingDir, { recursive: true, force: true });
59
62
  mkdirSyncImpl(bundleStagingDir, { recursive: true });
60
63
  cpSyncImpl(sourceBackendDir, resolvePathImpl(bundleStagingDir, bundleBackendRoot), { recursive: true });
64
+ if (
65
+ generatedServerPublishDir &&
66
+ generatedServerRelativeDir &&
67
+ existsSyncImpl(generatedServerPublishDir)
68
+ ) {
69
+ const generatedServerTarget = resolvePathImpl(
70
+ bundleStagingDir,
71
+ bundleBackendRoot,
72
+ generatedServerRelativeDir,
73
+ );
74
+ rmSyncImpl(generatedServerTarget, { recursive: true, force: true });
75
+ mkdirSyncImpl(dirname(generatedServerTarget), { recursive: true });
76
+ cpSyncImpl(generatedServerPublishDir, generatedServerTarget, { recursive: true });
77
+ }
61
78
 
62
79
  if (canonicalBundleProjectConfig) {
63
80
  writeCanonicalBundleProjectConfig({
@@ -0,0 +1,122 @@
1
+ import { isAbsolute, relative, sep } from "path";
2
+
3
+ import { resolveCodegenServerPublishDir, runCodegenWithReporting } from "./codegen-command.mjs";
4
+
5
+ const GENERATED_AUTH_SCHEMA_IMPORT =
6
+ /(?:export\s+\*\s+from|import)\s*["'][^"']*generated\/schema-auth\.gen["']/u;
7
+
8
+ export function resolveConfiguredBackendRoot(projectConfig) {
9
+ const pathValue = projectConfig?.rootDir ?? projectConfig?.functionsDir ?? "gencow";
10
+ if (typeof pathValue !== "string") return "gencow";
11
+ const normalized = pathValue
12
+ .trim()
13
+ .replace(/^\.\/+/, "")
14
+ .replace(/[\\/]+$/, "");
15
+ return normalized || "gencow";
16
+ }
17
+
18
+ export async function loadDeployMigrationGenerationContext({
19
+ buildEnvImpl,
20
+ cwd,
21
+ errorImpl,
22
+ existsSyncImpl,
23
+ infoImpl,
24
+ loadConfigImpl,
25
+ loadProjectConfigForDeployImpl,
26
+ readFileSyncImpl,
27
+ resolvePathImpl,
28
+ statSyncImpl,
29
+ warnImpl,
30
+ }) {
31
+ if (!loadConfigImpl || !buildEnvImpl) {
32
+ warnImpl("Deploy packaging is using legacy migration generation without a Gencow schema contract.");
33
+ return { config: null, genEnv: null };
34
+ }
35
+ const config = await loadProjectConfigForDeployImpl({
36
+ cwd,
37
+ existsSyncImpl,
38
+ readFileSyncImpl,
39
+ resolvePathImpl,
40
+ statSyncImpl,
41
+ warnImpl,
42
+ errorImpl,
43
+ loadConfigImpl,
44
+ throwOnInvalid: true,
45
+ });
46
+ const genEnv = buildEnvImpl(config, { cwd, existsSyncImpl, readFileSyncImpl, resolvePathImpl });
47
+ infoImpl("Using Gencow-derived schema contract for deploy packaging.");
48
+ return { config, genEnv };
49
+ }
50
+
51
+ export async function prepareDeployCodegenArtifacts({
52
+ backendRoot,
53
+ config,
54
+ cwd,
55
+ diagnosticsColors,
56
+ errorImpl,
57
+ existsSyncImpl,
58
+ infoImpl,
59
+ logImpl,
60
+ readFileSyncImpl,
61
+ relativePathImpl = relative,
62
+ resolvePathImpl,
63
+ rmSyncImpl,
64
+ runCodegenForDeployImpl = runCodegenWithReporting,
65
+ successImpl,
66
+ }) {
67
+ const authSchemaPath = resolvePathImpl(cwd, backendRoot, "schema-auth.ts");
68
+ const serverPublishDir = resolveCodegenServerPublishDir(cwd, config);
69
+ const authSchemaGeneratedPath = resolvePathImpl(serverPublishDir, "schema-auth.gen.ts");
70
+ const hasGeneratedAuthSchemaDependency =
71
+ existsSyncImpl(authSchemaPath) &&
72
+ GENERATED_AUTH_SCHEMA_IMPORT.test(readFileSyncImpl(authSchemaPath, "utf8"));
73
+ const shouldGenerate =
74
+ config.codegen !== undefined ||
75
+ (hasGeneratedAuthSchemaDependency && !existsSyncImpl(authSchemaGeneratedPath));
76
+ if (!shouldGenerate) return null;
77
+
78
+ const backendRootDir = resolvePathImpl(cwd, backendRoot);
79
+ const serverPublishRelativeDir = relativePathImpl(backendRootDir, serverPublishDir);
80
+ if (
81
+ !serverPublishRelativeDir ||
82
+ serverPublishRelativeDir === "." ||
83
+ isAbsolute(serverPublishRelativeDir) ||
84
+ serverPublishRelativeDir === ".." ||
85
+ serverPublishRelativeDir.startsWith(`..${sep}`)
86
+ ) {
87
+ errorImpl("Deploy codegen server output must be inside the configured backend root.");
88
+ infoImpl("Code: CODEGEN_SERVER_OUTPUT_OUTSIDE_BACKEND");
89
+ throw new Error("CODEGEN_SERVER_OUTPUT_OUTSIDE_BACKEND");
90
+ }
91
+
92
+ infoImpl("Generating required auth schema for deploy packaging...");
93
+ const deployCodegenDir = resolvePathImpl(cwd, ".gencow", "deploy-codegen");
94
+ const deployCodegenClientDir = resolvePathImpl(cwd, ".gencow", "deploy-codegen-client");
95
+ const deployCodegenServerDir = resolvePathImpl(cwd, ".gencow", "deploy-codegen-server");
96
+ const cleanup = () => {
97
+ rmSyncImpl(deployCodegenDir, { recursive: true, force: true });
98
+ rmSyncImpl(deployCodegenClientDir, { recursive: true, force: true });
99
+ rmSyncImpl(deployCodegenServerDir, { recursive: true, force: true });
100
+ };
101
+
102
+ try {
103
+ await runCodegenForDeployImpl({
104
+ config,
105
+ cwd,
106
+ diagnosticsColors,
107
+ logImpl,
108
+ outDir: deployCodegenDir,
109
+ publishDir: deployCodegenClientDir,
110
+ serverPublishDir: deployCodegenServerDir,
111
+ successImpl,
112
+ });
113
+ } catch {
114
+ cleanup();
115
+ errorImpl("Deploy codegen generation failed.");
116
+ infoImpl("Code: CODEGEN_GENERATION_FAILED");
117
+ throw new Error("CODEGEN_GENERATION_FAILED");
118
+ }
119
+
120
+ successImpl("Required auth schema generated for deploy packaging");
121
+ return { cleanup, serverPublishDir: deployCodegenServerDir, serverPublishRelativeDir };
122
+ }
@@ -5,6 +5,11 @@ import { fetchAppDiagnosticLogsViaRest, normalizeDiagnosticLogLines } from "./ap
5
5
  import { resolveCreatedAppResponse } from "./app-create-response.mjs";
6
6
  import { resolveConfiguredAuditorImplementation } from "./auditor-mode.mjs";
7
7
  import { writeProjectMetadata } from "./deploy-project-metadata.mjs";
8
+ import {
9
+ loadDeployMigrationGenerationContext,
10
+ prepareDeployCodegenArtifacts,
11
+ resolveConfiguredBackendRoot,
12
+ } from "./deploy-codegen-preflight.mjs";
8
13
  import {
9
14
  SUPPORTED_DRIZZLE_KIT_GENERATOR_VERSION,
10
15
  buildMigrationGenerationError,
@@ -40,18 +45,6 @@ async function loadProjectConfigDefault(options) {
40
45
  const { loadConfig } = await import("./cli-project-runtime.mjs");
41
46
  return loadConfig(options);
42
47
  }
43
- function normalizeBackendRootDir(pathValue) {
44
- if (typeof pathValue !== "string") return "gencow";
45
- const normalized = pathValue
46
- .trim()
47
- .replace(/^\.\/+/, "")
48
- .replace(/[\\/]+$/, "");
49
- return normalized || "gencow";
50
- }
51
- function resolveConfiguredBackendRoot(projectConfig) {
52
- return normalizeBackendRootDir(projectConfig?.rootDir ?? projectConfig?.functionsDir ?? "gencow");
53
- }
54
-
55
48
  export function isExplicitEmptyBackendApi(source) {
56
49
  return /\bdefineApi\s*\(\s*\{\s*procedures\s*:\s*\{\s*\}\s*,?\s*\}\s*\)\s*;?\s*$/u.test(source);
57
50
  }
@@ -148,8 +141,14 @@ export function createDeployPackageRuntime({
148
141
  updateEnvLocalUrlImpl,
149
142
  loadInternalBundleImpl,
150
143
  loadDeployAuditorImpl,
144
+ runCodegenForDeployImpl,
151
145
  } = {}) {
152
146
  let migrationProjectConfig = null;
147
+ let preparedDeployCodegenArtifacts = null;
148
+ function cleanupPreparedDeploySource() {
149
+ preparedDeployCodegenArtifacts?.cleanup?.();
150
+ preparedDeployCodegenArtifacts = null;
151
+ }
153
152
  async function loadAnalyzerBundleForDeployAudit() {
154
153
  try {
155
154
  const bundled = await (loadInternalBundleImpl ?? loadInternalToolingDefault)();
@@ -176,35 +175,43 @@ export function createDeployPackageRuntime({
176
175
  }
177
176
  }
178
177
  async function loadMigrationGenerationContext(cwd) {
179
- if (loadConfigImpl && buildEnvImpl) {
180
- const config = await loadProjectConfigForDeploy({
178
+ const context = await loadDeployMigrationGenerationContext({
179
+ buildEnvImpl,
180
+ cwd,
181
+ errorImpl,
182
+ existsSyncImpl,
183
+ infoImpl: (message) => infoImpl(`${DIM}${message}${RESET}`),
184
+ loadConfigImpl,
185
+ loadProjectConfigForDeployImpl: loadProjectConfigForDeploy,
186
+ readFileSyncImpl,
187
+ resolvePathImpl,
188
+ statSyncImpl,
189
+ warnImpl,
190
+ });
191
+ migrationProjectConfig = context.config;
192
+ return context;
193
+ }
194
+ async function runMigrationGenerate() {
195
+ const cwd = cwdImpl();
196
+ cleanupPreparedDeploySource();
197
+ const { config, genEnv } = await loadMigrationGenerationContext(cwd);
198
+ if (config) {
199
+ preparedDeployCodegenArtifacts = await prepareDeployCodegenArtifacts({
200
+ backendRoot: resolveConfiguredBackendRoot(config),
201
+ config,
181
202
  cwd,
182
- existsSyncImpl,
183
- readFileSyncImpl,
184
- resolvePathImpl,
185
- statSyncImpl,
186
- warnImpl,
203
+ diagnosticsColors: { CYAN, DIM, RED, RESET, YELLOW },
187
204
  errorImpl,
188
- loadConfigImpl,
189
- throwOnInvalid: true,
190
- });
191
- migrationProjectConfig = config;
192
- const genEnv = buildEnvImpl(config, {
193
- cwd,
194
205
  existsSyncImpl,
206
+ infoImpl,
207
+ logImpl,
195
208
  readFileSyncImpl,
196
209
  resolvePathImpl,
210
+ rmSyncImpl,
211
+ runCodegenForDeployImpl,
212
+ successImpl,
197
213
  });
198
- infoImpl(`${DIM}Using Gencow-derived schema contract for deploy packaging.${RESET}`);
199
- return { config, genEnv };
200
214
  }
201
- migrationProjectConfig = null;
202
- warnImpl("Deploy packaging is using legacy migration generation without a Gencow schema contract.");
203
- return { config: null, genEnv: null };
204
- }
205
- async function runMigrationGenerate() {
206
- const cwd = cwdImpl();
207
- const { genEnv } = await loadMigrationGenerationContext(cwd);
208
215
  if (
209
216
  !hasProjectDatabaseSchemaSource({
210
217
  cwd,
@@ -249,6 +256,7 @@ export function createDeployPackageRuntime({
249
256
  logImpl(`${DIM} ok Migrations up-to-date — no new schema changes detected${RESET}`);
250
257
  return SUPPORTED_DRIZZLE_KIT_GENERATOR_VERSION;
251
258
  }
259
+ cleanupPreparedDeploySource();
252
260
  throw buildMigrationGenerationError(caught);
253
261
  }
254
262
  }
@@ -370,7 +378,6 @@ export function createDeployPackageRuntime({
370
378
  ? preparedGeneratorVersion || SUPPORTED_DRIZZLE_KIT_GENERATOR_VERSION
371
379
  : await prepareDeployProjectSource({ existingBundleMode });
372
380
  logImpl("");
373
-
374
381
  infoImpl("Packaging project...");
375
382
  const tmpBundle = resolvePathImpl(cwd, ".gencow", "deploy-bundle.tar.gz");
376
383
  mkdirSyncImpl(dirname(tmpBundle), { recursive: true });
@@ -386,15 +393,12 @@ export function createDeployPackageRuntime({
386
393
  throwOnInvalid: false,
387
394
  });
388
395
  const backendRoot = resolveConfiguredBackendRoot(projectConfig);
389
-
390
396
  if (!existsSyncImpl(resolvePathImpl(cwd, backendRoot))) {
391
397
  errorImpl(`${backendRoot}/ directory not found. Run from Gencow project root.`);
392
398
  exitImpl(1);
393
399
  return null;
394
400
  }
395
-
396
401
  const entryPoint = resolvePathImpl(cwd, backendRoot, "index.ts");
397
-
398
402
  await runWorkflowShadowingAudit({ cwd, projectConfig, backendRoot });
399
403
 
400
404
  let dependencyAuditManifest = null;
@@ -461,6 +465,8 @@ export function createDeployPackageRuntime({
461
465
  existsSyncImpl,
462
466
  cpSyncImpl,
463
467
  generatorVersion,
468
+ generatedServerPublishDir: preparedDeployCodegenArtifacts?.serverPublishDir,
469
+ generatedServerRelativeDir: preparedDeployCodegenArtifacts?.serverPublishRelativeDir,
464
470
  lockfileSelection,
465
471
  migrationProjectConfig,
466
472
  mkdirSyncImpl,
@@ -478,8 +484,10 @@ export function createDeployPackageRuntime({
478
484
  } catch (caught) {
479
485
  errorImpl(`Packaging failed: ${caught.message}`);
480
486
  exitImpl(1);
487
+ cleanupPreparedDeploySource();
481
488
  return null;
482
489
  }
490
+ cleanupPreparedDeploySource();
483
491
 
484
492
  const bundleBuffer = readFileSyncImpl(tmpBundle);
485
493
  const bundleSize = statSyncImpl(tmpBundle).size;
@@ -518,7 +526,7 @@ export function createDeployPackageRuntime({
518
526
  return { bundleBuffer, bundleSize, deployClaim, tmpBundle };
519
527
  }
520
528
 
521
- async function createCloudAppIfNeeded({ creds, appId, displayName, gencowJsonPath }) {
529
+ async function createCloudAppIfNeeded({ creds, appId, displayName, envTarget = "dev", gencowJsonPath }) {
522
530
  if (appId) return appId;
523
531
 
524
532
  infoImpl("Creating app (auto-generating ID)...");
@@ -544,6 +552,7 @@ export function createDeployPackageRuntime({
544
552
  writeProjectMetadata({
545
553
  appId: nextAppId,
546
554
  displayName,
555
+ envTarget,
547
556
  platformUrl: creds.platformUrl,
548
557
  gencowJsonPath,
549
558
  writeFileSyncImpl,
@@ -667,6 +676,7 @@ export function createDeployPackageRuntime({
667
676
  creds,
668
677
  appId: null,
669
678
  displayName,
679
+ envTarget,
670
680
  gencowJsonPath,
671
681
  });
672
682
  if (activeDeployClaim) {
@@ -782,6 +792,7 @@ export function createDeployPackageRuntime({
782
792
  runMigrationGenerate,
783
793
  preflightBackendCapability,
784
794
  prepareDeployProjectSource,
795
+ cleanupPreparedDeploySource,
785
796
  packageDeployProject,
786
797
  createCloudAppIfNeeded,
787
798
  deployBundleWithRetry,
@@ -1,8 +1,35 @@
1
- import { writeFileSync } from "fs";
1
+ import { existsSync, readFileSync, writeFileSync } from "fs";
2
+
3
+ function readExistingProjectMetadata(gencowJsonPath) {
4
+ if (!existsSync(gencowJsonPath)) return {};
5
+ try {
6
+ const parsed = JSON.parse(readFileSync(gencowJsonPath, "utf8"));
7
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
8
+ } catch {
9
+ // Fall through to the stable fail-closed diagnostic below.
10
+ }
11
+ throw new Error("MIGRATION_PROJECT_CONFIG_INVALID");
12
+ }
13
+
14
+ export function buildProjectMetadata({
15
+ appId,
16
+ displayName,
17
+ envTarget = "dev",
18
+ existingMetadata,
19
+ platformUrl,
20
+ }) {
21
+ return {
22
+ ...existingMetadata,
23
+ displayName,
24
+ platformUrl,
25
+ ...(envTarget === "prod" ? { prodApp: appId } : { appId }),
26
+ };
27
+ }
2
28
 
3
29
  export function writeProjectMetadata({
4
30
  appId,
5
31
  displayName,
32
+ envTarget = "dev",
6
33
  platformUrl,
7
34
  gencowJsonPath,
8
35
  writeFileSyncImpl = writeFileSync,
@@ -10,11 +37,13 @@ export function writeProjectMetadata({
10
37
  writeFileSyncImpl(
11
38
  gencowJsonPath,
12
39
  JSON.stringify(
13
- {
40
+ buildProjectMetadata({
14
41
  appId,
15
42
  displayName,
43
+ envTarget,
44
+ existingMetadata: readExistingProjectMetadata(gencowJsonPath),
16
45
  platformUrl,
17
- },
46
+ }),
18
47
  null,
19
48
  2,
20
49
  ),
@@ -124,7 +124,7 @@ export function readDeployProjectContext({
124
124
 
125
125
  if (existsSyncImpl(gencowJsonPath)) {
126
126
  const gencowJson = JSON.parse(readFileSyncImpl(gencowJsonPath, "utf8"));
127
- if (!appId) appId = gencowJson.appId || gencowJson.appName;
127
+ if (!appId) appId = gencowJson.appId || gencowJson.appName || null;
128
128
  if (typeof gencowJson.displayName === "string" && gencowJson.displayName.trim()) {
129
129
  fallbackDisplayName = gencowJson.displayName.trim();
130
130
  }
@@ -114,6 +114,7 @@ export async function deployBackendPackage({
114
114
  creds,
115
115
  appId,
116
116
  displayName,
117
+ envTarget,
117
118
  gencowJsonPath,
118
119
  });
119
120
  if (!activeAppId) return null;
@@ -158,6 +159,7 @@ export async function deployBackendPackage({
158
159
  /* ignore */
159
160
  }
160
161
  }
162
+ activePackageRuntime.cleanupPreparedDeploySource?.();
161
163
  }
162
164
 
163
165
  if (!deployed) return null;
@@ -169,6 +171,7 @@ export async function deployBackendPackage({
169
171
  writeProjectMetadata({
170
172
  appId: deployed.appId,
171
173
  displayName,
174
+ envTarget,
172
175
  platformUrl: creds.platformUrl,
173
176
  gencowJsonPath,
174
177
  writeFileSyncImpl,
@@ -18,6 +18,7 @@ import { buildDeployClaimFromArchive } from "./deploy-package-claim.mjs";
18
18
  import { buildStaticArtifactManifest } from "./static-artifact-manifest.mjs";
19
19
  import { getCliInvocationSelection } from "./project-context.mjs";
20
20
  import { pollAcceptedDeploymentOperation } from "./deployment-operation-poll.mjs";
21
+ import { writeProjectMetadata } from "./deploy-project-metadata.mjs";
21
22
 
22
23
  export function resolveStaticDeployDir({
23
24
  staticDirArg,
@@ -153,27 +154,6 @@ async function confirmStaticApiReferenceProceed(createInterfaceImpl) {
153
154
  });
154
155
  }
155
156
 
156
- function writeProjectMetadata({
157
- appId,
158
- displayName,
159
- platformUrl,
160
- gencowJsonPath,
161
- writeFileSyncImpl = writeFileSync,
162
- }) {
163
- writeFileSyncImpl(
164
- gencowJsonPath,
165
- JSON.stringify(
166
- {
167
- appId,
168
- displayName,
169
- platformUrl,
170
- },
171
- null,
172
- 2,
173
- ),
174
- );
175
- }
176
-
177
157
  export function createStaticDeployRuntime({
178
158
  buildDeployClaimFromArchiveImpl = buildDeployClaimFromArchive,
179
159
  cliVersion = "0.0.0",
@@ -303,6 +283,7 @@ export function createStaticDeployRuntime({
303
283
  writeProjectMetadata({
304
284
  appId,
305
285
  displayName,
286
+ envTarget: opts.envTarget || "dev",
306
287
  platformUrl: creds.platformUrl,
307
288
  gencowJsonPath,
308
289
  writeFileSyncImpl,
@@ -505,6 +486,7 @@ export function createStaticDeployRuntime({
505
486
  writeProjectMetadata({
506
487
  appId,
507
488
  displayName,
489
+ envTarget: opts.envTarget || "dev",
508
490
  platformUrl: creds.platformUrl,
509
491
  gencowJsonPath,
510
492
  writeFileSyncImpl,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gencow",
3
- "version": "0.1.200",
3
+ "version": "0.1.201",
4
4
  "description": "Gencow — AI Backend Engine",
5
5
  "type": "module",
6
6
  "bin": {
@@ -34,8 +34,8 @@
34
34
  "@types/node": "^25.9.5",
35
35
  "better-auth": "^1.6.23",
36
36
  "@gencow/core": "0.1.42",
37
- "@gencow/client": "0.2.6",
38
- "@gencow/react": "0.2.6"
37
+ "@gencow/react": "0.2.6",
38
+ "@gencow/client": "0.2.6"
39
39
  },
40
40
  "scripts": {
41
41
  "prebuild": "pnpm --filter @gencow/migration-contract run build && pnpm --filter @gencow/server run build",