@supacloud/admin 0.27.1 → 0.28.2

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 +383 -115
  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));
@@ -30122,6 +30121,8 @@ function decodedSchema(inputSchema, outputSchema, decode, options) {
30122
30121
  return result;
30123
30122
  }
30124
30123
  function schemaEnumValues(schema) {
30124
+ if (!schema)
30125
+ return [];
30125
30126
  const view = schema;
30126
30127
  if (Array.isArray(view.enum)) {
30127
30128
  return view.enum.filter((value) => typeof value === "string" || typeof value === "number").map((value) => String(value));
@@ -30149,12 +30150,33 @@ function schemaProperties(schema) {
30149
30150
  }
30150
30151
  return schema;
30151
30152
  }
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.";
30154
+ var removedFrontendActions = new Set([
30155
+ "deploy_git",
30156
+ "deploy_upload",
30157
+ "redeploy",
30158
+ "upload_release",
30159
+ "activate_release"
30160
+ ]);
30161
+ var removedDeployFlags = ["target", "id", "build_command", "output_dir", "plan", "diff", "dry_run"];
30162
+ function assertCurrentDeploymentInput(tool, input) {
30163
+ if (!input || typeof input !== "object" || Array.isArray(input))
30164
+ return;
30165
+ const args = input;
30166
+ if (tool === "frontend" && typeof args["action"] === "string" && removedFrontendActions.has(args["action"])) {
30167
+ throw new Error(DEPLOYMENT_UPGRADE);
30168
+ }
30169
+ if (tool === "deploy" && removedDeployFlags.some((flag) => Object.hasOwn(args, flag))) {
30170
+ throw new Error(`${DEPLOYMENT_UPGRADE} Put build settings in the frontend configuration. For read-only review use \`supacloud app deploy-plan\`.`);
30171
+ }
30172
+ }
30152
30173
  var resultSchema = _Object_({
30153
30174
  content: _Array_(_Object_({ type: Literal("text"), text: String2() })),
30154
30175
  isError: Optional(Boolean2())
30155
30176
  });
30156
30177
  function registerTool(server, name, description, schema, callback) {
30157
30178
  server.tool(name, description, schema, async (input) => {
30179
+ assertCurrentDeploymentInput(name, input);
30158
30180
  const args = parseToolArguments(schema, input);
30159
30181
  const result = await callback(args);
30160
30182
  if (!Check2(resultSchema, result))
@@ -37748,23 +37770,22 @@ function InstanceKeys2(value) {
37748
37770
  function IsIEEE7542(value) {
37749
37771
  return typeof value === "number";
37750
37772
  }
37751
- var ByteMarker2;
37752
- (function(ByteMarker) {
37753
- ByteMarker[ByteMarker["Array"] = 0] = "Array";
37754
- ByteMarker[ByteMarker["BigInt"] = 1] = "BigInt";
37755
- ByteMarker[ByteMarker["Boolean"] = 2] = "Boolean";
37756
- ByteMarker[ByteMarker["Date"] = 3] = "Date";
37757
- ByteMarker[ByteMarker["Constructor"] = 4] = "Constructor";
37758
- ByteMarker[ByteMarker["Function"] = 5] = "Function";
37759
- ByteMarker[ByteMarker["Null"] = 6] = "Null";
37760
- ByteMarker[ByteMarker["Number"] = 7] = "Number";
37761
- ByteMarker[ByteMarker["Object"] = 8] = "Object";
37762
- ByteMarker[ByteMarker["RegExp"] = 9] = "RegExp";
37763
- ByteMarker[ByteMarker["String"] = 10] = "String";
37764
- ByteMarker[ByteMarker["Symbol"] = 11] = "Symbol";
37765
- ByteMarker[ByteMarker["TypeArray"] = 12] = "TypeArray";
37766
- ByteMarker[ByteMarker["Undefined"] = 13] = "Undefined";
37767
- })(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
+ };
37768
37789
  var Accumulator2 = BigInt("14695981039346656037");
37769
37790
  var [Prime2, Size2] = [BigInt("1099511628211"), BigInt("18446744073709551616")];
37770
37791
  var Bytes2 = Array.from({ length: 256 }).map((_, i) => BigInt(i));
@@ -43282,6 +43303,28 @@ function decodedSchema2(inputSchema, outputSchema, decode, options) {
43282
43303
  return result;
43283
43304
  }
43284
43305
 
43306
+ // ../cli/src/shared/deployment-upgrade.ts
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.";
43308
+ var removedFrontendActions2 = new Set([
43309
+ "deploy_git",
43310
+ "deploy_upload",
43311
+ "redeploy",
43312
+ "upload_release",
43313
+ "activate_release"
43314
+ ]);
43315
+ var removedDeployFlags2 = ["target", "id", "build_command", "output_dir", "plan", "diff", "dry_run"];
43316
+ function assertCurrentDeploymentInput2(tool, input) {
43317
+ if (!input || typeof input !== "object" || Array.isArray(input))
43318
+ return;
43319
+ const args = input;
43320
+ if (tool === "frontend" && typeof args["action"] === "string" && removedFrontendActions2.has(args["action"])) {
43321
+ throw new Error(DEPLOYMENT_UPGRADE2);
43322
+ }
43323
+ if (tool === "deploy" && removedDeployFlags2.some((flag) => Object.hasOwn(args, flag))) {
43324
+ throw new Error(`${DEPLOYMENT_UPGRADE2} Put build settings in the frontend configuration. For read-only review use \`supacloud app deploy-plan\`.`);
43325
+ }
43326
+ }
43327
+
43285
43328
  // ../cli/src/shared/tool-server.ts
43286
43329
  var resultSchema2 = _Object_2({
43287
43330
  content: _Array_2(_Object_2({ type: Literal2("text"), text: String4() })),
@@ -43289,6 +43332,7 @@ var resultSchema2 = _Object_2({
43289
43332
  });
43290
43333
  function registerTool2(server, name, description, schema, callback) {
43291
43334
  server.tool(name, description, schema, async (input) => {
43335
+ assertCurrentDeploymentInput2(name, input);
43292
43336
  const args = parseToolArguments2(schema, input);
43293
43337
  const result = await callback(args);
43294
43338
  if (!Check4(resultSchema2, result))
@@ -43656,12 +43700,188 @@ var FRONTEND_ARCHIVE_MAX_FILES2 = 1e4;
43656
43700
  var FRONTEND_ARCHIVE_MAX_SOURCE_BYTES2 = 300 * 1024 * 1024;
43657
43701
  var FRONTEND_ARCHIVE_MAX_TAR_BYTES2 = FRONTEND_ARCHIVE_MAX_SOURCE_BYTES2 + FRONTEND_ARCHIVE_MAX_FILES2 * 2048 + 1024;
43658
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
+
43659
43879
  // ../cli/src/shared/tools/frontend-release-control.ts
43660
43880
  var PROJECT_REF_PATTERN3 = /^[A-Za-z0-9_-]{1,20}$/u;
43661
43881
  var DEPLOYMENT_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/u;
43662
43882
  var RELEASE_ID_PATTERN = /^[0-9a-f]{64}$/u;
43663
- 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;
43664
- 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;
43665
43885
  var ARCHIVE_MAX_BYTES = 100 * 1024 * 1024;
43666
43886
  var ARCHIVE_CHUNK_BYTES = 64 * 1024;
43667
43887
  var RESPONSE_MAX_BYTES = 1024 * 1024;
@@ -43702,7 +43922,7 @@ function releaseRecord(candidate) {
43702
43922
  "kind",
43703
43923
  "archive_format"
43704
43924
  ];
43705
- 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")
43706
43926
  return null;
43707
43927
  return {
43708
43928
  project_ref: record.project_ref,
@@ -43726,8 +43946,8 @@ function releaseEnvelope(candidate, expected) {
43726
43946
  return null;
43727
43947
  return release;
43728
43948
  }
43729
- function canonicalTimestamp4(candidate) {
43730
- if (typeof candidate !== "string" || !TIMESTAMP_PATTERN.test(candidate))
43949
+ function canonicalTimestamp5(candidate) {
43950
+ if (typeof candidate !== "string" || !TIMESTAMP_PATTERN2.test(candidate))
43731
43951
  return false;
43732
43952
  const milliseconds = Date.parse(candidate);
43733
43953
  return Number.isFinite(milliseconds) && new Date(milliseconds).toISOString() === candidate;
@@ -43752,7 +43972,7 @@ function releaseInventory(candidate, expected) {
43752
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))
43753
43973
  return null;
43754
43974
  const activeReleaseId = nullableIdentity(record.active_release_id, RELEASE_ID_PATTERN);
43755
- const activeActivationId = nullableIdentity(record.active_activation_id, MUTATION_ID_PATTERN);
43975
+ const activeActivationId = nullableIdentity(record.active_activation_id, MUTATION_ID_PATTERN2);
43756
43976
  const nextCursor = nullableIdentity(record.next_cursor, RELEASE_ID_PATTERN);
43757
43977
  const releases = record.releases.map(releaseRecord);
43758
43978
  if (activeReleaseId === undefined || activeActivationId === undefined || nextCursor === undefined || activeReleaseId === null !== (activeActivationId === null) || releases.some((release) => release === null))
@@ -43863,13 +44083,16 @@ async function getFrontendRelease(http, projectRef, deploymentId, releaseId) {
43863
44083
  const response = await http.get(releasePath(projectRef, deploymentId, releaseId), {
43864
44084
  maxJsonBytes: RESPONSE_MAX_BYTES
43865
44085
  });
43866
- 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;
43867
44087
  if (!release) {
43868
44088
  return releaseReadFailure("frontend.get_release", response);
43869
44089
  }
43870
44090
  return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
43871
44091
  }
43872
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) {
43873
44096
  const endpoint = releaseEndpoint(projectRef, deploymentId);
43874
44097
  const archive = await verifiedArchive(archivePath);
43875
44098
  let response;
@@ -43888,13 +44111,15 @@ async function uploadFrontendRelease(http, projectRef, deploymentId, archivePath
43888
44111
  } finally {
43889
44112
  await archive.handle.close();
43890
44113
  }
43891
- 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;
43892
44115
  if (!release) {
43893
44116
  if (response.status >= 400 && response.status < 500 && response.status !== 408 && !response.transportError) {
43894
44117
  return releaseFailure("frontend.upload_release", "HTTP_ERROR", response.status);
43895
44118
  }
43896
44119
  return uploadReadback(http, projectRef, deploymentId, archive.sha256, response.status);
43897
44120
  }
44121
+ if (!verifyReadback)
44122
+ return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
43898
44123
  const readback = await http.get(`${endpoint}/${release.release_id}`, { maxJsonBytes: RESPONSE_MAX_BYTES });
43899
44124
  const verified = readback.ok ? releaseEnvelope(readback.data, { projectRef, deploymentId, releaseId: release.release_id }) : null;
43900
44125
  if (!verified || verified.tree_sha256 !== release.tree_sha256) {
@@ -43906,7 +44131,7 @@ async function uploadReadback(http, projectRef, deploymentId, releaseId, uploadS
43906
44131
  const response = await http.get(releasePath(projectRef, deploymentId, releaseId), {
43907
44132
  maxJsonBytes: RESPONSE_MAX_BYTES
43908
44133
  });
43909
- 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;
43910
44135
  if (!release) {
43911
44136
  return releaseFailure("frontend.upload_release", "OUTCOME_UNKNOWN", uploadStatus);
43912
44137
  }
@@ -43937,25 +44162,8 @@ function publicMutationReceipt(candidate, expected) {
43937
44162
  if (!candidate || typeof candidate !== "object" || Array.isArray(candidate))
43938
44163
  return null;
43939
44164
  const envelope = candidate;
43940
- const mutation = envelope.mutation;
43941
- const expectedKeys = [
43942
- "project_ref",
43943
- "mutation_id",
43944
- "operation",
43945
- "resource_key",
43946
- "request_fingerprint",
43947
- "principal",
43948
- "status",
43949
- "checkpoint",
43950
- "receipt",
43951
- "response_status",
43952
- "failure_code",
43953
- "lease",
43954
- "completed_at",
43955
- "created_at",
43956
- "updated_at"
43957
- ];
43958
- 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)
43959
44167
  return null;
43960
44168
  return {
43961
44169
  operation: mutation.operation,
@@ -43982,6 +44190,18 @@ function activationReceipt(candidate, input) {
43982
44190
  return release;
43983
44191
  }
43984
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) {
43985
44205
  const snapshot = await readActiveFrontendRelease(http, identity.projectRef, identity.deploymentId);
43986
44206
  if ("failure" in snapshot)
43987
44207
  return { release: null, status: snapshot.status };
@@ -43989,16 +44209,7 @@ async function activeReleaseReadback(http, identity) {
43989
44209
  if (inventory.active_release_id !== identity.releaseId || inventory.active_activation_id !== identity.mutationId) {
43990
44210
  return { release: null, status: 200 };
43991
44211
  }
43992
- if (snapshot.exactReadback) {
43993
- return { release: inventory.releases[0] ?? null, status: 200 };
43994
- }
43995
- const releaseRead = await http.get(releasePath(identity.projectRef, identity.deploymentId, identity.releaseId), { maxJsonBytes: RESPONSE_MAX_BYTES });
43996
- const release = releaseRead.ok ? releaseEnvelope(releaseRead.data, {
43997
- projectRef: identity.projectRef,
43998
- deploymentId: identity.deploymentId,
43999
- releaseId: identity.releaseId
44000
- }) : null;
44001
- return { release, status: releaseRead.status };
44212
+ return { release: inventory.releases[0] ?? null, status: 200 };
44002
44213
  }
44003
44214
  async function readActiveFrontendRelease(http, projectRef, deploymentId) {
44004
44215
  const response = await http.get(`${deploymentEndpoint(projectRef, deploymentId)}/active-release`, {
@@ -44009,44 +44220,99 @@ async function readActiveFrontendRelease(http, projectRef, deploymentId) {
44009
44220
  if (inventory.next_cursor !== null || inventory.releases.length !== (inventory.active_release_id === null ? 0 : 1) || inventory.releases[0] && inventory.releases[0].release_id !== inventory.active_release_id) {
44010
44221
  return { failure: releaseReadFailure("frontend.get_active_release", response), status: response.status };
44011
44222
  }
44012
- return { inventory, exactReadback: false };
44223
+ return { inventory };
44013
44224
  }
44014
- if (response.ok || response.status !== 404) {
44015
- return { failure: releaseReadFailure("frontend.get_active_release", response), status: response.status };
44016
- }
44017
- const historyResponse = await http.get(`${releaseEndpoint(projectRef, deploymentId)}?limit=1`, {
44018
- maxJsonBytes: RESPONSE_MAX_BYTES
44019
- });
44020
- const history = historyResponse.ok && historyResponse.status === 200 ? releaseInventory(historyResponse.data, { projectRef, deploymentId }) : null;
44021
- if (!history || history.releases.length > 1) {
44225
+ if (response.status === 404) {
44022
44226
  return {
44023
- failure: releaseReadFailure("frontend.get_active_release", historyResponse),
44024
- status: historyResponse.status
44025
- };
44026
- }
44027
- if (history.active_release_id === null) {
44028
- return { inventory: { ...history, releases: [], next_cursor: null }, exactReadback: false };
44029
- }
44030
- const exactResponse = await http.get(releasePath(projectRef, deploymentId, history.active_release_id), {
44031
- maxJsonBytes: RESPONSE_MAX_BYTES
44032
- });
44033
- const release = exactResponse.ok && exactResponse.status === 200 ? releaseEnvelope(exactResponse.data, { projectRef, deploymentId, releaseId: history.active_release_id }) : null;
44034
- if (!release) {
44035
- return {
44036
- failure: releaseReadFailure("frontend.get_active_release", exactResponse),
44037
- status: exactResponse.status
44227
+ failure: {
44228
+ isError: true,
44229
+ content: [{ type: "text", text: JSON.stringify({
44230
+ ok: false,
44231
+ operation: "frontend.get_active_release",
44232
+ error: {
44233
+ code: "DEPLOYMENT_UPGRADE_REQUIRED",
44234
+ http_status: 404,
44235
+ message: `${DEPLOYMENT_UPGRADE2} Check that the deployment exists and upgrade the server if this endpoint is unavailable.`
44236
+ }
44237
+ }) }]
44238
+ },
44239
+ status: response.status
44038
44240
  };
44039
44241
  }
44040
- return { inventory: { ...history, releases: [release], next_cursor: null }, exactReadback: true };
44242
+ return { failure: releaseReadFailure("frontend.get_active_release", response), status: response.status };
44041
44243
  }
44042
44244
  async function getActiveFrontendRelease(http, projectRef, deploymentId) {
44043
44245
  const snapshot = await readActiveFrontendRelease(http, projectRef, deploymentId);
44044
44246
  return "failure" in snapshot ? snapshot.failure : toolResponse(snapshot.inventory);
44045
44247
  }
44046
- 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 = {}) {
44047
44286
  if (releaseId !== undefined && !RELEASE_ID_PATTERN.test(releaseId)) {
44048
44287
  throw new Error("'release_id' must be a SHA-256 digest");
44049
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
+ }
44050
44316
  const authority = releaseId === undefined ? await readPreviousFrontendRelease(http, projectRef, deploymentId) : await readActiveFrontendRelease(http, projectRef, deploymentId);
44051
44317
  if ("failure" in authority)
44052
44318
  return authority.failure;
@@ -44115,8 +44381,8 @@ async function readPreviousFrontendRelease(http, projectRef, deploymentId) {
44115
44381
  const data = response.data;
44116
44382
  const value = data && typeof data === "object" && !Array.isArray(data) ? data : null;
44117
44383
  const activeReleaseId = value ? nullableIdentity(value.active_release_id, RELEASE_ID_PATTERN) : undefined;
44118
- const activeActivationId = value ? nullableIdentity(value.active_activation_id, MUTATION_ID_PATTERN) : undefined;
44119
- 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;
44120
44386
  const previous = value?.previous_release === null ? null : releaseRecord(value?.previous_release);
44121
44387
  if (!response.ok || response.status !== 200 || !value || !exactKeys(value, [
44122
44388
  "schema",
@@ -44138,18 +44404,20 @@ async function readPreviousFrontendRelease(http, projectRef, deploymentId) {
44138
44404
  releases: [],
44139
44405
  next_cursor: null
44140
44406
  },
44141
- exactReadback: false,
44142
44407
  ...previous ? { previousRelease: previous } : {}
44143
44408
  };
44144
44409
  }
44145
44410
  async function activateFrontendRelease(http, input) {
44411
+ return activateFrontendReleaseWithReadback(http, input, activeReleaseReadback);
44412
+ }
44413
+ async function activateFrontendReleaseWithReadback(http, input, readActive) {
44146
44414
  const mutationId = input.mutationId;
44147
- if (!MUTATION_ID_PATTERN.test(mutationId))
44415
+ if (!MUTATION_ID_PATTERN2.test(mutationId))
44148
44416
  throw new Error("'mutation_id' must be a UUIDv4");
44149
44417
  if (input.expectedActiveReleaseId !== "absent" && !RELEASE_ID_PATTERN.test(input.expectedActiveReleaseId)) {
44150
44418
  throw new Error("'expected_active_release_id' is invalid");
44151
44419
  }
44152
- if (input.expectedActivationId !== "absent" && !MUTATION_ID_PATTERN.test(input.expectedActivationId)) {
44420
+ if (input.expectedActivationId !== "absent" && !MUTATION_ID_PATTERN2.test(input.expectedActivationId)) {
44153
44421
  throw new Error("'expected_activation_id' is invalid");
44154
44422
  }
44155
44423
  const endpoint = `${releasePath(input.projectRef, input.deploymentId, input.releaseId)}/activate`;
@@ -44162,13 +44430,13 @@ async function activateFrontendRelease(http, input) {
44162
44430
  responseTimeoutMs: MUTATION_RESPONSE_TIMEOUT_MS
44163
44431
  });
44164
44432
  const release = activationReceipt(response.data, { ...input, mutationId });
44165
- if (!response.ok || !release) {
44433
+ if (!response.ok || response.status !== 200 || !release) {
44166
44434
  if (response.status >= 400 && response.status < 500 && response.status !== 408 && !response.transportError) {
44167
44435
  return releaseFailure("frontend.activate_release", "HTTP_ERROR", response.status);
44168
44436
  }
44169
44437
  return activationReadback(http, input, mutationId, response.status);
44170
44438
  }
44171
- const readback = await activeReleaseReadback(http, { ...input, mutationId });
44439
+ const readback = await readActive(http, { ...input, mutationId });
44172
44440
  if (!readback.release || readback.release.tree_sha256 !== release.tree_sha256) {
44173
44441
  return releaseFailure("frontend.activate_release", "OUTCOME_UNKNOWN", readback.status);
44174
44442
  }
@@ -44183,7 +44451,7 @@ async function activateFrontendRelease(http, input) {
44183
44451
  async function activationReadback(http, input, mutationId, activationStatus) {
44184
44452
  const mutationRead = await http.get(`/v1/projects/${encodeURIComponent(input.projectRef)}/mutations/${mutationId}`, { maxJsonBytes: RESPONSE_MAX_BYTES });
44185
44453
  const mutationEnvelope = mutationRead.data;
44186
- const mutation = mutationRead.ok ? publicMutationReceipt(mutationRead.data, {
44454
+ const mutation = mutationRead.ok && mutationRead.status === 200 ? publicMutationReceipt(mutationRead.data, {
44187
44455
  projectRef: input.projectRef,
44188
44456
  mutationId,
44189
44457
  resourceKey: activationResourceKey(input.deploymentId),
@@ -44288,7 +44556,7 @@ Actions: list_releases, get_active_release, get_release, upload_release, activat
44288
44556
  // package.json
44289
44557
  var package_default = {
44290
44558
  name: "@supacloud/admin",
44291
- version: "0.27.1",
44559
+ version: "0.28.2",
44292
44560
  description: "Platform administration CLI for SupaCloud operators",
44293
44561
  type: "module",
44294
44562
  main: "./dist/index.js",
@@ -44323,21 +44591,21 @@ var package_default = {
44323
44591
  directory: "packages/admin"
44324
44592
  },
44325
44593
  dependencies: {
44326
- "@supacloud/delivery": "0.14.1",
44327
- typebox: "1.3.36",
44328
- "@supacloud/cli": "0.88.0",
44594
+ "@supacloud/delivery": "0.19.2",
44595
+ typebox: "1.3.37",
44596
+ "@supacloud/cli": "0.103.5",
44329
44597
  ssh2: "^1.17.0"
44330
44598
  },
44331
44599
  devDependencies: {
44332
- "@types/bun": "^1.4.2",
44600
+ "@types/bun": "^1.4.3",
44333
44601
  "@types/ssh2": "^1.15.6",
44334
44602
  typescript: "^7.0.2"
44335
44603
  },
44336
44604
  overrides: {
44337
- "@supacloud/contracts": "0.8.1",
44338
- "@supacloud/db": "0.16.1",
44339
- "@supacloud/delivery": "0.14.1",
44340
- "@graphql-tools/utils": "^12.0.3"
44605
+ "@supacloud/contracts": "0.11.3",
44606
+ "@supacloud/db": "0.18.2",
44607
+ "@supacloud/delivery": "0.19.2",
44608
+ "@graphql-tools/utils": "^12.0.4"
44341
44609
  }
44342
44610
  };
44343
44611
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/admin",
3
- "version": "0.27.1",
3
+ "version": "0.28.2",
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.14.1",
39
- "typebox": "1.3.36",
40
- "@supacloud/cli": "0.88.0",
38
+ "@supacloud/delivery": "0.19.2",
39
+ "typebox": "1.3.37",
40
+ "@supacloud/cli": "0.103.5",
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.1",
51
- "@supacloud/delivery": "0.14.1",
52
- "@graphql-tools/utils": "^12.0.3"
49
+ "@supacloud/contracts": "0.11.3",
50
+ "@supacloud/db": "0.18.2",
51
+ "@supacloud/delivery": "0.19.2",
52
+ "@graphql-tools/utils": "^12.0.4"
53
53
  }
54
54
  }