@postman-cse/onboarding-repo-sync 2.1.13 → 2.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/action.cjs CHANGED
@@ -26569,7 +26569,7 @@ var require_util7 = __commonJS({
26569
26569
  exports2.esc = esc;
26570
26570
  exports2.slugify = slugify;
26571
26571
  exports2.isObject = isObject;
26572
- exports2.isPlainObject = isPlainObject2;
26572
+ exports2.isPlainObject = isPlainObject3;
26573
26573
  exports2.shallowClone = shallowClone;
26574
26574
  exports2.numKeys = numKeys;
26575
26575
  exports2.escapeRegex = escapeRegex;
@@ -26752,7 +26752,7 @@ var require_util7 = __commonJS({
26752
26752
  return false;
26753
26753
  }
26754
26754
  });
26755
- function isPlainObject2(o) {
26755
+ function isPlainObject3(o) {
26756
26756
  if (isObject(o) === false)
26757
26757
  return false;
26758
26758
  const ctor = o.constructor;
@@ -26769,7 +26769,7 @@ var require_util7 = __commonJS({
26769
26769
  return true;
26770
26770
  }
26771
26771
  function shallowClone(o) {
26772
- if (isPlainObject2(o))
26772
+ if (isPlainObject3(o))
26773
26773
  return { ...o };
26774
26774
  if (Array.isArray(o))
26775
26775
  return [...o];
@@ -26974,7 +26974,7 @@ var require_util7 = __commonJS({
26974
26974
  return clone(schema, def);
26975
26975
  }
26976
26976
  function extend(schema, shape) {
26977
- if (!isPlainObject2(shape)) {
26977
+ if (!isPlainObject3(shape)) {
26978
26978
  throw new Error("Invalid input to extend: expected a plain object");
26979
26979
  }
26980
26980
  const checks = schema._zod.def.checks;
@@ -26997,7 +26997,7 @@ var require_util7 = __commonJS({
26997
26997
  return clone(schema, def);
26998
26998
  }
26999
26999
  function safeExtend(schema, shape) {
27000
- if (!isPlainObject2(shape)) {
27000
+ if (!isPlainObject3(shape)) {
27001
27001
  throw new Error("Invalid input to safeExtend: expected a plain object");
27002
27002
  }
27003
27003
  const def = mergeDefs(schema._zod.def, {
@@ -54816,7 +54816,7 @@ var require_lodash = __commonJS({
54816
54816
  } else {
54817
54817
  newValue = [];
54818
54818
  }
54819
- } else if (isPlainObject2(srcValue) || isArguments(srcValue)) {
54819
+ } else if (isPlainObject3(srcValue) || isArguments(srcValue)) {
54820
54820
  newValue = objValue;
54821
54821
  if (isArguments(objValue)) {
54822
54822
  newValue = toPlainObject(objValue);
@@ -55780,7 +55780,7 @@ var require_lodash = __commonJS({
55780
55780
  return objValue;
55781
55781
  }
55782
55782
  function customOmitClone(value) {
55783
- return isPlainObject2(value) ? undefined2 : value;
55783
+ return isPlainObject3(value) ? undefined2 : value;
55784
55784
  }
55785
55785
  function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
55786
55786
  var isPartial = bitmask & COMPARE_PARTIAL_FLAG, arrLength = array.length, othLength = other.length;
@@ -57281,7 +57281,7 @@ var require_lodash = __commonJS({
57281
57281
  var isBuffer = nativeIsBuffer || stubFalse;
57282
57282
  var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;
57283
57283
  function isElement(value) {
57284
- return isObjectLike(value) && value.nodeType === 1 && !isPlainObject2(value);
57284
+ return isObjectLike(value) && value.nodeType === 1 && !isPlainObject3(value);
57285
57285
  }
57286
57286
  function isEmpty(value) {
57287
57287
  if (value == null) {
@@ -57317,7 +57317,7 @@ var require_lodash = __commonJS({
57317
57317
  return false;
57318
57318
  }
57319
57319
  var tag = baseGetTag(value);
57320
- return tag == errorTag || tag == domExcTag || typeof value.message == "string" && typeof value.name == "string" && !isPlainObject2(value);
57320
+ return tag == errorTag || tag == domExcTag || typeof value.message == "string" && typeof value.name == "string" && !isPlainObject3(value);
57321
57321
  }
57322
57322
  function isFinite2(value) {
57323
57323
  return typeof value == "number" && nativeIsFinite(value);
@@ -57368,7 +57368,7 @@ var require_lodash = __commonJS({
57368
57368
  function isNumber(value) {
57369
57369
  return typeof value == "number" || isObjectLike(value) && baseGetTag(value) == numberTag;
57370
57370
  }
57371
- function isPlainObject2(value) {
57371
+ function isPlainObject3(value) {
57372
57372
  if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
57373
57373
  return false;
57374
57374
  }
@@ -58439,7 +58439,7 @@ var require_lodash = __commonJS({
58439
58439
  lodash.isNumber = isNumber;
58440
58440
  lodash.isObject = isObject;
58441
58441
  lodash.isObjectLike = isObjectLike;
58442
- lodash.isPlainObject = isPlainObject2;
58442
+ lodash.isPlainObject = isPlainObject3;
58443
58443
  lodash.isRegExp = isRegExp;
58444
58444
  lodash.isSafeInteger = isSafeInteger;
58445
58445
  lodash.isSet = isSet;
@@ -131082,7 +131082,8 @@ function getIDToken(aud) {
131082
131082
  }
131083
131083
 
131084
131084
  // src/index.ts
131085
- var import_node_fs4 = require("node:fs");
131085
+ var import_node_crypto4 = require("node:crypto");
131086
+ var import_node_fs5 = require("node:fs");
131086
131087
  var path8 = __toESM(require("node:path"), 1);
131087
131088
 
131088
131089
  // node_modules/js-yaml/dist/js-yaml.mjs
@@ -133998,6 +133999,7 @@ function dump(input, options = {}) {
133998
133999
  }
133999
134000
 
134000
134001
  // src/postman-v3/converter.ts
134002
+ var import_node_fs = require("node:fs");
134001
134003
  var fs3 = __toESM(require("node:fs/promises"), 1);
134002
134004
  var path6 = __toESM(require("node:path"), 1);
134003
134005
  var V2 = __toESM(require_v2(), 1);
@@ -134068,6 +134070,72 @@ function structuredCloneSafe(value) {
134068
134070
  if (typeof structuredClone === "function") return structuredClone(value);
134069
134071
  return JSON.parse(JSON.stringify(value));
134070
134072
  }
134073
+ var ArtifactDigestStreamError = class extends Error {
134074
+ code = "ARTIFACT_DIGEST_STREAM";
134075
+ constructor(message, options) {
134076
+ super(message, options);
134077
+ this.name = "ArtifactDigestStreamError";
134078
+ }
134079
+ };
134080
+ function sameFileIdentity(left, right) {
134081
+ return left.dev === right.dev && left.ino === right.ino && left.size === right.size;
134082
+ }
134083
+ async function appendArtifactDigestFileStreaming(hash, relative4, absolute, expected) {
134084
+ const flags = typeof import_node_fs.constants.O_NOFOLLOW === "number" ? import_node_fs.constants.O_RDONLY | import_node_fs.constants.O_NOFOLLOW : import_node_fs.constants.O_RDONLY;
134085
+ let handle;
134086
+ try {
134087
+ handle = await fs3.open(absolute, flags);
134088
+ } catch (error2) {
134089
+ const code = error2?.code;
134090
+ if (code === "ELOOP" || code === "EMLINK" || code === "EINVAL") {
134091
+ throw new ArtifactDigestStreamError(
134092
+ `prebuilt collection tree file became a symlink or unsupported node at ${relative4}`,
134093
+ { cause: error2 }
134094
+ );
134095
+ }
134096
+ throw new ArtifactDigestStreamError(
134097
+ `prebuilt collection tree file changed or became unsupported at ${relative4}`,
134098
+ { cause: error2 }
134099
+ );
134100
+ }
134101
+ try {
134102
+ const before = await handle.stat();
134103
+ if (!before.isFile() || !sameFileIdentity(before, expected)) {
134104
+ throw new ArtifactDigestStreamError(
134105
+ `prebuilt collection tree file changed or became unsupported at ${relative4}`
134106
+ );
134107
+ }
134108
+ hash.update(relative4);
134109
+ hash.update("\0");
134110
+ const content = Buffer.allocUnsafe(expected.size);
134111
+ let total = 0;
134112
+ const buffer = Buffer.alloc(64 * 1024);
134113
+ for (; ; ) {
134114
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, null);
134115
+ if (bytesRead === 0) {
134116
+ break;
134117
+ }
134118
+ if (total + bytesRead > expected.size) {
134119
+ throw new ArtifactDigestStreamError(
134120
+ `prebuilt collection tree file changed while reading at ${relative4}`
134121
+ );
134122
+ }
134123
+ buffer.copy(content, total, 0, bytesRead);
134124
+ hash.update(buffer.subarray(0, bytesRead));
134125
+ total += bytesRead;
134126
+ }
134127
+ hash.update("\0");
134128
+ const after = await handle.stat();
134129
+ if (!after.isFile() || !sameFileIdentity(after, expected) || total !== expected.size) {
134130
+ throw new ArtifactDigestStreamError(
134131
+ `prebuilt collection tree file changed while reading at ${relative4}`
134132
+ );
134133
+ }
134134
+ return total === expected.size ? content : content.subarray(0, total);
134135
+ } finally {
134136
+ await handle.close();
134137
+ }
134138
+ }
134071
134139
  async function listFilesRelative(dir, base) {
134072
134140
  let entries;
134073
134141
  try {
@@ -134628,7 +134696,7 @@ function getCiWorkflowTemplate(provider, options = {}) {
134628
134696
  }
134629
134697
 
134630
134698
  // src/lib/github/repo-mutation.ts
134631
- var import_node_fs = require("node:fs");
134699
+ var import_node_fs2 = require("node:fs");
134632
134700
  var import_node_path = __toESM(require("node:path"), 1);
134633
134701
 
134634
134702
  // src/lib/secrets.ts
@@ -134918,7 +134986,7 @@ var RepoMutationService = class {
134918
134986
  throw new Error(this.secretMasker(changed.stderr || changed.stdout || "Failed to inspect generated changes"));
134919
134987
  }
134920
134988
  const hasPlannedRemoval = removePaths.some(
134921
- (removePath) => (0, import_node_fs.existsSync)(import_node_path.default.resolve(this.cwd, removePath))
134989
+ (removePath) => (0, import_node_fs2.existsSync)(import_node_path.default.resolve(this.cwd, removePath))
134922
134990
  );
134923
134991
  if (!changed.stdout.trim() && !hasPlannedRemoval) {
134924
134992
  return {
@@ -134942,7 +135010,7 @@ var RepoMutationService = class {
134942
135010
  await this.execute("git", ["config", "user.name", options.committerName]);
134943
135011
  await this.execute("git", ["config", "user.email", options.committerEmail]);
134944
135012
  for (const removePath of removePaths) {
134945
- (0, import_node_fs.rmSync)(import_node_path.default.resolve(this.cwd, removePath), { force: true });
135013
+ (0, import_node_fs2.rmSync)(import_node_path.default.resolve(this.cwd, removePath), { force: true });
134946
135014
  }
134947
135015
  await this.execute("git", ["add", "-A", "--", ...stagePaths]);
134948
135016
  const staged = await this.execute("git", ["diff", "--cached", "--quiet"]);
@@ -135485,14 +135553,14 @@ function createTelemetryContext(options) {
135485
135553
  }
135486
135554
 
135487
135555
  // src/action-version.ts
135488
- var import_node_fs2 = require("node:fs");
135556
+ var import_node_fs3 = require("node:fs");
135489
135557
  var import_node_path2 = require("node:path");
135490
135558
  function resolveActionVersion2() {
135491
135559
  if (false) {
135492
135560
  return void 0;
135493
135561
  }
135494
135562
  try {
135495
- const raw = (0, import_node_fs2.readFileSync)((0, import_node_path2.join)(__dirname, "..", "package.json"), "utf8");
135563
+ const raw = (0, import_node_fs3.readFileSync)((0, import_node_path2.join)(__dirname, "..", "package.json"), "utf8");
135496
135564
  return JSON.parse(raw).version ?? "unknown";
135497
135565
  } catch {
135498
135566
  return "unknown";
@@ -135731,7 +135799,8 @@ async function resolveSessionIdentity(opts) {
135731
135799
  opts.fetchImpl ?? fetch,
135732
135800
  Math.max(1, opts.maxAttempts ?? SESSION_MAX_ATTEMPTS),
135733
135801
  opts.sleepImpl ?? defaultSessionSleep,
135734
- opts.randomImpl ?? defaultRandom
135802
+ opts.randomImpl ?? defaultRandom,
135803
+ opts.onRetryEvent
135735
135804
  );
135736
135805
  sessionMemo.set(memoKey, pending);
135737
135806
  }
@@ -135765,7 +135834,7 @@ async function parseSessionResponse(response) {
135765
135834
  consumerType: coerceText(root.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
135766
135835
  };
135767
135836
  }
135768
- async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts, sleepImpl, random) {
135837
+ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts, sleepImpl, random, onRetryEvent) {
135769
135838
  let failure = "unavailable";
135770
135839
  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
135771
135840
  let response;
@@ -135777,7 +135846,9 @@ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts
135777
135846
  } catch {
135778
135847
  failure = "unavailable";
135779
135848
  if (attempt < maxAttempts) {
135780
- await sleepImpl(computeSessionRetryDelayMs(void 0, attempt, random));
135849
+ const delay = computeSessionRetryDelayMs(void 0, attempt, random);
135850
+ onRetryEvent?.({ class: "transport", attempt, delay });
135851
+ await sleepImpl(delay);
135781
135852
  continue;
135782
135853
  }
135783
135854
  break;
@@ -135799,7 +135870,9 @@ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts
135799
135870
  if (response.status === 429 || response.status >= 500) {
135800
135871
  failure = "unavailable";
135801
135872
  if (attempt < maxAttempts) {
135802
- await sleepImpl(computeSessionRetryDelayMs(response, attempt, random));
135873
+ const delay = computeSessionRetryDelayMs(response, attempt, random);
135874
+ onRetryEvent?.({ class: "http", status: response.status, attempt, delay });
135875
+ await sleepImpl(delay);
135803
135876
  continue;
135804
135877
  }
135805
135878
  break;
@@ -135901,7 +135974,8 @@ async function runCredentialPreflight(args) {
135901
135974
  accessToken,
135902
135975
  fetchImpl: args.fetchImpl,
135903
135976
  ...args.sleepImpl ? { sleepImpl: args.sleepImpl } : {},
135904
- ...args.randomImpl ? { randomImpl: args.randomImpl } : {}
135977
+ ...args.randomImpl ? { randomImpl: args.randomImpl } : {},
135978
+ onRetryEvent: args.retryEvent ?? args.log.retryEvent
135905
135979
  });
135906
135980
  } catch (error2) {
135907
135981
  args.log.warning(
@@ -136553,6 +136627,11 @@ var postmanRepoSyncActionContract = {
136553
136627
  description: "Contract collection ID used for exported artifacts.",
136554
136628
  required: false
136555
136629
  },
136630
+ "prebuilt-collections-json": {
136631
+ description: "Optional digest-bound JSON manifest of unique baseline, smoke, or contract roles with confined repo-relative path, SHA-256 artifact digest of the on-disk v3 collection tree (sorted relative-path + NUL + bytes + NUL), and canonical cloud ID. The optional payloadDigest field is the semantic v2 payload digest carried for provenance (format-validated only, not the reuse gate). Exact role, path, cloudId, and artifactDigest matches reuse the on-disk tree without cloud export.",
136632
+ required: false,
136633
+ default: ""
136634
+ },
136556
136635
  "collection-sync-mode": {
136557
136636
  description: "Collection sync lifecycle mode (refresh or version).",
136558
136637
  required: false,
@@ -136795,7 +136874,7 @@ var postmanRepoSyncActionContract = {
136795
136874
  "Create or update Postman environments from runtime URLs.",
136796
136875
  "Associate Postman environments to system environments through Postman integration APIs.",
136797
136876
  "Create mock servers and smoke monitors from generated collections.",
136798
- "Export Postman collections in the Collection v3 multi-file YAML directory structure under `postman/collections/` (e.g., `<name>/collection.yaml`, nested folder and request YAML files), and export environments plus `.postman/resources.yaml` into the repository.",
136877
+ "Export Postman collections in the Collection v3 multi-file YAML directory structure under `postman/collections/` (canonical `.resources/definition.yaml` plus request/resource YAML files), and export environments plus `.postman/resources.yaml` into the repository.",
136799
136878
  "Link the Postman workspace to the repository (GitHub or GitLab) through Postman integration APIs.",
136800
136879
  "Commit synced artifacts and push them back to the current checked out ref."
136801
136880
  ],
@@ -137580,6 +137659,7 @@ var AccessTokenProvider = class {
137580
137659
  maxAttempts;
137581
137660
  onToken;
137582
137661
  sleep;
137662
+ onRetryEvent;
137583
137663
  inflight;
137584
137664
  constructor(options) {
137585
137665
  this.token = String(options.accessToken || "").trim();
@@ -137591,6 +137671,7 @@ var AccessTokenProvider = class {
137591
137671
  this.maxAttempts = Math.max(1, options.maxAttempts ?? 2);
137592
137672
  this.onToken = options.onToken;
137593
137673
  this.sleep = options.sleep;
137674
+ this.onRetryEvent = options.onRetryEvent;
137594
137675
  }
137595
137676
  current() {
137596
137677
  return this.token;
@@ -137616,7 +137697,12 @@ var AccessTokenProvider = class {
137616
137697
  delayMs: 1e3,
137617
137698
  backoffMultiplier: 2,
137618
137699
  ...this.sleep ? { sleep: this.sleep } : {},
137619
- shouldRetry: (error2) => !(error2 instanceof MintError && error2.permanent)
137700
+ shouldRetry: (error2) => !(error2 instanceof MintError && error2.permanent),
137701
+ onRetry: ({ attempt, delayMs, error: error2 }) => {
137702
+ const status = error2 instanceof MintError ? error2.status : void 0;
137703
+ const retryClass = status === void 0 ? "transport" : "http";
137704
+ this.onRetryEvent?.({ class: retryClass, ...status === void 0 ? {} : { status }, attempt, delay: Math.max(0, delayMs) });
137705
+ }
137620
137706
  });
137621
137707
  this.token = token;
137622
137708
  this.onToken?.(token);
@@ -137647,7 +137733,7 @@ var AccessTokenProvider = class {
137647
137733
  true
137648
137734
  );
137649
137735
  }
137650
- throw new MintError(`postman: re-mint failed (service-account-tokens HTTP ${status}).`, false);
137736
+ throw new MintError(`postman: re-mint failed (service-account-tokens HTTP ${status}).`, false, status);
137651
137737
  }
137652
137738
  let parsed;
137653
137739
  try {
@@ -137678,7 +137764,8 @@ async function mintAccessTokenIfNeeded(inputs, log, setSecret2, fetchImpl = fetc
137678
137764
  apiKey: inputs.postmanApiKey,
137679
137765
  apiBaseUrl,
137680
137766
  fetchImpl,
137681
- onToken: (token) => setSecret2?.(token)
137767
+ onToken: (token) => setSecret2?.(token),
137768
+ onRetryEvent: (event) => log.retryEvent?.(event)
137682
137769
  });
137683
137770
  try {
137684
137771
  inputs.postmanAccessToken = await provider.refresh();
@@ -137718,6 +137805,7 @@ var AccessTokenGatewayClient = class {
137718
137805
  requestTimeoutMs;
137719
137806
  retryMaxDelayMs;
137720
137807
  randomImpl;
137808
+ onRetryEvent;
137721
137809
  constructor(options) {
137722
137810
  this.tokenProvider = options.tokenProvider;
137723
137811
  this.bifrostBaseUrl = String(
@@ -137736,6 +137824,7 @@ var AccessTokenGatewayClient = class {
137736
137824
  this.requestTimeoutMs = options.requestTimeoutMs ?? 3e4;
137737
137825
  this.retryMaxDelayMs = options.retryMaxDelayMs ?? 5e3;
137738
137826
  this.randomImpl = options.randomImpl ?? Math.random;
137827
+ this.onRetryEvent = options.onRetryEvent;
137739
137828
  }
137740
137829
  configureTeamContext(teamId, orgMode) {
137741
137830
  this.teamId = String(teamId || "").trim();
@@ -137804,8 +137893,9 @@ var AccessTokenGatewayClient = class {
137804
137893
  if (!this.fallbackBaseUrl) return false;
137805
137894
  return retryTransient || request.fallback === "auto";
137806
137895
  }
137807
- async attemptFallback(request, retryTransient) {
137896
+ async attemptFallback(request, retryTransient, status) {
137808
137897
  if (!this.fallbackEligible(request, retryTransient)) return null;
137898
+ this.emitRetryEvent("fallback", status, 1, 0);
137809
137899
  const response = await this.tryFallback(request);
137810
137900
  if (!response) return null;
137811
137901
  if (response.ok) return response;
@@ -137831,6 +137921,7 @@ var AccessTokenGatewayClient = class {
137831
137921
  } catch (error2) {
137832
137922
  if (retryTransient && attempt < this.maxRetries) {
137833
137923
  const delay = this.retryDelayMs(attempt);
137924
+ this.emitRetryEvent("transport", void 0, attempt + 1, delay);
137834
137925
  attempt += 1;
137835
137926
  await this.sleepImpl(delay);
137836
137927
  continue;
@@ -137844,7 +137935,9 @@ var AccessTokenGatewayClient = class {
137844
137935
  const inner = this.innerStatus(okBody);
137845
137936
  if (inner !== void 0) {
137846
137937
  if (retryTransient && this.isTransient(inner, okBody) && attempt < this.maxRetries) {
137847
- await this.sleepImpl(this.retryDelayMs(attempt));
137938
+ const delay = this.retryDelayMs(attempt);
137939
+ this.emitRetryEvent("inner", inner, attempt + 1, delay);
137940
+ await this.sleepImpl(delay);
137848
137941
  attempt += 1;
137849
137942
  continue;
137850
137943
  }
@@ -137854,6 +137947,7 @@ var AccessTokenGatewayClient = class {
137854
137947
  }
137855
137948
  const body = await response.text().catch(() => "");
137856
137949
  if (isExpiredAuthError(response.status, body) && this.tokenProvider.canRefresh()) {
137950
+ this.emitRetryEvent("auth", response.status, 1, 0);
137857
137951
  await this.tokenProvider.refresh();
137858
137952
  response = await this.send(request);
137859
137953
  if (response.ok) {
@@ -137864,11 +137958,12 @@ var AccessTokenGatewayClient = class {
137864
137958
  }
137865
137959
  if (retryTransient && this.isTransient(response.status, body) && attempt < this.maxRetries) {
137866
137960
  const delay = this.retryDelayMs(attempt, parseRetryAfterMs2(response.headers.get("retry-after")));
137961
+ this.emitRetryEvent("http", response.status, attempt + 1, delay);
137867
137962
  attempt += 1;
137868
137963
  await this.sleepImpl(delay);
137869
137964
  continue;
137870
137965
  }
137871
- const fallbackResponse = await this.attemptFallback(request, retryTransient);
137966
+ const fallbackResponse = await this.attemptFallback(request, retryTransient, response.status);
137872
137967
  if (fallbackResponse) return fallbackResponse;
137873
137968
  throw this.toHttpError(request, response, body);
137874
137969
  }
@@ -137876,6 +137971,14 @@ var AccessTokenGatewayClient = class {
137876
137971
  retryDelayMs(attempt, retryAfter) {
137877
137972
  return retryAfter === void 0 ? fullJitterDelayMs(attempt, this.retryBaseDelayMs, this.retryMaxDelayMs, this.randomImpl) : Math.min(this.retryMaxDelayMs, retryAfter);
137878
137973
  }
137974
+ emitRetryEvent(retryClass, status, attempt, delay) {
137975
+ this.onRetryEvent?.({
137976
+ class: retryClass,
137977
+ ...status === void 0 ? {} : { status },
137978
+ attempt: Math.max(1, attempt),
137979
+ delay: Math.max(0, delay)
137980
+ });
137981
+ }
137879
137982
  isTransient(status, body) {
137880
137983
  return status === 408 || status === 429 || status >= 500 || /ESOCKETTIMEDOUT|ETIMEDOUT|ECONNRESET|serverError|downstream/.test(body);
137881
137984
  }
@@ -138005,7 +138108,7 @@ function validateCertMaterial(certBase64, keyBase64, passphrase) {
138005
138108
  }
138006
138109
 
138007
138110
  // src/lib/repo/branch-decision.ts
138008
- var import_node_fs3 = require("node:fs");
138111
+ var import_node_fs4 = require("node:fs");
138009
138112
  var import_node_crypto3 = require("node:crypto");
138010
138113
  var ContractError = class extends Error {
138011
138114
  code;
@@ -138046,7 +138149,7 @@ function readGithubEvent(env) {
138046
138149
  const path9 = clean(env.GITHUB_EVENT_PATH);
138047
138150
  if (!path9) return void 0;
138048
138151
  try {
138049
- return JSON.parse((0, import_node_fs3.readFileSync)(path9, "utf8"));
138152
+ return JSON.parse((0, import_node_fs4.readFileSync)(path9, "utf8"));
138050
138153
  } catch {
138051
138154
  return void 0;
138052
138155
  }
@@ -138502,6 +138605,7 @@ function resolveInputs(env = process.env) {
138502
138605
  baselineCollectionId: getInput2("baseline-collection-id", env),
138503
138606
  smokeCollectionId: getInput2("smoke-collection-id", env),
138504
138607
  contractCollectionId: getInput2("contract-collection-id", env),
138608
+ prebuiltCollectionsJson: getInput2("prebuilt-collections-json", env),
138505
138609
  specId: getInput2("spec-id", env),
138506
138610
  specContentChanged: parseBooleanInput(getInput2("spec-content-changed", env), true),
138507
138611
  specPath: getInput2("spec-path", env),
@@ -138617,7 +138721,7 @@ var StateUnreadableError = class extends Error {
138617
138721
  function readResourcesState() {
138618
138722
  let raw;
138619
138723
  try {
138620
- raw = (0, import_node_fs4.readFileSync)(".postman/resources.yaml", "utf8");
138724
+ raw = (0, import_node_fs5.readFileSync)(".postman/resources.yaml", "utf8");
138621
138725
  } catch {
138622
138726
  return null;
138623
138727
  }
@@ -138676,12 +138780,15 @@ function getEnvironmentUidsFromResources(resourcesState) {
138676
138780
  function normalizeToPosix(filePath) {
138677
138781
  return filePath.split(path8.sep).join("/").replace(/\\/g, "/");
138678
138782
  }
138783
+ function canonicalizeRelativePath(value) {
138784
+ return normalizeToPosix(String(value ?? "").trim()).replace(/^\.\/+/, "").replace(/\/{2,}/g, "/").replace(/\/+$/g, "");
138785
+ }
138679
138786
  function isOpenApiSpecFile(filePath) {
138680
138787
  if (!(filePath.endsWith(".json") || filePath.endsWith(".yaml") || filePath.endsWith(".yml"))) {
138681
138788
  return false;
138682
138789
  }
138683
138790
  try {
138684
- const raw = (0, import_node_fs4.readFileSync)(filePath, "utf8");
138791
+ const raw = (0, import_node_fs5.readFileSync)(filePath, "utf8");
138685
138792
  const parsed = filePath.endsWith(".json") ? JSON.parse(raw) : load(raw);
138686
138793
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
138687
138794
  return false;
@@ -138710,7 +138817,7 @@ function scanLocalSpecReferences(baseDir = ".") {
138710
138817
  const found = /* @__PURE__ */ new Set();
138711
138818
  const refs = [];
138712
138819
  const visit2 = (currentDir) => {
138713
- for (const entry of (0, import_node_fs4.readdirSync)(currentDir, { withFileTypes: true })) {
138820
+ for (const entry of (0, import_node_fs5.readdirSync)(currentDir, { withFileTypes: true })) {
138714
138821
  if (ignoredDirs.has(entry.name)) {
138715
138822
  continue;
138716
138823
  }
@@ -138740,7 +138847,7 @@ function resolveMappedSpecReference(explicitSpecPath, discoveredSpecs) {
138740
138847
  const normalizedExplicitPath = normalizeToPosix(explicitSpecPath.trim());
138741
138848
  if (normalizedExplicitPath) {
138742
138849
  const explicitFullPath = path8.resolve(normalizedExplicitPath);
138743
- if ((0, import_node_fs4.existsSync)(explicitFullPath) && (0, import_node_fs4.statSync)(explicitFullPath).isFile()) {
138850
+ if ((0, import_node_fs5.existsSync)(explicitFullPath) && (0, import_node_fs5.statSync)(explicitFullPath).isFile()) {
138744
138851
  return {
138745
138852
  repoRelativePath: normalizedExplicitPath,
138746
138853
  configRelativePath: normalizeToPosix(path8.join("..", normalizedExplicitPath))
@@ -138792,6 +138899,7 @@ function readActionInputs(actionCore) {
138792
138899
  INPUT_BASELINE_COLLECTION_ID: readInput(actionCore, "baseline-collection-id"),
138793
138900
  INPUT_SMOKE_COLLECTION_ID: readInput(actionCore, "smoke-collection-id"),
138794
138901
  INPUT_CONTRACT_COLLECTION_ID: readInput(actionCore, "contract-collection-id"),
138902
+ INPUT_PREBUILT_COLLECTIONS_JSON: readInput(actionCore, "prebuilt-collections-json"),
138795
138903
  INPUT_SPEC_ID: readInput(actionCore, "spec-id"),
138796
138904
  INPUT_SPEC_PATH: readInput(actionCore, "spec-path"),
138797
138905
  INPUT_COLLECTION_SYNC_MODE: readInput(actionCore, "collection-sync-mode") || "refresh",
@@ -139005,6 +139113,7 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
139005
139113
  );
139006
139114
  }
139007
139115
  envUids[envName] = existingUid;
139116
+ dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
139008
139117
  continue;
139009
139118
  }
139010
139119
  const values = buildEnvironmentValues(envName, runtimeUrl);
@@ -139015,6 +139124,7 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
139015
139124
  displayName,
139016
139125
  values
139017
139126
  );
139127
+ dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
139018
139128
  } catch (error2) {
139019
139129
  throw new Error(
139020
139130
  formatOrchestrationIssue({
@@ -139031,7 +139141,7 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
139031
139141
  return envUids;
139032
139142
  }
139033
139143
  function ensureDir(path9) {
139034
- (0, import_node_fs4.mkdirSync)(path9, { recursive: true });
139144
+ (0, import_node_fs5.mkdirSync)(path9, { recursive: true });
139035
139145
  }
139036
139146
  function getCollectionDirectoryName(kind, projectName) {
139037
139147
  if (kind === "Baseline") {
@@ -139068,7 +139178,7 @@ function stripVolatileFields(obj) {
139068
139178
  }
139069
139179
  function writeJsonFile(path9, content, normalize4 = false) {
139070
139180
  const data = normalize4 ? stripVolatileFields(content) : content;
139071
- (0, import_node_fs4.writeFileSync)(path9, JSON.stringify(data, null, 2));
139181
+ (0, import_node_fs5.writeFileSync)(path9, JSON.stringify(data, null, 2));
139072
139182
  }
139073
139183
  function buildMappedSpecCloudKey(mappedSource, specSyncMode, releaseLabel) {
139074
139184
  if (specSyncMode !== "version") {
@@ -139132,22 +139242,422 @@ function buildResourcesManifest(workspaceId, collectionMap, envMap, artifactDir,
139132
139242
  sortKeys: false
139133
139243
  });
139134
139244
  }
139135
- function buildSpecCollectionWorkflowManifest(specRef, collectionRefs) {
139136
- return dump(
139137
- {
139138
- workflows: {
139139
- syncSpecToCollection: collectionRefs.map((collectionRef) => ({
139140
- spec: specRef,
139141
- collection: collectionRef
139142
- }))
139245
+ function isPlainObject2(value) {
139246
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
139247
+ }
139248
+ function buildSpecCollectionWorkflowManifest(specRef, collectionRefs, existingRaw) {
139249
+ const pairs = collectionRefs.map((collectionRef) => ({
139250
+ spec: specRef,
139251
+ collection: collectionRef
139252
+ }));
139253
+ let root = {};
139254
+ if (typeof existingRaw === "string" && existingRaw.trim()) {
139255
+ let parsed;
139256
+ try {
139257
+ parsed = load(existingRaw);
139258
+ } catch (error2) {
139259
+ throw new Error(
139260
+ `CONTRACT_WORKFLOWS_UNREADABLE: .postman/workflows.yaml exists but is not parseable YAML (${error2 instanceof Error ? error2.message : String(error2)}). Fix or delete the file; refusing to overwrite unrelated workflow data.`,
139261
+ { cause: error2 }
139262
+ );
139263
+ }
139264
+ if (parsed === null || parsed === void 0) {
139265
+ root = {};
139266
+ } else if (!isPlainObject2(parsed)) {
139267
+ throw new Error(
139268
+ "CONTRACT_WORKFLOWS_UNREADABLE: .postman/workflows.yaml exists but does not contain a YAML mapping. Fix or delete the file; refusing to overwrite unrelated workflow data."
139269
+ );
139270
+ } else {
139271
+ root = { ...parsed };
139272
+ }
139273
+ }
139274
+ const workflows = isPlainObject2(root.workflows) ? { ...root.workflows } : {};
139275
+ const desiredCollections = new Set(collectionRefs);
139276
+ const currentPairs = (Array.isArray(workflows.syncSpecToCollection) ? workflows.syncSpecToCollection : []).map((entry) => isPlainObject2(entry) ? { ...entry } : null).filter((entry) => Boolean(entry)).filter(
139277
+ (entry) => String(entry.spec ?? "") !== specRef || desiredCollections.has(String(entry.collection ?? ""))
139278
+ );
139279
+ for (const pair of pairs) {
139280
+ const index = currentPairs.findIndex(
139281
+ (entry) => String(entry.spec ?? "") === pair.spec && String(entry.collection ?? "") === pair.collection
139282
+ );
139283
+ if (index >= 0) {
139284
+ const previous = currentPairs[index];
139285
+ currentPairs[index] = { ...previous, spec: pair.spec, collection: pair.collection };
139286
+ } else {
139287
+ currentPairs.push({ spec: pair.spec, collection: pair.collection });
139288
+ }
139289
+ }
139290
+ workflows.syncSpecToCollection = currentPairs;
139291
+ root.workflows = workflows;
139292
+ return dump(root, {
139293
+ lineWidth: -1,
139294
+ noRefs: true,
139295
+ sortKeys: false
139296
+ });
139297
+ }
139298
+ var PREBUILT_COLLECTION_ROLES = /* @__PURE__ */ new Set([
139299
+ "baseline",
139300
+ "smoke",
139301
+ "contract"
139302
+ ]);
139303
+ var SHA256_HEX = /^[a-f0-9]{64}$/;
139304
+ var PREBUILT_CLOUD_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
139305
+ function failPrebuiltCollections(detail) {
139306
+ throw new Error(`CONTRACT_PREBUILT_COLLECTIONS_INVALID: ${detail}`);
139307
+ }
139308
+ function parsePrebuiltCollectionsJson(raw) {
139309
+ const trimmed = String(raw ?? "").trim();
139310
+ if (!trimmed) {
139311
+ return [];
139312
+ }
139313
+ let parsed;
139314
+ try {
139315
+ parsed = JSON.parse(trimmed);
139316
+ } catch (error2) {
139317
+ throw new Error(
139318
+ `CONTRACT_PREBUILT_COLLECTIONS_INVALID: malformed JSON (${error2 instanceof Error ? error2.message : String(error2)})`,
139319
+ { cause: error2 }
139320
+ );
139321
+ }
139322
+ let entriesRaw;
139323
+ if (Array.isArray(parsed)) {
139324
+ entriesRaw = parsed;
139325
+ } else if (isPlainObject2(parsed)) {
139326
+ if (parsed.schemaVersion !== 1) {
139327
+ failPrebuiltCollections("schemaVersion must be 1");
139328
+ }
139329
+ if (!Array.isArray(parsed.collections)) {
139330
+ failPrebuiltCollections("collections must be an array when schemaVersion is set");
139331
+ }
139332
+ entriesRaw = parsed.collections;
139333
+ } else {
139334
+ failPrebuiltCollections("expected a JSON array or {schemaVersion:1,collections:[]}");
139335
+ }
139336
+ const seenRoles = /* @__PURE__ */ new Set();
139337
+ const entries = [];
139338
+ for (const [index, value] of entriesRaw.entries()) {
139339
+ if (!isPlainObject2(value)) {
139340
+ failPrebuiltCollections(`collections[${index}] must be an object`);
139341
+ }
139342
+ const roleRaw = String(value.role ?? "").trim();
139343
+ if (!PREBUILT_COLLECTION_ROLES.has(roleRaw)) {
139344
+ failPrebuiltCollections(
139345
+ `collections[${index}].role must be one of baseline|smoke|contract`
139346
+ );
139347
+ }
139348
+ const role = roleRaw;
139349
+ if (seenRoles.has(role)) {
139350
+ failPrebuiltCollections(`duplicate role ${role}`);
139351
+ }
139352
+ seenRoles.add(role);
139353
+ const collectionPath = String(
139354
+ value.collectionPath ?? value.path ?? ""
139355
+ ).trim();
139356
+ if (!collectionPath || hasControlCharacter2(collectionPath)) {
139357
+ failPrebuiltCollections(
139358
+ `collections[${index}].collectionPath must be a non-empty confined relative path`
139359
+ );
139360
+ }
139361
+ const cloudId = String(value.cloudId ?? "").trim();
139362
+ if (!cloudId || !PREBUILT_CLOUD_ID.test(cloudId)) {
139363
+ failPrebuiltCollections(
139364
+ `collections[${index}].cloudId must be a non-empty Postman collection id`
139365
+ );
139366
+ }
139367
+ let payloadDigest;
139368
+ if (Object.prototype.hasOwnProperty.call(value, "payloadDigest")) {
139369
+ const payloadDigestRaw = value.payloadDigest;
139370
+ if (payloadDigestRaw !== void 0 && payloadDigestRaw !== null) {
139371
+ payloadDigest = String(payloadDigestRaw).trim();
139372
+ if (!SHA256_HEX.test(payloadDigest)) {
139373
+ failPrebuiltCollections(
139374
+ `collections[${index}].payloadDigest must be lowercase 64-hex`
139375
+ );
139376
+ }
139143
139377
  }
139144
- },
139145
- {
139146
- lineWidth: -1,
139147
- noRefs: true,
139148
- sortKeys: false
139149
139378
  }
139379
+ const artifactDigest = String(value.artifactDigest ?? "").trim();
139380
+ if (!SHA256_HEX.test(artifactDigest)) {
139381
+ failPrebuiltCollections(
139382
+ `collections[${index}].artifactDigest must be lowercase 64-hex`
139383
+ );
139384
+ }
139385
+ entries.push({
139386
+ role,
139387
+ collectionPath,
139388
+ cloudId,
139389
+ ...payloadDigest !== void 0 ? { payloadDigest } : {},
139390
+ artifactDigest
139391
+ });
139392
+ }
139393
+ return entries;
139394
+ }
139395
+ function assertPathWithinArtifactRoot(targetPath, artifactDir, fieldName) {
139396
+ assertPathWithinCwd(targetPath, fieldName);
139397
+ assertPathWithinCwd(artifactDir, "artifact-dir");
139398
+ const cwd = (0, import_node_fs5.realpathSync)(process.cwd());
139399
+ const artifactRoot = path8.resolve(cwd, artifactDir.trim());
139400
+ const resolved = path8.resolve(cwd, targetPath.trim());
139401
+ const relativeToArtifact = path8.relative(artifactRoot, resolved);
139402
+ if (!relativeToArtifact || relativeToArtifact.startsWith("..") || path8.isAbsolute(relativeToArtifact)) {
139403
+ failPrebuiltCollections(
139404
+ `${fieldName} must stay under artifact-dir (${artifactDir}); received ${targetPath}`
139405
+ );
139406
+ }
139407
+ let existingPath = resolved;
139408
+ while (!(0, import_node_fs5.existsSync)(existingPath)) {
139409
+ const parent = path8.dirname(existingPath);
139410
+ if (parent === existingPath) {
139411
+ break;
139412
+ }
139413
+ existingPath = parent;
139414
+ }
139415
+ const realExisting = (0, import_node_fs5.realpathSync)(existingPath);
139416
+ const realRelative = path8.relative(artifactRoot, realExisting);
139417
+ if (realRelative.startsWith("..") || path8.isAbsolute(realRelative)) {
139418
+ failPrebuiltCollections(
139419
+ `${fieldName} resolves outside artifact-dir via symlink; received ${targetPath}`
139420
+ );
139421
+ }
139422
+ return normalizeToPosix(path8.relative(cwd, resolved));
139423
+ }
139424
+ function prebuiltDirectoryTraversalIdentity(absolutePath, stats, options = {}) {
139425
+ const platform2 = options.platform ?? process.platform;
139426
+ const inodeIsZero = stats.ino === 0 || stats.ino === 0n;
139427
+ if (platform2 !== "win32" && !inodeIsZero) {
139428
+ return `${stats.dev}:${stats.ino}`;
139429
+ }
139430
+ const resolveCanonicalPath = options.resolveCanonicalPath ?? ((candidate) => import_node_fs5.realpathSync.native(candidate));
139431
+ const canonical = resolveCanonicalPath(absolutePath);
139432
+ return platform2 === "win32" ? canonical.toLowerCase() : canonical;
139433
+ }
139434
+ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
139435
+ const confined = assertPathWithinArtifactRoot(
139436
+ collectionPath,
139437
+ artifactDir,
139438
+ "prebuilt collection path"
139439
+ );
139440
+ const absRoot = path8.resolve(process.cwd(), confined);
139441
+ if (!(0, import_node_fs5.existsSync)(absRoot)) {
139442
+ return [];
139443
+ }
139444
+ let rootStat;
139445
+ try {
139446
+ rootStat = (0, import_node_fs5.lstatSync)(absRoot);
139447
+ } catch {
139448
+ return [];
139449
+ }
139450
+ if (rootStat.isSymbolicLink()) {
139451
+ failPrebuiltCollections(
139452
+ `prebuilt collection path must not be a symlink; received ${collectionPath}`
139453
+ );
139454
+ }
139455
+ if (!rootStat.isDirectory()) {
139456
+ return [];
139457
+ }
139458
+ const files = [];
139459
+ const pendingDirectories = [absRoot];
139460
+ const seenDirectories = /* @__PURE__ */ new Set();
139461
+ while (pendingDirectories.length > 0) {
139462
+ const currentAbsolute = pendingDirectories.pop();
139463
+ if (!currentAbsolute) {
139464
+ break;
139465
+ }
139466
+ const currentStat = (0, import_node_fs5.lstatSync)(currentAbsolute);
139467
+ if (currentStat.isSymbolicLink() || !currentStat.isDirectory()) {
139468
+ failPrebuiltCollections(
139469
+ `prebuilt collection tree directory changed or became unsupported at ${normalizeToPosix(path8.relative(absRoot, currentAbsolute)) || "."}`
139470
+ );
139471
+ }
139472
+ const currentKey = prebuiltDirectoryTraversalIdentity(currentAbsolute, currentStat);
139473
+ if (seenDirectories.has(currentKey)) {
139474
+ failPrebuiltCollections(
139475
+ `prebuilt collection tree directory cycle detected at ${normalizeToPosix(path8.relative(absRoot, currentAbsolute)) || "."}`
139476
+ );
139477
+ }
139478
+ seenDirectories.add(currentKey);
139479
+ const entries = (0, import_node_fs5.readdirSync)(currentAbsolute, { withFileTypes: true });
139480
+ for (const entry of entries) {
139481
+ const abs = path8.join(currentAbsolute, entry.name);
139482
+ if (entry.isSymbolicLink()) {
139483
+ failPrebuiltCollections(
139484
+ `prebuilt collection tree must not contain symlinks; received ${normalizeToPosix(path8.relative(absRoot, abs))}`
139485
+ );
139486
+ }
139487
+ if (entry.isDirectory()) {
139488
+ pendingDirectories.push(abs);
139489
+ continue;
139490
+ }
139491
+ if (!entry.isFile()) {
139492
+ failPrebuiltCollections(
139493
+ `prebuilt collection tree contains unsupported entry type at ${normalizeToPosix(path8.relative(absRoot, abs))}`
139494
+ );
139495
+ }
139496
+ const fileLstat = (0, import_node_fs5.lstatSync)(abs);
139497
+ if (fileLstat.isSymbolicLink() || !fileLstat.isFile()) {
139498
+ failPrebuiltCollections(
139499
+ `prebuilt collection tree file changed or became unsupported at ${normalizeToPosix(path8.relative(absRoot, abs))}`
139500
+ );
139501
+ }
139502
+ files.push({
139503
+ absolute: abs,
139504
+ relative: normalizeToPosix(path8.relative(absRoot, abs)),
139505
+ dev: fileLstat.dev,
139506
+ ino: fileLstat.ino,
139507
+ size: fileLstat.size
139508
+ });
139509
+ }
139510
+ }
139511
+ files.sort((a, b) => a.relative.localeCompare(b.relative));
139512
+ return files;
139513
+ }
139514
+ function validateCanonicalV3CollectionFile(relative4, bytes) {
139515
+ let expectedKind;
139516
+ if (/(^|\/)\.resources\/definition\.yaml$/.test(relative4)) {
139517
+ expectedKind = "collection";
139518
+ } else if (relative4.endsWith(".request.yaml")) {
139519
+ expectedKind = "request";
139520
+ } else if (relative4.endsWith(".example.yaml")) {
139521
+ expectedKind = "example";
139522
+ } else if (relative4.endsWith(".message.yaml")) {
139523
+ expectedKind = "message";
139524
+ } else {
139525
+ failPrebuiltCollections(`prebuilt collection tree contains unexpected file ${relative4}`);
139526
+ }
139527
+ let parsed;
139528
+ try {
139529
+ parsed = load(bytes.toString("utf8"));
139530
+ } catch (error2) {
139531
+ failPrebuiltCollections(
139532
+ `prebuilt collection tree contains malformed YAML at ${relative4} (${error2 instanceof Error ? error2.message : String(error2)})`
139533
+ );
139534
+ }
139535
+ if (!isPlainObject2(parsed)) {
139536
+ failPrebuiltCollections(`prebuilt collection tree file ${relative4} must contain a YAML mapping`);
139537
+ }
139538
+ const kind = typeof parsed.$kind === "string" ? parsed.$kind.trim() : "";
139539
+ if (!kind) {
139540
+ failPrebuiltCollections(`prebuilt collection tree file ${relative4} must contain a nonempty $kind`);
139541
+ }
139542
+ const agrees = expectedKind === "collection" ? kind === "collection" : kind.endsWith(`-${expectedKind}`);
139543
+ if (!agrees) {
139544
+ failPrebuiltCollections(
139545
+ `prebuilt collection tree file ${relative4} has $kind ${kind} inconsistent with its filename`
139546
+ );
139547
+ }
139548
+ }
139549
+ async function digestAndValidatePrebuiltCollectionTree(files) {
139550
+ if (!files.some((file) => file.relative === ".resources/definition.yaml")) {
139551
+ failPrebuiltCollections("prebuilt collection tree is missing .resources/definition.yaml");
139552
+ }
139553
+ const hash = (0, import_node_crypto4.createHash)("sha256");
139554
+ for (const file of files) {
139555
+ let bytes;
139556
+ try {
139557
+ bytes = await appendArtifactDigestFileStreaming(hash, file.relative, file.absolute, {
139558
+ dev: file.dev,
139559
+ ino: file.ino,
139560
+ size: file.size
139561
+ });
139562
+ } catch (error2) {
139563
+ if (error2 instanceof ArtifactDigestStreamError) {
139564
+ failPrebuiltCollections(error2.message);
139565
+ }
139566
+ const code = error2?.code;
139567
+ if (code === "ELOOP" || code === "EPERM") {
139568
+ failPrebuiltCollections(
139569
+ `prebuilt collection tree file became a symlink or unsupported node at ${file.relative}`
139570
+ );
139571
+ }
139572
+ failPrebuiltCollections(
139573
+ `prebuilt collection tree file changed or became unsupported at ${file.relative}`
139574
+ );
139575
+ }
139576
+ validateCanonicalV3CollectionFile(file.relative, bytes);
139577
+ }
139578
+ return hash.digest("hex");
139579
+ }
139580
+ async function preparePrebuiltCollections(inputs) {
139581
+ const prepared = /* @__PURE__ */ new Map();
139582
+ for (const entry of parsePrebuiltCollectionsJson(inputs.prebuiltCollectionsJson ?? "")) {
139583
+ const confinedPath = assertPathWithinArtifactRoot(
139584
+ entry.collectionPath,
139585
+ inputs.artifactDir,
139586
+ `prebuilt ${entry.role} collection path`
139587
+ );
139588
+ const absolute = path8.resolve(process.cwd(), confinedPath);
139589
+ if (!(0, import_node_fs5.existsSync)(absolute)) {
139590
+ prepared.set(entry.role, { entry, confinedPath });
139591
+ continue;
139592
+ }
139593
+ const files = listPrebuiltCollectionTreeFiles(confinedPath, inputs.artifactDir);
139594
+ const artifactDigest = await digestAndValidatePrebuiltCollectionTree(files);
139595
+ prepared.set(entry.role, {
139596
+ entry,
139597
+ confinedPath,
139598
+ artifactDigest
139599
+ });
139600
+ }
139601
+ return prepared;
139602
+ }
139603
+ function tryReusePrebuiltCollection(options) {
139604
+ const { prepared, expectedPath, expectedCloudId } = options;
139605
+ const { entry } = prepared;
139606
+ if (!expectedCloudId || entry.cloudId !== expectedCloudId) {
139607
+ return false;
139608
+ }
139609
+ const expectedNormalized = canonicalizeRelativePath(expectedPath);
139610
+ const entryNormalized = canonicalizeRelativePath(entry.collectionPath);
139611
+ if (entryNormalized !== expectedNormalized) {
139612
+ return false;
139613
+ }
139614
+ const confined = canonicalizeRelativePath(prepared.confinedPath);
139615
+ if (confined !== expectedNormalized) {
139616
+ return false;
139617
+ }
139618
+ const expectedName = path8.posix.basename(expectedNormalized);
139619
+ if (path8.posix.basename(confined) !== expectedName) {
139620
+ return false;
139621
+ }
139622
+ return prepared.artifactDigest === entry.artifactDigest;
139623
+ }
139624
+ async function exportCollectionArtifact(options) {
139625
+ const {
139626
+ role,
139627
+ collectionId,
139628
+ dirName,
139629
+ collectionsDir,
139630
+ prebuiltByRole,
139631
+ postman,
139632
+ core
139633
+ } = options;
139634
+ if (!collectionId) {
139635
+ return void 0;
139636
+ }
139637
+ const expectedPath = `${collectionsDir}/${dirName}`;
139638
+ const entry = prebuiltByRole.get(role);
139639
+ if (entry) {
139640
+ const reused = tryReusePrebuiltCollection({
139641
+ prepared: entry,
139642
+ expectedPath,
139643
+ expectedCloudId: collectionId
139644
+ });
139645
+ if (reused) {
139646
+ core.info(
139647
+ `Reusing prebuilt ${role} collection tree at ${expectedPath} (artifactDigest match)`
139648
+ );
139649
+ return `../${expectedPath}`;
139650
+ }
139651
+ core.info(
139652
+ `Prebuilt ${role} collection entry present but did not exactly match; exporting from cloud`
139653
+ );
139654
+ }
139655
+ const col = await postman.getCollection(collectionId);
139656
+ await convertAndSplitAnyCollection(
139657
+ col,
139658
+ expectedPath
139150
139659
  );
139660
+ return `../${expectedPath}`;
139151
139661
  }
139152
139662
  function hasControlCharacter2(value) {
139153
139663
  for (let index = 0; index < value.length; index += 1) {
@@ -139165,21 +139675,21 @@ function assertPathWithinCwd(targetPath, fieldName) {
139165
139675
  if (!rawPath || hasControlCharacter2(originalPath) || path8.isAbsolute(rawPath) || path8.win32.isAbsolute(rawPath) || segments.includes("..") || rawPath.startsWith(":") || hasControlCharacter2(rawPath)) {
139166
139676
  throw new Error(`${fieldName} must stay within the repository root; received ${targetPath}`);
139167
139677
  }
139168
- const base = (0, import_node_fs4.realpathSync)(process.cwd());
139678
+ const base = (0, import_node_fs5.realpathSync)(process.cwd());
139169
139679
  const resolved = path8.resolve(base, rawPath);
139170
139680
  const relative4 = path8.relative(base, resolved);
139171
139681
  if (relative4.startsWith("..") || path8.isAbsolute(relative4)) {
139172
139682
  throw new Error(`${fieldName} must stay within the repository root; received ${targetPath}`);
139173
139683
  }
139174
139684
  let existingPath = resolved;
139175
- while (!(0, import_node_fs4.existsSync)(existingPath)) {
139685
+ while (!(0, import_node_fs5.existsSync)(existingPath)) {
139176
139686
  const parent = path8.dirname(existingPath);
139177
139687
  if (parent === existingPath) {
139178
139688
  break;
139179
139689
  }
139180
139690
  existingPath = parent;
139181
139691
  }
139182
- const realExistingPath = (0, import_node_fs4.realpathSync)(existingPath);
139692
+ const realExistingPath = (0, import_node_fs5.realpathSync)(existingPath);
139183
139693
  const realRelative = path8.relative(base, realExistingPath);
139184
139694
  if (realRelative.startsWith("..") || path8.isAbsolute(realRelative)) {
139185
139695
  throw new Error(`${fieldName} must stay within the repository root; received ${targetPath}`);
@@ -139207,8 +139717,8 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
139207
139717
  ensureDir(specsDir);
139208
139718
  ensureDir(".postman");
139209
139719
  const globalsFilePath = `${globalsDir}/workspace.globals.yaml`;
139210
- if (!(0, import_node_fs4.existsSync)(globalsFilePath)) {
139211
- (0, import_node_fs4.writeFileSync)(globalsFilePath, "name: Globals\nvalues: []\n");
139720
+ if (!(0, import_node_fs5.existsSync)(globalsFilePath)) {
139721
+ (0, import_node_fs5.writeFileSync)(globalsFilePath, "name: Globals\nvalues: []\n");
139212
139722
  }
139213
139723
  if (inputs.generateCiWorkflow) {
139214
139724
  const ciDir = inputs.ciWorkflowPath.split("/").slice(0, -1).join("/");
@@ -139224,23 +139734,42 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
139224
139734
  inputs.specSyncMode,
139225
139735
  options.releaseLabel
139226
139736
  ) : void 0;
139227
- if (inputs.baselineCollectionId) {
139228
- const col = await dependencies.postman.getCollection(inputs.baselineCollectionId);
139229
- const dirName = getCollectionDirectoryName("Baseline", assetProjectName);
139230
- await convertAndSplitAnyCollection(col, `${collectionsDir}/${dirName}`);
139231
- manifestCollections[`../${collectionsDir}/${dirName}`] = inputs.baselineCollectionId;
139232
- }
139233
- if (inputs.smokeCollectionId) {
139234
- const col = await dependencies.postman.getCollection(inputs.smokeCollectionId);
139235
- const dirName = getCollectionDirectoryName("Smoke", assetProjectName);
139236
- await convertAndSplitAnyCollection(col, `${collectionsDir}/${dirName}`);
139237
- manifestCollections[`../${collectionsDir}/${dirName}`] = inputs.smokeCollectionId;
139238
- }
139239
- if (inputs.contractCollectionId) {
139240
- const col = await dependencies.postman.getCollection(inputs.contractCollectionId);
139241
- const dirName = getCollectionDirectoryName("Contract", assetProjectName);
139242
- await convertAndSplitAnyCollection(col, `${collectionsDir}/${dirName}`);
139243
- manifestCollections[`../${collectionsDir}/${dirName}`] = inputs.contractCollectionId;
139737
+ const prebuiltByRole = options.preparedPrebuiltCollections;
139738
+ const baselineRef = await exportCollectionArtifact({
139739
+ role: "baseline",
139740
+ collectionId: inputs.baselineCollectionId,
139741
+ dirName: getCollectionDirectoryName("Baseline", assetProjectName),
139742
+ collectionsDir,
139743
+ prebuiltByRole,
139744
+ postman: dependencies.postman,
139745
+ core: dependencies.core
139746
+ });
139747
+ if (baselineRef) {
139748
+ manifestCollections[baselineRef] = inputs.baselineCollectionId;
139749
+ }
139750
+ const smokeRef = await exportCollectionArtifact({
139751
+ role: "smoke",
139752
+ collectionId: inputs.smokeCollectionId,
139753
+ dirName: getCollectionDirectoryName("Smoke", assetProjectName),
139754
+ collectionsDir,
139755
+ prebuiltByRole,
139756
+ postman: dependencies.postman,
139757
+ core: dependencies.core
139758
+ });
139759
+ if (smokeRef) {
139760
+ manifestCollections[smokeRef] = inputs.smokeCollectionId;
139761
+ }
139762
+ const contractRef = await exportCollectionArtifact({
139763
+ role: "contract",
139764
+ collectionId: inputs.contractCollectionId,
139765
+ dirName: getCollectionDirectoryName("Contract", assetProjectName),
139766
+ collectionsDir,
139767
+ prebuiltByRole,
139768
+ postman: dependencies.postman,
139769
+ core: dependencies.core
139770
+ });
139771
+ if (contractRef) {
139772
+ manifestCollections[contractRef] = inputs.contractCollectionId;
139244
139773
  }
139245
139774
  for (const [envName, envUid] of Object.entries(envUids)) {
139246
139775
  writeJsonFile(
@@ -139255,7 +139784,7 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
139255
139784
  workspaceLinkEnabled: inputs.workspaceLinkEnabled,
139256
139785
  workspaceLinkStatus: options.workspaceLinkStatus
139257
139786
  });
139258
- (0, import_node_fs4.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
139787
+ (0, import_node_fs5.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
139259
139788
  durableWorkspaceId,
139260
139789
  manifestCollections,
139261
139790
  envUids,
@@ -139267,11 +139796,18 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
139267
139796
  options.priorState
139268
139797
  ));
139269
139798
  if (mappedSpec && Object.keys(manifestCollections).length > 0) {
139270
- (0, import_node_fs4.writeFileSync)(
139799
+ let existingWorkflows;
139800
+ try {
139801
+ existingWorkflows = (0, import_node_fs5.readFileSync)(".postman/workflows.yaml", "utf8");
139802
+ } catch {
139803
+ existingWorkflows = void 0;
139804
+ }
139805
+ (0, import_node_fs5.writeFileSync)(
139271
139806
  ".postman/workflows.yaml",
139272
139807
  buildSpecCollectionWorkflowManifest(
139273
139808
  mappedSpec.configRelativePath,
139274
- Object.keys(manifestCollections)
139809
+ Object.keys(manifestCollections),
139810
+ existingWorkflows
139275
139811
  )
139276
139812
  );
139277
139813
  }
@@ -139316,12 +139852,12 @@ async function commitAndPushGeneratedFiles(inputs, dependencies) {
139316
139852
  const dir = parts.slice(0, -1).join("/");
139317
139853
  ensureDir(dir);
139318
139854
  }
139319
- (0, import_node_fs4.writeFileSync)(inputs.ciWorkflowPath, ciWorkflow);
139855
+ (0, import_node_fs5.writeFileSync)(inputs.ciWorkflowPath, ciWorkflow);
139320
139856
  if (inputs.provider === "github" || inputs.provider === "unknown") {
139321
139857
  const gcPath = ".github/workflows/postman-preview-gc.yml";
139322
139858
  if (inputs.ciWorkflowPath.endsWith(".github/workflows/ci.yml") || inputs.ciWorkflowPath === ".github/workflows/ci.yml") {
139323
139859
  ensureDir(".github/workflows");
139324
- (0, import_node_fs4.writeFileSync)(gcPath, renderGcWorkflowTemplate());
139860
+ (0, import_node_fs5.writeFileSync)(gcPath, renderGcWorkflowTemplate());
139325
139861
  }
139326
139862
  }
139327
139863
  }
@@ -139329,16 +139865,16 @@ async function commitAndPushGeneratedFiles(inputs, dependencies) {
139329
139865
  return { commitSha: "", resolvedCurrentRef: "", pushed: false };
139330
139866
  }
139331
139867
  const provisionPath = ".github/workflows/provision.yml";
139332
- const provisionExists = inputs.provider === "github" && (0, import_node_fs4.existsSync)(provisionPath);
139868
+ const provisionExists = inputs.provider === "github" && (0, import_node_fs5.existsSync)(provisionPath);
139333
139869
  const gcWorkflowPath = ".github/workflows/postman-preview-gc.yml";
139334
- const gcExists = inputs.generateCiWorkflow && (0, import_node_fs4.existsSync)(gcWorkflowPath);
139870
+ const gcExists = inputs.generateCiWorkflow && (0, import_node_fs5.existsSync)(gcWorkflowPath);
139335
139871
  const stagePaths = [
139336
139872
  inputs.artifactDir,
139337
139873
  ".postman",
139338
139874
  inputs.generateCiWorkflow ? inputs.ciWorkflowPath : null,
139339
139875
  gcExists ? gcWorkflowPath : null,
139340
139876
  provisionExists ? provisionPath : null
139341
- ].filter((entry) => typeof entry === "string" && ((0, import_node_fs4.existsSync)(entry) || entry === provisionPath));
139877
+ ].filter((entry) => typeof entry === "string" && ((0, import_node_fs5.existsSync)(entry) || entry === provisionPath));
139342
139878
  if (stagePaths.length === 0) {
139343
139879
  dependencies.core.info("No generated repository paths were found; skipping repo mutation.");
139344
139880
  return {
@@ -139446,6 +139982,7 @@ async function runRepoSyncInner(inputs, dependencies) {
139446
139982
  }
139447
139983
  }
139448
139984
  }
139985
+ const preparedPrebuiltCollections = await preparePrebuiltCollections(inputs);
139449
139986
  let skipRepositoryLinkPost = false;
139450
139987
  let repositoryLinkPreflightWasFree = false;
139451
139988
  if (inputs.workspaceLinkEnabled && inputs.workspaceId && inputs.repoUrl && dependencies.internalIntegration?.findWorkspaceForRepo) {
@@ -139482,6 +140019,7 @@ async function runRepoSyncInner(inputs, dependencies) {
139482
140019
  const branchAssetMarker = buildBranchAssetMarker(branchDecision, inputs);
139483
140020
  const envUids = await upsertEnvironments(inputs, dependencies, resourcesState, branchAssetMarker);
139484
140021
  outputs["environment-uids-json"] = JSON.stringify(envUids);
140022
+ dependencies.core.setOutput("environment-uids-json", outputs["environment-uids-json"]);
139485
140023
  if (inputs.environmentSyncEnabled && inputs.workspaceId && dependencies.internalIntegration) {
139486
140024
  const associations = Object.entries(envUids).map(([envName, envUid]) => ({
139487
140025
  envUid,
@@ -139600,6 +140138,7 @@ async function runRepoSyncInner(inputs, dependencies) {
139600
140138
  }
139601
140139
  }
139602
140140
  outputs["mock-url"] = resolvedMockUrl;
140141
+ dependencies.core.setOutput("mock-url", resolvedMockUrl);
139603
140142
  }
139604
140143
  }
139605
140144
  if (inputs.workspaceId && inputs.smokeCollectionId && Object.keys(envUids).length > 0) {
@@ -139675,6 +140214,7 @@ async function runRepoSyncInner(inputs, dependencies) {
139675
140214
  }
139676
140215
  }
139677
140216
  outputs["monitor-id"] = resolvedMonitorId;
140217
+ dependencies.core.setOutput("monitor-id", resolvedMonitorId);
139678
140218
  if (!effectiveCron && resolvedMonitorId) {
139679
140219
  try {
139680
140220
  await dependencies.postman.runMonitor(resolvedMonitorId);
@@ -139732,7 +140272,8 @@ async function runRepoSyncInner(inputs, dependencies) {
139732
140272
  priorWorkspaceId: resourcesState?.workspace?.id,
139733
140273
  existingSpecs: resourcesState?.cloudResources?.specs,
139734
140274
  releaseLabel,
139735
- priorState: resourcesState
140275
+ priorState: resourcesState,
140276
+ preparedPrebuiltCollections
139736
140277
  });
139737
140278
  const commit = await commitAndPushGeneratedFiles(inputs, dependencies);
139738
140279
  outputs["commit-sha"] = commit.commitSha;
@@ -139958,7 +140499,12 @@ async function resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, mas
139958
140499
  bifrostBaseUrl: inputs.postmanBifrostBase,
139959
140500
  // No fallback on the org-mode probe: the expected non-org 400 must
139960
140501
  // surface verbatim, not be re-fired against the /_api alias.
139961
- secretMasker: masker
140502
+ secretMasker: masker,
140503
+ onRetryEvent: (event) => {
140504
+ actionCore.info(
140505
+ `[postman retry] action=repo-sync class=${event.class} status=${event.status ?? "none"} attempt=${event.attempt} delayMs=${event.delay}`
140506
+ );
140507
+ }
139962
140508
  });
139963
140509
  const squads = await gateway.getSquads(teamId);
139964
140510
  if (squads.length > 0) {
@@ -140022,7 +140568,12 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
140022
140568
  fallbackBaseUrl: inputs.postmanFallbackBase,
140023
140569
  teamId: resolved.teamId,
140024
140570
  orgMode: inputs.orgMode,
140025
- secretMasker: masker
140571
+ secretMasker: masker,
140572
+ onRetryEvent: (event) => {
140573
+ factories.core.info(
140574
+ `[postman retry] action=repo-sync class=${event.class} status=${event.status ?? "none"} attempt=${event.attempt} delayMs=${event.delay}`
140575
+ );
140576
+ }
140026
140577
  });
140027
140578
  const gatewayAssets = new PostmanGatewayAssetsClient({
140028
140579
  gateway,
@@ -140141,7 +140692,10 @@ async function runAction(actionCore = core_exports, actionExec = exec_exports) {
140141
140692
  }
140142
140693
  await mintAccessTokenIfNeeded(inputs, {
140143
140694
  info: (message) => actionCore.info(message),
140144
- warning: (message) => actionCore.warning(message)
140695
+ warning: (message) => actionCore.warning(message),
140696
+ retryEvent: (event) => actionCore.info(
140697
+ `[postman retry] action=repo-sync class=${event.class} status=${event.status ?? "none"} attempt=${event.attempt} delayMs=${event.delay}`
140698
+ )
140145
140699
  }, (secret) => actionCore.setSecret(secret));
140146
140700
  const masker = createSecretMasker([
140147
140701
  inputs.postmanApiKey,
@@ -140162,7 +140716,12 @@ async function runAction(actionCore = core_exports, actionExec = exec_exports) {
140162
140716
  explicitTeamId: inputs.teamId || void 0,
140163
140717
  mode: inputs.credentialPreflight,
140164
140718
  mask: masker,
140165
- log: actionCore
140719
+ log: {
140720
+ ...actionCore,
140721
+ retryEvent: (event) => actionCore.info(
140722
+ `[postman retry] action=repo-sync class=${event.class} status=${event.status ?? "none"} attempt=${event.attempt} delayMs=${event.delay}`
140723
+ )
140724
+ }
140166
140725
  });
140167
140726
  const resolved = await resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, masker, {
140168
140727
  env: process.env