gencow 0.1.259 → 0.1.260
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/lib/cloud-targets.mjs +14 -4
- package/lib/db-command.mjs +16 -2
- package/lib/deploy-prepared-source.mjs +37 -0
- package/lib/deploy-runtime.mjs +85 -69
- package/lib/deploy-static-fullstack-runtime.mjs +18 -15
- package/lib/static-command.mjs +13 -3
- package/package.json +4 -4
- package/runtime/server.mjs +14 -14
package/lib/cloud-targets.mjs
CHANGED
|
@@ -47,6 +47,14 @@ export function resolveProdAppTarget({ explicitAppId = null, prodApp = null, acc
|
|
|
47
47
|
return { appId: prodApp };
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
// Single rule for the implicit prod environment: an explicit app id that is this project's
|
|
51
|
+
// prod app selects the prod environment even without --prod. Every command that picks a
|
|
52
|
+
// cloud app (cloud targets, deploy) must use this helper instead of repeating the condition.
|
|
53
|
+
export function resolveImplicitProdEnvironment({ explicitApp = false, envTarget = "dev", appId = null, prodApp = null }) {
|
|
54
|
+
if (explicitApp && envTarget === "dev" && prodApp && appId === prodApp) return "prod";
|
|
55
|
+
return envTarget;
|
|
56
|
+
}
|
|
57
|
+
|
|
50
58
|
// Shared human message for a failed prod target; falls back to the call site's own text.
|
|
51
59
|
export function describeProdTargetFailure(result, fallbackMessage) {
|
|
52
60
|
if (result?.reason === "explicit_app_not_prod_app") {
|
|
@@ -81,10 +89,12 @@ export function resolveCloudAppTarget(restArgs, options = {}) {
|
|
|
81
89
|
if (projectTargets.invalid) {
|
|
82
90
|
return { error: "MIGRATION_PROJECT_CONFIG_INVALID" };
|
|
83
91
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
envTarget
|
|
87
|
-
|
|
92
|
+
envTarget = resolveImplicitProdEnvironment({
|
|
93
|
+
explicitApp,
|
|
94
|
+
envTarget,
|
|
95
|
+
appId,
|
|
96
|
+
prodApp: projectTargets.prodApp,
|
|
97
|
+
});
|
|
88
98
|
if (!appId) {
|
|
89
99
|
appId = envTarget === "prod" ? projectTargets.prodApp : projectTargets.appId;
|
|
90
100
|
}
|
package/lib/db-command.mjs
CHANGED
|
@@ -17,22 +17,36 @@ import { createDbCheckCommand, createDbPushCommand } from "./db-push-command.mjs
|
|
|
17
17
|
import { logEnvFileOperationWithType } from "./backend-env-resolver.mjs";
|
|
18
18
|
import { runDrizzleGenerateWithFallback } from "./drizzle-generate.mjs";
|
|
19
19
|
import { BOLD, CYAN, DIM, GREEN, RED, RESET, error, info, log, success, warn } from "./output.mjs";
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
describeProdTargetFailure,
|
|
22
|
+
resolveImplicitProdEnvironment,
|
|
23
|
+
resolveProdAppTarget,
|
|
24
|
+
} from "./cloud-targets.mjs";
|
|
21
25
|
import { platformFetch, requireCreds } from "./platform-client.mjs";
|
|
22
26
|
import { readProjectMetadata } from "./project-context.mjs";
|
|
23
27
|
|
|
24
28
|
export function resolveDbCloudTarget(args, gencowJson = null) {
|
|
25
|
-
const isProd = args.includes("--prod");
|
|
26
29
|
let explicitAppId = null;
|
|
30
|
+
let hasExplicitApp = false;
|
|
27
31
|
let platformUrl = null;
|
|
28
32
|
|
|
29
33
|
for (let i = 0; i < args.length; i++) {
|
|
30
34
|
if (args[i] === "--app" || args[i] === "-a") {
|
|
31
35
|
explicitAppId = args[i + 1] ?? null;
|
|
36
|
+
hasExplicitApp = true;
|
|
32
37
|
i++;
|
|
33
38
|
}
|
|
34
39
|
}
|
|
35
40
|
|
|
41
|
+
// Same implicit prod rule as deploy and static: an --app naming the project's prodApp is prod even without --prod.
|
|
42
|
+
const isProd =
|
|
43
|
+
resolveImplicitProdEnvironment({
|
|
44
|
+
explicitApp: hasExplicitApp,
|
|
45
|
+
envTarget: args.includes("--prod") ? "prod" : "dev",
|
|
46
|
+
appId: explicitAppId,
|
|
47
|
+
prodApp: gencowJson?.prodApp || null,
|
|
48
|
+
}) === "prod";
|
|
49
|
+
|
|
36
50
|
if (gencowJson) {
|
|
37
51
|
platformUrl = gencowJson.platformUrl || null;
|
|
38
52
|
if (isProd) {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { unlinkSync } from "fs";
|
|
2
|
+
|
|
3
|
+
// Local-only backend source preparation for a first `deploy --prod`. Every step here
|
|
4
|
+
// reads the project on disk (capability check, migration generation, codegen, the
|
|
5
|
+
// packaging audits and the bundle with its round-trip check). It runs once, before the
|
|
6
|
+
// production app is created, so a rejection leaves no remote app behind.
|
|
7
|
+
export async function prepareBackendSourceForProdCreate(
|
|
8
|
+
runtime,
|
|
9
|
+
{ forceDeploy = false, requestId = null } = {},
|
|
10
|
+
) {
|
|
11
|
+
if ((await runtime.preflightBackendCapability?.()) === false) return null;
|
|
12
|
+
const generatorVersion = await runtime.prepareDeployProjectSource?.({ existingBundleMode: false });
|
|
13
|
+
const packageResult = await runtime.packageDeployProject({
|
|
14
|
+
forceDeploy,
|
|
15
|
+
existingBundleMode: false,
|
|
16
|
+
requestId,
|
|
17
|
+
sourcePrepared: true,
|
|
18
|
+
preparedGeneratorVersion: generatorVersion,
|
|
19
|
+
});
|
|
20
|
+
if (!packageResult) return null;
|
|
21
|
+
return { runtime, generatorVersion, packageResult };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Drops the temporary bundle file and codegen output of a prepared source that did not
|
|
25
|
+
// reach the backend deploy (which otherwise releases them itself). Safe to call twice.
|
|
26
|
+
export function releasePreparedBackendSource(prepared, { unlinkSyncImpl = unlinkSync } = {}) {
|
|
27
|
+
if (!prepared) return;
|
|
28
|
+
const tmpBundle = prepared.packageResult?.tmpBundle;
|
|
29
|
+
if (tmpBundle) {
|
|
30
|
+
try {
|
|
31
|
+
unlinkSyncImpl(tmpBundle);
|
|
32
|
+
} catch {
|
|
33
|
+
/* already removed */
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
prepared.runtime?.cleanupPreparedDeploySource?.();
|
|
37
|
+
}
|
package/lib/deploy-runtime.mjs
CHANGED
|
@@ -19,6 +19,11 @@ import { detectStaticDeployBackend, preflightStaticDeployArtifact } from "./stat
|
|
|
19
19
|
import { formatCommandError } from "./cli-command-runner.mjs";
|
|
20
20
|
import { readJsonObjectResponse } from "./http-response-json.mjs";
|
|
21
21
|
import { ensureProductionDeployTarget } from "./deploy-prod-target.mjs";
|
|
22
|
+
import {
|
|
23
|
+
prepareBackendSourceForProdCreate,
|
|
24
|
+
releasePreparedBackendSource,
|
|
25
|
+
} from "./deploy-prepared-source.mjs";
|
|
26
|
+
import { resolveImplicitProdEnvironment } from "./cloud-targets.mjs";
|
|
22
27
|
|
|
23
28
|
export function parseDeployArgs(deployArgs) {
|
|
24
29
|
const parsed = {
|
|
@@ -183,14 +188,6 @@ function showUnknownDeployArgument(arg, { errorImpl = error, infoImpl = info, lo
|
|
|
183
188
|
infoImpl(" gencow static [dir] Deploy static files only");
|
|
184
189
|
}
|
|
185
190
|
|
|
186
|
-
// Returns the prepared backend source, or null when the capability check rejected it
|
|
187
|
-
// (the rejection is already rendered and exit is already requested).
|
|
188
|
-
async function prepareBackendSourceForProdCreate(runtime) {
|
|
189
|
-
if ((await runtime.preflightBackendCapability?.()) === false) return null;
|
|
190
|
-
const generatorVersion = await runtime.prepareDeployProjectSource?.({ existingBundleMode: false });
|
|
191
|
-
return { runtime, generatorVersion };
|
|
192
|
-
}
|
|
193
|
-
|
|
194
191
|
async function runRollbackDeploy({
|
|
195
192
|
appId,
|
|
196
193
|
envTarget,
|
|
@@ -432,6 +429,14 @@ export function createDeployCommand({
|
|
|
432
429
|
resolvePathImpl,
|
|
433
430
|
});
|
|
434
431
|
let { appId, displayName, gencowJsonPath, prodAppId, projectDir } = context;
|
|
432
|
+
// Same environment rule as cloud-targets.mjs: --app <project prod app> deploys to prod even without --prod.
|
|
433
|
+
// Every branch below (static, rollback, existing-bundle, backend) reads this promoted environment.
|
|
434
|
+
parsed.envTarget = resolveImplicitProdEnvironment({
|
|
435
|
+
explicitApp: Boolean(parsed.appId),
|
|
436
|
+
envTarget: parsed.envTarget,
|
|
437
|
+
appId: parsed.appId,
|
|
438
|
+
prodApp: prodAppId,
|
|
439
|
+
});
|
|
435
440
|
const rootAppId = appId;
|
|
436
441
|
appId = resolveEnvironmentDeployTarget({ appId, envTarget: parsed.envTarget, prodAppId });
|
|
437
442
|
const backendProjectRoot = projectDir ?? projectRoot;
|
|
@@ -524,14 +529,20 @@ export function createDeployCommand({
|
|
|
524
529
|
region: parsed.region,
|
|
525
530
|
prepareLocalSource: preparesBackendSource
|
|
526
531
|
? async () => {
|
|
527
|
-
preparedSource = await prepareBackendSourceForProdCreate(backendDeployRuntime
|
|
532
|
+
preparedSource = await prepareBackendSourceForProdCreate(backendDeployRuntime, {
|
|
533
|
+
forceDeploy: parsed.forceDeploy,
|
|
534
|
+
requestId: parsed.requestId,
|
|
535
|
+
});
|
|
528
536
|
return preparedSource !== null;
|
|
529
537
|
}
|
|
530
538
|
: null,
|
|
531
539
|
});
|
|
532
540
|
} finally {
|
|
533
|
-
// Prepared codegen output
|
|
534
|
-
if (!prodTarget)
|
|
541
|
+
// Prepared codegen output and bundle are temporary; drop them when no production app was created.
|
|
542
|
+
if (!prodTarget) {
|
|
543
|
+
backendDeployRuntime.cleanupPreparedDeploySource?.();
|
|
544
|
+
releasePreparedBackendSource(preparedSource, { unlinkSyncImpl });
|
|
545
|
+
}
|
|
535
546
|
}
|
|
536
547
|
if (!prodTarget) return;
|
|
537
548
|
appId = prodTarget;
|
|
@@ -544,64 +555,69 @@ export function createDeployCommand({
|
|
|
544
555
|
}
|
|
545
556
|
|
|
546
557
|
if (parsed.staticDeploy) {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
558
|
+
try {
|
|
559
|
+
await runStaticDeployFlow({
|
|
560
|
+
appId,
|
|
561
|
+
preparedSource,
|
|
562
|
+
backendRoot: backendProjectRoot,
|
|
563
|
+
creds,
|
|
564
|
+
displayName,
|
|
565
|
+
envTarget: parsed.envTarget,
|
|
566
|
+
forceDeploy: parsed.forceDeploy,
|
|
567
|
+
requestId: parsed.requestId,
|
|
568
|
+
resumeStaticOnly: parsed.resumeRequested,
|
|
569
|
+
gencowJsonPath,
|
|
570
|
+
hasDetectedBackend,
|
|
571
|
+
selectedClient,
|
|
572
|
+
staticDirArg: resolvedStaticDirArg,
|
|
573
|
+
staticArtifactPreflight,
|
|
574
|
+
createDeployPackageRuntimeForCwd,
|
|
575
|
+
cwdImpl,
|
|
576
|
+
deployPackageRuntime: backendDeployRuntime,
|
|
577
|
+
errorImpl,
|
|
578
|
+
existsSyncImpl,
|
|
579
|
+
exitImpl,
|
|
580
|
+
infoImpl,
|
|
581
|
+
logImpl,
|
|
582
|
+
resolvePathImpl,
|
|
583
|
+
runStaticDeployRuntimeImpl,
|
|
584
|
+
unlinkSyncImpl,
|
|
585
|
+
writeFileSyncImpl,
|
|
586
|
+
prepareReleaseAttempt: prepareReleaseAttemptImpl
|
|
587
|
+
? ({ appId: activeAppId, sourceRoot }) =>
|
|
588
|
+
prepareReleaseAttemptImpl({
|
|
589
|
+
root: sourceRoot || backendProjectRoot,
|
|
590
|
+
sourceRootKind: "fullstack",
|
|
591
|
+
components: ["backend", "static"],
|
|
592
|
+
cliVersion,
|
|
593
|
+
creds,
|
|
594
|
+
appId: activeAppId,
|
|
595
|
+
environment: parsed.envTarget,
|
|
596
|
+
requestId: parsed.requestId,
|
|
597
|
+
platformFetchImpl,
|
|
598
|
+
capabilityTimeoutMs: 15_000,
|
|
599
|
+
allowCapabilityTimeoutFallback: true,
|
|
600
|
+
warnImpl,
|
|
601
|
+
})
|
|
602
|
+
: undefined,
|
|
603
|
+
failReleaseAttempt: failReleaseAttemptImpl
|
|
604
|
+
? ({ appId: activeAppId, attemptId, failureStage, failureCode }) =>
|
|
605
|
+
failReleaseAttemptImpl({
|
|
606
|
+
creds,
|
|
607
|
+
appId: activeAppId,
|
|
608
|
+
attemptId,
|
|
609
|
+
environment: parsed.envTarget,
|
|
610
|
+
failureStage,
|
|
611
|
+
failureCode,
|
|
612
|
+
platformFetchImpl,
|
|
613
|
+
})
|
|
614
|
+
: undefined,
|
|
615
|
+
successImpl,
|
|
616
|
+
});
|
|
617
|
+
} finally {
|
|
618
|
+
// The static flow can return before the backend deploy consumes the prepared source.
|
|
619
|
+
releasePreparedBackendSource(preparedSource, { unlinkSyncImpl });
|
|
620
|
+
}
|
|
605
621
|
return 0;
|
|
606
622
|
}
|
|
607
623
|
|
|
@@ -125,22 +125,25 @@ export async function deployBackendPackage({
|
|
|
125
125
|
});
|
|
126
126
|
if (!activeAppId) return null;
|
|
127
127
|
} else {
|
|
128
|
-
if (
|
|
128
|
+
if (preparedSource) {
|
|
129
|
+
// Local preparation and packaging already ran once, before the production create.
|
|
130
|
+
packageResult = preparedSource.packageResult;
|
|
131
|
+
} else {
|
|
129
132
|
if ((await activePackageRuntime.preflightBackendCapability?.()) === false) return null;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
133
|
+
const preparedGeneratorVersion = await activePackageRuntime.prepareDeployProjectSource?.({
|
|
134
|
+
existingBundleMode,
|
|
135
|
+
});
|
|
136
|
+
packageResult = await activePackageRuntime.packageDeployProject({
|
|
137
|
+
forceDeploy,
|
|
138
|
+
existingBundleMode,
|
|
139
|
+
requestId,
|
|
140
|
+
sourcePrepared: true,
|
|
141
|
+
preparedGeneratorVersion,
|
|
142
|
+
});
|
|
143
|
+
if (!packageResult) {
|
|
144
|
+
await markAttemptFailed("package", "PACKAGE_FAILED");
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
144
147
|
}
|
|
145
148
|
|
|
146
149
|
activeAppId = await activePackageRuntime.createCloudAppIfNeeded({
|
package/lib/static-command.mjs
CHANGED
|
@@ -3,7 +3,11 @@ import { isAbsolute, resolve } from "path";
|
|
|
3
3
|
|
|
4
4
|
import { readProjectDisplayName } from "./cli-project-runtime.mjs";
|
|
5
5
|
import { formatCommandError } from "./cli-command-runner.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
describeProdTargetFailure,
|
|
8
|
+
resolveImplicitProdEnvironment,
|
|
9
|
+
resolveProdAppTarget,
|
|
10
|
+
} from "./cloud-targets.mjs";
|
|
7
11
|
import {
|
|
8
12
|
getCliInvocationSelection,
|
|
9
13
|
resolveProjectMetadataPath,
|
|
@@ -291,8 +295,14 @@ export function createStaticCommand(options = {}) {
|
|
|
291
295
|
return;
|
|
292
296
|
}
|
|
293
297
|
}
|
|
294
|
-
|
|
295
|
-
const envTarget =
|
|
298
|
+
// Same environment rule as deploy (cloud-targets.mjs): --app <project prod app> is prod even without --prod.
|
|
299
|
+
const envTarget = resolveImplicitProdEnvironment({
|
|
300
|
+
explicitApp: Boolean(parsed.appId),
|
|
301
|
+
envTarget: parsed.isProd ? "prod" : "dev",
|
|
302
|
+
appId: parsed.appId,
|
|
303
|
+
prodApp: prodAppId,
|
|
304
|
+
});
|
|
305
|
+
let deployTarget = envTarget === "prod" ? prodAppId || appId : appId;
|
|
296
306
|
|
|
297
307
|
if (parsed.isProd && !prodAppId) {
|
|
298
308
|
deployTarget = await ensureStaticProductionTarget({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gencow",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.260",
|
|
4
4
|
"description": "Gencow — AI Backend Engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,10 +41,10 @@
|
|
|
41
41
|
"better-auth": "1.7.11",
|
|
42
42
|
"postgres": "^3.4.9",
|
|
43
43
|
"@gencow/client": "0.2.8",
|
|
44
|
-
"@gencow/
|
|
44
|
+
"@gencow/react": "0.2.8",
|
|
45
45
|
"@gencow/core": "0.1.47",
|
|
46
|
-
"@gencow/
|
|
47
|
-
"@gencow/
|
|
46
|
+
"@gencow/shared": "0.0.0",
|
|
47
|
+
"@gencow/server": "0.1.3"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "node scripts/bundle-core.mjs && node scripts/bundle-shared.mjs && node scripts/bundle-server.mjs",
|