gencow 0.1.185 → 0.1.187

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.
@@ -4,6 +4,7 @@ import { resolve } from "path";
4
4
  import { readProjectDisplayName } from "./cli-project-runtime.mjs";
5
5
  import { BOLD, CYAN, DIM, RESET, error, info, log, success } from "./output.mjs";
6
6
  import { platformFetch } from "./platform-client.mjs";
7
+ import { readJsonObjectResponse } from "./http-response-json.mjs";
7
8
  import { detectStaticDeployBackend, preflightStaticDeployArtifact } from "./static-deploy-command.mjs";
8
9
 
9
10
  export function parseStaticArgs(staticArgs) {
@@ -92,12 +93,16 @@ async function ensureStaticProductionTarget({
92
93
  });
93
94
 
94
95
  if (!createProdRes.ok) {
95
- const errData = await createProdRes.json().catch(() => ({}));
96
- errorImpl(`Prod app creation failed: ${errData.error || createProdRes.statusText}`);
96
+ const errData = await readJsonObjectResponse(createProdRes);
97
+ errorImpl(`Prod app creation failed: ${errData?.error || createProdRes.statusText}`);
97
98
  return null;
98
99
  }
99
100
 
100
- const createProdData = await createProdRes.json();
101
+ const createProdData = await readJsonObjectResponse(createProdRes);
102
+ if (!createProdData) {
103
+ errorImpl("Prod app creation failed: server returned an invalid JSON response");
104
+ return null;
105
+ }
101
106
  const nextProdAppId = createProdData.prodApp;
102
107
  const gencowJson = existsSync(gencowJsonPath) ? JSON.parse(readFileSyncImpl(gencowJsonPath, "utf8")) : {};
103
108
  gencowJson.prodApp = nextProdAppId;
@@ -11,6 +11,7 @@ import {
11
11
  import { relative, resolve } from "path";
12
12
  import { BOLD, CYAN, DIM, RESET, YELLOW, error, info, log, success, warn } from "./output.mjs";
13
13
  import { resolveCreatedAppResponse } from "./app-create-response.mjs";
14
+ import { readJsonObjectResponse } from "./http-response-json.mjs";
14
15
  import { platformFetch, rpcMutation } from "./platform-client.mjs";
15
16
  import { createTarGzipArchive } from "./tar-archive.mjs";
16
17
  import { buildDeployClaimFromArchive } from "./deploy-package-claim.mjs";
@@ -259,7 +260,7 @@ export function createStaticDeployRuntime({
259
260
  logImpl("");
260
261
  warnImpl("Static hosting has no API server — these will return 404.");
261
262
  infoImpl(
262
- `💡 If you need a backend: ${CYAN}VITE_API_URL=https://{backend}.{domain} npm run build${RESET} then deploy`,
263
+ `💡 If you need a backend: ${CYAN}VITE_API_URL=https://{backend}.{domain} bun run build${RESET} then deploy`,
263
264
  );
264
265
  infoImpl(`💡 If using a separate backend: set ${CYAN}VITE_API_URL${RESET} env var before building.`);
265
266
  logImpl("");
@@ -309,12 +310,12 @@ export function createStaticDeployRuntime({
309
310
  infoImpl("Creating app (auto-generating ID)...");
310
311
  const createRes = await rpcMutationImpl(creds, "apps.create", { name: displayName });
311
312
  if (!createRes.ok) {
312
- const createErr = await createRes.json().catch(() => ({}));
313
- errorImpl(`App creation failed: ${createErr.error || createRes.statusText}`);
313
+ const createErr = await readJsonObjectResponse(createRes);
314
+ errorImpl(`App creation failed: ${createErr?.error || createRes.statusText}`);
314
315
  exitImpl(1);
315
316
  return;
316
317
  }
317
- const createData = await createRes.json();
318
+ const createData = await readJsonObjectResponse(createRes);
318
319
  try {
319
320
  appId = resolveCreatedAppResponse(createData, { platformUrl: creds.platformUrl }).appId;
320
321
  } catch (caught) {
@@ -368,13 +369,18 @@ export function createStaticDeployRuntime({
368
369
  }
369
370
 
370
371
  if (!deployRes.ok) {
371
- const errData = await deployRes.json().catch(() => ({}));
372
- errorImpl(`Static deploy failed: ${errData.error || deployRes.statusText}`);
372
+ const errData = await readJsonObjectResponse(deployRes);
373
+ errorImpl(`Static deploy failed: ${errData?.error || deployRes.statusText}`);
373
374
  exitImpl(1);
374
375
  return;
375
376
  }
376
377
 
377
- const data = await deployRes.json();
378
+ const data = await readJsonObjectResponse(deployRes);
379
+ if (!data) {
380
+ errorImpl("Static deploy failed: server returned an invalid JSON response");
381
+ exitImpl(1);
382
+ return;
383
+ }
378
384
  logImpl("");
379
385
  successImpl("Static deploy complete!");
380
386
  infoImpl(`App ID: ${appId}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gencow",
3
- "version": "0.1.185",
3
+ "version": "0.1.187",
4
4
  "description": "Gencow — AI Backend Engine",
5
5
  "type": "module",
6
6
  "bin": {
@@ -74629,8 +74629,10 @@ var init_server_deployment_control_plane_bootstrap = __esm({
74629
74629
  deployment_id INTEGER NOT NULL REFERENCES deployments(id),
74630
74630
  bundle_manifest_sha256 TEXT,
74631
74631
  compatibility_class TEXT NOT NULL DEFAULT 'none'
74632
- CHECK (compatibility_class IN ('none', 'expand_compatible', 'manual_breaking')),
74632
+ CONSTRAINT app_schema_revisions_compatibility_check
74633
+ CHECK (compatibility_class IN ('none', 'expand_compatible', 'versioned_v1', 'manual_breaking')),
74633
74634
  state TEXT NOT NULL DEFAULT 'planned'
74635
+ CONSTRAINT app_schema_revisions_state_check
74634
74636
  CHECK (state IN (
74635
74637
  'not_required', 'planned', 'preflight_passed', 'applying',
74636
74638
  'applied', 'failed', 'outcome_uncertain', 'recovery_required'
@@ -74645,6 +74647,56 @@ var init_server_deployment_control_plane_bootstrap = __esm({
74645
74647
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
74646
74648
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
74647
74649
  )`,
74650
+ `DO $deployment_schema_revision_compatibility$
74651
+ DECLARE
74652
+ compatibility_constraint_count INTEGER;
74653
+ canonical_constraint_count INTEGER;
74654
+ BEGIN
74655
+ SELECT
74656
+ COUNT(*),
74657
+ COUNT(*) FILTER (
74658
+ WHERE conname = 'app_schema_revisions_compatibility_check'
74659
+ AND convalidated
74660
+ AND POSITION('versioned_v1' IN pg_get_constraintdef(oid)) > 0
74661
+ )
74662
+ INTO compatibility_constraint_count, canonical_constraint_count
74663
+ FROM pg_constraint
74664
+ WHERE conrelid = 'app_schema_revisions'::regclass
74665
+ AND conname IN (
74666
+ 'app_schema_revisions_compatibility_check',
74667
+ 'app_schema_revisions_compatibility_class_check'
74668
+ );
74669
+
74670
+ IF compatibility_constraint_count <> 1 OR canonical_constraint_count <> 1 THEN
74671
+ ALTER TABLE app_schema_revisions
74672
+ DROP CONSTRAINT IF EXISTS app_schema_revisions_compatibility_check;
74673
+ ALTER TABLE app_schema_revisions
74674
+ DROP CONSTRAINT IF EXISTS app_schema_revisions_compatibility_class_check;
74675
+ ALTER TABLE app_schema_revisions
74676
+ ADD CONSTRAINT app_schema_revisions_compatibility_check
74677
+ CHECK (compatibility_class IN ('none', 'expand_compatible', 'versioned_v1', 'manual_breaking'));
74678
+ END IF;
74679
+
74680
+ SELECT
74681
+ COUNT(*),
74682
+ COUNT(*) FILTER (
74683
+ WHERE conname = 'app_schema_revisions_compatibility_check'
74684
+ AND convalidated
74685
+ AND POSITION('versioned_v1' IN pg_get_constraintdef(oid)) > 0
74686
+ )
74687
+ INTO compatibility_constraint_count, canonical_constraint_count
74688
+ FROM pg_constraint
74689
+ WHERE conrelid = 'app_schema_revisions'::regclass
74690
+ AND conname IN (
74691
+ 'app_schema_revisions_compatibility_check',
74692
+ 'app_schema_revisions_compatibility_class_check'
74693
+ );
74694
+
74695
+ IF compatibility_constraint_count <> 1 OR canonical_constraint_count <> 1 THEN
74696
+ RAISE EXCEPTION 'app_schema_revisions compatibility constraint did not converge';
74697
+ END IF;
74698
+ END
74699
+ $deployment_schema_revision_compatibility$`,
74648
74700
  `CREATE UNIQUE INDEX IF NOT EXISTS app_schema_revisions_deployment_unique
74649
74701
  ON app_schema_revisions (deployment_id)`,
74650
74702
  `CREATE INDEX IF NOT EXISTS app_schema_revisions_app_state_idx
@@ -74867,42 +74919,19 @@ var init_server_deployment_control_plane_bootstrap = __esm({
74867
74919
  });
74868
74920
 
74869
74921
  // ../server/dist/server-static-backend-pointer-bootstrap.js
74870
- async function ensureStaticBackendDeploymentAuthoritySchema(params) {
74871
- await params.rawSql(`ALTER TABLE apps ADD COLUMN IF NOT EXISTS current_static_deployment_id INTEGER`);
74872
- await params.rawSql(DEPLOYMENT_AUTHORITY_REMEDIATION_SCHEMA_SQL);
74873
- await params.rawSql(DEPLOYMENT_AUTHORITY_REMEDIATION_SECURITY_SQL);
74922
+ async function reconcileStaticBackendDeploymentAuthorityRuntime(params) {
74874
74923
  await params.rawSql(STATIC_DEPLOYMENT_POINTER_BACKFILL_SQL);
74875
- await params.rawSql(UNSAFE_BACKEND_POINTER_REMEDIATION_SQL);
74876
- await params.rawSql(BACKEND_AUTHORITY_REMEDIATION_STATUS_SQL);
74877
74924
  await params.rawSql(BACKEND_AUTHORITY_REMEDIATION_RESOLUTION_SQL);
74878
74925
  await params.rawSql(BACKEND_DEPLOYMENT_POINTER_REPAIR_SQL);
74879
74926
  await params.rawSql(STATIC_ONLY_BACKEND_AUTHORITY_REMEDIATION_RESOLUTION_SQL);
74880
74927
  await params.rawSql(STATIC_ONLY_BACKEND_AUTHORITY_STATUS_CLEAR_SQL);
74881
74928
  await params.rawSql(STATIC_ONLY_BACKEND_POINTER_CLEAR_SQL);
74929
+ await params.rawSql(BACKEND_AUTHORITY_REMEDIATION_STATUS_SQL);
74882
74930
  }
74883
- var DEPLOYMENT_AUTHORITY_REMEDIATION_SCHEMA_SQL, DEPLOYMENT_AUTHORITY_REMEDIATION_SECURITY_SQL, STATIC_DEPLOYMENT_POINTER_BACKFILL_SQL, EXACT_BACKEND_AUTHORITY_CTE, UNSAFE_BACKEND_POINTER_REMEDIATION_SQL, BACKEND_AUTHORITY_REMEDIATION_STATUS_SQL, BACKEND_DEPLOYMENT_POINTER_REPAIR_SQL, BACKEND_AUTHORITY_REMEDIATION_RESOLUTION_SQL, STATIC_ONLY_BACKEND_AUTHORITY_REMEDIATION_RESOLUTION_SQL, STATIC_ONLY_BACKEND_AUTHORITY_STATUS_CLEAR_SQL, STATIC_ONLY_BACKEND_POINTER_CLEAR_SQL;
74931
+ var STATIC_DEPLOYMENT_POINTER_BACKFILL_SQL, EXACT_BACKEND_AUTHORITY_CTE, UNSAFE_BACKEND_POINTER_REMEDIATION_SQL, BACKEND_AUTHORITY_REMEDIATION_STATUS_SQL, BACKEND_DEPLOYMENT_POINTER_REPAIR_SQL, BACKEND_AUTHORITY_REMEDIATION_RESOLUTION_SQL, STATIC_ONLY_BACKEND_AUTHORITY_REMEDIATION_RESOLUTION_SQL, STATIC_ONLY_BACKEND_AUTHORITY_STATUS_CLEAR_SQL, STATIC_ONLY_BACKEND_POINTER_CLEAR_SQL;
74884
74932
  var init_server_static_backend_pointer_bootstrap = __esm({
74885
74933
  "../server/dist/server-static-backend-pointer-bootstrap.js"() {
74886
74934
  "use strict";
74887
- DEPLOYMENT_AUTHORITY_REMEDIATION_SCHEMA_SQL = `
74888
- CREATE TABLE IF NOT EXISTS app_deployment_authority_remediations (
74889
- app_id INTEGER PRIMARY KEY REFERENCES apps(id) ON DELETE CASCADE,
74890
- state TEXT NOT NULL DEFAULT 'pending'
74891
- CONSTRAINT app_deployment_authority_remediations_state_check
74892
- CHECK (state IN ('pending', 'resolved')),
74893
- reason_code TEXT NOT NULL
74894
- CONSTRAINT app_deployment_authority_remediations_reason_check
74895
- CHECK (reason_code IN ('backend_pointer_unverified')),
74896
- observed_current_deployment_id INTEGER,
74897
- resolution_deployment_id INTEGER,
74898
- detected_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
74899
- updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
74900
- resolved_at TIMESTAMPTZ
74901
- )
74902
- `;
74903
- DEPLOYMENT_AUTHORITY_REMEDIATION_SECURITY_SQL = `
74904
- REVOKE ALL ON TABLE app_deployment_authority_remediations FROM PUBLIC
74905
- `;
74906
74935
  STATIC_DEPLOYMENT_POINTER_BACKFILL_SQL = `
74907
74936
  UPDATE apps AS app
74908
74937
  SET current_static_deployment_id = (
@@ -74920,10 +74949,6 @@ WHERE app.current_static_deployment_id IS NULL
74920
74949
  exact_backend_authority AS (
74921
74950
  SELECT app.id AS app_id, activation.deployment_id
74922
74951
  FROM apps AS app
74923
- JOIN deployments AS current_deployment
74924
- ON current_deployment.id = app.current_deploy_id
74925
- AND current_deployment.app_id = app.id
74926
- AND current_deployment.env = 'static'
74927
74952
  JOIN app_runtime_desired_state AS desired
74928
74953
  ON desired.app_id = app.id
74929
74954
  AND desired.authority_mode = 'enforce'
@@ -75023,6 +75048,10 @@ SET current_deploy_id = exact.deployment_id,
75023
75048
  END
75024
75049
  FROM exact_backend_authority AS exact
75025
75050
  WHERE exact.app_id = app.id
75051
+ AND (
75052
+ app.current_deploy_id IS DISTINCT FROM exact.deployment_id
75053
+ OR app.status_reason = 'backend_deployment_authority_remediation_required'
75054
+ )
75026
75055
  `;
75027
75056
  BACKEND_AUTHORITY_REMEDIATION_RESOLUTION_SQL = `
75028
75057
  WITH ${EXACT_BACKEND_AUTHORITY_CTE}
@@ -75813,7 +75842,6 @@ async function ensurePlatformSchemaUpgrade(params) {
75813
75842
  await params.rawSql(`ALTER TABLE deployments ADD COLUMN IF NOT EXISTS env TEXT DEFAULT 'dev'`);
75814
75843
  await ensureDeploymentRuntimeMetadataSchema(params.rawSql);
75815
75844
  await ensureDeploymentControlPlaneSchema({ rawSql: params.rawSql });
75816
- await ensureStaticBackendDeploymentAuthoritySchema({ rawSql: params.rawSql });
75817
75845
  await params.rawSql(`CREATE TABLE IF NOT EXISTS db_backups (
75818
75846
  id SERIAL PRIMARY KEY,
75819
75847
  app_id INTEGER NOT NULL,
@@ -76187,6 +76215,7 @@ async function ensurePlatformSchemaUpgrade(params) {
76187
76215
  if (params.strict)
76188
76216
  throw error51;
76189
76217
  }
76218
+ await reconcileStaticBackendDeploymentAuthorityRuntime({ rawSql: params.rawSql });
76190
76219
  await ensurePlatformRlsPolicies({
76191
76220
  rawSql: params.rawSql,
76192
76221
  isPlatform: params.isPlatform,