gencow 0.1.213 → 0.1.215
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/app-delete-operation.mjs +14 -3
- package/lib/deploy-command.mjs +3 -2
- package/lib/deploy-package-runtime.mjs +1 -1
- package/lib/deploy-runtime.mjs +1 -0
- package/lib/deploy-static-fullstack-runtime.mjs +24 -2
- package/lib/static-deploy-command.mjs +12 -7
- package/package.json +2 -2
- package/runtime/server.mjs +1081 -681
|
@@ -16,7 +16,14 @@ const APP_DELETE_ACTIVE_STATES = new Set([
|
|
|
16
16
|
"failed_tenant_db_cleanup",
|
|
17
17
|
"failed_catalog_cleanup",
|
|
18
18
|
]);
|
|
19
|
-
const APP_DELETE_TERMINAL_FAILURE_STATES = new Set([
|
|
19
|
+
const APP_DELETE_TERMINAL_FAILURE_STATES = new Set([
|
|
20
|
+
"blocked_catalog_outcome_unknown",
|
|
21
|
+
"failed_delete_recovery_required",
|
|
22
|
+
]);
|
|
23
|
+
const APP_DELETE_RESPONSE_STATES = new Set([
|
|
24
|
+
...APP_DELETE_ACTIVE_STATES,
|
|
25
|
+
...APP_DELETE_TERMINAL_FAILURE_STATES,
|
|
26
|
+
]);
|
|
20
27
|
const CORRELATION_ID_PATTERN = /^[A-Za-z0-9_-]{8,128}$/u;
|
|
21
28
|
const DIAGNOSTIC_CODE_PATTERN = /^[A-Za-z][A-Za-z0-9_]{2,127}$/u;
|
|
22
29
|
const APP_ID_PATTERN = /^(?=.{3,63}$)[a-z][a-z0-9]*(?:-[a-z0-9]+){2,7}$/u;
|
|
@@ -44,7 +51,7 @@ export function parseAppDeleteOperationEnvelope(value, expectedAppId) {
|
|
|
44
51
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
45
52
|
if (value.success !== undefined && value.success !== false) return null;
|
|
46
53
|
if (!APP_DELETE_OPERATION_PATTERN.test(value.operationId ?? "")) return null;
|
|
47
|
-
if (!
|
|
54
|
+
if (!APP_DELETE_RESPONSE_STATES.has(value.state)) return null;
|
|
48
55
|
if (
|
|
49
56
|
!CORRELATION_ID_PATTERN.test(value.correlationId ?? "") ||
|
|
50
57
|
(value.deleted !== undefined && value.deleted !== expectedAppId) ||
|
|
@@ -87,7 +94,8 @@ function isMatchingTerminalFailureResponse(value, accepted, expectedAppId) {
|
|
|
87
94
|
value.deleted === expectedAppId &&
|
|
88
95
|
value.operationId === accepted.operationId &&
|
|
89
96
|
value.correlationId === accepted.correlationId &&
|
|
90
|
-
APP_DELETE_TERMINAL_FAILURE_STATES.has(value.state)
|
|
97
|
+
(APP_DELETE_TERMINAL_FAILURE_STATES.has(value.state) ||
|
|
98
|
+
(value.state === "blocked_active_work" && value.code === "PLATFORM_ACTION_REQUIRED")) &&
|
|
91
99
|
DIAGNOSTIC_CODE_PATTERN.test(value.code ?? "")
|
|
92
100
|
);
|
|
93
101
|
}
|
|
@@ -103,6 +111,9 @@ export async function pollAppDeleteOperation({
|
|
|
103
111
|
}) {
|
|
104
112
|
const accepted = parseAppDeleteOperationEnvelope(initialBody, name);
|
|
105
113
|
if (!accepted) return null;
|
|
114
|
+
if (isMatchingTerminalFailureResponse(initialBody, accepted, name)) {
|
|
115
|
+
return { ...initialBody, error: initialBody.code };
|
|
116
|
+
}
|
|
106
117
|
|
|
107
118
|
let latest = accepted;
|
|
108
119
|
let successfulPollResponses = 0;
|
package/lib/deploy-command.mjs
CHANGED
|
@@ -179,6 +179,7 @@ export async function verifyAppReady(params) {
|
|
|
179
179
|
successImpl = success,
|
|
180
180
|
warnImpl = warn,
|
|
181
181
|
infoImpl = info,
|
|
182
|
+
announceReady = true,
|
|
182
183
|
} = params;
|
|
183
184
|
let readinessUrl = appUrl;
|
|
184
185
|
if (readinessBaseUrl) {
|
|
@@ -232,9 +233,9 @@ export async function verifyAppReady(params) {
|
|
|
232
233
|
writeStdoutImpl("\r" + " ".repeat(50) + "\r");
|
|
233
234
|
|
|
234
235
|
const healthElapsed = ((nowImpl() - start) / 1000).toFixed(1);
|
|
235
|
-
if (healthy) {
|
|
236
|
+
if (healthy && announceReady) {
|
|
236
237
|
successImpl(`App Ready! (${healthElapsed}s)`);
|
|
237
|
-
} else {
|
|
238
|
+
} else if (!healthy) {
|
|
238
239
|
warnImpl(`App readiness check failed (${healthElapsed}s).`);
|
|
239
240
|
if (lastStatus !== null) infoImpl(`Last response: HTTP ${lastStatus}`);
|
|
240
241
|
infoImpl(`Manual check: ${CYAN}${appUrl}${RESET}`);
|
|
@@ -748,7 +748,7 @@ export function createDeployPackageRuntime({
|
|
|
748
748
|
successImpl(`Server build complete! (${deployElapsed}s)`);
|
|
749
749
|
|
|
750
750
|
if (deployData.url) {
|
|
751
|
-
const ready = await verifyAppReadyImpl({ appUrl: deployData.url, appId: targetAppId });
|
|
751
|
+
const ready = await verifyAppReadyImpl(releaseAttemptId ? { appUrl: deployData.url, appId: targetAppId, announceReady: false } : { appUrl: deployData.url, appId: targetAppId });
|
|
752
752
|
if (!ready) {
|
|
753
753
|
errorImpl("Deploy failed: app did not become ready after deployment.");
|
|
754
754
|
await showCrashLogs(null, "Readiness failure diagnostics:", targetAppId);
|
package/lib/deploy-runtime.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, unlinkSync, writeFileSync } from "fs";
|
|
|
2
2
|
import { resolve } from "path";
|
|
3
3
|
|
|
4
4
|
import { createDeployPackageRuntime, writeProjectMetadata } from "./deploy-package-runtime.mjs";
|
|
5
|
-
import { BOLD, CYAN, DIM, RESET, error, info, log } from "./output.mjs";
|
|
5
|
+
import { BOLD, CYAN, DIM, RESET, error, info, log, success } from "./output.mjs";
|
|
6
6
|
import { preflightStaticDeployArtifact } from "./static-deploy-command.mjs";
|
|
7
7
|
|
|
8
8
|
export function createScopedDeployPackageRuntime({
|
|
@@ -86,6 +86,7 @@ export async function deployBackendPackage({
|
|
|
86
86
|
failReleaseAttempt,
|
|
87
87
|
sourceRoot = null,
|
|
88
88
|
clientName = null,
|
|
89
|
+
successImpl = success,
|
|
89
90
|
}) {
|
|
90
91
|
if ((await activePackageRuntime.preflightBackendCapability?.()) === false) return null;
|
|
91
92
|
const preparedGeneratorVersion = await activePackageRuntime.prepareDeployProjectSource?.({
|
|
@@ -163,8 +164,27 @@ export async function deployBackendPackage({
|
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
if (!deployed) return null;
|
|
167
|
+
// Persist the production target before finalize. Finalize is a separate durable
|
|
168
|
+
// release effect; if it fails, the next customer retry must reuse this exact
|
|
169
|
+
// app instead of creating a second production child.
|
|
170
|
+
if (envTarget === "prod") {
|
|
171
|
+
writeProjectMetadata({
|
|
172
|
+
appId: deployed.appId,
|
|
173
|
+
displayName,
|
|
174
|
+
envTarget,
|
|
175
|
+
platformUrl: creds.platformUrl,
|
|
176
|
+
gencowJsonPath,
|
|
177
|
+
writeFileSyncImpl,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
166
180
|
if (releaseAttempt && finalizeReleaseAttempt) {
|
|
167
|
-
|
|
181
|
+
try {
|
|
182
|
+
await finalizeReleaseAttempt({ appId: deployed.appId, attemptId: releaseAttempt.attemptId });
|
|
183
|
+
} catch (caught) {
|
|
184
|
+
await markAttemptFailed("finalize", "APP_RELEASE_FINALIZE_FAILED");
|
|
185
|
+
throw caught;
|
|
186
|
+
}
|
|
187
|
+
successImpl("App Ready! (release finalized)");
|
|
168
188
|
}
|
|
169
189
|
|
|
170
190
|
if (!existsSyncImpl(gencowJsonPath)) {
|
|
@@ -210,6 +230,7 @@ export async function runStaticDeployFlow({
|
|
|
210
230
|
prepareReleaseAttempt,
|
|
211
231
|
failReleaseAttempt,
|
|
212
232
|
selectedClient = null,
|
|
233
|
+
successImpl = success,
|
|
213
234
|
}) {
|
|
214
235
|
if (!runStaticDeployRuntimeImpl) {
|
|
215
236
|
errorImpl("Static deploy runtime is not configured.");
|
|
@@ -272,6 +293,7 @@ export async function runStaticDeployFlow({
|
|
|
272
293
|
failReleaseAttempt,
|
|
273
294
|
sourceRoot: backendRoot,
|
|
274
295
|
clientName: selectedClient?.name ?? null,
|
|
296
|
+
successImpl,
|
|
275
297
|
});
|
|
276
298
|
if (!deployed) return;
|
|
277
299
|
activeAppId = deployed.appId;
|
|
@@ -438,13 +438,18 @@ export function createStaticDeployRuntime({
|
|
|
438
438
|
}
|
|
439
439
|
let release = null;
|
|
440
440
|
if (releaseAttemptId && finalizeReleaseAttemptImpl) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
441
|
+
try {
|
|
442
|
+
release = await finalizeReleaseAttemptImpl({
|
|
443
|
+
creds,
|
|
444
|
+
appId,
|
|
445
|
+
attemptId: releaseAttemptId,
|
|
446
|
+
environment: opts.envTarget || "dev",
|
|
447
|
+
platformFetchImpl,
|
|
448
|
+
});
|
|
449
|
+
} catch (caught) {
|
|
450
|
+
await markAttemptFailed("finalize", "APP_RELEASE_FINALIZE_FAILED");
|
|
451
|
+
throw caught;
|
|
452
|
+
}
|
|
448
453
|
}
|
|
449
454
|
logImpl("");
|
|
450
455
|
successImpl("Static deploy complete!");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gencow",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.215",
|
|
4
4
|
"description": "Gencow — AI Backend Engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^25.9.5",
|
|
35
35
|
"better-auth": "^1.6.23",
|
|
36
|
-
"@gencow/core": "0.1.43",
|
|
37
36
|
"@gencow/client": "0.2.7",
|
|
37
|
+
"@gencow/core": "0.1.43",
|
|
38
38
|
"@gencow/react": "0.2.7"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|