@supacloud/admin 0.28.0 → 0.28.3

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.
Files changed (2) hide show
  1. package/dist/index.js +323 -88
  2. package/package.json +9 -9
package/dist/index.js CHANGED
@@ -24588,23 +24588,22 @@ function InstanceKeys(value) {
24588
24588
  function IsIEEE754(value) {
24589
24589
  return typeof value === "number";
24590
24590
  }
24591
- var ByteMarker;
24592
- (function(ByteMarker) {
24593
- ByteMarker[ByteMarker["Array"] = 0] = "Array";
24594
- ByteMarker[ByteMarker["BigInt"] = 1] = "BigInt";
24595
- ByteMarker[ByteMarker["Boolean"] = 2] = "Boolean";
24596
- ByteMarker[ByteMarker["Date"] = 3] = "Date";
24597
- ByteMarker[ByteMarker["Constructor"] = 4] = "Constructor";
24598
- ByteMarker[ByteMarker["Function"] = 5] = "Function";
24599
- ByteMarker[ByteMarker["Null"] = 6] = "Null";
24600
- ByteMarker[ByteMarker["Number"] = 7] = "Number";
24601
- ByteMarker[ByteMarker["Object"] = 8] = "Object";
24602
- ByteMarker[ByteMarker["RegExp"] = 9] = "RegExp";
24603
- ByteMarker[ByteMarker["String"] = 10] = "String";
24604
- ByteMarker[ByteMarker["Symbol"] = 11] = "Symbol";
24605
- ByteMarker[ByteMarker["TypeArray"] = 12] = "TypeArray";
24606
- ByteMarker[ByteMarker["Undefined"] = 13] = "Undefined";
24607
- })(ByteMarker || (ByteMarker = {}));
24591
+ var ByteMarker = {
24592
+ Array: 0,
24593
+ BigInt: 1,
24594
+ Boolean: 2,
24595
+ Date: 3,
24596
+ Constructor: 4,
24597
+ Function: 5,
24598
+ Null: 6,
24599
+ Number: 7,
24600
+ Object: 8,
24601
+ RegExp: 9,
24602
+ String: 10,
24603
+ Symbol: 11,
24604
+ TypeArray: 12,
24605
+ Undefined: 13
24606
+ };
24608
24607
  var Accumulator = BigInt("14695981039346656037");
24609
24608
  var [Prime, Size] = [BigInt("1099511628211"), BigInt("18446744073709551616")];
24610
24609
  var Bytes = Array.from({ length: 256 }).map((_, i) => BigInt(i));
@@ -30151,7 +30150,7 @@ function schemaProperties(schema) {
30151
30150
  }
30152
30151
  return schema;
30153
30152
  }
30154
- var DEPLOYMENT_UPGRADE = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment is no longer supported. Upgrade with `npm install -g @supacloud/cli@latest`, bind application.id and application.environmentId in supacloud.json (or SUPACLOUD_APPLICATION_ID and SUPACLOUD_ENV), then run `supacloud deploy`. SupaCloud owns deployment planning and activation; do not retry with legacy commands.";
30153
+ var DEPLOYMENT_UPGRADE = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment commands are no longer supported. Upgrade with `npm install -g @supacloud/cli@latest`, configure frontend in supacloud.json for static assets, or application.id and application.environmentId for executable application delivery, then run `supacloud deploy`. With a frontend configured, deploy publishes only Web assets; use `supacloud deploy --backend` for the application backend. `supacloud deploy --assets_only` remains an explicit Web-only option. SupaCloud owns activation; do not retry with legacy commands.";
30155
30154
  var removedFrontendActions = new Set([
30156
30155
  "deploy_git",
30157
30156
  "deploy_upload",
@@ -37771,23 +37770,22 @@ function InstanceKeys2(value) {
37771
37770
  function IsIEEE7542(value) {
37772
37771
  return typeof value === "number";
37773
37772
  }
37774
- var ByteMarker2;
37775
- (function(ByteMarker) {
37776
- ByteMarker[ByteMarker["Array"] = 0] = "Array";
37777
- ByteMarker[ByteMarker["BigInt"] = 1] = "BigInt";
37778
- ByteMarker[ByteMarker["Boolean"] = 2] = "Boolean";
37779
- ByteMarker[ByteMarker["Date"] = 3] = "Date";
37780
- ByteMarker[ByteMarker["Constructor"] = 4] = "Constructor";
37781
- ByteMarker[ByteMarker["Function"] = 5] = "Function";
37782
- ByteMarker[ByteMarker["Null"] = 6] = "Null";
37783
- ByteMarker[ByteMarker["Number"] = 7] = "Number";
37784
- ByteMarker[ByteMarker["Object"] = 8] = "Object";
37785
- ByteMarker[ByteMarker["RegExp"] = 9] = "RegExp";
37786
- ByteMarker[ByteMarker["String"] = 10] = "String";
37787
- ByteMarker[ByteMarker["Symbol"] = 11] = "Symbol";
37788
- ByteMarker[ByteMarker["TypeArray"] = 12] = "TypeArray";
37789
- ByteMarker[ByteMarker["Undefined"] = 13] = "Undefined";
37790
- })(ByteMarker2 || (ByteMarker2 = {}));
37773
+ var ByteMarker2 = {
37774
+ Array: 0,
37775
+ BigInt: 1,
37776
+ Boolean: 2,
37777
+ Date: 3,
37778
+ Constructor: 4,
37779
+ Function: 5,
37780
+ Null: 6,
37781
+ Number: 7,
37782
+ Object: 8,
37783
+ RegExp: 9,
37784
+ String: 10,
37785
+ Symbol: 11,
37786
+ TypeArray: 12,
37787
+ Undefined: 13
37788
+ };
37791
37789
  var Accumulator2 = BigInt("14695981039346656037");
37792
37790
  var [Prime2, Size2] = [BigInt("1099511628211"), BigInt("18446744073709551616")];
37793
37791
  var Bytes2 = Array.from({ length: 256 }).map((_, i) => BigInt(i));
@@ -43306,7 +43304,7 @@ function decodedSchema2(inputSchema, outputSchema, decode, options) {
43306
43304
  }
43307
43305
 
43308
43306
  // ../cli/src/shared/deployment-upgrade.ts
43309
- var DEPLOYMENT_UPGRADE2 = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment is no longer supported. Upgrade with `npm install -g @supacloud/cli@latest`, bind application.id and application.environmentId in supacloud.json (or SUPACLOUD_APPLICATION_ID and SUPACLOUD_ENV), then run `supacloud deploy`. SupaCloud owns deployment planning and activation; do not retry with legacy commands.";
43307
+ var DEPLOYMENT_UPGRADE2 = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment commands are no longer supported. Upgrade with `npm install -g @supacloud/cli@latest`, configure frontend in supacloud.json for static assets, or application.id and application.environmentId for executable application delivery, then run `supacloud deploy`. With a frontend configured, deploy publishes only Web assets; use `supacloud deploy --backend` for the application backend. `supacloud deploy --assets_only` remains an explicit Web-only option. SupaCloud owns activation; do not retry with legacy commands.";
43310
43308
  var removedFrontendActions2 = new Set([
43311
43309
  "deploy_git",
43312
43310
  "deploy_upload",
@@ -43702,12 +43700,188 @@ var FRONTEND_ARCHIVE_MAX_FILES2 = 1e4;
43702
43700
  var FRONTEND_ARCHIVE_MAX_SOURCE_BYTES2 = 300 * 1024 * 1024;
43703
43701
  var FRONTEND_ARCHIVE_MAX_TAR_BYTES2 = FRONTEND_ARCHIVE_MAX_SOURCE_BYTES2 + FRONTEND_ARCHIVE_MAX_FILES2 * 2048 + 1024;
43704
43702
 
43703
+ // ../cli/src/shared/mutation-protocol.ts
43704
+ var MUTATION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
43705
+ var FINGERPRINT_PATTERN = /^[0-9a-f]{64}$/;
43706
+ var OPERATION_PATTERN = /^[a-z0-9][a-z0-9._:-]{0,127}$/;
43707
+ var RESOURCE_KEY_PATTERN = /^v1\/(?:[a-z0-9][a-z0-9._-]{0,63})\/([A-Za-z0-9_-]{2,171})$/;
43708
+ var RESOURCE_ID_CONTROL_PATTERN = /[\u0000-\u001f\u007f-\u009f]/u;
43709
+ var FAILURE_CODE_PATTERN = /^[A-Z][A-Z0-9_]{0,63}$/;
43710
+ var LEASE_OWNER_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:@/-]{0,254}$/;
43711
+ var TIMESTAMP_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
43712
+ var MAX_RESOURCE_ID_BYTES = 128;
43713
+ var FATAL_UTF8_DECODER = new TextDecoder("utf-8", { fatal: true });
43714
+ var MUTATION_STATUSES = new Set([
43715
+ "pending",
43716
+ "running",
43717
+ "succeeded",
43718
+ "failed_retryable",
43719
+ "failed_terminal",
43720
+ "outcome_unknown"
43721
+ ]);
43722
+ var MUTATION_KEYS = [
43723
+ "project_ref",
43724
+ "mutation_id",
43725
+ "operation",
43726
+ "resource_key",
43727
+ "request_fingerprint",
43728
+ "principal",
43729
+ "status",
43730
+ "checkpoint",
43731
+ "receipt",
43732
+ "response_status",
43733
+ "failure_code",
43734
+ "lease",
43735
+ "completed_at",
43736
+ "created_at",
43737
+ "updated_at"
43738
+ ];
43739
+ var PRINCIPAL_KEYS = ["type", "id"];
43740
+ var LEASE_KEYS = ["owner", "expires_at", "fencing_epoch"];
43741
+ function isMutationId(candidate) {
43742
+ return typeof candidate === "string" && MUTATION_ID_PATTERN.test(candidate);
43743
+ }
43744
+ function objectRecord(candidate) {
43745
+ return candidate && typeof candidate === "object" && !Array.isArray(candidate) ? candidate : null;
43746
+ }
43747
+ function exactRecord(candidate, keys) {
43748
+ const record = objectRecord(candidate);
43749
+ if (!record || Object.keys(record).length !== keys.length)
43750
+ return null;
43751
+ return keys.every((key) => Object.hasOwn(record, key)) ? record : null;
43752
+ }
43753
+ function emptyProjection(candidate) {
43754
+ const record = objectRecord(candidate);
43755
+ return record && Object.keys(record).length === 0 ? record : null;
43756
+ }
43757
+ function canonicalTimestamp4(candidate) {
43758
+ if (typeof candidate !== "string" || !TIMESTAMP_PATTERN.test(candidate))
43759
+ return false;
43760
+ const milliseconds = Date.parse(candidate);
43761
+ return Number.isFinite(milliseconds) && new Date(milliseconds).toISOString() === candidate;
43762
+ }
43763
+ function nullableTimestamp(candidate) {
43764
+ return candidate === null || canonicalTimestamp4(candidate);
43765
+ }
43766
+ function safePrincipal(candidate) {
43767
+ const principal = exactRecord(candidate, PRINCIPAL_KEYS);
43768
+ if (!principal || !["master", "admin", "project"].includes(String(principal["type"])))
43769
+ return null;
43770
+ if (typeof principal["id"] !== "string" || !principal["id"] || principal["id"].length > 320 || principal["id"].trim() !== principal["id"] || /[\u0000-\u001f\u007f]/u.test(principal["id"]))
43771
+ return null;
43772
+ return { type: principal["type"], id: principal["id"] };
43773
+ }
43774
+ function safeLease(candidate) {
43775
+ const lease = exactRecord(candidate, LEASE_KEYS);
43776
+ if (!lease || lease["owner"] !== null && (typeof lease["owner"] !== "string" || !LEASE_OWNER_PATTERN.test(lease["owner"])))
43777
+ return null;
43778
+ if (!nullableTimestamp(lease["expires_at"]) || !Number.isSafeInteger(lease["fencing_epoch"]) || Number(lease["fencing_epoch"]) < 0)
43779
+ return null;
43780
+ return {
43781
+ owner: lease["owner"],
43782
+ expires_at: lease["expires_at"],
43783
+ fencing_epoch: Number(lease["fencing_epoch"])
43784
+ };
43785
+ }
43786
+ function safeResponseStatus(candidate) {
43787
+ if (candidate === null)
43788
+ return null;
43789
+ return Number.isInteger(candidate) && Number(candidate) >= 100 && Number(candidate) <= 599 ? Number(candidate) : undefined;
43790
+ }
43791
+ function validLeaseState(status, lease) {
43792
+ const running = status === "running";
43793
+ return running ? lease.owner !== null && lease.expires_at !== null && lease.fencing_epoch > 0 : lease.owner === null && lease.expires_at === null;
43794
+ }
43795
+ function validMutationLifecycle(mutation, receipt, responseStatus) {
43796
+ const terminal = ["succeeded", "failed_terminal", "outcome_unknown"].includes(String(mutation["status"]));
43797
+ if (mutation["completed_at"] !== null !== terminal)
43798
+ return false;
43799
+ if (mutation["status"] === "succeeded") {
43800
+ return receipt !== null && responseStatus !== null && responseStatus >= 200 && responseStatus < 300 && mutation["failure_code"] === null;
43801
+ }
43802
+ if (mutation["status"] === "failed_terminal") {
43803
+ return receipt !== null && typeof mutation["failure_code"] === "string";
43804
+ }
43805
+ if (mutation["status"] === "failed_retryable" || mutation["status"] === "outcome_unknown") {
43806
+ return receipt !== null && typeof mutation["failure_code"] === "string";
43807
+ }
43808
+ if (mutation["status"] === "pending") {
43809
+ return receipt === null && responseStatus === null && mutation["failure_code"] === null;
43810
+ }
43811
+ return true;
43812
+ }
43813
+ function canonicalMutationResourceKey(candidate) {
43814
+ if (typeof candidate !== "string")
43815
+ return false;
43816
+ const match = RESOURCE_KEY_PATTERN.exec(candidate);
43817
+ if (!match)
43818
+ return false;
43819
+ const encodedResourceId = match[1];
43820
+ const resourceIdBytes = Buffer.from(encodedResourceId, "base64url");
43821
+ if (resourceIdBytes.byteLength < 1 || resourceIdBytes.byteLength > MAX_RESOURCE_ID_BYTES || resourceIdBytes.toString("base64url") !== encodedResourceId)
43822
+ return false;
43823
+ let resourceId;
43824
+ try {
43825
+ resourceId = FATAL_UTF8_DECODER.decode(resourceIdBytes);
43826
+ } catch (decodeError) {
43827
+ if (decodeError instanceof TypeError)
43828
+ return false;
43829
+ throw decodeError;
43830
+ }
43831
+ return resourceId.trim() === resourceId && !RESOURCE_ID_CONTROL_PATTERN.test(resourceId) && Buffer.from(resourceId, "utf8").equals(resourceIdBytes);
43832
+ }
43833
+ function validMutationIdentity(mutation) {
43834
+ if (!isMutationId(mutation["mutation_id"]) || typeof mutation["project_ref"] !== "string")
43835
+ return false;
43836
+ if (typeof mutation["operation"] !== "string" || !OPERATION_PATTERN.test(mutation["operation"]))
43837
+ return false;
43838
+ if (mutation["resource_key"] !== null && !canonicalMutationResourceKey(mutation["resource_key"]))
43839
+ return false;
43840
+ return typeof mutation["request_fingerprint"] === "string" && FINGERPRINT_PATTERN.test(mutation["request_fingerprint"]);
43841
+ }
43842
+ function validMutationTerminalFields(mutation) {
43843
+ if (typeof mutation["status"] !== "string" || !MUTATION_STATUSES.has(mutation["status"]))
43844
+ return false;
43845
+ if (mutation["failure_code"] !== null && (typeof mutation["failure_code"] !== "string" || !FAILURE_CODE_PATTERN.test(mutation["failure_code"])))
43846
+ return false;
43847
+ return nullableTimestamp(mutation["completed_at"]) && canonicalTimestamp4(mutation["created_at"]) && canonicalTimestamp4(mutation["updated_at"]);
43848
+ }
43849
+ function safeMutationStatus(candidate) {
43850
+ const mutation = exactRecord(candidate, MUTATION_KEYS);
43851
+ if (!mutation || !validMutationIdentity(mutation) || !validMutationTerminalFields(mutation))
43852
+ return null;
43853
+ const principal = safePrincipal(mutation["principal"]);
43854
+ const checkpoint = emptyProjection(mutation["checkpoint"]);
43855
+ const receipt = mutation["receipt"] === null ? null : emptyProjection(mutation["receipt"]);
43856
+ const responseStatus = safeResponseStatus(mutation["response_status"]);
43857
+ const lease = safeLease(mutation["lease"]);
43858
+ if (!principal || !checkpoint || mutation["receipt"] !== null && !receipt || responseStatus === undefined || !lease || !validLeaseState(String(mutation["status"]), lease) || !validMutationLifecycle(mutation, receipt, responseStatus))
43859
+ return null;
43860
+ return {
43861
+ project_ref: mutation["project_ref"],
43862
+ mutation_id: mutation["mutation_id"],
43863
+ operation: mutation["operation"],
43864
+ resource_key: mutation["resource_key"],
43865
+ request_fingerprint: mutation["request_fingerprint"],
43866
+ principal,
43867
+ status: mutation["status"],
43868
+ checkpoint,
43869
+ receipt,
43870
+ response_status: responseStatus,
43871
+ failure_code: mutation["failure_code"],
43872
+ lease,
43873
+ completed_at: mutation["completed_at"],
43874
+ created_at: mutation["created_at"],
43875
+ updated_at: mutation["updated_at"]
43876
+ };
43877
+ }
43878
+
43705
43879
  // ../cli/src/shared/tools/frontend-release-control.ts
43706
43880
  var PROJECT_REF_PATTERN3 = /^[A-Za-z0-9_-]{1,20}$/u;
43707
43881
  var DEPLOYMENT_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/u;
43708
43882
  var RELEASE_ID_PATTERN = /^[0-9a-f]{64}$/u;
43709
- var MUTATION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
43710
- var TIMESTAMP_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u;
43883
+ var MUTATION_ID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
43884
+ var TIMESTAMP_PATTERN2 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u;
43711
43885
  var ARCHIVE_MAX_BYTES = 100 * 1024 * 1024;
43712
43886
  var ARCHIVE_CHUNK_BYTES = 64 * 1024;
43713
43887
  var RESPONSE_MAX_BYTES = 1024 * 1024;
@@ -43748,7 +43922,7 @@ function releaseRecord(candidate) {
43748
43922
  "kind",
43749
43923
  "archive_format"
43750
43924
  ];
43751
- if (!exactKeys(record, keys) || record.schema !== FRONTEND_ARCHIVE_RELEASE_SCHEMA || record.archive_format !== FRONTEND_ARCHIVE_FORMAT || typeof record.project_ref !== "string" || !PROJECT_REF_PATTERN3.test(record.project_ref) || typeof record.deployment_id !== "string" || !DEPLOYMENT_ID_PATTERN.test(record.deployment_id) || typeof record.release_id !== "string" || !RELEASE_ID_PATTERN.test(record.release_id) || record.sha256 !== record.release_id || typeof record.tree_sha256 !== "string" || !RELEASE_ID_PATTERN.test(record.tree_sha256) || !Number.isSafeInteger(record.size_bytes) || Number(record.size_bytes) < 1 || !Number.isSafeInteger(record.file_count) || Number(record.file_count) < 1 || !canonicalTimestamp4(record.created_at) || record.kind !== "prebuilt_static")
43925
+ if (!exactKeys(record, keys) || record.schema !== FRONTEND_ARCHIVE_RELEASE_SCHEMA || record.archive_format !== FRONTEND_ARCHIVE_FORMAT || typeof record.project_ref !== "string" || !PROJECT_REF_PATTERN3.test(record.project_ref) || typeof record.deployment_id !== "string" || !DEPLOYMENT_ID_PATTERN.test(record.deployment_id) || typeof record.release_id !== "string" || !RELEASE_ID_PATTERN.test(record.release_id) || record.sha256 !== record.release_id || typeof record.tree_sha256 !== "string" || !RELEASE_ID_PATTERN.test(record.tree_sha256) || !Number.isSafeInteger(record.size_bytes) || Number(record.size_bytes) < 1 || !Number.isSafeInteger(record.file_count) || Number(record.file_count) < 1 || !canonicalTimestamp5(record.created_at) || record.kind !== "prebuilt_static")
43752
43926
  return null;
43753
43927
  return {
43754
43928
  project_ref: record.project_ref,
@@ -43772,8 +43946,8 @@ function releaseEnvelope(candidate, expected) {
43772
43946
  return null;
43773
43947
  return release;
43774
43948
  }
43775
- function canonicalTimestamp4(candidate) {
43776
- if (typeof candidate !== "string" || !TIMESTAMP_PATTERN.test(candidate))
43949
+ function canonicalTimestamp5(candidate) {
43950
+ if (typeof candidate !== "string" || !TIMESTAMP_PATTERN2.test(candidate))
43777
43951
  return false;
43778
43952
  const milliseconds = Date.parse(candidate);
43779
43953
  return Number.isFinite(milliseconds) && new Date(milliseconds).toISOString() === candidate;
@@ -43798,7 +43972,7 @@ function releaseInventory(candidate, expected) {
43798
43972
  if (!exactKeys(record, keys) || typeof record.project_ref !== "string" || !PROJECT_REF_PATTERN3.test(record.project_ref) || typeof record.deployment_id !== "string" || !DEPLOYMENT_ID_PATTERN.test(record.deployment_id) || !Array.isArray(record.releases))
43799
43973
  return null;
43800
43974
  const activeReleaseId = nullableIdentity(record.active_release_id, RELEASE_ID_PATTERN);
43801
- const activeActivationId = nullableIdentity(record.active_activation_id, MUTATION_ID_PATTERN);
43975
+ const activeActivationId = nullableIdentity(record.active_activation_id, MUTATION_ID_PATTERN2);
43802
43976
  const nextCursor = nullableIdentity(record.next_cursor, RELEASE_ID_PATTERN);
43803
43977
  const releases = record.releases.map(releaseRecord);
43804
43978
  if (activeReleaseId === undefined || activeActivationId === undefined || nextCursor === undefined || activeReleaseId === null !== (activeActivationId === null) || releases.some((release) => release === null))
@@ -43909,13 +44083,16 @@ async function getFrontendRelease(http, projectRef, deploymentId, releaseId) {
43909
44083
  const response = await http.get(releasePath(projectRef, deploymentId, releaseId), {
43910
44084
  maxJsonBytes: RESPONSE_MAX_BYTES
43911
44085
  });
43912
- const release = response.ok ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId }) : null;
44086
+ const release = response.ok && response.status === 200 ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId }) : null;
43913
44087
  if (!release) {
43914
44088
  return releaseReadFailure("frontend.get_release", response);
43915
44089
  }
43916
44090
  return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
43917
44091
  }
43918
44092
  async function uploadFrontendRelease(http, projectRef, deploymentId, archivePath) {
44093
+ return uploadFrontendReleaseWithReadback(http, projectRef, deploymentId, archivePath, true);
44094
+ }
44095
+ async function uploadFrontendReleaseWithReadback(http, projectRef, deploymentId, archivePath, verifyReadback) {
43919
44096
  const endpoint = releaseEndpoint(projectRef, deploymentId);
43920
44097
  const archive = await verifiedArchive(archivePath);
43921
44098
  let response;
@@ -43934,13 +44111,15 @@ async function uploadFrontendRelease(http, projectRef, deploymentId, archivePath
43934
44111
  } finally {
43935
44112
  await archive.handle.close();
43936
44113
  }
43937
- const release = response.ok ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId: archive.sha256 }) : null;
44114
+ const release = response.ok && (response.status === 200 || response.status === 201) ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId: archive.sha256 }) : null;
43938
44115
  if (!release) {
43939
44116
  if (response.status >= 400 && response.status < 500 && response.status !== 408 && !response.transportError) {
43940
44117
  return releaseFailure("frontend.upload_release", "HTTP_ERROR", response.status);
43941
44118
  }
43942
44119
  return uploadReadback(http, projectRef, deploymentId, archive.sha256, response.status);
43943
44120
  }
44121
+ if (!verifyReadback)
44122
+ return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
43944
44123
  const readback = await http.get(`${endpoint}/${release.release_id}`, { maxJsonBytes: RESPONSE_MAX_BYTES });
43945
44124
  const verified = readback.ok ? releaseEnvelope(readback.data, { projectRef, deploymentId, releaseId: release.release_id }) : null;
43946
44125
  if (!verified || verified.tree_sha256 !== release.tree_sha256) {
@@ -43952,7 +44131,7 @@ async function uploadReadback(http, projectRef, deploymentId, releaseId, uploadS
43952
44131
  const response = await http.get(releasePath(projectRef, deploymentId, releaseId), {
43953
44132
  maxJsonBytes: RESPONSE_MAX_BYTES
43954
44133
  });
43955
- const release = response.ok ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId }) : null;
44134
+ const release = response.ok && response.status === 200 ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId }) : null;
43956
44135
  if (!release) {
43957
44136
  return releaseFailure("frontend.upload_release", "OUTCOME_UNKNOWN", uploadStatus);
43958
44137
  }
@@ -43983,25 +44162,8 @@ function publicMutationReceipt(candidate, expected) {
43983
44162
  if (!candidate || typeof candidate !== "object" || Array.isArray(candidate))
43984
44163
  return null;
43985
44164
  const envelope = candidate;
43986
- const mutation = envelope.mutation;
43987
- const expectedKeys = [
43988
- "project_ref",
43989
- "mutation_id",
43990
- "operation",
43991
- "resource_key",
43992
- "request_fingerprint",
43993
- "principal",
43994
- "status",
43995
- "checkpoint",
43996
- "receipt",
43997
- "response_status",
43998
- "failure_code",
43999
- "lease",
44000
- "completed_at",
44001
- "created_at",
44002
- "updated_at"
44003
- ];
44004
- if (!mutation || !exactKeys(envelope, ["project_ref", "mutation"]) || !exactKeys(mutation, expectedKeys) || envelope.project_ref !== expected.projectRef || mutation.project_ref !== expected.projectRef || mutation.mutation_id !== expected.mutationId || mutation.resource_key !== expected.resourceKey || mutation.request_fingerprint !== expected.requestFingerprint || typeof mutation.operation !== "string" || typeof mutation.status !== "string" || !(mutation.response_status === null || Number.isSafeInteger(mutation.response_status)) || !(mutation.failure_code === null || typeof mutation.failure_code === "string"))
44165
+ const mutation = safeMutationStatus(envelope.mutation);
44166
+ if (!mutation || !exactKeys(envelope, ["project_ref", "mutation"]) || envelope.project_ref !== expected.projectRef || mutation.project_ref !== expected.projectRef || mutation.mutation_id !== expected.mutationId || mutation.resource_key !== expected.resourceKey || mutation.request_fingerprint !== expected.requestFingerprint)
44005
44167
  return null;
44006
44168
  return {
44007
44169
  operation: mutation.operation,
@@ -44028,6 +44190,18 @@ function activationReceipt(candidate, input) {
44028
44190
  return release;
44029
44191
  }
44030
44192
  async function activeReleaseReadback(http, identity) {
44193
+ const snapshot = await activeReleaseSnapshotReadback(http, identity);
44194
+ if (!snapshot.release)
44195
+ return snapshot;
44196
+ const releaseRead = await http.get(releasePath(identity.projectRef, identity.deploymentId, identity.releaseId), { maxJsonBytes: RESPONSE_MAX_BYTES });
44197
+ const release = releaseRead.ok && releaseRead.status === 200 ? releaseEnvelope(releaseRead.data, {
44198
+ projectRef: identity.projectRef,
44199
+ deploymentId: identity.deploymentId,
44200
+ releaseId: identity.releaseId
44201
+ }) : null;
44202
+ return { release, status: releaseRead.status };
44203
+ }
44204
+ async function activeReleaseSnapshotReadback(http, identity) {
44031
44205
  const snapshot = await readActiveFrontendRelease(http, identity.projectRef, identity.deploymentId);
44032
44206
  if ("failure" in snapshot)
44033
44207
  return { release: null, status: snapshot.status };
@@ -44035,13 +44209,7 @@ async function activeReleaseReadback(http, identity) {
44035
44209
  if (inventory.active_release_id !== identity.releaseId || inventory.active_activation_id !== identity.mutationId) {
44036
44210
  return { release: null, status: 200 };
44037
44211
  }
44038
- const releaseRead = await http.get(releasePath(identity.projectRef, identity.deploymentId, identity.releaseId), { maxJsonBytes: RESPONSE_MAX_BYTES });
44039
- const release = releaseRead.ok ? releaseEnvelope(releaseRead.data, {
44040
- projectRef: identity.projectRef,
44041
- deploymentId: identity.deploymentId,
44042
- releaseId: identity.releaseId
44043
- }) : null;
44044
- return { release, status: releaseRead.status };
44212
+ return { release: inventory.releases[0] ?? null, status: 200 };
44045
44213
  }
44046
44214
  async function readActiveFrontendRelease(http, projectRef, deploymentId) {
44047
44215
  const response = await http.get(`${deploymentEndpoint(projectRef, deploymentId)}/active-release`, {
@@ -44077,10 +44245,74 @@ async function getActiveFrontendRelease(http, projectRef, deploymentId) {
44077
44245
  const snapshot = await readActiveFrontendRelease(http, projectRef, deploymentId);
44078
44246
  return "failure" in snapshot ? snapshot.failure : toolResponse(snapshot.inventory);
44079
44247
  }
44080
- async function rollbackFrontendRelease(http, projectRef, deploymentId, releaseId) {
44248
+ function boundRollbackResponse(result, input) {
44249
+ const payload = JSON.parse(result.content[0].text);
44250
+ return {
44251
+ ...toolResponse({
44252
+ ...payload,
44253
+ operation: "frontend.rollback",
44254
+ project_ref: input.projectRef,
44255
+ deployment_id: input.deploymentId,
44256
+ target_release_id: input.releaseId,
44257
+ mutation_id: input.mutationId,
44258
+ expected_active_release_id: input.expectedActiveReleaseId,
44259
+ expected_activation_id: input.expectedActivationId,
44260
+ ...!result.isError ? {
44261
+ rollback: true,
44262
+ previous_release_id: input.expectedActiveReleaseId,
44263
+ previous_activation_id: input.expectedActivationId
44264
+ } : {}
44265
+ }),
44266
+ ...result.isError ? { isError: true } : {}
44267
+ };
44268
+ }
44269
+ async function rollbackBoundFrontendRelease(http, input) {
44270
+ const authority = await readActiveFrontendRelease(http, input.projectRef, input.deploymentId);
44271
+ if ("failure" in authority)
44272
+ return boundRollbackResponse(authority.failure, input);
44273
+ const current = authority.inventory;
44274
+ if (current.active_release_id === input.releaseId && current.active_activation_id === input.mutationId) {
44275
+ return boundRollbackResponse(await activationReadback(http, input, input.mutationId, 200), input);
44276
+ }
44277
+ if (current.active_release_id !== input.expectedActiveReleaseId || current.active_activation_id !== input.expectedActivationId) {
44278
+ return boundRollbackResponse(releaseFailure("frontend.rollback", "STALE_AUTHORITY", 409), input);
44279
+ }
44280
+ const target = await getFrontendRelease(http, input.projectRef, input.deploymentId, input.releaseId);
44281
+ if (target.isError)
44282
+ return boundRollbackResponse(target, input);
44283
+ return boundRollbackResponse(await activateFrontendRelease(http, input), input);
44284
+ }
44285
+ async function rollbackFrontendRelease(http, projectRef, deploymentId, releaseId, options = {}) {
44081
44286
  if (releaseId !== undefined && !RELEASE_ID_PATTERN.test(releaseId)) {
44082
44287
  throw new Error("'release_id' must be a SHA-256 digest");
44083
44288
  }
44289
+ const bound = options.expectedActiveReleaseId !== undefined || options.expectedActivationId !== undefined || options.mutationId !== undefined;
44290
+ if (bound) {
44291
+ const { expectedActiveReleaseId, expectedActivationId, mutationId } = options;
44292
+ if (releaseId === undefined || expectedActiveReleaseId === undefined || expectedActivationId === undefined || mutationId === undefined) {
44293
+ throw new Error("'release_id', 'expected_active_release_id', 'expected_activation_id', and 'mutation_id' are required together for a bound rollback");
44294
+ }
44295
+ if (!RELEASE_ID_PATTERN.test(expectedActiveReleaseId)) {
44296
+ throw new Error("'expected_active_release_id' must be a SHA-256 digest");
44297
+ }
44298
+ if (!MUTATION_ID_PATTERN2.test(expectedActivationId)) {
44299
+ throw new Error("'expected_activation_id' must be a UUIDv4");
44300
+ }
44301
+ if (!MUTATION_ID_PATTERN2.test(mutationId)) {
44302
+ throw new Error("'mutation_id' must be a UUIDv4");
44303
+ }
44304
+ if (releaseId === expectedActiveReleaseId || mutationId === expectedActivationId) {
44305
+ throw new Error("Bound rollback requires a different target release and a distinct mutation UUID");
44306
+ }
44307
+ return rollbackBoundFrontendRelease(http, {
44308
+ projectRef,
44309
+ deploymentId,
44310
+ releaseId,
44311
+ expectedActiveReleaseId,
44312
+ expectedActivationId,
44313
+ mutationId
44314
+ });
44315
+ }
44084
44316
  const authority = releaseId === undefined ? await readPreviousFrontendRelease(http, projectRef, deploymentId) : await readActiveFrontendRelease(http, projectRef, deploymentId);
44085
44317
  if ("failure" in authority)
44086
44318
  return authority.failure;
@@ -44149,8 +44381,8 @@ async function readPreviousFrontendRelease(http, projectRef, deploymentId) {
44149
44381
  const data = response.data;
44150
44382
  const value = data && typeof data === "object" && !Array.isArray(data) ? data : null;
44151
44383
  const activeReleaseId = value ? nullableIdentity(value.active_release_id, RELEASE_ID_PATTERN) : undefined;
44152
- const activeActivationId = value ? nullableIdentity(value.active_activation_id, MUTATION_ID_PATTERN) : undefined;
44153
- const previousActivationId = value ? nullableIdentity(value.previous_activation_id, MUTATION_ID_PATTERN) : undefined;
44384
+ const activeActivationId = value ? nullableIdentity(value.active_activation_id, MUTATION_ID_PATTERN2) : undefined;
44385
+ const previousActivationId = value ? nullableIdentity(value.previous_activation_id, MUTATION_ID_PATTERN2) : undefined;
44154
44386
  const previous = value?.previous_release === null ? null : releaseRecord(value?.previous_release);
44155
44387
  if (!response.ok || response.status !== 200 || !value || !exactKeys(value, [
44156
44388
  "schema",
@@ -44176,13 +44408,16 @@ async function readPreviousFrontendRelease(http, projectRef, deploymentId) {
44176
44408
  };
44177
44409
  }
44178
44410
  async function activateFrontendRelease(http, input) {
44411
+ return activateFrontendReleaseWithReadback(http, input, activeReleaseReadback);
44412
+ }
44413
+ async function activateFrontendReleaseWithReadback(http, input, readActive) {
44179
44414
  const mutationId = input.mutationId;
44180
- if (!MUTATION_ID_PATTERN.test(mutationId))
44415
+ if (!MUTATION_ID_PATTERN2.test(mutationId))
44181
44416
  throw new Error("'mutation_id' must be a UUIDv4");
44182
44417
  if (input.expectedActiveReleaseId !== "absent" && !RELEASE_ID_PATTERN.test(input.expectedActiveReleaseId)) {
44183
44418
  throw new Error("'expected_active_release_id' is invalid");
44184
44419
  }
44185
- if (input.expectedActivationId !== "absent" && !MUTATION_ID_PATTERN.test(input.expectedActivationId)) {
44420
+ if (input.expectedActivationId !== "absent" && !MUTATION_ID_PATTERN2.test(input.expectedActivationId)) {
44186
44421
  throw new Error("'expected_activation_id' is invalid");
44187
44422
  }
44188
44423
  const endpoint = `${releasePath(input.projectRef, input.deploymentId, input.releaseId)}/activate`;
@@ -44195,13 +44430,13 @@ async function activateFrontendRelease(http, input) {
44195
44430
  responseTimeoutMs: MUTATION_RESPONSE_TIMEOUT_MS
44196
44431
  });
44197
44432
  const release = activationReceipt(response.data, { ...input, mutationId });
44198
- if (!response.ok || !release) {
44433
+ if (!response.ok || response.status !== 200 || !release) {
44199
44434
  if (response.status >= 400 && response.status < 500 && response.status !== 408 && !response.transportError) {
44200
44435
  return releaseFailure("frontend.activate_release", "HTTP_ERROR", response.status);
44201
44436
  }
44202
44437
  return activationReadback(http, input, mutationId, response.status);
44203
44438
  }
44204
- const readback = await activeReleaseReadback(http, { ...input, mutationId });
44439
+ const readback = await readActive(http, { ...input, mutationId });
44205
44440
  if (!readback.release || readback.release.tree_sha256 !== release.tree_sha256) {
44206
44441
  return releaseFailure("frontend.activate_release", "OUTCOME_UNKNOWN", readback.status);
44207
44442
  }
@@ -44216,7 +44451,7 @@ async function activateFrontendRelease(http, input) {
44216
44451
  async function activationReadback(http, input, mutationId, activationStatus) {
44217
44452
  const mutationRead = await http.get(`/v1/projects/${encodeURIComponent(input.projectRef)}/mutations/${mutationId}`, { maxJsonBytes: RESPONSE_MAX_BYTES });
44218
44453
  const mutationEnvelope = mutationRead.data;
44219
- const mutation = mutationRead.ok ? publicMutationReceipt(mutationRead.data, {
44454
+ const mutation = mutationRead.ok && mutationRead.status === 200 ? publicMutationReceipt(mutationRead.data, {
44220
44455
  projectRef: input.projectRef,
44221
44456
  mutationId,
44222
44457
  resourceKey: activationResourceKey(input.deploymentId),
@@ -44321,7 +44556,7 @@ Actions: list_releases, get_active_release, get_release, upload_release, activat
44321
44556
  // package.json
44322
44557
  var package_default = {
44323
44558
  name: "@supacloud/admin",
44324
- version: "0.28.0",
44559
+ version: "0.28.3",
44325
44560
  description: "Platform administration CLI for SupaCloud operators",
44326
44561
  type: "module",
44327
44562
  main: "./dist/index.js",
@@ -44356,21 +44591,21 @@ var package_default = {
44356
44591
  directory: "packages/admin"
44357
44592
  },
44358
44593
  dependencies: {
44359
- "@supacloud/delivery": "0.16.0",
44360
- typebox: "1.3.36",
44361
- "@supacloud/cli": "0.94.0",
44594
+ "@supacloud/delivery": "0.19.3",
44595
+ typebox: "1.3.37",
44596
+ "@supacloud/cli": "0.103.6",
44362
44597
  ssh2: "^1.17.0"
44363
44598
  },
44364
44599
  devDependencies: {
44365
- "@types/bun": "^1.4.2",
44600
+ "@types/bun": "^1.4.3",
44366
44601
  "@types/ssh2": "^1.15.6",
44367
44602
  typescript: "^7.0.2"
44368
44603
  },
44369
44604
  overrides: {
44370
- "@supacloud/contracts": "0.8.1",
44371
- "@supacloud/db": "0.16.2",
44372
- "@supacloud/delivery": "0.16.0",
44373
- "@graphql-tools/utils": "^12.0.3"
44605
+ "@supacloud/contracts": "0.11.4",
44606
+ "@supacloud/db": "0.18.3",
44607
+ "@supacloud/delivery": "0.19.3",
44608
+ "@graphql-tools/utils": "^12.0.4"
44374
44609
  }
44375
44610
  };
44376
44611
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/admin",
3
- "version": "0.28.0",
3
+ "version": "0.28.3",
4
4
  "description": "Platform administration CLI for SupaCloud operators",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -35,20 +35,20 @@
35
35
  "directory": "packages/admin"
36
36
  },
37
37
  "dependencies": {
38
- "@supacloud/delivery": "0.16.0",
39
- "typebox": "1.3.36",
40
- "@supacloud/cli": "0.94.0",
38
+ "@supacloud/delivery": "0.19.3",
39
+ "typebox": "1.3.37",
40
+ "@supacloud/cli": "0.103.6",
41
41
  "ssh2": "^1.17.0"
42
42
  },
43
43
  "devDependencies": {
44
- "@types/bun": "^1.4.2",
44
+ "@types/bun": "^1.4.3",
45
45
  "@types/ssh2": "^1.15.6",
46
46
  "typescript": "^7.0.2"
47
47
  },
48
48
  "overrides": {
49
- "@supacloud/contracts": "0.8.1",
50
- "@supacloud/db": "0.16.2",
51
- "@supacloud/delivery": "0.16.0",
52
- "@graphql-tools/utils": "^12.0.3"
49
+ "@supacloud/contracts": "0.11.4",
50
+ "@supacloud/db": "0.18.3",
51
+ "@supacloud/delivery": "0.19.3",
52
+ "@graphql-tools/utils": "^12.0.4"
53
53
  }
54
54
  }