@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/index.cjs CHANGED
@@ -26570,7 +26570,7 @@ var require_util7 = __commonJS({
26570
26570
  exports2.esc = esc;
26571
26571
  exports2.slugify = slugify;
26572
26572
  exports2.isObject = isObject;
26573
- exports2.isPlainObject = isPlainObject2;
26573
+ exports2.isPlainObject = isPlainObject3;
26574
26574
  exports2.shallowClone = shallowClone;
26575
26575
  exports2.numKeys = numKeys;
26576
26576
  exports2.escapeRegex = escapeRegex;
@@ -26753,7 +26753,7 @@ var require_util7 = __commonJS({
26753
26753
  return false;
26754
26754
  }
26755
26755
  });
26756
- function isPlainObject2(o) {
26756
+ function isPlainObject3(o) {
26757
26757
  if (isObject(o) === false)
26758
26758
  return false;
26759
26759
  const ctor = o.constructor;
@@ -26770,7 +26770,7 @@ var require_util7 = __commonJS({
26770
26770
  return true;
26771
26771
  }
26772
26772
  function shallowClone(o) {
26773
- if (isPlainObject2(o))
26773
+ if (isPlainObject3(o))
26774
26774
  return { ...o };
26775
26775
  if (Array.isArray(o))
26776
26776
  return [...o];
@@ -26975,7 +26975,7 @@ var require_util7 = __commonJS({
26975
26975
  return clone(schema, def);
26976
26976
  }
26977
26977
  function extend(schema, shape) {
26978
- if (!isPlainObject2(shape)) {
26978
+ if (!isPlainObject3(shape)) {
26979
26979
  throw new Error("Invalid input to extend: expected a plain object");
26980
26980
  }
26981
26981
  const checks = schema._zod.def.checks;
@@ -26998,7 +26998,7 @@ var require_util7 = __commonJS({
26998
26998
  return clone(schema, def);
26999
26999
  }
27000
27000
  function safeExtend(schema, shape) {
27001
- if (!isPlainObject2(shape)) {
27001
+ if (!isPlainObject3(shape)) {
27002
27002
  throw new Error("Invalid input to safeExtend: expected a plain object");
27003
27003
  }
27004
27004
  const def = mergeDefs(schema._zod.def, {
@@ -54817,7 +54817,7 @@ var require_lodash = __commonJS({
54817
54817
  } else {
54818
54818
  newValue = [];
54819
54819
  }
54820
- } else if (isPlainObject2(srcValue) || isArguments(srcValue)) {
54820
+ } else if (isPlainObject3(srcValue) || isArguments(srcValue)) {
54821
54821
  newValue = objValue;
54822
54822
  if (isArguments(objValue)) {
54823
54823
  newValue = toPlainObject(objValue);
@@ -55781,7 +55781,7 @@ var require_lodash = __commonJS({
55781
55781
  return objValue;
55782
55782
  }
55783
55783
  function customOmitClone(value) {
55784
- return isPlainObject2(value) ? undefined2 : value;
55784
+ return isPlainObject3(value) ? undefined2 : value;
55785
55785
  }
55786
55786
  function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
55787
55787
  var isPartial = bitmask & COMPARE_PARTIAL_FLAG, arrLength = array.length, othLength = other.length;
@@ -57282,7 +57282,7 @@ var require_lodash = __commonJS({
57282
57282
  var isBuffer = nativeIsBuffer || stubFalse;
57283
57283
  var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;
57284
57284
  function isElement(value) {
57285
- return isObjectLike(value) && value.nodeType === 1 && !isPlainObject2(value);
57285
+ return isObjectLike(value) && value.nodeType === 1 && !isPlainObject3(value);
57286
57286
  }
57287
57287
  function isEmpty(value) {
57288
57288
  if (value == null) {
@@ -57318,7 +57318,7 @@ var require_lodash = __commonJS({
57318
57318
  return false;
57319
57319
  }
57320
57320
  var tag = baseGetTag(value);
57321
- return tag == errorTag || tag == domExcTag || typeof value.message == "string" && typeof value.name == "string" && !isPlainObject2(value);
57321
+ return tag == errorTag || tag == domExcTag || typeof value.message == "string" && typeof value.name == "string" && !isPlainObject3(value);
57322
57322
  }
57323
57323
  function isFinite2(value) {
57324
57324
  return typeof value == "number" && nativeIsFinite(value);
@@ -57369,7 +57369,7 @@ var require_lodash = __commonJS({
57369
57369
  function isNumber(value) {
57370
57370
  return typeof value == "number" || isObjectLike(value) && baseGetTag(value) == numberTag;
57371
57371
  }
57372
- function isPlainObject2(value) {
57372
+ function isPlainObject3(value) {
57373
57373
  if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
57374
57374
  return false;
57375
57375
  }
@@ -58440,7 +58440,7 @@ var require_lodash = __commonJS({
58440
58440
  lodash.isNumber = isNumber;
58441
58441
  lodash.isObject = isObject;
58442
58442
  lodash.isObjectLike = isObjectLike;
58443
- lodash.isPlainObject = isPlainObject2;
58443
+ lodash.isPlainObject = isPlainObject3;
58444
58444
  lodash.isRegExp = isRegExp;
58445
58445
  lodash.isSafeInteger = isSafeInteger;
58446
58446
  lodash.isSet = isSet;
@@ -128815,6 +128815,7 @@ __export(index_exports, {
128815
128815
  decideBranchTier: () => decideBranchTier,
128816
128816
  getInput: () => getInput2,
128817
128817
  hasInput: () => hasInput,
128818
+ prebuiltDirectoryTraversalIdentity: () => prebuiltDirectoryTraversalIdentity,
128818
128819
  readActionInputs: () => readActionInputs,
128819
128820
  resolveInputs: () => resolveInputs,
128820
128821
  resolvePostmanApiKeyAndTeamId: () => resolvePostmanApiKeyAndTeamId,
@@ -131103,7 +131104,8 @@ function getIDToken(aud) {
131103
131104
  }
131104
131105
 
131105
131106
  // src/index.ts
131106
- var import_node_fs4 = require("node:fs");
131107
+ var import_node_crypto4 = require("node:crypto");
131108
+ var import_node_fs5 = require("node:fs");
131107
131109
  var path8 = __toESM(require("node:path"), 1);
131108
131110
 
131109
131111
  // node_modules/js-yaml/dist/js-yaml.mjs
@@ -134019,6 +134021,7 @@ function dump(input, options = {}) {
134019
134021
  }
134020
134022
 
134021
134023
  // src/postman-v3/converter.ts
134024
+ var import_node_fs = require("node:fs");
134022
134025
  var fs3 = __toESM(require("node:fs/promises"), 1);
134023
134026
  var path6 = __toESM(require("node:path"), 1);
134024
134027
  var V2 = __toESM(require_v2(), 1);
@@ -134089,6 +134092,72 @@ function structuredCloneSafe(value) {
134089
134092
  if (typeof structuredClone === "function") return structuredClone(value);
134090
134093
  return JSON.parse(JSON.stringify(value));
134091
134094
  }
134095
+ var ArtifactDigestStreamError = class extends Error {
134096
+ code = "ARTIFACT_DIGEST_STREAM";
134097
+ constructor(message, options) {
134098
+ super(message, options);
134099
+ this.name = "ArtifactDigestStreamError";
134100
+ }
134101
+ };
134102
+ function sameFileIdentity(left, right) {
134103
+ return left.dev === right.dev && left.ino === right.ino && left.size === right.size;
134104
+ }
134105
+ async function appendArtifactDigestFileStreaming(hash, relative4, absolute, expected) {
134106
+ 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;
134107
+ let handle;
134108
+ try {
134109
+ handle = await fs3.open(absolute, flags);
134110
+ } catch (error2) {
134111
+ const code = error2?.code;
134112
+ if (code === "ELOOP" || code === "EMLINK" || code === "EINVAL") {
134113
+ throw new ArtifactDigestStreamError(
134114
+ `prebuilt collection tree file became a symlink or unsupported node at ${relative4}`,
134115
+ { cause: error2 }
134116
+ );
134117
+ }
134118
+ throw new ArtifactDigestStreamError(
134119
+ `prebuilt collection tree file changed or became unsupported at ${relative4}`,
134120
+ { cause: error2 }
134121
+ );
134122
+ }
134123
+ try {
134124
+ const before = await handle.stat();
134125
+ if (!before.isFile() || !sameFileIdentity(before, expected)) {
134126
+ throw new ArtifactDigestStreamError(
134127
+ `prebuilt collection tree file changed or became unsupported at ${relative4}`
134128
+ );
134129
+ }
134130
+ hash.update(relative4);
134131
+ hash.update("\0");
134132
+ const content = Buffer.allocUnsafe(expected.size);
134133
+ let total = 0;
134134
+ const buffer = Buffer.alloc(64 * 1024);
134135
+ for (; ; ) {
134136
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, null);
134137
+ if (bytesRead === 0) {
134138
+ break;
134139
+ }
134140
+ if (total + bytesRead > expected.size) {
134141
+ throw new ArtifactDigestStreamError(
134142
+ `prebuilt collection tree file changed while reading at ${relative4}`
134143
+ );
134144
+ }
134145
+ buffer.copy(content, total, 0, bytesRead);
134146
+ hash.update(buffer.subarray(0, bytesRead));
134147
+ total += bytesRead;
134148
+ }
134149
+ hash.update("\0");
134150
+ const after = await handle.stat();
134151
+ if (!after.isFile() || !sameFileIdentity(after, expected) || total !== expected.size) {
134152
+ throw new ArtifactDigestStreamError(
134153
+ `prebuilt collection tree file changed while reading at ${relative4}`
134154
+ );
134155
+ }
134156
+ return total === expected.size ? content : content.subarray(0, total);
134157
+ } finally {
134158
+ await handle.close();
134159
+ }
134160
+ }
134092
134161
  async function listFilesRelative(dir, base) {
134093
134162
  let entries;
134094
134163
  try {
@@ -134649,7 +134718,7 @@ function getCiWorkflowTemplate(provider, options = {}) {
134649
134718
  }
134650
134719
 
134651
134720
  // src/lib/github/repo-mutation.ts
134652
- var import_node_fs = require("node:fs");
134721
+ var import_node_fs2 = require("node:fs");
134653
134722
  var import_node_path = __toESM(require("node:path"), 1);
134654
134723
 
134655
134724
  // src/lib/secrets.ts
@@ -134939,7 +135008,7 @@ var RepoMutationService = class {
134939
135008
  throw new Error(this.secretMasker(changed.stderr || changed.stdout || "Failed to inspect generated changes"));
134940
135009
  }
134941
135010
  const hasPlannedRemoval = removePaths.some(
134942
- (removePath) => (0, import_node_fs.existsSync)(import_node_path.default.resolve(this.cwd, removePath))
135011
+ (removePath) => (0, import_node_fs2.existsSync)(import_node_path.default.resolve(this.cwd, removePath))
134943
135012
  );
134944
135013
  if (!changed.stdout.trim() && !hasPlannedRemoval) {
134945
135014
  return {
@@ -134963,7 +135032,7 @@ var RepoMutationService = class {
134963
135032
  await this.execute("git", ["config", "user.name", options.committerName]);
134964
135033
  await this.execute("git", ["config", "user.email", options.committerEmail]);
134965
135034
  for (const removePath of removePaths) {
134966
- (0, import_node_fs.rmSync)(import_node_path.default.resolve(this.cwd, removePath), { force: true });
135035
+ (0, import_node_fs2.rmSync)(import_node_path.default.resolve(this.cwd, removePath), { force: true });
134967
135036
  }
134968
135037
  await this.execute("git", ["add", "-A", "--", ...stagePaths]);
134969
135038
  const staged = await this.execute("git", ["diff", "--cached", "--quiet"]);
@@ -135506,14 +135575,14 @@ function createTelemetryContext(options) {
135506
135575
  }
135507
135576
 
135508
135577
  // src/action-version.ts
135509
- var import_node_fs2 = require("node:fs");
135578
+ var import_node_fs3 = require("node:fs");
135510
135579
  var import_node_path2 = require("node:path");
135511
135580
  function resolveActionVersion2() {
135512
135581
  if (false) {
135513
135582
  return void 0;
135514
135583
  }
135515
135584
  try {
135516
- const raw = (0, import_node_fs2.readFileSync)((0, import_node_path2.join)(__dirname, "..", "package.json"), "utf8");
135585
+ const raw = (0, import_node_fs3.readFileSync)((0, import_node_path2.join)(__dirname, "..", "package.json"), "utf8");
135517
135586
  return JSON.parse(raw).version ?? "unknown";
135518
135587
  } catch {
135519
135588
  return "unknown";
@@ -135752,7 +135821,8 @@ async function resolveSessionIdentity(opts) {
135752
135821
  opts.fetchImpl ?? fetch,
135753
135822
  Math.max(1, opts.maxAttempts ?? SESSION_MAX_ATTEMPTS),
135754
135823
  opts.sleepImpl ?? defaultSessionSleep,
135755
- opts.randomImpl ?? defaultRandom
135824
+ opts.randomImpl ?? defaultRandom,
135825
+ opts.onRetryEvent
135756
135826
  );
135757
135827
  sessionMemo.set(memoKey, pending);
135758
135828
  }
@@ -135786,7 +135856,7 @@ async function parseSessionResponse(response) {
135786
135856
  consumerType: coerceText(root.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
135787
135857
  };
135788
135858
  }
135789
- async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts, sleepImpl, random) {
135859
+ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts, sleepImpl, random, onRetryEvent) {
135790
135860
  let failure = "unavailable";
135791
135861
  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
135792
135862
  let response;
@@ -135798,7 +135868,9 @@ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts
135798
135868
  } catch {
135799
135869
  failure = "unavailable";
135800
135870
  if (attempt < maxAttempts) {
135801
- await sleepImpl(computeSessionRetryDelayMs(void 0, attempt, random));
135871
+ const delay = computeSessionRetryDelayMs(void 0, attempt, random);
135872
+ onRetryEvent?.({ class: "transport", attempt, delay });
135873
+ await sleepImpl(delay);
135802
135874
  continue;
135803
135875
  }
135804
135876
  break;
@@ -135820,7 +135892,9 @@ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts
135820
135892
  if (response.status === 429 || response.status >= 500) {
135821
135893
  failure = "unavailable";
135822
135894
  if (attempt < maxAttempts) {
135823
- await sleepImpl(computeSessionRetryDelayMs(response, attempt, random));
135895
+ const delay = computeSessionRetryDelayMs(response, attempt, random);
135896
+ onRetryEvent?.({ class: "http", status: response.status, attempt, delay });
135897
+ await sleepImpl(delay);
135824
135898
  continue;
135825
135899
  }
135826
135900
  break;
@@ -135922,7 +135996,8 @@ async function runCredentialPreflight(args) {
135922
135996
  accessToken,
135923
135997
  fetchImpl: args.fetchImpl,
135924
135998
  ...args.sleepImpl ? { sleepImpl: args.sleepImpl } : {},
135925
- ...args.randomImpl ? { randomImpl: args.randomImpl } : {}
135999
+ ...args.randomImpl ? { randomImpl: args.randomImpl } : {},
136000
+ onRetryEvent: args.retryEvent ?? args.log.retryEvent
135926
136001
  });
135927
136002
  } catch (error2) {
135928
136003
  args.log.warning(
@@ -136574,6 +136649,11 @@ var postmanRepoSyncActionContract = {
136574
136649
  description: "Contract collection ID used for exported artifacts.",
136575
136650
  required: false
136576
136651
  },
136652
+ "prebuilt-collections-json": {
136653
+ 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.",
136654
+ required: false,
136655
+ default: ""
136656
+ },
136577
136657
  "collection-sync-mode": {
136578
136658
  description: "Collection sync lifecycle mode (refresh or version).",
136579
136659
  required: false,
@@ -136816,7 +136896,7 @@ var postmanRepoSyncActionContract = {
136816
136896
  "Create or update Postman environments from runtime URLs.",
136817
136897
  "Associate Postman environments to system environments through Postman integration APIs.",
136818
136898
  "Create mock servers and smoke monitors from generated collections.",
136819
- "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.",
136899
+ "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.",
136820
136900
  "Link the Postman workspace to the repository (GitHub or GitLab) through Postman integration APIs.",
136821
136901
  "Commit synced artifacts and push them back to the current checked out ref."
136822
136902
  ],
@@ -137601,6 +137681,7 @@ var AccessTokenProvider = class {
137601
137681
  maxAttempts;
137602
137682
  onToken;
137603
137683
  sleep;
137684
+ onRetryEvent;
137604
137685
  inflight;
137605
137686
  constructor(options) {
137606
137687
  this.token = String(options.accessToken || "").trim();
@@ -137612,6 +137693,7 @@ var AccessTokenProvider = class {
137612
137693
  this.maxAttempts = Math.max(1, options.maxAttempts ?? 2);
137613
137694
  this.onToken = options.onToken;
137614
137695
  this.sleep = options.sleep;
137696
+ this.onRetryEvent = options.onRetryEvent;
137615
137697
  }
137616
137698
  current() {
137617
137699
  return this.token;
@@ -137637,7 +137719,12 @@ var AccessTokenProvider = class {
137637
137719
  delayMs: 1e3,
137638
137720
  backoffMultiplier: 2,
137639
137721
  ...this.sleep ? { sleep: this.sleep } : {},
137640
- shouldRetry: (error2) => !(error2 instanceof MintError && error2.permanent)
137722
+ shouldRetry: (error2) => !(error2 instanceof MintError && error2.permanent),
137723
+ onRetry: ({ attempt, delayMs, error: error2 }) => {
137724
+ const status = error2 instanceof MintError ? error2.status : void 0;
137725
+ const retryClass = status === void 0 ? "transport" : "http";
137726
+ this.onRetryEvent?.({ class: retryClass, ...status === void 0 ? {} : { status }, attempt, delay: Math.max(0, delayMs) });
137727
+ }
137641
137728
  });
137642
137729
  this.token = token;
137643
137730
  this.onToken?.(token);
@@ -137668,7 +137755,7 @@ var AccessTokenProvider = class {
137668
137755
  true
137669
137756
  );
137670
137757
  }
137671
- throw new MintError(`postman: re-mint failed (service-account-tokens HTTP ${status}).`, false);
137758
+ throw new MintError(`postman: re-mint failed (service-account-tokens HTTP ${status}).`, false, status);
137672
137759
  }
137673
137760
  let parsed;
137674
137761
  try {
@@ -137699,7 +137786,8 @@ async function mintAccessTokenIfNeeded(inputs, log, setSecret2, fetchImpl = fetc
137699
137786
  apiKey: inputs.postmanApiKey,
137700
137787
  apiBaseUrl,
137701
137788
  fetchImpl,
137702
- onToken: (token) => setSecret2?.(token)
137789
+ onToken: (token) => setSecret2?.(token),
137790
+ onRetryEvent: (event) => log.retryEvent?.(event)
137703
137791
  });
137704
137792
  try {
137705
137793
  inputs.postmanAccessToken = await provider.refresh();
@@ -137739,6 +137827,7 @@ var AccessTokenGatewayClient = class {
137739
137827
  requestTimeoutMs;
137740
137828
  retryMaxDelayMs;
137741
137829
  randomImpl;
137830
+ onRetryEvent;
137742
137831
  constructor(options) {
137743
137832
  this.tokenProvider = options.tokenProvider;
137744
137833
  this.bifrostBaseUrl = String(
@@ -137757,6 +137846,7 @@ var AccessTokenGatewayClient = class {
137757
137846
  this.requestTimeoutMs = options.requestTimeoutMs ?? 3e4;
137758
137847
  this.retryMaxDelayMs = options.retryMaxDelayMs ?? 5e3;
137759
137848
  this.randomImpl = options.randomImpl ?? Math.random;
137849
+ this.onRetryEvent = options.onRetryEvent;
137760
137850
  }
137761
137851
  configureTeamContext(teamId, orgMode) {
137762
137852
  this.teamId = String(teamId || "").trim();
@@ -137825,8 +137915,9 @@ var AccessTokenGatewayClient = class {
137825
137915
  if (!this.fallbackBaseUrl) return false;
137826
137916
  return retryTransient || request.fallback === "auto";
137827
137917
  }
137828
- async attemptFallback(request, retryTransient) {
137918
+ async attemptFallback(request, retryTransient, status) {
137829
137919
  if (!this.fallbackEligible(request, retryTransient)) return null;
137920
+ this.emitRetryEvent("fallback", status, 1, 0);
137830
137921
  const response = await this.tryFallback(request);
137831
137922
  if (!response) return null;
137832
137923
  if (response.ok) return response;
@@ -137852,6 +137943,7 @@ var AccessTokenGatewayClient = class {
137852
137943
  } catch (error2) {
137853
137944
  if (retryTransient && attempt < this.maxRetries) {
137854
137945
  const delay = this.retryDelayMs(attempt);
137946
+ this.emitRetryEvent("transport", void 0, attempt + 1, delay);
137855
137947
  attempt += 1;
137856
137948
  await this.sleepImpl(delay);
137857
137949
  continue;
@@ -137865,7 +137957,9 @@ var AccessTokenGatewayClient = class {
137865
137957
  const inner = this.innerStatus(okBody);
137866
137958
  if (inner !== void 0) {
137867
137959
  if (retryTransient && this.isTransient(inner, okBody) && attempt < this.maxRetries) {
137868
- await this.sleepImpl(this.retryDelayMs(attempt));
137960
+ const delay = this.retryDelayMs(attempt);
137961
+ this.emitRetryEvent("inner", inner, attempt + 1, delay);
137962
+ await this.sleepImpl(delay);
137869
137963
  attempt += 1;
137870
137964
  continue;
137871
137965
  }
@@ -137875,6 +137969,7 @@ var AccessTokenGatewayClient = class {
137875
137969
  }
137876
137970
  const body = await response.text().catch(() => "");
137877
137971
  if (isExpiredAuthError(response.status, body) && this.tokenProvider.canRefresh()) {
137972
+ this.emitRetryEvent("auth", response.status, 1, 0);
137878
137973
  await this.tokenProvider.refresh();
137879
137974
  response = await this.send(request);
137880
137975
  if (response.ok) {
@@ -137885,11 +137980,12 @@ var AccessTokenGatewayClient = class {
137885
137980
  }
137886
137981
  if (retryTransient && this.isTransient(response.status, body) && attempt < this.maxRetries) {
137887
137982
  const delay = this.retryDelayMs(attempt, parseRetryAfterMs2(response.headers.get("retry-after")));
137983
+ this.emitRetryEvent("http", response.status, attempt + 1, delay);
137888
137984
  attempt += 1;
137889
137985
  await this.sleepImpl(delay);
137890
137986
  continue;
137891
137987
  }
137892
- const fallbackResponse = await this.attemptFallback(request, retryTransient);
137988
+ const fallbackResponse = await this.attemptFallback(request, retryTransient, response.status);
137893
137989
  if (fallbackResponse) return fallbackResponse;
137894
137990
  throw this.toHttpError(request, response, body);
137895
137991
  }
@@ -137897,6 +137993,14 @@ var AccessTokenGatewayClient = class {
137897
137993
  retryDelayMs(attempt, retryAfter) {
137898
137994
  return retryAfter === void 0 ? fullJitterDelayMs(attempt, this.retryBaseDelayMs, this.retryMaxDelayMs, this.randomImpl) : Math.min(this.retryMaxDelayMs, retryAfter);
137899
137995
  }
137996
+ emitRetryEvent(retryClass, status, attempt, delay) {
137997
+ this.onRetryEvent?.({
137998
+ class: retryClass,
137999
+ ...status === void 0 ? {} : { status },
138000
+ attempt: Math.max(1, attempt),
138001
+ delay: Math.max(0, delay)
138002
+ });
138003
+ }
137900
138004
  isTransient(status, body) {
137901
138005
  return status === 408 || status === 429 || status >= 500 || /ESOCKETTIMEDOUT|ETIMEDOUT|ECONNRESET|serverError|downstream/.test(body);
137902
138006
  }
@@ -138026,7 +138130,7 @@ function validateCertMaterial(certBase64, keyBase64, passphrase) {
138026
138130
  }
138027
138131
 
138028
138132
  // src/lib/repo/branch-decision.ts
138029
- var import_node_fs3 = require("node:fs");
138133
+ var import_node_fs4 = require("node:fs");
138030
138134
  var import_node_crypto3 = require("node:crypto");
138031
138135
  var ContractError = class extends Error {
138032
138136
  code;
@@ -138067,7 +138171,7 @@ function readGithubEvent(env) {
138067
138171
  const path9 = clean(env.GITHUB_EVENT_PATH);
138068
138172
  if (!path9) return void 0;
138069
138173
  try {
138070
- return JSON.parse((0, import_node_fs3.readFileSync)(path9, "utf8"));
138174
+ return JSON.parse((0, import_node_fs4.readFileSync)(path9, "utf8"));
138071
138175
  } catch {
138072
138176
  return void 0;
138073
138177
  }
@@ -138523,6 +138627,7 @@ function resolveInputs(env = process.env) {
138523
138627
  baselineCollectionId: getInput2("baseline-collection-id", env),
138524
138628
  smokeCollectionId: getInput2("smoke-collection-id", env),
138525
138629
  contractCollectionId: getInput2("contract-collection-id", env),
138630
+ prebuiltCollectionsJson: getInput2("prebuilt-collections-json", env),
138526
138631
  specId: getInput2("spec-id", env),
138527
138632
  specContentChanged: parseBooleanInput(getInput2("spec-content-changed", env), true),
138528
138633
  specPath: getInput2("spec-path", env),
@@ -138638,7 +138743,7 @@ var StateUnreadableError = class extends Error {
138638
138743
  function readResourcesState() {
138639
138744
  let raw;
138640
138745
  try {
138641
- raw = (0, import_node_fs4.readFileSync)(".postman/resources.yaml", "utf8");
138746
+ raw = (0, import_node_fs5.readFileSync)(".postman/resources.yaml", "utf8");
138642
138747
  } catch {
138643
138748
  return null;
138644
138749
  }
@@ -138697,12 +138802,15 @@ function getEnvironmentUidsFromResources(resourcesState) {
138697
138802
  function normalizeToPosix(filePath) {
138698
138803
  return filePath.split(path8.sep).join("/").replace(/\\/g, "/");
138699
138804
  }
138805
+ function canonicalizeRelativePath(value) {
138806
+ return normalizeToPosix(String(value ?? "").trim()).replace(/^\.\/+/, "").replace(/\/{2,}/g, "/").replace(/\/+$/g, "");
138807
+ }
138700
138808
  function isOpenApiSpecFile(filePath) {
138701
138809
  if (!(filePath.endsWith(".json") || filePath.endsWith(".yaml") || filePath.endsWith(".yml"))) {
138702
138810
  return false;
138703
138811
  }
138704
138812
  try {
138705
- const raw = (0, import_node_fs4.readFileSync)(filePath, "utf8");
138813
+ const raw = (0, import_node_fs5.readFileSync)(filePath, "utf8");
138706
138814
  const parsed = filePath.endsWith(".json") ? JSON.parse(raw) : load(raw);
138707
138815
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
138708
138816
  return false;
@@ -138731,7 +138839,7 @@ function scanLocalSpecReferences(baseDir = ".") {
138731
138839
  const found = /* @__PURE__ */ new Set();
138732
138840
  const refs = [];
138733
138841
  const visit2 = (currentDir) => {
138734
- for (const entry of (0, import_node_fs4.readdirSync)(currentDir, { withFileTypes: true })) {
138842
+ for (const entry of (0, import_node_fs5.readdirSync)(currentDir, { withFileTypes: true })) {
138735
138843
  if (ignoredDirs.has(entry.name)) {
138736
138844
  continue;
138737
138845
  }
@@ -138761,7 +138869,7 @@ function resolveMappedSpecReference(explicitSpecPath, discoveredSpecs) {
138761
138869
  const normalizedExplicitPath = normalizeToPosix(explicitSpecPath.trim());
138762
138870
  if (normalizedExplicitPath) {
138763
138871
  const explicitFullPath = path8.resolve(normalizedExplicitPath);
138764
- if ((0, import_node_fs4.existsSync)(explicitFullPath) && (0, import_node_fs4.statSync)(explicitFullPath).isFile()) {
138872
+ if ((0, import_node_fs5.existsSync)(explicitFullPath) && (0, import_node_fs5.statSync)(explicitFullPath).isFile()) {
138765
138873
  return {
138766
138874
  repoRelativePath: normalizedExplicitPath,
138767
138875
  configRelativePath: normalizeToPosix(path8.join("..", normalizedExplicitPath))
@@ -138813,6 +138921,7 @@ function readActionInputs(actionCore) {
138813
138921
  INPUT_BASELINE_COLLECTION_ID: readInput(actionCore, "baseline-collection-id"),
138814
138922
  INPUT_SMOKE_COLLECTION_ID: readInput(actionCore, "smoke-collection-id"),
138815
138923
  INPUT_CONTRACT_COLLECTION_ID: readInput(actionCore, "contract-collection-id"),
138924
+ INPUT_PREBUILT_COLLECTIONS_JSON: readInput(actionCore, "prebuilt-collections-json"),
138816
138925
  INPUT_SPEC_ID: readInput(actionCore, "spec-id"),
138817
138926
  INPUT_SPEC_PATH: readInput(actionCore, "spec-path"),
138818
138927
  INPUT_COLLECTION_SYNC_MODE: readInput(actionCore, "collection-sync-mode") || "refresh",
@@ -139026,6 +139135,7 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
139026
139135
  );
139027
139136
  }
139028
139137
  envUids[envName] = existingUid;
139138
+ dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
139029
139139
  continue;
139030
139140
  }
139031
139141
  const values = buildEnvironmentValues(envName, runtimeUrl);
@@ -139036,6 +139146,7 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
139036
139146
  displayName,
139037
139147
  values
139038
139148
  );
139149
+ dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
139039
139150
  } catch (error2) {
139040
139151
  throw new Error(
139041
139152
  formatOrchestrationIssue({
@@ -139052,7 +139163,7 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
139052
139163
  return envUids;
139053
139164
  }
139054
139165
  function ensureDir(path9) {
139055
- (0, import_node_fs4.mkdirSync)(path9, { recursive: true });
139166
+ (0, import_node_fs5.mkdirSync)(path9, { recursive: true });
139056
139167
  }
139057
139168
  function getCollectionDirectoryName(kind, projectName) {
139058
139169
  if (kind === "Baseline") {
@@ -139089,7 +139200,7 @@ function stripVolatileFields(obj) {
139089
139200
  }
139090
139201
  function writeJsonFile(path9, content, normalize4 = false) {
139091
139202
  const data = normalize4 ? stripVolatileFields(content) : content;
139092
- (0, import_node_fs4.writeFileSync)(path9, JSON.stringify(data, null, 2));
139203
+ (0, import_node_fs5.writeFileSync)(path9, JSON.stringify(data, null, 2));
139093
139204
  }
139094
139205
  function buildMappedSpecCloudKey(mappedSource, specSyncMode, releaseLabel) {
139095
139206
  if (specSyncMode !== "version") {
@@ -139153,22 +139264,422 @@ function buildResourcesManifest(workspaceId, collectionMap, envMap, artifactDir,
139153
139264
  sortKeys: false
139154
139265
  });
139155
139266
  }
139156
- function buildSpecCollectionWorkflowManifest(specRef, collectionRefs) {
139157
- return dump(
139158
- {
139159
- workflows: {
139160
- syncSpecToCollection: collectionRefs.map((collectionRef) => ({
139161
- spec: specRef,
139162
- collection: collectionRef
139163
- }))
139267
+ function isPlainObject2(value) {
139268
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
139269
+ }
139270
+ function buildSpecCollectionWorkflowManifest(specRef, collectionRefs, existingRaw) {
139271
+ const pairs = collectionRefs.map((collectionRef) => ({
139272
+ spec: specRef,
139273
+ collection: collectionRef
139274
+ }));
139275
+ let root = {};
139276
+ if (typeof existingRaw === "string" && existingRaw.trim()) {
139277
+ let parsed;
139278
+ try {
139279
+ parsed = load(existingRaw);
139280
+ } catch (error2) {
139281
+ throw new Error(
139282
+ `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.`,
139283
+ { cause: error2 }
139284
+ );
139285
+ }
139286
+ if (parsed === null || parsed === void 0) {
139287
+ root = {};
139288
+ } else if (!isPlainObject2(parsed)) {
139289
+ throw new Error(
139290
+ "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."
139291
+ );
139292
+ } else {
139293
+ root = { ...parsed };
139294
+ }
139295
+ }
139296
+ const workflows = isPlainObject2(root.workflows) ? { ...root.workflows } : {};
139297
+ const desiredCollections = new Set(collectionRefs);
139298
+ const currentPairs = (Array.isArray(workflows.syncSpecToCollection) ? workflows.syncSpecToCollection : []).map((entry) => isPlainObject2(entry) ? { ...entry } : null).filter((entry) => Boolean(entry)).filter(
139299
+ (entry) => String(entry.spec ?? "") !== specRef || desiredCollections.has(String(entry.collection ?? ""))
139300
+ );
139301
+ for (const pair of pairs) {
139302
+ const index = currentPairs.findIndex(
139303
+ (entry) => String(entry.spec ?? "") === pair.spec && String(entry.collection ?? "") === pair.collection
139304
+ );
139305
+ if (index >= 0) {
139306
+ const previous = currentPairs[index];
139307
+ currentPairs[index] = { ...previous, spec: pair.spec, collection: pair.collection };
139308
+ } else {
139309
+ currentPairs.push({ spec: pair.spec, collection: pair.collection });
139310
+ }
139311
+ }
139312
+ workflows.syncSpecToCollection = currentPairs;
139313
+ root.workflows = workflows;
139314
+ return dump(root, {
139315
+ lineWidth: -1,
139316
+ noRefs: true,
139317
+ sortKeys: false
139318
+ });
139319
+ }
139320
+ var PREBUILT_COLLECTION_ROLES = /* @__PURE__ */ new Set([
139321
+ "baseline",
139322
+ "smoke",
139323
+ "contract"
139324
+ ]);
139325
+ var SHA256_HEX = /^[a-f0-9]{64}$/;
139326
+ var PREBUILT_CLOUD_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
139327
+ function failPrebuiltCollections(detail) {
139328
+ throw new Error(`CONTRACT_PREBUILT_COLLECTIONS_INVALID: ${detail}`);
139329
+ }
139330
+ function parsePrebuiltCollectionsJson(raw) {
139331
+ const trimmed = String(raw ?? "").trim();
139332
+ if (!trimmed) {
139333
+ return [];
139334
+ }
139335
+ let parsed;
139336
+ try {
139337
+ parsed = JSON.parse(trimmed);
139338
+ } catch (error2) {
139339
+ throw new Error(
139340
+ `CONTRACT_PREBUILT_COLLECTIONS_INVALID: malformed JSON (${error2 instanceof Error ? error2.message : String(error2)})`,
139341
+ { cause: error2 }
139342
+ );
139343
+ }
139344
+ let entriesRaw;
139345
+ if (Array.isArray(parsed)) {
139346
+ entriesRaw = parsed;
139347
+ } else if (isPlainObject2(parsed)) {
139348
+ if (parsed.schemaVersion !== 1) {
139349
+ failPrebuiltCollections("schemaVersion must be 1");
139350
+ }
139351
+ if (!Array.isArray(parsed.collections)) {
139352
+ failPrebuiltCollections("collections must be an array when schemaVersion is set");
139353
+ }
139354
+ entriesRaw = parsed.collections;
139355
+ } else {
139356
+ failPrebuiltCollections("expected a JSON array or {schemaVersion:1,collections:[]}");
139357
+ }
139358
+ const seenRoles = /* @__PURE__ */ new Set();
139359
+ const entries = [];
139360
+ for (const [index, value] of entriesRaw.entries()) {
139361
+ if (!isPlainObject2(value)) {
139362
+ failPrebuiltCollections(`collections[${index}] must be an object`);
139363
+ }
139364
+ const roleRaw = String(value.role ?? "").trim();
139365
+ if (!PREBUILT_COLLECTION_ROLES.has(roleRaw)) {
139366
+ failPrebuiltCollections(
139367
+ `collections[${index}].role must be one of baseline|smoke|contract`
139368
+ );
139369
+ }
139370
+ const role = roleRaw;
139371
+ if (seenRoles.has(role)) {
139372
+ failPrebuiltCollections(`duplicate role ${role}`);
139373
+ }
139374
+ seenRoles.add(role);
139375
+ const collectionPath = String(
139376
+ value.collectionPath ?? value.path ?? ""
139377
+ ).trim();
139378
+ if (!collectionPath || hasControlCharacter2(collectionPath)) {
139379
+ failPrebuiltCollections(
139380
+ `collections[${index}].collectionPath must be a non-empty confined relative path`
139381
+ );
139382
+ }
139383
+ const cloudId = String(value.cloudId ?? "").trim();
139384
+ if (!cloudId || !PREBUILT_CLOUD_ID.test(cloudId)) {
139385
+ failPrebuiltCollections(
139386
+ `collections[${index}].cloudId must be a non-empty Postman collection id`
139387
+ );
139388
+ }
139389
+ let payloadDigest;
139390
+ if (Object.prototype.hasOwnProperty.call(value, "payloadDigest")) {
139391
+ const payloadDigestRaw = value.payloadDigest;
139392
+ if (payloadDigestRaw !== void 0 && payloadDigestRaw !== null) {
139393
+ payloadDigest = String(payloadDigestRaw).trim();
139394
+ if (!SHA256_HEX.test(payloadDigest)) {
139395
+ failPrebuiltCollections(
139396
+ `collections[${index}].payloadDigest must be lowercase 64-hex`
139397
+ );
139398
+ }
139164
139399
  }
139165
- },
139166
- {
139167
- lineWidth: -1,
139168
- noRefs: true,
139169
- sortKeys: false
139170
139400
  }
139401
+ const artifactDigest = String(value.artifactDigest ?? "").trim();
139402
+ if (!SHA256_HEX.test(artifactDigest)) {
139403
+ failPrebuiltCollections(
139404
+ `collections[${index}].artifactDigest must be lowercase 64-hex`
139405
+ );
139406
+ }
139407
+ entries.push({
139408
+ role,
139409
+ collectionPath,
139410
+ cloudId,
139411
+ ...payloadDigest !== void 0 ? { payloadDigest } : {},
139412
+ artifactDigest
139413
+ });
139414
+ }
139415
+ return entries;
139416
+ }
139417
+ function assertPathWithinArtifactRoot(targetPath, artifactDir, fieldName) {
139418
+ assertPathWithinCwd(targetPath, fieldName);
139419
+ assertPathWithinCwd(artifactDir, "artifact-dir");
139420
+ const cwd = (0, import_node_fs5.realpathSync)(process.cwd());
139421
+ const artifactRoot = path8.resolve(cwd, artifactDir.trim());
139422
+ const resolved = path8.resolve(cwd, targetPath.trim());
139423
+ const relativeToArtifact = path8.relative(artifactRoot, resolved);
139424
+ if (!relativeToArtifact || relativeToArtifact.startsWith("..") || path8.isAbsolute(relativeToArtifact)) {
139425
+ failPrebuiltCollections(
139426
+ `${fieldName} must stay under artifact-dir (${artifactDir}); received ${targetPath}`
139427
+ );
139428
+ }
139429
+ let existingPath = resolved;
139430
+ while (!(0, import_node_fs5.existsSync)(existingPath)) {
139431
+ const parent = path8.dirname(existingPath);
139432
+ if (parent === existingPath) {
139433
+ break;
139434
+ }
139435
+ existingPath = parent;
139436
+ }
139437
+ const realExisting = (0, import_node_fs5.realpathSync)(existingPath);
139438
+ const realRelative = path8.relative(artifactRoot, realExisting);
139439
+ if (realRelative.startsWith("..") || path8.isAbsolute(realRelative)) {
139440
+ failPrebuiltCollections(
139441
+ `${fieldName} resolves outside artifact-dir via symlink; received ${targetPath}`
139442
+ );
139443
+ }
139444
+ return normalizeToPosix(path8.relative(cwd, resolved));
139445
+ }
139446
+ function prebuiltDirectoryTraversalIdentity(absolutePath, stats, options = {}) {
139447
+ const platform2 = options.platform ?? process.platform;
139448
+ const inodeIsZero = stats.ino === 0 || stats.ino === 0n;
139449
+ if (platform2 !== "win32" && !inodeIsZero) {
139450
+ return `${stats.dev}:${stats.ino}`;
139451
+ }
139452
+ const resolveCanonicalPath = options.resolveCanonicalPath ?? ((candidate) => import_node_fs5.realpathSync.native(candidate));
139453
+ const canonical = resolveCanonicalPath(absolutePath);
139454
+ return platform2 === "win32" ? canonical.toLowerCase() : canonical;
139455
+ }
139456
+ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
139457
+ const confined = assertPathWithinArtifactRoot(
139458
+ collectionPath,
139459
+ artifactDir,
139460
+ "prebuilt collection path"
139461
+ );
139462
+ const absRoot = path8.resolve(process.cwd(), confined);
139463
+ if (!(0, import_node_fs5.existsSync)(absRoot)) {
139464
+ return [];
139465
+ }
139466
+ let rootStat;
139467
+ try {
139468
+ rootStat = (0, import_node_fs5.lstatSync)(absRoot);
139469
+ } catch {
139470
+ return [];
139471
+ }
139472
+ if (rootStat.isSymbolicLink()) {
139473
+ failPrebuiltCollections(
139474
+ `prebuilt collection path must not be a symlink; received ${collectionPath}`
139475
+ );
139476
+ }
139477
+ if (!rootStat.isDirectory()) {
139478
+ return [];
139479
+ }
139480
+ const files = [];
139481
+ const pendingDirectories = [absRoot];
139482
+ const seenDirectories = /* @__PURE__ */ new Set();
139483
+ while (pendingDirectories.length > 0) {
139484
+ const currentAbsolute = pendingDirectories.pop();
139485
+ if (!currentAbsolute) {
139486
+ break;
139487
+ }
139488
+ const currentStat = (0, import_node_fs5.lstatSync)(currentAbsolute);
139489
+ if (currentStat.isSymbolicLink() || !currentStat.isDirectory()) {
139490
+ failPrebuiltCollections(
139491
+ `prebuilt collection tree directory changed or became unsupported at ${normalizeToPosix(path8.relative(absRoot, currentAbsolute)) || "."}`
139492
+ );
139493
+ }
139494
+ const currentKey = prebuiltDirectoryTraversalIdentity(currentAbsolute, currentStat);
139495
+ if (seenDirectories.has(currentKey)) {
139496
+ failPrebuiltCollections(
139497
+ `prebuilt collection tree directory cycle detected at ${normalizeToPosix(path8.relative(absRoot, currentAbsolute)) || "."}`
139498
+ );
139499
+ }
139500
+ seenDirectories.add(currentKey);
139501
+ const entries = (0, import_node_fs5.readdirSync)(currentAbsolute, { withFileTypes: true });
139502
+ for (const entry of entries) {
139503
+ const abs = path8.join(currentAbsolute, entry.name);
139504
+ if (entry.isSymbolicLink()) {
139505
+ failPrebuiltCollections(
139506
+ `prebuilt collection tree must not contain symlinks; received ${normalizeToPosix(path8.relative(absRoot, abs))}`
139507
+ );
139508
+ }
139509
+ if (entry.isDirectory()) {
139510
+ pendingDirectories.push(abs);
139511
+ continue;
139512
+ }
139513
+ if (!entry.isFile()) {
139514
+ failPrebuiltCollections(
139515
+ `prebuilt collection tree contains unsupported entry type at ${normalizeToPosix(path8.relative(absRoot, abs))}`
139516
+ );
139517
+ }
139518
+ const fileLstat = (0, import_node_fs5.lstatSync)(abs);
139519
+ if (fileLstat.isSymbolicLink() || !fileLstat.isFile()) {
139520
+ failPrebuiltCollections(
139521
+ `prebuilt collection tree file changed or became unsupported at ${normalizeToPosix(path8.relative(absRoot, abs))}`
139522
+ );
139523
+ }
139524
+ files.push({
139525
+ absolute: abs,
139526
+ relative: normalizeToPosix(path8.relative(absRoot, abs)),
139527
+ dev: fileLstat.dev,
139528
+ ino: fileLstat.ino,
139529
+ size: fileLstat.size
139530
+ });
139531
+ }
139532
+ }
139533
+ files.sort((a, b) => a.relative.localeCompare(b.relative));
139534
+ return files;
139535
+ }
139536
+ function validateCanonicalV3CollectionFile(relative4, bytes) {
139537
+ let expectedKind;
139538
+ if (/(^|\/)\.resources\/definition\.yaml$/.test(relative4)) {
139539
+ expectedKind = "collection";
139540
+ } else if (relative4.endsWith(".request.yaml")) {
139541
+ expectedKind = "request";
139542
+ } else if (relative4.endsWith(".example.yaml")) {
139543
+ expectedKind = "example";
139544
+ } else if (relative4.endsWith(".message.yaml")) {
139545
+ expectedKind = "message";
139546
+ } else {
139547
+ failPrebuiltCollections(`prebuilt collection tree contains unexpected file ${relative4}`);
139548
+ }
139549
+ let parsed;
139550
+ try {
139551
+ parsed = load(bytes.toString("utf8"));
139552
+ } catch (error2) {
139553
+ failPrebuiltCollections(
139554
+ `prebuilt collection tree contains malformed YAML at ${relative4} (${error2 instanceof Error ? error2.message : String(error2)})`
139555
+ );
139556
+ }
139557
+ if (!isPlainObject2(parsed)) {
139558
+ failPrebuiltCollections(`prebuilt collection tree file ${relative4} must contain a YAML mapping`);
139559
+ }
139560
+ const kind = typeof parsed.$kind === "string" ? parsed.$kind.trim() : "";
139561
+ if (!kind) {
139562
+ failPrebuiltCollections(`prebuilt collection tree file ${relative4} must contain a nonempty $kind`);
139563
+ }
139564
+ const agrees = expectedKind === "collection" ? kind === "collection" : kind.endsWith(`-${expectedKind}`);
139565
+ if (!agrees) {
139566
+ failPrebuiltCollections(
139567
+ `prebuilt collection tree file ${relative4} has $kind ${kind} inconsistent with its filename`
139568
+ );
139569
+ }
139570
+ }
139571
+ async function digestAndValidatePrebuiltCollectionTree(files) {
139572
+ if (!files.some((file) => file.relative === ".resources/definition.yaml")) {
139573
+ failPrebuiltCollections("prebuilt collection tree is missing .resources/definition.yaml");
139574
+ }
139575
+ const hash = (0, import_node_crypto4.createHash)("sha256");
139576
+ for (const file of files) {
139577
+ let bytes;
139578
+ try {
139579
+ bytes = await appendArtifactDigestFileStreaming(hash, file.relative, file.absolute, {
139580
+ dev: file.dev,
139581
+ ino: file.ino,
139582
+ size: file.size
139583
+ });
139584
+ } catch (error2) {
139585
+ if (error2 instanceof ArtifactDigestStreamError) {
139586
+ failPrebuiltCollections(error2.message);
139587
+ }
139588
+ const code = error2?.code;
139589
+ if (code === "ELOOP" || code === "EPERM") {
139590
+ failPrebuiltCollections(
139591
+ `prebuilt collection tree file became a symlink or unsupported node at ${file.relative}`
139592
+ );
139593
+ }
139594
+ failPrebuiltCollections(
139595
+ `prebuilt collection tree file changed or became unsupported at ${file.relative}`
139596
+ );
139597
+ }
139598
+ validateCanonicalV3CollectionFile(file.relative, bytes);
139599
+ }
139600
+ return hash.digest("hex");
139601
+ }
139602
+ async function preparePrebuiltCollections(inputs) {
139603
+ const prepared = /* @__PURE__ */ new Map();
139604
+ for (const entry of parsePrebuiltCollectionsJson(inputs.prebuiltCollectionsJson ?? "")) {
139605
+ const confinedPath = assertPathWithinArtifactRoot(
139606
+ entry.collectionPath,
139607
+ inputs.artifactDir,
139608
+ `prebuilt ${entry.role} collection path`
139609
+ );
139610
+ const absolute = path8.resolve(process.cwd(), confinedPath);
139611
+ if (!(0, import_node_fs5.existsSync)(absolute)) {
139612
+ prepared.set(entry.role, { entry, confinedPath });
139613
+ continue;
139614
+ }
139615
+ const files = listPrebuiltCollectionTreeFiles(confinedPath, inputs.artifactDir);
139616
+ const artifactDigest = await digestAndValidatePrebuiltCollectionTree(files);
139617
+ prepared.set(entry.role, {
139618
+ entry,
139619
+ confinedPath,
139620
+ artifactDigest
139621
+ });
139622
+ }
139623
+ return prepared;
139624
+ }
139625
+ function tryReusePrebuiltCollection(options) {
139626
+ const { prepared, expectedPath, expectedCloudId } = options;
139627
+ const { entry } = prepared;
139628
+ if (!expectedCloudId || entry.cloudId !== expectedCloudId) {
139629
+ return false;
139630
+ }
139631
+ const expectedNormalized = canonicalizeRelativePath(expectedPath);
139632
+ const entryNormalized = canonicalizeRelativePath(entry.collectionPath);
139633
+ if (entryNormalized !== expectedNormalized) {
139634
+ return false;
139635
+ }
139636
+ const confined = canonicalizeRelativePath(prepared.confinedPath);
139637
+ if (confined !== expectedNormalized) {
139638
+ return false;
139639
+ }
139640
+ const expectedName = path8.posix.basename(expectedNormalized);
139641
+ if (path8.posix.basename(confined) !== expectedName) {
139642
+ return false;
139643
+ }
139644
+ return prepared.artifactDigest === entry.artifactDigest;
139645
+ }
139646
+ async function exportCollectionArtifact(options) {
139647
+ const {
139648
+ role,
139649
+ collectionId,
139650
+ dirName,
139651
+ collectionsDir,
139652
+ prebuiltByRole,
139653
+ postman,
139654
+ core
139655
+ } = options;
139656
+ if (!collectionId) {
139657
+ return void 0;
139658
+ }
139659
+ const expectedPath = `${collectionsDir}/${dirName}`;
139660
+ const entry = prebuiltByRole.get(role);
139661
+ if (entry) {
139662
+ const reused = tryReusePrebuiltCollection({
139663
+ prepared: entry,
139664
+ expectedPath,
139665
+ expectedCloudId: collectionId
139666
+ });
139667
+ if (reused) {
139668
+ core.info(
139669
+ `Reusing prebuilt ${role} collection tree at ${expectedPath} (artifactDigest match)`
139670
+ );
139671
+ return `../${expectedPath}`;
139672
+ }
139673
+ core.info(
139674
+ `Prebuilt ${role} collection entry present but did not exactly match; exporting from cloud`
139675
+ );
139676
+ }
139677
+ const col = await postman.getCollection(collectionId);
139678
+ await convertAndSplitAnyCollection(
139679
+ col,
139680
+ expectedPath
139171
139681
  );
139682
+ return `../${expectedPath}`;
139172
139683
  }
139173
139684
  function hasControlCharacter2(value) {
139174
139685
  for (let index = 0; index < value.length; index += 1) {
@@ -139186,21 +139697,21 @@ function assertPathWithinCwd(targetPath, fieldName) {
139186
139697
  if (!rawPath || hasControlCharacter2(originalPath) || path8.isAbsolute(rawPath) || path8.win32.isAbsolute(rawPath) || segments.includes("..") || rawPath.startsWith(":") || hasControlCharacter2(rawPath)) {
139187
139698
  throw new Error(`${fieldName} must stay within the repository root; received ${targetPath}`);
139188
139699
  }
139189
- const base = (0, import_node_fs4.realpathSync)(process.cwd());
139700
+ const base = (0, import_node_fs5.realpathSync)(process.cwd());
139190
139701
  const resolved = path8.resolve(base, rawPath);
139191
139702
  const relative4 = path8.relative(base, resolved);
139192
139703
  if (relative4.startsWith("..") || path8.isAbsolute(relative4)) {
139193
139704
  throw new Error(`${fieldName} must stay within the repository root; received ${targetPath}`);
139194
139705
  }
139195
139706
  let existingPath = resolved;
139196
- while (!(0, import_node_fs4.existsSync)(existingPath)) {
139707
+ while (!(0, import_node_fs5.existsSync)(existingPath)) {
139197
139708
  const parent = path8.dirname(existingPath);
139198
139709
  if (parent === existingPath) {
139199
139710
  break;
139200
139711
  }
139201
139712
  existingPath = parent;
139202
139713
  }
139203
- const realExistingPath = (0, import_node_fs4.realpathSync)(existingPath);
139714
+ const realExistingPath = (0, import_node_fs5.realpathSync)(existingPath);
139204
139715
  const realRelative = path8.relative(base, realExistingPath);
139205
139716
  if (realRelative.startsWith("..") || path8.isAbsolute(realRelative)) {
139206
139717
  throw new Error(`${fieldName} must stay within the repository root; received ${targetPath}`);
@@ -139228,8 +139739,8 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
139228
139739
  ensureDir(specsDir);
139229
139740
  ensureDir(".postman");
139230
139741
  const globalsFilePath = `${globalsDir}/workspace.globals.yaml`;
139231
- if (!(0, import_node_fs4.existsSync)(globalsFilePath)) {
139232
- (0, import_node_fs4.writeFileSync)(globalsFilePath, "name: Globals\nvalues: []\n");
139742
+ if (!(0, import_node_fs5.existsSync)(globalsFilePath)) {
139743
+ (0, import_node_fs5.writeFileSync)(globalsFilePath, "name: Globals\nvalues: []\n");
139233
139744
  }
139234
139745
  if (inputs.generateCiWorkflow) {
139235
139746
  const ciDir = inputs.ciWorkflowPath.split("/").slice(0, -1).join("/");
@@ -139245,23 +139756,42 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
139245
139756
  inputs.specSyncMode,
139246
139757
  options.releaseLabel
139247
139758
  ) : void 0;
139248
- if (inputs.baselineCollectionId) {
139249
- const col = await dependencies.postman.getCollection(inputs.baselineCollectionId);
139250
- const dirName = getCollectionDirectoryName("Baseline", assetProjectName);
139251
- await convertAndSplitAnyCollection(col, `${collectionsDir}/${dirName}`);
139252
- manifestCollections[`../${collectionsDir}/${dirName}`] = inputs.baselineCollectionId;
139253
- }
139254
- if (inputs.smokeCollectionId) {
139255
- const col = await dependencies.postman.getCollection(inputs.smokeCollectionId);
139256
- const dirName = getCollectionDirectoryName("Smoke", assetProjectName);
139257
- await convertAndSplitAnyCollection(col, `${collectionsDir}/${dirName}`);
139258
- manifestCollections[`../${collectionsDir}/${dirName}`] = inputs.smokeCollectionId;
139259
- }
139260
- if (inputs.contractCollectionId) {
139261
- const col = await dependencies.postman.getCollection(inputs.contractCollectionId);
139262
- const dirName = getCollectionDirectoryName("Contract", assetProjectName);
139263
- await convertAndSplitAnyCollection(col, `${collectionsDir}/${dirName}`);
139264
- manifestCollections[`../${collectionsDir}/${dirName}`] = inputs.contractCollectionId;
139759
+ const prebuiltByRole = options.preparedPrebuiltCollections;
139760
+ const baselineRef = await exportCollectionArtifact({
139761
+ role: "baseline",
139762
+ collectionId: inputs.baselineCollectionId,
139763
+ dirName: getCollectionDirectoryName("Baseline", assetProjectName),
139764
+ collectionsDir,
139765
+ prebuiltByRole,
139766
+ postman: dependencies.postman,
139767
+ core: dependencies.core
139768
+ });
139769
+ if (baselineRef) {
139770
+ manifestCollections[baselineRef] = inputs.baselineCollectionId;
139771
+ }
139772
+ const smokeRef = await exportCollectionArtifact({
139773
+ role: "smoke",
139774
+ collectionId: inputs.smokeCollectionId,
139775
+ dirName: getCollectionDirectoryName("Smoke", assetProjectName),
139776
+ collectionsDir,
139777
+ prebuiltByRole,
139778
+ postman: dependencies.postman,
139779
+ core: dependencies.core
139780
+ });
139781
+ if (smokeRef) {
139782
+ manifestCollections[smokeRef] = inputs.smokeCollectionId;
139783
+ }
139784
+ const contractRef = await exportCollectionArtifact({
139785
+ role: "contract",
139786
+ collectionId: inputs.contractCollectionId,
139787
+ dirName: getCollectionDirectoryName("Contract", assetProjectName),
139788
+ collectionsDir,
139789
+ prebuiltByRole,
139790
+ postman: dependencies.postman,
139791
+ core: dependencies.core
139792
+ });
139793
+ if (contractRef) {
139794
+ manifestCollections[contractRef] = inputs.contractCollectionId;
139265
139795
  }
139266
139796
  for (const [envName, envUid] of Object.entries(envUids)) {
139267
139797
  writeJsonFile(
@@ -139276,7 +139806,7 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
139276
139806
  workspaceLinkEnabled: inputs.workspaceLinkEnabled,
139277
139807
  workspaceLinkStatus: options.workspaceLinkStatus
139278
139808
  });
139279
- (0, import_node_fs4.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
139809
+ (0, import_node_fs5.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
139280
139810
  durableWorkspaceId,
139281
139811
  manifestCollections,
139282
139812
  envUids,
@@ -139288,11 +139818,18 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
139288
139818
  options.priorState
139289
139819
  ));
139290
139820
  if (mappedSpec && Object.keys(manifestCollections).length > 0) {
139291
- (0, import_node_fs4.writeFileSync)(
139821
+ let existingWorkflows;
139822
+ try {
139823
+ existingWorkflows = (0, import_node_fs5.readFileSync)(".postman/workflows.yaml", "utf8");
139824
+ } catch {
139825
+ existingWorkflows = void 0;
139826
+ }
139827
+ (0, import_node_fs5.writeFileSync)(
139292
139828
  ".postman/workflows.yaml",
139293
139829
  buildSpecCollectionWorkflowManifest(
139294
139830
  mappedSpec.configRelativePath,
139295
- Object.keys(manifestCollections)
139831
+ Object.keys(manifestCollections),
139832
+ existingWorkflows
139296
139833
  )
139297
139834
  );
139298
139835
  }
@@ -139337,12 +139874,12 @@ async function commitAndPushGeneratedFiles(inputs, dependencies) {
139337
139874
  const dir = parts.slice(0, -1).join("/");
139338
139875
  ensureDir(dir);
139339
139876
  }
139340
- (0, import_node_fs4.writeFileSync)(inputs.ciWorkflowPath, ciWorkflow);
139877
+ (0, import_node_fs5.writeFileSync)(inputs.ciWorkflowPath, ciWorkflow);
139341
139878
  if (inputs.provider === "github" || inputs.provider === "unknown") {
139342
139879
  const gcPath = ".github/workflows/postman-preview-gc.yml";
139343
139880
  if (inputs.ciWorkflowPath.endsWith(".github/workflows/ci.yml") || inputs.ciWorkflowPath === ".github/workflows/ci.yml") {
139344
139881
  ensureDir(".github/workflows");
139345
- (0, import_node_fs4.writeFileSync)(gcPath, renderGcWorkflowTemplate());
139882
+ (0, import_node_fs5.writeFileSync)(gcPath, renderGcWorkflowTemplate());
139346
139883
  }
139347
139884
  }
139348
139885
  }
@@ -139350,16 +139887,16 @@ async function commitAndPushGeneratedFiles(inputs, dependencies) {
139350
139887
  return { commitSha: "", resolvedCurrentRef: "", pushed: false };
139351
139888
  }
139352
139889
  const provisionPath = ".github/workflows/provision.yml";
139353
- const provisionExists = inputs.provider === "github" && (0, import_node_fs4.existsSync)(provisionPath);
139890
+ const provisionExists = inputs.provider === "github" && (0, import_node_fs5.existsSync)(provisionPath);
139354
139891
  const gcWorkflowPath = ".github/workflows/postman-preview-gc.yml";
139355
- const gcExists = inputs.generateCiWorkflow && (0, import_node_fs4.existsSync)(gcWorkflowPath);
139892
+ const gcExists = inputs.generateCiWorkflow && (0, import_node_fs5.existsSync)(gcWorkflowPath);
139356
139893
  const stagePaths = [
139357
139894
  inputs.artifactDir,
139358
139895
  ".postman",
139359
139896
  inputs.generateCiWorkflow ? inputs.ciWorkflowPath : null,
139360
139897
  gcExists ? gcWorkflowPath : null,
139361
139898
  provisionExists ? provisionPath : null
139362
- ].filter((entry) => typeof entry === "string" && ((0, import_node_fs4.existsSync)(entry) || entry === provisionPath));
139899
+ ].filter((entry) => typeof entry === "string" && ((0, import_node_fs5.existsSync)(entry) || entry === provisionPath));
139363
139900
  if (stagePaths.length === 0) {
139364
139901
  dependencies.core.info("No generated repository paths were found; skipping repo mutation.");
139365
139902
  return {
@@ -139467,6 +140004,7 @@ async function runRepoSyncInner(inputs, dependencies) {
139467
140004
  }
139468
140005
  }
139469
140006
  }
140007
+ const preparedPrebuiltCollections = await preparePrebuiltCollections(inputs);
139470
140008
  let skipRepositoryLinkPost = false;
139471
140009
  let repositoryLinkPreflightWasFree = false;
139472
140010
  if (inputs.workspaceLinkEnabled && inputs.workspaceId && inputs.repoUrl && dependencies.internalIntegration?.findWorkspaceForRepo) {
@@ -139503,6 +140041,7 @@ async function runRepoSyncInner(inputs, dependencies) {
139503
140041
  const branchAssetMarker = buildBranchAssetMarker(branchDecision, inputs);
139504
140042
  const envUids = await upsertEnvironments(inputs, dependencies, resourcesState, branchAssetMarker);
139505
140043
  outputs["environment-uids-json"] = JSON.stringify(envUids);
140044
+ dependencies.core.setOutput("environment-uids-json", outputs["environment-uids-json"]);
139506
140045
  if (inputs.environmentSyncEnabled && inputs.workspaceId && dependencies.internalIntegration) {
139507
140046
  const associations = Object.entries(envUids).map(([envName, envUid]) => ({
139508
140047
  envUid,
@@ -139621,6 +140160,7 @@ async function runRepoSyncInner(inputs, dependencies) {
139621
140160
  }
139622
140161
  }
139623
140162
  outputs["mock-url"] = resolvedMockUrl;
140163
+ dependencies.core.setOutput("mock-url", resolvedMockUrl);
139624
140164
  }
139625
140165
  }
139626
140166
  if (inputs.workspaceId && inputs.smokeCollectionId && Object.keys(envUids).length > 0) {
@@ -139696,6 +140236,7 @@ async function runRepoSyncInner(inputs, dependencies) {
139696
140236
  }
139697
140237
  }
139698
140238
  outputs["monitor-id"] = resolvedMonitorId;
140239
+ dependencies.core.setOutput("monitor-id", resolvedMonitorId);
139699
140240
  if (!effectiveCron && resolvedMonitorId) {
139700
140241
  try {
139701
140242
  await dependencies.postman.runMonitor(resolvedMonitorId);
@@ -139753,7 +140294,8 @@ async function runRepoSyncInner(inputs, dependencies) {
139753
140294
  priorWorkspaceId: resourcesState?.workspace?.id,
139754
140295
  existingSpecs: resourcesState?.cloudResources?.specs,
139755
140296
  releaseLabel,
139756
- priorState: resourcesState
140297
+ priorState: resourcesState,
140298
+ preparedPrebuiltCollections
139757
140299
  });
139758
140300
  const commit = await commitAndPushGeneratedFiles(inputs, dependencies);
139759
140301
  outputs["commit-sha"] = commit.commitSha;
@@ -139979,7 +140521,12 @@ async function resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, mas
139979
140521
  bifrostBaseUrl: inputs.postmanBifrostBase,
139980
140522
  // No fallback on the org-mode probe: the expected non-org 400 must
139981
140523
  // surface verbatim, not be re-fired against the /_api alias.
139982
- secretMasker: masker
140524
+ secretMasker: masker,
140525
+ onRetryEvent: (event) => {
140526
+ actionCore.info(
140527
+ `[postman retry] action=repo-sync class=${event.class} status=${event.status ?? "none"} attempt=${event.attempt} delayMs=${event.delay}`
140528
+ );
140529
+ }
139983
140530
  });
139984
140531
  const squads = await gateway.getSquads(teamId);
139985
140532
  if (squads.length > 0) {
@@ -140043,7 +140590,12 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
140043
140590
  fallbackBaseUrl: inputs.postmanFallbackBase,
140044
140591
  teamId: resolved.teamId,
140045
140592
  orgMode: inputs.orgMode,
140046
- secretMasker: masker
140593
+ secretMasker: masker,
140594
+ onRetryEvent: (event) => {
140595
+ factories.core.info(
140596
+ `[postman retry] action=repo-sync class=${event.class} status=${event.status ?? "none"} attempt=${event.attempt} delayMs=${event.delay}`
140597
+ );
140598
+ }
140047
140599
  });
140048
140600
  const gatewayAssets = new PostmanGatewayAssetsClient({
140049
140601
  gateway,
@@ -140162,7 +140714,10 @@ async function runAction(actionCore = core_exports, actionExec = exec_exports) {
140162
140714
  }
140163
140715
  await mintAccessTokenIfNeeded(inputs, {
140164
140716
  info: (message) => actionCore.info(message),
140165
- warning: (message) => actionCore.warning(message)
140717
+ warning: (message) => actionCore.warning(message),
140718
+ retryEvent: (event) => actionCore.info(
140719
+ `[postman retry] action=repo-sync class=${event.class} status=${event.status ?? "none"} attempt=${event.attempt} delayMs=${event.delay}`
140720
+ )
140166
140721
  }, (secret) => actionCore.setSecret(secret));
140167
140722
  const masker = createSecretMasker([
140168
140723
  inputs.postmanApiKey,
@@ -140183,7 +140738,12 @@ async function runAction(actionCore = core_exports, actionExec = exec_exports) {
140183
140738
  explicitTeamId: inputs.teamId || void 0,
140184
140739
  mode: inputs.credentialPreflight,
140185
140740
  mask: masker,
140186
- log: actionCore
140741
+ log: {
140742
+ ...actionCore,
140743
+ retryEvent: (event) => actionCore.info(
140744
+ `[postman retry] action=repo-sync class=${event.class} status=${event.status ?? "none"} attempt=${event.attempt} delayMs=${event.delay}`
140745
+ )
140746
+ }
140187
140747
  });
140188
140748
  const resolved = await resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, masker, {
140189
140749
  env: process.env
@@ -140224,6 +140784,7 @@ async function runAction(actionCore = core_exports, actionExec = exec_exports) {
140224
140784
  decideBranchTier,
140225
140785
  getInput,
140226
140786
  hasInput,
140787
+ prebuiltDirectoryTraversalIdentity,
140227
140788
  readActionInputs,
140228
140789
  resolveInputs,
140229
140790
  resolvePostmanApiKeyAndTeamId,