@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/cli.cjs CHANGED
@@ -99990,11 +99990,11 @@ var require_valid = __commonJS({
99990
99990
  var require_clean = __commonJS({
99991
99991
  "node_modules/postman-collection/node_modules/semver/functions/clean.js"(exports2, module2) {
99992
99992
  var parse10 = require_parse6();
99993
- var clean = (version, options) => {
99993
+ var clean2 = (version, options) => {
99994
99994
  const s = parse10(version.trim().replace(/^[=v]+/, ""), options);
99995
99995
  return s ? s.version : null;
99996
99996
  };
99997
- module2.exports = clean;
99997
+ module2.exports = clean2;
99998
99998
  }
99999
99999
  });
100000
100000
 
@@ -101305,7 +101305,7 @@ var require_semver2 = __commonJS({
101305
101305
  var identifiers = require_identifiers();
101306
101306
  var parse10 = require_parse6();
101307
101307
  var valid = require_valid();
101308
- var clean = require_clean();
101308
+ var clean2 = require_clean();
101309
101309
  var inc = require_inc();
101310
101310
  var diff = require_diff();
101311
101311
  var major = require_major();
@@ -101343,7 +101343,7 @@ var require_semver2 = __commonJS({
101343
101343
  module2.exports = {
101344
101344
  parse: parse10,
101345
101345
  valid,
101346
- clean,
101346
+ clean: clean2,
101347
101347
  inc,
101348
101348
  diff,
101349
101349
  major,
@@ -253789,7 +253789,7 @@ __export(cli_exports, {
253789
253789
  toDotenv: () => toDotenv
253790
253790
  });
253791
253791
  module.exports = __toCommonJS(cli_exports);
253792
- var import_node_fs6 = require("node:fs");
253792
+ var import_node_fs7 = require("node:fs");
253793
253793
  var import_promises4 = require("node:fs/promises");
253794
253794
  var import_node_child_process = require("node:child_process");
253795
253795
  var import_node_path5 = __toESM(require("node:path"), 1);
@@ -254515,8 +254515,8 @@ var ExitCode;
254515
254515
  })(ExitCode || (ExitCode = {}));
254516
254516
 
254517
254517
  // src/index.ts
254518
- var import_node_crypto5 = require("node:crypto");
254519
- var import_node_fs5 = require("node:fs");
254518
+ var import_node_crypto6 = require("node:crypto");
254519
+ var import_node_fs6 = require("node:fs");
254520
254520
  var path6 = __toESM(require("node:path"), 1);
254521
254521
  var import_yaml4 = __toESM(require_dist(), 1);
254522
254522
 
@@ -254624,6 +254624,12 @@ var bootstrapActionContract = {
254624
254624
  default: "",
254625
254625
  allowedValues: ["3.0", "3.1"]
254626
254626
  },
254627
+ "preserve-oas30-type-null": {
254628
+ 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.",
254629
+ required: false,
254630
+ default: "false",
254631
+ allowedValues: ["true", "false"]
254632
+ },
254627
254633
  "breaking-change-mode": {
254628
254634
  description: "OpenAPI breaking-change comparison mode.",
254629
254635
  required: false,
@@ -254680,6 +254686,20 @@ var bootstrapActionContract = {
254680
254686
  default: "warn",
254681
254687
  allowedValues: ["enforce", "warn"]
254682
254688
  },
254689
+ "branch-strategy": {
254690
+ 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.",
254691
+ required: false,
254692
+ default: "legacy",
254693
+ allowedValues: ["legacy", "preview", "publish-gate"]
254694
+ },
254695
+ "canonical-branch": {
254696
+ 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.",
254697
+ required: false
254698
+ },
254699
+ "channels": {
254700
+ 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.',
254701
+ required: false
254702
+ },
254683
254703
  "integration-backend": {
254684
254704
  description: "Integration backend for downstream workspace connectivity.",
254685
254705
  required: false,
@@ -254749,6 +254769,21 @@ var bootstrapActionContract = {
254749
254769
  },
254750
254770
  "breaking-change-summary-json": {
254751
254771
  description: "JSON summary of the OpenAPI breaking-change check."
254772
+ },
254773
+ "sync-status": {
254774
+ 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."
254775
+ },
254776
+ "branch-decision": {
254777
+ description: "Serialized BranchDecision JSON for downstream actions (also exported as POSTMAN_BRANCH_DECISION)."
254778
+ },
254779
+ "spec-version-tag": {
254780
+ 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)."
254781
+ },
254782
+ "spec-version-url": {
254783
+ description: "Reserved for the repo-sync finalizer; bootstrap does not tag before complete onboarding."
254784
+ },
254785
+ "spec-content-changed": {
254786
+ description: "Whether bootstrap changed canonical spec content; repo-sync uses this to skip native version tags on no-op syncs."
254752
254787
  }
254753
254788
  },
254754
254789
  retainedBehavior: [
@@ -255875,6 +255910,15 @@ function assertSupportedLocalViewContract(node, options) {
255875
255910
  }
255876
255911
 
255877
255912
  // src/lib/postman/additional-collections.ts
255913
+ var RESOURCES_STATE_VERSION = 2;
255914
+ var SUPPORTED_STATE_VERSIONS = /* @__PURE__ */ new Set([1, RESOURCES_STATE_VERSION]);
255915
+ var StateUnreadableError = class extends Error {
255916
+ code = "CONTRACT_STATE_UNREADABLE";
255917
+ constructor(message) {
255918
+ super(`CONTRACT_STATE_UNREADABLE: ${message}`);
255919
+ this.name = "StateUnreadableError";
255920
+ }
255921
+ };
255878
255922
  var ADDITIONAL_COLLECTION_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".yaml", ".yml"]);
255879
255923
  var POSTMAN_COLLECTION_V21_SCHEMA_FRAGMENT = "/collection/v2.1.0/collection.json";
255880
255924
  var V3_DEFINITION_PATH = import_node_path2.default.join(".resources", "definition.yaml");
@@ -255930,16 +255974,46 @@ function resourcesStatePath() {
255930
255974
  return import_node_path2.default.join(workspaceRootForLocalInputs(), RESOURCES_PATH);
255931
255975
  }
255932
255976
  function readResourcesState() {
255977
+ let raw;
255933
255978
  try {
255934
- return (0, import_yaml.parse)((0, import_node_fs2.readFileSync)(resourcesStatePath(), "utf8"));
255979
+ raw = (0, import_node_fs2.readFileSync)(resourcesStatePath(), "utf8");
255935
255980
  } catch {
255936
255981
  return null;
255937
255982
  }
255983
+ let parsed;
255984
+ try {
255985
+ parsed = (0, import_yaml.parse)(raw);
255986
+ } catch (error) {
255987
+ throw new StateUnreadableError(
255988
+ `.postman/resources.yaml exists but is not parseable YAML (${error instanceof Error ? error.message : String(error)}). Fix or delete the file; refusing to treat tracked state as absent.`
255989
+ );
255990
+ }
255991
+ if (parsed === null || parsed === void 0) {
255992
+ return null;
255993
+ }
255994
+ if (typeof parsed !== "object" || Array.isArray(parsed)) {
255995
+ throw new StateUnreadableError(
255996
+ ".postman/resources.yaml exists but does not contain a YAML mapping. Fix or delete the file; refusing to treat tracked state as absent."
255997
+ );
255998
+ }
255999
+ const state = parsed;
256000
+ if (state.version !== void 0 && !SUPPORTED_STATE_VERSIONS.has(Number(state.version))) {
256001
+ throw new StateUnreadableError(
256002
+ `.postman/resources.yaml declares unsupported state version ${String(state.version)} (supported: 1, ${RESOURCES_STATE_VERSION}). Upgrade the action or fix the file.`
256003
+ );
256004
+ }
256005
+ if (state.canonical && !state.cloudResources) {
256006
+ state.cloudResources = { ...state.canonical };
256007
+ }
256008
+ return state;
255938
256009
  }
255939
256010
  function writeResourcesState(state) {
255940
256011
  const target = resourcesStatePath();
255941
256012
  (0, import_node_fs2.mkdirSync)(import_node_path2.default.dirname(target), { recursive: true });
255942
- (0, import_node_fs2.writeFileSync)(target, (0, import_yaml.stringify)(state), "utf8");
256013
+ const canonical = state.cloudResources ?? state.canonical ?? {};
256014
+ const persisted = { ...state, version: RESOURCES_STATE_VERSION, canonical };
256015
+ delete persisted.cloudResources;
256016
+ (0, import_node_fs2.writeFileSync)(target, (0, import_yaml.stringify)(persisted), "utf8");
255943
256017
  }
255944
256018
  function findCloudResourceId(map, matcher) {
255945
256019
  if (!map) {
@@ -255949,7 +256023,7 @@ function findCloudResourceId(map, matcher) {
255949
256023
  return match?.[1];
255950
256024
  }
255951
256025
  function findExistingAdditionalCollectionId(resourcesState, resourcePath) {
255952
- return resourcesState?.cloudResources?.additionalCollections?.[resourcePath] ?? resourcesState?.cloudResources?.collections?.[resourcePath];
256026
+ return resourcesState?.canonical?.additionalCollections?.[resourcePath] ?? resourcesState?.canonical?.collections?.[resourcePath] ?? resourcesState?.cloudResources?.additionalCollections?.[resourcePath] ?? resourcesState?.cloudResources?.collections?.[resourcePath];
255953
256027
  }
255954
256028
  function resolveAdditionalCollectionsDir(directoryInput) {
255955
256029
  const workspaceRoot = workspaceRootForLocalInputs();
@@ -256951,6 +257025,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
256951
257025
  * endpoint aborts rather than blocking the run forever. */
256952
257026
  static REQUEST_TIMEOUT_MS = 3e4;
256953
257027
  static POSTMAN_APP_VERSION_URL = `https://dl.pstmn.io/update/status?currentVersion=${_BifrostInternalIntegrationAdapter.MINIMUM_POSTMAN_APP_VERSION}&platform=osx_arm64`;
257028
+ /** Concurrent dual-trigger previews share one spec; peer sync holds a 423 lock. */
257029
+ static SYNC_LOCKED_MAX_RETRIES = 6;
256954
257030
  accessToken;
256955
257031
  tokenProvider;
256956
257032
  appVersionPromise;
@@ -256959,6 +257035,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
256959
257035
  gatewayBaseUrl;
256960
257036
  orgMode;
256961
257037
  secretMasker;
257038
+ sleep;
256962
257039
  teamId;
256963
257040
  constructor(options) {
256964
257041
  this.accessToken = String(options.accessToken || "").trim();
@@ -256972,6 +257049,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
256972
257049
  ).replace(/\/+$/, "");
256973
257050
  this.orgMode = options.orgMode ?? false;
256974
257051
  this.secretMasker = options.secretMasker ?? createSecretMasker([this.accessToken]);
257052
+ this.sleep = options.sleep ?? ((delayMs) => new Promise((resolve4) => setTimeout(resolve4, delayMs)));
256975
257053
  this.teamId = String(options.teamId || "").trim();
256976
257054
  }
256977
257055
  configureTeamContext(teamId, orgMode) {
@@ -257178,55 +257256,72 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
257178
257256
  if (collections.length === 0) {
257179
257257
  return;
257180
257258
  }
257181
- const response = await this.proxyRequest(
257182
- "specification",
257183
- "put",
257184
- `/specifications/${specificationId}/collections`,
257185
- collections.map((collection) => ({
257186
- collectionId: collection.collectionId,
257187
- ...collection.syncOptions ? { syncOptions: collection.syncOptions } : {}
257188
- }))
257189
- );
257190
- if (response.ok) {
257191
- return;
257259
+ const body2 = collections.map((collection) => ({
257260
+ collectionId: collection.collectionId,
257261
+ ...collection.syncOptions ? { syncOptions: collection.syncOptions } : {}
257262
+ }));
257263
+ for (let lockedAttempt = 0; ; lockedAttempt += 1) {
257264
+ const response = await this.proxyRequest(
257265
+ "specification",
257266
+ "put",
257267
+ `/specifications/${specificationId}/collections`,
257268
+ body2
257269
+ );
257270
+ if (response.ok) {
257271
+ return;
257272
+ }
257273
+ const httpErr = await HttpError.fromResponse(response, {
257274
+ method: "POST",
257275
+ requestHeaders: {
257276
+ "Content-Type": "application/json",
257277
+ "x-access-token": this.currentToken(),
257278
+ ...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
257279
+ },
257280
+ secretValues: [this.currentToken()],
257281
+ url: `${this.bifrostBaseUrl}/ws/proxy`
257282
+ });
257283
+ if (httpErr.status === 423 && lockedAttempt < _BifrostInternalIntegrationAdapter.SYNC_LOCKED_MAX_RETRIES) {
257284
+ await this.sleep(2e3 * Math.pow(2, lockedAttempt));
257285
+ continue;
257286
+ }
257287
+ const advised = adviseFromHttpError(
257288
+ httpErr,
257289
+ this.adviceContext("collection-to-specification linking")
257290
+ );
257291
+ throw advised ?? httpErr;
257192
257292
  }
257193
- const httpErr = await HttpError.fromResponse(response, {
257194
- method: "POST",
257195
- requestHeaders: {
257196
- "Content-Type": "application/json",
257197
- "x-access-token": this.currentToken(),
257198
- ...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
257199
- },
257200
- secretValues: [this.currentToken()],
257201
- url: `${this.bifrostBaseUrl}/ws/proxy`
257202
- });
257203
- const advised = adviseFromHttpError(
257204
- httpErr,
257205
- this.adviceContext("collection-to-specification linking")
257206
- );
257207
- throw advised ?? httpErr;
257208
257293
  }
257209
257294
  async syncCollection(specificationId, collectionId) {
257210
- const response = await this.proxyRequest(
257211
- "specification",
257212
- "post",
257213
- `/specifications/${specificationId}/collections/${collectionId}/sync`
257214
- );
257215
- if (response.ok) {
257216
- return;
257295
+ for (let lockedAttempt = 0; ; lockedAttempt += 1) {
257296
+ const response = await this.proxyRequest(
257297
+ "specification",
257298
+ "post",
257299
+ `/specifications/${specificationId}/collections/${collectionId}/sync`
257300
+ );
257301
+ if (response.ok) {
257302
+ return;
257303
+ }
257304
+ const bodyText = await response.clone().text().catch(() => "");
257305
+ if (response.status === 400 && /already in sync/i.test(bodyText)) {
257306
+ return;
257307
+ }
257308
+ const httpErr = await HttpError.fromResponse(response, {
257309
+ method: "POST",
257310
+ requestHeaders: {
257311
+ "Content-Type": "application/json",
257312
+ "x-access-token": this.currentToken(),
257313
+ ...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
257314
+ },
257315
+ secretValues: [this.currentToken()],
257316
+ url: `${this.bifrostBaseUrl}/ws/proxy`
257317
+ });
257318
+ if (httpErr.status === 423 && lockedAttempt < _BifrostInternalIntegrationAdapter.SYNC_LOCKED_MAX_RETRIES) {
257319
+ await this.sleep(2e3 * Math.pow(2, lockedAttempt));
257320
+ continue;
257321
+ }
257322
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("collection sync"));
257323
+ throw advised ?? httpErr;
257217
257324
  }
257218
- const httpErr = await HttpError.fromResponse(response, {
257219
- method: "POST",
257220
- requestHeaders: {
257221
- "Content-Type": "application/json",
257222
- "x-access-token": this.currentToken(),
257223
- ...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
257224
- },
257225
- secretValues: [this.currentToken()],
257226
- url: `${this.bifrostBaseUrl}/ws/proxy`
257227
- });
257228
- const advised = adviseFromHttpError(httpErr, this.adviceContext("collection sync"));
257229
- throw advised ?? httpErr;
257230
257325
  }
257231
257326
  async getWorkspaceGitRepoUrl(workspaceId) {
257232
257327
  const response = await this.proxyRequest(
@@ -257631,6 +257726,18 @@ async function retry(operation, options = {}) {
257631
257726
  }
257632
257727
  throw new Error("Retry exhausted without returning or throwing");
257633
257728
  }
257729
+ function fullJitterDelayMs(attempt, baseMs, capMs, random = Math.random) {
257730
+ const ceiling = Math.min(capMs, baseMs * 2 ** Math.max(0, attempt));
257731
+ return Math.floor(random() * Math.max(0, ceiling));
257732
+ }
257733
+ function parseRetryAfterMs2(value) {
257734
+ if (!value) return void 0;
257735
+ const trimmed = value.trim();
257736
+ if (/^\d+$/.test(trimmed)) return Number(trimmed) * 1e3;
257737
+ const when = Date.parse(trimmed);
257738
+ if (!Number.isNaN(when)) return Math.max(0, when - Date.now());
257739
+ return void 0;
257740
+ }
257634
257741
 
257635
257742
  // src/lib/postman/postman-ec-client.ts
257636
257743
  var EC_WRITE_MAX_ATTEMPTS = 3;
@@ -262244,6 +262351,12 @@ var BOOTSTRAP_BARE_UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9
262244
262351
  function isMissingPatchValueError(error) {
262245
262352
  return error instanceof HttpError && error.status === 400 && error.responseBody.includes("Remove operation must point to an existing value");
262246
262353
  }
262354
+ function isRejectedPatchError(error) {
262355
+ return error instanceof HttpError && error.status === 400 && /REJECTED_PATCH|must update at least one/i.test(
262356
+ `${error.message}
262357
+ ${error.responseBody ?? ""}`
262358
+ );
262359
+ }
262247
262360
  function canonicalize(value) {
262248
262361
  if (Array.isArray(value)) return value.map(canonicalize);
262249
262362
  if (value && typeof value === "object") {
@@ -262307,6 +262420,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
262307
262420
  static DEFAULT_GENERATION_POLL_DELAY_MS = 2e3;
262308
262421
  gateway;
262309
262422
  sleep;
262423
+ random;
262310
262424
  generationPollAttempts;
262311
262425
  generationPollDelayMs;
262312
262426
  createIdentity;
@@ -262314,6 +262428,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
262314
262428
  this.gateway = options.gateway;
262315
262429
  this.createIdentity = options.createIdentity ?? import_node_crypto2.randomUUID;
262316
262430
  this.sleep = options.sleep ?? ((delayMs) => new Promise((resolve4) => setTimeout(resolve4, delayMs)));
262431
+ this.random = options.random ?? Math.random;
262317
262432
  this.generationPollAttempts = resolvePollBudget(
262318
262433
  options.generationPollAttempts,
262319
262434
  process.env.POSTMAN_GENERATION_POLL_ATTEMPTS,
@@ -262371,6 +262486,16 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
262371
262486
  if (openapiVersion !== "3.0" && openapiVersion !== "3.1") {
262372
262487
  throw new Error(`uploadSpec: unsupported openapiVersion "${openapiVersion}". Expected '3.0' or '3.1'.`);
262373
262488
  }
262489
+ const before = await this.findSpecificationsByExactName(workspaceId, projectName);
262490
+ const existing = adoptExactMatch(
262491
+ `specification:${workspaceId}:${projectName}`,
262492
+ before,
262493
+ (entry) => entry.id
262494
+ );
262495
+ if (existing) {
262496
+ await this.updateSpec(existing.id, specContent, workspaceId);
262497
+ return existing.id;
262498
+ }
262374
262499
  const specType = openapiVersion === "3.1" ? "OPENAPI:3.1" : "OPENAPI:3.0";
262375
262500
  let created;
262376
262501
  try {
@@ -262395,10 +262520,49 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
262395
262520
  if (!match) throw error;
262396
262521
  created = { data: { id: match.id } };
262397
262522
  }
262398
- const specId = String(asRecord8(created?.data)?.id ?? created?.id ?? "").trim();
262523
+ let specId = String(asRecord8(created?.data)?.id ?? created?.id ?? "").trim();
262399
262524
  if (!specId) {
262400
262525
  throw new Error("Spec upload did not return an ID");
262401
262526
  }
262527
+ let matches = await this.findSpecificationsByExactName(workspaceId, projectName);
262528
+ if (before.length === 0 && matches.length <= 1) {
262529
+ await this.sleep(1e3);
262530
+ const settled = await this.findSpecificationsByExactName(workspaceId, projectName);
262531
+ if (settled.length > 0) matches = settled;
262532
+ }
262533
+ if (matches.length > 1 && before.length === 0) {
262534
+ for (const duplicate of matches.slice(1)) {
262535
+ try {
262536
+ await this.deleteSpecification(duplicate.id);
262537
+ } catch (error) {
262538
+ if (!(error instanceof HttpError && error.status === 404)) throw error;
262539
+ }
262540
+ }
262541
+ for (let attempt = 0; attempt < 5; attempt += 1) {
262542
+ matches = await this.findSpecificationsByExactName(workspaceId, projectName);
262543
+ if (matches.length <= 1) break;
262544
+ await this.sleep(250 * (attempt + 1));
262545
+ }
262546
+ const converged = adoptExactMatch(
262547
+ `specification:${workspaceId}:${projectName}`,
262548
+ matches,
262549
+ (entry) => entry.id
262550
+ );
262551
+ if (!converged) {
262552
+ throw new Error(`Concurrent specification create for ${projectName} did not converge`);
262553
+ }
262554
+ specId = converged.id;
262555
+ if (specId !== String(asRecord8(created?.data)?.id ?? created?.id ?? "").trim()) {
262556
+ await this.updateSpec(specId, specContent, workspaceId);
262557
+ }
262558
+ } else {
262559
+ const verified = adoptExactMatch(
262560
+ `specification:${workspaceId}:${projectName}`,
262561
+ matches,
262562
+ (entry) => entry.id
262563
+ );
262564
+ if (verified) specId = verified.id;
262565
+ }
262402
262566
  await this.gateway.requestJson({
262403
262567
  service: "specification",
262404
262568
  method: "get",
@@ -262406,6 +262570,14 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
262406
262570
  });
262407
262571
  return specId;
262408
262572
  }
262573
+ async deleteSpecification(specId) {
262574
+ await this.gateway.requestJson({
262575
+ service: "specification",
262576
+ method: "delete",
262577
+ path: `/specifications/${specId}`,
262578
+ retry: "none"
262579
+ });
262580
+ }
262409
262581
  async findSpecificationsByExactName(workspaceId, name) {
262410
262582
  const response = await this.gateway.requestJson({
262411
262583
  service: "specification",
@@ -262469,6 +262641,41 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
262469
262641
  return void 0;
262470
262642
  }
262471
262643
  }
262644
+ /**
262645
+ * Native Spec Hub version tags (branch-aware sync P3.5). Tags attach to the
262646
+ * LATEST changelog group; the backend 409s when that group is already tagged
262647
+ * (VersionControlService). Callers handle 409 as idempotent-by-group.
262648
+ */
262649
+ async tagSpecVersion(specId, name) {
262650
+ const trimmed = name.trim().slice(0, 255);
262651
+ const created = await this.gateway.requestJson({
262652
+ service: "specification",
262653
+ method: "post",
262654
+ path: `/specifications/${specId}/tags`,
262655
+ retry: "none",
262656
+ body: { name: trimmed }
262657
+ });
262658
+ const record = asRecord8(created?.data) ?? created ?? {};
262659
+ return {
262660
+ id: String(record.id ?? "").trim(),
262661
+ name: String(record.name ?? trimmed).trim()
262662
+ };
262663
+ }
262664
+ /** List a spec's native version tags (newest first per backend ordering). */
262665
+ async listSpecVersionTags(specId) {
262666
+ const response = await this.gateway.requestJson({
262667
+ service: "specification",
262668
+ method: "get",
262669
+ path: `/specifications/${specId}/tags`,
262670
+ query: { limit: "50" }
262671
+ });
262672
+ const entries = Array.isArray(response?.data) ? response.data : [];
262673
+ return entries.map((value) => asRecord8(value)).filter((value) => value !== null).map((value) => ({
262674
+ id: String(value.id ?? "").trim(),
262675
+ // listTags returns `message`; createTag returns `name`. Accept both.
262676
+ name: String(value.name ?? value.message ?? "").trim()
262677
+ })).filter((value) => value.id || value.name);
262678
+ }
262472
262679
  /** Resolve a specification's ROOT file uuid via the files list. */
262473
262680
  async resolveRootFileId(specId) {
262474
262681
  const files = await this.gateway.requestJson({
@@ -262488,79 +262695,182 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
262488
262695
  */
262489
262696
  async generateCollection(specId, projectName, prefix, folderStrategy, nestedFolderHierarchy, requestNameSource) {
262490
262697
  const name = [prefix.trim(), projectName.trim()].filter(Boolean).join(" ");
262491
- const submittedName = `${name} [bootstrap:${this.createIdentity()}]`;
262492
- const body2 = {
262493
- name: submittedName,
262494
- options: {
262495
- requestNameSource,
262496
- folderStrategy,
262497
- ...folderStrategy === "Tags" ? { nestedFolderHierarchy } : {}
262498
- }
262499
- };
262500
262698
  const before = await this.listGeneratedCollectionRefs(specId);
262501
- let taskId;
262502
- try {
262503
- taskId = await this.postGenerationWithLockRetry(specId, body2);
262504
- } catch (error) {
262505
- if (!isAmbiguousTransportError(error)) throw error;
262506
- const beforeIds2 = new Set(before.map((entry) => entry.id));
262507
- const appeared2 = (await this.listGeneratedCollectionRefs(specId)).filter(
262508
- (entry) => !beforeIds2.has(entry.id)
262509
- );
262510
- const exactAppeared = await this.filterGeneratedCollectionsByExactName(
262511
- appeared2,
262699
+ const existing = adoptExactMatch(
262700
+ `generated-collection:${specId}:${name}`,
262701
+ await this.filterGeneratedCollectionsByExactName(before, name),
262702
+ (entry) => entry.id
262703
+ );
262704
+ if (existing) return this.convergeGeneratedCollections(specId, name, existing.id);
262705
+ let lastError;
262706
+ for (let taskAttempt = 0; taskAttempt < 2; taskAttempt += 1) {
262707
+ const submittedName = `${name} [bootstrap:${this.createIdentity()}]`;
262708
+ const body2 = {
262709
+ name: submittedName,
262710
+ options: {
262711
+ requestNameSource,
262712
+ folderStrategy,
262713
+ ...folderStrategy === "Tags" ? { nestedFolderHierarchy } : {}
262714
+ }
262715
+ };
262716
+ let taskId;
262717
+ try {
262718
+ const generation = await this.postGenerationWithLockRetry(specId, body2, name);
262719
+ if (generation.adoptedId) {
262720
+ return this.convergeGeneratedCollections(specId, name, generation.adoptedId);
262721
+ }
262722
+ taskId = generation.taskId ?? "";
262723
+ } catch (error) {
262724
+ if (!isAmbiguousTransportError(error)) throw error;
262725
+ const beforeIds2 = new Set(before.map((entry) => entry.id));
262726
+ const appeared2 = (await this.listGeneratedCollectionRefs(specId)).filter(
262727
+ (entry) => !beforeIds2.has(entry.id)
262728
+ );
262729
+ const exactAppeared = await this.filterGeneratedCollectionsByExactName(
262730
+ appeared2,
262731
+ submittedName
262732
+ );
262733
+ const match = adoptExactMatch(
262734
+ `generated-collection:${specId}:${submittedName}`,
262735
+ exactAppeared,
262736
+ (entry) => entry.id
262737
+ );
262738
+ if (!match) throw error;
262739
+ await this.renameGeneratedCollection(match.id, name);
262740
+ return this.convergeGeneratedCollections(specId, name, match.id);
262741
+ }
262742
+ let taskFailed = false;
262743
+ if (taskId) {
262744
+ for (let attempt = 0; attempt < this.generationPollAttempts; attempt += 1) {
262745
+ await this.sleep(this.generationPollDelayMs);
262746
+ const task = await this.gateway.requestJson({
262747
+ service: "specification",
262748
+ method: "get",
262749
+ path: "/tasks",
262750
+ query: { entityId: specId, entityType: "specification", type: "collection-generation" }
262751
+ });
262752
+ const status = String(asRecord8(task?.data)?.[taskId] ?? "").toLowerCase();
262753
+ if (status === "failed" || status === "error") {
262754
+ taskFailed = true;
262755
+ lastError = new Error(`Collection generation task failed for ${prefix}`);
262756
+ break;
262757
+ }
262758
+ if (status && status !== "in-progress" && status !== "pending" && status !== "queued") {
262759
+ break;
262760
+ }
262761
+ if (attempt === this.generationPollAttempts - 1) {
262762
+ throw new Error(`Collection generation timed out for ${prefix}`);
262763
+ }
262764
+ }
262765
+ }
262766
+ if (taskFailed) {
262767
+ await this.sleep(1e3 * (taskAttempt + 1));
262768
+ continue;
262769
+ }
262770
+ const beforeIds = new Set(before.map((entry) => entry.id));
262771
+ const after = await this.listGeneratedCollectionRefs(specId);
262772
+ const appeared = after.filter((entry) => !beforeIds.has(entry.id));
262773
+ const candidates = await this.filterGeneratedCollectionsByExactName(
262774
+ appeared,
262512
262775
  submittedName
262513
262776
  );
262514
- const match = adoptExactMatch(
262777
+ const uid = adoptExactMatch(
262515
262778
  `generated-collection:${specId}:${submittedName}`,
262516
- exactAppeared,
262779
+ candidates,
262517
262780
  (entry) => entry.id
262518
- );
262519
- if (!match) throw error;
262520
- await this.renameGeneratedCollection(match.id, name);
262521
- return match.id;
262781
+ )?.id;
262782
+ if (!uid) {
262783
+ throw new Error(`Collection generation did not yield a collection uid for ${prefix}`);
262784
+ }
262785
+ await this.renameGeneratedCollection(uid, name);
262786
+ return this.convergeGeneratedCollections(specId, name, uid);
262522
262787
  }
262523
- if (taskId) {
262524
- for (let attempt = 0; attempt < this.generationPollAttempts; attempt += 1) {
262525
- await this.sleep(this.generationPollDelayMs);
262526
- const task = await this.gateway.requestJson({
262527
- service: "specification",
262528
- method: "get",
262529
- path: "/tasks",
262530
- query: { entityId: specId, entityType: "specification", type: "collection-generation" }
262531
- });
262532
- const status = String(asRecord8(task?.data)?.[taskId] ?? "").toLowerCase();
262533
- if (status === "failed" || status === "error") {
262534
- throw new Error(`Collection generation task failed for ${prefix}`);
262535
- }
262536
- if (status && status !== "in-progress" && status !== "pending" && status !== "queued") {
262537
- break;
262538
- }
262539
- if (attempt === this.generationPollAttempts - 1) {
262540
- throw new Error(`Collection generation timed out for ${prefix}`);
262788
+ throw lastError ?? new Error(`Collection generation task failed for ${prefix}`);
262789
+ }
262790
+ /**
262791
+ * Re-elect the durable generated collection for a final name. Call after
262792
+ * concurrent dual-trigger generates and before description/inject/tag so a
262793
+ * peer orphan-sweep cannot leave this runner holding a deleted id.
262794
+ */
262795
+ async adoptGeneratedCollection(specId, projectName, prefix, preferredId = "") {
262796
+ const name = [prefix.trim(), projectName.trim()].filter(Boolean).join(" ");
262797
+ return this.convergeGeneratedCollections(specId, name, preferredId);
262798
+ }
262799
+ /**
262800
+ * Concurrent dual-trigger previews can each generate+rename the same final
262801
+ * collection identity. Elect the stable lowest-id winner.
262802
+ *
262803
+ * Losers only delete *their own* preferred collection (never a peer's still-
262804
+ * in-use id). Winners wait briefly for peers to self-delete, then clean any
262805
+ * leftover same-identity orphans (temps + extra finals).
262806
+ */
262807
+ async convergeGeneratedCollections(specId, finalName, preferredId) {
262808
+ const tempPrefix = `${finalName} [bootstrap:`;
262809
+ const hydrate = async () => {
262810
+ const linked = await this.listGeneratedCollectionRefs(specId);
262811
+ return Promise.all(
262812
+ linked.map(async (entry) => {
262813
+ if (entry.name) return { id: entry.id, name: entry.name };
262814
+ try {
262815
+ const collection = await this.gateway.requestJson({
262816
+ service: "collection",
262817
+ method: "get",
262818
+ path: `/v3/collections/${this.bareModelId(entry.id)}`
262819
+ });
262820
+ return {
262821
+ id: entry.id,
262822
+ name: String(asRecord8(collection?.data)?.name ?? "").trim()
262823
+ };
262824
+ } catch (error) {
262825
+ if (error instanceof HttpError && error.status === 404) {
262826
+ return { id: entry.id, name: "" };
262827
+ }
262828
+ throw error;
262829
+ }
262830
+ })
262831
+ );
262832
+ };
262833
+ const selectSameIdentity = (entries) => entries.filter(
262834
+ (entry) => entry.name === finalName || entry.name.startsWith(tempPrefix)
262835
+ ).sort((a, b) => a.id.localeCompare(b.id));
262836
+ let sameIdentity = selectSameIdentity(await hydrate());
262837
+ if (sameIdentity.length === 0) return preferredId;
262838
+ if (sameIdentity.length === 1) {
262839
+ await this.sleep(1e3);
262840
+ sameIdentity = selectSameIdentity(await hydrate());
262841
+ if (sameIdentity.length === 0) return preferredId;
262842
+ }
262843
+ const winner = sameIdentity[0];
262844
+ if (winner.name !== finalName) {
262845
+ await this.renameGeneratedCollection(winner.id, finalName);
262846
+ }
262847
+ if (preferredId && preferredId !== winner.id) {
262848
+ const own = sameIdentity.find((entry) => entry.id === preferredId);
262849
+ if (own) {
262850
+ try {
262851
+ await this.deleteCollection(preferredId);
262852
+ } catch (error) {
262853
+ if (!(error instanceof HttpError && error.status === 404)) throw error;
262541
262854
  }
262542
262855
  }
262856
+ return winner.id;
262543
262857
  }
262544
- const beforeIds = new Set(before.map((entry) => entry.id));
262545
- const after = await this.listGeneratedCollectionRefs(specId);
262546
- const appeared = after.filter((entry) => !beforeIds.has(entry.id));
262547
- const candidates = await this.filterGeneratedCollectionsByExactName(
262548
- appeared,
262549
- submittedName
262550
- );
262551
- const uid = adoptExactMatch(
262552
- `generated-collection:${specId}:${submittedName}`,
262553
- candidates,
262554
- (entry) => entry.id
262555
- )?.id;
262556
- if (!uid) {
262557
- throw new Error(`Collection generation did not yield a collection uid for ${prefix}`);
262858
+ if (sameIdentity.length > 1) {
262859
+ await this.sleep(1500);
262860
+ sameIdentity = selectSameIdentity(await hydrate());
262861
+ for (const duplicate of sameIdentity) {
262862
+ if (duplicate.id === winner.id) continue;
262863
+ try {
262864
+ await this.deleteCollection(duplicate.id);
262865
+ } catch (error) {
262866
+ if (!(error instanceof HttpError && error.status === 404)) throw error;
262867
+ }
262868
+ }
262558
262869
  }
262559
- await this.renameGeneratedCollection(uid, name);
262560
- return uid;
262870
+ return winner.id;
262561
262871
  }
262562
262872
  /** POST the generation request, retrying a 423-locked spec; returns the task id. */
262563
- async postGenerationWithLockRetry(specId, body2) {
262873
+ async postGenerationWithLockRetry(specId, body2, finalName) {
262564
262874
  for (let lockedAttempt = 0; ; lockedAttempt += 1) {
262565
262875
  try {
262566
262876
  const created = await this.gateway.requestJson({
@@ -262570,13 +262880,22 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
262570
262880
  retry: "none",
262571
262881
  body: body2
262572
262882
  });
262573
- return String(asRecord8(created?.data)?.taskId ?? "").trim();
262883
+ return { taskId: String(asRecord8(created?.data)?.taskId ?? "").trim() };
262574
262884
  } catch (error) {
262575
262885
  const locked = error instanceof HttpError && error.status === 423;
262576
262886
  if (!locked || lockedAttempt >= _PostmanGatewayAssetsClient.GENERATION_LOCKED_MAX_RETRIES) {
262577
262887
  throw error;
262578
262888
  }
262579
262889
  await this.sleep(5e3 * Math.pow(2, lockedAttempt));
262890
+ const adopted = adoptExactMatch(
262891
+ `generated-collection:${specId}:${finalName}`,
262892
+ await this.filterGeneratedCollectionsByExactName(
262893
+ await this.listGeneratedCollectionRefs(specId),
262894
+ finalName
262895
+ ),
262896
+ (entry) => entry.id
262897
+ );
262898
+ if (adopted) return { adoptedId: adopted.id };
262580
262899
  }
262581
262900
  }
262582
262901
  }
@@ -262613,14 +262932,24 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
262613
262932
  return hydrated.filter((entry) => entry.name === expectedName);
262614
262933
  }
262615
262934
  async renameGeneratedCollection(collectionId, name) {
262616
- await this.gateway.requestJson({
262617
- service: "collection",
262618
- method: "patch",
262619
- path: `/v3/collections/${this.bareModelId(collectionId)}`,
262620
- // Replacing a generated collection's name with the same value is idempotent.
262621
- retry: "safe",
262622
- body: [{ op: "replace", path: "/name", value: name }]
262623
- });
262935
+ try {
262936
+ await this.gateway.requestJson({
262937
+ service: "collection",
262938
+ method: "patch",
262939
+ path: `/v3/collections/${this.bareModelId(collectionId)}`,
262940
+ // Replacing a generated collection's name with the same value is idempotent.
262941
+ retry: "safe",
262942
+ body: [{ op: "replace", path: "/name", value: name }]
262943
+ });
262944
+ } catch (error) {
262945
+ if (error instanceof HttpError && error.status === 400 && /must update at least one|REJECTED_PATCH/i.test(
262946
+ `${error.message}
262947
+ ${error.responseBody ?? ""}`
262948
+ )) {
262949
+ return;
262950
+ }
262951
+ throw error;
262952
+ }
262624
262953
  }
262625
262954
  /**
262626
262955
  * Create a team-visible workspace through the gateway workspaces service.
@@ -262874,7 +263203,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
262874
263203
  if (!retriable || attempt === maxAttempts - 1) {
262875
263204
  throw error;
262876
263205
  }
262877
- await this.sleep(Math.min(2e3, 300 * 2 ** attempt));
263206
+ await this.sleep(fullJitterDelayMs(attempt, 300, 2e3, this.random));
262878
263207
  }
262879
263208
  }
262880
263209
  }
@@ -262895,6 +263224,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
262895
263224
  service: "tagging",
262896
263225
  method: "put",
262897
263226
  path: `/v1/tags/collections/${collectionUid}`,
263227
+ retry: "safe",
262898
263228
  body: { tags: normalized.map((slug) => ({ slug })) }
262899
263229
  });
262900
263230
  }
@@ -263124,14 +263454,19 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
263124
263454
  { type: "afterResponse", code: exec.join("\n"), language: "text/javascript" }
263125
263455
  ];
263126
263456
  for (const script of plan.scripts) {
263127
- await this.gateway.requestJson({
263128
- service: "collection",
263129
- method: "patch",
263130
- path: `/v3/collections/${cid}/items/${script.itemId}`,
263131
- retry: "safe",
263132
- headers: { "X-Entity-Type": "http-request" },
263133
- body: [{ op: "add", path: "/scripts", value: toV3Scripts(script.exec) }]
263134
- });
263457
+ try {
263458
+ await this.gateway.requestJson({
263459
+ service: "collection",
263460
+ method: "patch",
263461
+ path: `/v3/collections/${cid}/items/${script.itemId}`,
263462
+ retry: "safe",
263463
+ headers: { "X-Entity-Type": "http-request" },
263464
+ body: [{ op: "add", path: "/scripts", value: toV3Scripts(script.exec) }]
263465
+ });
263466
+ } catch (error) {
263467
+ if (isRejectedPatchError(error)) continue;
263468
+ throw error;
263469
+ }
263135
263470
  }
263136
263471
  if (!items.some((i) => String(i.name ?? "") === "00 - Resolve Secrets")) {
263137
263472
  const created = await this.gateway.requestJson({
@@ -263336,36 +263671,47 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
263336
263671
  async createItemTree(cid, items, parentId) {
263337
263672
  for (const item of items) {
263338
263673
  const kind = String(item.$kind ?? "http-request");
263339
- let created;
263340
- try {
263341
- created = await this.gateway.requestJson({
263342
- service: "collection",
263343
- method: "post",
263344
- path: `/v3/collections/${cid}/items/`,
263345
- retry: "none",
263346
- headers: { "X-Entity-Type": kind },
263347
- body: this.buildItemCreateBody(item, parentId)
263348
- });
263349
- } catch (error) {
263350
- if (!isAmbiguousTransportError(error)) throw error;
263351
- const name = String(item.name ?? "Untitled");
263352
- const matches = (await this.listCollectionItems(cid)).filter((candidate) => {
263353
- if (String(candidate.name ?? candidate.title ?? "") !== name) return false;
263354
- if (String(candidate.$kind ?? candidate.type ?? "http-request") !== kind) return false;
263355
- const position = asRecord8(candidate.position);
263356
- const parent = asRecord8(position?.parent);
263357
- const candidateParent = String(parent?.id ?? position?.parent ?? candidate.parent ?? "").trim();
263358
- return Boolean(candidateParent) && this.bareModelId(candidateParent) === this.bareModelId(parentId);
263359
- });
263360
- const match = adoptExactMatch(
263361
- `collection-item:${cid}:${parentId}:${kind}:${name}`,
263362
- matches,
263363
- (candidate) => String(candidate.id ?? "")
263364
- );
263365
- if (!match) throw error;
263366
- created = { data: { id: match.id } };
263674
+ const maxAttempts = 4;
263675
+ let newId = "";
263676
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
263677
+ let created;
263678
+ try {
263679
+ created = await this.gateway.requestJson({
263680
+ service: "collection",
263681
+ method: "post",
263682
+ path: `/v3/collections/${cid}/items/`,
263683
+ retry: "none",
263684
+ headers: { "X-Entity-Type": kind },
263685
+ body: this.buildItemCreateBody(item, parentId)
263686
+ });
263687
+ } catch (error) {
263688
+ if (!isAmbiguousTransportError(error)) throw error;
263689
+ const name = String(item.name ?? "Untitled");
263690
+ const matches = (await this.listCollectionItems(cid)).filter((candidate) => {
263691
+ if (String(candidate.name ?? candidate.title ?? "") !== name) return false;
263692
+ if (String(candidate.$kind ?? candidate.type ?? "http-request") !== kind) return false;
263693
+ const position = asRecord8(candidate.position);
263694
+ const parent = asRecord8(position?.parent);
263695
+ const candidateParent = String(parent?.id ?? position?.parent ?? candidate.parent ?? "").trim();
263696
+ return Boolean(candidateParent) && this.bareModelId(candidateParent) === this.bareModelId(parentId);
263697
+ });
263698
+ const match = adoptExactMatch(
263699
+ `collection-item:${cid}:${parentId}:${kind}:${name}`,
263700
+ matches,
263701
+ (candidate) => String(candidate.id ?? "")
263702
+ );
263703
+ if (match) {
263704
+ created = { data: { id: match.id } };
263705
+ } else {
263706
+ const retriable = error instanceof HttpError && error.status >= 500;
263707
+ if (!retriable || attempt === maxAttempts) throw error;
263708
+ await this.sleep(fullJitterDelayMs(attempt - 1, 300, 2e3, this.random));
263709
+ continue;
263710
+ }
263711
+ }
263712
+ newId = String(asRecord8(created?.data)?.id ?? "").trim();
263713
+ if (newId) break;
263367
263714
  }
263368
- const newId = String(asRecord8(created?.data)?.id ?? "").trim();
263369
263715
  if (!newId) {
263370
263716
  throw new Error(
263371
263717
  `Item create did not return an id for ${String(item.name ?? "item")}`
@@ -263408,6 +263754,30 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
263408
263754
  * - `remove` of /description always works (field exists as "")
263409
263755
  * - on update, GET the root first and only remove fields that currently exist
263410
263756
  */
263757
+ /**
263758
+ * GET a collection root, retrying through the v3 surface's read-after-write
263759
+ * 404 lag. A freshly generated/renamed collection can transiently report
263760
+ * RESOURCE_NOT_FOUND for a few seconds (worse under concurrent runner load);
263761
+ * retrying absorbs that instead of hard-failing the run.
263762
+ */
263763
+ async getCollectionRoot(cid) {
263764
+ const got = await retry(
263765
+ () => this.gateway.requestJson({
263766
+ service: "collection",
263767
+ method: "get",
263768
+ path: `/v3/collections/${cid}`,
263769
+ retry: "none"
263770
+ }),
263771
+ {
263772
+ maxAttempts: 6,
263773
+ delayMs: 1e3,
263774
+ backoffMultiplier: 2,
263775
+ maxDelayMs: 8e3,
263776
+ shouldRetry: (error) => error instanceof HttpError && error.status === 404
263777
+ }
263778
+ );
263779
+ return asRecord8(got?.data);
263780
+ }
263411
263781
  async applyCollectionLevelSettings(cid, v3, options = {}) {
263412
263782
  const ops = [];
263413
263783
  if (options.rename && typeof v3.name === "string" && v3.name) {
@@ -263415,12 +263785,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
263415
263785
  }
263416
263786
  let current = null;
263417
263787
  if (options.reconcileRemovals) {
263418
- const got = await this.gateway.requestJson({
263419
- service: "collection",
263420
- method: "get",
263421
- path: `/v3/collections/${cid}`
263422
- });
263423
- current = asRecord8(got?.data);
263788
+ current = await this.getCollectionRoot(cid);
263424
263789
  }
263425
263790
  const hasDescription = typeof v3.description === "string" && v3.description.length > 0;
263426
263791
  if (hasDescription) {
@@ -263459,6 +263824,9 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
263459
263824
  if (isMissingPatchValueError(error) && ops.some((op) => op.op === "remove") && await this.verifyRootSettingsApplied(cid, ops)) {
263460
263825
  return;
263461
263826
  }
263827
+ if (isRejectedPatchError(error) && await this.verifyRootSettingsApplied(cid, ops)) {
263828
+ return;
263829
+ }
263462
263830
  throw error;
263463
263831
  }
263464
263832
  }
@@ -263521,6 +263889,15 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
263521
263889
  async createCollection(workspaceId, collection, options = {}) {
263522
263890
  const v3 = this.normalizeCollectionForWrite(collection);
263523
263891
  const desiredName = String(v3.name ?? "Untitled Collection");
263892
+ const existing = adoptExactMatch(
263893
+ `collection:${workspaceId}:${desiredName}`,
263894
+ await this.findCollectionsByExactName(workspaceId, desiredName),
263895
+ (entry) => entry.id
263896
+ );
263897
+ if (existing) {
263898
+ await this.updateCollection(existing.id, collection);
263899
+ return existing.id;
263900
+ }
263524
263901
  const submittedName = `${desiredName} [bootstrap:${this.createIdentity()}]`;
263525
263902
  const rootBody = { name: submittedName };
263526
263903
  let created;
@@ -263571,6 +263948,12 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
263571
263948
  }
263572
263949
  return rawId;
263573
263950
  }
263951
+ /** Patch only the durable collection description without reconciling its item tree. */
263952
+ async updateCollectionDescription(collectionUid, description) {
263953
+ const cid = this.bareModelId(collectionUid);
263954
+ await this.getCollectionRoot(cid);
263955
+ await this.applyCollectionLevelSettings(cid, { description });
263956
+ }
263574
263957
  /**
263575
263958
  * Full-replace reconcile of a curated local v2.1.0 or collection v3 payload: delete every
263576
263959
  * root-level item (deleting a folder cascades its children server-side —
@@ -263652,6 +264035,7 @@ function detectInnerError(body2) {
263652
264035
  return typeof innerStatus === "number" && innerStatus >= 400 ? innerStatus : 502;
263653
264036
  }
263654
264037
  function isTransientGatewayError(status, body2) {
264038
+ if (status === 429) return true;
263655
264039
  if (status === 502 || status === 503 || status === 504) return true;
263656
264040
  if (status >= 500 && (body2.includes("ESOCKETTIMEDOUT") || body2.includes("ETIMEDOUT") || body2.includes("ECONNRESET") || body2.includes("serverError") || body2.includes("downstream"))) {
263657
264041
  return true;
@@ -263670,8 +264054,10 @@ var AccessTokenGatewayClient = class {
263670
264054
  secretMasker;
263671
264055
  maxRetries;
263672
264056
  retryBaseDelayMs;
264057
+ retryMaxDelayMs;
263673
264058
  requestTimeoutMs;
263674
264059
  sleepImpl;
264060
+ randomImpl;
263675
264061
  constructor(options) {
263676
264062
  this.tokenProvider = options.tokenProvider;
263677
264063
  this.bifrostBaseUrl = String(
@@ -263683,8 +264069,10 @@ var AccessTokenGatewayClient = class {
263683
264069
  this.secretMasker = options.secretMasker ?? createSecretMasker([this.tokenProvider.current()]);
263684
264070
  this.maxRetries = options.maxRetries ?? 3;
263685
264071
  this.retryBaseDelayMs = options.retryBaseDelayMs ?? 400;
264072
+ this.retryMaxDelayMs = options.retryMaxDelayMs ?? 5e3;
263686
264073
  this.requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
263687
264074
  this.sleepImpl = options.sleepImpl ?? defaultSleep;
264075
+ this.randomImpl = options.randomImpl ?? Math.random;
263688
264076
  }
263689
264077
  configureTeamContext(teamId, orgMode) {
263690
264078
  this.teamId = String(teamId || "").trim();
@@ -263744,7 +264132,7 @@ var AccessTokenGatewayClient = class {
263744
264132
  response = await this.send(request);
263745
264133
  } catch (error) {
263746
264134
  if (retryMode === "safe" && attempt < this.maxRetries) {
263747
- const delay = this.retryBaseDelayMs * 2 ** attempt;
264135
+ const delay = this.retryDelayMs(attempt);
263748
264136
  attempt += 1;
263749
264137
  await this.sleepImpl(delay);
263750
264138
  continue;
@@ -263756,7 +264144,7 @@ var AccessTokenGatewayClient = class {
263756
264144
  const innerStatus = detectInnerError(okBody);
263757
264145
  if (innerStatus !== null) {
263758
264146
  if (retryMode === "safe" && isTransientGatewayError(innerStatus, okBody) && attempt < this.maxRetries) {
263759
- const delay = this.retryBaseDelayMs * 2 ** attempt;
264147
+ const delay = this.retryDelayMs(attempt);
263760
264148
  attempt += 1;
263761
264149
  await this.sleepImpl(delay);
263762
264150
  continue;
@@ -263781,7 +264169,10 @@ var AccessTokenGatewayClient = class {
263781
264169
  throw this.toHttpError(request, response, retryBody);
263782
264170
  }
263783
264171
  if (retryMode === "safe" && isTransientGatewayError(response.status, body2) && attempt < this.maxRetries) {
263784
- const delay = this.retryBaseDelayMs * 2 ** attempt;
264172
+ const delay = this.retryDelayMs(
264173
+ attempt,
264174
+ parseRetryAfterMs2(response.headers.get("retry-after"))
264175
+ );
263785
264176
  attempt += 1;
263786
264177
  await this.sleepImpl(delay);
263787
264178
  continue;
@@ -263789,13 +264180,26 @@ var AccessTokenGatewayClient = class {
263789
264180
  throw this.toHttpError(request, response, body2);
263790
264181
  }
263791
264182
  }
264183
+ /**
264184
+ * Full-jitter backoff (uniform in [0, min(cap, base * 2^attempt))) so
264185
+ * concurrent CI runners that fail together never retry in lockstep against
264186
+ * the shared gateway. A server-sent Retry-After beats the heuristic: it is
264187
+ * authoritative backpressure, honored verbatim (capped by the ceiling).
264188
+ */
264189
+ retryDelayMs(attempt, retryAfterMs) {
264190
+ if (retryAfterMs !== void 0) {
264191
+ return Math.min(this.retryMaxDelayMs, retryAfterMs);
264192
+ }
264193
+ return fullJitterDelayMs(attempt, this.retryBaseDelayMs, this.retryMaxDelayMs, this.randomImpl);
264194
+ }
263792
264195
  /**
263793
264196
  * The success path reads the body to inspect for an inner error, which
263794
264197
  * consumes the stream. Hand callers a fresh Response over the buffered text so
263795
264198
  * `requestJson` can still parse it.
263796
264199
  */
263797
264200
  rebuildResponse(response, body2) {
263798
- return new Response(body2, {
264201
+ const nullBody = response.status === 204 || response.status === 205 || response.status === 304;
264202
+ return new Response(nullBody ? null : body2, {
263799
264203
  status: response.status,
263800
264204
  statusText: response.statusText,
263801
264205
  headers: response.headers
@@ -264525,6 +264929,9 @@ function createTelemetryContext(options) {
264525
264929
  var import_node_fs3 = require("node:fs");
264526
264930
  var import_node_path3 = require("node:path");
264527
264931
  function resolveActionVersion2() {
264932
+ if (false) {
264933
+ return void 0;
264934
+ }
264528
264935
  try {
264529
264936
  const raw = (0, import_node_fs3.readFileSync)((0, import_node_path3.join)(__dirname, "..", "package.json"), "utf8");
264530
264937
  return JSON.parse(raw).version ?? "unknown";
@@ -280247,6 +280654,61 @@ function serializeOpenApiDocument(document2) {
280247
280654
  return `${JSON.stringify(document2, null, 2)}
280248
280655
  `;
280249
280656
  }
280657
+ function typeNullPath(pathSegments) {
280658
+ return pathSegments.map(String).join(".");
280659
+ }
280660
+ function isNullOnlySchema(value) {
280661
+ const record = asRecord10(value);
280662
+ if (!record || record.type !== "null") return false;
280663
+ return Object.keys(record).every((key) => key === "type" || key.startsWith("x-"));
280664
+ }
280665
+ function createOas30TypeNullCompatibilityDocument(sourceDocument) {
280666
+ const document2 = structuredClone(sourceDocument);
280667
+ const sourceTypeNullPaths = [];
280668
+ const visit4 = (value, pathSegments) => {
280669
+ if (Array.isArray(value)) {
280670
+ value.forEach((entry, index) => visit4(entry, [...pathSegments, index]));
280671
+ return;
280672
+ }
280673
+ const record = asRecord10(value);
280674
+ if (!record) return;
280675
+ const oneOf = Array.isArray(record.oneOf) ? record.oneOf : void 0;
280676
+ const nullIndexes = oneOf ? oneOf.flatMap((entry, index) => isNullOnlySchema(entry) ? [index] : []) : [];
280677
+ if (nullIndexes.length > 0) {
280678
+ if (oneOf?.length !== 2 || nullIndexes.length !== 1) {
280679
+ throw new Error(
280680
+ `CONTRACT_OAS30_TYPE_NULL_UNSUPPORTED: ${typeNullPath(pathSegments)} must use oneOf with exactly one null-only member and one non-null schema`
280681
+ );
280682
+ }
280683
+ const nullIndex = nullIndexes[0];
280684
+ const nonNullIndex = nullIndex === 0 ? 1 : 0;
280685
+ const nonNullSchema = asRecord10(oneOf[nonNullIndex]);
280686
+ if (!nonNullSchema || nonNullSchema.type === "null") {
280687
+ throw new Error(
280688
+ `CONTRACT_OAS30_TYPE_NULL_UNSUPPORTED: ${typeNullPath(pathSegments)} must pair the null-only member with one non-null schema`
280689
+ );
280690
+ }
280691
+ const siblings = Object.fromEntries(
280692
+ Object.entries(record).filter(([key]) => key !== "oneOf")
280693
+ );
280694
+ for (const key of Object.keys(record)) delete record[key];
280695
+ Object.assign(record, structuredClone(nonNullSchema), siblings, { nullable: true });
280696
+ sourceTypeNullPaths.push(typeNullPath([...pathSegments, "oneOf", nullIndex, "type"]));
280697
+ visit4(record, pathSegments);
280698
+ return;
280699
+ }
280700
+ if (record.type === "null") {
280701
+ throw new Error(
280702
+ `CONTRACT_OAS30_TYPE_NULL_UNSUPPORTED: ${typeNullPath([...pathSegments, "type"])} is not a supported nullable oneOf member`
280703
+ );
280704
+ }
280705
+ for (const [key, child3] of Object.entries(record)) {
280706
+ visit4(child3, [...pathSegments, key]);
280707
+ }
280708
+ };
280709
+ visit4(document2, []);
280710
+ return { document: document2, sourceTypeNullPaths };
280711
+ }
280250
280712
  async function bundleSpec(baseUrl, document2, options) {
280251
280713
  const budget = options.budget ?? { refs: 0, totalBytes: Buffer.byteLength(JSON.stringify(document2), "utf8") };
280252
280714
  const fetchText = options.fetchText ?? safeFetchText;
@@ -280288,7 +280750,14 @@ function createCachedFetchText(options) {
280288
280750
  async function buildLoadedSpec(content, baseRef, options, fetchText, budget) {
280289
280751
  const document2 = parseOpenApiDocument(content);
280290
280752
  const version = detectOpenApiVersion2(document2);
280291
- const bundledDocument = await bundleSpec(baseRef, document2, { ...options, budget, fetchText });
280753
+ let contractDocument = document2;
280754
+ let sourceTypeNullPaths = [];
280755
+ if (options.preserveOas30TypeNull && version === "3.0") {
280756
+ const compatibility = createOas30TypeNullCompatibilityDocument(document2);
280757
+ contractDocument = compatibility.document;
280758
+ sourceTypeNullPaths = compatibility.sourceTypeNullPaths;
280759
+ }
280760
+ const bundledDocument = await bundleSpec(baseRef, contractDocument, { ...options, budget, fetchText });
280292
280761
  const validation = await validate(bundledDocument, {
280293
280762
  resolve: { external: false, file: false },
280294
280763
  dereference: { circular: "ignore" },
@@ -280302,6 +280771,7 @@ async function buildLoadedSpec(content, baseRef, options, fetchText, budget) {
280302
280771
  bundledDocument,
280303
280772
  contractIndex: buildContractIndex(bundledDocument),
280304
280773
  content,
280774
+ sourceTypeNullPaths,
280305
280775
  version
280306
280776
  };
280307
280777
  }
@@ -280427,6 +280897,309 @@ function looksLikeIntrospection(record) {
280427
280897
  return Boolean(data && typeof data === "object" && data.__schema);
280428
280898
  }
280429
280899
 
280900
+ // src/lib/repo/branch-decision.ts
280901
+ var import_node_fs5 = require("node:fs");
280902
+ var import_node_crypto4 = require("node:crypto");
280903
+ var ContractError = class extends Error {
280904
+ code;
280905
+ constructor(code, message) {
280906
+ super(`${code}: ${message}`);
280907
+ this.code = code;
280908
+ this.name = "ContractError";
280909
+ }
280910
+ };
280911
+ function clean(value) {
280912
+ const trimmed = (value ?? "").trim();
280913
+ return trimmed.length > 0 ? trimmed : void 0;
280914
+ }
280915
+ function stripRefPrefix(ref) {
280916
+ const raw = clean(ref);
280917
+ if (!raw) {
280918
+ return { kind: "unknown" };
280919
+ }
280920
+ if (raw.startsWith("refs/heads/")) {
280921
+ return { name: raw.slice("refs/heads/".length), kind: "branch" };
280922
+ }
280923
+ if (raw.startsWith("refs/tags/")) {
280924
+ return { name: raw.slice("refs/tags/".length), kind: "tag" };
280925
+ }
280926
+ if (raw.startsWith("refs/pull/") || raw.startsWith("refs/merge")) {
280927
+ return { kind: "unknown" };
280928
+ }
280929
+ return { name: raw, kind: "branch" };
280930
+ }
280931
+ function detectProvider(env) {
280932
+ if (clean(env.GITHUB_ACTIONS) || clean(env.GITHUB_REPOSITORY)) return "github";
280933
+ if (clean(env.GITLAB_CI) || clean(env.CI_PROJECT_PATH)) return "gitlab";
280934
+ if (clean(env.BITBUCKET_REPO_SLUG) || clean(env.BITBUCKET_BRANCH)) return "bitbucket";
280935
+ if (clean(env.TF_BUILD) || clean(env.BUILD_REPOSITORY_URI)) return "azure-devops";
280936
+ return "unknown";
280937
+ }
280938
+ function readGithubEvent(env) {
280939
+ const path8 = clean(env.GITHUB_EVENT_PATH);
280940
+ if (!path8) return void 0;
280941
+ try {
280942
+ return JSON.parse((0, import_node_fs5.readFileSync)(path8, "utf8"));
280943
+ } catch {
280944
+ return void 0;
280945
+ }
280946
+ }
280947
+ function resolveBranchIdentity(env = process.env, overrides = {}) {
280948
+ const provider = detectProvider(env);
280949
+ const explicitDefault = clean(overrides.defaultBranch);
280950
+ let headBranch;
280951
+ let rawRef;
280952
+ let refKind;
280953
+ let isPrContext = false;
280954
+ let isForkPr = false;
280955
+ let defaultBranch = explicitDefault;
280956
+ let headSha;
280957
+ switch (provider) {
280958
+ case "github": {
280959
+ const event2 = readGithubEvent(env);
280960
+ headSha = clean(env.GITHUB_SHA);
280961
+ defaultBranch ??= clean(event2?.repository?.default_branch);
280962
+ const headRef = clean(env.GITHUB_HEAD_REF);
280963
+ if (headRef) {
280964
+ isPrContext = true;
280965
+ headBranch = headRef;
280966
+ rawRef = clean(env.GITHUB_REF) ?? headRef;
280967
+ refKind = "branch";
280968
+ const headRepo = event2?.pull_request?.head?.repo?.full_name;
280969
+ const baseRepo = event2?.pull_request?.base?.repo?.full_name ?? event2?.repository?.full_name;
280970
+ isForkPr = Boolean(headRepo && baseRepo && headRepo !== baseRepo);
280971
+ headSha = clean(event2?.pull_request?.head?.sha) ?? headSha;
280972
+ } else {
280973
+ rawRef = clean(env.GITHUB_REF) ?? clean(env.GITHUB_REF_NAME);
280974
+ const parsed = stripRefPrefix(rawRef);
280975
+ headBranch = parsed.kind === "branch" ? parsed.name : void 0;
280976
+ refKind = parsed.kind;
280977
+ }
280978
+ break;
280979
+ }
280980
+ case "gitlab": {
280981
+ headSha = clean(env.CI_COMMIT_SHA);
280982
+ defaultBranch ??= clean(env.CI_DEFAULT_BRANCH);
280983
+ const mrSource = clean(env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME);
280984
+ if (mrSource) {
280985
+ isPrContext = true;
280986
+ headBranch = mrSource;
280987
+ rawRef = mrSource;
280988
+ refKind = "branch";
280989
+ const sourceProject = clean(env.CI_MERGE_REQUEST_SOURCE_PROJECT_ID);
280990
+ const targetProject = clean(env.CI_MERGE_REQUEST_PROJECT_ID);
280991
+ isForkPr = Boolean(sourceProject && targetProject && sourceProject !== targetProject);
280992
+ } else if (clean(env.CI_COMMIT_TAG)) {
280993
+ rawRef = clean(env.CI_COMMIT_TAG);
280994
+ refKind = "tag";
280995
+ } else {
280996
+ headBranch = clean(env.CI_COMMIT_BRANCH) ?? clean(env.CI_COMMIT_REF_NAME);
280997
+ rawRef = headBranch;
280998
+ refKind = headBranch ? "branch" : "unknown";
280999
+ }
281000
+ break;
281001
+ }
281002
+ case "bitbucket": {
281003
+ headSha = clean(env.BITBUCKET_COMMIT);
281004
+ if (clean(env.BITBUCKET_TAG)) {
281005
+ rawRef = clean(env.BITBUCKET_TAG);
281006
+ refKind = "tag";
281007
+ } else {
281008
+ headBranch = clean(env.BITBUCKET_BRANCH);
281009
+ rawRef = headBranch;
281010
+ refKind = headBranch ? "branch" : "unknown";
281011
+ isPrContext = Boolean(clean(env.BITBUCKET_PR_ID));
281012
+ }
281013
+ break;
281014
+ }
281015
+ case "azure-devops": {
281016
+ headSha = clean(env.BUILD_SOURCEVERSION);
281017
+ const prSource = clean(env.SYSTEM_PULLREQUEST_SOURCEBRANCH);
281018
+ if (prSource) {
281019
+ isPrContext = true;
281020
+ const parsed = stripRefPrefix(prSource);
281021
+ headBranch = parsed.kind === "branch" ? parsed.name : void 0;
281022
+ rawRef = prSource;
281023
+ refKind = parsed.kind;
281024
+ const forkFlag = clean(env.SYSTEM_PULLREQUEST_ISFORK);
281025
+ isForkPr = forkFlag?.toLowerCase() === "true";
281026
+ } else {
281027
+ rawRef = clean(env.BUILD_SOURCEBRANCH);
281028
+ const parsed = stripRefPrefix(rawRef);
281029
+ headBranch = parsed.kind === "branch" ? parsed.name : void 0;
281030
+ refKind = parsed.kind;
281031
+ }
281032
+ break;
281033
+ }
281034
+ default: {
281035
+ refKind = "unknown";
281036
+ }
281037
+ }
281038
+ if (refKind === "branch" && headBranch && defaultBranch && headBranch === defaultBranch) {
281039
+ refKind = "default-branch";
281040
+ }
281041
+ return { provider, headBranch, rawRef, defaultBranch, refKind, isPrContext, isForkPr, headSha };
281042
+ }
281043
+ function parseChannelRules(input) {
281044
+ const raw = clean(input);
281045
+ const rules = [];
281046
+ for (const part of raw ? raw.split(",") : []) {
281047
+ const entry = part.trim();
281048
+ if (!entry) continue;
281049
+ const eq = entry.indexOf("=");
281050
+ if (eq <= 0 || eq === entry.length - 1) {
281051
+ throw new ContractError(
281052
+ "CONTRACT_CHANNELS_INPUT_INVALID",
281053
+ `channels entry "${entry}" must be <branch-or-glob>=<CODE>`
281054
+ );
281055
+ }
281056
+ const pattern = entry.slice(0, eq).trim();
281057
+ const code = entry.slice(eq + 1).trim().toUpperCase();
281058
+ if (!/^[A-Z][A-Z0-9_-]{0,15}$/.test(code)) {
281059
+ throw new ContractError(
281060
+ "CONTRACT_CHANNELS_INPUT_INVALID",
281061
+ `channel code "${code}" must be 1-16 chars, A-Z 0-9 _ -, starting with a letter`
281062
+ );
281063
+ }
281064
+ rules.push({ pattern, code });
281065
+ }
281066
+ if (!rules.some((rule) => rule.pattern === "release/*")) {
281067
+ rules.push({ pattern: "release/*", code: "RC" });
281068
+ }
281069
+ return rules;
281070
+ }
281071
+ function matchChannel(branch, rules) {
281072
+ for (const rule of rules) {
281073
+ if (rule.pattern.endsWith("*")) {
281074
+ const prefix = rule.pattern.slice(0, -1);
281075
+ if (branch.startsWith(prefix)) return rule;
281076
+ } else if (branch === rule.pattern) {
281077
+ return rule;
281078
+ }
281079
+ }
281080
+ return void 0;
281081
+ }
281082
+ function resolveBranchDecision(options) {
281083
+ const { strategy, identity } = options;
281084
+ const channels = options.channels ?? [];
281085
+ if (strategy === "legacy") {
281086
+ return {
281087
+ tier: "legacy",
281088
+ strategy,
281089
+ identity,
281090
+ canonicalBranch: clean(options.canonicalBranch) ?? identity.defaultBranch,
281091
+ reason: "branch-strategy legacy: branch-blind pre-v2 behavior"
281092
+ };
281093
+ }
281094
+ const canonicalBranch = clean(options.canonicalBranch) ?? identity.defaultBranch;
281095
+ if (!canonicalBranch) {
281096
+ throw new ContractError(
281097
+ "CONTRACT_DEFAULT_BRANCH_UNRESOLVED",
281098
+ `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.`
281099
+ );
281100
+ }
281101
+ if (identity.refKind === "tag" || identity.refKind === "unknown" || !identity.headBranch) {
281102
+ return {
281103
+ tier: "gated",
281104
+ strategy,
281105
+ identity,
281106
+ canonicalBranch,
281107
+ reason: `ref kind ${identity.refKind}: never canonical/preview-eligible; no-op with annotation`
281108
+ };
281109
+ }
281110
+ if (identity.headBranch === canonicalBranch) {
281111
+ return {
281112
+ tier: "canonical",
281113
+ strategy,
281114
+ identity,
281115
+ canonicalBranch,
281116
+ reason: `head branch equals canonical branch ${canonicalBranch}`
281117
+ };
281118
+ }
281119
+ const channel = matchChannel(identity.headBranch, channels);
281120
+ if (channel) {
281121
+ return {
281122
+ tier: "channel",
281123
+ strategy,
281124
+ identity,
281125
+ canonicalBranch,
281126
+ channel,
281127
+ reason: `branch ${identity.headBranch} matches channel ${channel.pattern}=${channel.code}`
281128
+ };
281129
+ }
281130
+ if (strategy === "preview") {
281131
+ if (identity.isForkPr) {
281132
+ return {
281133
+ tier: "gated",
281134
+ strategy,
281135
+ identity,
281136
+ canonicalBranch,
281137
+ reason: "fork PR: preview-ineligible (same-repo gate), gated instead"
281138
+ };
281139
+ }
281140
+ return {
281141
+ tier: "preview",
281142
+ strategy,
281143
+ identity,
281144
+ canonicalBranch,
281145
+ reason: `branch ${identity.headBranch} under branch-strategy preview`
281146
+ };
281147
+ }
281148
+ return {
281149
+ tier: "gated",
281150
+ strategy,
281151
+ identity,
281152
+ canonicalBranch,
281153
+ reason: `branch ${identity.headBranch} under branch-strategy publish-gate`
281154
+ };
281155
+ }
281156
+ var BRANCH_DECISION_ENV = "POSTMAN_BRANCH_DECISION";
281157
+ function serializeBranchDecision(decision) {
281158
+ return JSON.stringify(decision);
281159
+ }
281160
+ function parseBranchDecision(raw) {
281161
+ const value = clean(raw);
281162
+ if (!value) return void 0;
281163
+ let parsed;
281164
+ try {
281165
+ parsed = JSON.parse(value);
281166
+ } catch {
281167
+ throw new ContractError("CONTRACT_BRANCH_DECISION_INVALID", "POSTMAN_BRANCH_DECISION is not valid JSON");
281168
+ }
281169
+ const candidate = parsed;
281170
+ const tiers = ["canonical", "channel", "preview", "gated", "legacy"];
281171
+ if (!candidate || typeof candidate !== "object" || !tiers.includes(candidate.tier) || !candidate.identity) {
281172
+ throw new ContractError("CONTRACT_BRANCH_DECISION_INVALID", "POSTMAN_BRANCH_DECISION does not carry a valid BranchDecision");
281173
+ }
281174
+ return candidate;
281175
+ }
281176
+ function resolveEffectiveBranchDecision(options, env = process.env) {
281177
+ const inherited = parseBranchDecision(env[BRANCH_DECISION_ENV]);
281178
+ if (inherited) return inherited;
281179
+ return resolveBranchDecision(options);
281180
+ }
281181
+ var PREVIEW_SLUG_MAX = 30;
281182
+ function buildBranchSlug(rawBranch) {
281183
+ const sanitized = rawBranch.replace(/^refs\/heads\//, "").replace(/\s+/g, "-").replace(/[^A-Za-z0-9._-]/g, "-").replace(/-+/g, "-").replace(/^[._-]+|[._-]+$/g, "");
281184
+ const truncated = sanitized.slice(0, PREVIEW_SLUG_MAX);
281185
+ const lossy = truncated !== rawBranch.replace(/^refs\/heads\//, "");
281186
+ if (!lossy) {
281187
+ return { suffix: truncated, slug: truncated, lossy };
281188
+ }
281189
+ const hash = (0, import_node_crypto4.createHash)("sha256").update(rawBranch).digest("hex").slice(0, 6);
281190
+ return { suffix: `${truncated}-${hash}`, slug: truncated, lossy };
281191
+ }
281192
+ function previewAssetName(baseName, rawBranch) {
281193
+ return `${baseName} @${buildBranchSlug(rawBranch).suffix}`;
281194
+ }
281195
+ function channelAssetName(baseName, code) {
281196
+ return `[${code}] ${baseName}`;
281197
+ }
281198
+ var MARKER_KEY = "x-pm-onboarding";
281199
+ function renderAssetMarker(marker) {
281200
+ return `${MARKER_KEY}: ${JSON.stringify(marker)}`;
281201
+ }
281202
+
280430
281203
  // node_modules/graphql/jsutils/inspect.mjs
280431
281204
  var MAX_ARRAY_LENGTH = 10;
280432
281205
  var MAX_RECURSIVE_DEPTH = 2;
@@ -296958,940 +297731,6 @@ function getPositionFromMatch(match) {
296958
297731
  }
296959
297732
 
296960
297733
  // node_modules/@nodable/entities/src/entities.js
296961
- var BASIC_LATIN = {
296962
- amp: "&",
296963
- AMP: "&",
296964
- lt: "<",
296965
- LT: "<",
296966
- gt: ">",
296967
- GT: ">",
296968
- quot: '"',
296969
- QUOT: '"',
296970
- apos: "'",
296971
- lsquo: "\u2018",
296972
- rsquo: "\u2019",
296973
- ldquo: "\u201C",
296974
- rdquo: "\u201D",
296975
- lsquor: "\u201A",
296976
- rsquor: "\u2019",
296977
- ldquor: "\u201E",
296978
- bdquo: "\u201E",
296979
- comma: ",",
296980
- period: ".",
296981
- colon: ":",
296982
- semi: ";",
296983
- excl: "!",
296984
- quest: "?",
296985
- num: "#",
296986
- dollar: "$",
296987
- percent: "%",
296988
- ast: "*",
296989
- commat: "@",
296990
- lowbar: "_",
296991
- verbar: "|",
296992
- vert: "|",
296993
- sol: "/",
296994
- bsol: "\\",
296995
- lbrace: "{",
296996
- rbrace: "}",
296997
- lbrack: "[",
296998
- rbrack: "]",
296999
- lpar: "(",
297000
- rpar: ")",
297001
- nbsp: "\xA0",
297002
- iexcl: "\xA1",
297003
- cent: "\xA2",
297004
- pound: "\xA3",
297005
- curren: "\xA4",
297006
- yen: "\xA5",
297007
- brvbar: "\xA6",
297008
- sect: "\xA7",
297009
- uml: "\xA8",
297010
- copy: "\xA9",
297011
- COPY: "\xA9",
297012
- ordf: "\xAA",
297013
- laquo: "\xAB",
297014
- not: "\xAC",
297015
- shy: "\xAD",
297016
- reg: "\xAE",
297017
- REG: "\xAE",
297018
- macr: "\xAF",
297019
- deg: "\xB0",
297020
- plusmn: "\xB1",
297021
- sup2: "\xB2",
297022
- sup3: "\xB3",
297023
- acute: "\xB4",
297024
- micro: "\xB5",
297025
- para: "\xB6",
297026
- middot: "\xB7",
297027
- cedil: "\xB8",
297028
- sup1: "\xB9",
297029
- ordm: "\xBA",
297030
- raquo: "\xBB",
297031
- frac14: "\xBC",
297032
- frac12: "\xBD",
297033
- half: "\xBD",
297034
- frac34: "\xBE",
297035
- iquest: "\xBF",
297036
- times: "\xD7",
297037
- div: "\xF7",
297038
- divide: "\xF7"
297039
- };
297040
- var LATIN_ACCENTS = {
297041
- Agrave: "\xC0",
297042
- agrave: "\xE0",
297043
- Aacute: "\xC1",
297044
- aacute: "\xE1",
297045
- Acirc: "\xC2",
297046
- acirc: "\xE2",
297047
- Atilde: "\xC3",
297048
- atilde: "\xE3",
297049
- Auml: "\xC4",
297050
- auml: "\xE4",
297051
- Aring: "\xC5",
297052
- aring: "\xE5",
297053
- AElig: "\xC6",
297054
- aelig: "\xE6",
297055
- Ccedil: "\xC7",
297056
- ccedil: "\xE7",
297057
- Egrave: "\xC8",
297058
- egrave: "\xE8",
297059
- Eacute: "\xC9",
297060
- eacute: "\xE9",
297061
- Ecirc: "\xCA",
297062
- ecirc: "\xEA",
297063
- Euml: "\xCB",
297064
- euml: "\xEB",
297065
- Igrave: "\xCC",
297066
- igrave: "\xEC",
297067
- Iacute: "\xCD",
297068
- iacute: "\xED",
297069
- Icirc: "\xCE",
297070
- icirc: "\xEE",
297071
- Iuml: "\xCF",
297072
- iuml: "\xEF",
297073
- ETH: "\xD0",
297074
- eth: "\xF0",
297075
- Ntilde: "\xD1",
297076
- ntilde: "\xF1",
297077
- Ograve: "\xD2",
297078
- ograve: "\xF2",
297079
- Oacute: "\xD3",
297080
- oacute: "\xF3",
297081
- Ocirc: "\xD4",
297082
- ocirc: "\xF4",
297083
- Otilde: "\xD5",
297084
- otilde: "\xF5",
297085
- Ouml: "\xD6",
297086
- ouml: "\xF6",
297087
- Oslash: "\xD8",
297088
- oslash: "\xF8",
297089
- Ugrave: "\xD9",
297090
- ugrave: "\xF9",
297091
- Uacute: "\xDA",
297092
- uacute: "\xFA",
297093
- Ucirc: "\xDB",
297094
- ucirc: "\xFB",
297095
- Uuml: "\xDC",
297096
- uuml: "\xFC",
297097
- Yacute: "\xDD",
297098
- yacute: "\xFD",
297099
- THORN: "\xDE",
297100
- thorn: "\xFE",
297101
- szlig: "\xDF",
297102
- yuml: "\xFF",
297103
- Yuml: "\u0178"
297104
- };
297105
- var LATIN_EXTENDED = {
297106
- Amacr: "\u0100",
297107
- amacr: "\u0101",
297108
- Abreve: "\u0102",
297109
- abreve: "\u0103",
297110
- Aogon: "\u0104",
297111
- aogon: "\u0105",
297112
- Cacute: "\u0106",
297113
- cacute: "\u0107",
297114
- Ccirc: "\u0108",
297115
- ccirc: "\u0109",
297116
- Cdot: "\u010A",
297117
- cdot: "\u010B",
297118
- Ccaron: "\u010C",
297119
- ccaron: "\u010D",
297120
- Dcaron: "\u010E",
297121
- dcaron: "\u010F",
297122
- Dstrok: "\u0110",
297123
- dstrok: "\u0111",
297124
- Emacr: "\u0112",
297125
- emacr: "\u0113",
297126
- Ecaron: "\u011A",
297127
- ecaron: "\u011B",
297128
- Edot: "\u0116",
297129
- edot: "\u0117",
297130
- Eogon: "\u0118",
297131
- eogon: "\u0119",
297132
- Gcirc: "\u011C",
297133
- gcirc: "\u011D",
297134
- Gbreve: "\u011E",
297135
- gbreve: "\u011F",
297136
- Gdot: "\u0120",
297137
- gdot: "\u0121",
297138
- Gcedil: "\u0122",
297139
- Hcirc: "\u0124",
297140
- hcirc: "\u0125",
297141
- Hstrok: "\u0126",
297142
- hstrok: "\u0127",
297143
- Itilde: "\u0128",
297144
- itilde: "\u0129",
297145
- Imacr: "\u012A",
297146
- imacr: "\u012B",
297147
- Iogon: "\u012E",
297148
- iogon: "\u012F",
297149
- Idot: "\u0130",
297150
- IJlig: "\u0132",
297151
- ijlig: "\u0133",
297152
- Jcirc: "\u0134",
297153
- jcirc: "\u0135",
297154
- Kcedil: "\u0136",
297155
- kcedil: "\u0137",
297156
- kgreen: "\u0138",
297157
- Lacute: "\u0139",
297158
- lacute: "\u013A",
297159
- Lcedil: "\u013B",
297160
- lcedil: "\u013C",
297161
- Lcaron: "\u013D",
297162
- lcaron: "\u013E",
297163
- Lmidot: "\u013F",
297164
- lmidot: "\u0140",
297165
- Lstrok: "\u0141",
297166
- lstrok: "\u0142",
297167
- Nacute: "\u0143",
297168
- nacute: "\u0144",
297169
- Ncaron: "\u0147",
297170
- ncaron: "\u0148",
297171
- Ncedil: "\u0145",
297172
- ncedil: "\u0146",
297173
- ENG: "\u014A",
297174
- eng: "\u014B",
297175
- Omacr: "\u014C",
297176
- omacr: "\u014D",
297177
- Odblac: "\u0150",
297178
- odblac: "\u0151",
297179
- OElig: "\u0152",
297180
- oelig: "\u0153",
297181
- Racute: "\u0154",
297182
- racute: "\u0155",
297183
- Rcaron: "\u0158",
297184
- rcaron: "\u0159",
297185
- Rcedil: "\u0156",
297186
- rcedil: "\u0157",
297187
- Sacute: "\u015A",
297188
- sacute: "\u015B",
297189
- Scirc: "\u015C",
297190
- scirc: "\u015D",
297191
- Scedil: "\u015E",
297192
- scedil: "\u015F",
297193
- Scaron: "\u0160",
297194
- scaron: "\u0161",
297195
- Tcedil: "\u0162",
297196
- tcedil: "\u0163",
297197
- Tcaron: "\u0164",
297198
- tcaron: "\u0165",
297199
- Tstrok: "\u0166",
297200
- tstrok: "\u0167",
297201
- Utilde: "\u0168",
297202
- utilde: "\u0169",
297203
- Umacr: "\u016A",
297204
- umacr: "\u016B",
297205
- Ubreve: "\u016C",
297206
- ubreve: "\u016D",
297207
- Uring: "\u016E",
297208
- uring: "\u016F",
297209
- Udblac: "\u0170",
297210
- udblac: "\u0171",
297211
- Uogon: "\u0172",
297212
- uogon: "\u0173",
297213
- Wcirc: "\u0174",
297214
- wcirc: "\u0175",
297215
- Ycirc: "\u0176",
297216
- ycirc: "\u0177",
297217
- Zacute: "\u0179",
297218
- zacute: "\u017A",
297219
- Zdot: "\u017B",
297220
- zdot: "\u017C",
297221
- Zcaron: "\u017D",
297222
- zcaron: "\u017E"
297223
- };
297224
- var GREEK = {
297225
- Alpha: "\u0391",
297226
- alpha: "\u03B1",
297227
- Beta: "\u0392",
297228
- beta: "\u03B2",
297229
- Gamma: "\u0393",
297230
- gamma: "\u03B3",
297231
- Delta: "\u0394",
297232
- delta: "\u03B4",
297233
- Epsilon: "\u0395",
297234
- epsilon: "\u03B5",
297235
- epsiv: "\u03F5",
297236
- varepsilon: "\u03F5",
297237
- Zeta: "\u0396",
297238
- zeta: "\u03B6",
297239
- Eta: "\u0397",
297240
- eta: "\u03B7",
297241
- Theta: "\u0398",
297242
- theta: "\u03B8",
297243
- thetasym: "\u03D1",
297244
- vartheta: "\u03D1",
297245
- Iota: "\u0399",
297246
- iota: "\u03B9",
297247
- Kappa: "\u039A",
297248
- kappa: "\u03BA",
297249
- kappav: "\u03F0",
297250
- varkappa: "\u03F0",
297251
- Lambda: "\u039B",
297252
- lambda: "\u03BB",
297253
- Mu: "\u039C",
297254
- mu: "\u03BC",
297255
- Nu: "\u039D",
297256
- nu: "\u03BD",
297257
- Xi: "\u039E",
297258
- xi: "\u03BE",
297259
- Omicron: "\u039F",
297260
- omicron: "\u03BF",
297261
- Pi: "\u03A0",
297262
- pi: "\u03C0",
297263
- piv: "\u03D6",
297264
- varpi: "\u03D6",
297265
- Rho: "\u03A1",
297266
- rho: "\u03C1",
297267
- rhov: "\u03F1",
297268
- varrho: "\u03F1",
297269
- Sigma: "\u03A3",
297270
- sigma: "\u03C3",
297271
- sigmaf: "\u03C2",
297272
- sigmav: "\u03C2",
297273
- varsigma: "\u03C2",
297274
- Tau: "\u03A4",
297275
- tau: "\u03C4",
297276
- Upsilon: "\u03A5",
297277
- upsilon: "\u03C5",
297278
- upsi: "\u03C5",
297279
- Upsi: "\u03D2",
297280
- upsih: "\u03D2",
297281
- Phi: "\u03A6",
297282
- phi: "\u03C6",
297283
- phiv: "\u03D5",
297284
- varphi: "\u03D5",
297285
- Chi: "\u03A7",
297286
- chi: "\u03C7",
297287
- Psi: "\u03A8",
297288
- psi: "\u03C8",
297289
- Omega: "\u03A9",
297290
- omega: "\u03C9",
297291
- ohm: "\u03A9",
297292
- Gammad: "\u03DC",
297293
- gammad: "\u03DD",
297294
- digamma: "\u03DD"
297295
- };
297296
- var CYRILLIC = {
297297
- Afr: "\u{1D504}",
297298
- afr: "\u{1D51E}",
297299
- Acy: "\u0410",
297300
- acy: "\u0430",
297301
- Bcy: "\u0411",
297302
- bcy: "\u0431",
297303
- Vcy: "\u0412",
297304
- vcy: "\u0432",
297305
- Gcy: "\u0413",
297306
- gcy: "\u0433",
297307
- Dcy: "\u0414",
297308
- dcy: "\u0434",
297309
- IEcy: "\u0415",
297310
- iecy: "\u0435",
297311
- IOcy: "\u0401",
297312
- iocy: "\u0451",
297313
- ZHcy: "\u0416",
297314
- zhcy: "\u0436",
297315
- Zcy: "\u0417",
297316
- zcy: "\u0437",
297317
- Icy: "\u0418",
297318
- icy: "\u0438",
297319
- Jcy: "\u0419",
297320
- jcy: "\u0439",
297321
- Kcy: "\u041A",
297322
- kcy: "\u043A",
297323
- Lcy: "\u041B",
297324
- lcy: "\u043B",
297325
- Mcy: "\u041C",
297326
- mcy: "\u043C",
297327
- Ncy: "\u041D",
297328
- ncy: "\u043D",
297329
- Ocy: "\u041E",
297330
- ocy: "\u043E",
297331
- Pcy: "\u041F",
297332
- pcy: "\u043F",
297333
- Rcy: "\u0420",
297334
- rcy: "\u0440",
297335
- Scy: "\u0421",
297336
- scy: "\u0441",
297337
- Tcy: "\u0422",
297338
- tcy: "\u0442",
297339
- Ucy: "\u0423",
297340
- ucy: "\u0443",
297341
- Fcy: "\u0424",
297342
- fcy: "\u0444",
297343
- KHcy: "\u0425",
297344
- khcy: "\u0445",
297345
- TScy: "\u0426",
297346
- tscy: "\u0446",
297347
- CHcy: "\u0427",
297348
- chcy: "\u0447",
297349
- SHcy: "\u0428",
297350
- shcy: "\u0448",
297351
- SHCHcy: "\u0429",
297352
- shchcy: "\u0449",
297353
- HARDcy: "\u042A",
297354
- hardcy: "\u044A",
297355
- Ycy: "\u042B",
297356
- ycy: "\u044B",
297357
- SOFTcy: "\u042C",
297358
- softcy: "\u044C",
297359
- Ecy: "\u042D",
297360
- ecy: "\u044D",
297361
- YUcy: "\u042E",
297362
- yucy: "\u044E",
297363
- YAcy: "\u042F",
297364
- yacy: "\u044F",
297365
- DJcy: "\u0402",
297366
- djcy: "\u0452",
297367
- GJcy: "\u0403",
297368
- gjcy: "\u0453",
297369
- Jukcy: "\u0404",
297370
- jukcy: "\u0454",
297371
- DScy: "\u0405",
297372
- dscy: "\u0455",
297373
- Iukcy: "\u0406",
297374
- iukcy: "\u0456",
297375
- YIcy: "\u0407",
297376
- yicy: "\u0457",
297377
- Jsercy: "\u0408",
297378
- jsercy: "\u0458",
297379
- LJcy: "\u0409",
297380
- ljcy: "\u0459",
297381
- NJcy: "\u040A",
297382
- njcy: "\u045A",
297383
- TSHcy: "\u040B",
297384
- tshcy: "\u045B",
297385
- KJcy: "\u040C",
297386
- kjcy: "\u045C",
297387
- Ubrcy: "\u040E",
297388
- ubrcy: "\u045E",
297389
- DZcy: "\u040F",
297390
- dzcy: "\u045F"
297391
- };
297392
- var MATH = {
297393
- plus: "+",
297394
- pm: "\xB1",
297395
- times: "\xD7",
297396
- div: "\xF7",
297397
- divide: "\xF7",
297398
- sdot: "\u22C5",
297399
- star: "\u2606",
297400
- starf: "\u2605",
297401
- bigstar: "\u2605",
297402
- lowast: "\u2217",
297403
- ast: "*",
297404
- midast: "*",
297405
- compfn: "\u2218",
297406
- smallcircle: "\u2218",
297407
- bullet: "\u2022",
297408
- bull: "\u2022",
297409
- nbsp: "\xA0",
297410
- hellip: "\u2026",
297411
- mldr: "\u2026",
297412
- prime: "\u2032",
297413
- Prime: "\u2033",
297414
- tprime: "\u2034",
297415
- bprime: "\u2035",
297416
- backprime: "\u2035",
297417
- minus: "\u2212",
297418
- minusd: "\u2238",
297419
- dotminus: "\u2238",
297420
- plusdo: "\u2214",
297421
- dotplus: "\u2214",
297422
- plusmn: "\xB1",
297423
- minusplus: "\u2213",
297424
- mnplus: "\u2213",
297425
- mp: "\u2213",
297426
- setminus: "\u2216",
297427
- smallsetminus: "\u2216",
297428
- Backslash: "\u2216",
297429
- setmn: "\u2216",
297430
- ssetmn: "\u2216",
297431
- lowbar: "_",
297432
- verbar: "|",
297433
- vert: "|",
297434
- VerticalLine: "|",
297435
- colon: ":",
297436
- Colon: "\u2237",
297437
- Proportion: "\u2237",
297438
- ratio: "\u2236",
297439
- equals: "=",
297440
- ne: "\u2260",
297441
- nequiv: "\u2262",
297442
- equiv: "\u2261",
297443
- Congruent: "\u2261",
297444
- sim: "\u223C",
297445
- thicksim: "\u223C",
297446
- thksim: "\u223C",
297447
- sime: "\u2243",
297448
- simeq: "\u2243",
297449
- TildeEqual: "\u2243",
297450
- asymp: "\u2248",
297451
- approx: "\u2248",
297452
- thickapprox: "\u2248",
297453
- thkap: "\u2248",
297454
- TildeTilde: "\u2248",
297455
- ncong: "\u2247",
297456
- cong: "\u2245",
297457
- TildeFullEqual: "\u2245",
297458
- asympeq: "\u224D",
297459
- CupCap: "\u224D",
297460
- bump: "\u224E",
297461
- Bumpeq: "\u224E",
297462
- HumpDownHump: "\u224E",
297463
- bumpe: "\u224F",
297464
- bumpeq: "\u224F",
297465
- HumpEqual: "\u224F",
297466
- le: "\u2264",
297467
- LessEqual: "\u2264",
297468
- ge: "\u2265",
297469
- GreaterEqual: "\u2265",
297470
- lesseqgtr: "\u22DA",
297471
- lesseqqgtr: "\u2A8B",
297472
- greater: ">",
297473
- less: "<"
297474
- };
297475
- var MATH_ADVANCED = {
297476
- alefsym: "\u2135",
297477
- aleph: "\u2135",
297478
- beth: "\u2136",
297479
- gimel: "\u2137",
297480
- daleth: "\u2138",
297481
- forall: "\u2200",
297482
- ForAll: "\u2200",
297483
- part: "\u2202",
297484
- PartialD: "\u2202",
297485
- exist: "\u2203",
297486
- Exists: "\u2203",
297487
- nexist: "\u2204",
297488
- nexists: "\u2204",
297489
- empty: "\u2205",
297490
- emptyset: "\u2205",
297491
- emptyv: "\u2205",
297492
- varnothing: "\u2205",
297493
- nabla: "\u2207",
297494
- Del: "\u2207",
297495
- isin: "\u2208",
297496
- isinv: "\u2208",
297497
- in: "\u2208",
297498
- Element: "\u2208",
297499
- notin: "\u2209",
297500
- notinva: "\u2209",
297501
- ni: "\u220B",
297502
- niv: "\u220B",
297503
- SuchThat: "\u220B",
297504
- ReverseElement: "\u220B",
297505
- notni: "\u220C",
297506
- notniva: "\u220C",
297507
- prod: "\u220F",
297508
- Product: "\u220F",
297509
- coprod: "\u2210",
297510
- Coproduct: "\u2210",
297511
- sum: "\u2211",
297512
- Sum: "\u2211",
297513
- minus: "\u2212",
297514
- mp: "\u2213",
297515
- plusdo: "\u2214",
297516
- dotplus: "\u2214",
297517
- setminus: "\u2216",
297518
- lowast: "\u2217",
297519
- radic: "\u221A",
297520
- Sqrt: "\u221A",
297521
- prop: "\u221D",
297522
- propto: "\u221D",
297523
- Proportional: "\u221D",
297524
- varpropto: "\u221D",
297525
- infin: "\u221E",
297526
- infintie: "\u29DD",
297527
- ang: "\u2220",
297528
- angle: "\u2220",
297529
- angmsd: "\u2221",
297530
- measuredangle: "\u2221",
297531
- angsph: "\u2222",
297532
- mid: "\u2223",
297533
- VerticalBar: "\u2223",
297534
- nmid: "\u2224",
297535
- nsmid: "\u2224",
297536
- npar: "\u2226",
297537
- parallel: "\u2225",
297538
- spar: "\u2225",
297539
- nparallel: "\u2226",
297540
- nspar: "\u2226",
297541
- and: "\u2227",
297542
- wedge: "\u2227",
297543
- or: "\u2228",
297544
- vee: "\u2228",
297545
- cap: "\u2229",
297546
- cup: "\u222A",
297547
- int: "\u222B",
297548
- Integral: "\u222B",
297549
- conint: "\u222E",
297550
- ContourIntegral: "\u222E",
297551
- Conint: "\u222F",
297552
- DoubleContourIntegral: "\u222F",
297553
- Cconint: "\u2230",
297554
- there4: "\u2234",
297555
- therefore: "\u2234",
297556
- Therefore: "\u2234",
297557
- becaus: "\u2235",
297558
- because: "\u2235",
297559
- Because: "\u2235",
297560
- ratio: "\u2236",
297561
- Proportion: "\u2237",
297562
- minusd: "\u2238",
297563
- dotminus: "\u2238",
297564
- mDDot: "\u223A",
297565
- homtht: "\u223B",
297566
- sim: "\u223C",
297567
- bsimg: "\u223D",
297568
- backsim: "\u223D",
297569
- ac: "\u223E",
297570
- mstpos: "\u223E",
297571
- acd: "\u223F",
297572
- VerticalTilde: "\u2240",
297573
- wr: "\u2240",
297574
- wreath: "\u2240",
297575
- nsime: "\u2244",
297576
- nsimeq: "\u2244",
297577
- ncong: "\u2247",
297578
- simne: "\u2246",
297579
- ncongdot: "\u2A6D\u0338",
297580
- ngsim: "\u2275",
297581
- nsim: "\u2241",
297582
- napprox: "\u2249",
297583
- nap: "\u2249",
297584
- ngeq: "\u2271",
297585
- nge: "\u2271",
297586
- nleq: "\u2270",
297587
- nle: "\u2270",
297588
- ngtr: "\u226F",
297589
- ngt: "\u226F",
297590
- nless: "\u226E",
297591
- nlt: "\u226E",
297592
- nprec: "\u2280",
297593
- npr: "\u2280",
297594
- nsucc: "\u2281",
297595
- nsc: "\u2281"
297596
- };
297597
- var ARROWS = {
297598
- larr: "\u2190",
297599
- leftarrow: "\u2190",
297600
- LeftArrow: "\u2190",
297601
- uarr: "\u2191",
297602
- uparrow: "\u2191",
297603
- UpArrow: "\u2191",
297604
- rarr: "\u2192",
297605
- rightarrow: "\u2192",
297606
- RightArrow: "\u2192",
297607
- darr: "\u2193",
297608
- downarrow: "\u2193",
297609
- DownArrow: "\u2193",
297610
- harr: "\u2194",
297611
- leftrightarrow: "\u2194",
297612
- LeftRightArrow: "\u2194",
297613
- varr: "\u2195",
297614
- updownarrow: "\u2195",
297615
- UpDownArrow: "\u2195",
297616
- nwarr: "\u2196",
297617
- nwarrow: "\u2196",
297618
- UpperLeftArrow: "\u2196",
297619
- nearr: "\u2197",
297620
- nearrow: "\u2197",
297621
- UpperRightArrow: "\u2197",
297622
- searr: "\u2198",
297623
- searrow: "\u2198",
297624
- LowerRightArrow: "\u2198",
297625
- swarr: "\u2199",
297626
- swarrow: "\u2199",
297627
- LowerLeftArrow: "\u2199",
297628
- lArr: "\u21D0",
297629
- Leftarrow: "\u21D0",
297630
- uArr: "\u21D1",
297631
- Uparrow: "\u21D1",
297632
- rArr: "\u21D2",
297633
- Rightarrow: "\u21D2",
297634
- dArr: "\u21D3",
297635
- Downarrow: "\u21D3",
297636
- hArr: "\u21D4",
297637
- Leftrightarrow: "\u21D4",
297638
- iff: "\u21D4",
297639
- vArr: "\u21D5",
297640
- Updownarrow: "\u21D5",
297641
- lAarr: "\u21DA",
297642
- Lleftarrow: "\u21DA",
297643
- rAarr: "\u21DB",
297644
- Rrightarrow: "\u21DB",
297645
- lrarr: "\u21C6",
297646
- leftrightarrows: "\u21C6",
297647
- rlarr: "\u21C4",
297648
- rightleftarrows: "\u21C4",
297649
- lrhar: "\u21CB",
297650
- leftrightharpoons: "\u21CB",
297651
- ReverseEquilibrium: "\u21CB",
297652
- rlhar: "\u21CC",
297653
- rightleftharpoons: "\u21CC",
297654
- Equilibrium: "\u21CC",
297655
- udarr: "\u21C5",
297656
- UpArrowDownArrow: "\u21C5",
297657
- duarr: "\u21F5",
297658
- DownArrowUpArrow: "\u21F5",
297659
- llarr: "\u21C7",
297660
- leftleftarrows: "\u21C7",
297661
- rrarr: "\u21C9",
297662
- rightrightarrows: "\u21C9",
297663
- ddarr: "\u21CA",
297664
- downdownarrows: "\u21CA",
297665
- har: "\u21BD",
297666
- lhard: "\u21BD",
297667
- leftharpoondown: "\u21BD",
297668
- lharu: "\u21BC",
297669
- leftharpoonup: "\u21BC",
297670
- rhard: "\u21C1",
297671
- rightharpoondown: "\u21C1",
297672
- rharu: "\u21C0",
297673
- rightharpoonup: "\u21C0",
297674
- lsh: "\u21B0",
297675
- Lsh: "\u21B0",
297676
- rsh: "\u21B1",
297677
- Rsh: "\u21B1",
297678
- ldsh: "\u21B2",
297679
- rdsh: "\u21B3",
297680
- hookleftarrow: "\u21A9",
297681
- hookrightarrow: "\u21AA",
297682
- mapstoleft: "\u21A4",
297683
- mapstoup: "\u21A5",
297684
- map: "\u21A6",
297685
- mapsto: "\u21A6",
297686
- mapstodown: "\u21A7",
297687
- crarr: "\u21B5",
297688
- nleftarrow: "\u219A",
297689
- nleftrightarrow: "\u21AE",
297690
- nrightarrow: "\u219B",
297691
- nrarr: "\u219B",
297692
- larrtl: "\u21A2",
297693
- rarrtl: "\u21A3",
297694
- leftarrowtail: "\u21A2",
297695
- rightarrowtail: "\u21A3",
297696
- twoheadleftarrow: "\u219E",
297697
- twoheadrightarrow: "\u21A0",
297698
- Larr: "\u219E",
297699
- Rarr: "\u21A0",
297700
- larrhk: "\u21A9",
297701
- rarrhk: "\u21AA",
297702
- larrlp: "\u21AB",
297703
- looparrowleft: "\u21AB",
297704
- rarrlp: "\u21AC",
297705
- looparrowright: "\u21AC",
297706
- harrw: "\u21AD",
297707
- leftrightsquigarrow: "\u21AD",
297708
- nrarrw: "\u219D\u0338",
297709
- rarrw: "\u219D",
297710
- rightsquigarrow: "\u219D",
297711
- larrbfs: "\u291F",
297712
- rarrbfs: "\u2920",
297713
- nvHarr: "\u2904",
297714
- nvlArr: "\u2902",
297715
- nvrArr: "\u2903",
297716
- larrfs: "\u291D",
297717
- rarrfs: "\u291E",
297718
- Map: "\u2905",
297719
- larrsim: "\u2973",
297720
- rarrsim: "\u2974",
297721
- harrcir: "\u2948",
297722
- Uarrocir: "\u2949",
297723
- lurdshar: "\u294A",
297724
- ldrdhar: "\u2967",
297725
- ldrushar: "\u294B",
297726
- rdldhar: "\u2969",
297727
- lrhard: "\u296D",
297728
- uharr: "\u21BE",
297729
- uharl: "\u21BF",
297730
- dharr: "\u21C2",
297731
- dharl: "\u21C3",
297732
- Uarr: "\u219F",
297733
- Darr: "\u21A1",
297734
- zigrarr: "\u21DD",
297735
- nwArr: "\u21D6",
297736
- neArr: "\u21D7",
297737
- seArr: "\u21D8",
297738
- swArr: "\u21D9",
297739
- nharr: "\u21AE",
297740
- nhArr: "\u21CE",
297741
- nlarr: "\u219A",
297742
- nlArr: "\u21CD",
297743
- nrArr: "\u21CF",
297744
- larrb: "\u21E4",
297745
- LeftArrowBar: "\u21E4",
297746
- rarrb: "\u21E5",
297747
- RightArrowBar: "\u21E5"
297748
- };
297749
- var SHAPES = {
297750
- square: "\u25A1",
297751
- Square: "\u25A1",
297752
- squ: "\u25A1",
297753
- squf: "\u25AA",
297754
- squarf: "\u25AA",
297755
- blacksquar: "\u25AA",
297756
- blacksquare: "\u25AA",
297757
- FilledVerySmallSquare: "\u25AA",
297758
- blk34: "\u2593",
297759
- blk12: "\u2592",
297760
- blk14: "\u2591",
297761
- block: "\u2588",
297762
- srect: "\u25AD",
297763
- rect: "\u25AD",
297764
- sdot: "\u22C5",
297765
- sdotb: "\u22A1",
297766
- dotsquare: "\u22A1",
297767
- triangle: "\u25B5",
297768
- tri: "\u25B5",
297769
- trine: "\u25B5",
297770
- utri: "\u25B5",
297771
- triangledown: "\u25BF",
297772
- dtri: "\u25BF",
297773
- tridown: "\u25BF",
297774
- triangleleft: "\u25C3",
297775
- ltri: "\u25C3",
297776
- triangleright: "\u25B9",
297777
- rtri: "\u25B9",
297778
- blacktriangle: "\u25B4",
297779
- utrif: "\u25B4",
297780
- blacktriangledown: "\u25BE",
297781
- dtrif: "\u25BE",
297782
- blacktriangleleft: "\u25C2",
297783
- ltrif: "\u25C2",
297784
- blacktriangleright: "\u25B8",
297785
- rtrif: "\u25B8",
297786
- loz: "\u25CA",
297787
- lozenge: "\u25CA",
297788
- blacklozenge: "\u29EB",
297789
- lozf: "\u29EB",
297790
- bigcirc: "\u25EF",
297791
- xcirc: "\u25EF",
297792
- circ: "\u02C6",
297793
- Circle: "\u25CB",
297794
- cir: "\u25CB",
297795
- o: "\u25CB",
297796
- bullet: "\u2022",
297797
- bull: "\u2022",
297798
- hellip: "\u2026",
297799
- mldr: "\u2026",
297800
- nldr: "\u2025",
297801
- boxh: "\u2500",
297802
- HorizontalLine: "\u2500",
297803
- boxv: "\u2502",
297804
- boxdr: "\u250C",
297805
- boxdl: "\u2510",
297806
- boxur: "\u2514",
297807
- boxul: "\u2518",
297808
- boxvr: "\u251C",
297809
- boxvl: "\u2524",
297810
- boxhd: "\u252C",
297811
- boxhu: "\u2534",
297812
- boxvh: "\u253C",
297813
- boxH: "\u2550",
297814
- boxV: "\u2551",
297815
- boxdR: "\u2552",
297816
- boxDr: "\u2553",
297817
- boxDR: "\u2554",
297818
- boxDl: "\u2555",
297819
- boxdL: "\u2556",
297820
- boxDL: "\u2557",
297821
- boxuR: "\u2558",
297822
- boxUr: "\u2559",
297823
- boxUR: "\u255A",
297824
- boxUl: "\u255C",
297825
- boxuL: "\u255B",
297826
- boxUL: "\u255D",
297827
- boxvR: "\u255E",
297828
- boxVr: "\u255F",
297829
- boxVR: "\u2560",
297830
- boxVl: "\u2562",
297831
- boxvL: "\u2561",
297832
- boxVL: "\u2563",
297833
- boxHd: "\u2564",
297834
- boxhD: "\u2565",
297835
- boxHD: "\u2566",
297836
- boxHu: "\u2567",
297837
- boxhU: "\u2568",
297838
- boxHU: "\u2569",
297839
- boxvH: "\u256A",
297840
- boxVh: "\u256B",
297841
- boxVH: "\u256C"
297842
- };
297843
- var PUNCTUATION = {
297844
- excl: "!",
297845
- iexcl: "\xA1",
297846
- brvbar: "\xA6",
297847
- sect: "\xA7",
297848
- uml: "\xA8",
297849
- copy: "\xA9",
297850
- ordf: "\xAA",
297851
- laquo: "\xAB",
297852
- not: "\xAC",
297853
- shy: "\xAD",
297854
- reg: "\xAE",
297855
- macr: "\xAF",
297856
- deg: "\xB0",
297857
- plusmn: "\xB1",
297858
- sup2: "\xB2",
297859
- sup3: "\xB3",
297860
- acute: "\xB4",
297861
- micro: "\xB5",
297862
- para: "\xB6",
297863
- middot: "\xB7",
297864
- cedil: "\xB8",
297865
- sup1: "\xB9",
297866
- ordm: "\xBA",
297867
- raquo: "\xBB",
297868
- frac14: "\xBC",
297869
- frac12: "\xBD",
297870
- frac34: "\xBE",
297871
- iquest: "\xBF",
297872
- nbsp: "\xA0",
297873
- comma: ",",
297874
- period: ".",
297875
- colon: ":",
297876
- semi: ";",
297877
- vert: "|",
297878
- Verbar: "\u2016",
297879
- verbar: "|",
297880
- dblac: "\u02DD",
297881
- circ: "\u02C6",
297882
- caron: "\u02C7",
297883
- breve: "\u02D8",
297884
- dot: "\u02D9",
297885
- ring: "\u02DA",
297886
- ogon: "\u02DB",
297887
- tilde: "\u02DC",
297888
- DiacriticalGrave: "`",
297889
- DiacriticalAcute: "\xB4",
297890
- DiacriticalTilde: "\u02DC",
297891
- DiacriticalDot: "\u02D9",
297892
- DiacriticalDoubleAcute: "\u02DD",
297893
- grave: "`"
297894
- };
297895
297734
  var CURRENCY = {
297896
297735
  cent: "\xA2",
297897
297736
  pound: "\xA3",
@@ -297909,106 +297748,6 @@ var CURRENCY = {
297909
297748
  yuan: "\xA5",
297910
297749
  cedil: "\xB8"
297911
297750
  };
297912
- var FRACTIONS = {
297913
- frac12: "\xBD",
297914
- half: "\xBD",
297915
- frac13: "\u2153",
297916
- frac14: "\xBC",
297917
- frac15: "\u2155",
297918
- frac16: "\u2159",
297919
- frac18: "\u215B",
297920
- frac23: "\u2154",
297921
- frac25: "\u2156",
297922
- frac34: "\xBE",
297923
- frac35: "\u2157",
297924
- frac38: "\u215C",
297925
- frac45: "\u2158",
297926
- frac56: "\u215A",
297927
- frac58: "\u215D",
297928
- frac78: "\u215E",
297929
- frasl: "\u2044"
297930
- };
297931
- var MISC_SYMBOLS = {
297932
- trade: "\u2122",
297933
- TRADE: "\u2122",
297934
- telrec: "\u2315",
297935
- target: "\u2316",
297936
- ulcorn: "\u231C",
297937
- ulcorner: "\u231C",
297938
- urcorn: "\u231D",
297939
- urcorner: "\u231D",
297940
- dlcorn: "\u231E",
297941
- llcorner: "\u231E",
297942
- drcorn: "\u231F",
297943
- lrcorner: "\u231F",
297944
- intercal: "\u22BA",
297945
- intcal: "\u22BA",
297946
- oplus: "\u2295",
297947
- CirclePlus: "\u2295",
297948
- ominus: "\u2296",
297949
- CircleMinus: "\u2296",
297950
- otimes: "\u2297",
297951
- CircleTimes: "\u2297",
297952
- osol: "\u2298",
297953
- odot: "\u2299",
297954
- CircleDot: "\u2299",
297955
- oast: "\u229B",
297956
- circledast: "\u229B",
297957
- odash: "\u229D",
297958
- circleddash: "\u229D",
297959
- ocirc: "\u229A",
297960
- circledcirc: "\u229A",
297961
- boxplus: "\u229E",
297962
- plusb: "\u229E",
297963
- boxminus: "\u229F",
297964
- minusb: "\u229F",
297965
- boxtimes: "\u22A0",
297966
- timesb: "\u22A0",
297967
- boxdot: "\u22A1",
297968
- sdotb: "\u22A1",
297969
- veebar: "\u22BB",
297970
- vee: "\u2228",
297971
- barvee: "\u22BD",
297972
- and: "\u2227",
297973
- wedge: "\u2227",
297974
- Cap: "\u22D2",
297975
- Cup: "\u22D3",
297976
- Fork: "\u22D4",
297977
- pitchfork: "\u22D4",
297978
- epar: "\u22D5",
297979
- ltlarr: "\u2976",
297980
- nvap: "\u224D\u20D2",
297981
- nvsim: "\u223C\u20D2",
297982
- nvge: "\u2265\u20D2",
297983
- nvle: "\u2264\u20D2",
297984
- nvlt: "<\u20D2",
297985
- nvgt: ">\u20D2",
297986
- nvltrie: "\u22B4\u20D2",
297987
- nvrtrie: "\u22B5\u20D2",
297988
- Vdash: "\u22A9",
297989
- dashv: "\u22A3",
297990
- vDash: "\u22A8",
297991
- Vvdash: "\u22AA",
297992
- nvdash: "\u22AC",
297993
- nvDash: "\u22AD",
297994
- nVdash: "\u22AE",
297995
- nVDash: "\u22AF"
297996
- };
297997
- var ALL_ENTITIES = {
297998
- ...BASIC_LATIN,
297999
- ...LATIN_ACCENTS,
298000
- ...LATIN_EXTENDED,
298001
- ...GREEK,
298002
- ...CYRILLIC,
298003
- ...MATH,
298004
- ...MATH_ADVANCED,
298005
- ...ARROWS,
298006
- ...SHAPES,
298007
- ...PUNCTUATION,
298008
- ...CURRENCY,
298009
- ...FRACTIONS,
298010
- ...MISC_SYMBOLS
298011
- };
298012
297751
  var XML = {
298013
297752
  amp: "&",
298014
297753
  apos: "'",
@@ -298652,7 +298391,7 @@ var XmlNode = class {
298652
298391
  }
298653
298392
  };
298654
298393
 
298655
- // node_modules/xml-naming/src/index.js
298394
+ // node_modules/fast-xml-parser/node_modules/xml-naming/src/index.js
298656
298395
  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";
298657
298396
  var nameChar10 = nameStartChar10 + "\\-\\.\\d\xB7\u0300-\u036F\u203F-\u2040";
298658
298397
  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}";
@@ -298671,8 +298410,14 @@ var buildRegexes = (startChar, char, flags = "") => {
298671
298410
  };
298672
298411
  var regexes10 = buildRegexes(nameStartChar10, nameChar10);
298673
298412
  var regexes11 = buildRegexes(nameStartChar11, nameChar11, "u");
298674
- var getRegexes = (xmlVersion = "1.0") => xmlVersion === "1.1" ? regexes11 : regexes10;
298675
- var qName = (str, { xmlVersion = "1.0" } = {}) => getRegexes(xmlVersion).qName.test(str);
298413
+ var nameStartCharAscii = ":A-Za-z_";
298414
+ var nameCharAscii = nameStartCharAscii + "\\-\\.\\d";
298415
+ var regexesAscii = buildRegexes(nameStartCharAscii, nameCharAscii);
298416
+ var getRegexes = (xmlVersion = "1.0", asciiOnly = false) => {
298417
+ if (asciiOnly) return regexesAscii;
298418
+ return xmlVersion === "1.1" ? regexes11 : regexes10;
298419
+ };
298420
+ var qName = (str, { xmlVersion = "1.0", asciiOnly = false } = {}) => getRegexes(xmlVersion, asciiOnly).qName.test(str);
298676
298421
 
298677
298422
  // node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js
298678
298423
  var DocTypeReader = class {
@@ -299834,17 +299579,16 @@ var Matcher = class {
299834
299579
  this.path[this.path.length - 1].values = void 0;
299835
299580
  }
299836
299581
  const currentLevel = this.path.length;
299837
- if (!this.siblingStacks[currentLevel]) {
299838
- this.siblingStacks[currentLevel] = /* @__PURE__ */ new Map();
299582
+ let level = this.siblingStacks[currentLevel];
299583
+ if (!level) {
299584
+ level = { counts: /* @__PURE__ */ new Map(), total: 0 };
299585
+ this.siblingStacks[currentLevel] = level;
299839
299586
  }
299840
- const siblings = this.siblingStacks[currentLevel];
299841
299587
  const siblingKey = namespace ? `${namespace}:${tagName}` : tagName;
299842
- const counter = siblings.get(siblingKey) || 0;
299843
- let position = 0;
299844
- for (const count of siblings.values()) {
299845
- position += count;
299846
- }
299847
- siblings.set(siblingKey, counter + 1);
299588
+ const counter = level.counts.get(siblingKey) || 0;
299589
+ const position = level.total;
299590
+ level.counts.set(siblingKey, counter + 1);
299591
+ level.total++;
299848
299592
  const node = {
299849
299593
  tag: tagName,
299850
299594
  position,
@@ -300153,7 +299897,7 @@ var Matcher = class {
300153
299897
  snapshot() {
300154
299898
  return {
300155
299899
  path: this.path.map((node) => ({ ...node })),
300156
- siblingStacks: this.siblingStacks.map((map) => new Map(map)),
299900
+ siblingStacks: this.siblingStacks.map((level) => level ? { counts: new Map(level.counts), total: level.total } : level),
300157
299901
  keptAttrs: this._keptAttrs.map((entry) => ({ ...entry }))
300158
299902
  };
300159
299903
  }
@@ -300164,7 +299908,7 @@ var Matcher = class {
300164
299908
  restore(snapshot) {
300165
299909
  this._pathStringCache = null;
300166
299910
  this.path = snapshot.path.map((node) => ({ ...node }));
300167
- this.siblingStacks = snapshot.siblingStacks.map((map) => new Map(map));
299911
+ this.siblingStacks = snapshot.siblingStacks.map((level) => level ? { counts: new Map(level.counts), total: level.total } : level);
300168
299912
  this._keptAttrs = (snapshot.keptAttrs || []).map((entry) => ({ ...entry }));
300169
299913
  }
300170
299914
  /**
@@ -300502,27 +300246,6 @@ var SQL_PATTERNS = [
300502
300246
  ];
300503
300247
  var sql_default = SQL_PATTERNS;
300504
300248
 
300505
- // node_modules/is-unsafe/src/contexts/sql-strict.js
300506
- var SQL_STRICT_EXTRA = [
300507
- {
300508
- id: "sql-line-comment",
300509
- description: "SQL line comment: -- followed by whitespace or end of string",
300510
- pattern: /--(?:\s|$)/
300511
- },
300512
- {
300513
- id: "sql-stacked-query",
300514
- description: "Stacked queries: semicolon immediately followed by a SQL keyword",
300515
- pattern: /;\s{0,10}(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC)\b/i
300516
- },
300517
- {
300518
- id: "sql-hex-encoding",
300519
- description: "Hex-encoded string injection: 0x41414141 style (MySQL)",
300520
- pattern: /\b0x[0-9a-f]{4,}/i
300521
- }
300522
- ];
300523
- var SQL_STRICT_PATTERNS = [...sql_default, ...SQL_STRICT_EXTRA];
300524
- var sql_strict_default = SQL_STRICT_PATTERNS;
300525
-
300526
300249
  // node_modules/is-unsafe/src/contexts/shell.js
300527
300250
  var SHELL_PATTERNS = [
300528
300251
  {
@@ -300834,8 +300557,38 @@ var LOG_PATTERNS = [
300834
300557
  ];
300835
300558
  var log_default = LOG_PATTERNS;
300836
300559
 
300837
- // node_modules/is-unsafe/src/registry.js
300838
- var CONTEXT_REGISTRY = {
300560
+ // node_modules/is-unsafe/src/contexts/sql-strict.js
300561
+ var SQL_STRICT_EXTRA = [
300562
+ {
300563
+ id: "sql-line-comment",
300564
+ description: "SQL line comment: -- followed by whitespace or end of string",
300565
+ pattern: /--(?:\s|$)/
300566
+ },
300567
+ {
300568
+ id: "sql-stacked-query",
300569
+ description: "Stacked queries: semicolon immediately followed by a SQL keyword",
300570
+ pattern: /;\s{0,10}(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC)\b/i
300571
+ },
300572
+ {
300573
+ id: "sql-hex-encoding",
300574
+ description: "Hex-encoded string injection: 0x41414141 style (MySQL)",
300575
+ pattern: /\b0x[0-9a-f]{4,}/i
300576
+ }
300577
+ ];
300578
+ var SQL_STRICT_PATTERNS = [...sql_default, ...SQL_STRICT_EXTRA];
300579
+ var sql_strict_default = SQL_STRICT_PATTERNS;
300580
+
300581
+ // node_modules/is-unsafe/src/index.js
300582
+ html_default.label = "HTML";
300583
+ xml_default.label = "XML";
300584
+ svg_default.label = "SVG";
300585
+ sql_default.label = "SQL";
300586
+ sql_strict_default.label = "SQL-STRICT";
300587
+ shell_default.label = "SHELL";
300588
+ redos_default.label = "REDOS";
300589
+ nosql_default.label = "NOSQL";
300590
+ log_default.label = "LOG";
300591
+ var VALID_CONTEXTS = Object.freeze({
300839
300592
  HTML: html_default,
300840
300593
  XML: xml_default,
300841
300594
  SVG: svg_default,
@@ -300845,13 +300598,7 @@ var CONTEXT_REGISTRY = {
300845
300598
  REDOS: redos_default,
300846
300599
  NOSQL: nosql_default,
300847
300600
  LOG: log_default
300848
- };
300849
- var registry_default = CONTEXT_REGISTRY;
300850
- var VALID_CONTEXTS = Object.freeze(
300851
- Object.fromEntries(Object.keys(CONTEXT_REGISTRY).map((k) => [k, k]))
300852
- );
300853
-
300854
- // node_modules/is-unsafe/src/index.js
300601
+ });
300855
300602
  function assertString(value) {
300856
300603
  if (typeof value !== "string") {
300857
300604
  throw new TypeError(
@@ -300861,36 +300608,35 @@ function assertString(value) {
300861
300608
  }
300862
300609
  function assertContext(context) {
300863
300610
  if (context instanceof RegExp) return;
300864
- if (typeof context === "string") {
300865
- if (!registry_default[context]) {
300866
- throw new TypeError(
300867
- `is-unsafe: unknown context "${context}". Valid contexts: ${Object.keys(VALID_CONTEXTS).join(", ")}`
300868
- );
300869
- }
300870
- return;
300871
- }
300872
300611
  if (Array.isArray(context)) {
300873
300612
  if (context.length === 0) {
300874
- throw new TypeError("is-unsafe: context array must not be empty");
300613
+ throw new TypeError("is-unsafe: context must not be an empty array");
300875
300614
  }
300876
- for (const c of context) {
300877
- if (typeof c !== "string" || !registry_default[c]) {
300878
- throw new TypeError(
300879
- `is-unsafe: unknown context "${c}" in array. Valid contexts: ${Object.keys(VALID_CONTEXTS).join(", ")}`
300880
- );
300615
+ if (Array.isArray(context[0])) {
300616
+ for (const list of context) {
300617
+ if (!Array.isArray(list) || list.length === 0) {
300618
+ throw new TypeError(
300619
+ "is-unsafe: each context in the array must be a non-empty pattern array (PatternList)"
300620
+ );
300621
+ }
300881
300622
  }
300882
300623
  }
300883
300624
  return;
300884
300625
  }
300885
300626
  throw new TypeError(
300886
- `is-unsafe: second argument must be a context string, array of context strings, or RegExp. Got: ${typeof context}`
300627
+ `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}`
300887
300628
  );
300888
300629
  }
300889
- function matchContext(value, contextName) {
300890
- const patterns = registry_default[contextName];
300891
- for (const rule of patterns) {
300630
+ function normalise(context) {
300631
+ if (context instanceof RegExp) return { lists: null, regex: context };
300632
+ if (Array.isArray(context[0])) return { lists: context, regex: null };
300633
+ return { lists: [context], regex: null };
300634
+ }
300635
+ function matchList(value, list) {
300636
+ const label = list.label ?? "CUSTOM";
300637
+ for (const rule of list) {
300892
300638
  if (rule.pattern.test(value)) {
300893
- return { context: contextName, id: rule.id, description: rule.description, pattern: rule.pattern };
300639
+ return { context: label, id: rule.id, description: rule.description, pattern: rule.pattern };
300894
300640
  }
300895
300641
  }
300896
300642
  return null;
@@ -300898,14 +300644,10 @@ function matchContext(value, contextName) {
300898
300644
  function isUnsafe(value, context) {
300899
300645
  assertString(value);
300900
300646
  assertContext(context);
300901
- if (context instanceof RegExp) {
300902
- return context.test(value);
300903
- }
300904
- if (typeof context === "string") {
300905
- return matchContext(value, context) !== null;
300906
- }
300907
- for (const c of context) {
300908
- if (matchContext(value, c) !== null) return true;
300647
+ const { lists, regex } = normalise(context);
300648
+ if (regex) return regex.test(value);
300649
+ for (const list of lists) {
300650
+ if (matchList(value, list) !== null) return true;
300909
300651
  }
300910
300652
  return false;
300911
300653
  }
@@ -300954,6 +300696,7 @@ var OrderedObjParser = class {
300954
300696
  this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes);
300955
300697
  this.entityExpansionCount = 0;
300956
300698
  this.currentExpandedLength = 0;
300699
+ this.doctypefound = false;
300957
300700
  let namedEntities = { ...XML };
300958
300701
  if (this.options.entityDecoder) {
300959
300702
  this.entityDecoder = this.options.entityDecoder;
@@ -300971,7 +300714,7 @@ var OrderedObjParser = class {
300971
300714
  // onExternalEntity: (name, value) => isUnsafe(value) ? 'block' : 'allow',
300972
300715
  onInputEntity: (name, value) => (
300973
300716
  //TODO: VALID_CONTEXTS.HTML should be set only if this.options.htmlEntities
300974
- isUnsafe(value, [VALID_CONTEXTS.HTML, VALID_CONTEXTS.XML]) ? ENTITY_ACTION.BLOCK : ENTITY_ACTION.ALLOW
300717
+ isUnsafe(value, [html_default, xml_default]) ? ENTITY_ACTION.BLOCK : ENTITY_ACTION.ALLOW
300975
300718
  )
300976
300719
  //postCheck: resolved => resolved
300977
300720
  });
@@ -301105,6 +300848,7 @@ var parseXml = function(xmlData) {
301105
300848
  this.entityDecoder.reset();
301106
300849
  this.entityExpansionCount = 0;
301107
300850
  this.currentExpandedLength = 0;
300851
+ this.doctypefound = false;
301108
300852
  const options = this.options;
301109
300853
  const docTypeReader = new DocTypeReader(options.processEntities);
301110
300854
  const xmlLen = xmlData.length;
@@ -301167,6 +300911,8 @@ var parseXml = function(xmlData) {
301167
300911
  }
301168
300912
  i = endIndex;
301169
300913
  } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 68) {
300914
+ if (this.doctypefound) throw new Error("Multiple DOCTYPE declarations found.");
300915
+ this.doctypefound = true;
301170
300916
  const result = docTypeReader.readDocType(xmlData, i);
301171
300917
  this.entityDecoder.addInputEntities(result.entities);
301172
300918
  i = result.i;
@@ -303758,7 +303504,7 @@ function parseWsdl(content, opts) {
303758
303504
  }
303759
303505
 
303760
303506
  // src/lib/protocols/soap/builder.ts
303761
- var import_node_crypto4 = require("node:crypto");
303507
+ var import_node_crypto5 = require("node:crypto");
303762
303508
  var COLLECTION_V210_SCHEMA2 = "https://schema.getpostman.com/json/collection/v2.1.0/collection.json";
303763
303509
  var SOAP11_ENVELOPE_NS = "http://schemas.xmlsoap.org/soap/envelope/";
303764
303510
  var SOAP12_ENVELOPE_NS = "http://www.w3.org/2003/05/soap-envelope";
@@ -303766,7 +303512,7 @@ var SOAP11_CONTENT_TYPE = "text/xml; charset=UTF-8";
303766
303512
  var SOAP12_CONTENT_TYPE = "application/soap+xml; charset=UTF-8";
303767
303513
  var WSA_NS = "http://www.w3.org/2005/08/addressing";
303768
303514
  function stableId2(seed) {
303769
- return (0, import_node_crypto4.createHash)("sha256").update(seed).digest("hex").slice(0, 32);
303515
+ return (0, import_node_crypto5.createHash)("sha256").update(seed).digest("hex").slice(0, 32);
303770
303516
  }
303771
303517
  function envelopeNamespace(version) {
303772
303518
  return version === "1.2" ? SOAP12_ENVELOPE_NS : SOAP11_ENVELOPE_NS;
@@ -310523,6 +310269,11 @@ function resolveInputs(env = process.env) {
310523
310269
  ),
310524
310270
  protocolEndpointUrl: getInput("protocol-endpoint-url", env),
310525
310271
  openapiVersion: resolveOpenapiVersion(getInput("openapi-version", env)),
310272
+ preserveOas30TypeNull: parseBooleanInput(
310273
+ "preserve-oas30-type-null",
310274
+ getInput("preserve-oas30-type-null", env),
310275
+ false
310276
+ ),
310526
310277
  breakingChangeMode: parseBreakingChangeMode(getInput("breaking-change-mode", env)),
310527
310278
  breakingBaselineSpecPath: getInput("breaking-baseline-spec-path", env),
310528
310279
  breakingRulesPath: getInput("breaking-rules-path", env) ?? bootstrapActionContract.inputs["breaking-rules-path"].default,
@@ -310530,8 +310281,8 @@ function resolveInputs(env = process.env) {
310530
310281
  breakingSummaryPath: getInput("breaking-summary-path", env),
310531
310282
  breakingLogPath: getInput("breaking-log-path", env),
310532
310283
  governanceMappingJson: parseGovernanceMappingJson(getInput("governance-mapping-json", env)),
310533
- postmanApiKey: getInput("postman-api-key", env) ?? "",
310534
- postmanAccessToken: getInput("postman-access-token", env),
310284
+ postmanApiKey: getInput("postman-api-key", env) || env.POSTMAN_API_KEY || "",
310285
+ postmanAccessToken: getInput("postman-access-token", env) || env.POSTMAN_ACCESS_TOKEN,
310535
310286
  credentialPreflight: parseEnumInput(
310536
310287
  "credential-preflight",
310537
310288
  getInput("credential-preflight", env),
@@ -310553,9 +310304,72 @@ function resolveInputs(env = process.env) {
310553
310304
  githubRef: env.GITHUB_REF,
310554
310305
  githubSha: env.GITHUB_SHA,
310555
310306
  githubToken: getInput("github-token", env) || env.GITHUB_TOKEN || "",
310556
- ghFallbackToken: getInput("gh-fallback-token", env) || env.GH_FALLBACK_TOKEN || ""
310307
+ ghFallbackToken: getInput("gh-fallback-token", env) || env.GH_FALLBACK_TOKEN || "",
310308
+ branchStrategy: parseEnumInput(
310309
+ "branch-strategy",
310310
+ getInput("branch-strategy", env),
310311
+ "legacy"
310312
+ ),
310313
+ canonicalBranch: getInput("canonical-branch", env),
310314
+ channels: getInput("channels", env)
310557
310315
  };
310558
310316
  }
310317
+ function decideBranchTier(inputs, env = process.env) {
310318
+ return resolveEffectiveBranchDecision(
310319
+ {
310320
+ // Tolerate hand-built inputs objects (tests, embedders) that omit the
310321
+ // field: absent means legacy, exactly like the action default.
310322
+ strategy: inputs.branchStrategy ?? "legacy",
310323
+ identity: resolveBranchIdentity(env, { defaultBranch: inputs.canonicalBranch }),
310324
+ canonicalBranch: inputs.canonicalBranch,
310325
+ channels: parseChannelRules(inputs.channels)
310326
+ },
310327
+ env
310328
+ );
310329
+ }
310330
+ function embedSpecBranchMarker(content, decision, repo) {
310331
+ if (decision.tier !== "preview" && decision.tier !== "channel" || !decision.identity.headBranch || !repo) {
310332
+ return content;
310333
+ }
310334
+ const rawBranch = decision.identity.headBranch;
310335
+ const now = (/* @__PURE__ */ new Date()).toISOString();
310336
+ const marker = {
310337
+ repo,
310338
+ rawBranch,
310339
+ sanitizedBranch: rawBranch.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/-+/g, "-").slice(0, 30),
310340
+ role: decision.tier,
310341
+ headSha: decision.identity.headSha,
310342
+ createdAt: now,
310343
+ lastSyncedAt: now
310344
+ };
310345
+ try {
310346
+ if (content.trim().startsWith("{")) {
310347
+ return `${JSON.stringify({ ...JSON.parse(content), "x-postman-onboarding": marker }, null, 2)}
310348
+ `;
310349
+ }
310350
+ const document2 = (0, import_yaml4.parse)(content);
310351
+ if (!document2 || typeof document2 !== "object" || Array.isArray(document2)) return content;
310352
+ return (0, import_yaml4.stringify)({ ...document2, "x-postman-onboarding": marker });
310353
+ } catch {
310354
+ return content;
310355
+ }
310356
+ }
310357
+ function renderCollectionBranchMarker(decision, repo, now = /* @__PURE__ */ new Date()) {
310358
+ if (decision.tier !== "preview" && decision.tier !== "channel" || !decision.identity.headBranch || !repo) {
310359
+ return void 0;
310360
+ }
310361
+ const rawBranch = decision.identity.headBranch;
310362
+ const timestamp = now.toISOString();
310363
+ return renderAssetMarker({
310364
+ repo,
310365
+ rawBranch,
310366
+ sanitizedBranch: rawBranch.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/-+/g, "-").slice(0, 30),
310367
+ role: decision.tier,
310368
+ headSha: decision.identity.headSha,
310369
+ createdAt: timestamp,
310370
+ lastSyncedAt: timestamp
310371
+ });
310372
+ }
310559
310373
  function createPlannedOutputs(inputs) {
310560
310374
  const workspaceName = inputs.domainCode ? `[${inputs.domainCode}] ${inputs.projectName}` : inputs.projectName;
310561
310375
  return {
@@ -310587,7 +310401,12 @@ function createPlannedOutputs(inputs) {
310587
310401
  mode: inputs.breakingChangeMode,
310588
310402
  status: "skipped",
310589
310403
  summaryPath: ""
310590
- })
310404
+ }),
310405
+ "sync-status": "",
310406
+ "branch-decision": "",
310407
+ "spec-version-tag": "",
310408
+ "spec-version-url": "",
310409
+ "spec-content-changed": ""
310591
310410
  };
310592
310411
  }
310593
310412
  async function mintAccessTokenIfNeeded2(inputs, log, setSecret2) {
@@ -310692,6 +310511,27 @@ async function lintSpecViaCli(dependencies, workspaceId, specId) {
310692
310511
  warnings
310693
310512
  };
310694
310513
  }
310514
+ function normalizeLintPath(value) {
310515
+ return value.trim().replace(/^\$\.?/, "").replace(/\[(\d+)\]/g, ".$1").replace(/^\./, "");
310516
+ }
310517
+ function applyOas30TypeNullLintCompatibility(summary2, sourceTypeNullPaths) {
310518
+ const acceptedPaths = new Set(sourceTypeNullPaths.map(normalizeLintPath));
310519
+ if (acceptedPaths.size === 0) return summary2;
310520
+ const violations = summary2.violations.map((violation) => {
310521
+ const path8 = normalizeLintPath(violation.path ?? "");
310522
+ const issue2 = violation.issue ?? "";
310523
+ const isTypeEnumFinding = /["']?type["']? property/i.test(issue2) && /allowed values|must be equal to one of/i.test(issue2);
310524
+ if (violation.severity === "ERROR" && acceptedPaths.has(path8) && isTypeEnumFinding) {
310525
+ return { ...violation, severity: "WARNING" };
310526
+ }
310527
+ return violation;
310528
+ });
310529
+ return {
310530
+ errors: violations.filter((entry) => entry.severity === "ERROR").length,
310531
+ violations,
310532
+ warnings: violations.filter((entry) => entry.severity === "WARNING").length
310533
+ };
310534
+ }
310695
310535
  function shouldRetrySpecFetch(error) {
310696
310536
  const retryability = classifySafeFetchRetryability(error);
310697
310537
  return retryability === "retryable" || retryability === "unknown";
@@ -311172,7 +311012,7 @@ async function runProtocolBootstrap(specType, rawSpecContent, inputs, dependenci
311172
311012
  const workspaceRoot = path6.resolve(process.env.GITHUB_WORKSPACE ?? process.cwd());
311173
311013
  const serviceConfigPath = path6.join(path6.dirname(path6.resolve(workspaceRoot, inputs.specPath)), "grpc_service_config.json");
311174
311014
  try {
311175
- grpcServiceConfigJson = (0, import_node_fs5.readFileSync)(serviceConfigPath, "utf8");
311015
+ grpcServiceConfigJson = (0, import_node_fs6.readFileSync)(serviceConfigPath, "utf8");
311176
311016
  dependencies.core.info(`Found gRPC service config at ${serviceConfigPath}; validating it against the proto contract`);
311177
311017
  } catch {
311178
311018
  }
@@ -311186,7 +311026,7 @@ async function runProtocolBootstrap(specType, rawSpecContent, inputs, dependenci
311186
311026
  const resolved = path6.resolve(specDir, location2);
311187
311027
  if (!resolved.startsWith(specDir + path6.sep)) return void 0;
311188
311028
  try {
311189
- return (0, import_node_fs5.readFileSync)(resolved, "utf8");
311029
+ return (0, import_node_fs6.readFileSync)(resolved, "utf8");
311190
311030
  } catch {
311191
311031
  return void 0;
311192
311032
  }
@@ -311327,6 +311167,42 @@ async function createExtensibleContractCollection(workspaceId, built, inputs, de
311327
311167
  }
311328
311168
  async function runBootstrapInner(inputs, dependencies, telemetry) {
311329
311169
  const outputs = createPlannedOutputs(inputs);
311170
+ const branchDecision = decideBranchTier(inputs);
311171
+ const isCanonicalWriter = branchDecision.tier === "legacy" || branchDecision.tier === "canonical";
311172
+ const canonicalProjectName = inputs.projectName;
311173
+ const workspaceName = createWorkspaceName(inputs);
311174
+ const aboutText = `Auto-provisioned by Postman for ${inputs.projectName}`;
311175
+ if (branchDecision.tier === "preview" && branchDecision.identity.headBranch) {
311176
+ inputs = {
311177
+ ...inputs,
311178
+ projectName: previewAssetName(inputs.projectName, branchDecision.identity.headBranch)
311179
+ };
311180
+ dependencies.core.info(`branch-aware sync: preview asset set "${inputs.projectName}"`);
311181
+ } else if (branchDecision.tier === "channel" && branchDecision.channel) {
311182
+ inputs = {
311183
+ ...inputs,
311184
+ projectName: channelAssetName(inputs.projectName, branchDecision.channel.code)
311185
+ };
311186
+ dependencies.core.info(`branch-aware sync: channel asset set "${inputs.projectName}"`);
311187
+ }
311188
+ const collectionBranchMarker = renderCollectionBranchMarker(branchDecision, inputs.repoUrl);
311189
+ if (branchDecision.tier !== "legacy") {
311190
+ outputs["sync-status"] = "synced";
311191
+ outputs["branch-decision"] = serializeBranchDecision(branchDecision);
311192
+ }
311193
+ if (!isCanonicalWriter) {
311194
+ const explicitCanonicalIds = [
311195
+ ["spec-id", inputs.specId],
311196
+ ["baseline-collection-id", inputs.baselineCollectionId],
311197
+ ["smoke-collection-id", inputs.smokeCollectionId],
311198
+ ["contract-collection-id", inputs.contractCollectionId]
311199
+ ].filter(([, value]) => Boolean(value));
311200
+ if (explicitCanonicalIds.length > 0) {
311201
+ throw new Error(
311202
+ `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).`
311203
+ );
311204
+ }
311205
+ }
311330
311206
  const requiresReleaseLabel = inputs.collectionSyncMode === "version" || inputs.specSyncMode === "version";
311331
311207
  const releaseLabel = requiresReleaseLabel ? deriveReleaseLabel(inputs) : void 0;
311332
311208
  if (requiresReleaseLabel && !releaseLabel) {
@@ -311334,11 +311210,23 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311334
311210
  "Versioned spec or collection sync requires a release-label or derivable GitHub ref metadata"
311335
311211
  );
311336
311212
  }
311337
- const collectionAssetProjectName = inputs.collectionSyncMode === "version" ? createAssetProjectName(inputs, releaseLabel) : inputs.projectName;
311338
- const workspaceName = createWorkspaceName(inputs);
311339
- const aboutText = `Auto-provisioned by Postman for ${inputs.projectName}`;
311340
- const stateStore = resolveResourcesStateStore(dependencies);
311341
- const resourcesState = stateStore.read();
311213
+ const collectionAssetProjectName = branchDecision.tier === "channel" ? canonicalProjectName : inputs.collectionSyncMode === "version" ? createAssetProjectName(inputs, releaseLabel) : inputs.projectName;
311214
+ const rawStateStore = resolveResourcesStateStore(dependencies);
311215
+ const trackedState = rawStateStore.read();
311216
+ const stateStore = isCanonicalWriter ? rawStateStore : {
311217
+ read: rawStateStore.read,
311218
+ write: () => {
311219
+ dependencies.core.info(
311220
+ `branch-aware sync: skipping .postman/resources.yaml write on ${branchDecision.tier} run (canonical-only tracked state)`
311221
+ );
311222
+ }
311223
+ };
311224
+ const resourcesState = isCanonicalWriter ? trackedState : trackedState?.workspace ? { workspace: trackedState.workspace } : null;
311225
+ if (!isCanonicalWriter && trackedState?.cloudResources) {
311226
+ dependencies.core.info(
311227
+ "branch-aware sync: canonical asset ids in .postman/resources.yaml are not resolved on a non-canonical run"
311228
+ );
311229
+ }
311342
311230
  const writableResourcesState = resourcesState ?? {};
311343
311231
  const additionalCollections = loadAdditionalCollectionFiles(
311344
311232
  inputs.additionalCollectionsDir,
@@ -311358,16 +311246,19 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311358
311246
  }
311359
311247
  let previousSpecContent;
311360
311248
  let previousSpecRollbackHash;
311249
+ let specContentUnchanged = false;
311361
311250
  let detectedOpenapiVersion = "3.0";
311362
311251
  let contractIndex;
311363
311252
  let sourceSpecContent = "";
311253
+ let sourceTypeNullPaths = [];
311254
+ let preserveSourceSpecBytes = false;
311364
311255
  const rawSpecContent = await runGroup(
311365
311256
  dependencies.core,
311366
311257
  "Read API Spec",
311367
311258
  async () => {
311368
311259
  if (inputs.specPath) {
311369
311260
  const workspaceRoot = path6.resolve(process.env.GITHUB_WORKSPACE ?? process.cwd());
311370
- return (0, import_node_fs5.readFileSync)(path6.resolve(workspaceRoot, inputs.specPath), "utf8");
311261
+ return (0, import_node_fs6.readFileSync)(path6.resolve(workspaceRoot, inputs.specPath), "utf8");
311371
311262
  }
311372
311263
  if (dependencies.specFetcher === fetch) {
311373
311264
  return safeFetchText(inputs.specUrl, { depth: 0 });
@@ -311403,6 +311294,7 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311403
311294
  };
311404
311295
  const rootKey = inputs.specPath ? void 0 : normalizeRef(inputs.specUrl);
311405
311296
  const loaderOptions = {
311297
+ preserveOas30TypeNull: Boolean(inputs.preserveOas30TypeNull),
311406
311298
  fetchText: async (url, fetchOptions) => {
311407
311299
  if (rootKey && normalizeRef(url) === rootKey) return rawSpecContent;
311408
311300
  if (dependencies.specFetcher === fetch) return safeFetchText(url, fetchOptions);
@@ -311411,6 +311303,8 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311411
311303
  };
311412
311304
  const loaded = inputs.specPath ? await loadOpenApiContractSpecFromPath(inputs.specPath, loaderOptions) : await loadOpenApiContractSpec(inputs.specUrl, loaderOptions);
311413
311305
  sourceSpecContent = loaded.content;
311306
+ sourceTypeNullPaths = loaded.sourceTypeNullPaths;
311307
+ preserveSourceSpecBytes = sourceTypeNullPaths.length > 0;
311414
311308
  const document2 = normalizeSpecDocument(
311415
311309
  loaded.bundledContent,
311416
311310
  (msg) => dependencies.core.warning(msg)
@@ -311433,11 +311327,11 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311433
311327
  `Unable to verify existing Spec Hub OpenAPI version for spec-id ${specId}; clear spec-id to create a fresh spec`
311434
311328
  );
311435
311329
  }
311436
- previousSpecContent = normalizeSpecDocument(
311330
+ previousSpecContent = preserveSourceSpecBytes ? previousRaw : normalizeSpecDocument(
311437
311331
  previousRaw,
311438
311332
  (msg) => dependencies.core.warning(`Previous spec normalization: ${msg}`)
311439
311333
  );
311440
- previousSpecRollbackHash = (0, import_node_crypto5.createHash)("sha256").update(previousSpecContent).digest("hex");
311334
+ previousSpecRollbackHash = (0, import_node_crypto6.createHash)("sha256").update(previousSpecContent).digest("hex");
311441
311335
  const existingSpecType = normalizeSpecTypeFromContent(previousSpecContent);
311442
311336
  if (existingSpecType !== incomingSpecType) {
311443
311337
  throw new Error(
@@ -311448,6 +311342,12 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311448
311342
  dependencies.core.info(
311449
311343
  `Auto-detected OpenAPI version from spec content: ${detectedOpenapiVersion}`
311450
311344
  );
311345
+ if (preserveSourceSpecBytes) {
311346
+ dependencies.core.info(
311347
+ `Preserving original OpenAPI source bytes; accepted ${sourceTypeNullPaths.length} legacy type: null member(s) for internal validation`
311348
+ );
311349
+ return loaded.content;
311350
+ }
311451
311351
  return document2;
311452
311352
  }
311453
311353
  );
@@ -311483,6 +311383,11 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311483
311383
  `OpenAPI breaking-change check failed: ${breakingChangeResult.message || "breaking changes detected"}`
311484
311384
  );
311485
311385
  }
311386
+ const uploadSpecContent = embedSpecBranchMarker(
311387
+ specContent,
311388
+ branchDecision,
311389
+ inputs.repoUrl
311390
+ );
311486
311391
  const provisioned = await provisionWorkspace(
311487
311392
  inputs,
311488
311393
  dependencies,
@@ -311607,10 +311512,17 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311607
311512
  specId ? "Update Spec in Spec Hub" : "Upload Spec to Spec Hub",
311608
311513
  async () => {
311609
311514
  if (specId) {
311610
- dependencies.core.info(
311611
- `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.`
311612
- );
311613
- await dependencies.postman.updateSpec(specId, specContent, workspaceId);
311515
+ if (previousSpecContent !== void 0 && (0, import_node_crypto6.createHash)("sha256").update(uploadSpecContent).digest("hex") === (0, import_node_crypto6.createHash)("sha256").update(previousSpecContent).digest("hex")) {
311516
+ specContentUnchanged = true;
311517
+ dependencies.core.info(
311518
+ `Spec content unchanged (sha256 match); skipping Spec Hub update and version tag for ${specId}.`
311519
+ );
311520
+ } else {
311521
+ dependencies.core.info(
311522
+ `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.`
311523
+ );
311524
+ await dependencies.postman.updateSpec(specId, uploadSpecContent, workspaceId);
311525
+ }
311614
311526
  } else {
311615
311527
  specId = await dependencies.postman.uploadSpec(
311616
311528
  workspaceId || "",
@@ -311618,7 +311530,7 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311618
311530
  inputs,
311619
311531
  inputs.specSyncMode === "version" ? releaseLabel : void 0
311620
311532
  ),
311621
- specContent,
311533
+ uploadSpecContent,
311622
311534
  detectedOpenapiVersion
311623
311535
  );
311624
311536
  }
@@ -311635,8 +311547,9 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311635
311547
  }
311636
311548
  )
311637
311549
  );
311550
+ outputs["spec-content-changed"] = isCanonicalWriter && !specContentUnchanged ? "true" : "false";
311638
311551
  if (lintEnabled) {
311639
- const lintSummary = await runRollbackStage(
311552
+ let lintSummary = await runRollbackStage(
311640
311553
  "Lint Spec via Postman CLI",
311641
311554
  async () => runGroup(
311642
311555
  dependencies.core,
@@ -311644,6 +311557,16 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311644
311557
  async () => lintSpecViaCli(dependencies, workspaceId || "", outputs["spec-id"])
311645
311558
  )
311646
311559
  );
311560
+ if (preserveSourceSpecBytes) {
311561
+ const originalErrorCount = lintSummary.errors;
311562
+ lintSummary = applyOas30TypeNullLintCompatibility(lintSummary, sourceTypeNullPaths);
311563
+ const acceptedCount = originalErrorCount - lintSummary.errors;
311564
+ if (acceptedCount > 0) {
311565
+ dependencies.core.info(
311566
+ `Accepted ${acceptedCount} Postman CLI type: null finding(s) covered by preserve-oas30-type-null`
311567
+ );
311568
+ }
311569
+ }
311647
311570
  outputs["lint-summary-json"] = JSON.stringify({
311648
311571
  errors: lintSummary.errors,
311649
311572
  total: lintSummary.violations.length,
@@ -311668,7 +311591,12 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311668
311591
  });
311669
311592
  dependencies.core.warning("lint skipped: governance errors not enforced (no postman-api-key)");
311670
311593
  }
311671
- await runRollbackStage(
311594
+ if (specContentUnchanged) {
311595
+ outputs["baseline-collection-id"] = baselineCollectionId || "";
311596
+ outputs["smoke-collection-id"] = smokeCollectionId || "";
311597
+ outputs["contract-collection-id"] = contractCollectionId || "";
311598
+ dependencies.core.info("Spec content unchanged; skipping collection regeneration and version finalization.");
311599
+ } else await runRollbackStage(
311672
311600
  "Generate Collections from Spec",
311673
311601
  async () => runGroup(
311674
311602
  dependencies.core,
@@ -311707,10 +311635,11 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311707
311635
  return;
311708
311636
  }
311709
311637
  }
311638
+ const effectivePrefix = branchDecision.tier === "channel" && branchDecision.channel ? channelAssetName(prefix, branchDecision.channel.code).trim() : prefix;
311710
311639
  outputs[outputKey] = await dependencies.postman.generateCollection(
311711
311640
  specId2,
311712
311641
  assetProjectName,
311713
- prefix,
311642
+ effectivePrefix,
311714
311643
  inputs.folderStrategy,
311715
311644
  inputs.nestedFolderHierarchy,
311716
311645
  inputs.requestNameSource
@@ -311731,6 +311660,32 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311731
311660
  await ensureCollection(BASELINE_COLLECTION_PREFIX, baselineCollectionId, "baseline-collection-id");
311732
311661
  await ensureCollection(SMOKE_COLLECTION_PREFIX, smokeCollectionId, "smoke-collection-id");
311733
311662
  await ensureCollection(CONTRACT_COLLECTION_PREFIX, contractCollectionId, "contract-collection-id");
311663
+ if (dependencies.postman.adoptGeneratedCollection) {
311664
+ const reelect = async (prefix, outputKey) => {
311665
+ const effectivePrefix = branchDecision.tier === "channel" && branchDecision.channel ? channelAssetName(prefix, branchDecision.channel.code).trim() : prefix;
311666
+ const preferred = outputs[outputKey];
311667
+ if (!preferred) return;
311668
+ outputs[outputKey] = await dependencies.postman.adoptGeneratedCollection(
311669
+ specId2,
311670
+ assetProjectName,
311671
+ effectivePrefix,
311672
+ preferred
311673
+ );
311674
+ };
311675
+ await reelect(BASELINE_COLLECTION_PREFIX, "baseline-collection-id");
311676
+ await reelect(SMOKE_COLLECTION_PREFIX, "smoke-collection-id");
311677
+ await reelect(CONTRACT_COLLECTION_PREFIX, "contract-collection-id");
311678
+ }
311679
+ if (collectionBranchMarker) {
311680
+ if (!dependencies.postman.updateCollectionDescription) {
311681
+ throw new Error("Branch-scoped collections require updateCollectionDescription support");
311682
+ }
311683
+ await Promise.all([
311684
+ outputs["baseline-collection-id"],
311685
+ outputs["smoke-collection-id"],
311686
+ outputs["contract-collection-id"]
311687
+ ].filter(Boolean).map((id) => dependencies.postman.updateCollectionDescription(id, collectionBranchMarker)));
311688
+ }
311734
311689
  if (!dependencies.postman.injectContractTests) {
311735
311690
  throw new Error(
311736
311691
  "Dynamic contract tests require injectContractTests support from the access-token gateway client"
@@ -311833,6 +311788,12 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311833
311788
  workspaceId: workspaceId || ""
311834
311789
  });
311835
311790
  for (const result of additionalResults) {
311791
+ if (collectionBranchMarker) {
311792
+ if (!dependencies.postman.updateCollectionDescription) {
311793
+ throw new Error("Branch-scoped collections require updateCollectionDescription support");
311794
+ }
311795
+ await dependencies.postman.updateCollectionDescription(result.collectionId, collectionBranchMarker);
311796
+ }
311836
311797
  completedExternalSideEffects.push(
311837
311798
  `${result.operation}AdditionalCollection(${result.collectionId} from ${result.displayPath})`
311838
311799
  );
@@ -311908,6 +311869,53 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
311908
311869
  }
311909
311870
  return outputs;
311910
311871
  }
311872
+ async function runGatedValidation(inputs, decision, actionCore) {
311873
+ actionCore.info(`branch-aware sync: gated run (${decision.reason}) \u2014 credential-free static validation, zero workspace writes`);
311874
+ const outputs = createPlannedOutputs(inputs);
311875
+ outputs["sync-status"] = "skipped-branch-gate";
311876
+ outputs["branch-decision"] = serializeBranchDecision(decision);
311877
+ let violations = [];
311878
+ let validated = false;
311879
+ try {
311880
+ let content;
311881
+ if (inputs.specPath) {
311882
+ content = (0, import_node_fs6.readFileSync)(inputs.specPath, "utf8");
311883
+ } else if (inputs.specUrl) {
311884
+ content = await safeFetchText(inputs.specUrl, { depth: 0 });
311885
+ }
311886
+ if (content) {
311887
+ const specType = detectSpecType(content, inputs.specPath);
311888
+ if (specType === "openapi") {
311889
+ const document2 = parseOpenApiDocument(content);
311890
+ const index = buildContractIndex(document2);
311891
+ violations = index.warnings;
311892
+ validated = true;
311893
+ } else {
311894
+ actionCore.info(`branch gate: static lint for spec type ${specType} runs through its protocol builder on publish; parse-only gate applied`);
311895
+ validated = true;
311896
+ }
311897
+ } else {
311898
+ actionCore.info("branch gate: no spec-url/spec-path provided; nothing to validate");
311899
+ }
311900
+ } catch (error) {
311901
+ throw new Error(
311902
+ `branch gate: static validation failed: ${error instanceof Error ? error.message : String(error)}`,
311903
+ { cause: error }
311904
+ );
311905
+ }
311906
+ outputs["lint-summary-json"] = JSON.stringify({
311907
+ status: validated ? "static-only" : "skipped",
311908
+ reason: "branch-gated run: governance lint requires upload and runs on publish/preview syncs",
311909
+ errors: 0,
311910
+ warnings: violations.length,
311911
+ total: violations.length,
311912
+ violations: violations.map((issue2) => ({ issue: issue2, severity: "WARNING" }))
311913
+ });
311914
+ for (const [name, value] of Object.entries(outputs)) {
311915
+ actionCore.setOutput(name, value);
311916
+ }
311917
+ return outputs;
311918
+ }
311911
311919
  function createRoutingPostmanClient(options) {
311912
311920
  const { gateway } = options;
311913
311921
  const requireAccessToken = (operation) => async () => {
@@ -311925,6 +311933,7 @@ function createRoutingPostmanClient(options) {
311925
311933
  updateSpec: requireAccessToken("updateSpec"),
311926
311934
  getSpecContent: requireAccessToken("getSpecContent"),
311927
311935
  generateCollection: requireAccessToken("generateCollection"),
311936
+ adoptGeneratedCollection: requireAccessToken("adoptGeneratedCollection"),
311928
311937
  createWorkspace: requireAccessToken("createWorkspace"),
311929
311938
  getWorkspaceVisibility: requireAccessToken("getWorkspaceVisibility"),
311930
311939
  getWorkspaceGitRepoUrl: requireAccessToken("getWorkspaceGitRepoUrl"),
@@ -311934,10 +311943,13 @@ function createRoutingPostmanClient(options) {
311934
311943
  inviteRequesterToWorkspace: requireAccessToken("inviteRequesterToWorkspace"),
311935
311944
  injectTests: requireAccessToken("injectTests"),
311936
311945
  tagCollection: requireAccessToken("tagCollection"),
311946
+ tagSpecVersion: requireAccessToken("tagSpecVersion"),
311947
+ listSpecVersionTags: requireAccessToken("listSpecVersionTags"),
311937
311948
  deleteCollection: requireAccessToken("deleteCollection"),
311938
311949
  injectContractTests: requireAccessToken("injectContractTests"),
311939
311950
  createCollection: requireAccessToken("createCollection"),
311940
- updateCollection: requireAccessToken("updateCollection")
311951
+ updateCollection: requireAccessToken("updateCollection"),
311952
+ updateCollectionDescription: requireAccessToken("updateCollectionDescription")
311941
311953
  };
311942
311954
  }
311943
311955
  return {
@@ -311949,6 +311961,7 @@ function createRoutingPostmanClient(options) {
311949
311961
  // not a reason to reach for the API key.
311950
311962
  uploadSpec: (workspaceId, projectName, specContent, openapiVersion) => gateway.uploadSpec(workspaceId, projectName, specContent, openapiVersion ?? "3.0"),
311951
311963
  generateCollection: (specId, projectName, prefix, folderStrategy, nestedFolderHierarchy, requestNameSource) => gateway.generateCollection(specId, projectName, prefix, folderStrategy, nestedFolderHierarchy, requestNameSource),
311964
+ adoptGeneratedCollection: (specId, projectName, prefix, preferredId) => gateway.adoptGeneratedCollection(specId, projectName, prefix, preferredId),
311952
311965
  updateSpec: (specId, specContent, workspaceId) => gateway.updateSpec(specId, specContent, workspaceId),
311953
311966
  getSpecContent: (specId) => gateway.getSpecContent(specId),
311954
311967
  createWorkspace: (name, about, targetTeamId) => gateway.createWorkspace(name, about, targetTeamId),
@@ -311960,6 +311973,8 @@ function createRoutingPostmanClient(options) {
311960
311973
  // + tagging surfaces (live-proven). PMAK is reserved for token minting, so
311961
311974
  // these never fall back to the API key even when one is present.
311962
311975
  injectTests: (collectionId, type) => gateway.injectTests(collectionId, type),
311976
+ tagSpecVersion: (specId, name) => gateway.tagSpecVersion(specId, name),
311977
+ listSpecVersionTags: (specId) => gateway.listSpecVersionTags(specId),
311963
311978
  tagCollection: (collectionId, tags) => gateway.tagCollection(collectionId, tags),
311964
311979
  // Sub-team (squad) enumeration over the gateway `ums` service. Access-token
311965
311980
  // only — never PMAK — so org-mode detection no longer needs a PMAK GET /teams.
@@ -311977,7 +311992,8 @@ function createRoutingPostmanClient(options) {
311977
311992
  // so no asset op ever reaches for the API key.
311978
311993
  injectContractTests: (collectionUid, index) => gateway.injectContractTests(collectionUid, index),
311979
311994
  createCollection: (workspaceId, collection, options2) => gateway.createCollection(workspaceId, collection, options2),
311980
- updateCollection: (collectionUid, collection) => gateway.updateCollection(collectionUid, collection)
311995
+ updateCollection: (collectionUid, collection) => gateway.updateCollection(collectionUid, collection),
311996
+ updateCollectionDescription: (collectionUid, description) => gateway.updateCollectionDescription(collectionUid, description)
311981
311997
  };
311982
311998
  }
311983
311999
  function createBootstrapDependencies(inputs, factories, orgMode = false) {
@@ -312073,6 +312089,9 @@ function wantsVersion(argv) {
312073
312089
  return argv.includes("--version") || argv.includes("-V");
312074
312090
  }
312075
312091
  function resolvePackageVersion() {
312092
+ if (false) {
312093
+ return void 0;
312094
+ }
312076
312095
  const candidates = [];
312077
312096
  if (typeof __filename === "string" && __filename) {
312078
312097
  candidates.push(import_node_path5.default.join(import_node_path5.default.dirname(__filename), "..", "package.json"));
@@ -312080,7 +312099,7 @@ function resolvePackageVersion() {
312080
312099
  candidates.push(import_node_path5.default.join(process.cwd(), "package.json"));
312081
312100
  for (const packageJsonPath of candidates) {
312082
312101
  try {
312083
- const packageJson = JSON.parse((0, import_node_fs6.readFileSync)(packageJsonPath, "utf8"));
312102
+ const packageJson = JSON.parse((0, import_node_fs7.readFileSync)(packageJsonPath, "utf8"));
312084
312103
  if (packageJson.name === "@postman-cse/onboarding-bootstrap" && packageJson.version) {
312085
312104
  return String(packageJson.version).trim();
312086
312105
  }
@@ -312131,6 +312150,9 @@ var cliInputNames = [
312131
312150
  "postman-api-key",
312132
312151
  "postman-access-token",
312133
312152
  "credential-preflight",
312153
+ "branch-strategy",
312154
+ "canonical-branch",
312155
+ "channels",
312134
312156
  "workspace-id",
312135
312157
  "spec-id",
312136
312158
  "baseline-collection-id",
@@ -312156,6 +312178,7 @@ var cliInputNames = [
312156
312178
  "workspace-team-id",
312157
312179
  "repo-url",
312158
312180
  "openapi-version",
312181
+ "preserve-oas30-type-null",
312159
312182
  "breaking-change-mode",
312160
312183
  "breaking-baseline-spec-path",
312161
312184
  "breaking-rules-path",
@@ -312292,11 +312315,11 @@ function nearestExistingPath2(candidate) {
312292
312315
  return current;
312293
312316
  }
312294
312317
  function pathExists(candidate) {
312295
- if ((0, import_node_fs6.existsSync)(candidate)) {
312318
+ if ((0, import_node_fs7.existsSync)(candidate)) {
312296
312319
  return true;
312297
312320
  }
312298
312321
  try {
312299
- (0, import_node_fs6.lstatSync)(candidate);
312322
+ (0, import_node_fs7.lstatSync)(candidate);
312300
312323
  return true;
312301
312324
  } catch {
312302
312325
  return false;
@@ -312304,10 +312327,10 @@ function pathExists(candidate) {
312304
312327
  }
312305
312328
  function checkedRealPath(existingPath, workspaceRealPath) {
312306
312329
  try {
312307
- return (0, import_node_fs6.realpathSync)(existingPath);
312330
+ return (0, import_node_fs7.realpathSync)(existingPath);
312308
312331
  } catch (error) {
312309
- if ((0, import_node_fs6.lstatSync)(existingPath).isSymbolicLink()) {
312310
- const linkTarget = (0, import_node_fs6.readlinkSync)(existingPath);
312332
+ if ((0, import_node_fs7.lstatSync)(existingPath).isSymbolicLink()) {
312333
+ const linkTarget = (0, import_node_fs7.readlinkSync)(existingPath);
312311
312334
  const resolvedTarget = import_node_path5.default.resolve(import_node_path5.default.dirname(existingPath), linkTarget);
312312
312335
  ensureInsideWorkspace(workspaceRealPath, resolvedTarget);
312313
312336
  }
@@ -312319,7 +312342,7 @@ function assertOutputFileAllowed2(filePath) {
312319
312342
  return void 0;
312320
312343
  }
312321
312344
  const workspaceRoot = import_node_path5.default.resolve(process.cwd());
312322
- const workspaceRealPath = (0, import_node_fs6.realpathSync)(workspaceRoot);
312345
+ const workspaceRealPath = (0, import_node_fs7.realpathSync)(workspaceRoot);
312323
312346
  const resolved = import_node_path5.default.isAbsolute(filePath) ? import_node_path5.default.resolve(filePath) : import_node_path5.default.resolve(workspaceRoot, filePath);
312324
312347
  const existingPath = nearestExistingPath2(resolved);
312325
312348
  ensureInsideWorkspace(workspaceRealPath, checkedRealPath(existingPath, workspaceRealPath));
@@ -312331,7 +312354,7 @@ async function writeOptionalFile(filePath, content) {
312331
312354
  return;
312332
312355
  }
312333
312356
  await (0, import_promises4.mkdir)(import_node_path5.default.dirname(resolved), { recursive: true });
312334
- ensureInsideWorkspace((0, import_node_fs6.realpathSync)(import_node_path5.default.resolve(process.cwd())), (0, import_node_fs6.realpathSync)(import_node_path5.default.dirname(resolved)));
312357
+ ensureInsideWorkspace((0, import_node_fs7.realpathSync)(import_node_path5.default.resolve(process.cwd())), (0, import_node_fs7.realpathSync)(import_node_path5.default.dirname(resolved)));
312335
312358
  await (0, import_promises4.writeFile)(resolved, content, "utf8");
312336
312359
  }
312337
312360
  function requireCliInput(name, value) {
@@ -312339,7 +312362,7 @@ function requireCliInput(name, value) {
312339
312362
  throw new Error(`${name} is required`);
312340
312363
  }
312341
312364
  }
312342
- function validateCliInputs(inputs) {
312365
+ function validateCliInputs(inputs, options = {}) {
312343
312366
  requireCliInput("project-name", inputs.projectName);
312344
312367
  if (!inputs.specUrl && !inputs.specPath) {
312345
312368
  throw new Error("One of spec-url or spec-path is required");
@@ -312347,7 +312370,7 @@ function validateCliInputs(inputs) {
312347
312370
  if (inputs.specUrl && inputs.specPath) {
312348
312371
  throw new Error("Provide either spec-url or spec-path, not both.");
312349
312372
  }
312350
- if (!inputs.postmanApiKey && !inputs.postmanAccessToken) {
312373
+ if (options.requireCredentials !== false && !inputs.postmanApiKey && !inputs.postmanAccessToken) {
312351
312374
  throw new Error("One of postman-api-key or postman-access-token is required.");
312352
312375
  }
312353
312376
  }
@@ -312368,9 +312391,26 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
312368
312391
  const env = runtime.env ?? process.env;
312369
312392
  const config = parseCliArgs(argv, env);
312370
312393
  const inputs = resolveInputs(config.inputEnv);
312371
- validateCliInputs(inputs);
312394
+ const branchDecision = decideBranchTier(inputs, config.inputEnv);
312395
+ validateCliInputs(inputs, { requireCredentials: branchDecision.tier !== "gated" });
312372
312396
  assertOutputFileAllowed2(config.resultJsonPath);
312373
312397
  assertOutputFileAllowed2(config.dotenvPath);
312398
+ if (branchDecision.tier === "gated") {
312399
+ const gatedReporter = new ConsoleReporter();
312400
+ const gated = await runGatedValidation(inputs, branchDecision, {
312401
+ info: (m) => gatedReporter.info(m),
312402
+ warning: (m) => gatedReporter.warning(m),
312403
+ setOutput: () => void 0
312404
+ });
312405
+ await writeOptionalFile(config.resultJsonPath, JSON.stringify(gated, null, 2));
312406
+ await writeOptionalFile(config.dotenvPath, toDotenv(gated));
312407
+ writeStdout(`${JSON.stringify(gated, null, 2)}
312408
+ `);
312409
+ return;
312410
+ }
312411
+ if (branchDecision.tier !== "legacy") {
312412
+ process.env[BRANCH_DECISION_ENV] = serializeBranchDecision(branchDecision);
312413
+ }
312374
312414
  const mintReporter = new ConsoleReporter();
312375
312415
  await mintAccessTokenIfNeeded2(inputs, mintReporter);
312376
312416
  const dependencies = createCliDependencies(inputs);
@@ -312403,7 +312443,7 @@ function isEntrypoint(currentPath, entrypointPath) {
312403
312443
  return false;
312404
312444
  }
312405
312445
  try {
312406
- return (0, import_node_fs6.realpathSync)(currentPath) === (0, import_node_fs6.realpathSync)(entrypointPath);
312446
+ return (0, import_node_fs7.realpathSync)(currentPath) === (0, import_node_fs7.realpathSync)(entrypointPath);
312407
312447
  } catch {
312408
312448
  return import_node_path5.default.resolve(currentPath) === import_node_path5.default.resolve(entrypointPath);
312409
312449
  }