@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/index.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,
@@ -253780,19 +253780,25 @@ var require_cjs4 = __commonJS({
253780
253780
  // src/index.ts
253781
253781
  var index_exports = {};
253782
253782
  __export(index_exports, {
253783
+ applyOas30TypeNullLintCompatibility: () => applyOas30TypeNullLintCompatibility,
253784
+ buildSpecVersionUrl: () => buildSpecVersionUrl,
253783
253785
  createBootstrapDependencies: () => createBootstrapDependencies,
253784
253786
  createExtensibleContractCollection: () => createExtensibleContractCollection,
253785
253787
  createPlannedOutputs: () => createPlannedOutputs,
253786
253788
  createRoutingPostmanClient: () => createRoutingPostmanClient,
253789
+ decideBranchTier: () => decideBranchTier,
253790
+ embedSpecBranchMarker: () => embedSpecBranchMarker,
253787
253791
  ensurePostmanCli: () => ensurePostmanCli,
253788
253792
  getInput: () => getInput2,
253789
253793
  lintSpecViaCli: () => lintSpecViaCli,
253790
253794
  mintAccessTokenIfNeeded: () => mintAccessTokenIfNeeded2,
253791
253795
  normalizeSpecDocument: () => normalizeSpecDocument,
253792
253796
  readActionInputs: () => readActionInputs,
253797
+ renderCollectionBranchMarker: () => renderCollectionBranchMarker,
253793
253798
  resolveInputs: () => resolveInputs,
253794
253799
  runAction: () => runAction,
253795
- runBootstrap: () => runBootstrap
253800
+ runBootstrap: () => runBootstrap,
253801
+ runGatedValidation: () => runGatedValidation
253796
253802
  });
253797
253803
  module.exports = __toCommonJS(index_exports);
253798
253804
 
@@ -256216,8 +256222,8 @@ function getIDToken(aud) {
256216
256222
  }
256217
256223
 
256218
256224
  // src/index.ts
256219
- var import_node_crypto5 = require("node:crypto");
256220
- var import_node_fs5 = require("node:fs");
256225
+ var import_node_crypto6 = require("node:crypto");
256226
+ var import_node_fs6 = require("node:fs");
256221
256227
  var path9 = __toESM(require("node:path"), 1);
256222
256228
  var import_yaml4 = __toESM(require_dist(), 1);
256223
256229
 
@@ -256325,6 +256331,12 @@ var bootstrapActionContract = {
256325
256331
  default: "",
256326
256332
  allowedValues: ["3.0", "3.1"]
256327
256333
  },
256334
+ "preserve-oas30-type-null": {
256335
+ 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.",
256336
+ required: false,
256337
+ default: "false",
256338
+ allowedValues: ["true", "false"]
256339
+ },
256328
256340
  "breaking-change-mode": {
256329
256341
  description: "OpenAPI breaking-change comparison mode.",
256330
256342
  required: false,
@@ -256381,6 +256393,20 @@ var bootstrapActionContract = {
256381
256393
  default: "warn",
256382
256394
  allowedValues: ["enforce", "warn"]
256383
256395
  },
256396
+ "branch-strategy": {
256397
+ 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.",
256398
+ required: false,
256399
+ default: "legacy",
256400
+ allowedValues: ["legacy", "preview", "publish-gate"]
256401
+ },
256402
+ "canonical-branch": {
256403
+ 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.",
256404
+ required: false
256405
+ },
256406
+ "channels": {
256407
+ 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.',
256408
+ required: false
256409
+ },
256384
256410
  "integration-backend": {
256385
256411
  description: "Integration backend for downstream workspace connectivity.",
256386
256412
  required: false,
@@ -256450,6 +256476,21 @@ var bootstrapActionContract = {
256450
256476
  },
256451
256477
  "breaking-change-summary-json": {
256452
256478
  description: "JSON summary of the OpenAPI breaking-change check."
256479
+ },
256480
+ "sync-status": {
256481
+ 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."
256482
+ },
256483
+ "branch-decision": {
256484
+ description: "Serialized BranchDecision JSON for downstream actions (also exported as POSTMAN_BRANCH_DECISION)."
256485
+ },
256486
+ "spec-version-tag": {
256487
+ 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)."
256488
+ },
256489
+ "spec-version-url": {
256490
+ description: "Reserved for the repo-sync finalizer; bootstrap does not tag before complete onboarding."
256491
+ },
256492
+ "spec-content-changed": {
256493
+ description: "Whether bootstrap changed canonical spec content; repo-sync uses this to skip native version tags on no-op syncs."
256453
256494
  }
256454
256495
  },
256455
256496
  retainedBehavior: [
@@ -257576,6 +257617,15 @@ function assertSupportedLocalViewContract(node, options) {
257576
257617
  }
257577
257618
 
257578
257619
  // src/lib/postman/additional-collections.ts
257620
+ var RESOURCES_STATE_VERSION = 2;
257621
+ var SUPPORTED_STATE_VERSIONS = /* @__PURE__ */ new Set([1, RESOURCES_STATE_VERSION]);
257622
+ var StateUnreadableError = class extends Error {
257623
+ code = "CONTRACT_STATE_UNREADABLE";
257624
+ constructor(message) {
257625
+ super(`CONTRACT_STATE_UNREADABLE: ${message}`);
257626
+ this.name = "StateUnreadableError";
257627
+ }
257628
+ };
257579
257629
  var ADDITIONAL_COLLECTION_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".yaml", ".yml"]);
257580
257630
  var POSTMAN_COLLECTION_V21_SCHEMA_FRAGMENT = "/collection/v2.1.0/collection.json";
257581
257631
  var V3_DEFINITION_PATH = import_node_path2.default.join(".resources", "definition.yaml");
@@ -257631,16 +257681,46 @@ function resourcesStatePath() {
257631
257681
  return import_node_path2.default.join(workspaceRootForLocalInputs(), RESOURCES_PATH);
257632
257682
  }
257633
257683
  function readResourcesState() {
257684
+ let raw;
257634
257685
  try {
257635
- return (0, import_yaml.parse)((0, import_node_fs2.readFileSync)(resourcesStatePath(), "utf8"));
257686
+ raw = (0, import_node_fs2.readFileSync)(resourcesStatePath(), "utf8");
257636
257687
  } catch {
257637
257688
  return null;
257638
257689
  }
257690
+ let parsed;
257691
+ try {
257692
+ parsed = (0, import_yaml.parse)(raw);
257693
+ } catch (error2) {
257694
+ throw new StateUnreadableError(
257695
+ `.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.`
257696
+ );
257697
+ }
257698
+ if (parsed === null || parsed === void 0) {
257699
+ return null;
257700
+ }
257701
+ if (typeof parsed !== "object" || Array.isArray(parsed)) {
257702
+ throw new StateUnreadableError(
257703
+ ".postman/resources.yaml exists but does not contain a YAML mapping. Fix or delete the file; refusing to treat tracked state as absent."
257704
+ );
257705
+ }
257706
+ const state = parsed;
257707
+ if (state.version !== void 0 && !SUPPORTED_STATE_VERSIONS.has(Number(state.version))) {
257708
+ throw new StateUnreadableError(
257709
+ `.postman/resources.yaml declares unsupported state version ${String(state.version)} (supported: 1, ${RESOURCES_STATE_VERSION}). Upgrade the action or fix the file.`
257710
+ );
257711
+ }
257712
+ if (state.canonical && !state.cloudResources) {
257713
+ state.cloudResources = { ...state.canonical };
257714
+ }
257715
+ return state;
257639
257716
  }
257640
257717
  function writeResourcesState(state) {
257641
257718
  const target = resourcesStatePath();
257642
257719
  (0, import_node_fs2.mkdirSync)(import_node_path2.default.dirname(target), { recursive: true });
257643
- (0, import_node_fs2.writeFileSync)(target, (0, import_yaml.stringify)(state), "utf8");
257720
+ const canonical = state.cloudResources ?? state.canonical ?? {};
257721
+ const persisted = { ...state, version: RESOURCES_STATE_VERSION, canonical };
257722
+ delete persisted.cloudResources;
257723
+ (0, import_node_fs2.writeFileSync)(target, (0, import_yaml.stringify)(persisted), "utf8");
257644
257724
  }
257645
257725
  function findCloudResourceId(map, matcher) {
257646
257726
  if (!map) {
@@ -257650,7 +257730,7 @@ function findCloudResourceId(map, matcher) {
257650
257730
  return match?.[1];
257651
257731
  }
257652
257732
  function findExistingAdditionalCollectionId(resourcesState, resourcePath) {
257653
- return resourcesState?.cloudResources?.additionalCollections?.[resourcePath] ?? resourcesState?.cloudResources?.collections?.[resourcePath];
257733
+ return resourcesState?.canonical?.additionalCollections?.[resourcePath] ?? resourcesState?.canonical?.collections?.[resourcePath] ?? resourcesState?.cloudResources?.additionalCollections?.[resourcePath] ?? resourcesState?.cloudResources?.collections?.[resourcePath];
257654
257734
  }
257655
257735
  function resolveAdditionalCollectionsDir(directoryInput) {
257656
257736
  const workspaceRoot = workspaceRootForLocalInputs();
@@ -258652,6 +258732,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
258652
258732
  * endpoint aborts rather than blocking the run forever. */
258653
258733
  static REQUEST_TIMEOUT_MS = 3e4;
258654
258734
  static POSTMAN_APP_VERSION_URL = `https://dl.pstmn.io/update/status?currentVersion=${_BifrostInternalIntegrationAdapter.MINIMUM_POSTMAN_APP_VERSION}&platform=osx_arm64`;
258735
+ /** Concurrent dual-trigger previews share one spec; peer sync holds a 423 lock. */
258736
+ static SYNC_LOCKED_MAX_RETRIES = 6;
258655
258737
  accessToken;
258656
258738
  tokenProvider;
258657
258739
  appVersionPromise;
@@ -258660,6 +258742,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
258660
258742
  gatewayBaseUrl;
258661
258743
  orgMode;
258662
258744
  secretMasker;
258745
+ sleep;
258663
258746
  teamId;
258664
258747
  constructor(options) {
258665
258748
  this.accessToken = String(options.accessToken || "").trim();
@@ -258673,6 +258756,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
258673
258756
  ).replace(/\/+$/, "");
258674
258757
  this.orgMode = options.orgMode ?? false;
258675
258758
  this.secretMasker = options.secretMasker ?? createSecretMasker([this.accessToken]);
258759
+ this.sleep = options.sleep ?? ((delayMs) => new Promise((resolve5) => setTimeout(resolve5, delayMs)));
258676
258760
  this.teamId = String(options.teamId || "").trim();
258677
258761
  }
258678
258762
  configureTeamContext(teamId, orgMode) {
@@ -258879,55 +258963,72 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
258879
258963
  if (collections.length === 0) {
258880
258964
  return;
258881
258965
  }
258882
- const response = await this.proxyRequest(
258883
- "specification",
258884
- "put",
258885
- `/specifications/${specificationId}/collections`,
258886
- collections.map((collection) => ({
258887
- collectionId: collection.collectionId,
258888
- ...collection.syncOptions ? { syncOptions: collection.syncOptions } : {}
258889
- }))
258890
- );
258891
- if (response.ok) {
258892
- return;
258966
+ const body2 = collections.map((collection) => ({
258967
+ collectionId: collection.collectionId,
258968
+ ...collection.syncOptions ? { syncOptions: collection.syncOptions } : {}
258969
+ }));
258970
+ for (let lockedAttempt = 0; ; lockedAttempt += 1) {
258971
+ const response = await this.proxyRequest(
258972
+ "specification",
258973
+ "put",
258974
+ `/specifications/${specificationId}/collections`,
258975
+ body2
258976
+ );
258977
+ if (response.ok) {
258978
+ return;
258979
+ }
258980
+ const httpErr = await HttpError.fromResponse(response, {
258981
+ method: "POST",
258982
+ requestHeaders: {
258983
+ "Content-Type": "application/json",
258984
+ "x-access-token": this.currentToken(),
258985
+ ...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
258986
+ },
258987
+ secretValues: [this.currentToken()],
258988
+ url: `${this.bifrostBaseUrl}/ws/proxy`
258989
+ });
258990
+ if (httpErr.status === 423 && lockedAttempt < _BifrostInternalIntegrationAdapter.SYNC_LOCKED_MAX_RETRIES) {
258991
+ await this.sleep(2e3 * Math.pow(2, lockedAttempt));
258992
+ continue;
258993
+ }
258994
+ const advised = adviseFromHttpError(
258995
+ httpErr,
258996
+ this.adviceContext("collection-to-specification linking")
258997
+ );
258998
+ throw advised ?? httpErr;
258893
258999
  }
258894
- const httpErr = await HttpError.fromResponse(response, {
258895
- method: "POST",
258896
- requestHeaders: {
258897
- "Content-Type": "application/json",
258898
- "x-access-token": this.currentToken(),
258899
- ...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
258900
- },
258901
- secretValues: [this.currentToken()],
258902
- url: `${this.bifrostBaseUrl}/ws/proxy`
258903
- });
258904
- const advised = adviseFromHttpError(
258905
- httpErr,
258906
- this.adviceContext("collection-to-specification linking")
258907
- );
258908
- throw advised ?? httpErr;
258909
259000
  }
258910
259001
  async syncCollection(specificationId, collectionId) {
258911
- const response = await this.proxyRequest(
258912
- "specification",
258913
- "post",
258914
- `/specifications/${specificationId}/collections/${collectionId}/sync`
258915
- );
258916
- if (response.ok) {
258917
- return;
259002
+ for (let lockedAttempt = 0; ; lockedAttempt += 1) {
259003
+ const response = await this.proxyRequest(
259004
+ "specification",
259005
+ "post",
259006
+ `/specifications/${specificationId}/collections/${collectionId}/sync`
259007
+ );
259008
+ if (response.ok) {
259009
+ return;
259010
+ }
259011
+ const bodyText = await response.clone().text().catch(() => "");
259012
+ if (response.status === 400 && /already in sync/i.test(bodyText)) {
259013
+ return;
259014
+ }
259015
+ const httpErr = await HttpError.fromResponse(response, {
259016
+ method: "POST",
259017
+ requestHeaders: {
259018
+ "Content-Type": "application/json",
259019
+ "x-access-token": this.currentToken(),
259020
+ ...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
259021
+ },
259022
+ secretValues: [this.currentToken()],
259023
+ url: `${this.bifrostBaseUrl}/ws/proxy`
259024
+ });
259025
+ if (httpErr.status === 423 && lockedAttempt < _BifrostInternalIntegrationAdapter.SYNC_LOCKED_MAX_RETRIES) {
259026
+ await this.sleep(2e3 * Math.pow(2, lockedAttempt));
259027
+ continue;
259028
+ }
259029
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("collection sync"));
259030
+ throw advised ?? httpErr;
258918
259031
  }
258919
- const httpErr = await HttpError.fromResponse(response, {
258920
- method: "POST",
258921
- requestHeaders: {
258922
- "Content-Type": "application/json",
258923
- "x-access-token": this.currentToken(),
258924
- ...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
258925
- },
258926
- secretValues: [this.currentToken()],
258927
- url: `${this.bifrostBaseUrl}/ws/proxy`
258928
- });
258929
- const advised = adviseFromHttpError(httpErr, this.adviceContext("collection sync"));
258930
- throw advised ?? httpErr;
258931
259032
  }
258932
259033
  async getWorkspaceGitRepoUrl(workspaceId) {
258933
259034
  const response = await this.proxyRequest(
@@ -259332,6 +259433,18 @@ async function retry(operation, options = {}) {
259332
259433
  }
259333
259434
  throw new Error("Retry exhausted without returning or throwing");
259334
259435
  }
259436
+ function fullJitterDelayMs(attempt, baseMs, capMs, random = Math.random) {
259437
+ const ceiling = Math.min(capMs, baseMs * 2 ** Math.max(0, attempt));
259438
+ return Math.floor(random() * Math.max(0, ceiling));
259439
+ }
259440
+ function parseRetryAfterMs2(value) {
259441
+ if (!value) return void 0;
259442
+ const trimmed = value.trim();
259443
+ if (/^\d+$/.test(trimmed)) return Number(trimmed) * 1e3;
259444
+ const when = Date.parse(trimmed);
259445
+ if (!Number.isNaN(when)) return Math.max(0, when - Date.now());
259446
+ return void 0;
259447
+ }
259335
259448
 
259336
259449
  // src/lib/postman/postman-ec-client.ts
259337
259450
  var EC_WRITE_MAX_ATTEMPTS = 3;
@@ -263945,6 +264058,12 @@ var BOOTSTRAP_BARE_UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9
263945
264058
  function isMissingPatchValueError(error2) {
263946
264059
  return error2 instanceof HttpError && error2.status === 400 && error2.responseBody.includes("Remove operation must point to an existing value");
263947
264060
  }
264061
+ function isRejectedPatchError(error2) {
264062
+ return error2 instanceof HttpError && error2.status === 400 && /REJECTED_PATCH|must update at least one/i.test(
264063
+ `${error2.message}
264064
+ ${error2.responseBody ?? ""}`
264065
+ );
264066
+ }
263948
264067
  function canonicalize(value) {
263949
264068
  if (Array.isArray(value)) return value.map(canonicalize);
263950
264069
  if (value && typeof value === "object") {
@@ -264008,6 +264127,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264008
264127
  static DEFAULT_GENERATION_POLL_DELAY_MS = 2e3;
264009
264128
  gateway;
264010
264129
  sleep;
264130
+ random;
264011
264131
  generationPollAttempts;
264012
264132
  generationPollDelayMs;
264013
264133
  createIdentity;
@@ -264015,6 +264135,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264015
264135
  this.gateway = options.gateway;
264016
264136
  this.createIdentity = options.createIdentity ?? import_node_crypto2.randomUUID;
264017
264137
  this.sleep = options.sleep ?? ((delayMs) => new Promise((resolve5) => setTimeout(resolve5, delayMs)));
264138
+ this.random = options.random ?? Math.random;
264018
264139
  this.generationPollAttempts = resolvePollBudget(
264019
264140
  options.generationPollAttempts,
264020
264141
  process.env.POSTMAN_GENERATION_POLL_ATTEMPTS,
@@ -264072,6 +264193,16 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264072
264193
  if (openapiVersion !== "3.0" && openapiVersion !== "3.1") {
264073
264194
  throw new Error(`uploadSpec: unsupported openapiVersion "${openapiVersion}". Expected '3.0' or '3.1'.`);
264074
264195
  }
264196
+ const before = await this.findSpecificationsByExactName(workspaceId, projectName);
264197
+ const existing = adoptExactMatch(
264198
+ `specification:${workspaceId}:${projectName}`,
264199
+ before,
264200
+ (entry) => entry.id
264201
+ );
264202
+ if (existing) {
264203
+ await this.updateSpec(existing.id, specContent, workspaceId);
264204
+ return existing.id;
264205
+ }
264075
264206
  const specType = openapiVersion === "3.1" ? "OPENAPI:3.1" : "OPENAPI:3.0";
264076
264207
  let created;
264077
264208
  try {
@@ -264096,10 +264227,49 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264096
264227
  if (!match) throw error2;
264097
264228
  created = { data: { id: match.id } };
264098
264229
  }
264099
- const specId = String(asRecord8(created?.data)?.id ?? created?.id ?? "").trim();
264230
+ let specId = String(asRecord8(created?.data)?.id ?? created?.id ?? "").trim();
264100
264231
  if (!specId) {
264101
264232
  throw new Error("Spec upload did not return an ID");
264102
264233
  }
264234
+ let matches = await this.findSpecificationsByExactName(workspaceId, projectName);
264235
+ if (before.length === 0 && matches.length <= 1) {
264236
+ await this.sleep(1e3);
264237
+ const settled = await this.findSpecificationsByExactName(workspaceId, projectName);
264238
+ if (settled.length > 0) matches = settled;
264239
+ }
264240
+ if (matches.length > 1 && before.length === 0) {
264241
+ for (const duplicate of matches.slice(1)) {
264242
+ try {
264243
+ await this.deleteSpecification(duplicate.id);
264244
+ } catch (error2) {
264245
+ if (!(error2 instanceof HttpError && error2.status === 404)) throw error2;
264246
+ }
264247
+ }
264248
+ for (let attempt = 0; attempt < 5; attempt += 1) {
264249
+ matches = await this.findSpecificationsByExactName(workspaceId, projectName);
264250
+ if (matches.length <= 1) break;
264251
+ await this.sleep(250 * (attempt + 1));
264252
+ }
264253
+ const converged = adoptExactMatch(
264254
+ `specification:${workspaceId}:${projectName}`,
264255
+ matches,
264256
+ (entry) => entry.id
264257
+ );
264258
+ if (!converged) {
264259
+ throw new Error(`Concurrent specification create for ${projectName} did not converge`);
264260
+ }
264261
+ specId = converged.id;
264262
+ if (specId !== String(asRecord8(created?.data)?.id ?? created?.id ?? "").trim()) {
264263
+ await this.updateSpec(specId, specContent, workspaceId);
264264
+ }
264265
+ } else {
264266
+ const verified = adoptExactMatch(
264267
+ `specification:${workspaceId}:${projectName}`,
264268
+ matches,
264269
+ (entry) => entry.id
264270
+ );
264271
+ if (verified) specId = verified.id;
264272
+ }
264103
264273
  await this.gateway.requestJson({
264104
264274
  service: "specification",
264105
264275
  method: "get",
@@ -264107,6 +264277,14 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264107
264277
  });
264108
264278
  return specId;
264109
264279
  }
264280
+ async deleteSpecification(specId) {
264281
+ await this.gateway.requestJson({
264282
+ service: "specification",
264283
+ method: "delete",
264284
+ path: `/specifications/${specId}`,
264285
+ retry: "none"
264286
+ });
264287
+ }
264110
264288
  async findSpecificationsByExactName(workspaceId, name) {
264111
264289
  const response = await this.gateway.requestJson({
264112
264290
  service: "specification",
@@ -264170,6 +264348,41 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264170
264348
  return void 0;
264171
264349
  }
264172
264350
  }
264351
+ /**
264352
+ * Native Spec Hub version tags (branch-aware sync P3.5). Tags attach to the
264353
+ * LATEST changelog group; the backend 409s when that group is already tagged
264354
+ * (VersionControlService). Callers handle 409 as idempotent-by-group.
264355
+ */
264356
+ async tagSpecVersion(specId, name) {
264357
+ const trimmed = name.trim().slice(0, 255);
264358
+ const created = await this.gateway.requestJson({
264359
+ service: "specification",
264360
+ method: "post",
264361
+ path: `/specifications/${specId}/tags`,
264362
+ retry: "none",
264363
+ body: { name: trimmed }
264364
+ });
264365
+ const record = asRecord8(created?.data) ?? created ?? {};
264366
+ return {
264367
+ id: String(record.id ?? "").trim(),
264368
+ name: String(record.name ?? trimmed).trim()
264369
+ };
264370
+ }
264371
+ /** List a spec's native version tags (newest first per backend ordering). */
264372
+ async listSpecVersionTags(specId) {
264373
+ const response = await this.gateway.requestJson({
264374
+ service: "specification",
264375
+ method: "get",
264376
+ path: `/specifications/${specId}/tags`,
264377
+ query: { limit: "50" }
264378
+ });
264379
+ const entries = Array.isArray(response?.data) ? response.data : [];
264380
+ return entries.map((value) => asRecord8(value)).filter((value) => value !== null).map((value) => ({
264381
+ id: String(value.id ?? "").trim(),
264382
+ // listTags returns `message`; createTag returns `name`. Accept both.
264383
+ name: String(value.name ?? value.message ?? "").trim()
264384
+ })).filter((value) => value.id || value.name);
264385
+ }
264173
264386
  /** Resolve a specification's ROOT file uuid via the files list. */
264174
264387
  async resolveRootFileId(specId) {
264175
264388
  const files = await this.gateway.requestJson({
@@ -264189,79 +264402,182 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264189
264402
  */
264190
264403
  async generateCollection(specId, projectName, prefix, folderStrategy, nestedFolderHierarchy, requestNameSource) {
264191
264404
  const name = [prefix.trim(), projectName.trim()].filter(Boolean).join(" ");
264192
- const submittedName = `${name} [bootstrap:${this.createIdentity()}]`;
264193
- const body2 = {
264194
- name: submittedName,
264195
- options: {
264196
- requestNameSource,
264197
- folderStrategy,
264198
- ...folderStrategy === "Tags" ? { nestedFolderHierarchy } : {}
264199
- }
264200
- };
264201
264405
  const before = await this.listGeneratedCollectionRefs(specId);
264202
- let taskId;
264203
- try {
264204
- taskId = await this.postGenerationWithLockRetry(specId, body2);
264205
- } catch (error2) {
264206
- if (!isAmbiguousTransportError(error2)) throw error2;
264207
- const beforeIds2 = new Set(before.map((entry) => entry.id));
264208
- const appeared2 = (await this.listGeneratedCollectionRefs(specId)).filter(
264209
- (entry) => !beforeIds2.has(entry.id)
264210
- );
264211
- const exactAppeared = await this.filterGeneratedCollectionsByExactName(
264212
- appeared2,
264406
+ const existing = adoptExactMatch(
264407
+ `generated-collection:${specId}:${name}`,
264408
+ await this.filterGeneratedCollectionsByExactName(before, name),
264409
+ (entry) => entry.id
264410
+ );
264411
+ if (existing) return this.convergeGeneratedCollections(specId, name, existing.id);
264412
+ let lastError;
264413
+ for (let taskAttempt = 0; taskAttempt < 2; taskAttempt += 1) {
264414
+ const submittedName = `${name} [bootstrap:${this.createIdentity()}]`;
264415
+ const body2 = {
264416
+ name: submittedName,
264417
+ options: {
264418
+ requestNameSource,
264419
+ folderStrategy,
264420
+ ...folderStrategy === "Tags" ? { nestedFolderHierarchy } : {}
264421
+ }
264422
+ };
264423
+ let taskId;
264424
+ try {
264425
+ const generation = await this.postGenerationWithLockRetry(specId, body2, name);
264426
+ if (generation.adoptedId) {
264427
+ return this.convergeGeneratedCollections(specId, name, generation.adoptedId);
264428
+ }
264429
+ taskId = generation.taskId ?? "";
264430
+ } catch (error2) {
264431
+ if (!isAmbiguousTransportError(error2)) throw error2;
264432
+ const beforeIds2 = new Set(before.map((entry) => entry.id));
264433
+ const appeared2 = (await this.listGeneratedCollectionRefs(specId)).filter(
264434
+ (entry) => !beforeIds2.has(entry.id)
264435
+ );
264436
+ const exactAppeared = await this.filterGeneratedCollectionsByExactName(
264437
+ appeared2,
264438
+ submittedName
264439
+ );
264440
+ const match = adoptExactMatch(
264441
+ `generated-collection:${specId}:${submittedName}`,
264442
+ exactAppeared,
264443
+ (entry) => entry.id
264444
+ );
264445
+ if (!match) throw error2;
264446
+ await this.renameGeneratedCollection(match.id, name);
264447
+ return this.convergeGeneratedCollections(specId, name, match.id);
264448
+ }
264449
+ let taskFailed = false;
264450
+ if (taskId) {
264451
+ for (let attempt = 0; attempt < this.generationPollAttempts; attempt += 1) {
264452
+ await this.sleep(this.generationPollDelayMs);
264453
+ const task = await this.gateway.requestJson({
264454
+ service: "specification",
264455
+ method: "get",
264456
+ path: "/tasks",
264457
+ query: { entityId: specId, entityType: "specification", type: "collection-generation" }
264458
+ });
264459
+ const status = String(asRecord8(task?.data)?.[taskId] ?? "").toLowerCase();
264460
+ if (status === "failed" || status === "error") {
264461
+ taskFailed = true;
264462
+ lastError = new Error(`Collection generation task failed for ${prefix}`);
264463
+ break;
264464
+ }
264465
+ if (status && status !== "in-progress" && status !== "pending" && status !== "queued") {
264466
+ break;
264467
+ }
264468
+ if (attempt === this.generationPollAttempts - 1) {
264469
+ throw new Error(`Collection generation timed out for ${prefix}`);
264470
+ }
264471
+ }
264472
+ }
264473
+ if (taskFailed) {
264474
+ await this.sleep(1e3 * (taskAttempt + 1));
264475
+ continue;
264476
+ }
264477
+ const beforeIds = new Set(before.map((entry) => entry.id));
264478
+ const after = await this.listGeneratedCollectionRefs(specId);
264479
+ const appeared = after.filter((entry) => !beforeIds.has(entry.id));
264480
+ const candidates = await this.filterGeneratedCollectionsByExactName(
264481
+ appeared,
264213
264482
  submittedName
264214
264483
  );
264215
- const match = adoptExactMatch(
264484
+ const uid = adoptExactMatch(
264216
264485
  `generated-collection:${specId}:${submittedName}`,
264217
- exactAppeared,
264486
+ candidates,
264218
264487
  (entry) => entry.id
264219
- );
264220
- if (!match) throw error2;
264221
- await this.renameGeneratedCollection(match.id, name);
264222
- return match.id;
264488
+ )?.id;
264489
+ if (!uid) {
264490
+ throw new Error(`Collection generation did not yield a collection uid for ${prefix}`);
264491
+ }
264492
+ await this.renameGeneratedCollection(uid, name);
264493
+ return this.convergeGeneratedCollections(specId, name, uid);
264223
264494
  }
264224
- if (taskId) {
264225
- for (let attempt = 0; attempt < this.generationPollAttempts; attempt += 1) {
264226
- await this.sleep(this.generationPollDelayMs);
264227
- const task = await this.gateway.requestJson({
264228
- service: "specification",
264229
- method: "get",
264230
- path: "/tasks",
264231
- query: { entityId: specId, entityType: "specification", type: "collection-generation" }
264232
- });
264233
- const status = String(asRecord8(task?.data)?.[taskId] ?? "").toLowerCase();
264234
- if (status === "failed" || status === "error") {
264235
- throw new Error(`Collection generation task failed for ${prefix}`);
264236
- }
264237
- if (status && status !== "in-progress" && status !== "pending" && status !== "queued") {
264238
- break;
264239
- }
264240
- if (attempt === this.generationPollAttempts - 1) {
264241
- throw new Error(`Collection generation timed out for ${prefix}`);
264495
+ throw lastError ?? new Error(`Collection generation task failed for ${prefix}`);
264496
+ }
264497
+ /**
264498
+ * Re-elect the durable generated collection for a final name. Call after
264499
+ * concurrent dual-trigger generates and before description/inject/tag so a
264500
+ * peer orphan-sweep cannot leave this runner holding a deleted id.
264501
+ */
264502
+ async adoptGeneratedCollection(specId, projectName, prefix, preferredId = "") {
264503
+ const name = [prefix.trim(), projectName.trim()].filter(Boolean).join(" ");
264504
+ return this.convergeGeneratedCollections(specId, name, preferredId);
264505
+ }
264506
+ /**
264507
+ * Concurrent dual-trigger previews can each generate+rename the same final
264508
+ * collection identity. Elect the stable lowest-id winner.
264509
+ *
264510
+ * Losers only delete *their own* preferred collection (never a peer's still-
264511
+ * in-use id). Winners wait briefly for peers to self-delete, then clean any
264512
+ * leftover same-identity orphans (temps + extra finals).
264513
+ */
264514
+ async convergeGeneratedCollections(specId, finalName, preferredId) {
264515
+ const tempPrefix = `${finalName} [bootstrap:`;
264516
+ const hydrate = async () => {
264517
+ const linked = await this.listGeneratedCollectionRefs(specId);
264518
+ return Promise.all(
264519
+ linked.map(async (entry) => {
264520
+ if (entry.name) return { id: entry.id, name: entry.name };
264521
+ try {
264522
+ const collection = await this.gateway.requestJson({
264523
+ service: "collection",
264524
+ method: "get",
264525
+ path: `/v3/collections/${this.bareModelId(entry.id)}`
264526
+ });
264527
+ return {
264528
+ id: entry.id,
264529
+ name: String(asRecord8(collection?.data)?.name ?? "").trim()
264530
+ };
264531
+ } catch (error2) {
264532
+ if (error2 instanceof HttpError && error2.status === 404) {
264533
+ return { id: entry.id, name: "" };
264534
+ }
264535
+ throw error2;
264536
+ }
264537
+ })
264538
+ );
264539
+ };
264540
+ const selectSameIdentity = (entries) => entries.filter(
264541
+ (entry) => entry.name === finalName || entry.name.startsWith(tempPrefix)
264542
+ ).sort((a, b) => a.id.localeCompare(b.id));
264543
+ let sameIdentity = selectSameIdentity(await hydrate());
264544
+ if (sameIdentity.length === 0) return preferredId;
264545
+ if (sameIdentity.length === 1) {
264546
+ await this.sleep(1e3);
264547
+ sameIdentity = selectSameIdentity(await hydrate());
264548
+ if (sameIdentity.length === 0) return preferredId;
264549
+ }
264550
+ const winner = sameIdentity[0];
264551
+ if (winner.name !== finalName) {
264552
+ await this.renameGeneratedCollection(winner.id, finalName);
264553
+ }
264554
+ if (preferredId && preferredId !== winner.id) {
264555
+ const own = sameIdentity.find((entry) => entry.id === preferredId);
264556
+ if (own) {
264557
+ try {
264558
+ await this.deleteCollection(preferredId);
264559
+ } catch (error2) {
264560
+ if (!(error2 instanceof HttpError && error2.status === 404)) throw error2;
264242
264561
  }
264243
264562
  }
264563
+ return winner.id;
264244
264564
  }
264245
- const beforeIds = new Set(before.map((entry) => entry.id));
264246
- const after = await this.listGeneratedCollectionRefs(specId);
264247
- const appeared = after.filter((entry) => !beforeIds.has(entry.id));
264248
- const candidates = await this.filterGeneratedCollectionsByExactName(
264249
- appeared,
264250
- submittedName
264251
- );
264252
- const uid = adoptExactMatch(
264253
- `generated-collection:${specId}:${submittedName}`,
264254
- candidates,
264255
- (entry) => entry.id
264256
- )?.id;
264257
- if (!uid) {
264258
- throw new Error(`Collection generation did not yield a collection uid for ${prefix}`);
264565
+ if (sameIdentity.length > 1) {
264566
+ await this.sleep(1500);
264567
+ sameIdentity = selectSameIdentity(await hydrate());
264568
+ for (const duplicate of sameIdentity) {
264569
+ if (duplicate.id === winner.id) continue;
264570
+ try {
264571
+ await this.deleteCollection(duplicate.id);
264572
+ } catch (error2) {
264573
+ if (!(error2 instanceof HttpError && error2.status === 404)) throw error2;
264574
+ }
264575
+ }
264259
264576
  }
264260
- await this.renameGeneratedCollection(uid, name);
264261
- return uid;
264577
+ return winner.id;
264262
264578
  }
264263
264579
  /** POST the generation request, retrying a 423-locked spec; returns the task id. */
264264
- async postGenerationWithLockRetry(specId, body2) {
264580
+ async postGenerationWithLockRetry(specId, body2, finalName) {
264265
264581
  for (let lockedAttempt = 0; ; lockedAttempt += 1) {
264266
264582
  try {
264267
264583
  const created = await this.gateway.requestJson({
@@ -264271,13 +264587,22 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264271
264587
  retry: "none",
264272
264588
  body: body2
264273
264589
  });
264274
- return String(asRecord8(created?.data)?.taskId ?? "").trim();
264590
+ return { taskId: String(asRecord8(created?.data)?.taskId ?? "").trim() };
264275
264591
  } catch (error2) {
264276
264592
  const locked = error2 instanceof HttpError && error2.status === 423;
264277
264593
  if (!locked || lockedAttempt >= _PostmanGatewayAssetsClient.GENERATION_LOCKED_MAX_RETRIES) {
264278
264594
  throw error2;
264279
264595
  }
264280
264596
  await this.sleep(5e3 * Math.pow(2, lockedAttempt));
264597
+ const adopted = adoptExactMatch(
264598
+ `generated-collection:${specId}:${finalName}`,
264599
+ await this.filterGeneratedCollectionsByExactName(
264600
+ await this.listGeneratedCollectionRefs(specId),
264601
+ finalName
264602
+ ),
264603
+ (entry) => entry.id
264604
+ );
264605
+ if (adopted) return { adoptedId: adopted.id };
264281
264606
  }
264282
264607
  }
264283
264608
  }
@@ -264314,14 +264639,24 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264314
264639
  return hydrated.filter((entry) => entry.name === expectedName);
264315
264640
  }
264316
264641
  async renameGeneratedCollection(collectionId, name) {
264317
- await this.gateway.requestJson({
264318
- service: "collection",
264319
- method: "patch",
264320
- path: `/v3/collections/${this.bareModelId(collectionId)}`,
264321
- // Replacing a generated collection's name with the same value is idempotent.
264322
- retry: "safe",
264323
- body: [{ op: "replace", path: "/name", value: name }]
264324
- });
264642
+ try {
264643
+ await this.gateway.requestJson({
264644
+ service: "collection",
264645
+ method: "patch",
264646
+ path: `/v3/collections/${this.bareModelId(collectionId)}`,
264647
+ // Replacing a generated collection's name with the same value is idempotent.
264648
+ retry: "safe",
264649
+ body: [{ op: "replace", path: "/name", value: name }]
264650
+ });
264651
+ } catch (error2) {
264652
+ if (error2 instanceof HttpError && error2.status === 400 && /must update at least one|REJECTED_PATCH/i.test(
264653
+ `${error2.message}
264654
+ ${error2.responseBody ?? ""}`
264655
+ )) {
264656
+ return;
264657
+ }
264658
+ throw error2;
264659
+ }
264325
264660
  }
264326
264661
  /**
264327
264662
  * Create a team-visible workspace through the gateway workspaces service.
@@ -264575,7 +264910,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264575
264910
  if (!retriable || attempt === maxAttempts - 1) {
264576
264911
  throw error2;
264577
264912
  }
264578
- await this.sleep(Math.min(2e3, 300 * 2 ** attempt));
264913
+ await this.sleep(fullJitterDelayMs(attempt, 300, 2e3, this.random));
264579
264914
  }
264580
264915
  }
264581
264916
  }
@@ -264596,6 +264931,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264596
264931
  service: "tagging",
264597
264932
  method: "put",
264598
264933
  path: `/v1/tags/collections/${collectionUid}`,
264934
+ retry: "safe",
264599
264935
  body: { tags: normalized.map((slug) => ({ slug })) }
264600
264936
  });
264601
264937
  }
@@ -264825,14 +265161,19 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
264825
265161
  { type: "afterResponse", code: exec2.join("\n"), language: "text/javascript" }
264826
265162
  ];
264827
265163
  for (const script of plan.scripts) {
264828
- await this.gateway.requestJson({
264829
- service: "collection",
264830
- method: "patch",
264831
- path: `/v3/collections/${cid}/items/${script.itemId}`,
264832
- retry: "safe",
264833
- headers: { "X-Entity-Type": "http-request" },
264834
- body: [{ op: "add", path: "/scripts", value: toV3Scripts(script.exec) }]
264835
- });
265164
+ try {
265165
+ await this.gateway.requestJson({
265166
+ service: "collection",
265167
+ method: "patch",
265168
+ path: `/v3/collections/${cid}/items/${script.itemId}`,
265169
+ retry: "safe",
265170
+ headers: { "X-Entity-Type": "http-request" },
265171
+ body: [{ op: "add", path: "/scripts", value: toV3Scripts(script.exec) }]
265172
+ });
265173
+ } catch (error2) {
265174
+ if (isRejectedPatchError(error2)) continue;
265175
+ throw error2;
265176
+ }
264836
265177
  }
264837
265178
  if (!items.some((i) => String(i.name ?? "") === "00 - Resolve Secrets")) {
264838
265179
  const created = await this.gateway.requestJson({
@@ -265037,36 +265378,47 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
265037
265378
  async createItemTree(cid, items, parentId) {
265038
265379
  for (const item of items) {
265039
265380
  const kind = String(item.$kind ?? "http-request");
265040
- let created;
265041
- try {
265042
- created = await this.gateway.requestJson({
265043
- service: "collection",
265044
- method: "post",
265045
- path: `/v3/collections/${cid}/items/`,
265046
- retry: "none",
265047
- headers: { "X-Entity-Type": kind },
265048
- body: this.buildItemCreateBody(item, parentId)
265049
- });
265050
- } catch (error2) {
265051
- if (!isAmbiguousTransportError(error2)) throw error2;
265052
- const name = String(item.name ?? "Untitled");
265053
- const matches = (await this.listCollectionItems(cid)).filter((candidate) => {
265054
- if (String(candidate.name ?? candidate.title ?? "") !== name) return false;
265055
- if (String(candidate.$kind ?? candidate.type ?? "http-request") !== kind) return false;
265056
- const position = asRecord8(candidate.position);
265057
- const parent = asRecord8(position?.parent);
265058
- const candidateParent = String(parent?.id ?? position?.parent ?? candidate.parent ?? "").trim();
265059
- return Boolean(candidateParent) && this.bareModelId(candidateParent) === this.bareModelId(parentId);
265060
- });
265061
- const match = adoptExactMatch(
265062
- `collection-item:${cid}:${parentId}:${kind}:${name}`,
265063
- matches,
265064
- (candidate) => String(candidate.id ?? "")
265065
- );
265066
- if (!match) throw error2;
265067
- created = { data: { id: match.id } };
265381
+ const maxAttempts = 4;
265382
+ let newId = "";
265383
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
265384
+ let created;
265385
+ try {
265386
+ created = await this.gateway.requestJson({
265387
+ service: "collection",
265388
+ method: "post",
265389
+ path: `/v3/collections/${cid}/items/`,
265390
+ retry: "none",
265391
+ headers: { "X-Entity-Type": kind },
265392
+ body: this.buildItemCreateBody(item, parentId)
265393
+ });
265394
+ } catch (error2) {
265395
+ if (!isAmbiguousTransportError(error2)) throw error2;
265396
+ const name = String(item.name ?? "Untitled");
265397
+ const matches = (await this.listCollectionItems(cid)).filter((candidate) => {
265398
+ if (String(candidate.name ?? candidate.title ?? "") !== name) return false;
265399
+ if (String(candidate.$kind ?? candidate.type ?? "http-request") !== kind) return false;
265400
+ const position = asRecord8(candidate.position);
265401
+ const parent = asRecord8(position?.parent);
265402
+ const candidateParent = String(parent?.id ?? position?.parent ?? candidate.parent ?? "").trim();
265403
+ return Boolean(candidateParent) && this.bareModelId(candidateParent) === this.bareModelId(parentId);
265404
+ });
265405
+ const match = adoptExactMatch(
265406
+ `collection-item:${cid}:${parentId}:${kind}:${name}`,
265407
+ matches,
265408
+ (candidate) => String(candidate.id ?? "")
265409
+ );
265410
+ if (match) {
265411
+ created = { data: { id: match.id } };
265412
+ } else {
265413
+ const retriable = error2 instanceof HttpError && error2.status >= 500;
265414
+ if (!retriable || attempt === maxAttempts) throw error2;
265415
+ await this.sleep(fullJitterDelayMs(attempt - 1, 300, 2e3, this.random));
265416
+ continue;
265417
+ }
265418
+ }
265419
+ newId = String(asRecord8(created?.data)?.id ?? "").trim();
265420
+ if (newId) break;
265068
265421
  }
265069
- const newId = String(asRecord8(created?.data)?.id ?? "").trim();
265070
265422
  if (!newId) {
265071
265423
  throw new Error(
265072
265424
  `Item create did not return an id for ${String(item.name ?? "item")}`
@@ -265109,6 +265461,30 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
265109
265461
  * - `remove` of /description always works (field exists as "")
265110
265462
  * - on update, GET the root first and only remove fields that currently exist
265111
265463
  */
265464
+ /**
265465
+ * GET a collection root, retrying through the v3 surface's read-after-write
265466
+ * 404 lag. A freshly generated/renamed collection can transiently report
265467
+ * RESOURCE_NOT_FOUND for a few seconds (worse under concurrent runner load);
265468
+ * retrying absorbs that instead of hard-failing the run.
265469
+ */
265470
+ async getCollectionRoot(cid) {
265471
+ const got = await retry(
265472
+ () => this.gateway.requestJson({
265473
+ service: "collection",
265474
+ method: "get",
265475
+ path: `/v3/collections/${cid}`,
265476
+ retry: "none"
265477
+ }),
265478
+ {
265479
+ maxAttempts: 6,
265480
+ delayMs: 1e3,
265481
+ backoffMultiplier: 2,
265482
+ maxDelayMs: 8e3,
265483
+ shouldRetry: (error2) => error2 instanceof HttpError && error2.status === 404
265484
+ }
265485
+ );
265486
+ return asRecord8(got?.data);
265487
+ }
265112
265488
  async applyCollectionLevelSettings(cid, v3, options = {}) {
265113
265489
  const ops = [];
265114
265490
  if (options.rename && typeof v3.name === "string" && v3.name) {
@@ -265116,12 +265492,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
265116
265492
  }
265117
265493
  let current = null;
265118
265494
  if (options.reconcileRemovals) {
265119
- const got = await this.gateway.requestJson({
265120
- service: "collection",
265121
- method: "get",
265122
- path: `/v3/collections/${cid}`
265123
- });
265124
- current = asRecord8(got?.data);
265495
+ current = await this.getCollectionRoot(cid);
265125
265496
  }
265126
265497
  const hasDescription = typeof v3.description === "string" && v3.description.length > 0;
265127
265498
  if (hasDescription) {
@@ -265160,6 +265531,9 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
265160
265531
  if (isMissingPatchValueError(error2) && ops.some((op) => op.op === "remove") && await this.verifyRootSettingsApplied(cid, ops)) {
265161
265532
  return;
265162
265533
  }
265534
+ if (isRejectedPatchError(error2) && await this.verifyRootSettingsApplied(cid, ops)) {
265535
+ return;
265536
+ }
265163
265537
  throw error2;
265164
265538
  }
265165
265539
  }
@@ -265222,6 +265596,15 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
265222
265596
  async createCollection(workspaceId, collection, options = {}) {
265223
265597
  const v3 = this.normalizeCollectionForWrite(collection);
265224
265598
  const desiredName = String(v3.name ?? "Untitled Collection");
265599
+ const existing = adoptExactMatch(
265600
+ `collection:${workspaceId}:${desiredName}`,
265601
+ await this.findCollectionsByExactName(workspaceId, desiredName),
265602
+ (entry) => entry.id
265603
+ );
265604
+ if (existing) {
265605
+ await this.updateCollection(existing.id, collection);
265606
+ return existing.id;
265607
+ }
265225
265608
  const submittedName = `${desiredName} [bootstrap:${this.createIdentity()}]`;
265226
265609
  const rootBody = { name: submittedName };
265227
265610
  let created;
@@ -265272,6 +265655,12 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
265272
265655
  }
265273
265656
  return rawId;
265274
265657
  }
265658
+ /** Patch only the durable collection description without reconciling its item tree. */
265659
+ async updateCollectionDescription(collectionUid, description) {
265660
+ const cid = this.bareModelId(collectionUid);
265661
+ await this.getCollectionRoot(cid);
265662
+ await this.applyCollectionLevelSettings(cid, { description });
265663
+ }
265275
265664
  /**
265276
265665
  * Full-replace reconcile of a curated local v2.1.0 or collection v3 payload: delete every
265277
265666
  * root-level item (deleting a folder cascades its children server-side —
@@ -265353,6 +265742,7 @@ function detectInnerError(body2) {
265353
265742
  return typeof innerStatus === "number" && innerStatus >= 400 ? innerStatus : 502;
265354
265743
  }
265355
265744
  function isTransientGatewayError(status, body2) {
265745
+ if (status === 429) return true;
265356
265746
  if (status === 502 || status === 503 || status === 504) return true;
265357
265747
  if (status >= 500 && (body2.includes("ESOCKETTIMEDOUT") || body2.includes("ETIMEDOUT") || body2.includes("ECONNRESET") || body2.includes("serverError") || body2.includes("downstream"))) {
265358
265748
  return true;
@@ -265371,8 +265761,10 @@ var AccessTokenGatewayClient = class {
265371
265761
  secretMasker;
265372
265762
  maxRetries;
265373
265763
  retryBaseDelayMs;
265764
+ retryMaxDelayMs;
265374
265765
  requestTimeoutMs;
265375
265766
  sleepImpl;
265767
+ randomImpl;
265376
265768
  constructor(options) {
265377
265769
  this.tokenProvider = options.tokenProvider;
265378
265770
  this.bifrostBaseUrl = String(
@@ -265384,8 +265776,10 @@ var AccessTokenGatewayClient = class {
265384
265776
  this.secretMasker = options.secretMasker ?? createSecretMasker([this.tokenProvider.current()]);
265385
265777
  this.maxRetries = options.maxRetries ?? 3;
265386
265778
  this.retryBaseDelayMs = options.retryBaseDelayMs ?? 400;
265779
+ this.retryMaxDelayMs = options.retryMaxDelayMs ?? 5e3;
265387
265780
  this.requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
265388
265781
  this.sleepImpl = options.sleepImpl ?? defaultSleep;
265782
+ this.randomImpl = options.randomImpl ?? Math.random;
265389
265783
  }
265390
265784
  configureTeamContext(teamId, orgMode) {
265391
265785
  this.teamId = String(teamId || "").trim();
@@ -265445,7 +265839,7 @@ var AccessTokenGatewayClient = class {
265445
265839
  response = await this.send(request);
265446
265840
  } catch (error2) {
265447
265841
  if (retryMode === "safe" && attempt < this.maxRetries) {
265448
- const delay = this.retryBaseDelayMs * 2 ** attempt;
265842
+ const delay = this.retryDelayMs(attempt);
265449
265843
  attempt += 1;
265450
265844
  await this.sleepImpl(delay);
265451
265845
  continue;
@@ -265457,7 +265851,7 @@ var AccessTokenGatewayClient = class {
265457
265851
  const innerStatus = detectInnerError(okBody);
265458
265852
  if (innerStatus !== null) {
265459
265853
  if (retryMode === "safe" && isTransientGatewayError(innerStatus, okBody) && attempt < this.maxRetries) {
265460
- const delay = this.retryBaseDelayMs * 2 ** attempt;
265854
+ const delay = this.retryDelayMs(attempt);
265461
265855
  attempt += 1;
265462
265856
  await this.sleepImpl(delay);
265463
265857
  continue;
@@ -265482,7 +265876,10 @@ var AccessTokenGatewayClient = class {
265482
265876
  throw this.toHttpError(request, response, retryBody);
265483
265877
  }
265484
265878
  if (retryMode === "safe" && isTransientGatewayError(response.status, body2) && attempt < this.maxRetries) {
265485
- const delay = this.retryBaseDelayMs * 2 ** attempt;
265879
+ const delay = this.retryDelayMs(
265880
+ attempt,
265881
+ parseRetryAfterMs2(response.headers.get("retry-after"))
265882
+ );
265486
265883
  attempt += 1;
265487
265884
  await this.sleepImpl(delay);
265488
265885
  continue;
@@ -265490,13 +265887,26 @@ var AccessTokenGatewayClient = class {
265490
265887
  throw this.toHttpError(request, response, body2);
265491
265888
  }
265492
265889
  }
265890
+ /**
265891
+ * Full-jitter backoff (uniform in [0, min(cap, base * 2^attempt))) so
265892
+ * concurrent CI runners that fail together never retry in lockstep against
265893
+ * the shared gateway. A server-sent Retry-After beats the heuristic: it is
265894
+ * authoritative backpressure, honored verbatim (capped by the ceiling).
265895
+ */
265896
+ retryDelayMs(attempt, retryAfterMs) {
265897
+ if (retryAfterMs !== void 0) {
265898
+ return Math.min(this.retryMaxDelayMs, retryAfterMs);
265899
+ }
265900
+ return fullJitterDelayMs(attempt, this.retryBaseDelayMs, this.retryMaxDelayMs, this.randomImpl);
265901
+ }
265493
265902
  /**
265494
265903
  * The success path reads the body to inspect for an inner error, which
265495
265904
  * consumes the stream. Hand callers a fresh Response over the buffered text so
265496
265905
  * `requestJson` can still parse it.
265497
265906
  */
265498
265907
  rebuildResponse(response, body2) {
265499
- return new Response(body2, {
265908
+ const nullBody = response.status === 204 || response.status === 205 || response.status === 304;
265909
+ return new Response(nullBody ? null : body2, {
265500
265910
  status: response.status,
265501
265911
  statusText: response.statusText,
265502
265912
  headers: response.headers
@@ -266226,6 +266636,9 @@ function createTelemetryContext(options) {
266226
266636
  var import_node_fs3 = require("node:fs");
266227
266637
  var import_node_path3 = require("node:path");
266228
266638
  function resolveActionVersion2() {
266639
+ if (false) {
266640
+ return void 0;
266641
+ }
266229
266642
  try {
266230
266643
  const raw = (0, import_node_fs3.readFileSync)((0, import_node_path3.join)(__dirname, "..", "package.json"), "utf8");
266231
266644
  return JSON.parse(raw).version ?? "unknown";
@@ -281948,6 +282361,61 @@ function serializeOpenApiDocument(document2) {
281948
282361
  return `${JSON.stringify(document2, null, 2)}
281949
282362
  `;
281950
282363
  }
282364
+ function typeNullPath(pathSegments) {
282365
+ return pathSegments.map(String).join(".");
282366
+ }
282367
+ function isNullOnlySchema(value) {
282368
+ const record = asRecord10(value);
282369
+ if (!record || record.type !== "null") return false;
282370
+ return Object.keys(record).every((key) => key === "type" || key.startsWith("x-"));
282371
+ }
282372
+ function createOas30TypeNullCompatibilityDocument(sourceDocument) {
282373
+ const document2 = structuredClone(sourceDocument);
282374
+ const sourceTypeNullPaths = [];
282375
+ const visit4 = (value, pathSegments) => {
282376
+ if (Array.isArray(value)) {
282377
+ value.forEach((entry, index) => visit4(entry, [...pathSegments, index]));
282378
+ return;
282379
+ }
282380
+ const record = asRecord10(value);
282381
+ if (!record) return;
282382
+ const oneOf = Array.isArray(record.oneOf) ? record.oneOf : void 0;
282383
+ const nullIndexes = oneOf ? oneOf.flatMap((entry, index) => isNullOnlySchema(entry) ? [index] : []) : [];
282384
+ if (nullIndexes.length > 0) {
282385
+ if (oneOf?.length !== 2 || nullIndexes.length !== 1) {
282386
+ throw new Error(
282387
+ `CONTRACT_OAS30_TYPE_NULL_UNSUPPORTED: ${typeNullPath(pathSegments)} must use oneOf with exactly one null-only member and one non-null schema`
282388
+ );
282389
+ }
282390
+ const nullIndex = nullIndexes[0];
282391
+ const nonNullIndex = nullIndex === 0 ? 1 : 0;
282392
+ const nonNullSchema = asRecord10(oneOf[nonNullIndex]);
282393
+ if (!nonNullSchema || nonNullSchema.type === "null") {
282394
+ throw new Error(
282395
+ `CONTRACT_OAS30_TYPE_NULL_UNSUPPORTED: ${typeNullPath(pathSegments)} must pair the null-only member with one non-null schema`
282396
+ );
282397
+ }
282398
+ const siblings = Object.fromEntries(
282399
+ Object.entries(record).filter(([key]) => key !== "oneOf")
282400
+ );
282401
+ for (const key of Object.keys(record)) delete record[key];
282402
+ Object.assign(record, structuredClone(nonNullSchema), siblings, { nullable: true });
282403
+ sourceTypeNullPaths.push(typeNullPath([...pathSegments, "oneOf", nullIndex, "type"]));
282404
+ visit4(record, pathSegments);
282405
+ return;
282406
+ }
282407
+ if (record.type === "null") {
282408
+ throw new Error(
282409
+ `CONTRACT_OAS30_TYPE_NULL_UNSUPPORTED: ${typeNullPath([...pathSegments, "type"])} is not a supported nullable oneOf member`
282410
+ );
282411
+ }
282412
+ for (const [key, child4] of Object.entries(record)) {
282413
+ visit4(child4, [...pathSegments, key]);
282414
+ }
282415
+ };
282416
+ visit4(document2, []);
282417
+ return { document: document2, sourceTypeNullPaths };
282418
+ }
281951
282419
  async function bundleSpec(baseUrl, document2, options) {
281952
282420
  const budget = options.budget ?? { refs: 0, totalBytes: Buffer.byteLength(JSON.stringify(document2), "utf8") };
281953
282421
  const fetchText = options.fetchText ?? safeFetchText;
@@ -281989,7 +282457,14 @@ function createCachedFetchText(options) {
281989
282457
  async function buildLoadedSpec(content, baseRef, options, fetchText, budget) {
281990
282458
  const document2 = parseOpenApiDocument(content);
281991
282459
  const version = detectOpenApiVersion2(document2);
281992
- const bundledDocument = await bundleSpec(baseRef, document2, { ...options, budget, fetchText });
282460
+ let contractDocument = document2;
282461
+ let sourceTypeNullPaths = [];
282462
+ if (options.preserveOas30TypeNull && version === "3.0") {
282463
+ const compatibility = createOas30TypeNullCompatibilityDocument(document2);
282464
+ contractDocument = compatibility.document;
282465
+ sourceTypeNullPaths = compatibility.sourceTypeNullPaths;
282466
+ }
282467
+ const bundledDocument = await bundleSpec(baseRef, contractDocument, { ...options, budget, fetchText });
281993
282468
  const validation = await validate(bundledDocument, {
281994
282469
  resolve: { external: false, file: false },
281995
282470
  dereference: { circular: "ignore" },
@@ -282003,6 +282478,7 @@ async function buildLoadedSpec(content, baseRef, options, fetchText, budget) {
282003
282478
  bundledDocument,
282004
282479
  contractIndex: buildContractIndex(bundledDocument),
282005
282480
  content,
282481
+ sourceTypeNullPaths,
282006
282482
  version
282007
282483
  };
282008
282484
  }
@@ -282128,6 +282604,309 @@ function looksLikeIntrospection(record) {
282128
282604
  return Boolean(data && typeof data === "object" && data.__schema);
282129
282605
  }
282130
282606
 
282607
+ // src/lib/repo/branch-decision.ts
282608
+ var import_node_fs5 = require("node:fs");
282609
+ var import_node_crypto4 = require("node:crypto");
282610
+ var ContractError = class extends Error {
282611
+ code;
282612
+ constructor(code, message) {
282613
+ super(`${code}: ${message}`);
282614
+ this.code = code;
282615
+ this.name = "ContractError";
282616
+ }
282617
+ };
282618
+ function clean(value) {
282619
+ const trimmed = (value ?? "").trim();
282620
+ return trimmed.length > 0 ? trimmed : void 0;
282621
+ }
282622
+ function stripRefPrefix(ref) {
282623
+ const raw = clean(ref);
282624
+ if (!raw) {
282625
+ return { kind: "unknown" };
282626
+ }
282627
+ if (raw.startsWith("refs/heads/")) {
282628
+ return { name: raw.slice("refs/heads/".length), kind: "branch" };
282629
+ }
282630
+ if (raw.startsWith("refs/tags/")) {
282631
+ return { name: raw.slice("refs/tags/".length), kind: "tag" };
282632
+ }
282633
+ if (raw.startsWith("refs/pull/") || raw.startsWith("refs/merge")) {
282634
+ return { kind: "unknown" };
282635
+ }
282636
+ return { name: raw, kind: "branch" };
282637
+ }
282638
+ function detectProvider(env) {
282639
+ if (clean(env.GITHUB_ACTIONS) || clean(env.GITHUB_REPOSITORY)) return "github";
282640
+ if (clean(env.GITLAB_CI) || clean(env.CI_PROJECT_PATH)) return "gitlab";
282641
+ if (clean(env.BITBUCKET_REPO_SLUG) || clean(env.BITBUCKET_BRANCH)) return "bitbucket";
282642
+ if (clean(env.TF_BUILD) || clean(env.BUILD_REPOSITORY_URI)) return "azure-devops";
282643
+ return "unknown";
282644
+ }
282645
+ function readGithubEvent(env) {
282646
+ const path10 = clean(env.GITHUB_EVENT_PATH);
282647
+ if (!path10) return void 0;
282648
+ try {
282649
+ return JSON.parse((0, import_node_fs5.readFileSync)(path10, "utf8"));
282650
+ } catch {
282651
+ return void 0;
282652
+ }
282653
+ }
282654
+ function resolveBranchIdentity(env = process.env, overrides = {}) {
282655
+ const provider = detectProvider(env);
282656
+ const explicitDefault = clean(overrides.defaultBranch);
282657
+ let headBranch;
282658
+ let rawRef;
282659
+ let refKind;
282660
+ let isPrContext = false;
282661
+ let isForkPr = false;
282662
+ let defaultBranch = explicitDefault;
282663
+ let headSha;
282664
+ switch (provider) {
282665
+ case "github": {
282666
+ const event2 = readGithubEvent(env);
282667
+ headSha = clean(env.GITHUB_SHA);
282668
+ defaultBranch ??= clean(event2?.repository?.default_branch);
282669
+ const headRef = clean(env.GITHUB_HEAD_REF);
282670
+ if (headRef) {
282671
+ isPrContext = true;
282672
+ headBranch = headRef;
282673
+ rawRef = clean(env.GITHUB_REF) ?? headRef;
282674
+ refKind = "branch";
282675
+ const headRepo = event2?.pull_request?.head?.repo?.full_name;
282676
+ const baseRepo = event2?.pull_request?.base?.repo?.full_name ?? event2?.repository?.full_name;
282677
+ isForkPr = Boolean(headRepo && baseRepo && headRepo !== baseRepo);
282678
+ headSha = clean(event2?.pull_request?.head?.sha) ?? headSha;
282679
+ } else {
282680
+ rawRef = clean(env.GITHUB_REF) ?? clean(env.GITHUB_REF_NAME);
282681
+ const parsed = stripRefPrefix(rawRef);
282682
+ headBranch = parsed.kind === "branch" ? parsed.name : void 0;
282683
+ refKind = parsed.kind;
282684
+ }
282685
+ break;
282686
+ }
282687
+ case "gitlab": {
282688
+ headSha = clean(env.CI_COMMIT_SHA);
282689
+ defaultBranch ??= clean(env.CI_DEFAULT_BRANCH);
282690
+ const mrSource = clean(env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME);
282691
+ if (mrSource) {
282692
+ isPrContext = true;
282693
+ headBranch = mrSource;
282694
+ rawRef = mrSource;
282695
+ refKind = "branch";
282696
+ const sourceProject = clean(env.CI_MERGE_REQUEST_SOURCE_PROJECT_ID);
282697
+ const targetProject = clean(env.CI_MERGE_REQUEST_PROJECT_ID);
282698
+ isForkPr = Boolean(sourceProject && targetProject && sourceProject !== targetProject);
282699
+ } else if (clean(env.CI_COMMIT_TAG)) {
282700
+ rawRef = clean(env.CI_COMMIT_TAG);
282701
+ refKind = "tag";
282702
+ } else {
282703
+ headBranch = clean(env.CI_COMMIT_BRANCH) ?? clean(env.CI_COMMIT_REF_NAME);
282704
+ rawRef = headBranch;
282705
+ refKind = headBranch ? "branch" : "unknown";
282706
+ }
282707
+ break;
282708
+ }
282709
+ case "bitbucket": {
282710
+ headSha = clean(env.BITBUCKET_COMMIT);
282711
+ if (clean(env.BITBUCKET_TAG)) {
282712
+ rawRef = clean(env.BITBUCKET_TAG);
282713
+ refKind = "tag";
282714
+ } else {
282715
+ headBranch = clean(env.BITBUCKET_BRANCH);
282716
+ rawRef = headBranch;
282717
+ refKind = headBranch ? "branch" : "unknown";
282718
+ isPrContext = Boolean(clean(env.BITBUCKET_PR_ID));
282719
+ }
282720
+ break;
282721
+ }
282722
+ case "azure-devops": {
282723
+ headSha = clean(env.BUILD_SOURCEVERSION);
282724
+ const prSource = clean(env.SYSTEM_PULLREQUEST_SOURCEBRANCH);
282725
+ if (prSource) {
282726
+ isPrContext = true;
282727
+ const parsed = stripRefPrefix(prSource);
282728
+ headBranch = parsed.kind === "branch" ? parsed.name : void 0;
282729
+ rawRef = prSource;
282730
+ refKind = parsed.kind;
282731
+ const forkFlag = clean(env.SYSTEM_PULLREQUEST_ISFORK);
282732
+ isForkPr = forkFlag?.toLowerCase() === "true";
282733
+ } else {
282734
+ rawRef = clean(env.BUILD_SOURCEBRANCH);
282735
+ const parsed = stripRefPrefix(rawRef);
282736
+ headBranch = parsed.kind === "branch" ? parsed.name : void 0;
282737
+ refKind = parsed.kind;
282738
+ }
282739
+ break;
282740
+ }
282741
+ default: {
282742
+ refKind = "unknown";
282743
+ }
282744
+ }
282745
+ if (refKind === "branch" && headBranch && defaultBranch && headBranch === defaultBranch) {
282746
+ refKind = "default-branch";
282747
+ }
282748
+ return { provider, headBranch, rawRef, defaultBranch, refKind, isPrContext, isForkPr, headSha };
282749
+ }
282750
+ function parseChannelRules(input) {
282751
+ const raw = clean(input);
282752
+ const rules = [];
282753
+ for (const part of raw ? raw.split(",") : []) {
282754
+ const entry = part.trim();
282755
+ if (!entry) continue;
282756
+ const eq = entry.indexOf("=");
282757
+ if (eq <= 0 || eq === entry.length - 1) {
282758
+ throw new ContractError(
282759
+ "CONTRACT_CHANNELS_INPUT_INVALID",
282760
+ `channels entry "${entry}" must be <branch-or-glob>=<CODE>`
282761
+ );
282762
+ }
282763
+ const pattern = entry.slice(0, eq).trim();
282764
+ const code = entry.slice(eq + 1).trim().toUpperCase();
282765
+ if (!/^[A-Z][A-Z0-9_-]{0,15}$/.test(code)) {
282766
+ throw new ContractError(
282767
+ "CONTRACT_CHANNELS_INPUT_INVALID",
282768
+ `channel code "${code}" must be 1-16 chars, A-Z 0-9 _ -, starting with a letter`
282769
+ );
282770
+ }
282771
+ rules.push({ pattern, code });
282772
+ }
282773
+ if (!rules.some((rule) => rule.pattern === "release/*")) {
282774
+ rules.push({ pattern: "release/*", code: "RC" });
282775
+ }
282776
+ return rules;
282777
+ }
282778
+ function matchChannel(branch, rules) {
282779
+ for (const rule of rules) {
282780
+ if (rule.pattern.endsWith("*")) {
282781
+ const prefix = rule.pattern.slice(0, -1);
282782
+ if (branch.startsWith(prefix)) return rule;
282783
+ } else if (branch === rule.pattern) {
282784
+ return rule;
282785
+ }
282786
+ }
282787
+ return void 0;
282788
+ }
282789
+ function resolveBranchDecision(options) {
282790
+ const { strategy, identity } = options;
282791
+ const channels = options.channels ?? [];
282792
+ if (strategy === "legacy") {
282793
+ return {
282794
+ tier: "legacy",
282795
+ strategy,
282796
+ identity,
282797
+ canonicalBranch: clean(options.canonicalBranch) ?? identity.defaultBranch,
282798
+ reason: "branch-strategy legacy: branch-blind pre-v2 behavior"
282799
+ };
282800
+ }
282801
+ const canonicalBranch = clean(options.canonicalBranch) ?? identity.defaultBranch;
282802
+ if (!canonicalBranch) {
282803
+ throw new ContractError(
282804
+ "CONTRACT_DEFAULT_BRANCH_UNRESOLVED",
282805
+ `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.`
282806
+ );
282807
+ }
282808
+ if (identity.refKind === "tag" || identity.refKind === "unknown" || !identity.headBranch) {
282809
+ return {
282810
+ tier: "gated",
282811
+ strategy,
282812
+ identity,
282813
+ canonicalBranch,
282814
+ reason: `ref kind ${identity.refKind}: never canonical/preview-eligible; no-op with annotation`
282815
+ };
282816
+ }
282817
+ if (identity.headBranch === canonicalBranch) {
282818
+ return {
282819
+ tier: "canonical",
282820
+ strategy,
282821
+ identity,
282822
+ canonicalBranch,
282823
+ reason: `head branch equals canonical branch ${canonicalBranch}`
282824
+ };
282825
+ }
282826
+ const channel = matchChannel(identity.headBranch, channels);
282827
+ if (channel) {
282828
+ return {
282829
+ tier: "channel",
282830
+ strategy,
282831
+ identity,
282832
+ canonicalBranch,
282833
+ channel,
282834
+ reason: `branch ${identity.headBranch} matches channel ${channel.pattern}=${channel.code}`
282835
+ };
282836
+ }
282837
+ if (strategy === "preview") {
282838
+ if (identity.isForkPr) {
282839
+ return {
282840
+ tier: "gated",
282841
+ strategy,
282842
+ identity,
282843
+ canonicalBranch,
282844
+ reason: "fork PR: preview-ineligible (same-repo gate), gated instead"
282845
+ };
282846
+ }
282847
+ return {
282848
+ tier: "preview",
282849
+ strategy,
282850
+ identity,
282851
+ canonicalBranch,
282852
+ reason: `branch ${identity.headBranch} under branch-strategy preview`
282853
+ };
282854
+ }
282855
+ return {
282856
+ tier: "gated",
282857
+ strategy,
282858
+ identity,
282859
+ canonicalBranch,
282860
+ reason: `branch ${identity.headBranch} under branch-strategy publish-gate`
282861
+ };
282862
+ }
282863
+ var BRANCH_DECISION_ENV = "POSTMAN_BRANCH_DECISION";
282864
+ function serializeBranchDecision(decision) {
282865
+ return JSON.stringify(decision);
282866
+ }
282867
+ function parseBranchDecision(raw) {
282868
+ const value = clean(raw);
282869
+ if (!value) return void 0;
282870
+ let parsed;
282871
+ try {
282872
+ parsed = JSON.parse(value);
282873
+ } catch {
282874
+ throw new ContractError("CONTRACT_BRANCH_DECISION_INVALID", "POSTMAN_BRANCH_DECISION is not valid JSON");
282875
+ }
282876
+ const candidate = parsed;
282877
+ const tiers = ["canonical", "channel", "preview", "gated", "legacy"];
282878
+ if (!candidate || typeof candidate !== "object" || !tiers.includes(candidate.tier) || !candidate.identity) {
282879
+ throw new ContractError("CONTRACT_BRANCH_DECISION_INVALID", "POSTMAN_BRANCH_DECISION does not carry a valid BranchDecision");
282880
+ }
282881
+ return candidate;
282882
+ }
282883
+ function resolveEffectiveBranchDecision(options, env = process.env) {
282884
+ const inherited = parseBranchDecision(env[BRANCH_DECISION_ENV]);
282885
+ if (inherited) return inherited;
282886
+ return resolveBranchDecision(options);
282887
+ }
282888
+ var PREVIEW_SLUG_MAX = 30;
282889
+ function buildBranchSlug(rawBranch) {
282890
+ const sanitized = rawBranch.replace(/^refs\/heads\//, "").replace(/\s+/g, "-").replace(/[^A-Za-z0-9._-]/g, "-").replace(/-+/g, "-").replace(/^[._-]+|[._-]+$/g, "");
282891
+ const truncated = sanitized.slice(0, PREVIEW_SLUG_MAX);
282892
+ const lossy = truncated !== rawBranch.replace(/^refs\/heads\//, "");
282893
+ if (!lossy) {
282894
+ return { suffix: truncated, slug: truncated, lossy };
282895
+ }
282896
+ const hash = (0, import_node_crypto4.createHash)("sha256").update(rawBranch).digest("hex").slice(0, 6);
282897
+ return { suffix: `${truncated}-${hash}`, slug: truncated, lossy };
282898
+ }
282899
+ function previewAssetName(baseName, rawBranch) {
282900
+ return `${baseName} @${buildBranchSlug(rawBranch).suffix}`;
282901
+ }
282902
+ function channelAssetName(baseName, code) {
282903
+ return `[${code}] ${baseName}`;
282904
+ }
282905
+ var MARKER_KEY = "x-pm-onboarding";
282906
+ function renderAssetMarker(marker) {
282907
+ return `${MARKER_KEY}: ${JSON.stringify(marker)}`;
282908
+ }
282909
+
282131
282910
  // node_modules/graphql/jsutils/inspect.mjs
282132
282911
  var MAX_ARRAY_LENGTH = 10;
282133
282912
  var MAX_RECURSIVE_DEPTH = 2;
@@ -298659,940 +299438,6 @@ function getPositionFromMatch(match) {
298659
299438
  }
298660
299439
 
298661
299440
  // node_modules/@nodable/entities/src/entities.js
298662
- var BASIC_LATIN = {
298663
- amp: "&",
298664
- AMP: "&",
298665
- lt: "<",
298666
- LT: "<",
298667
- gt: ">",
298668
- GT: ">",
298669
- quot: '"',
298670
- QUOT: '"',
298671
- apos: "'",
298672
- lsquo: "\u2018",
298673
- rsquo: "\u2019",
298674
- ldquo: "\u201C",
298675
- rdquo: "\u201D",
298676
- lsquor: "\u201A",
298677
- rsquor: "\u2019",
298678
- ldquor: "\u201E",
298679
- bdquo: "\u201E",
298680
- comma: ",",
298681
- period: ".",
298682
- colon: ":",
298683
- semi: ";",
298684
- excl: "!",
298685
- quest: "?",
298686
- num: "#",
298687
- dollar: "$",
298688
- percent: "%",
298689
- ast: "*",
298690
- commat: "@",
298691
- lowbar: "_",
298692
- verbar: "|",
298693
- vert: "|",
298694
- sol: "/",
298695
- bsol: "\\",
298696
- lbrace: "{",
298697
- rbrace: "}",
298698
- lbrack: "[",
298699
- rbrack: "]",
298700
- lpar: "(",
298701
- rpar: ")",
298702
- nbsp: "\xA0",
298703
- iexcl: "\xA1",
298704
- cent: "\xA2",
298705
- pound: "\xA3",
298706
- curren: "\xA4",
298707
- yen: "\xA5",
298708
- brvbar: "\xA6",
298709
- sect: "\xA7",
298710
- uml: "\xA8",
298711
- copy: "\xA9",
298712
- COPY: "\xA9",
298713
- ordf: "\xAA",
298714
- laquo: "\xAB",
298715
- not: "\xAC",
298716
- shy: "\xAD",
298717
- reg: "\xAE",
298718
- REG: "\xAE",
298719
- macr: "\xAF",
298720
- deg: "\xB0",
298721
- plusmn: "\xB1",
298722
- sup2: "\xB2",
298723
- sup3: "\xB3",
298724
- acute: "\xB4",
298725
- micro: "\xB5",
298726
- para: "\xB6",
298727
- middot: "\xB7",
298728
- cedil: "\xB8",
298729
- sup1: "\xB9",
298730
- ordm: "\xBA",
298731
- raquo: "\xBB",
298732
- frac14: "\xBC",
298733
- frac12: "\xBD",
298734
- half: "\xBD",
298735
- frac34: "\xBE",
298736
- iquest: "\xBF",
298737
- times: "\xD7",
298738
- div: "\xF7",
298739
- divide: "\xF7"
298740
- };
298741
- var LATIN_ACCENTS = {
298742
- Agrave: "\xC0",
298743
- agrave: "\xE0",
298744
- Aacute: "\xC1",
298745
- aacute: "\xE1",
298746
- Acirc: "\xC2",
298747
- acirc: "\xE2",
298748
- Atilde: "\xC3",
298749
- atilde: "\xE3",
298750
- Auml: "\xC4",
298751
- auml: "\xE4",
298752
- Aring: "\xC5",
298753
- aring: "\xE5",
298754
- AElig: "\xC6",
298755
- aelig: "\xE6",
298756
- Ccedil: "\xC7",
298757
- ccedil: "\xE7",
298758
- Egrave: "\xC8",
298759
- egrave: "\xE8",
298760
- Eacute: "\xC9",
298761
- eacute: "\xE9",
298762
- Ecirc: "\xCA",
298763
- ecirc: "\xEA",
298764
- Euml: "\xCB",
298765
- euml: "\xEB",
298766
- Igrave: "\xCC",
298767
- igrave: "\xEC",
298768
- Iacute: "\xCD",
298769
- iacute: "\xED",
298770
- Icirc: "\xCE",
298771
- icirc: "\xEE",
298772
- Iuml: "\xCF",
298773
- iuml: "\xEF",
298774
- ETH: "\xD0",
298775
- eth: "\xF0",
298776
- Ntilde: "\xD1",
298777
- ntilde: "\xF1",
298778
- Ograve: "\xD2",
298779
- ograve: "\xF2",
298780
- Oacute: "\xD3",
298781
- oacute: "\xF3",
298782
- Ocirc: "\xD4",
298783
- ocirc: "\xF4",
298784
- Otilde: "\xD5",
298785
- otilde: "\xF5",
298786
- Ouml: "\xD6",
298787
- ouml: "\xF6",
298788
- Oslash: "\xD8",
298789
- oslash: "\xF8",
298790
- Ugrave: "\xD9",
298791
- ugrave: "\xF9",
298792
- Uacute: "\xDA",
298793
- uacute: "\xFA",
298794
- Ucirc: "\xDB",
298795
- ucirc: "\xFB",
298796
- Uuml: "\xDC",
298797
- uuml: "\xFC",
298798
- Yacute: "\xDD",
298799
- yacute: "\xFD",
298800
- THORN: "\xDE",
298801
- thorn: "\xFE",
298802
- szlig: "\xDF",
298803
- yuml: "\xFF",
298804
- Yuml: "\u0178"
298805
- };
298806
- var LATIN_EXTENDED = {
298807
- Amacr: "\u0100",
298808
- amacr: "\u0101",
298809
- Abreve: "\u0102",
298810
- abreve: "\u0103",
298811
- Aogon: "\u0104",
298812
- aogon: "\u0105",
298813
- Cacute: "\u0106",
298814
- cacute: "\u0107",
298815
- Ccirc: "\u0108",
298816
- ccirc: "\u0109",
298817
- Cdot: "\u010A",
298818
- cdot: "\u010B",
298819
- Ccaron: "\u010C",
298820
- ccaron: "\u010D",
298821
- Dcaron: "\u010E",
298822
- dcaron: "\u010F",
298823
- Dstrok: "\u0110",
298824
- dstrok: "\u0111",
298825
- Emacr: "\u0112",
298826
- emacr: "\u0113",
298827
- Ecaron: "\u011A",
298828
- ecaron: "\u011B",
298829
- Edot: "\u0116",
298830
- edot: "\u0117",
298831
- Eogon: "\u0118",
298832
- eogon: "\u0119",
298833
- Gcirc: "\u011C",
298834
- gcirc: "\u011D",
298835
- Gbreve: "\u011E",
298836
- gbreve: "\u011F",
298837
- Gdot: "\u0120",
298838
- gdot: "\u0121",
298839
- Gcedil: "\u0122",
298840
- Hcirc: "\u0124",
298841
- hcirc: "\u0125",
298842
- Hstrok: "\u0126",
298843
- hstrok: "\u0127",
298844
- Itilde: "\u0128",
298845
- itilde: "\u0129",
298846
- Imacr: "\u012A",
298847
- imacr: "\u012B",
298848
- Iogon: "\u012E",
298849
- iogon: "\u012F",
298850
- Idot: "\u0130",
298851
- IJlig: "\u0132",
298852
- ijlig: "\u0133",
298853
- Jcirc: "\u0134",
298854
- jcirc: "\u0135",
298855
- Kcedil: "\u0136",
298856
- kcedil: "\u0137",
298857
- kgreen: "\u0138",
298858
- Lacute: "\u0139",
298859
- lacute: "\u013A",
298860
- Lcedil: "\u013B",
298861
- lcedil: "\u013C",
298862
- Lcaron: "\u013D",
298863
- lcaron: "\u013E",
298864
- Lmidot: "\u013F",
298865
- lmidot: "\u0140",
298866
- Lstrok: "\u0141",
298867
- lstrok: "\u0142",
298868
- Nacute: "\u0143",
298869
- nacute: "\u0144",
298870
- Ncaron: "\u0147",
298871
- ncaron: "\u0148",
298872
- Ncedil: "\u0145",
298873
- ncedil: "\u0146",
298874
- ENG: "\u014A",
298875
- eng: "\u014B",
298876
- Omacr: "\u014C",
298877
- omacr: "\u014D",
298878
- Odblac: "\u0150",
298879
- odblac: "\u0151",
298880
- OElig: "\u0152",
298881
- oelig: "\u0153",
298882
- Racute: "\u0154",
298883
- racute: "\u0155",
298884
- Rcaron: "\u0158",
298885
- rcaron: "\u0159",
298886
- Rcedil: "\u0156",
298887
- rcedil: "\u0157",
298888
- Sacute: "\u015A",
298889
- sacute: "\u015B",
298890
- Scirc: "\u015C",
298891
- scirc: "\u015D",
298892
- Scedil: "\u015E",
298893
- scedil: "\u015F",
298894
- Scaron: "\u0160",
298895
- scaron: "\u0161",
298896
- Tcedil: "\u0162",
298897
- tcedil: "\u0163",
298898
- Tcaron: "\u0164",
298899
- tcaron: "\u0165",
298900
- Tstrok: "\u0166",
298901
- tstrok: "\u0167",
298902
- Utilde: "\u0168",
298903
- utilde: "\u0169",
298904
- Umacr: "\u016A",
298905
- umacr: "\u016B",
298906
- Ubreve: "\u016C",
298907
- ubreve: "\u016D",
298908
- Uring: "\u016E",
298909
- uring: "\u016F",
298910
- Udblac: "\u0170",
298911
- udblac: "\u0171",
298912
- Uogon: "\u0172",
298913
- uogon: "\u0173",
298914
- Wcirc: "\u0174",
298915
- wcirc: "\u0175",
298916
- Ycirc: "\u0176",
298917
- ycirc: "\u0177",
298918
- Zacute: "\u0179",
298919
- zacute: "\u017A",
298920
- Zdot: "\u017B",
298921
- zdot: "\u017C",
298922
- Zcaron: "\u017D",
298923
- zcaron: "\u017E"
298924
- };
298925
- var GREEK = {
298926
- Alpha: "\u0391",
298927
- alpha: "\u03B1",
298928
- Beta: "\u0392",
298929
- beta: "\u03B2",
298930
- Gamma: "\u0393",
298931
- gamma: "\u03B3",
298932
- Delta: "\u0394",
298933
- delta: "\u03B4",
298934
- Epsilon: "\u0395",
298935
- epsilon: "\u03B5",
298936
- epsiv: "\u03F5",
298937
- varepsilon: "\u03F5",
298938
- Zeta: "\u0396",
298939
- zeta: "\u03B6",
298940
- Eta: "\u0397",
298941
- eta: "\u03B7",
298942
- Theta: "\u0398",
298943
- theta: "\u03B8",
298944
- thetasym: "\u03D1",
298945
- vartheta: "\u03D1",
298946
- Iota: "\u0399",
298947
- iota: "\u03B9",
298948
- Kappa: "\u039A",
298949
- kappa: "\u03BA",
298950
- kappav: "\u03F0",
298951
- varkappa: "\u03F0",
298952
- Lambda: "\u039B",
298953
- lambda: "\u03BB",
298954
- Mu: "\u039C",
298955
- mu: "\u03BC",
298956
- Nu: "\u039D",
298957
- nu: "\u03BD",
298958
- Xi: "\u039E",
298959
- xi: "\u03BE",
298960
- Omicron: "\u039F",
298961
- omicron: "\u03BF",
298962
- Pi: "\u03A0",
298963
- pi: "\u03C0",
298964
- piv: "\u03D6",
298965
- varpi: "\u03D6",
298966
- Rho: "\u03A1",
298967
- rho: "\u03C1",
298968
- rhov: "\u03F1",
298969
- varrho: "\u03F1",
298970
- Sigma: "\u03A3",
298971
- sigma: "\u03C3",
298972
- sigmaf: "\u03C2",
298973
- sigmav: "\u03C2",
298974
- varsigma: "\u03C2",
298975
- Tau: "\u03A4",
298976
- tau: "\u03C4",
298977
- Upsilon: "\u03A5",
298978
- upsilon: "\u03C5",
298979
- upsi: "\u03C5",
298980
- Upsi: "\u03D2",
298981
- upsih: "\u03D2",
298982
- Phi: "\u03A6",
298983
- phi: "\u03C6",
298984
- phiv: "\u03D5",
298985
- varphi: "\u03D5",
298986
- Chi: "\u03A7",
298987
- chi: "\u03C7",
298988
- Psi: "\u03A8",
298989
- psi: "\u03C8",
298990
- Omega: "\u03A9",
298991
- omega: "\u03C9",
298992
- ohm: "\u03A9",
298993
- Gammad: "\u03DC",
298994
- gammad: "\u03DD",
298995
- digamma: "\u03DD"
298996
- };
298997
- var CYRILLIC = {
298998
- Afr: "\u{1D504}",
298999
- afr: "\u{1D51E}",
299000
- Acy: "\u0410",
299001
- acy: "\u0430",
299002
- Bcy: "\u0411",
299003
- bcy: "\u0431",
299004
- Vcy: "\u0412",
299005
- vcy: "\u0432",
299006
- Gcy: "\u0413",
299007
- gcy: "\u0433",
299008
- Dcy: "\u0414",
299009
- dcy: "\u0434",
299010
- IEcy: "\u0415",
299011
- iecy: "\u0435",
299012
- IOcy: "\u0401",
299013
- iocy: "\u0451",
299014
- ZHcy: "\u0416",
299015
- zhcy: "\u0436",
299016
- Zcy: "\u0417",
299017
- zcy: "\u0437",
299018
- Icy: "\u0418",
299019
- icy: "\u0438",
299020
- Jcy: "\u0419",
299021
- jcy: "\u0439",
299022
- Kcy: "\u041A",
299023
- kcy: "\u043A",
299024
- Lcy: "\u041B",
299025
- lcy: "\u043B",
299026
- Mcy: "\u041C",
299027
- mcy: "\u043C",
299028
- Ncy: "\u041D",
299029
- ncy: "\u043D",
299030
- Ocy: "\u041E",
299031
- ocy: "\u043E",
299032
- Pcy: "\u041F",
299033
- pcy: "\u043F",
299034
- Rcy: "\u0420",
299035
- rcy: "\u0440",
299036
- Scy: "\u0421",
299037
- scy: "\u0441",
299038
- Tcy: "\u0422",
299039
- tcy: "\u0442",
299040
- Ucy: "\u0423",
299041
- ucy: "\u0443",
299042
- Fcy: "\u0424",
299043
- fcy: "\u0444",
299044
- KHcy: "\u0425",
299045
- khcy: "\u0445",
299046
- TScy: "\u0426",
299047
- tscy: "\u0446",
299048
- CHcy: "\u0427",
299049
- chcy: "\u0447",
299050
- SHcy: "\u0428",
299051
- shcy: "\u0448",
299052
- SHCHcy: "\u0429",
299053
- shchcy: "\u0449",
299054
- HARDcy: "\u042A",
299055
- hardcy: "\u044A",
299056
- Ycy: "\u042B",
299057
- ycy: "\u044B",
299058
- SOFTcy: "\u042C",
299059
- softcy: "\u044C",
299060
- Ecy: "\u042D",
299061
- ecy: "\u044D",
299062
- YUcy: "\u042E",
299063
- yucy: "\u044E",
299064
- YAcy: "\u042F",
299065
- yacy: "\u044F",
299066
- DJcy: "\u0402",
299067
- djcy: "\u0452",
299068
- GJcy: "\u0403",
299069
- gjcy: "\u0453",
299070
- Jukcy: "\u0404",
299071
- jukcy: "\u0454",
299072
- DScy: "\u0405",
299073
- dscy: "\u0455",
299074
- Iukcy: "\u0406",
299075
- iukcy: "\u0456",
299076
- YIcy: "\u0407",
299077
- yicy: "\u0457",
299078
- Jsercy: "\u0408",
299079
- jsercy: "\u0458",
299080
- LJcy: "\u0409",
299081
- ljcy: "\u0459",
299082
- NJcy: "\u040A",
299083
- njcy: "\u045A",
299084
- TSHcy: "\u040B",
299085
- tshcy: "\u045B",
299086
- KJcy: "\u040C",
299087
- kjcy: "\u045C",
299088
- Ubrcy: "\u040E",
299089
- ubrcy: "\u045E",
299090
- DZcy: "\u040F",
299091
- dzcy: "\u045F"
299092
- };
299093
- var MATH = {
299094
- plus: "+",
299095
- pm: "\xB1",
299096
- times: "\xD7",
299097
- div: "\xF7",
299098
- divide: "\xF7",
299099
- sdot: "\u22C5",
299100
- star: "\u2606",
299101
- starf: "\u2605",
299102
- bigstar: "\u2605",
299103
- lowast: "\u2217",
299104
- ast: "*",
299105
- midast: "*",
299106
- compfn: "\u2218",
299107
- smallcircle: "\u2218",
299108
- bullet: "\u2022",
299109
- bull: "\u2022",
299110
- nbsp: "\xA0",
299111
- hellip: "\u2026",
299112
- mldr: "\u2026",
299113
- prime: "\u2032",
299114
- Prime: "\u2033",
299115
- tprime: "\u2034",
299116
- bprime: "\u2035",
299117
- backprime: "\u2035",
299118
- minus: "\u2212",
299119
- minusd: "\u2238",
299120
- dotminus: "\u2238",
299121
- plusdo: "\u2214",
299122
- dotplus: "\u2214",
299123
- plusmn: "\xB1",
299124
- minusplus: "\u2213",
299125
- mnplus: "\u2213",
299126
- mp: "\u2213",
299127
- setminus: "\u2216",
299128
- smallsetminus: "\u2216",
299129
- Backslash: "\u2216",
299130
- setmn: "\u2216",
299131
- ssetmn: "\u2216",
299132
- lowbar: "_",
299133
- verbar: "|",
299134
- vert: "|",
299135
- VerticalLine: "|",
299136
- colon: ":",
299137
- Colon: "\u2237",
299138
- Proportion: "\u2237",
299139
- ratio: "\u2236",
299140
- equals: "=",
299141
- ne: "\u2260",
299142
- nequiv: "\u2262",
299143
- equiv: "\u2261",
299144
- Congruent: "\u2261",
299145
- sim: "\u223C",
299146
- thicksim: "\u223C",
299147
- thksim: "\u223C",
299148
- sime: "\u2243",
299149
- simeq: "\u2243",
299150
- TildeEqual: "\u2243",
299151
- asymp: "\u2248",
299152
- approx: "\u2248",
299153
- thickapprox: "\u2248",
299154
- thkap: "\u2248",
299155
- TildeTilde: "\u2248",
299156
- ncong: "\u2247",
299157
- cong: "\u2245",
299158
- TildeFullEqual: "\u2245",
299159
- asympeq: "\u224D",
299160
- CupCap: "\u224D",
299161
- bump: "\u224E",
299162
- Bumpeq: "\u224E",
299163
- HumpDownHump: "\u224E",
299164
- bumpe: "\u224F",
299165
- bumpeq: "\u224F",
299166
- HumpEqual: "\u224F",
299167
- le: "\u2264",
299168
- LessEqual: "\u2264",
299169
- ge: "\u2265",
299170
- GreaterEqual: "\u2265",
299171
- lesseqgtr: "\u22DA",
299172
- lesseqqgtr: "\u2A8B",
299173
- greater: ">",
299174
- less: "<"
299175
- };
299176
- var MATH_ADVANCED = {
299177
- alefsym: "\u2135",
299178
- aleph: "\u2135",
299179
- beth: "\u2136",
299180
- gimel: "\u2137",
299181
- daleth: "\u2138",
299182
- forall: "\u2200",
299183
- ForAll: "\u2200",
299184
- part: "\u2202",
299185
- PartialD: "\u2202",
299186
- exist: "\u2203",
299187
- Exists: "\u2203",
299188
- nexist: "\u2204",
299189
- nexists: "\u2204",
299190
- empty: "\u2205",
299191
- emptyset: "\u2205",
299192
- emptyv: "\u2205",
299193
- varnothing: "\u2205",
299194
- nabla: "\u2207",
299195
- Del: "\u2207",
299196
- isin: "\u2208",
299197
- isinv: "\u2208",
299198
- in: "\u2208",
299199
- Element: "\u2208",
299200
- notin: "\u2209",
299201
- notinva: "\u2209",
299202
- ni: "\u220B",
299203
- niv: "\u220B",
299204
- SuchThat: "\u220B",
299205
- ReverseElement: "\u220B",
299206
- notni: "\u220C",
299207
- notniva: "\u220C",
299208
- prod: "\u220F",
299209
- Product: "\u220F",
299210
- coprod: "\u2210",
299211
- Coproduct: "\u2210",
299212
- sum: "\u2211",
299213
- Sum: "\u2211",
299214
- minus: "\u2212",
299215
- mp: "\u2213",
299216
- plusdo: "\u2214",
299217
- dotplus: "\u2214",
299218
- setminus: "\u2216",
299219
- lowast: "\u2217",
299220
- radic: "\u221A",
299221
- Sqrt: "\u221A",
299222
- prop: "\u221D",
299223
- propto: "\u221D",
299224
- Proportional: "\u221D",
299225
- varpropto: "\u221D",
299226
- infin: "\u221E",
299227
- infintie: "\u29DD",
299228
- ang: "\u2220",
299229
- angle: "\u2220",
299230
- angmsd: "\u2221",
299231
- measuredangle: "\u2221",
299232
- angsph: "\u2222",
299233
- mid: "\u2223",
299234
- VerticalBar: "\u2223",
299235
- nmid: "\u2224",
299236
- nsmid: "\u2224",
299237
- npar: "\u2226",
299238
- parallel: "\u2225",
299239
- spar: "\u2225",
299240
- nparallel: "\u2226",
299241
- nspar: "\u2226",
299242
- and: "\u2227",
299243
- wedge: "\u2227",
299244
- or: "\u2228",
299245
- vee: "\u2228",
299246
- cap: "\u2229",
299247
- cup: "\u222A",
299248
- int: "\u222B",
299249
- Integral: "\u222B",
299250
- conint: "\u222E",
299251
- ContourIntegral: "\u222E",
299252
- Conint: "\u222F",
299253
- DoubleContourIntegral: "\u222F",
299254
- Cconint: "\u2230",
299255
- there4: "\u2234",
299256
- therefore: "\u2234",
299257
- Therefore: "\u2234",
299258
- becaus: "\u2235",
299259
- because: "\u2235",
299260
- Because: "\u2235",
299261
- ratio: "\u2236",
299262
- Proportion: "\u2237",
299263
- minusd: "\u2238",
299264
- dotminus: "\u2238",
299265
- mDDot: "\u223A",
299266
- homtht: "\u223B",
299267
- sim: "\u223C",
299268
- bsimg: "\u223D",
299269
- backsim: "\u223D",
299270
- ac: "\u223E",
299271
- mstpos: "\u223E",
299272
- acd: "\u223F",
299273
- VerticalTilde: "\u2240",
299274
- wr: "\u2240",
299275
- wreath: "\u2240",
299276
- nsime: "\u2244",
299277
- nsimeq: "\u2244",
299278
- ncong: "\u2247",
299279
- simne: "\u2246",
299280
- ncongdot: "\u2A6D\u0338",
299281
- ngsim: "\u2275",
299282
- nsim: "\u2241",
299283
- napprox: "\u2249",
299284
- nap: "\u2249",
299285
- ngeq: "\u2271",
299286
- nge: "\u2271",
299287
- nleq: "\u2270",
299288
- nle: "\u2270",
299289
- ngtr: "\u226F",
299290
- ngt: "\u226F",
299291
- nless: "\u226E",
299292
- nlt: "\u226E",
299293
- nprec: "\u2280",
299294
- npr: "\u2280",
299295
- nsucc: "\u2281",
299296
- nsc: "\u2281"
299297
- };
299298
- var ARROWS = {
299299
- larr: "\u2190",
299300
- leftarrow: "\u2190",
299301
- LeftArrow: "\u2190",
299302
- uarr: "\u2191",
299303
- uparrow: "\u2191",
299304
- UpArrow: "\u2191",
299305
- rarr: "\u2192",
299306
- rightarrow: "\u2192",
299307
- RightArrow: "\u2192",
299308
- darr: "\u2193",
299309
- downarrow: "\u2193",
299310
- DownArrow: "\u2193",
299311
- harr: "\u2194",
299312
- leftrightarrow: "\u2194",
299313
- LeftRightArrow: "\u2194",
299314
- varr: "\u2195",
299315
- updownarrow: "\u2195",
299316
- UpDownArrow: "\u2195",
299317
- nwarr: "\u2196",
299318
- nwarrow: "\u2196",
299319
- UpperLeftArrow: "\u2196",
299320
- nearr: "\u2197",
299321
- nearrow: "\u2197",
299322
- UpperRightArrow: "\u2197",
299323
- searr: "\u2198",
299324
- searrow: "\u2198",
299325
- LowerRightArrow: "\u2198",
299326
- swarr: "\u2199",
299327
- swarrow: "\u2199",
299328
- LowerLeftArrow: "\u2199",
299329
- lArr: "\u21D0",
299330
- Leftarrow: "\u21D0",
299331
- uArr: "\u21D1",
299332
- Uparrow: "\u21D1",
299333
- rArr: "\u21D2",
299334
- Rightarrow: "\u21D2",
299335
- dArr: "\u21D3",
299336
- Downarrow: "\u21D3",
299337
- hArr: "\u21D4",
299338
- Leftrightarrow: "\u21D4",
299339
- iff: "\u21D4",
299340
- vArr: "\u21D5",
299341
- Updownarrow: "\u21D5",
299342
- lAarr: "\u21DA",
299343
- Lleftarrow: "\u21DA",
299344
- rAarr: "\u21DB",
299345
- Rrightarrow: "\u21DB",
299346
- lrarr: "\u21C6",
299347
- leftrightarrows: "\u21C6",
299348
- rlarr: "\u21C4",
299349
- rightleftarrows: "\u21C4",
299350
- lrhar: "\u21CB",
299351
- leftrightharpoons: "\u21CB",
299352
- ReverseEquilibrium: "\u21CB",
299353
- rlhar: "\u21CC",
299354
- rightleftharpoons: "\u21CC",
299355
- Equilibrium: "\u21CC",
299356
- udarr: "\u21C5",
299357
- UpArrowDownArrow: "\u21C5",
299358
- duarr: "\u21F5",
299359
- DownArrowUpArrow: "\u21F5",
299360
- llarr: "\u21C7",
299361
- leftleftarrows: "\u21C7",
299362
- rrarr: "\u21C9",
299363
- rightrightarrows: "\u21C9",
299364
- ddarr: "\u21CA",
299365
- downdownarrows: "\u21CA",
299366
- har: "\u21BD",
299367
- lhard: "\u21BD",
299368
- leftharpoondown: "\u21BD",
299369
- lharu: "\u21BC",
299370
- leftharpoonup: "\u21BC",
299371
- rhard: "\u21C1",
299372
- rightharpoondown: "\u21C1",
299373
- rharu: "\u21C0",
299374
- rightharpoonup: "\u21C0",
299375
- lsh: "\u21B0",
299376
- Lsh: "\u21B0",
299377
- rsh: "\u21B1",
299378
- Rsh: "\u21B1",
299379
- ldsh: "\u21B2",
299380
- rdsh: "\u21B3",
299381
- hookleftarrow: "\u21A9",
299382
- hookrightarrow: "\u21AA",
299383
- mapstoleft: "\u21A4",
299384
- mapstoup: "\u21A5",
299385
- map: "\u21A6",
299386
- mapsto: "\u21A6",
299387
- mapstodown: "\u21A7",
299388
- crarr: "\u21B5",
299389
- nleftarrow: "\u219A",
299390
- nleftrightarrow: "\u21AE",
299391
- nrightarrow: "\u219B",
299392
- nrarr: "\u219B",
299393
- larrtl: "\u21A2",
299394
- rarrtl: "\u21A3",
299395
- leftarrowtail: "\u21A2",
299396
- rightarrowtail: "\u21A3",
299397
- twoheadleftarrow: "\u219E",
299398
- twoheadrightarrow: "\u21A0",
299399
- Larr: "\u219E",
299400
- Rarr: "\u21A0",
299401
- larrhk: "\u21A9",
299402
- rarrhk: "\u21AA",
299403
- larrlp: "\u21AB",
299404
- looparrowleft: "\u21AB",
299405
- rarrlp: "\u21AC",
299406
- looparrowright: "\u21AC",
299407
- harrw: "\u21AD",
299408
- leftrightsquigarrow: "\u21AD",
299409
- nrarrw: "\u219D\u0338",
299410
- rarrw: "\u219D",
299411
- rightsquigarrow: "\u219D",
299412
- larrbfs: "\u291F",
299413
- rarrbfs: "\u2920",
299414
- nvHarr: "\u2904",
299415
- nvlArr: "\u2902",
299416
- nvrArr: "\u2903",
299417
- larrfs: "\u291D",
299418
- rarrfs: "\u291E",
299419
- Map: "\u2905",
299420
- larrsim: "\u2973",
299421
- rarrsim: "\u2974",
299422
- harrcir: "\u2948",
299423
- Uarrocir: "\u2949",
299424
- lurdshar: "\u294A",
299425
- ldrdhar: "\u2967",
299426
- ldrushar: "\u294B",
299427
- rdldhar: "\u2969",
299428
- lrhard: "\u296D",
299429
- uharr: "\u21BE",
299430
- uharl: "\u21BF",
299431
- dharr: "\u21C2",
299432
- dharl: "\u21C3",
299433
- Uarr: "\u219F",
299434
- Darr: "\u21A1",
299435
- zigrarr: "\u21DD",
299436
- nwArr: "\u21D6",
299437
- neArr: "\u21D7",
299438
- seArr: "\u21D8",
299439
- swArr: "\u21D9",
299440
- nharr: "\u21AE",
299441
- nhArr: "\u21CE",
299442
- nlarr: "\u219A",
299443
- nlArr: "\u21CD",
299444
- nrArr: "\u21CF",
299445
- larrb: "\u21E4",
299446
- LeftArrowBar: "\u21E4",
299447
- rarrb: "\u21E5",
299448
- RightArrowBar: "\u21E5"
299449
- };
299450
- var SHAPES = {
299451
- square: "\u25A1",
299452
- Square: "\u25A1",
299453
- squ: "\u25A1",
299454
- squf: "\u25AA",
299455
- squarf: "\u25AA",
299456
- blacksquar: "\u25AA",
299457
- blacksquare: "\u25AA",
299458
- FilledVerySmallSquare: "\u25AA",
299459
- blk34: "\u2593",
299460
- blk12: "\u2592",
299461
- blk14: "\u2591",
299462
- block: "\u2588",
299463
- srect: "\u25AD",
299464
- rect: "\u25AD",
299465
- sdot: "\u22C5",
299466
- sdotb: "\u22A1",
299467
- dotsquare: "\u22A1",
299468
- triangle: "\u25B5",
299469
- tri: "\u25B5",
299470
- trine: "\u25B5",
299471
- utri: "\u25B5",
299472
- triangledown: "\u25BF",
299473
- dtri: "\u25BF",
299474
- tridown: "\u25BF",
299475
- triangleleft: "\u25C3",
299476
- ltri: "\u25C3",
299477
- triangleright: "\u25B9",
299478
- rtri: "\u25B9",
299479
- blacktriangle: "\u25B4",
299480
- utrif: "\u25B4",
299481
- blacktriangledown: "\u25BE",
299482
- dtrif: "\u25BE",
299483
- blacktriangleleft: "\u25C2",
299484
- ltrif: "\u25C2",
299485
- blacktriangleright: "\u25B8",
299486
- rtrif: "\u25B8",
299487
- loz: "\u25CA",
299488
- lozenge: "\u25CA",
299489
- blacklozenge: "\u29EB",
299490
- lozf: "\u29EB",
299491
- bigcirc: "\u25EF",
299492
- xcirc: "\u25EF",
299493
- circ: "\u02C6",
299494
- Circle: "\u25CB",
299495
- cir: "\u25CB",
299496
- o: "\u25CB",
299497
- bullet: "\u2022",
299498
- bull: "\u2022",
299499
- hellip: "\u2026",
299500
- mldr: "\u2026",
299501
- nldr: "\u2025",
299502
- boxh: "\u2500",
299503
- HorizontalLine: "\u2500",
299504
- boxv: "\u2502",
299505
- boxdr: "\u250C",
299506
- boxdl: "\u2510",
299507
- boxur: "\u2514",
299508
- boxul: "\u2518",
299509
- boxvr: "\u251C",
299510
- boxvl: "\u2524",
299511
- boxhd: "\u252C",
299512
- boxhu: "\u2534",
299513
- boxvh: "\u253C",
299514
- boxH: "\u2550",
299515
- boxV: "\u2551",
299516
- boxdR: "\u2552",
299517
- boxDr: "\u2553",
299518
- boxDR: "\u2554",
299519
- boxDl: "\u2555",
299520
- boxdL: "\u2556",
299521
- boxDL: "\u2557",
299522
- boxuR: "\u2558",
299523
- boxUr: "\u2559",
299524
- boxUR: "\u255A",
299525
- boxUl: "\u255C",
299526
- boxuL: "\u255B",
299527
- boxUL: "\u255D",
299528
- boxvR: "\u255E",
299529
- boxVr: "\u255F",
299530
- boxVR: "\u2560",
299531
- boxVl: "\u2562",
299532
- boxvL: "\u2561",
299533
- boxVL: "\u2563",
299534
- boxHd: "\u2564",
299535
- boxhD: "\u2565",
299536
- boxHD: "\u2566",
299537
- boxHu: "\u2567",
299538
- boxhU: "\u2568",
299539
- boxHU: "\u2569",
299540
- boxvH: "\u256A",
299541
- boxVh: "\u256B",
299542
- boxVH: "\u256C"
299543
- };
299544
- var PUNCTUATION = {
299545
- excl: "!",
299546
- iexcl: "\xA1",
299547
- brvbar: "\xA6",
299548
- sect: "\xA7",
299549
- uml: "\xA8",
299550
- copy: "\xA9",
299551
- ordf: "\xAA",
299552
- laquo: "\xAB",
299553
- not: "\xAC",
299554
- shy: "\xAD",
299555
- reg: "\xAE",
299556
- macr: "\xAF",
299557
- deg: "\xB0",
299558
- plusmn: "\xB1",
299559
- sup2: "\xB2",
299560
- sup3: "\xB3",
299561
- acute: "\xB4",
299562
- micro: "\xB5",
299563
- para: "\xB6",
299564
- middot: "\xB7",
299565
- cedil: "\xB8",
299566
- sup1: "\xB9",
299567
- ordm: "\xBA",
299568
- raquo: "\xBB",
299569
- frac14: "\xBC",
299570
- frac12: "\xBD",
299571
- frac34: "\xBE",
299572
- iquest: "\xBF",
299573
- nbsp: "\xA0",
299574
- comma: ",",
299575
- period: ".",
299576
- colon: ":",
299577
- semi: ";",
299578
- vert: "|",
299579
- Verbar: "\u2016",
299580
- verbar: "|",
299581
- dblac: "\u02DD",
299582
- circ: "\u02C6",
299583
- caron: "\u02C7",
299584
- breve: "\u02D8",
299585
- dot: "\u02D9",
299586
- ring: "\u02DA",
299587
- ogon: "\u02DB",
299588
- tilde: "\u02DC",
299589
- DiacriticalGrave: "`",
299590
- DiacriticalAcute: "\xB4",
299591
- DiacriticalTilde: "\u02DC",
299592
- DiacriticalDot: "\u02D9",
299593
- DiacriticalDoubleAcute: "\u02DD",
299594
- grave: "`"
299595
- };
299596
299441
  var CURRENCY = {
299597
299442
  cent: "\xA2",
299598
299443
  pound: "\xA3",
@@ -299610,106 +299455,6 @@ var CURRENCY = {
299610
299455
  yuan: "\xA5",
299611
299456
  cedil: "\xB8"
299612
299457
  };
299613
- var FRACTIONS = {
299614
- frac12: "\xBD",
299615
- half: "\xBD",
299616
- frac13: "\u2153",
299617
- frac14: "\xBC",
299618
- frac15: "\u2155",
299619
- frac16: "\u2159",
299620
- frac18: "\u215B",
299621
- frac23: "\u2154",
299622
- frac25: "\u2156",
299623
- frac34: "\xBE",
299624
- frac35: "\u2157",
299625
- frac38: "\u215C",
299626
- frac45: "\u2158",
299627
- frac56: "\u215A",
299628
- frac58: "\u215D",
299629
- frac78: "\u215E",
299630
- frasl: "\u2044"
299631
- };
299632
- var MISC_SYMBOLS = {
299633
- trade: "\u2122",
299634
- TRADE: "\u2122",
299635
- telrec: "\u2315",
299636
- target: "\u2316",
299637
- ulcorn: "\u231C",
299638
- ulcorner: "\u231C",
299639
- urcorn: "\u231D",
299640
- urcorner: "\u231D",
299641
- dlcorn: "\u231E",
299642
- llcorner: "\u231E",
299643
- drcorn: "\u231F",
299644
- lrcorner: "\u231F",
299645
- intercal: "\u22BA",
299646
- intcal: "\u22BA",
299647
- oplus: "\u2295",
299648
- CirclePlus: "\u2295",
299649
- ominus: "\u2296",
299650
- CircleMinus: "\u2296",
299651
- otimes: "\u2297",
299652
- CircleTimes: "\u2297",
299653
- osol: "\u2298",
299654
- odot: "\u2299",
299655
- CircleDot: "\u2299",
299656
- oast: "\u229B",
299657
- circledast: "\u229B",
299658
- odash: "\u229D",
299659
- circleddash: "\u229D",
299660
- ocirc: "\u229A",
299661
- circledcirc: "\u229A",
299662
- boxplus: "\u229E",
299663
- plusb: "\u229E",
299664
- boxminus: "\u229F",
299665
- minusb: "\u229F",
299666
- boxtimes: "\u22A0",
299667
- timesb: "\u22A0",
299668
- boxdot: "\u22A1",
299669
- sdotb: "\u22A1",
299670
- veebar: "\u22BB",
299671
- vee: "\u2228",
299672
- barvee: "\u22BD",
299673
- and: "\u2227",
299674
- wedge: "\u2227",
299675
- Cap: "\u22D2",
299676
- Cup: "\u22D3",
299677
- Fork: "\u22D4",
299678
- pitchfork: "\u22D4",
299679
- epar: "\u22D5",
299680
- ltlarr: "\u2976",
299681
- nvap: "\u224D\u20D2",
299682
- nvsim: "\u223C\u20D2",
299683
- nvge: "\u2265\u20D2",
299684
- nvle: "\u2264\u20D2",
299685
- nvlt: "<\u20D2",
299686
- nvgt: ">\u20D2",
299687
- nvltrie: "\u22B4\u20D2",
299688
- nvrtrie: "\u22B5\u20D2",
299689
- Vdash: "\u22A9",
299690
- dashv: "\u22A3",
299691
- vDash: "\u22A8",
299692
- Vvdash: "\u22AA",
299693
- nvdash: "\u22AC",
299694
- nvDash: "\u22AD",
299695
- nVdash: "\u22AE",
299696
- nVDash: "\u22AF"
299697
- };
299698
- var ALL_ENTITIES = {
299699
- ...BASIC_LATIN,
299700
- ...LATIN_ACCENTS,
299701
- ...LATIN_EXTENDED,
299702
- ...GREEK,
299703
- ...CYRILLIC,
299704
- ...MATH,
299705
- ...MATH_ADVANCED,
299706
- ...ARROWS,
299707
- ...SHAPES,
299708
- ...PUNCTUATION,
299709
- ...CURRENCY,
299710
- ...FRACTIONS,
299711
- ...MISC_SYMBOLS
299712
- };
299713
299458
  var XML = {
299714
299459
  amp: "&",
299715
299460
  apos: "'",
@@ -300353,7 +300098,7 @@ var XmlNode = class {
300353
300098
  }
300354
300099
  };
300355
300100
 
300356
- // node_modules/xml-naming/src/index.js
300101
+ // node_modules/fast-xml-parser/node_modules/xml-naming/src/index.js
300357
300102
  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";
300358
300103
  var nameChar10 = nameStartChar10 + "\\-\\.\\d\xB7\u0300-\u036F\u203F-\u2040";
300359
300104
  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}";
@@ -300372,8 +300117,14 @@ var buildRegexes = (startChar, char, flags = "") => {
300372
300117
  };
300373
300118
  var regexes10 = buildRegexes(nameStartChar10, nameChar10);
300374
300119
  var regexes11 = buildRegexes(nameStartChar11, nameChar11, "u");
300375
- var getRegexes = (xmlVersion = "1.0") => xmlVersion === "1.1" ? regexes11 : regexes10;
300376
- var qName = (str, { xmlVersion = "1.0" } = {}) => getRegexes(xmlVersion).qName.test(str);
300120
+ var nameStartCharAscii = ":A-Za-z_";
300121
+ var nameCharAscii = nameStartCharAscii + "\\-\\.\\d";
300122
+ var regexesAscii = buildRegexes(nameStartCharAscii, nameCharAscii);
300123
+ var getRegexes = (xmlVersion = "1.0", asciiOnly = false) => {
300124
+ if (asciiOnly) return regexesAscii;
300125
+ return xmlVersion === "1.1" ? regexes11 : regexes10;
300126
+ };
300127
+ var qName = (str, { xmlVersion = "1.0", asciiOnly = false } = {}) => getRegexes(xmlVersion, asciiOnly).qName.test(str);
300377
300128
 
300378
300129
  // node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js
300379
300130
  var DocTypeReader = class {
@@ -301535,17 +301286,16 @@ var Matcher = class {
301535
301286
  this.path[this.path.length - 1].values = void 0;
301536
301287
  }
301537
301288
  const currentLevel = this.path.length;
301538
- if (!this.siblingStacks[currentLevel]) {
301539
- this.siblingStacks[currentLevel] = /* @__PURE__ */ new Map();
301289
+ let level = this.siblingStacks[currentLevel];
301290
+ if (!level) {
301291
+ level = { counts: /* @__PURE__ */ new Map(), total: 0 };
301292
+ this.siblingStacks[currentLevel] = level;
301540
301293
  }
301541
- const siblings = this.siblingStacks[currentLevel];
301542
301294
  const siblingKey = namespace ? `${namespace}:${tagName}` : tagName;
301543
- const counter = siblings.get(siblingKey) || 0;
301544
- let position = 0;
301545
- for (const count of siblings.values()) {
301546
- position += count;
301547
- }
301548
- siblings.set(siblingKey, counter + 1);
301295
+ const counter = level.counts.get(siblingKey) || 0;
301296
+ const position = level.total;
301297
+ level.counts.set(siblingKey, counter + 1);
301298
+ level.total++;
301549
301299
  const node = {
301550
301300
  tag: tagName,
301551
301301
  position,
@@ -301854,7 +301604,7 @@ var Matcher = class {
301854
301604
  snapshot() {
301855
301605
  return {
301856
301606
  path: this.path.map((node) => ({ ...node })),
301857
- siblingStacks: this.siblingStacks.map((map) => new Map(map)),
301607
+ siblingStacks: this.siblingStacks.map((level) => level ? { counts: new Map(level.counts), total: level.total } : level),
301858
301608
  keptAttrs: this._keptAttrs.map((entry) => ({ ...entry }))
301859
301609
  };
301860
301610
  }
@@ -301865,7 +301615,7 @@ var Matcher = class {
301865
301615
  restore(snapshot) {
301866
301616
  this._pathStringCache = null;
301867
301617
  this.path = snapshot.path.map((node) => ({ ...node }));
301868
- this.siblingStacks = snapshot.siblingStacks.map((map) => new Map(map));
301618
+ this.siblingStacks = snapshot.siblingStacks.map((level) => level ? { counts: new Map(level.counts), total: level.total } : level);
301869
301619
  this._keptAttrs = (snapshot.keptAttrs || []).map((entry) => ({ ...entry }));
301870
301620
  }
301871
301621
  /**
@@ -302203,27 +301953,6 @@ var SQL_PATTERNS = [
302203
301953
  ];
302204
301954
  var sql_default = SQL_PATTERNS;
302205
301955
 
302206
- // node_modules/is-unsafe/src/contexts/sql-strict.js
302207
- var SQL_STRICT_EXTRA = [
302208
- {
302209
- id: "sql-line-comment",
302210
- description: "SQL line comment: -- followed by whitespace or end of string",
302211
- pattern: /--(?:\s|$)/
302212
- },
302213
- {
302214
- id: "sql-stacked-query",
302215
- description: "Stacked queries: semicolon immediately followed by a SQL keyword",
302216
- pattern: /;\s{0,10}(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC)\b/i
302217
- },
302218
- {
302219
- id: "sql-hex-encoding",
302220
- description: "Hex-encoded string injection: 0x41414141 style (MySQL)",
302221
- pattern: /\b0x[0-9a-f]{4,}/i
302222
- }
302223
- ];
302224
- var SQL_STRICT_PATTERNS = [...sql_default, ...SQL_STRICT_EXTRA];
302225
- var sql_strict_default = SQL_STRICT_PATTERNS;
302226
-
302227
301956
  // node_modules/is-unsafe/src/contexts/shell.js
302228
301957
  var SHELL_PATTERNS = [
302229
301958
  {
@@ -302535,8 +302264,38 @@ var LOG_PATTERNS = [
302535
302264
  ];
302536
302265
  var log_default = LOG_PATTERNS;
302537
302266
 
302538
- // node_modules/is-unsafe/src/registry.js
302539
- var CONTEXT_REGISTRY = {
302267
+ // node_modules/is-unsafe/src/contexts/sql-strict.js
302268
+ var SQL_STRICT_EXTRA = [
302269
+ {
302270
+ id: "sql-line-comment",
302271
+ description: "SQL line comment: -- followed by whitespace or end of string",
302272
+ pattern: /--(?:\s|$)/
302273
+ },
302274
+ {
302275
+ id: "sql-stacked-query",
302276
+ description: "Stacked queries: semicolon immediately followed by a SQL keyword",
302277
+ pattern: /;\s{0,10}(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC)\b/i
302278
+ },
302279
+ {
302280
+ id: "sql-hex-encoding",
302281
+ description: "Hex-encoded string injection: 0x41414141 style (MySQL)",
302282
+ pattern: /\b0x[0-9a-f]{4,}/i
302283
+ }
302284
+ ];
302285
+ var SQL_STRICT_PATTERNS = [...sql_default, ...SQL_STRICT_EXTRA];
302286
+ var sql_strict_default = SQL_STRICT_PATTERNS;
302287
+
302288
+ // node_modules/is-unsafe/src/index.js
302289
+ html_default.label = "HTML";
302290
+ xml_default.label = "XML";
302291
+ svg_default.label = "SVG";
302292
+ sql_default.label = "SQL";
302293
+ sql_strict_default.label = "SQL-STRICT";
302294
+ shell_default.label = "SHELL";
302295
+ redos_default.label = "REDOS";
302296
+ nosql_default.label = "NOSQL";
302297
+ log_default.label = "LOG";
302298
+ var VALID_CONTEXTS = Object.freeze({
302540
302299
  HTML: html_default,
302541
302300
  XML: xml_default,
302542
302301
  SVG: svg_default,
@@ -302546,13 +302305,7 @@ var CONTEXT_REGISTRY = {
302546
302305
  REDOS: redos_default,
302547
302306
  NOSQL: nosql_default,
302548
302307
  LOG: log_default
302549
- };
302550
- var registry_default = CONTEXT_REGISTRY;
302551
- var VALID_CONTEXTS = Object.freeze(
302552
- Object.fromEntries(Object.keys(CONTEXT_REGISTRY).map((k) => [k, k]))
302553
- );
302554
-
302555
- // node_modules/is-unsafe/src/index.js
302308
+ });
302556
302309
  function assertString(value) {
302557
302310
  if (typeof value !== "string") {
302558
302311
  throw new TypeError(
@@ -302562,36 +302315,35 @@ function assertString(value) {
302562
302315
  }
302563
302316
  function assertContext(context) {
302564
302317
  if (context instanceof RegExp) return;
302565
- if (typeof context === "string") {
302566
- if (!registry_default[context]) {
302567
- throw new TypeError(
302568
- `is-unsafe: unknown context "${context}". Valid contexts: ${Object.keys(VALID_CONTEXTS).join(", ")}`
302569
- );
302570
- }
302571
- return;
302572
- }
302573
302318
  if (Array.isArray(context)) {
302574
302319
  if (context.length === 0) {
302575
- throw new TypeError("is-unsafe: context array must not be empty");
302320
+ throw new TypeError("is-unsafe: context must not be an empty array");
302576
302321
  }
302577
- for (const c of context) {
302578
- if (typeof c !== "string" || !registry_default[c]) {
302579
- throw new TypeError(
302580
- `is-unsafe: unknown context "${c}" in array. Valid contexts: ${Object.keys(VALID_CONTEXTS).join(", ")}`
302581
- );
302322
+ if (Array.isArray(context[0])) {
302323
+ for (const list of context) {
302324
+ if (!Array.isArray(list) || list.length === 0) {
302325
+ throw new TypeError(
302326
+ "is-unsafe: each context in the array must be a non-empty pattern array (PatternList)"
302327
+ );
302328
+ }
302582
302329
  }
302583
302330
  }
302584
302331
  return;
302585
302332
  }
302586
302333
  throw new TypeError(
302587
- `is-unsafe: second argument must be a context string, array of context strings, or RegExp. Got: ${typeof context}`
302334
+ `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}`
302588
302335
  );
302589
302336
  }
302590
- function matchContext(value, contextName) {
302591
- const patterns = registry_default[contextName];
302592
- for (const rule of patterns) {
302337
+ function normalise(context) {
302338
+ if (context instanceof RegExp) return { lists: null, regex: context };
302339
+ if (Array.isArray(context[0])) return { lists: context, regex: null };
302340
+ return { lists: [context], regex: null };
302341
+ }
302342
+ function matchList(value, list) {
302343
+ const label = list.label ?? "CUSTOM";
302344
+ for (const rule of list) {
302593
302345
  if (rule.pattern.test(value)) {
302594
- return { context: contextName, id: rule.id, description: rule.description, pattern: rule.pattern };
302346
+ return { context: label, id: rule.id, description: rule.description, pattern: rule.pattern };
302595
302347
  }
302596
302348
  }
302597
302349
  return null;
@@ -302599,14 +302351,10 @@ function matchContext(value, contextName) {
302599
302351
  function isUnsafe(value, context) {
302600
302352
  assertString(value);
302601
302353
  assertContext(context);
302602
- if (context instanceof RegExp) {
302603
- return context.test(value);
302604
- }
302605
- if (typeof context === "string") {
302606
- return matchContext(value, context) !== null;
302607
- }
302608
- for (const c of context) {
302609
- if (matchContext(value, c) !== null) return true;
302354
+ const { lists, regex } = normalise(context);
302355
+ if (regex) return regex.test(value);
302356
+ for (const list of lists) {
302357
+ if (matchList(value, list) !== null) return true;
302610
302358
  }
302611
302359
  return false;
302612
302360
  }
@@ -302655,6 +302403,7 @@ var OrderedObjParser = class {
302655
302403
  this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes);
302656
302404
  this.entityExpansionCount = 0;
302657
302405
  this.currentExpandedLength = 0;
302406
+ this.doctypefound = false;
302658
302407
  let namedEntities = { ...XML };
302659
302408
  if (this.options.entityDecoder) {
302660
302409
  this.entityDecoder = this.options.entityDecoder;
@@ -302672,7 +302421,7 @@ var OrderedObjParser = class {
302672
302421
  // onExternalEntity: (name, value) => isUnsafe(value) ? 'block' : 'allow',
302673
302422
  onInputEntity: (name, value) => (
302674
302423
  //TODO: VALID_CONTEXTS.HTML should be set only if this.options.htmlEntities
302675
- isUnsafe(value, [VALID_CONTEXTS.HTML, VALID_CONTEXTS.XML]) ? ENTITY_ACTION.BLOCK : ENTITY_ACTION.ALLOW
302424
+ isUnsafe(value, [html_default, xml_default]) ? ENTITY_ACTION.BLOCK : ENTITY_ACTION.ALLOW
302676
302425
  )
302677
302426
  //postCheck: resolved => resolved
302678
302427
  });
@@ -302806,6 +302555,7 @@ var parseXml = function(xmlData) {
302806
302555
  this.entityDecoder.reset();
302807
302556
  this.entityExpansionCount = 0;
302808
302557
  this.currentExpandedLength = 0;
302558
+ this.doctypefound = false;
302809
302559
  const options = this.options;
302810
302560
  const docTypeReader = new DocTypeReader(options.processEntities);
302811
302561
  const xmlLen = xmlData.length;
@@ -302868,6 +302618,8 @@ var parseXml = function(xmlData) {
302868
302618
  }
302869
302619
  i = endIndex;
302870
302620
  } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 68) {
302621
+ if (this.doctypefound) throw new Error("Multiple DOCTYPE declarations found.");
302622
+ this.doctypefound = true;
302871
302623
  const result = docTypeReader.readDocType(xmlData, i);
302872
302624
  this.entityDecoder.addInputEntities(result.entities);
302873
302625
  i = result.i;
@@ -305459,7 +305211,7 @@ function parseWsdl(content, opts) {
305459
305211
  }
305460
305212
 
305461
305213
  // src/lib/protocols/soap/builder.ts
305462
- var import_node_crypto4 = require("node:crypto");
305214
+ var import_node_crypto5 = require("node:crypto");
305463
305215
  var COLLECTION_V210_SCHEMA2 = "https://schema.getpostman.com/json/collection/v2.1.0/collection.json";
305464
305216
  var SOAP11_ENVELOPE_NS = "http://schemas.xmlsoap.org/soap/envelope/";
305465
305217
  var SOAP12_ENVELOPE_NS = "http://www.w3.org/2003/05/soap-envelope";
@@ -305467,7 +305219,7 @@ var SOAP11_CONTENT_TYPE = "text/xml; charset=UTF-8";
305467
305219
  var SOAP12_CONTENT_TYPE = "application/soap+xml; charset=UTF-8";
305468
305220
  var WSA_NS = "http://www.w3.org/2005/08/addressing";
305469
305221
  function stableId2(seed) {
305470
- return (0, import_node_crypto4.createHash)("sha256").update(seed).digest("hex").slice(0, 32);
305222
+ return (0, import_node_crypto5.createHash)("sha256").update(seed).digest("hex").slice(0, 32);
305471
305223
  }
305472
305224
  function envelopeNamespace(version) {
305473
305225
  return version === "1.2" ? SOAP12_ENVELOPE_NS : SOAP11_ENVELOPE_NS;
@@ -312230,6 +311982,11 @@ function resolveInputs(env = process.env) {
312230
311982
  ),
312231
311983
  protocolEndpointUrl: getInput2("protocol-endpoint-url", env),
312232
311984
  openapiVersion: resolveOpenapiVersion(getInput2("openapi-version", env)),
311985
+ preserveOas30TypeNull: parseBooleanInput(
311986
+ "preserve-oas30-type-null",
311987
+ getInput2("preserve-oas30-type-null", env),
311988
+ false
311989
+ ),
312233
311990
  breakingChangeMode: parseBreakingChangeMode(getInput2("breaking-change-mode", env)),
312234
311991
  breakingBaselineSpecPath: getInput2("breaking-baseline-spec-path", env),
312235
311992
  breakingRulesPath: getInput2("breaking-rules-path", env) ?? bootstrapActionContract.inputs["breaking-rules-path"].default,
@@ -312237,8 +311994,8 @@ function resolveInputs(env = process.env) {
312237
311994
  breakingSummaryPath: getInput2("breaking-summary-path", env),
312238
311995
  breakingLogPath: getInput2("breaking-log-path", env),
312239
311996
  governanceMappingJson: parseGovernanceMappingJson(getInput2("governance-mapping-json", env)),
312240
- postmanApiKey: getInput2("postman-api-key", env) ?? "",
312241
- postmanAccessToken: getInput2("postman-access-token", env),
311997
+ postmanApiKey: getInput2("postman-api-key", env) || env.POSTMAN_API_KEY || "",
311998
+ postmanAccessToken: getInput2("postman-access-token", env) || env.POSTMAN_ACCESS_TOKEN,
312242
311999
  credentialPreflight: parseEnumInput(
312243
312000
  "credential-preflight",
312244
312001
  getInput2("credential-preflight", env),
@@ -312260,9 +312017,75 @@ function resolveInputs(env = process.env) {
312260
312017
  githubRef: env.GITHUB_REF,
312261
312018
  githubSha: env.GITHUB_SHA,
312262
312019
  githubToken: getInput2("github-token", env) || env.GITHUB_TOKEN || "",
312263
- ghFallbackToken: getInput2("gh-fallback-token", env) || env.GH_FALLBACK_TOKEN || ""
312020
+ ghFallbackToken: getInput2("gh-fallback-token", env) || env.GH_FALLBACK_TOKEN || "",
312021
+ branchStrategy: parseEnumInput(
312022
+ "branch-strategy",
312023
+ getInput2("branch-strategy", env),
312024
+ "legacy"
312025
+ ),
312026
+ canonicalBranch: getInput2("canonical-branch", env),
312027
+ channels: getInput2("channels", env)
312264
312028
  };
312265
312029
  }
312030
+ function decideBranchTier(inputs, env = process.env) {
312031
+ return resolveEffectiveBranchDecision(
312032
+ {
312033
+ // Tolerate hand-built inputs objects (tests, embedders) that omit the
312034
+ // field: absent means legacy, exactly like the action default.
312035
+ strategy: inputs.branchStrategy ?? "legacy",
312036
+ identity: resolveBranchIdentity(env, { defaultBranch: inputs.canonicalBranch }),
312037
+ canonicalBranch: inputs.canonicalBranch,
312038
+ channels: parseChannelRules(inputs.channels)
312039
+ },
312040
+ env
312041
+ );
312042
+ }
312043
+ function buildSpecVersionUrl(workspaceId, specId, tagId, versionLabel) {
312044
+ return "https://go.postman.co/workspace/" + workspaceId + "/specification/" + specId + "?tagId=" + encodeURIComponent(tagId) + "&versionLabel=" + encodeURIComponent(versionLabel);
312045
+ }
312046
+ function embedSpecBranchMarker(content, decision, repo) {
312047
+ if (decision.tier !== "preview" && decision.tier !== "channel" || !decision.identity.headBranch || !repo) {
312048
+ return content;
312049
+ }
312050
+ const rawBranch = decision.identity.headBranch;
312051
+ const now = (/* @__PURE__ */ new Date()).toISOString();
312052
+ const marker = {
312053
+ repo,
312054
+ rawBranch,
312055
+ sanitizedBranch: rawBranch.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/-+/g, "-").slice(0, 30),
312056
+ role: decision.tier,
312057
+ headSha: decision.identity.headSha,
312058
+ createdAt: now,
312059
+ lastSyncedAt: now
312060
+ };
312061
+ try {
312062
+ if (content.trim().startsWith("{")) {
312063
+ return `${JSON.stringify({ ...JSON.parse(content), "x-postman-onboarding": marker }, null, 2)}
312064
+ `;
312065
+ }
312066
+ const document2 = (0, import_yaml4.parse)(content);
312067
+ if (!document2 || typeof document2 !== "object" || Array.isArray(document2)) return content;
312068
+ return (0, import_yaml4.stringify)({ ...document2, "x-postman-onboarding": marker });
312069
+ } catch {
312070
+ return content;
312071
+ }
312072
+ }
312073
+ function renderCollectionBranchMarker(decision, repo, now = /* @__PURE__ */ new Date()) {
312074
+ if (decision.tier !== "preview" && decision.tier !== "channel" || !decision.identity.headBranch || !repo) {
312075
+ return void 0;
312076
+ }
312077
+ const rawBranch = decision.identity.headBranch;
312078
+ const timestamp = now.toISOString();
312079
+ return renderAssetMarker({
312080
+ repo,
312081
+ rawBranch,
312082
+ sanitizedBranch: rawBranch.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/-+/g, "-").slice(0, 30),
312083
+ role: decision.tier,
312084
+ headSha: decision.identity.headSha,
312085
+ createdAt: timestamp,
312086
+ lastSyncedAt: timestamp
312087
+ });
312088
+ }
312266
312089
  function createPlannedOutputs(inputs) {
312267
312090
  const workspaceName = inputs.domainCode ? `[${inputs.domainCode}] ${inputs.projectName}` : inputs.projectName;
312268
312091
  return {
@@ -312294,7 +312117,12 @@ function createPlannedOutputs(inputs) {
312294
312117
  mode: inputs.breakingChangeMode,
312295
312118
  status: "skipped",
312296
312119
  summaryPath: ""
312297
- })
312120
+ }),
312121
+ "sync-status": "",
312122
+ "branch-decision": "",
312123
+ "spec-version-tag": "",
312124
+ "spec-version-url": "",
312125
+ "spec-content-changed": ""
312298
312126
  };
312299
312127
  }
312300
312128
  function warnIfDeprecatedAccessToken(actionCore, inputs) {
@@ -312329,11 +312157,8 @@ function readActionInputs(actionCore) {
312329
312157
  if (specUrl && specPath) {
312330
312158
  throw new Error("Provide either spec-url or spec-path, not both.");
312331
312159
  }
312332
- const postmanApiKey = optionalInput(actionCore, "postman-api-key") ?? "";
312333
- const postmanAccessToken = optionalInput(actionCore, "postman-access-token");
312334
- if (!postmanApiKey && !postmanAccessToken) {
312335
- throw new Error("One of postman-api-key or postman-access-token is required.");
312336
- }
312160
+ const postmanApiKey = optionalInput(actionCore, "postman-api-key") || process.env.POSTMAN_API_KEY || "";
312161
+ const postmanAccessToken = optionalInput(actionCore, "postman-access-token") || process.env.POSTMAN_ACCESS_TOKEN;
312337
312162
  const githubToken = optionalInput(actionCore, "github-token") || process.env.GITHUB_TOKEN;
312338
312163
  const ghFallbackToken = optionalInput(actionCore, "gh-fallback-token") || process.env.GH_FALLBACK_TOKEN;
312339
312164
  if (postmanApiKey) actionCore.setSecret(postmanApiKey);
@@ -312377,6 +312202,7 @@ function readActionInputs(actionCore) {
312377
312202
  INPUT_NESTED_FOLDER_HIERARCHY: optionalInput(actionCore, "nested-folder-hierarchy") ?? bootstrapActionContract.inputs["nested-folder-hierarchy"].default,
312378
312203
  INPUT_REQUEST_NAME_SOURCE: optionalInput(actionCore, "request-name-source") ?? bootstrapActionContract.inputs["request-name-source"].default,
312379
312204
  INPUT_OPENAPI_VERSION: optionalInput(actionCore, "openapi-version") ?? "",
312205
+ INPUT_PRESERVE_OAS30_TYPE_NULL: optionalInput(actionCore, "preserve-oas30-type-null") ?? bootstrapActionContract.inputs["preserve-oas30-type-null"].default,
312380
312206
  INPUT_BREAKING_CHANGE_MODE: optionalInput(actionCore, "breaking-change-mode") ?? bootstrapActionContract.inputs["breaking-change-mode"].default,
312381
312207
  INPUT_BREAKING_BASELINE_SPEC_PATH: optionalInput(actionCore, "breaking-baseline-spec-path"),
312382
312208
  INPUT_BREAKING_RULES_PATH: optionalInput(actionCore, "breaking-rules-path") ?? bootstrapActionContract.inputs["breaking-rules-path"].default,
@@ -312487,6 +312313,27 @@ async function lintSpecViaCli(dependencies, workspaceId, specId) {
312487
312313
  warnings
312488
312314
  };
312489
312315
  }
312316
+ function normalizeLintPath(value) {
312317
+ return value.trim().replace(/^\$\.?/, "").replace(/\[(\d+)\]/g, ".$1").replace(/^\./, "");
312318
+ }
312319
+ function applyOas30TypeNullLintCompatibility(summary2, sourceTypeNullPaths) {
312320
+ const acceptedPaths = new Set(sourceTypeNullPaths.map(normalizeLintPath));
312321
+ if (acceptedPaths.size === 0) return summary2;
312322
+ const violations = summary2.violations.map((violation) => {
312323
+ const path10 = normalizeLintPath(violation.path ?? "");
312324
+ const issue2 = violation.issue ?? "";
312325
+ const isTypeEnumFinding = /["']?type["']? property/i.test(issue2) && /allowed values|must be equal to one of/i.test(issue2);
312326
+ if (violation.severity === "ERROR" && acceptedPaths.has(path10) && isTypeEnumFinding) {
312327
+ return { ...violation, severity: "WARNING" };
312328
+ }
312329
+ return violation;
312330
+ });
312331
+ return {
312332
+ errors: violations.filter((entry) => entry.severity === "ERROR").length,
312333
+ violations,
312334
+ warnings: violations.filter((entry) => entry.severity === "WARNING").length
312335
+ };
312336
+ }
312490
312337
  function shouldRetrySpecFetch(error2) {
312491
312338
  const retryability = classifySafeFetchRetryability(error2);
312492
312339
  return retryability === "retryable" || retryability === "unknown";
@@ -312967,7 +312814,7 @@ async function runProtocolBootstrap(specType, rawSpecContent, inputs, dependenci
312967
312814
  const workspaceRoot = path9.resolve(process.env.GITHUB_WORKSPACE ?? process.cwd());
312968
312815
  const serviceConfigPath = path9.join(path9.dirname(path9.resolve(workspaceRoot, inputs.specPath)), "grpc_service_config.json");
312969
312816
  try {
312970
- grpcServiceConfigJson = (0, import_node_fs5.readFileSync)(serviceConfigPath, "utf8");
312817
+ grpcServiceConfigJson = (0, import_node_fs6.readFileSync)(serviceConfigPath, "utf8");
312971
312818
  dependencies.core.info(`Found gRPC service config at ${serviceConfigPath}; validating it against the proto contract`);
312972
312819
  } catch {
312973
312820
  }
@@ -312981,7 +312828,7 @@ async function runProtocolBootstrap(specType, rawSpecContent, inputs, dependenci
312981
312828
  const resolved = path9.resolve(specDir, location2);
312982
312829
  if (!resolved.startsWith(specDir + path9.sep)) return void 0;
312983
312830
  try {
312984
- return (0, import_node_fs5.readFileSync)(resolved, "utf8");
312831
+ return (0, import_node_fs6.readFileSync)(resolved, "utf8");
312985
312832
  } catch {
312986
312833
  return void 0;
312987
312834
  }
@@ -313122,6 +312969,42 @@ async function createExtensibleContractCollection(workspaceId, built, inputs, de
313122
312969
  }
313123
312970
  async function runBootstrapInner(inputs, dependencies, telemetry) {
313124
312971
  const outputs = createPlannedOutputs(inputs);
312972
+ const branchDecision = decideBranchTier(inputs);
312973
+ const isCanonicalWriter = branchDecision.tier === "legacy" || branchDecision.tier === "canonical";
312974
+ const canonicalProjectName = inputs.projectName;
312975
+ const workspaceName = createWorkspaceName(inputs);
312976
+ const aboutText = `Auto-provisioned by Postman for ${inputs.projectName}`;
312977
+ if (branchDecision.tier === "preview" && branchDecision.identity.headBranch) {
312978
+ inputs = {
312979
+ ...inputs,
312980
+ projectName: previewAssetName(inputs.projectName, branchDecision.identity.headBranch)
312981
+ };
312982
+ dependencies.core.info(`branch-aware sync: preview asset set "${inputs.projectName}"`);
312983
+ } else if (branchDecision.tier === "channel" && branchDecision.channel) {
312984
+ inputs = {
312985
+ ...inputs,
312986
+ projectName: channelAssetName(inputs.projectName, branchDecision.channel.code)
312987
+ };
312988
+ dependencies.core.info(`branch-aware sync: channel asset set "${inputs.projectName}"`);
312989
+ }
312990
+ const collectionBranchMarker = renderCollectionBranchMarker(branchDecision, inputs.repoUrl);
312991
+ if (branchDecision.tier !== "legacy") {
312992
+ outputs["sync-status"] = "synced";
312993
+ outputs["branch-decision"] = serializeBranchDecision(branchDecision);
312994
+ }
312995
+ if (!isCanonicalWriter) {
312996
+ const explicitCanonicalIds = [
312997
+ ["spec-id", inputs.specId],
312998
+ ["baseline-collection-id", inputs.baselineCollectionId],
312999
+ ["smoke-collection-id", inputs.smokeCollectionId],
313000
+ ["contract-collection-id", inputs.contractCollectionId]
313001
+ ].filter(([, value]) => Boolean(value));
313002
+ if (explicitCanonicalIds.length > 0) {
313003
+ throw new Error(
313004
+ `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).`
313005
+ );
313006
+ }
313007
+ }
313125
313008
  const requiresReleaseLabel = inputs.collectionSyncMode === "version" || inputs.specSyncMode === "version";
313126
313009
  const releaseLabel = requiresReleaseLabel ? deriveReleaseLabel(inputs) : void 0;
313127
313010
  if (requiresReleaseLabel && !releaseLabel) {
@@ -313129,11 +313012,23 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313129
313012
  "Versioned spec or collection sync requires a release-label or derivable GitHub ref metadata"
313130
313013
  );
313131
313014
  }
313132
- const collectionAssetProjectName = inputs.collectionSyncMode === "version" ? createAssetProjectName(inputs, releaseLabel) : inputs.projectName;
313133
- const workspaceName = createWorkspaceName(inputs);
313134
- const aboutText = `Auto-provisioned by Postman for ${inputs.projectName}`;
313135
- const stateStore = resolveResourcesStateStore(dependencies);
313136
- const resourcesState = stateStore.read();
313015
+ const collectionAssetProjectName = branchDecision.tier === "channel" ? canonicalProjectName : inputs.collectionSyncMode === "version" ? createAssetProjectName(inputs, releaseLabel) : inputs.projectName;
313016
+ const rawStateStore = resolveResourcesStateStore(dependencies);
313017
+ const trackedState = rawStateStore.read();
313018
+ const stateStore = isCanonicalWriter ? rawStateStore : {
313019
+ read: rawStateStore.read,
313020
+ write: () => {
313021
+ dependencies.core.info(
313022
+ `branch-aware sync: skipping .postman/resources.yaml write on ${branchDecision.tier} run (canonical-only tracked state)`
313023
+ );
313024
+ }
313025
+ };
313026
+ const resourcesState = isCanonicalWriter ? trackedState : trackedState?.workspace ? { workspace: trackedState.workspace } : null;
313027
+ if (!isCanonicalWriter && trackedState?.cloudResources) {
313028
+ dependencies.core.info(
313029
+ "branch-aware sync: canonical asset ids in .postman/resources.yaml are not resolved on a non-canonical run"
313030
+ );
313031
+ }
313137
313032
  const writableResourcesState = resourcesState ?? {};
313138
313033
  const additionalCollections = loadAdditionalCollectionFiles(
313139
313034
  inputs.additionalCollectionsDir,
@@ -313153,16 +313048,19 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313153
313048
  }
313154
313049
  let previousSpecContent;
313155
313050
  let previousSpecRollbackHash;
313051
+ let specContentUnchanged = false;
313156
313052
  let detectedOpenapiVersion = "3.0";
313157
313053
  let contractIndex;
313158
313054
  let sourceSpecContent = "";
313055
+ let sourceTypeNullPaths = [];
313056
+ let preserveSourceSpecBytes = false;
313159
313057
  const rawSpecContent = await runGroup(
313160
313058
  dependencies.core,
313161
313059
  "Read API Spec",
313162
313060
  async () => {
313163
313061
  if (inputs.specPath) {
313164
313062
  const workspaceRoot = path9.resolve(process.env.GITHUB_WORKSPACE ?? process.cwd());
313165
- return (0, import_node_fs5.readFileSync)(path9.resolve(workspaceRoot, inputs.specPath), "utf8");
313063
+ return (0, import_node_fs6.readFileSync)(path9.resolve(workspaceRoot, inputs.specPath), "utf8");
313166
313064
  }
313167
313065
  if (dependencies.specFetcher === fetch) {
313168
313066
  return safeFetchText(inputs.specUrl, { depth: 0 });
@@ -313198,6 +313096,7 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313198
313096
  };
313199
313097
  const rootKey = inputs.specPath ? void 0 : normalizeRef(inputs.specUrl);
313200
313098
  const loaderOptions = {
313099
+ preserveOas30TypeNull: Boolean(inputs.preserveOas30TypeNull),
313201
313100
  fetchText: async (url, fetchOptions) => {
313202
313101
  if (rootKey && normalizeRef(url) === rootKey) return rawSpecContent;
313203
313102
  if (dependencies.specFetcher === fetch) return safeFetchText(url, fetchOptions);
@@ -313206,6 +313105,8 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313206
313105
  };
313207
313106
  const loaded = inputs.specPath ? await loadOpenApiContractSpecFromPath(inputs.specPath, loaderOptions) : await loadOpenApiContractSpec(inputs.specUrl, loaderOptions);
313208
313107
  sourceSpecContent = loaded.content;
313108
+ sourceTypeNullPaths = loaded.sourceTypeNullPaths;
313109
+ preserveSourceSpecBytes = sourceTypeNullPaths.length > 0;
313209
313110
  const document2 = normalizeSpecDocument(
313210
313111
  loaded.bundledContent,
313211
313112
  (msg) => dependencies.core.warning(msg)
@@ -313228,11 +313129,11 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313228
313129
  `Unable to verify existing Spec Hub OpenAPI version for spec-id ${specId}; clear spec-id to create a fresh spec`
313229
313130
  );
313230
313131
  }
313231
- previousSpecContent = normalizeSpecDocument(
313132
+ previousSpecContent = preserveSourceSpecBytes ? previousRaw : normalizeSpecDocument(
313232
313133
  previousRaw,
313233
313134
  (msg) => dependencies.core.warning(`Previous spec normalization: ${msg}`)
313234
313135
  );
313235
- previousSpecRollbackHash = (0, import_node_crypto5.createHash)("sha256").update(previousSpecContent).digest("hex");
313136
+ previousSpecRollbackHash = (0, import_node_crypto6.createHash)("sha256").update(previousSpecContent).digest("hex");
313236
313137
  const existingSpecType = normalizeSpecTypeFromContent(previousSpecContent);
313237
313138
  if (existingSpecType !== incomingSpecType) {
313238
313139
  throw new Error(
@@ -313243,6 +313144,12 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313243
313144
  dependencies.core.info(
313244
313145
  `Auto-detected OpenAPI version from spec content: ${detectedOpenapiVersion}`
313245
313146
  );
313147
+ if (preserveSourceSpecBytes) {
313148
+ dependencies.core.info(
313149
+ `Preserving original OpenAPI source bytes; accepted ${sourceTypeNullPaths.length} legacy type: null member(s) for internal validation`
313150
+ );
313151
+ return loaded.content;
313152
+ }
313246
313153
  return document2;
313247
313154
  }
313248
313155
  );
@@ -313278,6 +313185,11 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313278
313185
  `OpenAPI breaking-change check failed: ${breakingChangeResult.message || "breaking changes detected"}`
313279
313186
  );
313280
313187
  }
313188
+ const uploadSpecContent = embedSpecBranchMarker(
313189
+ specContent,
313190
+ branchDecision,
313191
+ inputs.repoUrl
313192
+ );
313281
313193
  const provisioned = await provisionWorkspace(
313282
313194
  inputs,
313283
313195
  dependencies,
@@ -313402,10 +313314,17 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313402
313314
  specId ? "Update Spec in Spec Hub" : "Upload Spec to Spec Hub",
313403
313315
  async () => {
313404
313316
  if (specId) {
313405
- dependencies.core.info(
313406
- `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.`
313407
- );
313408
- await dependencies.postman.updateSpec(specId, specContent, workspaceId);
313317
+ if (previousSpecContent !== void 0 && (0, import_node_crypto6.createHash)("sha256").update(uploadSpecContent).digest("hex") === (0, import_node_crypto6.createHash)("sha256").update(previousSpecContent).digest("hex")) {
313318
+ specContentUnchanged = true;
313319
+ dependencies.core.info(
313320
+ `Spec content unchanged (sha256 match); skipping Spec Hub update and version tag for ${specId}.`
313321
+ );
313322
+ } else {
313323
+ dependencies.core.info(
313324
+ `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.`
313325
+ );
313326
+ await dependencies.postman.updateSpec(specId, uploadSpecContent, workspaceId);
313327
+ }
313409
313328
  } else {
313410
313329
  specId = await dependencies.postman.uploadSpec(
313411
313330
  workspaceId || "",
@@ -313413,7 +313332,7 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313413
313332
  inputs,
313414
313333
  inputs.specSyncMode === "version" ? releaseLabel : void 0
313415
313334
  ),
313416
- specContent,
313335
+ uploadSpecContent,
313417
313336
  detectedOpenapiVersion
313418
313337
  );
313419
313338
  }
@@ -313430,8 +313349,9 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313430
313349
  }
313431
313350
  )
313432
313351
  );
313352
+ outputs["spec-content-changed"] = isCanonicalWriter && !specContentUnchanged ? "true" : "false";
313433
313353
  if (lintEnabled) {
313434
- const lintSummary = await runRollbackStage(
313354
+ let lintSummary = await runRollbackStage(
313435
313355
  "Lint Spec via Postman CLI",
313436
313356
  async () => runGroup(
313437
313357
  dependencies.core,
@@ -313439,6 +313359,16 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313439
313359
  async () => lintSpecViaCli(dependencies, workspaceId || "", outputs["spec-id"])
313440
313360
  )
313441
313361
  );
313362
+ if (preserveSourceSpecBytes) {
313363
+ const originalErrorCount = lintSummary.errors;
313364
+ lintSummary = applyOas30TypeNullLintCompatibility(lintSummary, sourceTypeNullPaths);
313365
+ const acceptedCount = originalErrorCount - lintSummary.errors;
313366
+ if (acceptedCount > 0) {
313367
+ dependencies.core.info(
313368
+ `Accepted ${acceptedCount} Postman CLI type: null finding(s) covered by preserve-oas30-type-null`
313369
+ );
313370
+ }
313371
+ }
313442
313372
  outputs["lint-summary-json"] = JSON.stringify({
313443
313373
  errors: lintSummary.errors,
313444
313374
  total: lintSummary.violations.length,
@@ -313463,7 +313393,12 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313463
313393
  });
313464
313394
  dependencies.core.warning("lint skipped: governance errors not enforced (no postman-api-key)");
313465
313395
  }
313466
- await runRollbackStage(
313396
+ if (specContentUnchanged) {
313397
+ outputs["baseline-collection-id"] = baselineCollectionId || "";
313398
+ outputs["smoke-collection-id"] = smokeCollectionId || "";
313399
+ outputs["contract-collection-id"] = contractCollectionId || "";
313400
+ dependencies.core.info("Spec content unchanged; skipping collection regeneration and version finalization.");
313401
+ } else await runRollbackStage(
313467
313402
  "Generate Collections from Spec",
313468
313403
  async () => runGroup(
313469
313404
  dependencies.core,
@@ -313502,10 +313437,11 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313502
313437
  return;
313503
313438
  }
313504
313439
  }
313440
+ const effectivePrefix = branchDecision.tier === "channel" && branchDecision.channel ? channelAssetName(prefix, branchDecision.channel.code).trim() : prefix;
313505
313441
  outputs[outputKey] = await dependencies.postman.generateCollection(
313506
313442
  specId2,
313507
313443
  assetProjectName,
313508
- prefix,
313444
+ effectivePrefix,
313509
313445
  inputs.folderStrategy,
313510
313446
  inputs.nestedFolderHierarchy,
313511
313447
  inputs.requestNameSource
@@ -313526,6 +313462,32 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313526
313462
  await ensureCollection(BASELINE_COLLECTION_PREFIX, baselineCollectionId, "baseline-collection-id");
313527
313463
  await ensureCollection(SMOKE_COLLECTION_PREFIX, smokeCollectionId, "smoke-collection-id");
313528
313464
  await ensureCollection(CONTRACT_COLLECTION_PREFIX, contractCollectionId, "contract-collection-id");
313465
+ if (dependencies.postman.adoptGeneratedCollection) {
313466
+ const reelect = async (prefix, outputKey) => {
313467
+ const effectivePrefix = branchDecision.tier === "channel" && branchDecision.channel ? channelAssetName(prefix, branchDecision.channel.code).trim() : prefix;
313468
+ const preferred = outputs[outputKey];
313469
+ if (!preferred) return;
313470
+ outputs[outputKey] = await dependencies.postman.adoptGeneratedCollection(
313471
+ specId2,
313472
+ assetProjectName,
313473
+ effectivePrefix,
313474
+ preferred
313475
+ );
313476
+ };
313477
+ await reelect(BASELINE_COLLECTION_PREFIX, "baseline-collection-id");
313478
+ await reelect(SMOKE_COLLECTION_PREFIX, "smoke-collection-id");
313479
+ await reelect(CONTRACT_COLLECTION_PREFIX, "contract-collection-id");
313480
+ }
313481
+ if (collectionBranchMarker) {
313482
+ if (!dependencies.postman.updateCollectionDescription) {
313483
+ throw new Error("Branch-scoped collections require updateCollectionDescription support");
313484
+ }
313485
+ await Promise.all([
313486
+ outputs["baseline-collection-id"],
313487
+ outputs["smoke-collection-id"],
313488
+ outputs["contract-collection-id"]
313489
+ ].filter(Boolean).map((id) => dependencies.postman.updateCollectionDescription(id, collectionBranchMarker)));
313490
+ }
313529
313491
  if (!dependencies.postman.injectContractTests) {
313530
313492
  throw new Error(
313531
313493
  "Dynamic contract tests require injectContractTests support from the access-token gateway client"
@@ -313628,6 +313590,12 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313628
313590
  workspaceId: workspaceId || ""
313629
313591
  });
313630
313592
  for (const result of additionalResults) {
313593
+ if (collectionBranchMarker) {
313594
+ if (!dependencies.postman.updateCollectionDescription) {
313595
+ throw new Error("Branch-scoped collections require updateCollectionDescription support");
313596
+ }
313597
+ await dependencies.postman.updateCollectionDescription(result.collectionId, collectionBranchMarker);
313598
+ }
313631
313599
  completedExternalSideEffects.push(
313632
313600
  `${result.operation}AdditionalCollection(${result.collectionId} from ${result.displayPath})`
313633
313601
  );
@@ -313703,8 +313671,66 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
313703
313671
  }
313704
313672
  return outputs;
313705
313673
  }
313674
+ async function runGatedValidation(inputs, decision, actionCore) {
313675
+ actionCore.info(`branch-aware sync: gated run (${decision.reason}) \u2014 credential-free static validation, zero workspace writes`);
313676
+ const outputs = createPlannedOutputs(inputs);
313677
+ outputs["sync-status"] = "skipped-branch-gate";
313678
+ outputs["branch-decision"] = serializeBranchDecision(decision);
313679
+ let violations = [];
313680
+ let validated = false;
313681
+ try {
313682
+ let content;
313683
+ if (inputs.specPath) {
313684
+ content = (0, import_node_fs6.readFileSync)(inputs.specPath, "utf8");
313685
+ } else if (inputs.specUrl) {
313686
+ content = await safeFetchText(inputs.specUrl, { depth: 0 });
313687
+ }
313688
+ if (content) {
313689
+ const specType = detectSpecType(content, inputs.specPath);
313690
+ if (specType === "openapi") {
313691
+ const document2 = parseOpenApiDocument(content);
313692
+ const index = buildContractIndex(document2);
313693
+ violations = index.warnings;
313694
+ validated = true;
313695
+ } else {
313696
+ actionCore.info(`branch gate: static lint for spec type ${specType} runs through its protocol builder on publish; parse-only gate applied`);
313697
+ validated = true;
313698
+ }
313699
+ } else {
313700
+ actionCore.info("branch gate: no spec-url/spec-path provided; nothing to validate");
313701
+ }
313702
+ } catch (error2) {
313703
+ throw new Error(
313704
+ `branch gate: static validation failed: ${error2 instanceof Error ? error2.message : String(error2)}`,
313705
+ { cause: error2 }
313706
+ );
313707
+ }
313708
+ outputs["lint-summary-json"] = JSON.stringify({
313709
+ status: validated ? "static-only" : "skipped",
313710
+ reason: "branch-gated run: governance lint requires upload and runs on publish/preview syncs",
313711
+ errors: 0,
313712
+ warnings: violations.length,
313713
+ total: violations.length,
313714
+ violations: violations.map((issue2) => ({ issue: issue2, severity: "WARNING" }))
313715
+ });
313716
+ for (const [name, value] of Object.entries(outputs)) {
313717
+ actionCore.setOutput(name, value);
313718
+ }
313719
+ return outputs;
313720
+ }
313706
313721
  async function runAction(actionCore = core_exports, actionExec = exec_exports, actionIo = io_exports) {
313707
313722
  const inputs = readActionInputs(actionCore);
313723
+ const branchDecision = decideBranchTier(inputs);
313724
+ if (branchDecision.tier === "gated") {
313725
+ return runGatedValidation(inputs, branchDecision, actionCore);
313726
+ }
313727
+ if (!inputs.postmanApiKey && !inputs.postmanAccessToken) {
313728
+ throw new Error("One of postman-api-key or postman-access-token is required for a writing sync.");
313729
+ }
313730
+ if (branchDecision.tier !== "legacy") {
313731
+ actionCore.info(`branch-aware sync: tier=${branchDecision.tier} (${branchDecision.reason})`);
313732
+ process.env[BRANCH_DECISION_ENV] = serializeBranchDecision(branchDecision);
313733
+ }
313708
313734
  await mintAccessTokenIfNeeded2(inputs, {
313709
313735
  info: (message) => actionCore.info(message),
313710
313736
  warning: (message) => actionCore.warning(message)
@@ -313781,6 +313807,7 @@ function createRoutingPostmanClient(options) {
313781
313807
  updateSpec: requireAccessToken("updateSpec"),
313782
313808
  getSpecContent: requireAccessToken("getSpecContent"),
313783
313809
  generateCollection: requireAccessToken("generateCollection"),
313810
+ adoptGeneratedCollection: requireAccessToken("adoptGeneratedCollection"),
313784
313811
  createWorkspace: requireAccessToken("createWorkspace"),
313785
313812
  getWorkspaceVisibility: requireAccessToken("getWorkspaceVisibility"),
313786
313813
  getWorkspaceGitRepoUrl: requireAccessToken("getWorkspaceGitRepoUrl"),
@@ -313790,10 +313817,13 @@ function createRoutingPostmanClient(options) {
313790
313817
  inviteRequesterToWorkspace: requireAccessToken("inviteRequesterToWorkspace"),
313791
313818
  injectTests: requireAccessToken("injectTests"),
313792
313819
  tagCollection: requireAccessToken("tagCollection"),
313820
+ tagSpecVersion: requireAccessToken("tagSpecVersion"),
313821
+ listSpecVersionTags: requireAccessToken("listSpecVersionTags"),
313793
313822
  deleteCollection: requireAccessToken("deleteCollection"),
313794
313823
  injectContractTests: requireAccessToken("injectContractTests"),
313795
313824
  createCollection: requireAccessToken("createCollection"),
313796
- updateCollection: requireAccessToken("updateCollection")
313825
+ updateCollection: requireAccessToken("updateCollection"),
313826
+ updateCollectionDescription: requireAccessToken("updateCollectionDescription")
313797
313827
  };
313798
313828
  }
313799
313829
  return {
@@ -313805,6 +313835,7 @@ function createRoutingPostmanClient(options) {
313805
313835
  // not a reason to reach for the API key.
313806
313836
  uploadSpec: (workspaceId, projectName, specContent, openapiVersion) => gateway.uploadSpec(workspaceId, projectName, specContent, openapiVersion ?? "3.0"),
313807
313837
  generateCollection: (specId, projectName, prefix, folderStrategy, nestedFolderHierarchy, requestNameSource) => gateway.generateCollection(specId, projectName, prefix, folderStrategy, nestedFolderHierarchy, requestNameSource),
313838
+ adoptGeneratedCollection: (specId, projectName, prefix, preferredId) => gateway.adoptGeneratedCollection(specId, projectName, prefix, preferredId),
313808
313839
  updateSpec: (specId, specContent, workspaceId) => gateway.updateSpec(specId, specContent, workspaceId),
313809
313840
  getSpecContent: (specId) => gateway.getSpecContent(specId),
313810
313841
  createWorkspace: (name, about, targetTeamId) => gateway.createWorkspace(name, about, targetTeamId),
@@ -313816,6 +313847,8 @@ function createRoutingPostmanClient(options) {
313816
313847
  // + tagging surfaces (live-proven). PMAK is reserved for token minting, so
313817
313848
  // these never fall back to the API key even when one is present.
313818
313849
  injectTests: (collectionId, type) => gateway.injectTests(collectionId, type),
313850
+ tagSpecVersion: (specId, name) => gateway.tagSpecVersion(specId, name),
313851
+ listSpecVersionTags: (specId) => gateway.listSpecVersionTags(specId),
313819
313852
  tagCollection: (collectionId, tags) => gateway.tagCollection(collectionId, tags),
313820
313853
  // Sub-team (squad) enumeration over the gateway `ums` service. Access-token
313821
313854
  // only — never PMAK — so org-mode detection no longer needs a PMAK GET /teams.
@@ -313833,7 +313866,8 @@ function createRoutingPostmanClient(options) {
313833
313866
  // so no asset op ever reaches for the API key.
313834
313867
  injectContractTests: (collectionUid, index) => gateway.injectContractTests(collectionUid, index),
313835
313868
  createCollection: (workspaceId, collection, options2) => gateway.createCollection(workspaceId, collection, options2),
313836
- updateCollection: (collectionUid, collection) => gateway.updateCollection(collectionUid, collection)
313869
+ updateCollection: (collectionUid, collection) => gateway.updateCollection(collectionUid, collection),
313870
+ updateCollectionDescription: (collectionUid, description) => gateway.updateCollectionDescription(collectionUid, description)
313837
313871
  };
313838
313872
  }
313839
313873
  function createBootstrapDependencies(inputs, factories, orgMode = false) {
@@ -313907,19 +313941,25 @@ function createBootstrapDependencies(inputs, factories, orgMode = false) {
313907
313941
  }
313908
313942
  // Annotate the CommonJS export names for ESM import in node:
313909
313943
  0 && (module.exports = {
313944
+ applyOas30TypeNullLintCompatibility,
313945
+ buildSpecVersionUrl,
313910
313946
  createBootstrapDependencies,
313911
313947
  createExtensibleContractCollection,
313912
313948
  createPlannedOutputs,
313913
313949
  createRoutingPostmanClient,
313950
+ decideBranchTier,
313951
+ embedSpecBranchMarker,
313914
313952
  ensurePostmanCli,
313915
313953
  getInput,
313916
313954
  lintSpecViaCli,
313917
313955
  mintAccessTokenIfNeeded,
313918
313956
  normalizeSpecDocument,
313919
313957
  readActionInputs,
313958
+ renderCollectionBranchMarker,
313920
313959
  resolveInputs,
313921
313960
  runAction,
313922
- runBootstrap
313961
+ runBootstrap,
313962
+ runGatedValidation
313923
313963
  });
313924
313964
  /*! Bundled license information:
313925
313965