gencow 0.1.190 → 0.1.191
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.
|
@@ -16,6 +16,7 @@ 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(["blocked_catalog_outcome_unknown"]);
|
|
19
20
|
const CORRELATION_ID_PATTERN = /^[A-Za-z0-9_-]{8,128}$/u;
|
|
20
21
|
const DIAGNOSTIC_CODE_PATTERN = /^[A-Za-z][A-Za-z0-9_]{2,127}$/u;
|
|
21
22
|
const APP_ID_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+){2}$/u;
|
|
@@ -74,6 +75,20 @@ function isMatchingTerminalResponse(value, accepted, expectedAppId) {
|
|
|
74
75
|
);
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
function isMatchingTerminalFailureResponse(value, accepted, expectedAppId) {
|
|
79
|
+
return (
|
|
80
|
+
value &&
|
|
81
|
+
typeof value === "object" &&
|
|
82
|
+
!Array.isArray(value) &&
|
|
83
|
+
value.success === false &&
|
|
84
|
+
value.deleted === expectedAppId &&
|
|
85
|
+
value.operationId === accepted.operationId &&
|
|
86
|
+
value.correlationId === accepted.correlationId &&
|
|
87
|
+
APP_DELETE_TERMINAL_FAILURE_STATES.has(value.state) &&
|
|
88
|
+
DIAGNOSTIC_CODE_PATTERN.test(value.code ?? "")
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
77
92
|
export async function pollAppDeleteOperation({
|
|
78
93
|
creds,
|
|
79
94
|
initialBody,
|
|
@@ -99,6 +114,9 @@ export async function pollAppDeleteOperation({
|
|
|
99
114
|
if (!statusRes?.ok || !statusData) return invalidPollResponse(accepted);
|
|
100
115
|
successfulPollResponses += 1;
|
|
101
116
|
if (isMatchingTerminalResponse(statusData, accepted, name)) return statusData;
|
|
117
|
+
if (isMatchingTerminalFailureResponse(statusData, accepted, name)) {
|
|
118
|
+
return { ...statusData, error: statusData.code };
|
|
119
|
+
}
|
|
102
120
|
const operation = parseAppDeleteOperationEnvelope(statusData, name);
|
|
103
121
|
if (
|
|
104
122
|
!operation ||
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { posix, win32 } from "node:path";
|
|
2
|
+
|
|
3
|
+
export function toDrizzleProjectPath(projectRoot, canonicalFile) {
|
|
4
|
+
const pathApi = win32.isAbsolute(projectRoot) ? win32 : posix;
|
|
5
|
+
const projectPath = pathApi.relative(projectRoot, canonicalFile).replaceAll("\\", "/");
|
|
6
|
+
return projectPath.startsWith(".") ? projectPath : `./${projectPath}`;
|
|
7
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { existsSync, lstatSync, realpathSync } from "node:fs";
|
|
2
2
|
import { basename, dirname, isAbsolute, relative, resolve } from "node:path";
|
|
3
3
|
|
|
4
|
+
import { toDrizzleProjectPath } from "./canonical-drizzle-generator-paths.mjs";
|
|
5
|
+
|
|
4
6
|
export const GENCOW_DRIZZLE_CONFIG_CONTRACT_VERSION = 1;
|
|
5
7
|
|
|
6
8
|
function requiredEnvironment(name) {
|
|
@@ -38,7 +40,7 @@ function resolveSchemaFiles(projectRoot) {
|
|
|
38
40
|
}
|
|
39
41
|
if (!seen.has(canonical)) {
|
|
40
42
|
seen.add(canonical);
|
|
41
|
-
files.push(canonical);
|
|
43
|
+
files.push(toDrizzleProjectPath(projectRoot, canonical));
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
if (files.length === 0) throw new Error("Gencow migration schema list is empty");
|
|
@@ -6,6 +6,7 @@ export const REQUIRED_CLI_TARBALL_FILES = Object.freeze([
|
|
|
6
6
|
"lib/cron-manifest.mjs",
|
|
7
7
|
"lib/dev-cloud-bundle.mjs",
|
|
8
8
|
"lib/canonical-drizzle-generator.config.mjs",
|
|
9
|
+
"lib/canonical-drizzle-generator-paths.mjs",
|
|
9
10
|
"runtime/tooling.mjs",
|
|
10
11
|
"runtime/server.mjs",
|
|
11
12
|
"templateFeature/ai/manifest.json",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gencow",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.191",
|
|
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.42",
|
|
37
36
|
"@gencow/client": "0.2.6",
|
|
37
|
+
"@gencow/core": "0.1.42",
|
|
38
38
|
"@gencow/react": "0.2.6"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
package/runtime/server.mjs
CHANGED
|
@@ -88955,7 +88955,7 @@ var require_package = __commonJS({
|
|
|
88955
88955
|
var require_libvips = __commonJS({
|
|
88956
88956
|
"../../node_modules/.pnpm/sharp@0.34.5/node_modules/sharp/lib/libvips.js"(exports2, module2) {
|
|
88957
88957
|
var { spawnSync } = __require("node:child_process");
|
|
88958
|
-
var { createHash:
|
|
88958
|
+
var { createHash: createHash25 } = __require("node:crypto");
|
|
88959
88959
|
var semverCoerce = require_coerce();
|
|
88960
88960
|
var semverGreaterThanOrEqualTo = require_gte();
|
|
88961
88961
|
var semverSatisfies = require_satisfies();
|
|
@@ -89046,7 +89046,7 @@ var require_libvips = __commonJS({
|
|
|
89046
89046
|
}
|
|
89047
89047
|
return false;
|
|
89048
89048
|
};
|
|
89049
|
-
var sha512 = (s) =>
|
|
89049
|
+
var sha512 = (s) => createHash25("sha512").update(s).digest("hex");
|
|
89050
89050
|
var yarnLocator = () => {
|
|
89051
89051
|
try {
|
|
89052
89052
|
const identHash = sha512(`imgsharp-libvips-${buildPlatformArch()}`);
|
|
@@ -94229,7 +94229,29 @@ var init_platform_active_slot = __esm({
|
|
|
94229
94229
|
});
|
|
94230
94230
|
|
|
94231
94231
|
// ../server/dist/server-platform-slot-promotion.js
|
|
94232
|
-
import { timingSafeEqual as timingSafeEqual6 } from "crypto";
|
|
94232
|
+
import { createHash as createHash17, timingSafeEqual as timingSafeEqual6 } from "crypto";
|
|
94233
|
+
function parseRouteProjectionDegradedApprovalHeaders(input) {
|
|
94234
|
+
if (input.count === void 0 && input.digest === void 0 && input.appIds === void 0)
|
|
94235
|
+
return void 0;
|
|
94236
|
+
if (!/^[1-9][0-9]{0,3}$/u.test(input.count ?? "") || !/^[a-f0-9]{64}$/u.test(input.digest ?? "") || !/^[1-9][0-9]{0,9}(,[1-9][0-9]{0,9}){0,999}$/u.test(input.appIds ?? "")) {
|
|
94237
|
+
throw new Error("PLATFORM_ROUTE_DEGRADED_APPROVAL_INVALID");
|
|
94238
|
+
}
|
|
94239
|
+
const readyMismatchAppCount = Number(input.count);
|
|
94240
|
+
const readyMismatchAppIds = input.appIds.split(",").map(Number);
|
|
94241
|
+
const canonicalAppIds = [...new Set(readyMismatchAppIds)].sort((left, right) => left - right);
|
|
94242
|
+
const canonicalDigest = createHash17("sha256").update(JSON.stringify(canonicalAppIds)).digest("hex");
|
|
94243
|
+
if (!Number.isSafeInteger(readyMismatchAppCount) || readyMismatchAppCount > 1e3 || readyMismatchAppIds.some((appId) => !Number.isSafeInteger(appId) || appId <= 0) || readyMismatchAppIds.some((appId, index) => appId !== canonicalAppIds[index]) || readyMismatchAppCount !== canonicalAppIds.length || input.digest !== canonicalDigest) {
|
|
94244
|
+
throw new Error("PLATFORM_ROUTE_DEGRADED_APPROVAL_INVALID");
|
|
94245
|
+
}
|
|
94246
|
+
return { readyMismatchAppCount, readyMismatchAppDigest: input.digest, readyMismatchAppIds };
|
|
94247
|
+
}
|
|
94248
|
+
function routeProjectionDegradedApprovalFromRequest(context2) {
|
|
94249
|
+
return parseRouteProjectionDegradedApprovalHeaders({
|
|
94250
|
+
count: context2.req.header(ROUTE_READY_MISMATCH_COUNT_HEADER),
|
|
94251
|
+
digest: context2.req.header(ROUTE_READY_MISMATCH_DIGEST_HEADER),
|
|
94252
|
+
appIds: context2.req.header(ROUTE_READY_MISMATCH_APP_IDS_HEADER)
|
|
94253
|
+
});
|
|
94254
|
+
}
|
|
94233
94255
|
function applyPlatformSlotPromotionRequestTimeout(request, server) {
|
|
94234
94256
|
if (!["/internal/platform-slot/prepare-promotion", "/internal/platform-slot/promote"].includes(new URL(request.url).pathname))
|
|
94235
94257
|
return false;
|
|
@@ -94274,8 +94296,9 @@ function registerPlatformSlotPromotionRoute(params) {
|
|
|
94274
94296
|
}
|
|
94275
94297
|
try {
|
|
94276
94298
|
state2 = "preparing";
|
|
94299
|
+
const approval = routeProjectionDegradedApprovalFromRequest(c);
|
|
94277
94300
|
const result2 = await params.autoRecoveryRuntime.promote();
|
|
94278
|
-
const evidence = await params.assertTenantRouteParity?.();
|
|
94301
|
+
const evidence = await params.assertTenantRouteParity?.(approval);
|
|
94279
94302
|
if (!evidence?.evidenceDigest || !Number.isSafeInteger(evidence.bindingCount)) {
|
|
94280
94303
|
throw new Error("PLATFORM_TENANT_ROUTE_PARITY_EVIDENCE_INVALID");
|
|
94281
94304
|
}
|
|
@@ -94306,7 +94329,8 @@ function registerPlatformSlotPromotionRoute(params) {
|
|
|
94306
94329
|
return c.json({ status: "prepared", promoted: false, code: "PLATFORM_SLOT_NOT_ROUTED" }, 409);
|
|
94307
94330
|
}
|
|
94308
94331
|
state2 = "promoting";
|
|
94309
|
-
const
|
|
94332
|
+
const approval = routeProjectionDegradedApprovalFromRequest(c);
|
|
94333
|
+
const currentEvidence = await params.assertTenantRouteParity?.(approval);
|
|
94310
94334
|
if (!currentEvidence || currentEvidence.bindingCount !== preparedEvidence.bindingCount || currentEvidence.evidenceDigest !== preparedEvidence.evidenceDigest)
|
|
94311
94335
|
throw new Error("PLATFORM_TENANT_ROUTE_PARITY_EVIDENCE_CHANGED");
|
|
94312
94336
|
params.setCandidateMode(false);
|
|
@@ -94322,11 +94346,14 @@ function registerPlatformSlotPromotionRoute(params) {
|
|
|
94322
94346
|
}
|
|
94323
94347
|
});
|
|
94324
94348
|
}
|
|
94325
|
-
var PLATFORM_SLOT_PROMOTION_REQUEST_TIMEOUT_SECONDS;
|
|
94349
|
+
var ROUTE_READY_MISMATCH_COUNT_HEADER, ROUTE_READY_MISMATCH_DIGEST_HEADER, ROUTE_READY_MISMATCH_APP_IDS_HEADER, PLATFORM_SLOT_PROMOTION_REQUEST_TIMEOUT_SECONDS;
|
|
94326
94350
|
var init_server_platform_slot_promotion = __esm({
|
|
94327
94351
|
"../server/dist/server-platform-slot-promotion.js"() {
|
|
94328
94352
|
"use strict";
|
|
94329
94353
|
init_platform_active_slot();
|
|
94354
|
+
ROUTE_READY_MISMATCH_COUNT_HEADER = "X-Gencow-Emergency-Route-Ready-Mismatch-Count";
|
|
94355
|
+
ROUTE_READY_MISMATCH_DIGEST_HEADER = "X-Gencow-Emergency-Route-Ready-Mismatch-Digest";
|
|
94356
|
+
ROUTE_READY_MISMATCH_APP_IDS_HEADER = "X-Gencow-Emergency-Route-Ready-Mismatch-App-Ids";
|
|
94330
94357
|
PLATFORM_SLOT_PROMOTION_REQUEST_TIMEOUT_SECONDS = 240;
|
|
94331
94358
|
}
|
|
94332
94359
|
});
|
|
@@ -134090,7 +134117,7 @@ var init_official_custom_domains = __esm({
|
|
|
134090
134117
|
});
|
|
134091
134118
|
|
|
134092
134119
|
// ../server/dist/server-platform-app-proxy-domain.js
|
|
134093
|
-
import { createHash as
|
|
134120
|
+
import { createHash as createHash22 } from "crypto";
|
|
134094
134121
|
function stripTrailingDots(host) {
|
|
134095
134122
|
return host.replace(/\.+$/, "");
|
|
134096
134123
|
}
|
|
@@ -134169,7 +134196,7 @@ function decodeActiveDomainApp(value, expectedHostname) {
|
|
|
134169
134196
|
return { appName, verifiedBinding };
|
|
134170
134197
|
}
|
|
134171
134198
|
function hashCustomDomainHost(host) {
|
|
134172
|
-
return
|
|
134199
|
+
return createHash22("sha256").update(host).digest("hex").slice(0, 16);
|
|
134173
134200
|
}
|
|
134174
134201
|
function isGenerationChangedError(error51) {
|
|
134175
134202
|
return error51?.code === "GENCOW_DB_GENERATION_CHANGED";
|
|
@@ -134409,7 +134436,7 @@ var init_server_platform_media_worker_storage_runtime = __esm({
|
|
|
134409
134436
|
});
|
|
134410
134437
|
|
|
134411
134438
|
// ../server/dist/server-runtime-activity-store.js
|
|
134412
|
-
import { createHash as
|
|
134439
|
+
import { createHash as createHash23 } from "node:crypto";
|
|
134413
134440
|
function rowsFromUnknown3(result2) {
|
|
134414
134441
|
if (Array.isArray(result2))
|
|
134415
134442
|
return result2;
|
|
@@ -134660,7 +134687,7 @@ async function checkpointRuntimeActivity(rawSql, checkpoint) {
|
|
|
134660
134687
|
if (!Number.isSafeInteger(appId) || !Number.isSafeInteger(activityEpoch) || activityEpoch < 0 || !nodeId || !Number.isSafeInteger(nodeEpoch) || nodeEpoch < 0) {
|
|
134661
134688
|
return null;
|
|
134662
134689
|
}
|
|
134663
|
-
const bindingHash =
|
|
134690
|
+
const bindingHash = createHash23("sha256").update(JSON.stringify([
|
|
134664
134691
|
"runtime-activity-binding-v1",
|
|
134665
134692
|
appId,
|
|
134666
134693
|
typeof row?.activation_id === "string" ? row.activation_id : null,
|
|
@@ -149672,7 +149699,7 @@ var init_server_platform_notification_worker_runtime = __esm({
|
|
|
149672
149699
|
});
|
|
149673
149700
|
|
|
149674
149701
|
// ../server/src/server-node-proxy-signature.ts
|
|
149675
|
-
import { createHash as
|
|
149702
|
+
import { createHash as createHash24, createHmac as createHmac9, timingSafeEqual as timingSafeEqual11 } from "crypto";
|
|
149676
149703
|
function sanitizeNodeProxyForwardHeaders(headers) {
|
|
149677
149704
|
const sanitized = new Headers();
|
|
149678
149705
|
for (const [key, value] of headers.entries()) {
|
|
@@ -149695,7 +149722,7 @@ function canonicalSignedHeaderHash2(headers) {
|
|
|
149695
149722
|
const value = headers?.get(name) ?? "";
|
|
149696
149723
|
return `${name}:${value.trim()}`;
|
|
149697
149724
|
}).join("\n");
|
|
149698
|
-
return
|
|
149725
|
+
return createHash24("sha256").update(canonical).digest("base64url");
|
|
149699
149726
|
}
|
|
149700
149727
|
function buildSignaturePayload2(input) {
|
|
149701
149728
|
return [
|
|
@@ -150030,17 +150057,22 @@ var init_server_platform_runtime_helpers = __esm({
|
|
|
150030
150057
|
|
|
150031
150058
|
// ../server/dist/server-legacy-runtime-recovery-route.js
|
|
150032
150059
|
import { resolve as resolve45 } from "node:path";
|
|
150060
|
+
function parseLegacyRuntimeRecoveryMode(value) {
|
|
150061
|
+
return value === "preserve_replace" || value === "canonicalize_absent" || value === "retire_unadmitted" ? value : null;
|
|
150062
|
+
}
|
|
150033
150063
|
function registerLegacyRuntimeRecoveryRoute(params) {
|
|
150034
150064
|
const logger3 = params.logger ?? console;
|
|
150035
150065
|
params.app.post("/internal/runtime-recovery/legacy-preserve-replace", async (c) => {
|
|
150036
|
-
if (
|
|
150066
|
+
if (params.internalToken && c.req.header("X-Internal-Token") !== params.internalToken) {
|
|
150037
150067
|
return c.json({ error: "Forbidden" }, 403);
|
|
150038
150068
|
}
|
|
150039
150069
|
const body = await c.req.json().catch(() => null);
|
|
150040
150070
|
const appName = typeof body?.appName === "string" ? body.appName.trim() : "";
|
|
150041
|
-
const mode = body?.mode
|
|
150071
|
+
const mode = parseLegacyRuntimeRecoveryMode(body?.mode ?? "preserve_replace");
|
|
150042
150072
|
if (!APP_NAME.test(appName))
|
|
150043
150073
|
return c.json({ error: "appName required" }, 400);
|
|
150074
|
+
if (!mode)
|
|
150075
|
+
return c.json({ error: "recovery mode invalid" }, 400);
|
|
150044
150076
|
if (!await params.isActiveController())
|
|
150045
150077
|
return c.json({ error: "Controller unavailable" }, 409);
|
|
150046
150078
|
try {
|
|
@@ -150060,6 +150092,63 @@ function registerLegacyRuntimeRecoveryRoute(params) {
|
|
|
150060
150092
|
const result3 = await convergeMalformedLegacyAbsence({ db: params.db, appId: app2.id, appName, currentNodeId: params.currentNodeId, evidence });
|
|
150061
150093
|
return c.json({ ok: true, result: result3 });
|
|
150062
150094
|
}
|
|
150095
|
+
if (mode === "retire_unadmitted") {
|
|
150096
|
+
const { getRuntimeLifecycleActivityCoordinator } = await import(resolve45(params.functionsPath, "../src/runtime-lifecycle-activity-coordinator.ts"));
|
|
150097
|
+
const { stopRuntimeAuthoritatively } = await import(resolve45(params.functionsPath, "../src/runtime-control-plane-lifecycle.ts"));
|
|
150098
|
+
const { observeLegacyRuntimeEvidence } = await import(resolve45(params.functionsPath, "../src/legacy-runtime-evidence-observer.ts"));
|
|
150099
|
+
const { convergeMalformedLegacyAbsence } = await import(resolve45(params.functionsPath, "../src/runtime-malformed-legacy-absence-recovery.ts"));
|
|
150100
|
+
const currentRows = await params.db.select({
|
|
150101
|
+
port: params.appsTable.port,
|
|
150102
|
+
instanceId: params.appsTable.instanceId,
|
|
150103
|
+
dataDir: params.appsTable.dataDir,
|
|
150104
|
+
nodeId: params.appsTable.nodeId,
|
|
150105
|
+
currentDeployId: params.appsTable.currentDeployId,
|
|
150106
|
+
hasBackend: params.appsTable.hasBackend
|
|
150107
|
+
}).from(params.appsTable).where(params.eqOp(params.appsTable.id, app2.id)).limit(1);
|
|
150108
|
+
const current = currentRows[0];
|
|
150109
|
+
const activity = getRuntimeLifecycleActivityCoordinator();
|
|
150110
|
+
if (!current || !activity)
|
|
150111
|
+
throw new Error("LEGACY_RUNTIME_RETIRE_COORDINATOR_UNAVAILABLE");
|
|
150112
|
+
activity.closeExplicitDrainGate(app2.id, appName);
|
|
150113
|
+
try {
|
|
150114
|
+
await activity.synchronizeRuntimeBinding(app2.id, appName);
|
|
150115
|
+
await activity.waitForQuiescence(app2.id, appName);
|
|
150116
|
+
const before2 = await observeLegacyRuntimeEvidence({
|
|
150117
|
+
appName,
|
|
150118
|
+
appPort: current.port,
|
|
150119
|
+
appNodeId: params.currentNodeId,
|
|
150120
|
+
currentNodeId: params.currentNodeId
|
|
150121
|
+
});
|
|
150122
|
+
if (!before2.observationComplete || ![before2.directProcess, before2.warmPoolAssignment, before2.listener].includes("present") || before2.effectiveRoute !== "exact") {
|
|
150123
|
+
throw new Error("LEGACY_RUNTIME_RETIRE_INCUMBENT_NOT_EXACT");
|
|
150124
|
+
}
|
|
150125
|
+
await stopRuntimeAuthoritatively({
|
|
150126
|
+
db: params.db,
|
|
150127
|
+
app: { id: app2.id, name: appName, ...current },
|
|
150128
|
+
currentNodeId: params.currentNodeId,
|
|
150129
|
+
reason: "operator_stop",
|
|
150130
|
+
actorId: "legacy-runtime-recovery",
|
|
150131
|
+
actorKind: "platform",
|
|
150132
|
+
expectedAuthority: "observe"
|
|
150133
|
+
});
|
|
150134
|
+
const evidence = await observeLegacyRuntimeEvidence({
|
|
150135
|
+
appName,
|
|
150136
|
+
appPort: current.port,
|
|
150137
|
+
appNodeId: params.currentNodeId,
|
|
150138
|
+
currentNodeId: params.currentNodeId
|
|
150139
|
+
});
|
|
150140
|
+
const result3 = await convergeMalformedLegacyAbsence({
|
|
150141
|
+
db: params.db,
|
|
150142
|
+
appId: app2.id,
|
|
150143
|
+
appName,
|
|
150144
|
+
currentNodeId: params.currentNodeId,
|
|
150145
|
+
evidence
|
|
150146
|
+
});
|
|
150147
|
+
return c.json({ ok: true, result: result3 });
|
|
150148
|
+
} finally {
|
|
150149
|
+
activity.reopenDrainGate(app2.id);
|
|
150150
|
+
}
|
|
150151
|
+
}
|
|
150063
150152
|
const { convergeLegacyRuntimeAuthority } = await import(resolve45(params.functionsPath, "../src/legacy-runtime-bootstrap-orchestrator.ts"));
|
|
150064
150153
|
const result2 = await convergeLegacyRuntimeAuthority({
|
|
150065
150154
|
db: params.db,
|
|
@@ -150644,7 +150733,7 @@ async function bootstrapPlatformRuntime(params) {
|
|
|
150644
150733
|
const convergeRuntimeRouteProjection = requirePlatformExplicitStopConverger(autoRecoveryRuntime.convergeRuntimeRouteProjection);
|
|
150645
150734
|
routeProjectionRuntime.setAbsentRouteConverger(convergeRuntimeRouteProjection);
|
|
150646
150735
|
params.app.get("/internal/platform-recovery/status", (c) => c.json(autoRecoveryRuntime.snapshot()));
|
|
150647
|
-
registerProcessPlatformSlotPromotionRoute(params.app, params.rawSql, autoRecoveryRuntime, () => routeProjectionRuntime.convergeServingFleet(), logger3);
|
|
150736
|
+
registerProcessPlatformSlotPromotionRoute(params.app, params.rawSql, autoRecoveryRuntime, (approval) => routeProjectionRuntime.convergeServingFleet(approval), logger3);
|
|
150648
150737
|
const explicitStopReconciler = await preparePlatformExplicitStopReconcilerForRuntime({
|
|
150649
150738
|
functionsPath: params.functionsPath,
|
|
150650
150739
|
db: params.db,
|
|
@@ -152779,6 +152868,8 @@ function classifyPostgresClientFailure(error51) {
|
|
|
152779
152868
|
}
|
|
152780
152869
|
for (const item of chain2) {
|
|
152781
152870
|
const code = errorCode(item);
|
|
152871
|
+
if (code === "GENCOW_DB_GENERATION_CHANGED")
|
|
152872
|
+
return "generation_changed";
|
|
152782
152873
|
if (code === "ERR_POSTGRES_CONNECTION_CLOSED")
|
|
152783
152874
|
return "connection_closed";
|
|
152784
152875
|
if (code === "ECONNRESET" || code === "EPIPE")
|
|
@@ -152919,11 +153010,11 @@ function createRuntimePostgresGenerationManager(params) {
|
|
|
152919
153010
|
let recoveryAttempts = 0;
|
|
152920
153011
|
let recoveryTimer;
|
|
152921
153012
|
const randomUnit = () => Math.min(0.999999999, Math.max(0, randomImpl()));
|
|
152922
|
-
function createRecord(client, generation, jitterMs) {
|
|
153013
|
+
function createRecord(client, generation, jitterMs, state2 = "healthy") {
|
|
152923
153014
|
return {
|
|
152924
153015
|
client,
|
|
152925
153016
|
generation,
|
|
152926
|
-
state:
|
|
153017
|
+
state: state2,
|
|
152927
153018
|
inFlight: 0,
|
|
152928
153019
|
closeStarted: false,
|
|
152929
153020
|
admitAfter: Date.now() + jitterMs
|
|
@@ -152932,7 +153023,7 @@ function createRuntimePostgresGenerationManager(params) {
|
|
|
152932
153023
|
function snapshot() {
|
|
152933
153024
|
if (managerClosed)
|
|
152934
153025
|
throw new RuntimePostgresGenerationError("GENCOW_DB_CLIENT_CLOSED");
|
|
152935
|
-
if (active.state !== "healthy") {
|
|
153026
|
+
if (active.state !== "healthy" && active.state !== "suspect") {
|
|
152936
153027
|
throw new RuntimePostgresGenerationError("GENCOW_DB_RECOVERY_CIRCUIT_OPEN");
|
|
152937
153028
|
}
|
|
152938
153029
|
return { client: active.client, generation: active.generation };
|
|
@@ -152951,7 +153042,7 @@ function createRuntimePostgresGenerationManager(params) {
|
|
|
152951
153042
|
void params.closeClient(record2.client).finally(() => {
|
|
152952
153043
|
record2.state = "closed";
|
|
152953
153044
|
quarantined.delete(record2.generation);
|
|
152954
|
-
if (!managerClosed && recoveryCircuitOpen && active.state !== "healthy" && quarantined.size < maxQuarantinedGenerations) {
|
|
153045
|
+
if (!managerClosed && recoveryCircuitOpen && active.state !== "healthy" && active.state !== "suspect" && quarantined.size < maxQuarantinedGenerations) {
|
|
152955
153046
|
const reason = lastRecoveryReason ?? "generation_capacity_recovered";
|
|
152956
153047
|
scheduleRecovery(reason);
|
|
152957
153048
|
}
|
|
@@ -152965,14 +153056,20 @@ function createRuntimePostgresGenerationManager(params) {
|
|
|
152965
153056
|
try {
|
|
152966
153057
|
nextGeneration += 1;
|
|
152967
153058
|
const jitterMs = recoveryJitterMaxMs === 0 ? 0 : Math.floor(randomUnit() * (recoveryJitterMaxMs + 1));
|
|
152968
|
-
active = createRecord(params.createClient(), nextGeneration, jitterMs);
|
|
152969
|
-
recoveryCircuitOpen = false;
|
|
152970
|
-
recoveryAttempts = 0;
|
|
152971
|
-
recoveryInFlight = false;
|
|
153059
|
+
active = createRecord(params.createClient(), nextGeneration, jitterMs, params.verifyClient ? "suspect" : "healthy");
|
|
152972
153060
|
if (recoveryTimer) {
|
|
152973
153061
|
clearTimeoutImpl(recoveryTimer);
|
|
152974
153062
|
recoveryTimer = void 0;
|
|
152975
153063
|
}
|
|
153064
|
+
if (params.verifyClient) {
|
|
153065
|
+
recoveryCircuitOpen = true;
|
|
153066
|
+
recoveryInFlight = true;
|
|
153067
|
+
active.verification = verifyReplacement(active, reason);
|
|
153068
|
+
return true;
|
|
153069
|
+
}
|
|
153070
|
+
recoveryCircuitOpen = false;
|
|
153071
|
+
recoveryAttempts = 0;
|
|
153072
|
+
recoveryInFlight = false;
|
|
152976
153073
|
params.onRecovered?.({ generation: nextGeneration, reason });
|
|
152977
153074
|
return true;
|
|
152978
153075
|
} catch {
|
|
@@ -152980,8 +153077,39 @@ function createRuntimePostgresGenerationManager(params) {
|
|
|
152980
153077
|
return false;
|
|
152981
153078
|
}
|
|
152982
153079
|
}
|
|
153080
|
+
async function verifyReplacement(record2, reason) {
|
|
153081
|
+
try {
|
|
153082
|
+
const waitMs = Math.max(0, record2.admitAfter - Date.now());
|
|
153083
|
+
if (waitMs > 0) {
|
|
153084
|
+
await new Promise((resolve50) => {
|
|
153085
|
+
const timer2 = setTimeoutImpl(resolve50, waitMs);
|
|
153086
|
+
timer2.unref?.();
|
|
153087
|
+
});
|
|
153088
|
+
}
|
|
153089
|
+
await params.verifyClient?.(record2.client);
|
|
153090
|
+
if (managerClosed || record2 !== active || record2.state !== "suspect") {
|
|
153091
|
+
return;
|
|
153092
|
+
}
|
|
153093
|
+
record2.state = "healthy";
|
|
153094
|
+
recoveryCircuitOpen = false;
|
|
153095
|
+
recoveryInFlight = false;
|
|
153096
|
+
recoveryAttempts = 0;
|
|
153097
|
+
params.onRecovered?.({ generation: record2.generation, reason });
|
|
153098
|
+
} catch {
|
|
153099
|
+
if (managerClosed || record2 !== active || record2.state !== "suspect") {
|
|
153100
|
+
return;
|
|
153101
|
+
}
|
|
153102
|
+
record2.state = "quarantined";
|
|
153103
|
+
quarantined.set(record2.generation, record2);
|
|
153104
|
+
lastRecoveryReason = reason;
|
|
153105
|
+
recoveryCircuitOpen = true;
|
|
153106
|
+
recoveryInFlight = false;
|
|
153107
|
+
closeWhenDrained(record2);
|
|
153108
|
+
scheduleRecovery(reason);
|
|
153109
|
+
}
|
|
153110
|
+
}
|
|
152983
153111
|
function scheduleRecovery(reason) {
|
|
152984
|
-
if (managerClosed || active.state === "healthy" || recoveryTimer)
|
|
153112
|
+
if (managerClosed || active.state === "healthy" || active.state === "suspect" || recoveryTimer)
|
|
152985
153113
|
return;
|
|
152986
153114
|
recoveryInFlight = true;
|
|
152987
153115
|
recoveryAttempts += 1;
|
|
@@ -153007,12 +153135,18 @@ function createRuntimePostgresGenerationManager(params) {
|
|
|
153007
153135
|
}
|
|
153008
153136
|
record2.inFlight += 1;
|
|
153009
153137
|
return Promise.resolve().then(async () => {
|
|
153138
|
+
if (record2.state === "suspect") {
|
|
153139
|
+
await record2.verification;
|
|
153140
|
+
}
|
|
153010
153141
|
const waitMs = Math.max(0, record2.admitAfter - Date.now());
|
|
153011
153142
|
if (waitMs > 0)
|
|
153012
153143
|
await new Promise((resolve50) => setTimeout(resolve50, waitMs));
|
|
153013
|
-
if (managerClosed || record2
|
|
153144
|
+
if (managerClosed || record2 !== active) {
|
|
153014
153145
|
throw new RuntimePostgresGenerationError("GENCOW_DB_GENERATION_CHANGED");
|
|
153015
153146
|
}
|
|
153147
|
+
if (record2.state !== "healthy") {
|
|
153148
|
+
throw new RuntimePostgresGenerationError("GENCOW_DB_RECOVERY_CIRCUIT_OPEN");
|
|
153149
|
+
}
|
|
153016
153150
|
return work();
|
|
153017
153151
|
}).finally(() => {
|
|
153018
153152
|
record2.inFlight = Math.max(0, record2.inFlight - 1);
|
|
@@ -153108,6 +153242,33 @@ async function closeWithBoundedWait(client, timeoutMs) {
|
|
|
153108
153242
|
} catch {
|
|
153109
153243
|
}
|
|
153110
153244
|
}
|
|
153245
|
+
async function verifyRuntimePostgresConnectivity(client, timeoutMs) {
|
|
153246
|
+
const pending = client.unsafe("SELECT 1");
|
|
153247
|
+
let timeout;
|
|
153248
|
+
try {
|
|
153249
|
+
await Promise.race([
|
|
153250
|
+
pending,
|
|
153251
|
+
new Promise((_3, reject2) => {
|
|
153252
|
+
timeout = setTimeout(() => {
|
|
153253
|
+
try {
|
|
153254
|
+
pending.cancel?.();
|
|
153255
|
+
} catch {
|
|
153256
|
+
}
|
|
153257
|
+
reject2(new RuntimePostgresClientError({
|
|
153258
|
+
reason: "operation_timeout",
|
|
153259
|
+
operation: "unsafe",
|
|
153260
|
+
generation: 0,
|
|
153261
|
+
elapsedMs: timeoutMs
|
|
153262
|
+
}));
|
|
153263
|
+
}, timeoutMs);
|
|
153264
|
+
timeout.unref?.();
|
|
153265
|
+
})
|
|
153266
|
+
]);
|
|
153267
|
+
} finally {
|
|
153268
|
+
if (timeout !== void 0)
|
|
153269
|
+
clearTimeout(timeout);
|
|
153270
|
+
}
|
|
153271
|
+
}
|
|
153111
153272
|
function rowsToValues(rows4) {
|
|
153112
153273
|
if (!Array.isArray(rows4))
|
|
153113
153274
|
return rows4;
|
|
@@ -153140,6 +153301,7 @@ function createRuntimePostgresClient(params) {
|
|
|
153140
153301
|
let lastFailure;
|
|
153141
153302
|
const generations = createRuntimePostgresGenerationManager({
|
|
153142
153303
|
createClient: params.createClient,
|
|
153304
|
+
verifyClient: (client) => verifyRuntimePostgresConnectivity(client, operationTimeoutMs > 0 ? operationTimeoutMs : 1e4),
|
|
153143
153305
|
closeClient: (client) => closeWithBoundedWait(client, 250),
|
|
153144
153306
|
recoveryJitterMaxMs: params.recoveryJitterMaxMs ?? (operationTimeoutMs > 0 ? Math.max(1, Math.min(25, Math.floor(operationTimeoutMs / 4))) : 25),
|
|
153145
153307
|
onRecovered: ({ generation, reason }) => {
|
|
@@ -153177,7 +153339,7 @@ function createRuntimePostgresClient(params) {
|
|
|
153177
153339
|
const causeCode = recordedFailure.causeCode ? ` causeCode=${recordedFailure.causeCode}` : "";
|
|
153178
153340
|
const causeName = recordedFailure.causeName ? ` causeName=${recordedFailure.causeName}` : "";
|
|
153179
153341
|
logger3.warn(`[db] postgres client quarantined label=${params.label}${dbInfo} reason=${recycleParams.reason} operation=${recycleParams.operation} elapsedMs=${recycleParams.elapsedMs} generation=${recycleParams.expectedGeneration} recoveries=${recoveries}${causeName}${causeCode}`);
|
|
153180
|
-
if (
|
|
153342
|
+
if (diagnostics.recoveryCircuitOpen) {
|
|
153181
153343
|
logger3.warn(`[db] postgres client circuit_open label=${params.label}${dbInfo} reason=${recycleParams.reason} generation=${diagnostics.activeGeneration} recoveries=${recoveries}`);
|
|
153182
153344
|
}
|
|
153183
153345
|
return recovery.recovered;
|
|
@@ -184150,6 +184312,7 @@ var ProcedureRpcHandler = class {
|
|
|
184150
184312
|
var RECYCLED_DB_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
184151
184313
|
"GENCOW_DB_CONNECTION_CLOSED",
|
|
184152
184314
|
"GENCOW_DB_CONNECTION_TIMEOUT",
|
|
184315
|
+
"GENCOW_DB_GENERATION_CHANGED",
|
|
184153
184316
|
"GENCOW_DB_OPERATION_TIMEOUT",
|
|
184154
184317
|
"GENCOW_DB_SOCKET_CLOSED"
|
|
184155
184318
|
]);
|
|
@@ -184250,6 +184413,7 @@ var APP_DELETE_ACTIVE_STATES = /* @__PURE__ */ new Set([
|
|
|
184250
184413
|
"failed_tenant_db_cleanup",
|
|
184251
184414
|
"failed_catalog_cleanup"
|
|
184252
184415
|
]);
|
|
184416
|
+
var APP_DELETE_TERMINAL_FAILURE_STATES = /* @__PURE__ */ new Set(["blocked_catalog_outcome_unknown"]);
|
|
184253
184417
|
var CAPABILITY_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/u;
|
|
184254
184418
|
function createAppDeleteStatusLoader(getQueryDef2) {
|
|
184255
184419
|
return async ({ ctx, args, result: result2 }) => {
|
|
@@ -184292,6 +184456,12 @@ function isMatchingNonterminalAppDeleteResult(value, accepted) {
|
|
|
184292
184456
|
const result2 = value;
|
|
184293
184457
|
return result2.operationId === accepted.operationId && result2.correlationId === accepted.correlationId && result2.deleted === accepted.deleted;
|
|
184294
184458
|
}
|
|
184459
|
+
function isMatchingTerminalFailureAppDeleteResult(value, accepted) {
|
|
184460
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
184461
|
+
return false;
|
|
184462
|
+
const result2 = value;
|
|
184463
|
+
return result2.success === false && APP_DELETE_TERMINAL_FAILURE_STATES.has(String(result2.state ?? "")) && result2.operationId === accepted.operationId && result2.correlationId === accepted.correlationId && result2.deleted === accepted.deleted;
|
|
184464
|
+
}
|
|
184295
184465
|
async function resolveMutationSuccessResponse(input) {
|
|
184296
184466
|
if (input.mutationName !== "apps.delete" || !isNonterminalAppDeleteResult(input.result)) {
|
|
184297
184467
|
return { result: input.result, status: 201 };
|
|
@@ -184319,6 +184489,9 @@ async function resolveMutationSuccessResponse(input) {
|
|
|
184319
184489
|
if (isMatchingTerminalAppDeleteResult(status, accepted)) {
|
|
184320
184490
|
return { result: status, status: 201 };
|
|
184321
184491
|
}
|
|
184492
|
+
if (isMatchingTerminalFailureAppDeleteResult(status, accepted)) {
|
|
184493
|
+
return { result: status, status: 409 };
|
|
184494
|
+
}
|
|
184322
184495
|
if (!isMatchingNonterminalAppDeleteResult(status, accepted)) {
|
|
184323
184496
|
return { result: input.result, status: 409 };
|
|
184324
184497
|
}
|
|
@@ -188192,6 +188365,16 @@ function registerServerHealthRoutes(input) {
|
|
|
188192
188365
|
isCoreAdmissionReady: input.isCoreAdmissionReady
|
|
188193
188366
|
}));
|
|
188194
188367
|
input.app.get("/health/ready", createReadinessHandler({
|
|
188368
|
+
rawSql: input.rawSql,
|
|
188369
|
+
checkPlatformDatabaseCapabilities: input.platformDatabaseCapabilities ? () => input.platformDatabaseCapabilities.checkReadiness() : void 0,
|
|
188370
|
+
requirePlatformDatabaseCapabilities: input.isPlatform,
|
|
188371
|
+
getRegisteredQueries: input.getRegisteredQueries,
|
|
188372
|
+
getRegisteredMutations: input.getRegisteredMutations,
|
|
188373
|
+
getOperationInventory: input.getOperationInventory,
|
|
188374
|
+
runtimeEnv: input.runtimeEnv,
|
|
188375
|
+
readDeepHealth: platformDeepHealth?.read
|
|
188376
|
+
}));
|
|
188377
|
+
input.app.get("/health/route-ready", createReadinessHandler({
|
|
188195
188378
|
rawSql: input.rawSql,
|
|
188196
188379
|
checkPlatformDatabaseCapabilities: input.platformDatabaseCapabilities ? () => input.platformDatabaseCapabilities.checkReadiness() : void 0,
|
|
188197
188380
|
requirePlatformDatabaseCapabilities: input.isPlatform,
|
|
@@ -189973,7 +190156,7 @@ async function recordAuthActivity(dbInstance2, c, params) {
|
|
|
189973
190156
|
}
|
|
189974
190157
|
|
|
189975
190158
|
// ../server/dist/auth-oauth-exchange-store.js
|
|
189976
|
-
import { createHash as
|
|
190159
|
+
import { createHash as createHash18 } from "crypto";
|
|
189977
190160
|
import { sql as sql29 } from "drizzle-orm";
|
|
189978
190161
|
|
|
189979
190162
|
// ../server/dist/crypto.js
|
|
@@ -189997,8 +190180,8 @@ function getSecretKey() {
|
|
|
189997
190180
|
return cachedKey;
|
|
189998
190181
|
const internalToken = process.env.GENCOW_INTERNAL_TOKEN;
|
|
189999
190182
|
if (internalToken) {
|
|
190000
|
-
const { createHash:
|
|
190001
|
-
cachedKey =
|
|
190183
|
+
const { createHash: createHash25 } = __require("crypto");
|
|
190184
|
+
cachedKey = createHash25("sha256").update(`gencow-settings-key:${internalToken}`).digest().subarray(0, KEY_LENGTH);
|
|
190002
190185
|
return cachedKey;
|
|
190003
190186
|
}
|
|
190004
190187
|
const keyPath = resolveSecretKeyPath();
|
|
@@ -190069,7 +190252,7 @@ function rowsFromResult17(result2) {
|
|
|
190069
190252
|
return [];
|
|
190070
190253
|
}
|
|
190071
190254
|
function hashOAuthExchangeCode(code) {
|
|
190072
|
-
return
|
|
190255
|
+
return createHash18("sha256").update(code).digest("hex");
|
|
190073
190256
|
}
|
|
190074
190257
|
async function createOAuthExchangeCode(db, record2) {
|
|
190075
190258
|
const code = crypto.randomUUID();
|
|
@@ -191713,7 +191896,7 @@ async function resolveAuthMePayload(input) {
|
|
|
191713
191896
|
}
|
|
191714
191897
|
|
|
191715
191898
|
// ../server/dist/auth-oauth-invite-reservation.js
|
|
191716
|
-
import { createHash as
|
|
191899
|
+
import { createHash as createHash19, randomUUID as randomUUID12 } from "crypto";
|
|
191717
191900
|
import { sql as sql33 } from "drizzle-orm";
|
|
191718
191901
|
|
|
191719
191902
|
// ../server/dist/invite-code.js
|
|
@@ -191809,7 +191992,7 @@ function rowsFromResult21(result2) {
|
|
|
191809
191992
|
return [];
|
|
191810
191993
|
}
|
|
191811
191994
|
function hashReservationToken(token) {
|
|
191812
|
-
return
|
|
191995
|
+
return createHash19("sha256").update(token).digest("hex");
|
|
191813
191996
|
}
|
|
191814
191997
|
function normalizeProvider2(provider) {
|
|
191815
191998
|
return typeof provider === "string" && provider.trim() ? provider.trim().toLowerCase() : "unknown";
|
|
@@ -191915,7 +192098,7 @@ async function finalizeOAuthInviteReservation(db, token, user2) {
|
|
|
191915
192098
|
}
|
|
191916
192099
|
|
|
191917
192100
|
// ../server/dist/auth-oauth-signup-handoff.js
|
|
191918
|
-
import { createHash as
|
|
192101
|
+
import { createHash as createHash20, randomUUID as randomUUID13 } from "crypto";
|
|
191919
192102
|
import { sql as sql34 } from "drizzle-orm";
|
|
191920
192103
|
init_postgres_temporal();
|
|
191921
192104
|
var OAUTH_SIGNUP_HANDOFF_TTL_MS = BETTER_AUTH_OAUTH_STATE_TTL_MS + 5 * 60 * 1e3;
|
|
@@ -191928,7 +192111,7 @@ function rowsFromResult22(result2) {
|
|
|
191928
192111
|
return [];
|
|
191929
192112
|
}
|
|
191930
192113
|
function hashHandoffToken(token) {
|
|
191931
|
-
return
|
|
192114
|
+
return createHash20("sha256").update(token).digest("hex");
|
|
191932
192115
|
}
|
|
191933
192116
|
function normalizeProvider3(provider) {
|
|
191934
192117
|
return typeof provider === "string" && provider.trim() ? provider.trim().toLowerCase() : "unknown";
|
|
@@ -192201,7 +192384,7 @@ function enforceAuthRateLimit(c, pathname, options = {}) {
|
|
|
192201
192384
|
}
|
|
192202
192385
|
|
|
192203
192386
|
// ../server/dist/server-node-proxy-signature.js
|
|
192204
|
-
import { createHash as
|
|
192387
|
+
import { createHash as createHash21, createHmac as createHmac8, timingSafeEqual as timingSafeEqual10 } from "crypto";
|
|
192205
192388
|
var NODE_PROXY_VERSION = "v1";
|
|
192206
192389
|
var DEFAULT_MAX_SKEW_MS = 3e4;
|
|
192207
192390
|
var NODE_PROXY_CONTROL_PLANE_APP_HEADER = "X-Gencow-Control-Plane-App";
|
|
@@ -192225,7 +192408,7 @@ function canonicalSignedHeaderHash(headers) {
|
|
|
192225
192408
|
const value = headers?.get(name) ?? "";
|
|
192226
192409
|
return `${name}:${value.trim()}`;
|
|
192227
192410
|
}).join("\n");
|
|
192228
|
-
return
|
|
192411
|
+
return createHash21("sha256").update(canonical).digest("base64url");
|
|
192229
192412
|
}
|
|
192230
192413
|
function buildSignaturePayload(input) {
|
|
192231
192414
|
return [
|
|
@@ -193827,6 +194010,20 @@ var SYSTEM_ENV_KEYS = [
|
|
|
193827
194010
|
// local/test-only release storage override
|
|
193828
194011
|
"GENCOW_RELEASE_OBJECTS_DIR",
|
|
193829
194012
|
// local/test-only release storage path
|
|
194013
|
+
"GENCOW_SERVING_ROUTE_PUBLICATION_MODE",
|
|
194014
|
+
// Platform serving route rollout policy
|
|
194015
|
+
"GENCOW_SERVING_ROUTE_PUBLICATION_ENVIRONMENT",
|
|
194016
|
+
// Platform serving route environment fence
|
|
194017
|
+
"GENCOW_SERVING_ROUTE_PUBLICATION_APP_ALLOWLIST",
|
|
194018
|
+
// Platform serving route app policy
|
|
194019
|
+
"GENCOW_SERVING_ROUTE_TOPOLOGY_REVISION",
|
|
194020
|
+
// Platform serving route topology fence
|
|
194021
|
+
"GENCOW_SERVING_ROUTE_UPSERT_TARGET_SET_ID",
|
|
194022
|
+
// Platform serving route target set
|
|
194023
|
+
"GENCOW_SERVING_ROUTE_TOMBSTONE_TARGET_SET_ID",
|
|
194024
|
+
// Platform serving route tombstone target set
|
|
194025
|
+
"GENCOW_SERVING_ROUTE_ARTIFACT_QUOTA_BYTES",
|
|
194026
|
+
// serving artifact quota
|
|
193830
194027
|
"GENCOW_BACKUP_RETENTION_V2_MODE",
|
|
193831
194028
|
// platform backup retention rollout mode
|
|
193832
194029
|
"GENCOW_BACKUP_RETENTION_V2_EFFECTIVE_AT",
|