@postman-cse/onboarding-bootstrap 2.9.4 → 2.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/action.cjs CHANGED
@@ -99989,11 +99989,11 @@ var require_valid = __commonJS({
99989
99989
  var require_clean = __commonJS({
99990
99990
  "node_modules/postman-collection/node_modules/semver/functions/clean.js"(exports2, module2) {
99991
99991
  var parse10 = require_parse6();
99992
- var clean = (version, options) => {
99992
+ var clean2 = (version, options) => {
99993
99993
  const s = parse10(version.trim().replace(/^[=v]+/, ""), options);
99994
99994
  return s ? s.version : null;
99995
99995
  };
99996
- module2.exports = clean;
99996
+ module2.exports = clean2;
99997
99997
  }
99998
99998
  });
99999
99999
 
@@ -101304,7 +101304,7 @@ var require_semver2 = __commonJS({
101304
101304
  var identifiers = require_identifiers();
101305
101305
  var parse10 = require_parse6();
101306
101306
  var valid = require_valid();
101307
- var clean = require_clean();
101307
+ var clean2 = require_clean();
101308
101308
  var inc = require_inc();
101309
101309
  var diff = require_diff();
101310
101310
  var major = require_major();
@@ -101342,7 +101342,7 @@ var require_semver2 = __commonJS({
101342
101342
  module2.exports = {
101343
101343
  parse: parse10,
101344
101344
  valid,
101345
- clean,
101345
+ clean: clean2,
101346
101346
  inc,
101347
101347
  diff,
101348
101348
  major,
@@ -256197,8 +256197,8 @@ function getIDToken(aud) {
256197
256197
  }
256198
256198
 
256199
256199
  // src/index.ts
256200
- var import_node_crypto5 = require("node:crypto");
256201
- var import_node_fs5 = require("node:fs");
256200
+ var import_node_crypto6 = require("node:crypto");
256201
+ var import_node_fs6 = require("node:fs");
256202
256202
  var path9 = __toESM(require("node:path"), 1);
256203
256203
  var import_yaml4 = __toESM(require_dist(), 1);
256204
256204
 
@@ -256306,6 +256306,12 @@ var bootstrapActionContract = {
256306
256306
  default: "",
256307
256307
  allowedValues: ["3.0", "3.1"]
256308
256308
  },
256309
+ "preserve-oas30-type-null": {
256310
+ description: "Opt-in compatibility mode for legacy OpenAPI 3.0 oneOf schemas that pair a normal schema with type: null. The original source bytes are uploaded unchanged while an internal nullable view is used for validation and generated artifacts.",
256311
+ required: false,
256312
+ default: "false",
256313
+ allowedValues: ["true", "false"]
256314
+ },
256309
256315
  "breaking-change-mode": {
256310
256316
  description: "OpenAPI breaking-change comparison mode.",
256311
256317
  required: false,
@@ -256362,6 +256368,20 @@ var bootstrapActionContract = {
256362
256368
  default: "warn",
256363
256369
  allowedValues: ["enforce", "warn"]
256364
256370
  },
256371
+ "branch-strategy": {
256372
+ description: "Branch-aware sync strategy. legacy (default) keeps branch-blind behavior; publish-gate restricts canonical writes to the canonical branch and runs credential-free static validation on other branches; preview additionally maintains suffixed per-branch preview asset sets.",
256373
+ required: false,
256374
+ default: "legacy",
256375
+ allowedValues: ["legacy", "preview", "publish-gate"]
256376
+ },
256377
+ "canonical-branch": {
256378
+ description: "Explicit canonical branch (the sole writer of canonical assets). Defaults to the provider-resolved default branch; required on providers without a default-branch variable (Bitbucket, Azure DevOps) when branch-strategy is not legacy.",
256379
+ required: false
256380
+ },
256381
+ "channels": {
256382
+ description: 'Comma-separated channel map for long-lived promotion branches, e.g. "develop=DEV, staging=STAGE, release/*=RC". Channel branches maintain prefix-named parallel asset sets and never mutate canonical assets.',
256383
+ required: false
256384
+ },
256365
256385
  "integration-backend": {
256366
256386
  description: "Integration backend for downstream workspace connectivity.",
256367
256387
  required: false,
@@ -256431,6 +256451,21 @@ var bootstrapActionContract = {
256431
256451
  },
256432
256452
  "breaking-change-summary-json": {
256433
256453
  description: "JSON summary of the OpenAPI breaking-change check."
256454
+ },
256455
+ "sync-status": {
256456
+ description: "Branch-aware sync status: synced (canonical/channel/preview write ran), skipped-branch-gate (gated run, credential-free validation only), or empty under branch-strategy legacy."
256457
+ },
256458
+ "branch-decision": {
256459
+ description: "Serialized BranchDecision JSON for downstream actions (also exported as POSTMAN_BRANCH_DECISION)."
256460
+ },
256461
+ "spec-version-tag": {
256462
+ description: "Native Spec Hub version tag applied on this canonical publish (tag-per-publish), empty when tagging was skipped (no-op sync, non-canonical run, or legacy client)."
256463
+ },
256464
+ "spec-version-url": {
256465
+ description: "Reserved for the repo-sync finalizer; bootstrap does not tag before complete onboarding."
256466
+ },
256467
+ "spec-content-changed": {
256468
+ description: "Whether bootstrap changed canonical spec content; repo-sync uses this to skip native version tags on no-op syncs."
256434
256469
  }
256435
256470
  },
256436
256471
  retainedBehavior: [
@@ -257557,6 +257592,15 @@ function assertSupportedLocalViewContract(node, options) {
257557
257592
  }
257558
257593
 
257559
257594
  // src/lib/postman/additional-collections.ts
257595
+ var RESOURCES_STATE_VERSION = 2;
257596
+ var SUPPORTED_STATE_VERSIONS = /* @__PURE__ */ new Set([1, RESOURCES_STATE_VERSION]);
257597
+ var StateUnreadableError = class extends Error {
257598
+ code = "CONTRACT_STATE_UNREADABLE";
257599
+ constructor(message) {
257600
+ super(`CONTRACT_STATE_UNREADABLE: ${message}`);
257601
+ this.name = "StateUnreadableError";
257602
+ }
257603
+ };
257560
257604
  var ADDITIONAL_COLLECTION_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".yaml", ".yml"]);
257561
257605
  var POSTMAN_COLLECTION_V21_SCHEMA_FRAGMENT = "/collection/v2.1.0/collection.json";
257562
257606
  var V3_DEFINITION_PATH = import_node_path2.default.join(".resources", "definition.yaml");
@@ -257612,16 +257656,46 @@ function resourcesStatePath() {
257612
257656
  return import_node_path2.default.join(workspaceRootForLocalInputs(), RESOURCES_PATH);
257613
257657
  }
257614
257658
  function readResourcesState() {
257659
+ let raw;
257615
257660
  try {
257616
- return (0, import_yaml.parse)((0, import_node_fs2.readFileSync)(resourcesStatePath(), "utf8"));
257661
+ raw = (0, import_node_fs2.readFileSync)(resourcesStatePath(), "utf8");
257617
257662
  } catch {
257618
257663
  return null;
257619
257664
  }
257665
+ let parsed;
257666
+ try {
257667
+ parsed = (0, import_yaml.parse)(raw);
257668
+ } catch (error2) {
257669
+ throw new StateUnreadableError(
257670
+ `.postman/resources.yaml exists but is not parseable YAML (${error2 instanceof Error ? error2.message : String(error2)}). Fix or delete the file; refusing to treat tracked state as absent.`
257671
+ );
257672
+ }
257673
+ if (parsed === null || parsed === void 0) {
257674
+ return null;
257675
+ }
257676
+ if (typeof parsed !== "object" || Array.isArray(parsed)) {
257677
+ throw new StateUnreadableError(
257678
+ ".postman/resources.yaml exists but does not contain a YAML mapping. Fix or delete the file; refusing to treat tracked state as absent."
257679
+ );
257680
+ }
257681
+ const state = parsed;
257682
+ if (state.version !== void 0 && !SUPPORTED_STATE_VERSIONS.has(Number(state.version))) {
257683
+ throw new StateUnreadableError(
257684
+ `.postman/resources.yaml declares unsupported state version ${String(state.version)} (supported: 1, ${RESOURCES_STATE_VERSION}). Upgrade the action or fix the file.`
257685
+ );
257686
+ }
257687
+ if (state.canonical && !state.cloudResources) {
257688
+ state.cloudResources = { ...state.canonical };
257689
+ }
257690
+ return state;
257620
257691
  }
257621
257692
  function writeResourcesState(state) {
257622
257693
  const target = resourcesStatePath();
257623
257694
  (0, import_node_fs2.mkdirSync)(import_node_path2.default.dirname(target), { recursive: true });
257624
- (0, import_node_fs2.writeFileSync)(target, (0, import_yaml.stringify)(state), "utf8");
257695
+ const canonical = state.cloudResources ?? state.canonical ?? {};
257696
+ const persisted = { ...state, version: RESOURCES_STATE_VERSION, canonical };
257697
+ delete persisted.cloudResources;
257698
+ (0, import_node_fs2.writeFileSync)(target, (0, import_yaml.stringify)(persisted), "utf8");
257625
257699
  }
257626
257700
  function findCloudResourceId(map, matcher) {
257627
257701
  if (!map) {
@@ -257631,7 +257705,7 @@ function findCloudResourceId(map, matcher) {
257631
257705
  return match?.[1];
257632
257706
  }
257633
257707
  function findExistingAdditionalCollectionId(resourcesState, resourcePath) {
257634
- return resourcesState?.cloudResources?.additionalCollections?.[resourcePath] ?? resourcesState?.cloudResources?.collections?.[resourcePath];
257708
+ return resourcesState?.canonical?.additionalCollections?.[resourcePath] ?? resourcesState?.canonical?.collections?.[resourcePath] ?? resourcesState?.cloudResources?.additionalCollections?.[resourcePath] ?? resourcesState?.cloudResources?.collections?.[resourcePath];
257635
257709
  }
257636
257710
  function resolveAdditionalCollectionsDir(directoryInput) {
257637
257711
  const workspaceRoot = workspaceRootForLocalInputs();
@@ -258633,6 +258707,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
258633
258707
  * endpoint aborts rather than blocking the run forever. */
258634
258708
  static REQUEST_TIMEOUT_MS = 3e4;
258635
258709
  static POSTMAN_APP_VERSION_URL = `https://dl.pstmn.io/update/status?currentVersion=${_BifrostInternalIntegrationAdapter.MINIMUM_POSTMAN_APP_VERSION}&platform=osx_arm64`;
258710
+ /** Concurrent dual-trigger previews share one spec; peer sync holds a 423 lock. */
258711
+ static SYNC_LOCKED_MAX_RETRIES = 6;
258636
258712
  accessToken;
258637
258713
  tokenProvider;
258638
258714
  appVersionPromise;
@@ -258641,6 +258717,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
258641
258717
  gatewayBaseUrl;
258642
258718
  orgMode;
258643
258719
  secretMasker;
258720
+ sleep;
258644
258721
  teamId;
258645
258722
  constructor(options) {
258646
258723
  this.accessToken = String(options.accessToken || "").trim();
@@ -258654,6 +258731,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
258654
258731
  ).replace(/\/+$/, "");
258655
258732
  this.orgMode = options.orgMode ?? false;
258656
258733
  this.secretMasker = options.secretMasker ?? createSecretMasker([this.accessToken]);
258734
+ this.sleep = options.sleep ?? ((delayMs) => new Promise((resolve5) => setTimeout(resolve5, delayMs)));
258657
258735
  this.teamId = String(options.teamId || "").trim();
258658
258736
  }
258659
258737
  configureTeamContext(teamId, orgMode) {
@@ -258860,55 +258938,72 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
258860
258938
  if (collections.length === 0) {
258861
258939
  return;
258862
258940
  }
258863
- const response = await this.proxyRequest(
258864
- "specification",
258865
- "put",
258866
- `/specifications/${specificationId}/collections`,
258867
- collections.map((collection) => ({
258868
- collectionId: collection.collectionId,
258869
- ...collection.syncOptions ? { syncOptions: collection.syncOptions } : {}
258870
- }))
258871
- );
258872
- if (response.ok) {
258873
- return;
258941
+ const body2 = collections.map((collection) => ({
258942
+ collectionId: collection.collectionId,
258943
+ ...collection.syncOptions ? { syncOptions: collection.syncOptions } : {}
258944
+ }));
258945
+ for (let lockedAttempt = 0; ; lockedAttempt += 1) {
258946
+ const response = await this.proxyRequest(
258947
+ "specification",
258948
+ "put",
258949
+ `/specifications/${specificationId}/collections`,
258950
+ body2
258951
+ );
258952
+ if (response.ok) {
258953
+ return;
258954
+ }
258955
+ const httpErr = await HttpError.fromResponse(response, {
258956
+ method: "POST",
258957
+ requestHeaders: {
258958
+ "Content-Type": "application/json",
258959
+ "x-access-token": this.currentToken(),
258960
+ ...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
258961
+ },
258962
+ secretValues: [this.currentToken()],
258963
+ url: `${this.bifrostBaseUrl}/ws/proxy`
258964
+ });
258965
+ if (httpErr.status === 423 && lockedAttempt < _BifrostInternalIntegrationAdapter.SYNC_LOCKED_MAX_RETRIES) {
258966
+ await this.sleep(2e3 * Math.pow(2, lockedAttempt));
258967
+ continue;
258968
+ }
258969
+ const advised = adviseFromHttpError(
258970
+ httpErr,
258971
+ this.adviceContext("collection-to-specification linking")
258972
+ );
258973
+ throw advised ?? httpErr;
258874
258974
  }
258875
- const httpErr = await HttpError.fromResponse(response, {
258876
- method: "POST",
258877
- requestHeaders: {
258878
- "Content-Type": "application/json",
258879
- "x-access-token": this.currentToken(),
258880
- ...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
258881
- },
258882
- secretValues: [this.currentToken()],
258883
- url: `${this.bifrostBaseUrl}/ws/proxy`
258884
- });
258885
- const advised = adviseFromHttpError(
258886
- httpErr,
258887
- this.adviceContext("collection-to-specification linking")
258888
- );
258889
- throw advised ?? httpErr;
258890
258975
  }
258891
258976
  async syncCollection(specificationId, collectionId) {
258892
- const response = await this.proxyRequest(
258893
- "specification",
258894
- "post",
258895
- `/specifications/${specificationId}/collections/${collectionId}/sync`
258896
- );
258897
- if (response.ok) {
258898
- return;
258977
+ for (let lockedAttempt = 0; ; lockedAttempt += 1) {
258978
+ const response = await this.proxyRequest(
258979
+ "specification",
258980
+ "post",
258981
+ `/specifications/${specificationId}/collections/${collectionId}/sync`
258982
+ );
258983
+ if (response.ok) {
258984
+ return;
258985
+ }
258986
+ const bodyText = await response.clone().text().catch(() => "");
258987
+ if (response.status === 400 && /already in sync/i.test(bodyText)) {
258988
+ return;
258989
+ }
258990
+ const httpErr = await HttpError.fromResponse(response, {
258991
+ method: "POST",
258992
+ requestHeaders: {
258993
+ "Content-Type": "application/json",
258994
+ "x-access-token": this.currentToken(),
258995
+ ...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
258996
+ },
258997
+ secretValues: [this.currentToken()],
258998
+ url: `${this.bifrostBaseUrl}/ws/proxy`
258999
+ });
259000
+ if (httpErr.status === 423 && lockedAttempt < _BifrostInternalIntegrationAdapter.SYNC_LOCKED_MAX_RETRIES) {
259001
+ await this.sleep(2e3 * Math.pow(2, lockedAttempt));
259002
+ continue;
259003
+ }
259004
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("collection sync"));
259005
+ throw advised ?? httpErr;
258899
259006
  }
258900
- const httpErr = await HttpError.fromResponse(response, {
258901
- method: "POST",
258902
- requestHeaders: {
258903
- "Content-Type": "application/json",
258904
- "x-access-token": this.currentToken(),
258905
- ...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
258906
- },
258907
- secretValues: [this.currentToken()],
258908
- url: `${this.bifrostBaseUrl}/ws/proxy`
258909
- });
258910
- const advised = adviseFromHttpError(httpErr, this.adviceContext("collection sync"));
258911
- throw advised ?? httpErr;
258912
259007
  }
258913
259008
  async getWorkspaceGitRepoUrl(workspaceId) {
258914
259009
  const response = await this.proxyRequest(
@@ -259313,6 +259408,18 @@ async function retry(operation, options = {}) {
259313
259408
  }
259314
259409
  throw new Error("Retry exhausted without returning or throwing");
259315
259410
  }
259411
+ function fullJitterDelayMs(attempt, baseMs, capMs, random = Math.random) {
259412
+ const ceiling = Math.min(capMs, baseMs * 2 ** Math.max(0, attempt));
259413
+ return Math.floor(random() * Math.max(0, ceiling));
259414
+ }
259415
+ function parseRetryAfterMs2(value) {
259416
+ if (!value) return void 0;
259417
+ const trimmed = value.trim();
259418
+ if (/^\d+$/.test(trimmed)) return Number(trimmed) * 1e3;
259419
+ const when = Date.parse(trimmed);
259420
+ if (!Number.isNaN(when)) return Math.max(0, when - Date.now());
259421
+ return void 0;
259422
+ }
259316
259423
 
259317
259424
  // src/lib/postman/postman-ec-client.ts
259318
259425
  var EC_WRITE_MAX_ATTEMPTS = 3;
@@ -263926,6 +264033,12 @@ var BOOTSTRAP_BARE_UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9
263926
264033
  function isMissingPatchValueError(error2) {
263927
264034
  return error2 instanceof HttpError && error2.status === 400 && error2.responseBody.includes("Remove operation must point to an existing value");
263928
264035
  }
264036
+ function isRejectedPatchError(error2) {
264037
+ return error2 instanceof HttpError && error2.status === 400 && /REJECTED_PATCH|must update at least one/i.test(
264038
+ `${error2.message}
264039
+ ${error2.responseBody ?? ""}`
264040
+ );
264041
+ }
263929
264042
  function canonicalize(value) {
263930
264043
  if (Array.isArray(value)) return value.map(canonicalize);
263931
264044
  if (value && typeof value === "object") {
@@ -263989,6 +264102,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
263989
264102
  static DEFAULT_GENERATION_POLL_DELAY_MS = 2e3;
263990
264103
  gateway;
263991
264104
  sleep;
264105
+ random;
263992
264106
  generationPollAttempts;
263993
264107
  generationPollDelayMs;
263994
264108
  createIdentity;
@@ -263996,6 +264110,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
263996
264110
  this.gateway = options.gateway;
263997
264111
  this.createIdentity = options.createIdentity ?? import_node_crypto2.randomUUID;
263998
264112
  this.sleep = options.sleep ?? ((delayMs) => new Promise((resolve5) => setTimeout(resolve5, delayMs)));
264113
+ this.random = options.random ?? Math.random;
263999
264114
  this.generationPollAttempts = resolvePollBudget(
264000
264115
  options.generationPollAttempts,
264001
264116
  process.env.POSTMAN_GENERATION_POLL_ATTEMPTS,
@@ -264053,6 +264168,16 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264053
264168
  if (openapiVersion !== "3.0" && openapiVersion !== "3.1") {
264054
264169
  throw new Error(`uploadSpec: unsupported openapiVersion "${openapiVersion}". Expected '3.0' or '3.1'.`);
264055
264170
  }
264171
+ const before = await this.findSpecificationsByExactName(workspaceId, projectName);
264172
+ const existing = adoptExactMatch(
264173
+ `specification:${workspaceId}:${projectName}`,
264174
+ before,
264175
+ (entry) => entry.id
264176
+ );
264177
+ if (existing) {
264178
+ await this.updateSpec(existing.id, specContent, workspaceId);
264179
+ return existing.id;
264180
+ }
264056
264181
  const specType = openapiVersion === "3.1" ? "OPENAPI:3.1" : "OPENAPI:3.0";
264057
264182
  let created;
264058
264183
  try {
@@ -264077,10 +264202,49 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264077
264202
  if (!match) throw error2;
264078
264203
  created = { data: { id: match.id } };
264079
264204
  }
264080
- const specId = String(asRecord8(created?.data)?.id ?? created?.id ?? "").trim();
264205
+ let specId = String(asRecord8(created?.data)?.id ?? created?.id ?? "").trim();
264081
264206
  if (!specId) {
264082
264207
  throw new Error("Spec upload did not return an ID");
264083
264208
  }
264209
+ let matches = await this.findSpecificationsByExactName(workspaceId, projectName);
264210
+ if (before.length === 0 && matches.length <= 1) {
264211
+ await this.sleep(1e3);
264212
+ const settled = await this.findSpecificationsByExactName(workspaceId, projectName);
264213
+ if (settled.length > 0) matches = settled;
264214
+ }
264215
+ if (matches.length > 1 && before.length === 0) {
264216
+ for (const duplicate of matches.slice(1)) {
264217
+ try {
264218
+ await this.deleteSpecification(duplicate.id);
264219
+ } catch (error2) {
264220
+ if (!(error2 instanceof HttpError && error2.status === 404)) throw error2;
264221
+ }
264222
+ }
264223
+ for (let attempt = 0; attempt < 5; attempt += 1) {
264224
+ matches = await this.findSpecificationsByExactName(workspaceId, projectName);
264225
+ if (matches.length <= 1) break;
264226
+ await this.sleep(250 * (attempt + 1));
264227
+ }
264228
+ const converged = adoptExactMatch(
264229
+ `specification:${workspaceId}:${projectName}`,
264230
+ matches,
264231
+ (entry) => entry.id
264232
+ );
264233
+ if (!converged) {
264234
+ throw new Error(`Concurrent specification create for ${projectName} did not converge`);
264235
+ }
264236
+ specId = converged.id;
264237
+ if (specId !== String(asRecord8(created?.data)?.id ?? created?.id ?? "").trim()) {
264238
+ await this.updateSpec(specId, specContent, workspaceId);
264239
+ }
264240
+ } else {
264241
+ const verified = adoptExactMatch(
264242
+ `specification:${workspaceId}:${projectName}`,
264243
+ matches,
264244
+ (entry) => entry.id
264245
+ );
264246
+ if (verified) specId = verified.id;
264247
+ }
264084
264248
  await this.gateway.requestJson({
264085
264249
  service: "specification",
264086
264250
  method: "get",
@@ -264088,6 +264252,14 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264088
264252
  });
264089
264253
  return specId;
264090
264254
  }
264255
+ async deleteSpecification(specId) {
264256
+ await this.gateway.requestJson({
264257
+ service: "specification",
264258
+ method: "delete",
264259
+ path: `/specifications/${specId}`,
264260
+ retry: "none"
264261
+ });
264262
+ }
264091
264263
  async findSpecificationsByExactName(workspaceId, name) {
264092
264264
  const response = await this.gateway.requestJson({
264093
264265
  service: "specification",
@@ -264151,6 +264323,41 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264151
264323
  return void 0;
264152
264324
  }
264153
264325
  }
264326
+ /**
264327
+ * Native Spec Hub version tags (branch-aware sync P3.5). Tags attach to the
264328
+ * LATEST changelog group; the backend 409s when that group is already tagged
264329
+ * (VersionControlService). Callers handle 409 as idempotent-by-group.
264330
+ */
264331
+ async tagSpecVersion(specId, name) {
264332
+ const trimmed = name.trim().slice(0, 255);
264333
+ const created = await this.gateway.requestJson({
264334
+ service: "specification",
264335
+ method: "post",
264336
+ path: `/specifications/${specId}/tags`,
264337
+ retry: "none",
264338
+ body: { name: trimmed }
264339
+ });
264340
+ const record = asRecord8(created?.data) ?? created ?? {};
264341
+ return {
264342
+ id: String(record.id ?? "").trim(),
264343
+ name: String(record.name ?? trimmed).trim()
264344
+ };
264345
+ }
264346
+ /** List a spec's native version tags (newest first per backend ordering). */
264347
+ async listSpecVersionTags(specId) {
264348
+ const response = await this.gateway.requestJson({
264349
+ service: "specification",
264350
+ method: "get",
264351
+ path: `/specifications/${specId}/tags`,
264352
+ query: { limit: "50" }
264353
+ });
264354
+ const entries = Array.isArray(response?.data) ? response.data : [];
264355
+ return entries.map((value) => asRecord8(value)).filter((value) => value !== null).map((value) => ({
264356
+ id: String(value.id ?? "").trim(),
264357
+ // listTags returns `message`; createTag returns `name`. Accept both.
264358
+ name: String(value.name ?? value.message ?? "").trim()
264359
+ })).filter((value) => value.id || value.name);
264360
+ }
264154
264361
  /** Resolve a specification's ROOT file uuid via the files list. */
264155
264362
  async resolveRootFileId(specId) {
264156
264363
  const files = await this.gateway.requestJson({
@@ -264170,79 +264377,182 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264170
264377
  */
264171
264378
  async generateCollection(specId, projectName, prefix, folderStrategy, nestedFolderHierarchy, requestNameSource) {
264172
264379
  const name = [prefix.trim(), projectName.trim()].filter(Boolean).join(" ");
264173
- const submittedName = `${name} [bootstrap:${this.createIdentity()}]`;
264174
- const body2 = {
264175
- name: submittedName,
264176
- options: {
264177
- requestNameSource,
264178
- folderStrategy,
264179
- ...folderStrategy === "Tags" ? { nestedFolderHierarchy } : {}
264180
- }
264181
- };
264182
264380
  const before = await this.listGeneratedCollectionRefs(specId);
264183
- let taskId;
264184
- try {
264185
- taskId = await this.postGenerationWithLockRetry(specId, body2);
264186
- } catch (error2) {
264187
- if (!isAmbiguousTransportError(error2)) throw error2;
264188
- const beforeIds2 = new Set(before.map((entry) => entry.id));
264189
- const appeared2 = (await this.listGeneratedCollectionRefs(specId)).filter(
264190
- (entry) => !beforeIds2.has(entry.id)
264191
- );
264192
- const exactAppeared = await this.filterGeneratedCollectionsByExactName(
264193
- appeared2,
264381
+ const existing = adoptExactMatch(
264382
+ `generated-collection:${specId}:${name}`,
264383
+ await this.filterGeneratedCollectionsByExactName(before, name),
264384
+ (entry) => entry.id
264385
+ );
264386
+ if (existing) return this.convergeGeneratedCollections(specId, name, existing.id);
264387
+ let lastError;
264388
+ for (let taskAttempt = 0; taskAttempt < 2; taskAttempt += 1) {
264389
+ const submittedName = `${name} [bootstrap:${this.createIdentity()}]`;
264390
+ const body2 = {
264391
+ name: submittedName,
264392
+ options: {
264393
+ requestNameSource,
264394
+ folderStrategy,
264395
+ ...folderStrategy === "Tags" ? { nestedFolderHierarchy } : {}
264396
+ }
264397
+ };
264398
+ let taskId;
264399
+ try {
264400
+ const generation = await this.postGenerationWithLockRetry(specId, body2, name);
264401
+ if (generation.adoptedId) {
264402
+ return this.convergeGeneratedCollections(specId, name, generation.adoptedId);
264403
+ }
264404
+ taskId = generation.taskId ?? "";
264405
+ } catch (error2) {
264406
+ if (!isAmbiguousTransportError(error2)) throw error2;
264407
+ const beforeIds2 = new Set(before.map((entry) => entry.id));
264408
+ const appeared2 = (await this.listGeneratedCollectionRefs(specId)).filter(
264409
+ (entry) => !beforeIds2.has(entry.id)
264410
+ );
264411
+ const exactAppeared = await this.filterGeneratedCollectionsByExactName(
264412
+ appeared2,
264413
+ submittedName
264414
+ );
264415
+ const match = adoptExactMatch(
264416
+ `generated-collection:${specId}:${submittedName}`,
264417
+ exactAppeared,
264418
+ (entry) => entry.id
264419
+ );
264420
+ if (!match) throw error2;
264421
+ await this.renameGeneratedCollection(match.id, name);
264422
+ return this.convergeGeneratedCollections(specId, name, match.id);
264423
+ }
264424
+ let taskFailed = false;
264425
+ if (taskId) {
264426
+ for (let attempt = 0; attempt < this.generationPollAttempts; attempt += 1) {
264427
+ await this.sleep(this.generationPollDelayMs);
264428
+ const task = await this.gateway.requestJson({
264429
+ service: "specification",
264430
+ method: "get",
264431
+ path: "/tasks",
264432
+ query: { entityId: specId, entityType: "specification", type: "collection-generation" }
264433
+ });
264434
+ const status = String(asRecord8(task?.data)?.[taskId] ?? "").toLowerCase();
264435
+ if (status === "failed" || status === "error") {
264436
+ taskFailed = true;
264437
+ lastError = new Error(`Collection generation task failed for ${prefix}`);
264438
+ break;
264439
+ }
264440
+ if (status && status !== "in-progress" && status !== "pending" && status !== "queued") {
264441
+ break;
264442
+ }
264443
+ if (attempt === this.generationPollAttempts - 1) {
264444
+ throw new Error(`Collection generation timed out for ${prefix}`);
264445
+ }
264446
+ }
264447
+ }
264448
+ if (taskFailed) {
264449
+ await this.sleep(1e3 * (taskAttempt + 1));
264450
+ continue;
264451
+ }
264452
+ const beforeIds = new Set(before.map((entry) => entry.id));
264453
+ const after = await this.listGeneratedCollectionRefs(specId);
264454
+ const appeared = after.filter((entry) => !beforeIds.has(entry.id));
264455
+ const candidates = await this.filterGeneratedCollectionsByExactName(
264456
+ appeared,
264194
264457
  submittedName
264195
264458
  );
264196
- const match = adoptExactMatch(
264459
+ const uid = adoptExactMatch(
264197
264460
  `generated-collection:${specId}:${submittedName}`,
264198
- exactAppeared,
264461
+ candidates,
264199
264462
  (entry) => entry.id
264200
- );
264201
- if (!match) throw error2;
264202
- await this.renameGeneratedCollection(match.id, name);
264203
- return match.id;
264463
+ )?.id;
264464
+ if (!uid) {
264465
+ throw new Error(`Collection generation did not yield a collection uid for ${prefix}`);
264466
+ }
264467
+ await this.renameGeneratedCollection(uid, name);
264468
+ return this.convergeGeneratedCollections(specId, name, uid);
264204
264469
  }
264205
- if (taskId) {
264206
- for (let attempt = 0; attempt < this.generationPollAttempts; attempt += 1) {
264207
- await this.sleep(this.generationPollDelayMs);
264208
- const task = await this.gateway.requestJson({
264209
- service: "specification",
264210
- method: "get",
264211
- path: "/tasks",
264212
- query: { entityId: specId, entityType: "specification", type: "collection-generation" }
264213
- });
264214
- const status = String(asRecord8(task?.data)?.[taskId] ?? "").toLowerCase();
264215
- if (status === "failed" || status === "error") {
264216
- throw new Error(`Collection generation task failed for ${prefix}`);
264217
- }
264218
- if (status && status !== "in-progress" && status !== "pending" && status !== "queued") {
264219
- break;
264220
- }
264221
- if (attempt === this.generationPollAttempts - 1) {
264222
- throw new Error(`Collection generation timed out for ${prefix}`);
264470
+ throw lastError ?? new Error(`Collection generation task failed for ${prefix}`);
264471
+ }
264472
+ /**
264473
+ * Re-elect the durable generated collection for a final name. Call after
264474
+ * concurrent dual-trigger generates and before description/inject/tag so a
264475
+ * peer orphan-sweep cannot leave this runner holding a deleted id.
264476
+ */
264477
+ async adoptGeneratedCollection(specId, projectName, prefix, preferredId = "") {
264478
+ const name = [prefix.trim(), projectName.trim()].filter(Boolean).join(" ");
264479
+ return this.convergeGeneratedCollections(specId, name, preferredId);
264480
+ }
264481
+ /**
264482
+ * Concurrent dual-trigger previews can each generate+rename the same final
264483
+ * collection identity. Elect the stable lowest-id winner.
264484
+ *
264485
+ * Losers only delete *their own* preferred collection (never a peer's still-
264486
+ * in-use id). Winners wait briefly for peers to self-delete, then clean any
264487
+ * leftover same-identity orphans (temps + extra finals).
264488
+ */
264489
+ async convergeGeneratedCollections(specId, finalName, preferredId) {
264490
+ const tempPrefix = `${finalName} [bootstrap:`;
264491
+ const hydrate = async () => {
264492
+ const linked = await this.listGeneratedCollectionRefs(specId);
264493
+ return Promise.all(
264494
+ linked.map(async (entry) => {
264495
+ if (entry.name) return { id: entry.id, name: entry.name };
264496
+ try {
264497
+ const collection = await this.gateway.requestJson({
264498
+ service: "collection",
264499
+ method: "get",
264500
+ path: `/v3/collections/${this.bareModelId(entry.id)}`
264501
+ });
264502
+ return {
264503
+ id: entry.id,
264504
+ name: String(asRecord8(collection?.data)?.name ?? "").trim()
264505
+ };
264506
+ } catch (error2) {
264507
+ if (error2 instanceof HttpError && error2.status === 404) {
264508
+ return { id: entry.id, name: "" };
264509
+ }
264510
+ throw error2;
264511
+ }
264512
+ })
264513
+ );
264514
+ };
264515
+ const selectSameIdentity = (entries) => entries.filter(
264516
+ (entry) => entry.name === finalName || entry.name.startsWith(tempPrefix)
264517
+ ).sort((a, b) => a.id.localeCompare(b.id));
264518
+ let sameIdentity = selectSameIdentity(await hydrate());
264519
+ if (sameIdentity.length === 0) return preferredId;
264520
+ if (sameIdentity.length === 1) {
264521
+ await this.sleep(1e3);
264522
+ sameIdentity = selectSameIdentity(await hydrate());
264523
+ if (sameIdentity.length === 0) return preferredId;
264524
+ }
264525
+ const winner = sameIdentity[0];
264526
+ if (winner.name !== finalName) {
264527
+ await this.renameGeneratedCollection(winner.id, finalName);
264528
+ }
264529
+ if (preferredId && preferredId !== winner.id) {
264530
+ const own = sameIdentity.find((entry) => entry.id === preferredId);
264531
+ if (own) {
264532
+ try {
264533
+ await this.deleteCollection(preferredId);
264534
+ } catch (error2) {
264535
+ if (!(error2 instanceof HttpError && error2.status === 404)) throw error2;
264223
264536
  }
264224
264537
  }
264538
+ return winner.id;
264225
264539
  }
264226
- const beforeIds = new Set(before.map((entry) => entry.id));
264227
- const after = await this.listGeneratedCollectionRefs(specId);
264228
- const appeared = after.filter((entry) => !beforeIds.has(entry.id));
264229
- const candidates = await this.filterGeneratedCollectionsByExactName(
264230
- appeared,
264231
- submittedName
264232
- );
264233
- const uid = adoptExactMatch(
264234
- `generated-collection:${specId}:${submittedName}`,
264235
- candidates,
264236
- (entry) => entry.id
264237
- )?.id;
264238
- if (!uid) {
264239
- throw new Error(`Collection generation did not yield a collection uid for ${prefix}`);
264540
+ if (sameIdentity.length > 1) {
264541
+ await this.sleep(1500);
264542
+ sameIdentity = selectSameIdentity(await hydrate());
264543
+ for (const duplicate of sameIdentity) {
264544
+ if (duplicate.id === winner.id) continue;
264545
+ try {
264546
+ await this.deleteCollection(duplicate.id);
264547
+ } catch (error2) {
264548
+ if (!(error2 instanceof HttpError && error2.status === 404)) throw error2;
264549
+ }
264550
+ }
264240
264551
  }
264241
- await this.renameGeneratedCollection(uid, name);
264242
- return uid;
264552
+ return winner.id;
264243
264553
  }
264244
264554
  /** POST the generation request, retrying a 423-locked spec; returns the task id. */
264245
- async postGenerationWithLockRetry(specId, body2) {
264555
+ async postGenerationWithLockRetry(specId, body2, finalName) {
264246
264556
  for (let lockedAttempt = 0; ; lockedAttempt += 1) {
264247
264557
  try {
264248
264558
  const created = await this.gateway.requestJson({
@@ -264252,13 +264562,22 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264252
264562
  retry: "none",
264253
264563
  body: body2
264254
264564
  });
264255
- return String(asRecord8(created?.data)?.taskId ?? "").trim();
264565
+ return { taskId: String(asRecord8(created?.data)?.taskId ?? "").trim() };
264256
264566
  } catch (error2) {
264257
264567
  const locked = error2 instanceof HttpError && error2.status === 423;
264258
264568
  if (!locked || lockedAttempt >= _PostmanGatewayAssetsClient.GENERATION_LOCKED_MAX_RETRIES) {
264259
264569
  throw error2;
264260
264570
  }
264261
264571
  await this.sleep(5e3 * Math.pow(2, lockedAttempt));
264572
+ const adopted = adoptExactMatch(
264573
+ `generated-collection:${specId}:${finalName}`,
264574
+ await this.filterGeneratedCollectionsByExactName(
264575
+ await this.listGeneratedCollectionRefs(specId),
264576
+ finalName
264577
+ ),
264578
+ (entry) => entry.id
264579
+ );
264580
+ if (adopted) return { adoptedId: adopted.id };
264262
264581
  }
264263
264582
  }
264264
264583
  }
@@ -264295,14 +264614,24 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264295
264614
  return hydrated.filter((entry) => entry.name === expectedName);
264296
264615
  }
264297
264616
  async renameGeneratedCollection(collectionId, name) {
264298
- await this.gateway.requestJson({
264299
- service: "collection",
264300
- method: "patch",
264301
- path: `/v3/collections/${this.bareModelId(collectionId)}`,
264302
- // Replacing a generated collection's name with the same value is idempotent.
264303
- retry: "safe",
264304
- body: [{ op: "replace", path: "/name", value: name }]
264305
- });
264617
+ try {
264618
+ await this.gateway.requestJson({
264619
+ service: "collection",
264620
+ method: "patch",
264621
+ path: `/v3/collections/${this.bareModelId(collectionId)}`,
264622
+ // Replacing a generated collection's name with the same value is idempotent.
264623
+ retry: "safe",
264624
+ body: [{ op: "replace", path: "/name", value: name }]
264625
+ });
264626
+ } catch (error2) {
264627
+ if (error2 instanceof HttpError && error2.status === 400 && /must update at least one|REJECTED_PATCH/i.test(
264628
+ `${error2.message}
264629
+ ${error2.responseBody ?? ""}`
264630
+ )) {
264631
+ return;
264632
+ }
264633
+ throw error2;
264634
+ }
264306
264635
  }
264307
264636
  /**
264308
264637
  * Create a team-visible workspace through the gateway workspaces service.
@@ -264556,7 +264885,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264556
264885
  if (!retriable || attempt === maxAttempts - 1) {
264557
264886
  throw error2;
264558
264887
  }
264559
- await this.sleep(Math.min(2e3, 300 * 2 ** attempt));
264888
+ await this.sleep(fullJitterDelayMs(attempt, 300, 2e3, this.random));
264560
264889
  }
264561
264890
  }
264562
264891
  }
@@ -264577,6 +264906,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264577
264906
  service: "tagging",
264578
264907
  method: "put",
264579
264908
  path: `/v1/tags/collections/${collectionUid}`,
264909
+ retry: "safe",
264580
264910
  body: { tags: normalized.map((slug) => ({ slug })) }
264581
264911
  });
264582
264912
  }
@@ -264806,14 +265136,19 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264806
265136
  { type: "afterResponse", code: exec2.join("\n"), language: "text/javascript" }
264807
265137
  ];
264808
265138
  for (const script of plan.scripts) {
264809
- await this.gateway.requestJson({
264810
- service: "collection",
264811
- method: "patch",
264812
- path: `/v3/collections/${cid}/items/${script.itemId}`,
264813
- retry: "safe",
264814
- headers: { "X-Entity-Type": "http-request" },
264815
- body: [{ op: "add", path: "/scripts", value: toV3Scripts(script.exec) }]
264816
- });
265139
+ try {
265140
+ await this.gateway.requestJson({
265141
+ service: "collection",
265142
+ method: "patch",
265143
+ path: `/v3/collections/${cid}/items/${script.itemId}`,
265144
+ retry: "safe",
265145
+ headers: { "X-Entity-Type": "http-request" },
265146
+ body: [{ op: "add", path: "/scripts", value: toV3Scripts(script.exec) }]
265147
+ });
265148
+ } catch (error2) {
265149
+ if (isRejectedPatchError(error2)) continue;
265150
+ throw error2;
265151
+ }
264817
265152
  }
264818
265153
  if (!items.some((i) => String(i.name ?? "") === "00 - Resolve Secrets")) {
264819
265154
  const created = await this.gateway.requestJson({
@@ -265018,36 +265353,47 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
265018
265353
  async createItemTree(cid, items, parentId) {
265019
265354
  for (const item of items) {
265020
265355
  const kind = String(item.$kind ?? "http-request");
265021
- let created;
265022
- try {
265023
- created = await this.gateway.requestJson({
265024
- service: "collection",
265025
- method: "post",
265026
- path: `/v3/collections/${cid}/items/`,
265027
- retry: "none",
265028
- headers: { "X-Entity-Type": kind },
265029
- body: this.buildItemCreateBody(item, parentId)
265030
- });
265031
- } catch (error2) {
265032
- if (!isAmbiguousTransportError(error2)) throw error2;
265033
- const name = String(item.name ?? "Untitled");
265034
- const matches = (await this.listCollectionItems(cid)).filter((candidate) => {
265035
- if (String(candidate.name ?? candidate.title ?? "") !== name) return false;
265036
- if (String(candidate.$kind ?? candidate.type ?? "http-request") !== kind) return false;
265037
- const position = asRecord8(candidate.position);
265038
- const parent = asRecord8(position?.parent);
265039
- const candidateParent = String(parent?.id ?? position?.parent ?? candidate.parent ?? "").trim();
265040
- return Boolean(candidateParent) && this.bareModelId(candidateParent) === this.bareModelId(parentId);
265041
- });
265042
- const match = adoptExactMatch(
265043
- `collection-item:${cid}:${parentId}:${kind}:${name}`,
265044
- matches,
265045
- (candidate) => String(candidate.id ?? "")
265046
- );
265047
- if (!match) throw error2;
265048
- created = { data: { id: match.id } };
265356
+ const maxAttempts = 4;
265357
+ let newId = "";
265358
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
265359
+ let created;
265360
+ try {
265361
+ created = await this.gateway.requestJson({
265362
+ service: "collection",
265363
+ method: "post",
265364
+ path: `/v3/collections/${cid}/items/`,
265365
+ retry: "none",
265366
+ headers: { "X-Entity-Type": kind },
265367
+ body: this.buildItemCreateBody(item, parentId)
265368
+ });
265369
+ } catch (error2) {
265370
+ if (!isAmbiguousTransportError(error2)) throw error2;
265371
+ const name = String(item.name ?? "Untitled");
265372
+ const matches = (await this.listCollectionItems(cid)).filter((candidate) => {
265373
+ if (String(candidate.name ?? candidate.title ?? "") !== name) return false;
265374
+ if (String(candidate.$kind ?? candidate.type ?? "http-request") !== kind) return false;
265375
+ const position = asRecord8(candidate.position);
265376
+ const parent = asRecord8(position?.parent);
265377
+ const candidateParent = String(parent?.id ?? position?.parent ?? candidate.parent ?? "").trim();
265378
+ return Boolean(candidateParent) && this.bareModelId(candidateParent) === this.bareModelId(parentId);
265379
+ });
265380
+ const match = adoptExactMatch(
265381
+ `collection-item:${cid}:${parentId}:${kind}:${name}`,
265382
+ matches,
265383
+ (candidate) => String(candidate.id ?? "")
265384
+ );
265385
+ if (match) {
265386
+ created = { data: { id: match.id } };
265387
+ } else {
265388
+ const retriable = error2 instanceof HttpError && error2.status >= 500;
265389
+ if (!retriable || attempt === maxAttempts) throw error2;
265390
+ await this.sleep(fullJitterDelayMs(attempt - 1, 300, 2e3, this.random));
265391
+ continue;
265392
+ }
265393
+ }
265394
+ newId = String(asRecord8(created?.data)?.id ?? "").trim();
265395
+ if (newId) break;
265049
265396
  }
265050
- const newId = String(asRecord8(created?.data)?.id ?? "").trim();
265051
265397
  if (!newId) {
265052
265398
  throw new Error(
265053
265399
  `Item create did not return an id for ${String(item.name ?? "item")}`
@@ -265090,6 +265436,30 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
265090
265436
  * - `remove` of /description always works (field exists as "")
265091
265437
  * - on update, GET the root first and only remove fields that currently exist
265092
265438
  */
265439
+ /**
265440
+ * GET a collection root, retrying through the v3 surface's read-after-write
265441
+ * 404 lag. A freshly generated/renamed collection can transiently report
265442
+ * RESOURCE_NOT_FOUND for a few seconds (worse under concurrent runner load);
265443
+ * retrying absorbs that instead of hard-failing the run.
265444
+ */
265445
+ async getCollectionRoot(cid) {
265446
+ const got = await retry(
265447
+ () => this.gateway.requestJson({
265448
+ service: "collection",
265449
+ method: "get",
265450
+ path: `/v3/collections/${cid}`,
265451
+ retry: "none"
265452
+ }),
265453
+ {
265454
+ maxAttempts: 6,
265455
+ delayMs: 1e3,
265456
+ backoffMultiplier: 2,
265457
+ maxDelayMs: 8e3,
265458
+ shouldRetry: (error2) => error2 instanceof HttpError && error2.status === 404
265459
+ }
265460
+ );
265461
+ return asRecord8(got?.data);
265462
+ }
265093
265463
  async applyCollectionLevelSettings(cid, v3, options = {}) {
265094
265464
  const ops = [];
265095
265465
  if (options.rename && typeof v3.name === "string" && v3.name) {
@@ -265097,12 +265467,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
265097
265467
  }
265098
265468
  let current = null;
265099
265469
  if (options.reconcileRemovals) {
265100
- const got = await this.gateway.requestJson({
265101
- service: "collection",
265102
- method: "get",
265103
- path: `/v3/collections/${cid}`
265104
- });
265105
- current = asRecord8(got?.data);
265470
+ current = await this.getCollectionRoot(cid);
265106
265471
  }
265107
265472
  const hasDescription = typeof v3.description === "string" && v3.description.length > 0;
265108
265473
  if (hasDescription) {
@@ -265141,6 +265506,9 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
265141
265506
  if (isMissingPatchValueError(error2) && ops.some((op) => op.op === "remove") && await this.verifyRootSettingsApplied(cid, ops)) {
265142
265507
  return;
265143
265508
  }
265509
+ if (isRejectedPatchError(error2) && await this.verifyRootSettingsApplied(cid, ops)) {
265510
+ return;
265511
+ }
265144
265512
  throw error2;
265145
265513
  }
265146
265514
  }
@@ -265203,6 +265571,15 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
265203
265571
  async createCollection(workspaceId, collection, options = {}) {
265204
265572
  const v3 = this.normalizeCollectionForWrite(collection);
265205
265573
  const desiredName = String(v3.name ?? "Untitled Collection");
265574
+ const existing = adoptExactMatch(
265575
+ `collection:${workspaceId}:${desiredName}`,
265576
+ await this.findCollectionsByExactName(workspaceId, desiredName),
265577
+ (entry) => entry.id
265578
+ );
265579
+ if (existing) {
265580
+ await this.updateCollection(existing.id, collection);
265581
+ return existing.id;
265582
+ }
265206
265583
  const submittedName = `${desiredName} [bootstrap:${this.createIdentity()}]`;
265207
265584
  const rootBody = { name: submittedName };
265208
265585
  let created;
@@ -265253,6 +265630,12 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
265253
265630
  }
265254
265631
  return rawId;
265255
265632
  }
265633
+ /** Patch only the durable collection description without reconciling its item tree. */
265634
+ async updateCollectionDescription(collectionUid, description) {
265635
+ const cid = this.bareModelId(collectionUid);
265636
+ await this.getCollectionRoot(cid);
265637
+ await this.applyCollectionLevelSettings(cid, { description });
265638
+ }
265256
265639
  /**
265257
265640
  * Full-replace reconcile of a curated local v2.1.0 or collection v3 payload: delete every
265258
265641
  * root-level item (deleting a folder cascades its children server-side —
@@ -265334,6 +265717,7 @@ function detectInnerError(body2) {
265334
265717
  return typeof innerStatus === "number" && innerStatus >= 400 ? innerStatus : 502;
265335
265718
  }
265336
265719
  function isTransientGatewayError(status, body2) {
265720
+ if (status === 429) return true;
265337
265721
  if (status === 502 || status === 503 || status === 504) return true;
265338
265722
  if (status >= 500 && (body2.includes("ESOCKETTIMEDOUT") || body2.includes("ETIMEDOUT") || body2.includes("ECONNRESET") || body2.includes("serverError") || body2.includes("downstream"))) {
265339
265723
  return true;
@@ -265352,8 +265736,10 @@ var AccessTokenGatewayClient = class {
265352
265736
  secretMasker;
265353
265737
  maxRetries;
265354
265738
  retryBaseDelayMs;
265739
+ retryMaxDelayMs;
265355
265740
  requestTimeoutMs;
265356
265741
  sleepImpl;
265742
+ randomImpl;
265357
265743
  constructor(options) {
265358
265744
  this.tokenProvider = options.tokenProvider;
265359
265745
  this.bifrostBaseUrl = String(
@@ -265365,8 +265751,10 @@ var AccessTokenGatewayClient = class {
265365
265751
  this.secretMasker = options.secretMasker ?? createSecretMasker([this.tokenProvider.current()]);
265366
265752
  this.maxRetries = options.maxRetries ?? 3;
265367
265753
  this.retryBaseDelayMs = options.retryBaseDelayMs ?? 400;
265754
+ this.retryMaxDelayMs = options.retryMaxDelayMs ?? 5e3;
265368
265755
  this.requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
265369
265756
  this.sleepImpl = options.sleepImpl ?? defaultSleep;
265757
+ this.randomImpl = options.randomImpl ?? Math.random;
265370
265758
  }
265371
265759
  configureTeamContext(teamId, orgMode) {
265372
265760
  this.teamId = String(teamId || "").trim();
@@ -265426,7 +265814,7 @@ var AccessTokenGatewayClient = class {
265426
265814
  response = await this.send(request);
265427
265815
  } catch (error2) {
265428
265816
  if (retryMode === "safe" && attempt < this.maxRetries) {
265429
- const delay = this.retryBaseDelayMs * 2 ** attempt;
265817
+ const delay = this.retryDelayMs(attempt);
265430
265818
  attempt += 1;
265431
265819
  await this.sleepImpl(delay);
265432
265820
  continue;
@@ -265438,7 +265826,7 @@ var AccessTokenGatewayClient = class {
265438
265826
  const innerStatus = detectInnerError(okBody);
265439
265827
  if (innerStatus !== null) {
265440
265828
  if (retryMode === "safe" && isTransientGatewayError(innerStatus, okBody) && attempt < this.maxRetries) {
265441
- const delay = this.retryBaseDelayMs * 2 ** attempt;
265829
+ const delay = this.retryDelayMs(attempt);
265442
265830
  attempt += 1;
265443
265831
  await this.sleepImpl(delay);
265444
265832
  continue;
@@ -265463,7 +265851,10 @@ var AccessTokenGatewayClient = class {
265463
265851
  throw this.toHttpError(request, response, retryBody);
265464
265852
  }
265465
265853
  if (retryMode === "safe" && isTransientGatewayError(response.status, body2) && attempt < this.maxRetries) {
265466
- const delay = this.retryBaseDelayMs * 2 ** attempt;
265854
+ const delay = this.retryDelayMs(
265855
+ attempt,
265856
+ parseRetryAfterMs2(response.headers.get("retry-after"))
265857
+ );
265467
265858
  attempt += 1;
265468
265859
  await this.sleepImpl(delay);
265469
265860
  continue;
@@ -265471,13 +265862,26 @@ var AccessTokenGatewayClient = class {
265471
265862
  throw this.toHttpError(request, response, body2);
265472
265863
  }
265473
265864
  }
265865
+ /**
265866
+ * Full-jitter backoff (uniform in [0, min(cap, base * 2^attempt))) so
265867
+ * concurrent CI runners that fail together never retry in lockstep against
265868
+ * the shared gateway. A server-sent Retry-After beats the heuristic: it is
265869
+ * authoritative backpressure, honored verbatim (capped by the ceiling).
265870
+ */
265871
+ retryDelayMs(attempt, retryAfterMs) {
265872
+ if (retryAfterMs !== void 0) {
265873
+ return Math.min(this.retryMaxDelayMs, retryAfterMs);
265874
+ }
265875
+ return fullJitterDelayMs(attempt, this.retryBaseDelayMs, this.retryMaxDelayMs, this.randomImpl);
265876
+ }
265474
265877
  /**
265475
265878
  * The success path reads the body to inspect for an inner error, which
265476
265879
  * consumes the stream. Hand callers a fresh Response over the buffered text so
265477
265880
  * `requestJson` can still parse it.
265478
265881
  */
265479
265882
  rebuildResponse(response, body2) {
265480
- return new Response(body2, {
265883
+ const nullBody = response.status === 204 || response.status === 205 || response.status === 304;
265884
+ return new Response(nullBody ? null : body2, {
265481
265885
  status: response.status,
265482
265886
  statusText: response.statusText,
265483
265887
  headers: response.headers
@@ -266207,6 +266611,9 @@ function createTelemetryContext(options) {
266207
266611
  var import_node_fs3 = require("node:fs");
266208
266612
  var import_node_path3 = require("node:path");
266209
266613
  function resolveActionVersion2() {
266614
+ if (false) {
266615
+ return void 0;
266616
+ }
266210
266617
  try {
266211
266618
  const raw = (0, import_node_fs3.readFileSync)((0, import_node_path3.join)(__dirname, "..", "package.json"), "utf8");
266212
266619
  return JSON.parse(raw).version ?? "unknown";
@@ -281929,6 +282336,61 @@ function serializeOpenApiDocument(document2) {
281929
282336
  return `${JSON.stringify(document2, null, 2)}
281930
282337
  `;
281931
282338
  }
282339
+ function typeNullPath(pathSegments) {
282340
+ return pathSegments.map(String).join(".");
282341
+ }
282342
+ function isNullOnlySchema(value) {
282343
+ const record = asRecord10(value);
282344
+ if (!record || record.type !== "null") return false;
282345
+ return Object.keys(record).every((key) => key === "type" || key.startsWith("x-"));
282346
+ }
282347
+ function createOas30TypeNullCompatibilityDocument(sourceDocument) {
282348
+ const document2 = structuredClone(sourceDocument);
282349
+ const sourceTypeNullPaths = [];
282350
+ const visit4 = (value, pathSegments) => {
282351
+ if (Array.isArray(value)) {
282352
+ value.forEach((entry, index) => visit4(entry, [...pathSegments, index]));
282353
+ return;
282354
+ }
282355
+ const record = asRecord10(value);
282356
+ if (!record) return;
282357
+ const oneOf = Array.isArray(record.oneOf) ? record.oneOf : void 0;
282358
+ const nullIndexes = oneOf ? oneOf.flatMap((entry, index) => isNullOnlySchema(entry) ? [index] : []) : [];
282359
+ if (nullIndexes.length > 0) {
282360
+ if (oneOf?.length !== 2 || nullIndexes.length !== 1) {
282361
+ throw new Error(
282362
+ `CONTRACT_OAS30_TYPE_NULL_UNSUPPORTED: ${typeNullPath(pathSegments)} must use oneOf with exactly one null-only member and one non-null schema`
282363
+ );
282364
+ }
282365
+ const nullIndex = nullIndexes[0];
282366
+ const nonNullIndex = nullIndex === 0 ? 1 : 0;
282367
+ const nonNullSchema = asRecord10(oneOf[nonNullIndex]);
282368
+ if (!nonNullSchema || nonNullSchema.type === "null") {
282369
+ throw new Error(
282370
+ `CONTRACT_OAS30_TYPE_NULL_UNSUPPORTED: ${typeNullPath(pathSegments)} must pair the null-only member with one non-null schema`
282371
+ );
282372
+ }
282373
+ const siblings = Object.fromEntries(
282374
+ Object.entries(record).filter(([key]) => key !== "oneOf")
282375
+ );
282376
+ for (const key of Object.keys(record)) delete record[key];
282377
+ Object.assign(record, structuredClone(nonNullSchema), siblings, { nullable: true });
282378
+ sourceTypeNullPaths.push(typeNullPath([...pathSegments, "oneOf", nullIndex, "type"]));
282379
+ visit4(record, pathSegments);
282380
+ return;
282381
+ }
282382
+ if (record.type === "null") {
282383
+ throw new Error(
282384
+ `CONTRACT_OAS30_TYPE_NULL_UNSUPPORTED: ${typeNullPath([...pathSegments, "type"])} is not a supported nullable oneOf member`
282385
+ );
282386
+ }
282387
+ for (const [key, child4] of Object.entries(record)) {
282388
+ visit4(child4, [...pathSegments, key]);
282389
+ }
282390
+ };
282391
+ visit4(document2, []);
282392
+ return { document: document2, sourceTypeNullPaths };
282393
+ }
281932
282394
  async function bundleSpec(baseUrl, document2, options) {
281933
282395
  const budget = options.budget ?? { refs: 0, totalBytes: Buffer.byteLength(JSON.stringify(document2), "utf8") };
281934
282396
  const fetchText = options.fetchText ?? safeFetchText;
@@ -281970,7 +282432,14 @@ function createCachedFetchText(options) {
281970
282432
  async function buildLoadedSpec(content, baseRef, options, fetchText, budget) {
281971
282433
  const document2 = parseOpenApiDocument(content);
281972
282434
  const version = detectOpenApiVersion2(document2);
281973
- const bundledDocument = await bundleSpec(baseRef, document2, { ...options, budget, fetchText });
282435
+ let contractDocument = document2;
282436
+ let sourceTypeNullPaths = [];
282437
+ if (options.preserveOas30TypeNull && version === "3.0") {
282438
+ const compatibility = createOas30TypeNullCompatibilityDocument(document2);
282439
+ contractDocument = compatibility.document;
282440
+ sourceTypeNullPaths = compatibility.sourceTypeNullPaths;
282441
+ }
282442
+ const bundledDocument = await bundleSpec(baseRef, contractDocument, { ...options, budget, fetchText });
281974
282443
  const validation = await validate(bundledDocument, {
281975
282444
  resolve: { external: false, file: false },
281976
282445
  dereference: { circular: "ignore" },
@@ -281984,6 +282453,7 @@ async function buildLoadedSpec(content, baseRef, options, fetchText, budget) {
281984
282453
  bundledDocument,
281985
282454
  contractIndex: buildContractIndex(bundledDocument),
281986
282455
  content,
282456
+ sourceTypeNullPaths,
281987
282457
  version
281988
282458
  };
281989
282459
  }
@@ -282109,6 +282579,309 @@ function looksLikeIntrospection(record) {
282109
282579
  return Boolean(data && typeof data === "object" && data.__schema);
282110
282580
  }
282111
282581
 
282582
+ // src/lib/repo/branch-decision.ts
282583
+ var import_node_fs5 = require("node:fs");
282584
+ var import_node_crypto4 = require("node:crypto");
282585
+ var ContractError = class extends Error {
282586
+ code;
282587
+ constructor(code, message) {
282588
+ super(`${code}: ${message}`);
282589
+ this.code = code;
282590
+ this.name = "ContractError";
282591
+ }
282592
+ };
282593
+ function clean(value) {
282594
+ const trimmed = (value ?? "").trim();
282595
+ return trimmed.length > 0 ? trimmed : void 0;
282596
+ }
282597
+ function stripRefPrefix(ref) {
282598
+ const raw = clean(ref);
282599
+ if (!raw) {
282600
+ return { kind: "unknown" };
282601
+ }
282602
+ if (raw.startsWith("refs/heads/")) {
282603
+ return { name: raw.slice("refs/heads/".length), kind: "branch" };
282604
+ }
282605
+ if (raw.startsWith("refs/tags/")) {
282606
+ return { name: raw.slice("refs/tags/".length), kind: "tag" };
282607
+ }
282608
+ if (raw.startsWith("refs/pull/") || raw.startsWith("refs/merge")) {
282609
+ return { kind: "unknown" };
282610
+ }
282611
+ return { name: raw, kind: "branch" };
282612
+ }
282613
+ function detectProvider(env) {
282614
+ if (clean(env.GITHUB_ACTIONS) || clean(env.GITHUB_REPOSITORY)) return "github";
282615
+ if (clean(env.GITLAB_CI) || clean(env.CI_PROJECT_PATH)) return "gitlab";
282616
+ if (clean(env.BITBUCKET_REPO_SLUG) || clean(env.BITBUCKET_BRANCH)) return "bitbucket";
282617
+ if (clean(env.TF_BUILD) || clean(env.BUILD_REPOSITORY_URI)) return "azure-devops";
282618
+ return "unknown";
282619
+ }
282620
+ function readGithubEvent(env) {
282621
+ const path10 = clean(env.GITHUB_EVENT_PATH);
282622
+ if (!path10) return void 0;
282623
+ try {
282624
+ return JSON.parse((0, import_node_fs5.readFileSync)(path10, "utf8"));
282625
+ } catch {
282626
+ return void 0;
282627
+ }
282628
+ }
282629
+ function resolveBranchIdentity(env = process.env, overrides = {}) {
282630
+ const provider = detectProvider(env);
282631
+ const explicitDefault = clean(overrides.defaultBranch);
282632
+ let headBranch;
282633
+ let rawRef;
282634
+ let refKind;
282635
+ let isPrContext = false;
282636
+ let isForkPr = false;
282637
+ let defaultBranch = explicitDefault;
282638
+ let headSha;
282639
+ switch (provider) {
282640
+ case "github": {
282641
+ const event2 = readGithubEvent(env);
282642
+ headSha = clean(env.GITHUB_SHA);
282643
+ defaultBranch ??= clean(event2?.repository?.default_branch);
282644
+ const headRef = clean(env.GITHUB_HEAD_REF);
282645
+ if (headRef) {
282646
+ isPrContext = true;
282647
+ headBranch = headRef;
282648
+ rawRef = clean(env.GITHUB_REF) ?? headRef;
282649
+ refKind = "branch";
282650
+ const headRepo = event2?.pull_request?.head?.repo?.full_name;
282651
+ const baseRepo = event2?.pull_request?.base?.repo?.full_name ?? event2?.repository?.full_name;
282652
+ isForkPr = Boolean(headRepo && baseRepo && headRepo !== baseRepo);
282653
+ headSha = clean(event2?.pull_request?.head?.sha) ?? headSha;
282654
+ } else {
282655
+ rawRef = clean(env.GITHUB_REF) ?? clean(env.GITHUB_REF_NAME);
282656
+ const parsed = stripRefPrefix(rawRef);
282657
+ headBranch = parsed.kind === "branch" ? parsed.name : void 0;
282658
+ refKind = parsed.kind;
282659
+ }
282660
+ break;
282661
+ }
282662
+ case "gitlab": {
282663
+ headSha = clean(env.CI_COMMIT_SHA);
282664
+ defaultBranch ??= clean(env.CI_DEFAULT_BRANCH);
282665
+ const mrSource = clean(env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME);
282666
+ if (mrSource) {
282667
+ isPrContext = true;
282668
+ headBranch = mrSource;
282669
+ rawRef = mrSource;
282670
+ refKind = "branch";
282671
+ const sourceProject = clean(env.CI_MERGE_REQUEST_SOURCE_PROJECT_ID);
282672
+ const targetProject = clean(env.CI_MERGE_REQUEST_PROJECT_ID);
282673
+ isForkPr = Boolean(sourceProject && targetProject && sourceProject !== targetProject);
282674
+ } else if (clean(env.CI_COMMIT_TAG)) {
282675
+ rawRef = clean(env.CI_COMMIT_TAG);
282676
+ refKind = "tag";
282677
+ } else {
282678
+ headBranch = clean(env.CI_COMMIT_BRANCH) ?? clean(env.CI_COMMIT_REF_NAME);
282679
+ rawRef = headBranch;
282680
+ refKind = headBranch ? "branch" : "unknown";
282681
+ }
282682
+ break;
282683
+ }
282684
+ case "bitbucket": {
282685
+ headSha = clean(env.BITBUCKET_COMMIT);
282686
+ if (clean(env.BITBUCKET_TAG)) {
282687
+ rawRef = clean(env.BITBUCKET_TAG);
282688
+ refKind = "tag";
282689
+ } else {
282690
+ headBranch = clean(env.BITBUCKET_BRANCH);
282691
+ rawRef = headBranch;
282692
+ refKind = headBranch ? "branch" : "unknown";
282693
+ isPrContext = Boolean(clean(env.BITBUCKET_PR_ID));
282694
+ }
282695
+ break;
282696
+ }
282697
+ case "azure-devops": {
282698
+ headSha = clean(env.BUILD_SOURCEVERSION);
282699
+ const prSource = clean(env.SYSTEM_PULLREQUEST_SOURCEBRANCH);
282700
+ if (prSource) {
282701
+ isPrContext = true;
282702
+ const parsed = stripRefPrefix(prSource);
282703
+ headBranch = parsed.kind === "branch" ? parsed.name : void 0;
282704
+ rawRef = prSource;
282705
+ refKind = parsed.kind;
282706
+ const forkFlag = clean(env.SYSTEM_PULLREQUEST_ISFORK);
282707
+ isForkPr = forkFlag?.toLowerCase() === "true";
282708
+ } else {
282709
+ rawRef = clean(env.BUILD_SOURCEBRANCH);
282710
+ const parsed = stripRefPrefix(rawRef);
282711
+ headBranch = parsed.kind === "branch" ? parsed.name : void 0;
282712
+ refKind = parsed.kind;
282713
+ }
282714
+ break;
282715
+ }
282716
+ default: {
282717
+ refKind = "unknown";
282718
+ }
282719
+ }
282720
+ if (refKind === "branch" && headBranch && defaultBranch && headBranch === defaultBranch) {
282721
+ refKind = "default-branch";
282722
+ }
282723
+ return { provider, headBranch, rawRef, defaultBranch, refKind, isPrContext, isForkPr, headSha };
282724
+ }
282725
+ function parseChannelRules(input) {
282726
+ const raw = clean(input);
282727
+ const rules = [];
282728
+ for (const part of raw ? raw.split(",") : []) {
282729
+ const entry = part.trim();
282730
+ if (!entry) continue;
282731
+ const eq = entry.indexOf("=");
282732
+ if (eq <= 0 || eq === entry.length - 1) {
282733
+ throw new ContractError(
282734
+ "CONTRACT_CHANNELS_INPUT_INVALID",
282735
+ `channels entry "${entry}" must be <branch-or-glob>=<CODE>`
282736
+ );
282737
+ }
282738
+ const pattern = entry.slice(0, eq).trim();
282739
+ const code = entry.slice(eq + 1).trim().toUpperCase();
282740
+ if (!/^[A-Z][A-Z0-9_-]{0,15}$/.test(code)) {
282741
+ throw new ContractError(
282742
+ "CONTRACT_CHANNELS_INPUT_INVALID",
282743
+ `channel code "${code}" must be 1-16 chars, A-Z 0-9 _ -, starting with a letter`
282744
+ );
282745
+ }
282746
+ rules.push({ pattern, code });
282747
+ }
282748
+ if (!rules.some((rule) => rule.pattern === "release/*")) {
282749
+ rules.push({ pattern: "release/*", code: "RC" });
282750
+ }
282751
+ return rules;
282752
+ }
282753
+ function matchChannel(branch, rules) {
282754
+ for (const rule of rules) {
282755
+ if (rule.pattern.endsWith("*")) {
282756
+ const prefix = rule.pattern.slice(0, -1);
282757
+ if (branch.startsWith(prefix)) return rule;
282758
+ } else if (branch === rule.pattern) {
282759
+ return rule;
282760
+ }
282761
+ }
282762
+ return void 0;
282763
+ }
282764
+ function resolveBranchDecision(options) {
282765
+ const { strategy, identity } = options;
282766
+ const channels = options.channels ?? [];
282767
+ if (strategy === "legacy") {
282768
+ return {
282769
+ tier: "legacy",
282770
+ strategy,
282771
+ identity,
282772
+ canonicalBranch: clean(options.canonicalBranch) ?? identity.defaultBranch,
282773
+ reason: "branch-strategy legacy: branch-blind pre-v2 behavior"
282774
+ };
282775
+ }
282776
+ const canonicalBranch = clean(options.canonicalBranch) ?? identity.defaultBranch;
282777
+ if (!canonicalBranch) {
282778
+ throw new ContractError(
282779
+ "CONTRACT_DEFAULT_BRANCH_UNRESOLVED",
282780
+ `cannot resolve the canonical branch on ${identity.provider} (no explicit canonical-branch input and the provider exposes no default-branch variable). Set the canonical-branch input.`
282781
+ );
282782
+ }
282783
+ if (identity.refKind === "tag" || identity.refKind === "unknown" || !identity.headBranch) {
282784
+ return {
282785
+ tier: "gated",
282786
+ strategy,
282787
+ identity,
282788
+ canonicalBranch,
282789
+ reason: `ref kind ${identity.refKind}: never canonical/preview-eligible; no-op with annotation`
282790
+ };
282791
+ }
282792
+ if (identity.headBranch === canonicalBranch) {
282793
+ return {
282794
+ tier: "canonical",
282795
+ strategy,
282796
+ identity,
282797
+ canonicalBranch,
282798
+ reason: `head branch equals canonical branch ${canonicalBranch}`
282799
+ };
282800
+ }
282801
+ const channel = matchChannel(identity.headBranch, channels);
282802
+ if (channel) {
282803
+ return {
282804
+ tier: "channel",
282805
+ strategy,
282806
+ identity,
282807
+ canonicalBranch,
282808
+ channel,
282809
+ reason: `branch ${identity.headBranch} matches channel ${channel.pattern}=${channel.code}`
282810
+ };
282811
+ }
282812
+ if (strategy === "preview") {
282813
+ if (identity.isForkPr) {
282814
+ return {
282815
+ tier: "gated",
282816
+ strategy,
282817
+ identity,
282818
+ canonicalBranch,
282819
+ reason: "fork PR: preview-ineligible (same-repo gate), gated instead"
282820
+ };
282821
+ }
282822
+ return {
282823
+ tier: "preview",
282824
+ strategy,
282825
+ identity,
282826
+ canonicalBranch,
282827
+ reason: `branch ${identity.headBranch} under branch-strategy preview`
282828
+ };
282829
+ }
282830
+ return {
282831
+ tier: "gated",
282832
+ strategy,
282833
+ identity,
282834
+ canonicalBranch,
282835
+ reason: `branch ${identity.headBranch} under branch-strategy publish-gate`
282836
+ };
282837
+ }
282838
+ var BRANCH_DECISION_ENV = "POSTMAN_BRANCH_DECISION";
282839
+ function serializeBranchDecision(decision) {
282840
+ return JSON.stringify(decision);
282841
+ }
282842
+ function parseBranchDecision(raw) {
282843
+ const value = clean(raw);
282844
+ if (!value) return void 0;
282845
+ let parsed;
282846
+ try {
282847
+ parsed = JSON.parse(value);
282848
+ } catch {
282849
+ throw new ContractError("CONTRACT_BRANCH_DECISION_INVALID", "POSTMAN_BRANCH_DECISION is not valid JSON");
282850
+ }
282851
+ const candidate = parsed;
282852
+ const tiers = ["canonical", "channel", "preview", "gated", "legacy"];
282853
+ if (!candidate || typeof candidate !== "object" || !tiers.includes(candidate.tier) || !candidate.identity) {
282854
+ throw new ContractError("CONTRACT_BRANCH_DECISION_INVALID", "POSTMAN_BRANCH_DECISION does not carry a valid BranchDecision");
282855
+ }
282856
+ return candidate;
282857
+ }
282858
+ function resolveEffectiveBranchDecision(options, env = process.env) {
282859
+ const inherited = parseBranchDecision(env[BRANCH_DECISION_ENV]);
282860
+ if (inherited) return inherited;
282861
+ return resolveBranchDecision(options);
282862
+ }
282863
+ var PREVIEW_SLUG_MAX = 30;
282864
+ function buildBranchSlug(rawBranch) {
282865
+ const sanitized = rawBranch.replace(/^refs\/heads\//, "").replace(/\s+/g, "-").replace(/[^A-Za-z0-9._-]/g, "-").replace(/-+/g, "-").replace(/^[._-]+|[._-]+$/g, "");
282866
+ const truncated = sanitized.slice(0, PREVIEW_SLUG_MAX);
282867
+ const lossy = truncated !== rawBranch.replace(/^refs\/heads\//, "");
282868
+ if (!lossy) {
282869
+ return { suffix: truncated, slug: truncated, lossy };
282870
+ }
282871
+ const hash = (0, import_node_crypto4.createHash)("sha256").update(rawBranch).digest("hex").slice(0, 6);
282872
+ return { suffix: `${truncated}-${hash}`, slug: truncated, lossy };
282873
+ }
282874
+ function previewAssetName(baseName, rawBranch) {
282875
+ return `${baseName} @${buildBranchSlug(rawBranch).suffix}`;
282876
+ }
282877
+ function channelAssetName(baseName, code) {
282878
+ return `[${code}] ${baseName}`;
282879
+ }
282880
+ var MARKER_KEY = "x-pm-onboarding";
282881
+ function renderAssetMarker(marker) {
282882
+ return `${MARKER_KEY}: ${JSON.stringify(marker)}`;
282883
+ }
282884
+
282112
282885
  // node_modules/graphql/jsutils/inspect.mjs
282113
282886
  var MAX_ARRAY_LENGTH = 10;
282114
282887
  var MAX_RECURSIVE_DEPTH = 2;
@@ -298640,940 +299413,6 @@ function getPositionFromMatch(match) {
298640
299413
  }
298641
299414
 
298642
299415
  // node_modules/@nodable/entities/src/entities.js
298643
- var BASIC_LATIN = {
298644
- amp: "&",
298645
- AMP: "&",
298646
- lt: "<",
298647
- LT: "<",
298648
- gt: ">",
298649
- GT: ">",
298650
- quot: '"',
298651
- QUOT: '"',
298652
- apos: "'",
298653
- lsquo: "\u2018",
298654
- rsquo: "\u2019",
298655
- ldquo: "\u201C",
298656
- rdquo: "\u201D",
298657
- lsquor: "\u201A",
298658
- rsquor: "\u2019",
298659
- ldquor: "\u201E",
298660
- bdquo: "\u201E",
298661
- comma: ",",
298662
- period: ".",
298663
- colon: ":",
298664
- semi: ";",
298665
- excl: "!",
298666
- quest: "?",
298667
- num: "#",
298668
- dollar: "$",
298669
- percent: "%",
298670
- ast: "*",
298671
- commat: "@",
298672
- lowbar: "_",
298673
- verbar: "|",
298674
- vert: "|",
298675
- sol: "/",
298676
- bsol: "\\",
298677
- lbrace: "{",
298678
- rbrace: "}",
298679
- lbrack: "[",
298680
- rbrack: "]",
298681
- lpar: "(",
298682
- rpar: ")",
298683
- nbsp: "\xA0",
298684
- iexcl: "\xA1",
298685
- cent: "\xA2",
298686
- pound: "\xA3",
298687
- curren: "\xA4",
298688
- yen: "\xA5",
298689
- brvbar: "\xA6",
298690
- sect: "\xA7",
298691
- uml: "\xA8",
298692
- copy: "\xA9",
298693
- COPY: "\xA9",
298694
- ordf: "\xAA",
298695
- laquo: "\xAB",
298696
- not: "\xAC",
298697
- shy: "\xAD",
298698
- reg: "\xAE",
298699
- REG: "\xAE",
298700
- macr: "\xAF",
298701
- deg: "\xB0",
298702
- plusmn: "\xB1",
298703
- sup2: "\xB2",
298704
- sup3: "\xB3",
298705
- acute: "\xB4",
298706
- micro: "\xB5",
298707
- para: "\xB6",
298708
- middot: "\xB7",
298709
- cedil: "\xB8",
298710
- sup1: "\xB9",
298711
- ordm: "\xBA",
298712
- raquo: "\xBB",
298713
- frac14: "\xBC",
298714
- frac12: "\xBD",
298715
- half: "\xBD",
298716
- frac34: "\xBE",
298717
- iquest: "\xBF",
298718
- times: "\xD7",
298719
- div: "\xF7",
298720
- divide: "\xF7"
298721
- };
298722
- var LATIN_ACCENTS = {
298723
- Agrave: "\xC0",
298724
- agrave: "\xE0",
298725
- Aacute: "\xC1",
298726
- aacute: "\xE1",
298727
- Acirc: "\xC2",
298728
- acirc: "\xE2",
298729
- Atilde: "\xC3",
298730
- atilde: "\xE3",
298731
- Auml: "\xC4",
298732
- auml: "\xE4",
298733
- Aring: "\xC5",
298734
- aring: "\xE5",
298735
- AElig: "\xC6",
298736
- aelig: "\xE6",
298737
- Ccedil: "\xC7",
298738
- ccedil: "\xE7",
298739
- Egrave: "\xC8",
298740
- egrave: "\xE8",
298741
- Eacute: "\xC9",
298742
- eacute: "\xE9",
298743
- Ecirc: "\xCA",
298744
- ecirc: "\xEA",
298745
- Euml: "\xCB",
298746
- euml: "\xEB",
298747
- Igrave: "\xCC",
298748
- igrave: "\xEC",
298749
- Iacute: "\xCD",
298750
- iacute: "\xED",
298751
- Icirc: "\xCE",
298752
- icirc: "\xEE",
298753
- Iuml: "\xCF",
298754
- iuml: "\xEF",
298755
- ETH: "\xD0",
298756
- eth: "\xF0",
298757
- Ntilde: "\xD1",
298758
- ntilde: "\xF1",
298759
- Ograve: "\xD2",
298760
- ograve: "\xF2",
298761
- Oacute: "\xD3",
298762
- oacute: "\xF3",
298763
- Ocirc: "\xD4",
298764
- ocirc: "\xF4",
298765
- Otilde: "\xD5",
298766
- otilde: "\xF5",
298767
- Ouml: "\xD6",
298768
- ouml: "\xF6",
298769
- Oslash: "\xD8",
298770
- oslash: "\xF8",
298771
- Ugrave: "\xD9",
298772
- ugrave: "\xF9",
298773
- Uacute: "\xDA",
298774
- uacute: "\xFA",
298775
- Ucirc: "\xDB",
298776
- ucirc: "\xFB",
298777
- Uuml: "\xDC",
298778
- uuml: "\xFC",
298779
- Yacute: "\xDD",
298780
- yacute: "\xFD",
298781
- THORN: "\xDE",
298782
- thorn: "\xFE",
298783
- szlig: "\xDF",
298784
- yuml: "\xFF",
298785
- Yuml: "\u0178"
298786
- };
298787
- var LATIN_EXTENDED = {
298788
- Amacr: "\u0100",
298789
- amacr: "\u0101",
298790
- Abreve: "\u0102",
298791
- abreve: "\u0103",
298792
- Aogon: "\u0104",
298793
- aogon: "\u0105",
298794
- Cacute: "\u0106",
298795
- cacute: "\u0107",
298796
- Ccirc: "\u0108",
298797
- ccirc: "\u0109",
298798
- Cdot: "\u010A",
298799
- cdot: "\u010B",
298800
- Ccaron: "\u010C",
298801
- ccaron: "\u010D",
298802
- Dcaron: "\u010E",
298803
- dcaron: "\u010F",
298804
- Dstrok: "\u0110",
298805
- dstrok: "\u0111",
298806
- Emacr: "\u0112",
298807
- emacr: "\u0113",
298808
- Ecaron: "\u011A",
298809
- ecaron: "\u011B",
298810
- Edot: "\u0116",
298811
- edot: "\u0117",
298812
- Eogon: "\u0118",
298813
- eogon: "\u0119",
298814
- Gcirc: "\u011C",
298815
- gcirc: "\u011D",
298816
- Gbreve: "\u011E",
298817
- gbreve: "\u011F",
298818
- Gdot: "\u0120",
298819
- gdot: "\u0121",
298820
- Gcedil: "\u0122",
298821
- Hcirc: "\u0124",
298822
- hcirc: "\u0125",
298823
- Hstrok: "\u0126",
298824
- hstrok: "\u0127",
298825
- Itilde: "\u0128",
298826
- itilde: "\u0129",
298827
- Imacr: "\u012A",
298828
- imacr: "\u012B",
298829
- Iogon: "\u012E",
298830
- iogon: "\u012F",
298831
- Idot: "\u0130",
298832
- IJlig: "\u0132",
298833
- ijlig: "\u0133",
298834
- Jcirc: "\u0134",
298835
- jcirc: "\u0135",
298836
- Kcedil: "\u0136",
298837
- kcedil: "\u0137",
298838
- kgreen: "\u0138",
298839
- Lacute: "\u0139",
298840
- lacute: "\u013A",
298841
- Lcedil: "\u013B",
298842
- lcedil: "\u013C",
298843
- Lcaron: "\u013D",
298844
- lcaron: "\u013E",
298845
- Lmidot: "\u013F",
298846
- lmidot: "\u0140",
298847
- Lstrok: "\u0141",
298848
- lstrok: "\u0142",
298849
- Nacute: "\u0143",
298850
- nacute: "\u0144",
298851
- Ncaron: "\u0147",
298852
- ncaron: "\u0148",
298853
- Ncedil: "\u0145",
298854
- ncedil: "\u0146",
298855
- ENG: "\u014A",
298856
- eng: "\u014B",
298857
- Omacr: "\u014C",
298858
- omacr: "\u014D",
298859
- Odblac: "\u0150",
298860
- odblac: "\u0151",
298861
- OElig: "\u0152",
298862
- oelig: "\u0153",
298863
- Racute: "\u0154",
298864
- racute: "\u0155",
298865
- Rcaron: "\u0158",
298866
- rcaron: "\u0159",
298867
- Rcedil: "\u0156",
298868
- rcedil: "\u0157",
298869
- Sacute: "\u015A",
298870
- sacute: "\u015B",
298871
- Scirc: "\u015C",
298872
- scirc: "\u015D",
298873
- Scedil: "\u015E",
298874
- scedil: "\u015F",
298875
- Scaron: "\u0160",
298876
- scaron: "\u0161",
298877
- Tcedil: "\u0162",
298878
- tcedil: "\u0163",
298879
- Tcaron: "\u0164",
298880
- tcaron: "\u0165",
298881
- Tstrok: "\u0166",
298882
- tstrok: "\u0167",
298883
- Utilde: "\u0168",
298884
- utilde: "\u0169",
298885
- Umacr: "\u016A",
298886
- umacr: "\u016B",
298887
- Ubreve: "\u016C",
298888
- ubreve: "\u016D",
298889
- Uring: "\u016E",
298890
- uring: "\u016F",
298891
- Udblac: "\u0170",
298892
- udblac: "\u0171",
298893
- Uogon: "\u0172",
298894
- uogon: "\u0173",
298895
- Wcirc: "\u0174",
298896
- wcirc: "\u0175",
298897
- Ycirc: "\u0176",
298898
- ycirc: "\u0177",
298899
- Zacute: "\u0179",
298900
- zacute: "\u017A",
298901
- Zdot: "\u017B",
298902
- zdot: "\u017C",
298903
- Zcaron: "\u017D",
298904
- zcaron: "\u017E"
298905
- };
298906
- var GREEK = {
298907
- Alpha: "\u0391",
298908
- alpha: "\u03B1",
298909
- Beta: "\u0392",
298910
- beta: "\u03B2",
298911
- Gamma: "\u0393",
298912
- gamma: "\u03B3",
298913
- Delta: "\u0394",
298914
- delta: "\u03B4",
298915
- Epsilon: "\u0395",
298916
- epsilon: "\u03B5",
298917
- epsiv: "\u03F5",
298918
- varepsilon: "\u03F5",
298919
- Zeta: "\u0396",
298920
- zeta: "\u03B6",
298921
- Eta: "\u0397",
298922
- eta: "\u03B7",
298923
- Theta: "\u0398",
298924
- theta: "\u03B8",
298925
- thetasym: "\u03D1",
298926
- vartheta: "\u03D1",
298927
- Iota: "\u0399",
298928
- iota: "\u03B9",
298929
- Kappa: "\u039A",
298930
- kappa: "\u03BA",
298931
- kappav: "\u03F0",
298932
- varkappa: "\u03F0",
298933
- Lambda: "\u039B",
298934
- lambda: "\u03BB",
298935
- Mu: "\u039C",
298936
- mu: "\u03BC",
298937
- Nu: "\u039D",
298938
- nu: "\u03BD",
298939
- Xi: "\u039E",
298940
- xi: "\u03BE",
298941
- Omicron: "\u039F",
298942
- omicron: "\u03BF",
298943
- Pi: "\u03A0",
298944
- pi: "\u03C0",
298945
- piv: "\u03D6",
298946
- varpi: "\u03D6",
298947
- Rho: "\u03A1",
298948
- rho: "\u03C1",
298949
- rhov: "\u03F1",
298950
- varrho: "\u03F1",
298951
- Sigma: "\u03A3",
298952
- sigma: "\u03C3",
298953
- sigmaf: "\u03C2",
298954
- sigmav: "\u03C2",
298955
- varsigma: "\u03C2",
298956
- Tau: "\u03A4",
298957
- tau: "\u03C4",
298958
- Upsilon: "\u03A5",
298959
- upsilon: "\u03C5",
298960
- upsi: "\u03C5",
298961
- Upsi: "\u03D2",
298962
- upsih: "\u03D2",
298963
- Phi: "\u03A6",
298964
- phi: "\u03C6",
298965
- phiv: "\u03D5",
298966
- varphi: "\u03D5",
298967
- Chi: "\u03A7",
298968
- chi: "\u03C7",
298969
- Psi: "\u03A8",
298970
- psi: "\u03C8",
298971
- Omega: "\u03A9",
298972
- omega: "\u03C9",
298973
- ohm: "\u03A9",
298974
- Gammad: "\u03DC",
298975
- gammad: "\u03DD",
298976
- digamma: "\u03DD"
298977
- };
298978
- var CYRILLIC = {
298979
- Afr: "\u{1D504}",
298980
- afr: "\u{1D51E}",
298981
- Acy: "\u0410",
298982
- acy: "\u0430",
298983
- Bcy: "\u0411",
298984
- bcy: "\u0431",
298985
- Vcy: "\u0412",
298986
- vcy: "\u0432",
298987
- Gcy: "\u0413",
298988
- gcy: "\u0433",
298989
- Dcy: "\u0414",
298990
- dcy: "\u0434",
298991
- IEcy: "\u0415",
298992
- iecy: "\u0435",
298993
- IOcy: "\u0401",
298994
- iocy: "\u0451",
298995
- ZHcy: "\u0416",
298996
- zhcy: "\u0436",
298997
- Zcy: "\u0417",
298998
- zcy: "\u0437",
298999
- Icy: "\u0418",
299000
- icy: "\u0438",
299001
- Jcy: "\u0419",
299002
- jcy: "\u0439",
299003
- Kcy: "\u041A",
299004
- kcy: "\u043A",
299005
- Lcy: "\u041B",
299006
- lcy: "\u043B",
299007
- Mcy: "\u041C",
299008
- mcy: "\u043C",
299009
- Ncy: "\u041D",
299010
- ncy: "\u043D",
299011
- Ocy: "\u041E",
299012
- ocy: "\u043E",
299013
- Pcy: "\u041F",
299014
- pcy: "\u043F",
299015
- Rcy: "\u0420",
299016
- rcy: "\u0440",
299017
- Scy: "\u0421",
299018
- scy: "\u0441",
299019
- Tcy: "\u0422",
299020
- tcy: "\u0442",
299021
- Ucy: "\u0423",
299022
- ucy: "\u0443",
299023
- Fcy: "\u0424",
299024
- fcy: "\u0444",
299025
- KHcy: "\u0425",
299026
- khcy: "\u0445",
299027
- TScy: "\u0426",
299028
- tscy: "\u0446",
299029
- CHcy: "\u0427",
299030
- chcy: "\u0447",
299031
- SHcy: "\u0428",
299032
- shcy: "\u0448",
299033
- SHCHcy: "\u0429",
299034
- shchcy: "\u0449",
299035
- HARDcy: "\u042A",
299036
- hardcy: "\u044A",
299037
- Ycy: "\u042B",
299038
- ycy: "\u044B",
299039
- SOFTcy: "\u042C",
299040
- softcy: "\u044C",
299041
- Ecy: "\u042D",
299042
- ecy: "\u044D",
299043
- YUcy: "\u042E",
299044
- yucy: "\u044E",
299045
- YAcy: "\u042F",
299046
- yacy: "\u044F",
299047
- DJcy: "\u0402",
299048
- djcy: "\u0452",
299049
- GJcy: "\u0403",
299050
- gjcy: "\u0453",
299051
- Jukcy: "\u0404",
299052
- jukcy: "\u0454",
299053
- DScy: "\u0405",
299054
- dscy: "\u0455",
299055
- Iukcy: "\u0406",
299056
- iukcy: "\u0456",
299057
- YIcy: "\u0407",
299058
- yicy: "\u0457",
299059
- Jsercy: "\u0408",
299060
- jsercy: "\u0458",
299061
- LJcy: "\u0409",
299062
- ljcy: "\u0459",
299063
- NJcy: "\u040A",
299064
- njcy: "\u045A",
299065
- TSHcy: "\u040B",
299066
- tshcy: "\u045B",
299067
- KJcy: "\u040C",
299068
- kjcy: "\u045C",
299069
- Ubrcy: "\u040E",
299070
- ubrcy: "\u045E",
299071
- DZcy: "\u040F",
299072
- dzcy: "\u045F"
299073
- };
299074
- var MATH = {
299075
- plus: "+",
299076
- pm: "\xB1",
299077
- times: "\xD7",
299078
- div: "\xF7",
299079
- divide: "\xF7",
299080
- sdot: "\u22C5",
299081
- star: "\u2606",
299082
- starf: "\u2605",
299083
- bigstar: "\u2605",
299084
- lowast: "\u2217",
299085
- ast: "*",
299086
- midast: "*",
299087
- compfn: "\u2218",
299088
- smallcircle: "\u2218",
299089
- bullet: "\u2022",
299090
- bull: "\u2022",
299091
- nbsp: "\xA0",
299092
- hellip: "\u2026",
299093
- mldr: "\u2026",
299094
- prime: "\u2032",
299095
- Prime: "\u2033",
299096
- tprime: "\u2034",
299097
- bprime: "\u2035",
299098
- backprime: "\u2035",
299099
- minus: "\u2212",
299100
- minusd: "\u2238",
299101
- dotminus: "\u2238",
299102
- plusdo: "\u2214",
299103
- dotplus: "\u2214",
299104
- plusmn: "\xB1",
299105
- minusplus: "\u2213",
299106
- mnplus: "\u2213",
299107
- mp: "\u2213",
299108
- setminus: "\u2216",
299109
- smallsetminus: "\u2216",
299110
- Backslash: "\u2216",
299111
- setmn: "\u2216",
299112
- ssetmn: "\u2216",
299113
- lowbar: "_",
299114
- verbar: "|",
299115
- vert: "|",
299116
- VerticalLine: "|",
299117
- colon: ":",
299118
- Colon: "\u2237",
299119
- Proportion: "\u2237",
299120
- ratio: "\u2236",
299121
- equals: "=",
299122
- ne: "\u2260",
299123
- nequiv: "\u2262",
299124
- equiv: "\u2261",
299125
- Congruent: "\u2261",
299126
- sim: "\u223C",
299127
- thicksim: "\u223C",
299128
- thksim: "\u223C",
299129
- sime: "\u2243",
299130
- simeq: "\u2243",
299131
- TildeEqual: "\u2243",
299132
- asymp: "\u2248",
299133
- approx: "\u2248",
299134
- thickapprox: "\u2248",
299135
- thkap: "\u2248",
299136
- TildeTilde: "\u2248",
299137
- ncong: "\u2247",
299138
- cong: "\u2245",
299139
- TildeFullEqual: "\u2245",
299140
- asympeq: "\u224D",
299141
- CupCap: "\u224D",
299142
- bump: "\u224E",
299143
- Bumpeq: "\u224E",
299144
- HumpDownHump: "\u224E",
299145
- bumpe: "\u224F",
299146
- bumpeq: "\u224F",
299147
- HumpEqual: "\u224F",
299148
- le: "\u2264",
299149
- LessEqual: "\u2264",
299150
- ge: "\u2265",
299151
- GreaterEqual: "\u2265",
299152
- lesseqgtr: "\u22DA",
299153
- lesseqqgtr: "\u2A8B",
299154
- greater: ">",
299155
- less: "<"
299156
- };
299157
- var MATH_ADVANCED = {
299158
- alefsym: "\u2135",
299159
- aleph: "\u2135",
299160
- beth: "\u2136",
299161
- gimel: "\u2137",
299162
- daleth: "\u2138",
299163
- forall: "\u2200",
299164
- ForAll: "\u2200",
299165
- part: "\u2202",
299166
- PartialD: "\u2202",
299167
- exist: "\u2203",
299168
- Exists: "\u2203",
299169
- nexist: "\u2204",
299170
- nexists: "\u2204",
299171
- empty: "\u2205",
299172
- emptyset: "\u2205",
299173
- emptyv: "\u2205",
299174
- varnothing: "\u2205",
299175
- nabla: "\u2207",
299176
- Del: "\u2207",
299177
- isin: "\u2208",
299178
- isinv: "\u2208",
299179
- in: "\u2208",
299180
- Element: "\u2208",
299181
- notin: "\u2209",
299182
- notinva: "\u2209",
299183
- ni: "\u220B",
299184
- niv: "\u220B",
299185
- SuchThat: "\u220B",
299186
- ReverseElement: "\u220B",
299187
- notni: "\u220C",
299188
- notniva: "\u220C",
299189
- prod: "\u220F",
299190
- Product: "\u220F",
299191
- coprod: "\u2210",
299192
- Coproduct: "\u2210",
299193
- sum: "\u2211",
299194
- Sum: "\u2211",
299195
- minus: "\u2212",
299196
- mp: "\u2213",
299197
- plusdo: "\u2214",
299198
- dotplus: "\u2214",
299199
- setminus: "\u2216",
299200
- lowast: "\u2217",
299201
- radic: "\u221A",
299202
- Sqrt: "\u221A",
299203
- prop: "\u221D",
299204
- propto: "\u221D",
299205
- Proportional: "\u221D",
299206
- varpropto: "\u221D",
299207
- infin: "\u221E",
299208
- infintie: "\u29DD",
299209
- ang: "\u2220",
299210
- angle: "\u2220",
299211
- angmsd: "\u2221",
299212
- measuredangle: "\u2221",
299213
- angsph: "\u2222",
299214
- mid: "\u2223",
299215
- VerticalBar: "\u2223",
299216
- nmid: "\u2224",
299217
- nsmid: "\u2224",
299218
- npar: "\u2226",
299219
- parallel: "\u2225",
299220
- spar: "\u2225",
299221
- nparallel: "\u2226",
299222
- nspar: "\u2226",
299223
- and: "\u2227",
299224
- wedge: "\u2227",
299225
- or: "\u2228",
299226
- vee: "\u2228",
299227
- cap: "\u2229",
299228
- cup: "\u222A",
299229
- int: "\u222B",
299230
- Integral: "\u222B",
299231
- conint: "\u222E",
299232
- ContourIntegral: "\u222E",
299233
- Conint: "\u222F",
299234
- DoubleContourIntegral: "\u222F",
299235
- Cconint: "\u2230",
299236
- there4: "\u2234",
299237
- therefore: "\u2234",
299238
- Therefore: "\u2234",
299239
- becaus: "\u2235",
299240
- because: "\u2235",
299241
- Because: "\u2235",
299242
- ratio: "\u2236",
299243
- Proportion: "\u2237",
299244
- minusd: "\u2238",
299245
- dotminus: "\u2238",
299246
- mDDot: "\u223A",
299247
- homtht: "\u223B",
299248
- sim: "\u223C",
299249
- bsimg: "\u223D",
299250
- backsim: "\u223D",
299251
- ac: "\u223E",
299252
- mstpos: "\u223E",
299253
- acd: "\u223F",
299254
- VerticalTilde: "\u2240",
299255
- wr: "\u2240",
299256
- wreath: "\u2240",
299257
- nsime: "\u2244",
299258
- nsimeq: "\u2244",
299259
- ncong: "\u2247",
299260
- simne: "\u2246",
299261
- ncongdot: "\u2A6D\u0338",
299262
- ngsim: "\u2275",
299263
- nsim: "\u2241",
299264
- napprox: "\u2249",
299265
- nap: "\u2249",
299266
- ngeq: "\u2271",
299267
- nge: "\u2271",
299268
- nleq: "\u2270",
299269
- nle: "\u2270",
299270
- ngtr: "\u226F",
299271
- ngt: "\u226F",
299272
- nless: "\u226E",
299273
- nlt: "\u226E",
299274
- nprec: "\u2280",
299275
- npr: "\u2280",
299276
- nsucc: "\u2281",
299277
- nsc: "\u2281"
299278
- };
299279
- var ARROWS = {
299280
- larr: "\u2190",
299281
- leftarrow: "\u2190",
299282
- LeftArrow: "\u2190",
299283
- uarr: "\u2191",
299284
- uparrow: "\u2191",
299285
- UpArrow: "\u2191",
299286
- rarr: "\u2192",
299287
- rightarrow: "\u2192",
299288
- RightArrow: "\u2192",
299289
- darr: "\u2193",
299290
- downarrow: "\u2193",
299291
- DownArrow: "\u2193",
299292
- harr: "\u2194",
299293
- leftrightarrow: "\u2194",
299294
- LeftRightArrow: "\u2194",
299295
- varr: "\u2195",
299296
- updownarrow: "\u2195",
299297
- UpDownArrow: "\u2195",
299298
- nwarr: "\u2196",
299299
- nwarrow: "\u2196",
299300
- UpperLeftArrow: "\u2196",
299301
- nearr: "\u2197",
299302
- nearrow: "\u2197",
299303
- UpperRightArrow: "\u2197",
299304
- searr: "\u2198",
299305
- searrow: "\u2198",
299306
- LowerRightArrow: "\u2198",
299307
- swarr: "\u2199",
299308
- swarrow: "\u2199",
299309
- LowerLeftArrow: "\u2199",
299310
- lArr: "\u21D0",
299311
- Leftarrow: "\u21D0",
299312
- uArr: "\u21D1",
299313
- Uparrow: "\u21D1",
299314
- rArr: "\u21D2",
299315
- Rightarrow: "\u21D2",
299316
- dArr: "\u21D3",
299317
- Downarrow: "\u21D3",
299318
- hArr: "\u21D4",
299319
- Leftrightarrow: "\u21D4",
299320
- iff: "\u21D4",
299321
- vArr: "\u21D5",
299322
- Updownarrow: "\u21D5",
299323
- lAarr: "\u21DA",
299324
- Lleftarrow: "\u21DA",
299325
- rAarr: "\u21DB",
299326
- Rrightarrow: "\u21DB",
299327
- lrarr: "\u21C6",
299328
- leftrightarrows: "\u21C6",
299329
- rlarr: "\u21C4",
299330
- rightleftarrows: "\u21C4",
299331
- lrhar: "\u21CB",
299332
- leftrightharpoons: "\u21CB",
299333
- ReverseEquilibrium: "\u21CB",
299334
- rlhar: "\u21CC",
299335
- rightleftharpoons: "\u21CC",
299336
- Equilibrium: "\u21CC",
299337
- udarr: "\u21C5",
299338
- UpArrowDownArrow: "\u21C5",
299339
- duarr: "\u21F5",
299340
- DownArrowUpArrow: "\u21F5",
299341
- llarr: "\u21C7",
299342
- leftleftarrows: "\u21C7",
299343
- rrarr: "\u21C9",
299344
- rightrightarrows: "\u21C9",
299345
- ddarr: "\u21CA",
299346
- downdownarrows: "\u21CA",
299347
- har: "\u21BD",
299348
- lhard: "\u21BD",
299349
- leftharpoondown: "\u21BD",
299350
- lharu: "\u21BC",
299351
- leftharpoonup: "\u21BC",
299352
- rhard: "\u21C1",
299353
- rightharpoondown: "\u21C1",
299354
- rharu: "\u21C0",
299355
- rightharpoonup: "\u21C0",
299356
- lsh: "\u21B0",
299357
- Lsh: "\u21B0",
299358
- rsh: "\u21B1",
299359
- Rsh: "\u21B1",
299360
- ldsh: "\u21B2",
299361
- rdsh: "\u21B3",
299362
- hookleftarrow: "\u21A9",
299363
- hookrightarrow: "\u21AA",
299364
- mapstoleft: "\u21A4",
299365
- mapstoup: "\u21A5",
299366
- map: "\u21A6",
299367
- mapsto: "\u21A6",
299368
- mapstodown: "\u21A7",
299369
- crarr: "\u21B5",
299370
- nleftarrow: "\u219A",
299371
- nleftrightarrow: "\u21AE",
299372
- nrightarrow: "\u219B",
299373
- nrarr: "\u219B",
299374
- larrtl: "\u21A2",
299375
- rarrtl: "\u21A3",
299376
- leftarrowtail: "\u21A2",
299377
- rightarrowtail: "\u21A3",
299378
- twoheadleftarrow: "\u219E",
299379
- twoheadrightarrow: "\u21A0",
299380
- Larr: "\u219E",
299381
- Rarr: "\u21A0",
299382
- larrhk: "\u21A9",
299383
- rarrhk: "\u21AA",
299384
- larrlp: "\u21AB",
299385
- looparrowleft: "\u21AB",
299386
- rarrlp: "\u21AC",
299387
- looparrowright: "\u21AC",
299388
- harrw: "\u21AD",
299389
- leftrightsquigarrow: "\u21AD",
299390
- nrarrw: "\u219D\u0338",
299391
- rarrw: "\u219D",
299392
- rightsquigarrow: "\u219D",
299393
- larrbfs: "\u291F",
299394
- rarrbfs: "\u2920",
299395
- nvHarr: "\u2904",
299396
- nvlArr: "\u2902",
299397
- nvrArr: "\u2903",
299398
- larrfs: "\u291D",
299399
- rarrfs: "\u291E",
299400
- Map: "\u2905",
299401
- larrsim: "\u2973",
299402
- rarrsim: "\u2974",
299403
- harrcir: "\u2948",
299404
- Uarrocir: "\u2949",
299405
- lurdshar: "\u294A",
299406
- ldrdhar: "\u2967",
299407
- ldrushar: "\u294B",
299408
- rdldhar: "\u2969",
299409
- lrhard: "\u296D",
299410
- uharr: "\u21BE",
299411
- uharl: "\u21BF",
299412
- dharr: "\u21C2",
299413
- dharl: "\u21C3",
299414
- Uarr: "\u219F",
299415
- Darr: "\u21A1",
299416
- zigrarr: "\u21DD",
299417
- nwArr: "\u21D6",
299418
- neArr: "\u21D7",
299419
- seArr: "\u21D8",
299420
- swArr: "\u21D9",
299421
- nharr: "\u21AE",
299422
- nhArr: "\u21CE",
299423
- nlarr: "\u219A",
299424
- nlArr: "\u21CD",
299425
- nrArr: "\u21CF",
299426
- larrb: "\u21E4",
299427
- LeftArrowBar: "\u21E4",
299428
- rarrb: "\u21E5",
299429
- RightArrowBar: "\u21E5"
299430
- };
299431
- var SHAPES = {
299432
- square: "\u25A1",
299433
- Square: "\u25A1",
299434
- squ: "\u25A1",
299435
- squf: "\u25AA",
299436
- squarf: "\u25AA",
299437
- blacksquar: "\u25AA",
299438
- blacksquare: "\u25AA",
299439
- FilledVerySmallSquare: "\u25AA",
299440
- blk34: "\u2593",
299441
- blk12: "\u2592",
299442
- blk14: "\u2591",
299443
- block: "\u2588",
299444
- srect: "\u25AD",
299445
- rect: "\u25AD",
299446
- sdot: "\u22C5",
299447
- sdotb: "\u22A1",
299448
- dotsquare: "\u22A1",
299449
- triangle: "\u25B5",
299450
- tri: "\u25B5",
299451
- trine: "\u25B5",
299452
- utri: "\u25B5",
299453
- triangledown: "\u25BF",
299454
- dtri: "\u25BF",
299455
- tridown: "\u25BF",
299456
- triangleleft: "\u25C3",
299457
- ltri: "\u25C3",
299458
- triangleright: "\u25B9",
299459
- rtri: "\u25B9",
299460
- blacktriangle: "\u25B4",
299461
- utrif: "\u25B4",
299462
- blacktriangledown: "\u25BE",
299463
- dtrif: "\u25BE",
299464
- blacktriangleleft: "\u25C2",
299465
- ltrif: "\u25C2",
299466
- blacktriangleright: "\u25B8",
299467
- rtrif: "\u25B8",
299468
- loz: "\u25CA",
299469
- lozenge: "\u25CA",
299470
- blacklozenge: "\u29EB",
299471
- lozf: "\u29EB",
299472
- bigcirc: "\u25EF",
299473
- xcirc: "\u25EF",
299474
- circ: "\u02C6",
299475
- Circle: "\u25CB",
299476
- cir: "\u25CB",
299477
- o: "\u25CB",
299478
- bullet: "\u2022",
299479
- bull: "\u2022",
299480
- hellip: "\u2026",
299481
- mldr: "\u2026",
299482
- nldr: "\u2025",
299483
- boxh: "\u2500",
299484
- HorizontalLine: "\u2500",
299485
- boxv: "\u2502",
299486
- boxdr: "\u250C",
299487
- boxdl: "\u2510",
299488
- boxur: "\u2514",
299489
- boxul: "\u2518",
299490
- boxvr: "\u251C",
299491
- boxvl: "\u2524",
299492
- boxhd: "\u252C",
299493
- boxhu: "\u2534",
299494
- boxvh: "\u253C",
299495
- boxH: "\u2550",
299496
- boxV: "\u2551",
299497
- boxdR: "\u2552",
299498
- boxDr: "\u2553",
299499
- boxDR: "\u2554",
299500
- boxDl: "\u2555",
299501
- boxdL: "\u2556",
299502
- boxDL: "\u2557",
299503
- boxuR: "\u2558",
299504
- boxUr: "\u2559",
299505
- boxUR: "\u255A",
299506
- boxUl: "\u255C",
299507
- boxuL: "\u255B",
299508
- boxUL: "\u255D",
299509
- boxvR: "\u255E",
299510
- boxVr: "\u255F",
299511
- boxVR: "\u2560",
299512
- boxVl: "\u2562",
299513
- boxvL: "\u2561",
299514
- boxVL: "\u2563",
299515
- boxHd: "\u2564",
299516
- boxhD: "\u2565",
299517
- boxHD: "\u2566",
299518
- boxHu: "\u2567",
299519
- boxhU: "\u2568",
299520
- boxHU: "\u2569",
299521
- boxvH: "\u256A",
299522
- boxVh: "\u256B",
299523
- boxVH: "\u256C"
299524
- };
299525
- var PUNCTUATION = {
299526
- excl: "!",
299527
- iexcl: "\xA1",
299528
- brvbar: "\xA6",
299529
- sect: "\xA7",
299530
- uml: "\xA8",
299531
- copy: "\xA9",
299532
- ordf: "\xAA",
299533
- laquo: "\xAB",
299534
- not: "\xAC",
299535
- shy: "\xAD",
299536
- reg: "\xAE",
299537
- macr: "\xAF",
299538
- deg: "\xB0",
299539
- plusmn: "\xB1",
299540
- sup2: "\xB2",
299541
- sup3: "\xB3",
299542
- acute: "\xB4",
299543
- micro: "\xB5",
299544
- para: "\xB6",
299545
- middot: "\xB7",
299546
- cedil: "\xB8",
299547
- sup1: "\xB9",
299548
- ordm: "\xBA",
299549
- raquo: "\xBB",
299550
- frac14: "\xBC",
299551
- frac12: "\xBD",
299552
- frac34: "\xBE",
299553
- iquest: "\xBF",
299554
- nbsp: "\xA0",
299555
- comma: ",",
299556
- period: ".",
299557
- colon: ":",
299558
- semi: ";",
299559
- vert: "|",
299560
- Verbar: "\u2016",
299561
- verbar: "|",
299562
- dblac: "\u02DD",
299563
- circ: "\u02C6",
299564
- caron: "\u02C7",
299565
- breve: "\u02D8",
299566
- dot: "\u02D9",
299567
- ring: "\u02DA",
299568
- ogon: "\u02DB",
299569
- tilde: "\u02DC",
299570
- DiacriticalGrave: "`",
299571
- DiacriticalAcute: "\xB4",
299572
- DiacriticalTilde: "\u02DC",
299573
- DiacriticalDot: "\u02D9",
299574
- DiacriticalDoubleAcute: "\u02DD",
299575
- grave: "`"
299576
- };
299577
299416
  var CURRENCY = {
299578
299417
  cent: "\xA2",
299579
299418
  pound: "\xA3",
@@ -299591,106 +299430,6 @@ var CURRENCY = {
299591
299430
  yuan: "\xA5",
299592
299431
  cedil: "\xB8"
299593
299432
  };
299594
- var FRACTIONS = {
299595
- frac12: "\xBD",
299596
- half: "\xBD",
299597
- frac13: "\u2153",
299598
- frac14: "\xBC",
299599
- frac15: "\u2155",
299600
- frac16: "\u2159",
299601
- frac18: "\u215B",
299602
- frac23: "\u2154",
299603
- frac25: "\u2156",
299604
- frac34: "\xBE",
299605
- frac35: "\u2157",
299606
- frac38: "\u215C",
299607
- frac45: "\u2158",
299608
- frac56: "\u215A",
299609
- frac58: "\u215D",
299610
- frac78: "\u215E",
299611
- frasl: "\u2044"
299612
- };
299613
- var MISC_SYMBOLS = {
299614
- trade: "\u2122",
299615
- TRADE: "\u2122",
299616
- telrec: "\u2315",
299617
- target: "\u2316",
299618
- ulcorn: "\u231C",
299619
- ulcorner: "\u231C",
299620
- urcorn: "\u231D",
299621
- urcorner: "\u231D",
299622
- dlcorn: "\u231E",
299623
- llcorner: "\u231E",
299624
- drcorn: "\u231F",
299625
- lrcorner: "\u231F",
299626
- intercal: "\u22BA",
299627
- intcal: "\u22BA",
299628
- oplus: "\u2295",
299629
- CirclePlus: "\u2295",
299630
- ominus: "\u2296",
299631
- CircleMinus: "\u2296",
299632
- otimes: "\u2297",
299633
- CircleTimes: "\u2297",
299634
- osol: "\u2298",
299635
- odot: "\u2299",
299636
- CircleDot: "\u2299",
299637
- oast: "\u229B",
299638
- circledast: "\u229B",
299639
- odash: "\u229D",
299640
- circleddash: "\u229D",
299641
- ocirc: "\u229A",
299642
- circledcirc: "\u229A",
299643
- boxplus: "\u229E",
299644
- plusb: "\u229E",
299645
- boxminus: "\u229F",
299646
- minusb: "\u229F",
299647
- boxtimes: "\u22A0",
299648
- timesb: "\u22A0",
299649
- boxdot: "\u22A1",
299650
- sdotb: "\u22A1",
299651
- veebar: "\u22BB",
299652
- vee: "\u2228",
299653
- barvee: "\u22BD",
299654
- and: "\u2227",
299655
- wedge: "\u2227",
299656
- Cap: "\u22D2",
299657
- Cup: "\u22D3",
299658
- Fork: "\u22D4",
299659
- pitchfork: "\u22D4",
299660
- epar: "\u22D5",
299661
- ltlarr: "\u2976",
299662
- nvap: "\u224D\u20D2",
299663
- nvsim: "\u223C\u20D2",
299664
- nvge: "\u2265\u20D2",
299665
- nvle: "\u2264\u20D2",
299666
- nvlt: "<\u20D2",
299667
- nvgt: ">\u20D2",
299668
- nvltrie: "\u22B4\u20D2",
299669
- nvrtrie: "\u22B5\u20D2",
299670
- Vdash: "\u22A9",
299671
- dashv: "\u22A3",
299672
- vDash: "\u22A8",
299673
- Vvdash: "\u22AA",
299674
- nvdash: "\u22AC",
299675
- nvDash: "\u22AD",
299676
- nVdash: "\u22AE",
299677
- nVDash: "\u22AF"
299678
- };
299679
- var ALL_ENTITIES = {
299680
- ...BASIC_LATIN,
299681
- ...LATIN_ACCENTS,
299682
- ...LATIN_EXTENDED,
299683
- ...GREEK,
299684
- ...CYRILLIC,
299685
- ...MATH,
299686
- ...MATH_ADVANCED,
299687
- ...ARROWS,
299688
- ...SHAPES,
299689
- ...PUNCTUATION,
299690
- ...CURRENCY,
299691
- ...FRACTIONS,
299692
- ...MISC_SYMBOLS
299693
- };
299694
299433
  var XML = {
299695
299434
  amp: "&",
299696
299435
  apos: "'",
@@ -300334,7 +300073,7 @@ var XmlNode = class {
300334
300073
  }
300335
300074
  };
300336
300075
 
300337
- // node_modules/xml-naming/src/index.js
300076
+ // node_modules/fast-xml-parser/node_modules/xml-naming/src/index.js
300338
300077
  var nameStartChar10 = ":A-Za-z_\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0370-\u037D\u037F-\u0486\u0488-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD";
300339
300078
  var nameChar10 = nameStartChar10 + "\\-\\.\\d\xB7\u0300-\u036F\u203F-\u2040";
300340
300079
  var nameStartChar11 = ":A-Za-z_\xC0-\u02FF\u0370-\u037D\u037F-\u0486\u0488-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u{10000}-\u{EFFFF}";
@@ -300353,8 +300092,14 @@ var buildRegexes = (startChar, char, flags = "") => {
300353
300092
  };
300354
300093
  var regexes10 = buildRegexes(nameStartChar10, nameChar10);
300355
300094
  var regexes11 = buildRegexes(nameStartChar11, nameChar11, "u");
300356
- var getRegexes = (xmlVersion = "1.0") => xmlVersion === "1.1" ? regexes11 : regexes10;
300357
- var qName = (str, { xmlVersion = "1.0" } = {}) => getRegexes(xmlVersion).qName.test(str);
300095
+ var nameStartCharAscii = ":A-Za-z_";
300096
+ var nameCharAscii = nameStartCharAscii + "\\-\\.\\d";
300097
+ var regexesAscii = buildRegexes(nameStartCharAscii, nameCharAscii);
300098
+ var getRegexes = (xmlVersion = "1.0", asciiOnly = false) => {
300099
+ if (asciiOnly) return regexesAscii;
300100
+ return xmlVersion === "1.1" ? regexes11 : regexes10;
300101
+ };
300102
+ var qName = (str, { xmlVersion = "1.0", asciiOnly = false } = {}) => getRegexes(xmlVersion, asciiOnly).qName.test(str);
300358
300103
 
300359
300104
  // node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js
300360
300105
  var DocTypeReader = class {
@@ -301516,17 +301261,16 @@ var Matcher = class {
301516
301261
  this.path[this.path.length - 1].values = void 0;
301517
301262
  }
301518
301263
  const currentLevel = this.path.length;
301519
- if (!this.siblingStacks[currentLevel]) {
301520
- this.siblingStacks[currentLevel] = /* @__PURE__ */ new Map();
301264
+ let level = this.siblingStacks[currentLevel];
301265
+ if (!level) {
301266
+ level = { counts: /* @__PURE__ */ new Map(), total: 0 };
301267
+ this.siblingStacks[currentLevel] = level;
301521
301268
  }
301522
- const siblings = this.siblingStacks[currentLevel];
301523
301269
  const siblingKey = namespace ? `${namespace}:${tagName}` : tagName;
301524
- const counter = siblings.get(siblingKey) || 0;
301525
- let position = 0;
301526
- for (const count of siblings.values()) {
301527
- position += count;
301528
- }
301529
- siblings.set(siblingKey, counter + 1);
301270
+ const counter = level.counts.get(siblingKey) || 0;
301271
+ const position = level.total;
301272
+ level.counts.set(siblingKey, counter + 1);
301273
+ level.total++;
301530
301274
  const node = {
301531
301275
  tag: tagName,
301532
301276
  position,
@@ -301835,7 +301579,7 @@ var Matcher = class {
301835
301579
  snapshot() {
301836
301580
  return {
301837
301581
  path: this.path.map((node) => ({ ...node })),
301838
- siblingStacks: this.siblingStacks.map((map) => new Map(map)),
301582
+ siblingStacks: this.siblingStacks.map((level) => level ? { counts: new Map(level.counts), total: level.total } : level),
301839
301583
  keptAttrs: this._keptAttrs.map((entry) => ({ ...entry }))
301840
301584
  };
301841
301585
  }
@@ -301846,7 +301590,7 @@ var Matcher = class {
301846
301590
  restore(snapshot) {
301847
301591
  this._pathStringCache = null;
301848
301592
  this.path = snapshot.path.map((node) => ({ ...node }));
301849
- this.siblingStacks = snapshot.siblingStacks.map((map) => new Map(map));
301593
+ this.siblingStacks = snapshot.siblingStacks.map((level) => level ? { counts: new Map(level.counts), total: level.total } : level);
301850
301594
  this._keptAttrs = (snapshot.keptAttrs || []).map((entry) => ({ ...entry }));
301851
301595
  }
301852
301596
  /**
@@ -302184,27 +301928,6 @@ var SQL_PATTERNS = [
302184
301928
  ];
302185
301929
  var sql_default = SQL_PATTERNS;
302186
301930
 
302187
- // node_modules/is-unsafe/src/contexts/sql-strict.js
302188
- var SQL_STRICT_EXTRA = [
302189
- {
302190
- id: "sql-line-comment",
302191
- description: "SQL line comment: -- followed by whitespace or end of string",
302192
- pattern: /--(?:\s|$)/
302193
- },
302194
- {
302195
- id: "sql-stacked-query",
302196
- description: "Stacked queries: semicolon immediately followed by a SQL keyword",
302197
- pattern: /;\s{0,10}(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC)\b/i
302198
- },
302199
- {
302200
- id: "sql-hex-encoding",
302201
- description: "Hex-encoded string injection: 0x41414141 style (MySQL)",
302202
- pattern: /\b0x[0-9a-f]{4,}/i
302203
- }
302204
- ];
302205
- var SQL_STRICT_PATTERNS = [...sql_default, ...SQL_STRICT_EXTRA];
302206
- var sql_strict_default = SQL_STRICT_PATTERNS;
302207
-
302208
301931
  // node_modules/is-unsafe/src/contexts/shell.js
302209
301932
  var SHELL_PATTERNS = [
302210
301933
  {
@@ -302516,8 +302239,38 @@ var LOG_PATTERNS = [
302516
302239
  ];
302517
302240
  var log_default = LOG_PATTERNS;
302518
302241
 
302519
- // node_modules/is-unsafe/src/registry.js
302520
- var CONTEXT_REGISTRY = {
302242
+ // node_modules/is-unsafe/src/contexts/sql-strict.js
302243
+ var SQL_STRICT_EXTRA = [
302244
+ {
302245
+ id: "sql-line-comment",
302246
+ description: "SQL line comment: -- followed by whitespace or end of string",
302247
+ pattern: /--(?:\s|$)/
302248
+ },
302249
+ {
302250
+ id: "sql-stacked-query",
302251
+ description: "Stacked queries: semicolon immediately followed by a SQL keyword",
302252
+ pattern: /;\s{0,10}(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC)\b/i
302253
+ },
302254
+ {
302255
+ id: "sql-hex-encoding",
302256
+ description: "Hex-encoded string injection: 0x41414141 style (MySQL)",
302257
+ pattern: /\b0x[0-9a-f]{4,}/i
302258
+ }
302259
+ ];
302260
+ var SQL_STRICT_PATTERNS = [...sql_default, ...SQL_STRICT_EXTRA];
302261
+ var sql_strict_default = SQL_STRICT_PATTERNS;
302262
+
302263
+ // node_modules/is-unsafe/src/index.js
302264
+ html_default.label = "HTML";
302265
+ xml_default.label = "XML";
302266
+ svg_default.label = "SVG";
302267
+ sql_default.label = "SQL";
302268
+ sql_strict_default.label = "SQL-STRICT";
302269
+ shell_default.label = "SHELL";
302270
+ redos_default.label = "REDOS";
302271
+ nosql_default.label = "NOSQL";
302272
+ log_default.label = "LOG";
302273
+ var VALID_CONTEXTS = Object.freeze({
302521
302274
  HTML: html_default,
302522
302275
  XML: xml_default,
302523
302276
  SVG: svg_default,
@@ -302527,13 +302280,7 @@ var CONTEXT_REGISTRY = {
302527
302280
  REDOS: redos_default,
302528
302281
  NOSQL: nosql_default,
302529
302282
  LOG: log_default
302530
- };
302531
- var registry_default = CONTEXT_REGISTRY;
302532
- var VALID_CONTEXTS = Object.freeze(
302533
- Object.fromEntries(Object.keys(CONTEXT_REGISTRY).map((k) => [k, k]))
302534
- );
302535
-
302536
- // node_modules/is-unsafe/src/index.js
302283
+ });
302537
302284
  function assertString(value) {
302538
302285
  if (typeof value !== "string") {
302539
302286
  throw new TypeError(
@@ -302543,36 +302290,35 @@ function assertString(value) {
302543
302290
  }
302544
302291
  function assertContext(context) {
302545
302292
  if (context instanceof RegExp) return;
302546
- if (typeof context === "string") {
302547
- if (!registry_default[context]) {
302548
- throw new TypeError(
302549
- `is-unsafe: unknown context "${context}". Valid contexts: ${Object.keys(VALID_CONTEXTS).join(", ")}`
302550
- );
302551
- }
302552
- return;
302553
- }
302554
302293
  if (Array.isArray(context)) {
302555
302294
  if (context.length === 0) {
302556
- throw new TypeError("is-unsafe: context array must not be empty");
302295
+ throw new TypeError("is-unsafe: context must not be an empty array");
302557
302296
  }
302558
- for (const c of context) {
302559
- if (typeof c !== "string" || !registry_default[c]) {
302560
- throw new TypeError(
302561
- `is-unsafe: unknown context "${c}" in array. Valid contexts: ${Object.keys(VALID_CONTEXTS).join(", ")}`
302562
- );
302297
+ if (Array.isArray(context[0])) {
302298
+ for (const list of context) {
302299
+ if (!Array.isArray(list) || list.length === 0) {
302300
+ throw new TypeError(
302301
+ "is-unsafe: each context in the array must be a non-empty pattern array (PatternList)"
302302
+ );
302303
+ }
302563
302304
  }
302564
302305
  }
302565
302306
  return;
302566
302307
  }
302567
302308
  throw new TypeError(
302568
- `is-unsafe: second argument must be a context string, array of context strings, or RegExp. Got: ${typeof context}`
302309
+ `is-unsafe: second argument must be a PatternList (e.g. HTML), an array of PatternLists (e.g. [HTML, XML]), or a RegExp. Got: ${typeof context}`
302569
302310
  );
302570
302311
  }
302571
- function matchContext(value, contextName) {
302572
- const patterns = registry_default[contextName];
302573
- for (const rule of patterns) {
302312
+ function normalise(context) {
302313
+ if (context instanceof RegExp) return { lists: null, regex: context };
302314
+ if (Array.isArray(context[0])) return { lists: context, regex: null };
302315
+ return { lists: [context], regex: null };
302316
+ }
302317
+ function matchList(value, list) {
302318
+ const label = list.label ?? "CUSTOM";
302319
+ for (const rule of list) {
302574
302320
  if (rule.pattern.test(value)) {
302575
- return { context: contextName, id: rule.id, description: rule.description, pattern: rule.pattern };
302321
+ return { context: label, id: rule.id, description: rule.description, pattern: rule.pattern };
302576
302322
  }
302577
302323
  }
302578
302324
  return null;
@@ -302580,14 +302326,10 @@ function matchContext(value, contextName) {
302580
302326
  function isUnsafe(value, context) {
302581
302327
  assertString(value);
302582
302328
  assertContext(context);
302583
- if (context instanceof RegExp) {
302584
- return context.test(value);
302585
- }
302586
- if (typeof context === "string") {
302587
- return matchContext(value, context) !== null;
302588
- }
302589
- for (const c of context) {
302590
- if (matchContext(value, c) !== null) return true;
302329
+ const { lists, regex } = normalise(context);
302330
+ if (regex) return regex.test(value);
302331
+ for (const list of lists) {
302332
+ if (matchList(value, list) !== null) return true;
302591
302333
  }
302592
302334
  return false;
302593
302335
  }
@@ -302636,6 +302378,7 @@ var OrderedObjParser = class {
302636
302378
  this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes);
302637
302379
  this.entityExpansionCount = 0;
302638
302380
  this.currentExpandedLength = 0;
302381
+ this.doctypefound = false;
302639
302382
  let namedEntities = { ...XML };
302640
302383
  if (this.options.entityDecoder) {
302641
302384
  this.entityDecoder = this.options.entityDecoder;
@@ -302653,7 +302396,7 @@ var OrderedObjParser = class {
302653
302396
  // onExternalEntity: (name, value) => isUnsafe(value) ? 'block' : 'allow',
302654
302397
  onInputEntity: (name, value) => (
302655
302398
  //TODO: VALID_CONTEXTS.HTML should be set only if this.options.htmlEntities
302656
- isUnsafe(value, [VALID_CONTEXTS.HTML, VALID_CONTEXTS.XML]) ? ENTITY_ACTION.BLOCK : ENTITY_ACTION.ALLOW
302399
+ isUnsafe(value, [html_default, xml_default]) ? ENTITY_ACTION.BLOCK : ENTITY_ACTION.ALLOW
302657
302400
  )
302658
302401
  //postCheck: resolved => resolved
302659
302402
  });
@@ -302787,6 +302530,7 @@ var parseXml = function(xmlData) {
302787
302530
  this.entityDecoder.reset();
302788
302531
  this.entityExpansionCount = 0;
302789
302532
  this.currentExpandedLength = 0;
302533
+ this.doctypefound = false;
302790
302534
  const options = this.options;
302791
302535
  const docTypeReader = new DocTypeReader(options.processEntities);
302792
302536
  const xmlLen = xmlData.length;
@@ -302849,6 +302593,8 @@ var parseXml = function(xmlData) {
302849
302593
  }
302850
302594
  i = endIndex;
302851
302595
  } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 68) {
302596
+ if (this.doctypefound) throw new Error("Multiple DOCTYPE declarations found.");
302597
+ this.doctypefound = true;
302852
302598
  const result = docTypeReader.readDocType(xmlData, i);
302853
302599
  this.entityDecoder.addInputEntities(result.entities);
302854
302600
  i = result.i;
@@ -305440,7 +305186,7 @@ function parseWsdl(content, opts) {
305440
305186
  }
305441
305187
 
305442
305188
  // src/lib/protocols/soap/builder.ts
305443
- var import_node_crypto4 = require("node:crypto");
305189
+ var import_node_crypto5 = require("node:crypto");
305444
305190
  var COLLECTION_V210_SCHEMA2 = "https://schema.getpostman.com/json/collection/v2.1.0/collection.json";
305445
305191
  var SOAP11_ENVELOPE_NS = "http://schemas.xmlsoap.org/soap/envelope/";
305446
305192
  var SOAP12_ENVELOPE_NS = "http://www.w3.org/2003/05/soap-envelope";
@@ -305448,7 +305194,7 @@ var SOAP11_CONTENT_TYPE = "text/xml; charset=UTF-8";
305448
305194
  var SOAP12_CONTENT_TYPE = "application/soap+xml; charset=UTF-8";
305449
305195
  var WSA_NS = "http://www.w3.org/2005/08/addressing";
305450
305196
  function stableId2(seed) {
305451
- return (0, import_node_crypto4.createHash)("sha256").update(seed).digest("hex").slice(0, 32);
305197
+ return (0, import_node_crypto5.createHash)("sha256").update(seed).digest("hex").slice(0, 32);
305452
305198
  }
305453
305199
  function envelopeNamespace(version) {
305454
305200
  return version === "1.2" ? SOAP12_ENVELOPE_NS : SOAP11_ENVELOPE_NS;
@@ -312211,6 +311957,11 @@ function resolveInputs(env = process.env) {
312211
311957
  ),
312212
311958
  protocolEndpointUrl: getInput2("protocol-endpoint-url", env),
312213
311959
  openapiVersion: resolveOpenapiVersion(getInput2("openapi-version", env)),
311960
+ preserveOas30TypeNull: parseBooleanInput(
311961
+ "preserve-oas30-type-null",
311962
+ getInput2("preserve-oas30-type-null", env),
311963
+ false
311964
+ ),
312214
311965
  breakingChangeMode: parseBreakingChangeMode(getInput2("breaking-change-mode", env)),
312215
311966
  breakingBaselineSpecPath: getInput2("breaking-baseline-spec-path", env),
312216
311967
  breakingRulesPath: getInput2("breaking-rules-path", env) ?? bootstrapActionContract.inputs["breaking-rules-path"].default,
@@ -312218,8 +311969,8 @@ function resolveInputs(env = process.env) {
312218
311969
  breakingSummaryPath: getInput2("breaking-summary-path", env),
312219
311970
  breakingLogPath: getInput2("breaking-log-path", env),
312220
311971
  governanceMappingJson: parseGovernanceMappingJson(getInput2("governance-mapping-json", env)),
312221
- postmanApiKey: getInput2("postman-api-key", env) ?? "",
312222
- postmanAccessToken: getInput2("postman-access-token", env),
311972
+ postmanApiKey: getInput2("postman-api-key", env) || env.POSTMAN_API_KEY || "",
311973
+ postmanAccessToken: getInput2("postman-access-token", env) || env.POSTMAN_ACCESS_TOKEN,
312223
311974
  credentialPreflight: parseEnumInput(
312224
311975
  "credential-preflight",
312225
311976
  getInput2("credential-preflight", env),
@@ -312241,9 +311992,72 @@ function resolveInputs(env = process.env) {
312241
311992
  githubRef: env.GITHUB_REF,
312242
311993
  githubSha: env.GITHUB_SHA,
312243
311994
  githubToken: getInput2("github-token", env) || env.GITHUB_TOKEN || "",
312244
- ghFallbackToken: getInput2("gh-fallback-token", env) || env.GH_FALLBACK_TOKEN || ""
311995
+ ghFallbackToken: getInput2("gh-fallback-token", env) || env.GH_FALLBACK_TOKEN || "",
311996
+ branchStrategy: parseEnumInput(
311997
+ "branch-strategy",
311998
+ getInput2("branch-strategy", env),
311999
+ "legacy"
312000
+ ),
312001
+ canonicalBranch: getInput2("canonical-branch", env),
312002
+ channels: getInput2("channels", env)
312245
312003
  };
312246
312004
  }
312005
+ function decideBranchTier(inputs, env = process.env) {
312006
+ return resolveEffectiveBranchDecision(
312007
+ {
312008
+ // Tolerate hand-built inputs objects (tests, embedders) that omit the
312009
+ // field: absent means legacy, exactly like the action default.
312010
+ strategy: inputs.branchStrategy ?? "legacy",
312011
+ identity: resolveBranchIdentity(env, { defaultBranch: inputs.canonicalBranch }),
312012
+ canonicalBranch: inputs.canonicalBranch,
312013
+ channels: parseChannelRules(inputs.channels)
312014
+ },
312015
+ env
312016
+ );
312017
+ }
312018
+ function embedSpecBranchMarker(content, decision, repo) {
312019
+ if (decision.tier !== "preview" && decision.tier !== "channel" || !decision.identity.headBranch || !repo) {
312020
+ return content;
312021
+ }
312022
+ const rawBranch = decision.identity.headBranch;
312023
+ const now = (/* @__PURE__ */ new Date()).toISOString();
312024
+ const marker = {
312025
+ repo,
312026
+ rawBranch,
312027
+ sanitizedBranch: rawBranch.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/-+/g, "-").slice(0, 30),
312028
+ role: decision.tier,
312029
+ headSha: decision.identity.headSha,
312030
+ createdAt: now,
312031
+ lastSyncedAt: now
312032
+ };
312033
+ try {
312034
+ if (content.trim().startsWith("{")) {
312035
+ return `${JSON.stringify({ ...JSON.parse(content), "x-postman-onboarding": marker }, null, 2)}
312036
+ `;
312037
+ }
312038
+ const document2 = (0, import_yaml4.parse)(content);
312039
+ if (!document2 || typeof document2 !== "object" || Array.isArray(document2)) return content;
312040
+ return (0, import_yaml4.stringify)({ ...document2, "x-postman-onboarding": marker });
312041
+ } catch {
312042
+ return content;
312043
+ }
312044
+ }
312045
+ function renderCollectionBranchMarker(decision, repo, now = /* @__PURE__ */ new Date()) {
312046
+ if (decision.tier !== "preview" && decision.tier !== "channel" || !decision.identity.headBranch || !repo) {
312047
+ return void 0;
312048
+ }
312049
+ const rawBranch = decision.identity.headBranch;
312050
+ const timestamp = now.toISOString();
312051
+ return renderAssetMarker({
312052
+ repo,
312053
+ rawBranch,
312054
+ sanitizedBranch: rawBranch.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/-+/g, "-").slice(0, 30),
312055
+ role: decision.tier,
312056
+ headSha: decision.identity.headSha,
312057
+ createdAt: timestamp,
312058
+ lastSyncedAt: timestamp
312059
+ });
312060
+ }
312247
312061
  function createPlannedOutputs(inputs) {
312248
312062
  const workspaceName = inputs.domainCode ? `[${inputs.domainCode}] ${inputs.projectName}` : inputs.projectName;
312249
312063
  return {
@@ -312275,7 +312089,12 @@ function createPlannedOutputs(inputs) {
312275
312089
  mode: inputs.breakingChangeMode,
312276
312090
  status: "skipped",
312277
312091
  summaryPath: ""
312278
- })
312092
+ }),
312093
+ "sync-status": "",
312094
+ "branch-decision": "",
312095
+ "spec-version-tag": "",
312096
+ "spec-version-url": "",
312097
+ "spec-content-changed": ""
312279
312098
  };
312280
312099
  }
312281
312100
  function warnIfDeprecatedAccessToken(actionCore, inputs) {
@@ -312310,11 +312129,8 @@ function readActionInputs(actionCore) {
312310
312129
  if (specUrl && specPath) {
312311
312130
  throw new Error("Provide either spec-url or spec-path, not both.");
312312
312131
  }
312313
- const postmanApiKey = optionalInput(actionCore, "postman-api-key") ?? "";
312314
- const postmanAccessToken = optionalInput(actionCore, "postman-access-token");
312315
- if (!postmanApiKey && !postmanAccessToken) {
312316
- throw new Error("One of postman-api-key or postman-access-token is required.");
312317
- }
312132
+ const postmanApiKey = optionalInput(actionCore, "postman-api-key") || process.env.POSTMAN_API_KEY || "";
312133
+ const postmanAccessToken = optionalInput(actionCore, "postman-access-token") || process.env.POSTMAN_ACCESS_TOKEN;
312318
312134
  const githubToken = optionalInput(actionCore, "github-token") || process.env.GITHUB_TOKEN;
312319
312135
  const ghFallbackToken = optionalInput(actionCore, "gh-fallback-token") || process.env.GH_FALLBACK_TOKEN;
312320
312136
  if (postmanApiKey) actionCore.setSecret(postmanApiKey);
@@ -312358,6 +312174,7 @@ function readActionInputs(actionCore) {
312358
312174
  INPUT_NESTED_FOLDER_HIERARCHY: optionalInput(actionCore, "nested-folder-hierarchy") ?? bootstrapActionContract.inputs["nested-folder-hierarchy"].default,
312359
312175
  INPUT_REQUEST_NAME_SOURCE: optionalInput(actionCore, "request-name-source") ?? bootstrapActionContract.inputs["request-name-source"].default,
312360
312176
  INPUT_OPENAPI_VERSION: optionalInput(actionCore, "openapi-version") ?? "",
312177
+ INPUT_PRESERVE_OAS30_TYPE_NULL: optionalInput(actionCore, "preserve-oas30-type-null") ?? bootstrapActionContract.inputs["preserve-oas30-type-null"].default,
312361
312178
  INPUT_BREAKING_CHANGE_MODE: optionalInput(actionCore, "breaking-change-mode") ?? bootstrapActionContract.inputs["breaking-change-mode"].default,
312362
312179
  INPUT_BREAKING_BASELINE_SPEC_PATH: optionalInput(actionCore, "breaking-baseline-spec-path"),
312363
312180
  INPUT_BREAKING_RULES_PATH: optionalInput(actionCore, "breaking-rules-path") ?? bootstrapActionContract.inputs["breaking-rules-path"].default,
@@ -312468,6 +312285,27 @@ async function lintSpecViaCli(dependencies, workspaceId, specId) {
312468
312285
  warnings
312469
312286
  };
312470
312287
  }
312288
+ function normalizeLintPath(value) {
312289
+ return value.trim().replace(/^\$\.?/, "").replace(/\[(\d+)\]/g, ".$1").replace(/^\./, "");
312290
+ }
312291
+ function applyOas30TypeNullLintCompatibility(summary2, sourceTypeNullPaths) {
312292
+ const acceptedPaths = new Set(sourceTypeNullPaths.map(normalizeLintPath));
312293
+ if (acceptedPaths.size === 0) return summary2;
312294
+ const violations = summary2.violations.map((violation) => {
312295
+ const path10 = normalizeLintPath(violation.path ?? "");
312296
+ const issue2 = violation.issue ?? "";
312297
+ const isTypeEnumFinding = /["']?type["']? property/i.test(issue2) && /allowed values|must be equal to one of/i.test(issue2);
312298
+ if (violation.severity === "ERROR" && acceptedPaths.has(path10) && isTypeEnumFinding) {
312299
+ return { ...violation, severity: "WARNING" };
312300
+ }
312301
+ return violation;
312302
+ });
312303
+ return {
312304
+ errors: violations.filter((entry) => entry.severity === "ERROR").length,
312305
+ violations,
312306
+ warnings: violations.filter((entry) => entry.severity === "WARNING").length
312307
+ };
312308
+ }
312471
312309
  function shouldRetrySpecFetch(error2) {
312472
312310
  const retryability = classifySafeFetchRetryability(error2);
312473
312311
  return retryability === "retryable" || retryability === "unknown";
@@ -312948,7 +312786,7 @@ async function runProtocolBootstrap(specType, rawSpecContent, inputs, dependenci
312948
312786
  const workspaceRoot = path9.resolve(process.env.GITHUB_WORKSPACE ?? process.cwd());
312949
312787
  const serviceConfigPath = path9.join(path9.dirname(path9.resolve(workspaceRoot, inputs.specPath)), "grpc_service_config.json");
312950
312788
  try {
312951
- grpcServiceConfigJson = (0, import_node_fs5.readFileSync)(serviceConfigPath, "utf8");
312789
+ grpcServiceConfigJson = (0, import_node_fs6.readFileSync)(serviceConfigPath, "utf8");
312952
312790
  dependencies.core.info(`Found gRPC service config at ${serviceConfigPath}; validating it against the proto contract`);
312953
312791
  } catch {
312954
312792
  }
@@ -312962,7 +312800,7 @@ async function runProtocolBootstrap(specType, rawSpecContent, inputs, dependenci
312962
312800
  const resolved = path9.resolve(specDir, location2);
312963
312801
  if (!resolved.startsWith(specDir + path9.sep)) return void 0;
312964
312802
  try {
312965
- return (0, import_node_fs5.readFileSync)(resolved, "utf8");
312803
+ return (0, import_node_fs6.readFileSync)(resolved, "utf8");
312966
312804
  } catch {
312967
312805
  return void 0;
312968
312806
  }
@@ -313103,6 +312941,42 @@ async function createExtensibleContractCollection(workspaceId, built, inputs, de
313103
312941
  }
313104
312942
  async function runBootstrapInner(inputs, dependencies, telemetry) {
313105
312943
  const outputs = createPlannedOutputs(inputs);
312944
+ const branchDecision = decideBranchTier(inputs);
312945
+ const isCanonicalWriter = branchDecision.tier === "legacy" || branchDecision.tier === "canonical";
312946
+ const canonicalProjectName = inputs.projectName;
312947
+ const workspaceName = createWorkspaceName(inputs);
312948
+ const aboutText = `Auto-provisioned by Postman for ${inputs.projectName}`;
312949
+ if (branchDecision.tier === "preview" && branchDecision.identity.headBranch) {
312950
+ inputs = {
312951
+ ...inputs,
312952
+ projectName: previewAssetName(inputs.projectName, branchDecision.identity.headBranch)
312953
+ };
312954
+ dependencies.core.info(`branch-aware sync: preview asset set "${inputs.projectName}"`);
312955
+ } else if (branchDecision.tier === "channel" && branchDecision.channel) {
312956
+ inputs = {
312957
+ ...inputs,
312958
+ projectName: channelAssetName(inputs.projectName, branchDecision.channel.code)
312959
+ };
312960
+ dependencies.core.info(`branch-aware sync: channel asset set "${inputs.projectName}"`);
312961
+ }
312962
+ const collectionBranchMarker = renderCollectionBranchMarker(branchDecision, inputs.repoUrl);
312963
+ if (branchDecision.tier !== "legacy") {
312964
+ outputs["sync-status"] = "synced";
312965
+ outputs["branch-decision"] = serializeBranchDecision(branchDecision);
312966
+ }
312967
+ if (!isCanonicalWriter) {
312968
+ const explicitCanonicalIds = [
312969
+ ["spec-id", inputs.specId],
312970
+ ["baseline-collection-id", inputs.baselineCollectionId],
312971
+ ["smoke-collection-id", inputs.smokeCollectionId],
312972
+ ["contract-collection-id", inputs.contractCollectionId]
312973
+ ].filter(([, value]) => Boolean(value));
312974
+ if (explicitCanonicalIds.length > 0) {
312975
+ throw new Error(
312976
+ `CONTRACT_BRANCH_CANONICAL_WRITE: a ${branchDecision.tier} run must not mutate canonical assets, but explicit asset id input(s) were provided: ${explicitCanonicalIds.map(([name]) => name).join(", ")}. Remove them (preview/channel runs discover or create their own suffixed asset sets).`
312977
+ );
312978
+ }
312979
+ }
313106
312980
  const requiresReleaseLabel = inputs.collectionSyncMode === "version" || inputs.specSyncMode === "version";
313107
312981
  const releaseLabel = requiresReleaseLabel ? deriveReleaseLabel(inputs) : void 0;
313108
312982
  if (requiresReleaseLabel && !releaseLabel) {
@@ -313110,11 +312984,23 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313110
312984
  "Versioned spec or collection sync requires a release-label or derivable GitHub ref metadata"
313111
312985
  );
313112
312986
  }
313113
- const collectionAssetProjectName = inputs.collectionSyncMode === "version" ? createAssetProjectName(inputs, releaseLabel) : inputs.projectName;
313114
- const workspaceName = createWorkspaceName(inputs);
313115
- const aboutText = `Auto-provisioned by Postman for ${inputs.projectName}`;
313116
- const stateStore = resolveResourcesStateStore(dependencies);
313117
- const resourcesState = stateStore.read();
312987
+ const collectionAssetProjectName = branchDecision.tier === "channel" ? canonicalProjectName : inputs.collectionSyncMode === "version" ? createAssetProjectName(inputs, releaseLabel) : inputs.projectName;
312988
+ const rawStateStore = resolveResourcesStateStore(dependencies);
312989
+ const trackedState = rawStateStore.read();
312990
+ const stateStore = isCanonicalWriter ? rawStateStore : {
312991
+ read: rawStateStore.read,
312992
+ write: () => {
312993
+ dependencies.core.info(
312994
+ `branch-aware sync: skipping .postman/resources.yaml write on ${branchDecision.tier} run (canonical-only tracked state)`
312995
+ );
312996
+ }
312997
+ };
312998
+ const resourcesState = isCanonicalWriter ? trackedState : trackedState?.workspace ? { workspace: trackedState.workspace } : null;
312999
+ if (!isCanonicalWriter && trackedState?.cloudResources) {
313000
+ dependencies.core.info(
313001
+ "branch-aware sync: canonical asset ids in .postman/resources.yaml are not resolved on a non-canonical run"
313002
+ );
313003
+ }
313118
313004
  const writableResourcesState = resourcesState ?? {};
313119
313005
  const additionalCollections = loadAdditionalCollectionFiles(
313120
313006
  inputs.additionalCollectionsDir,
@@ -313134,16 +313020,19 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313134
313020
  }
313135
313021
  let previousSpecContent;
313136
313022
  let previousSpecRollbackHash;
313023
+ let specContentUnchanged = false;
313137
313024
  let detectedOpenapiVersion = "3.0";
313138
313025
  let contractIndex;
313139
313026
  let sourceSpecContent = "";
313027
+ let sourceTypeNullPaths = [];
313028
+ let preserveSourceSpecBytes = false;
313140
313029
  const rawSpecContent = await runGroup(
313141
313030
  dependencies.core,
313142
313031
  "Read API Spec",
313143
313032
  async () => {
313144
313033
  if (inputs.specPath) {
313145
313034
  const workspaceRoot = path9.resolve(process.env.GITHUB_WORKSPACE ?? process.cwd());
313146
- return (0, import_node_fs5.readFileSync)(path9.resolve(workspaceRoot, inputs.specPath), "utf8");
313035
+ return (0, import_node_fs6.readFileSync)(path9.resolve(workspaceRoot, inputs.specPath), "utf8");
313147
313036
  }
313148
313037
  if (dependencies.specFetcher === fetch) {
313149
313038
  return safeFetchText(inputs.specUrl, { depth: 0 });
@@ -313179,6 +313068,7 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313179
313068
  };
313180
313069
  const rootKey = inputs.specPath ? void 0 : normalizeRef(inputs.specUrl);
313181
313070
  const loaderOptions = {
313071
+ preserveOas30TypeNull: Boolean(inputs.preserveOas30TypeNull),
313182
313072
  fetchText: async (url, fetchOptions) => {
313183
313073
  if (rootKey && normalizeRef(url) === rootKey) return rawSpecContent;
313184
313074
  if (dependencies.specFetcher === fetch) return safeFetchText(url, fetchOptions);
@@ -313187,6 +313077,8 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313187
313077
  };
313188
313078
  const loaded = inputs.specPath ? await loadOpenApiContractSpecFromPath(inputs.specPath, loaderOptions) : await loadOpenApiContractSpec(inputs.specUrl, loaderOptions);
313189
313079
  sourceSpecContent = loaded.content;
313080
+ sourceTypeNullPaths = loaded.sourceTypeNullPaths;
313081
+ preserveSourceSpecBytes = sourceTypeNullPaths.length > 0;
313190
313082
  const document2 = normalizeSpecDocument(
313191
313083
  loaded.bundledContent,
313192
313084
  (msg) => dependencies.core.warning(msg)
@@ -313209,11 +313101,11 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313209
313101
  `Unable to verify existing Spec Hub OpenAPI version for spec-id ${specId}; clear spec-id to create a fresh spec`
313210
313102
  );
313211
313103
  }
313212
- previousSpecContent = normalizeSpecDocument(
313104
+ previousSpecContent = preserveSourceSpecBytes ? previousRaw : normalizeSpecDocument(
313213
313105
  previousRaw,
313214
313106
  (msg) => dependencies.core.warning(`Previous spec normalization: ${msg}`)
313215
313107
  );
313216
- previousSpecRollbackHash = (0, import_node_crypto5.createHash)("sha256").update(previousSpecContent).digest("hex");
313108
+ previousSpecRollbackHash = (0, import_node_crypto6.createHash)("sha256").update(previousSpecContent).digest("hex");
313217
313109
  const existingSpecType = normalizeSpecTypeFromContent(previousSpecContent);
313218
313110
  if (existingSpecType !== incomingSpecType) {
313219
313111
  throw new Error(
@@ -313224,6 +313116,12 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313224
313116
  dependencies.core.info(
313225
313117
  `Auto-detected OpenAPI version from spec content: ${detectedOpenapiVersion}`
313226
313118
  );
313119
+ if (preserveSourceSpecBytes) {
313120
+ dependencies.core.info(
313121
+ `Preserving original OpenAPI source bytes; accepted ${sourceTypeNullPaths.length} legacy type: null member(s) for internal validation`
313122
+ );
313123
+ return loaded.content;
313124
+ }
313227
313125
  return document2;
313228
313126
  }
313229
313127
  );
@@ -313259,6 +313157,11 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313259
313157
  `OpenAPI breaking-change check failed: ${breakingChangeResult.message || "breaking changes detected"}`
313260
313158
  );
313261
313159
  }
313160
+ const uploadSpecContent = embedSpecBranchMarker(
313161
+ specContent,
313162
+ branchDecision,
313163
+ inputs.repoUrl
313164
+ );
313262
313165
  const provisioned = await provisionWorkspace(
313263
313166
  inputs,
313264
313167
  dependencies,
@@ -313383,10 +313286,17 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313383
313286
  specId ? "Update Spec in Spec Hub" : "Upload Spec to Spec Hub",
313384
313287
  async () => {
313385
313288
  if (specId) {
313386
- dependencies.core.info(
313387
- `Updating existing spec ${specId} (detected version: ${detectedOpenapiVersion}). Note: the spec type (OPENAPI:3.0 / OPENAPI:3.1) is set at creation and cannot be changed on update. If you changed OpenAPI versions, clear the spec-id input to create a fresh spec.`
313388
- );
313389
- await dependencies.postman.updateSpec(specId, specContent, workspaceId);
313289
+ if (previousSpecContent !== void 0 && (0, import_node_crypto6.createHash)("sha256").update(uploadSpecContent).digest("hex") === (0, import_node_crypto6.createHash)("sha256").update(previousSpecContent).digest("hex")) {
313290
+ specContentUnchanged = true;
313291
+ dependencies.core.info(
313292
+ `Spec content unchanged (sha256 match); skipping Spec Hub update and version tag for ${specId}.`
313293
+ );
313294
+ } else {
313295
+ dependencies.core.info(
313296
+ `Updating existing spec ${specId} (detected version: ${detectedOpenapiVersion}). Note: the spec type (OPENAPI:3.0 / OPENAPI:3.1) is set at creation and cannot be changed on update. If you changed OpenAPI versions, clear the spec-id input to create a fresh spec.`
313297
+ );
313298
+ await dependencies.postman.updateSpec(specId, uploadSpecContent, workspaceId);
313299
+ }
313390
313300
  } else {
313391
313301
  specId = await dependencies.postman.uploadSpec(
313392
313302
  workspaceId || "",
@@ -313394,7 +313304,7 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313394
313304
  inputs,
313395
313305
  inputs.specSyncMode === "version" ? releaseLabel : void 0
313396
313306
  ),
313397
- specContent,
313307
+ uploadSpecContent,
313398
313308
  detectedOpenapiVersion
313399
313309
  );
313400
313310
  }
@@ -313411,8 +313321,9 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313411
313321
  }
313412
313322
  )
313413
313323
  );
313324
+ outputs["spec-content-changed"] = isCanonicalWriter && !specContentUnchanged ? "true" : "false";
313414
313325
  if (lintEnabled) {
313415
- const lintSummary = await runRollbackStage(
313326
+ let lintSummary = await runRollbackStage(
313416
313327
  "Lint Spec via Postman CLI",
313417
313328
  async () => runGroup(
313418
313329
  dependencies.core,
@@ -313420,6 +313331,16 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313420
313331
  async () => lintSpecViaCli(dependencies, workspaceId || "", outputs["spec-id"])
313421
313332
  )
313422
313333
  );
313334
+ if (preserveSourceSpecBytes) {
313335
+ const originalErrorCount = lintSummary.errors;
313336
+ lintSummary = applyOas30TypeNullLintCompatibility(lintSummary, sourceTypeNullPaths);
313337
+ const acceptedCount = originalErrorCount - lintSummary.errors;
313338
+ if (acceptedCount > 0) {
313339
+ dependencies.core.info(
313340
+ `Accepted ${acceptedCount} Postman CLI type: null finding(s) covered by preserve-oas30-type-null`
313341
+ );
313342
+ }
313343
+ }
313423
313344
  outputs["lint-summary-json"] = JSON.stringify({
313424
313345
  errors: lintSummary.errors,
313425
313346
  total: lintSummary.violations.length,
@@ -313444,7 +313365,12 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313444
313365
  });
313445
313366
  dependencies.core.warning("lint skipped: governance errors not enforced (no postman-api-key)");
313446
313367
  }
313447
- await runRollbackStage(
313368
+ if (specContentUnchanged) {
313369
+ outputs["baseline-collection-id"] = baselineCollectionId || "";
313370
+ outputs["smoke-collection-id"] = smokeCollectionId || "";
313371
+ outputs["contract-collection-id"] = contractCollectionId || "";
313372
+ dependencies.core.info("Spec content unchanged; skipping collection regeneration and version finalization.");
313373
+ } else await runRollbackStage(
313448
313374
  "Generate Collections from Spec",
313449
313375
  async () => runGroup(
313450
313376
  dependencies.core,
@@ -313483,10 +313409,11 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313483
313409
  return;
313484
313410
  }
313485
313411
  }
313412
+ const effectivePrefix = branchDecision.tier === "channel" && branchDecision.channel ? channelAssetName(prefix, branchDecision.channel.code).trim() : prefix;
313486
313413
  outputs[outputKey] = await dependencies.postman.generateCollection(
313487
313414
  specId2,
313488
313415
  assetProjectName,
313489
- prefix,
313416
+ effectivePrefix,
313490
313417
  inputs.folderStrategy,
313491
313418
  inputs.nestedFolderHierarchy,
313492
313419
  inputs.requestNameSource
@@ -313507,6 +313434,32 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313507
313434
  await ensureCollection(BASELINE_COLLECTION_PREFIX, baselineCollectionId, "baseline-collection-id");
313508
313435
  await ensureCollection(SMOKE_COLLECTION_PREFIX, smokeCollectionId, "smoke-collection-id");
313509
313436
  await ensureCollection(CONTRACT_COLLECTION_PREFIX, contractCollectionId, "contract-collection-id");
313437
+ if (dependencies.postman.adoptGeneratedCollection) {
313438
+ const reelect = async (prefix, outputKey) => {
313439
+ const effectivePrefix = branchDecision.tier === "channel" && branchDecision.channel ? channelAssetName(prefix, branchDecision.channel.code).trim() : prefix;
313440
+ const preferred = outputs[outputKey];
313441
+ if (!preferred) return;
313442
+ outputs[outputKey] = await dependencies.postman.adoptGeneratedCollection(
313443
+ specId2,
313444
+ assetProjectName,
313445
+ effectivePrefix,
313446
+ preferred
313447
+ );
313448
+ };
313449
+ await reelect(BASELINE_COLLECTION_PREFIX, "baseline-collection-id");
313450
+ await reelect(SMOKE_COLLECTION_PREFIX, "smoke-collection-id");
313451
+ await reelect(CONTRACT_COLLECTION_PREFIX, "contract-collection-id");
313452
+ }
313453
+ if (collectionBranchMarker) {
313454
+ if (!dependencies.postman.updateCollectionDescription) {
313455
+ throw new Error("Branch-scoped collections require updateCollectionDescription support");
313456
+ }
313457
+ await Promise.all([
313458
+ outputs["baseline-collection-id"],
313459
+ outputs["smoke-collection-id"],
313460
+ outputs["contract-collection-id"]
313461
+ ].filter(Boolean).map((id) => dependencies.postman.updateCollectionDescription(id, collectionBranchMarker)));
313462
+ }
313510
313463
  if (!dependencies.postman.injectContractTests) {
313511
313464
  throw new Error(
313512
313465
  "Dynamic contract tests require injectContractTests support from the access-token gateway client"
@@ -313609,6 +313562,12 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313609
313562
  workspaceId: workspaceId || ""
313610
313563
  });
313611
313564
  for (const result of additionalResults) {
313565
+ if (collectionBranchMarker) {
313566
+ if (!dependencies.postman.updateCollectionDescription) {
313567
+ throw new Error("Branch-scoped collections require updateCollectionDescription support");
313568
+ }
313569
+ await dependencies.postman.updateCollectionDescription(result.collectionId, collectionBranchMarker);
313570
+ }
313612
313571
  completedExternalSideEffects.push(
313613
313572
  `${result.operation}AdditionalCollection(${result.collectionId} from ${result.displayPath})`
313614
313573
  );
@@ -313684,8 +313643,66 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313684
313643
  }
313685
313644
  return outputs;
313686
313645
  }
313646
+ async function runGatedValidation(inputs, decision, actionCore) {
313647
+ actionCore.info(`branch-aware sync: gated run (${decision.reason}) \u2014 credential-free static validation, zero workspace writes`);
313648
+ const outputs = createPlannedOutputs(inputs);
313649
+ outputs["sync-status"] = "skipped-branch-gate";
313650
+ outputs["branch-decision"] = serializeBranchDecision(decision);
313651
+ let violations = [];
313652
+ let validated = false;
313653
+ try {
313654
+ let content;
313655
+ if (inputs.specPath) {
313656
+ content = (0, import_node_fs6.readFileSync)(inputs.specPath, "utf8");
313657
+ } else if (inputs.specUrl) {
313658
+ content = await safeFetchText(inputs.specUrl, { depth: 0 });
313659
+ }
313660
+ if (content) {
313661
+ const specType = detectSpecType(content, inputs.specPath);
313662
+ if (specType === "openapi") {
313663
+ const document2 = parseOpenApiDocument(content);
313664
+ const index = buildContractIndex(document2);
313665
+ violations = index.warnings;
313666
+ validated = true;
313667
+ } else {
313668
+ actionCore.info(`branch gate: static lint for spec type ${specType} runs through its protocol builder on publish; parse-only gate applied`);
313669
+ validated = true;
313670
+ }
313671
+ } else {
313672
+ actionCore.info("branch gate: no spec-url/spec-path provided; nothing to validate");
313673
+ }
313674
+ } catch (error2) {
313675
+ throw new Error(
313676
+ `branch gate: static validation failed: ${error2 instanceof Error ? error2.message : String(error2)}`,
313677
+ { cause: error2 }
313678
+ );
313679
+ }
313680
+ outputs["lint-summary-json"] = JSON.stringify({
313681
+ status: validated ? "static-only" : "skipped",
313682
+ reason: "branch-gated run: governance lint requires upload and runs on publish/preview syncs",
313683
+ errors: 0,
313684
+ warnings: violations.length,
313685
+ total: violations.length,
313686
+ violations: violations.map((issue2) => ({ issue: issue2, severity: "WARNING" }))
313687
+ });
313688
+ for (const [name, value] of Object.entries(outputs)) {
313689
+ actionCore.setOutput(name, value);
313690
+ }
313691
+ return outputs;
313692
+ }
313687
313693
  async function runAction(actionCore = core_exports, actionExec = exec_exports, actionIo = io_exports) {
313688
313694
  const inputs = readActionInputs(actionCore);
313695
+ const branchDecision = decideBranchTier(inputs);
313696
+ if (branchDecision.tier === "gated") {
313697
+ return runGatedValidation(inputs, branchDecision, actionCore);
313698
+ }
313699
+ if (!inputs.postmanApiKey && !inputs.postmanAccessToken) {
313700
+ throw new Error("One of postman-api-key or postman-access-token is required for a writing sync.");
313701
+ }
313702
+ if (branchDecision.tier !== "legacy") {
313703
+ actionCore.info(`branch-aware sync: tier=${branchDecision.tier} (${branchDecision.reason})`);
313704
+ process.env[BRANCH_DECISION_ENV] = serializeBranchDecision(branchDecision);
313705
+ }
313689
313706
  await mintAccessTokenIfNeeded2(inputs, {
313690
313707
  info: (message) => actionCore.info(message),
313691
313708
  warning: (message) => actionCore.warning(message)
@@ -313762,6 +313779,7 @@ function createRoutingPostmanClient(options) {
313762
313779
  updateSpec: requireAccessToken("updateSpec"),
313763
313780
  getSpecContent: requireAccessToken("getSpecContent"),
313764
313781
  generateCollection: requireAccessToken("generateCollection"),
313782
+ adoptGeneratedCollection: requireAccessToken("adoptGeneratedCollection"),
313765
313783
  createWorkspace: requireAccessToken("createWorkspace"),
313766
313784
  getWorkspaceVisibility: requireAccessToken("getWorkspaceVisibility"),
313767
313785
  getWorkspaceGitRepoUrl: requireAccessToken("getWorkspaceGitRepoUrl"),
@@ -313771,10 +313789,13 @@ function createRoutingPostmanClient(options) {
313771
313789
  inviteRequesterToWorkspace: requireAccessToken("inviteRequesterToWorkspace"),
313772
313790
  injectTests: requireAccessToken("injectTests"),
313773
313791
  tagCollection: requireAccessToken("tagCollection"),
313792
+ tagSpecVersion: requireAccessToken("tagSpecVersion"),
313793
+ listSpecVersionTags: requireAccessToken("listSpecVersionTags"),
313774
313794
  deleteCollection: requireAccessToken("deleteCollection"),
313775
313795
  injectContractTests: requireAccessToken("injectContractTests"),
313776
313796
  createCollection: requireAccessToken("createCollection"),
313777
- updateCollection: requireAccessToken("updateCollection")
313797
+ updateCollection: requireAccessToken("updateCollection"),
313798
+ updateCollectionDescription: requireAccessToken("updateCollectionDescription")
313778
313799
  };
313779
313800
  }
313780
313801
  return {
@@ -313786,6 +313807,7 @@ function createRoutingPostmanClient(options) {
313786
313807
  // not a reason to reach for the API key.
313787
313808
  uploadSpec: (workspaceId, projectName, specContent, openapiVersion) => gateway.uploadSpec(workspaceId, projectName, specContent, openapiVersion ?? "3.0"),
313788
313809
  generateCollection: (specId, projectName, prefix, folderStrategy, nestedFolderHierarchy, requestNameSource) => gateway.generateCollection(specId, projectName, prefix, folderStrategy, nestedFolderHierarchy, requestNameSource),
313810
+ adoptGeneratedCollection: (specId, projectName, prefix, preferredId) => gateway.adoptGeneratedCollection(specId, projectName, prefix, preferredId),
313789
313811
  updateSpec: (specId, specContent, workspaceId) => gateway.updateSpec(specId, specContent, workspaceId),
313790
313812
  getSpecContent: (specId) => gateway.getSpecContent(specId),
313791
313813
  createWorkspace: (name, about, targetTeamId) => gateway.createWorkspace(name, about, targetTeamId),
@@ -313797,6 +313819,8 @@ function createRoutingPostmanClient(options) {
313797
313819
  // + tagging surfaces (live-proven). PMAK is reserved for token minting, so
313798
313820
  // these never fall back to the API key even when one is present.
313799
313821
  injectTests: (collectionId, type) => gateway.injectTests(collectionId, type),
313822
+ tagSpecVersion: (specId, name) => gateway.tagSpecVersion(specId, name),
313823
+ listSpecVersionTags: (specId) => gateway.listSpecVersionTags(specId),
313800
313824
  tagCollection: (collectionId, tags) => gateway.tagCollection(collectionId, tags),
313801
313825
  // Sub-team (squad) enumeration over the gateway `ums` service. Access-token
313802
313826
  // only — never PMAK — so org-mode detection no longer needs a PMAK GET /teams.
@@ -313814,7 +313838,8 @@ function createRoutingPostmanClient(options) {
313814
313838
  // so no asset op ever reaches for the API key.
313815
313839
  injectContractTests: (collectionUid, index) => gateway.injectContractTests(collectionUid, index),
313816
313840
  createCollection: (workspaceId, collection, options2) => gateway.createCollection(workspaceId, collection, options2),
313817
- updateCollection: (collectionUid, collection) => gateway.updateCollection(collectionUid, collection)
313841
+ updateCollection: (collectionUid, collection) => gateway.updateCollection(collectionUid, collection),
313842
+ updateCollectionDescription: (collectionUid, description) => gateway.updateCollectionDescription(collectionUid, description)
313818
313843
  };
313819
313844
  }
313820
313845
  function createBootstrapDependencies(inputs, factories, orgMode = false) {