@postman-cse/onboarding-repo-sync 2.1.10 → 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
@@ -19746,7 +19746,7 @@ var require_response = __commonJS({
19746
19746
  var assert = require("node:assert");
19747
19747
  var { isomorphicEncode, serializeJavascriptValueToJSONString } = require_infra();
19748
19748
  var textEncoder = new TextEncoder("utf-8");
19749
- var Response = class _Response {
19749
+ var Response2 = class _Response {
19750
19750
  /** @type {Headers} */
19751
19751
  #headers;
19752
19752
  #state;
@@ -19916,13 +19916,13 @@ var require_response = __commonJS({
19916
19916
  response.#state = newState;
19917
19917
  }
19918
19918
  };
19919
- var { getResponseHeaders, setResponseHeaders, getResponseState, setResponseState } = Response;
19920
- Reflect.deleteProperty(Response, "getResponseHeaders");
19921
- Reflect.deleteProperty(Response, "setResponseHeaders");
19922
- Reflect.deleteProperty(Response, "getResponseState");
19923
- Reflect.deleteProperty(Response, "setResponseState");
19924
- mixinBody(Response, getResponseState);
19925
- Object.defineProperties(Response.prototype, {
19919
+ var { getResponseHeaders, setResponseHeaders, getResponseState, setResponseState } = Response2;
19920
+ Reflect.deleteProperty(Response2, "getResponseHeaders");
19921
+ Reflect.deleteProperty(Response2, "setResponseHeaders");
19922
+ Reflect.deleteProperty(Response2, "getResponseState");
19923
+ Reflect.deleteProperty(Response2, "setResponseState");
19924
+ mixinBody(Response2, getResponseState);
19925
+ Object.defineProperties(Response2.prototype, {
19926
19926
  type: kEnumerableProperty,
19927
19927
  url: kEnumerableProperty,
19928
19928
  status: kEnumerableProperty,
@@ -19938,7 +19938,7 @@ var require_response = __commonJS({
19938
19938
  configurable: true
19939
19939
  }
19940
19940
  });
19941
- Object.defineProperties(Response, {
19941
+ Object.defineProperties(Response2, {
19942
19942
  json: kEnumerableProperty,
19943
19943
  redirect: kEnumerableProperty,
19944
19944
  error: kEnumerableProperty
@@ -20071,7 +20071,7 @@ var require_response = __commonJS({
20071
20071
  }
20072
20072
  }
20073
20073
  function fromInnerResponse(innerResponse, guard) {
20074
- const response = new Response(kConstruct);
20074
+ const response = new Response2(kConstruct);
20075
20075
  setResponseState(response, innerResponse);
20076
20076
  const headers = new Headers3(kConstruct);
20077
20077
  setResponseHeaders(response, headers);
@@ -20125,14 +20125,14 @@ var require_response = __commonJS({
20125
20125
  converter: webidl.converters.HeadersInit
20126
20126
  }
20127
20127
  ]);
20128
- webidl.is.Response = webidl.util.MakeTypeAssertion(Response);
20128
+ webidl.is.Response = webidl.util.MakeTypeAssertion(Response2);
20129
20129
  module2.exports = {
20130
20130
  isNetworkError,
20131
20131
  makeNetworkError,
20132
20132
  makeResponse,
20133
20133
  makeAppropriateNetworkError,
20134
20134
  filterResponse,
20135
- Response,
20135
+ Response: Response2,
20136
20136
  cloneResponse,
20137
20137
  fromInnerResponse,
20138
20138
  getResponseState
@@ -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;
@@ -99440,7 +99440,7 @@ var require_response2 = __commonJS({
99440
99440
  }
99441
99441
  return stream;
99442
99442
  };
99443
- var Response;
99443
+ var Response2;
99444
99444
  _.inherit(
99445
99445
  /**
99446
99446
  * Response holds data related to the request body. By default, it provides a nice wrapper for url-encoded,
@@ -99451,14 +99451,14 @@ var require_response2 = __commonJS({
99451
99451
  *
99452
99452
  * @param {Response.definition} options -
99453
99453
  */
99454
- Response = function PostmanResponse(options) {
99455
- Response.super_.apply(this, arguments);
99454
+ Response2 = function PostmanResponse(options) {
99455
+ Response2.super_.apply(this, arguments);
99456
99456
  this.update(options || {});
99457
99457
  },
99458
99458
  Property
99459
99459
  );
99460
99460
  _.assign(
99461
- Response.prototype,
99461
+ Response2.prototype,
99462
99462
  /** @lends Response.prototype */
99463
99463
  {
99464
99464
  update(options) {
@@ -99524,7 +99524,7 @@ var require_response2 = __commonJS({
99524
99524
  }
99525
99525
  );
99526
99526
  _.assign(
99527
- Response.prototype,
99527
+ Response2.prototype,
99528
99528
  /** @lends Response.prototype */
99529
99529
  {
99530
99530
  /**
@@ -99702,7 +99702,7 @@ var require_response2 = __commonJS({
99702
99702
  }
99703
99703
  );
99704
99704
  _.assign(
99705
- Response,
99705
+ Response2,
99706
99706
  /** @lends Response */
99707
99707
  {
99708
99708
  /**
@@ -99720,7 +99720,7 @@ var require_response2 = __commonJS({
99720
99720
  * @returns {Boolean}
99721
99721
  */
99722
99722
  isResponse: function(obj) {
99723
- return Boolean(obj) && (obj instanceof Response || _.inSuperChain(obj.constructor, "_postman_propertyName", Response._postman_propertyName));
99723
+ return Boolean(obj) && (obj instanceof Response2 || _.inSuperChain(obj.constructor, "_postman_propertyName", Response2._postman_propertyName));
99724
99724
  },
99725
99725
  /**
99726
99726
  * Converts the response object from the request module to the postman responseBody format
@@ -99731,7 +99731,7 @@ var require_response2 = __commonJS({
99731
99731
  * @todo Add a key: `originalRequest` to the returned object as well, referring to response.request
99732
99732
  */
99733
99733
  createFromNode: function(response, cookies) {
99734
- return new Response({
99734
+ return new Response2({
99735
99735
  cookie: cookies,
99736
99736
  body: response.body.toString(),
99737
99737
  stream: response.body,
@@ -99810,7 +99810,7 @@ var require_response2 = __commonJS({
99810
99810
  }
99811
99811
  );
99812
99812
  module2.exports = {
99813
- Response
99813
+ Response: Response2
99814
99814
  };
99815
99815
  }
99816
99816
  });
@@ -99824,7 +99824,7 @@ var require_item = __commonJS({
99824
99824
  var EventList = require_event_list().EventList;
99825
99825
  var Request = require_request13().Request;
99826
99826
  var RequestAuth = require_request_auth().RequestAuth;
99827
- var Response = require_response2().Response;
99827
+ var Response2 = require_response2().Response;
99828
99828
  var Item;
99829
99829
  var OBJECT = "object";
99830
99830
  var STRING = "string";
@@ -99891,7 +99891,7 @@ var require_item = __commonJS({
99891
99891
  *
99892
99892
  * @type {PropertyList<Response>}
99893
99893
  */
99894
- responses: new PropertyList(Response, this, definition && definition.response),
99894
+ responses: new PropertyList(Response2, this, definition && definition.response),
99895
99895
  /**
99896
99896
  * Events are a set of of {@link Script}s that are executed when certain activities are triggered on an
99897
99897
  * Item. For example, on defining an event that listens to the "test" event, would cause the associated
@@ -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";
@@ -135578,6 +135647,54 @@ var HttpError = class _HttpError extends Error {
135578
135647
  }
135579
135648
  };
135580
135649
 
135650
+ // src/lib/postman/pmak-diagnostics.ts
135651
+ var memo = /* @__PURE__ */ new Map();
135652
+ var normalize3 = (value) => new URL(value.trim()).toString().replace(/\/+$/, "");
135653
+ function maskPmakDiagnostic(message, secrets) {
135654
+ let masked = String(message);
135655
+ for (const secret of secrets) if (secret) masked = masked.split(secret).join("***");
135656
+ return Array.from(masked, (character) => {
135657
+ const code = character.codePointAt(0) ?? 0;
135658
+ return code <= 31 || code >= 127 && code <= 159 ? " " : character;
135659
+ }).join("").replace(/\s+/g, " ").trim();
135660
+ }
135661
+ function formatRejectedMint(original, result) {
135662
+ const teamId = typeof result.payload?.user?.teamId === "number" ? ` (team ${(result.payload?.user).teamId})` : "";
135663
+ if (result.kind === "personal") return `Personal API key detected, cannot mint a service-account access token${teamId}.`;
135664
+ if (result.kind === "service-account") return `The postman-api-key authenticates (GET /me OK) but was rejected by POST /service-account-tokens${teamId} and lacks permission to mint access tokens.`;
135665
+ if (result.kind === "invalid") return "The postman-api-key is invalid, disabled, or expired.";
135666
+ return original;
135667
+ }
135668
+ async function inspectPmakIdentity(options) {
135669
+ const apiBaseUrl = normalize3(options.apiBaseUrl);
135670
+ const key = `${apiBaseUrl}\0${options.apiKey}`;
135671
+ let pending = memo.get(key);
135672
+ if (!pending) {
135673
+ pending = (async () => {
135674
+ try {
135675
+ const timeout = AbortSignal.timeout(options.timeoutMs ?? 2e3);
135676
+ const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;
135677
+ const response = await (options.fetchImpl ?? fetch)(`${apiBaseUrl}/me`, { method: "GET", headers: { "X-Api-Key": options.apiKey }, signal });
135678
+ if (response.status === 401 || response.status === 403) return { kind: "invalid", status: response.status };
135679
+ if (!response.ok) return { kind: "inconclusive", status: response.status };
135680
+ const payload = await response.json().catch(() => void 0);
135681
+ const user = payload?.user;
135682
+ if (!user || typeof user !== "object" || Array.isArray(user)) return { kind: "inconclusive", payload };
135683
+ const record = user;
135684
+ if (typeof record.username === "string" && record.username || typeof record.email === "string" && record.email) return { kind: "personal", status: response.status, payload };
135685
+ if ("username" in record && "email" in record && (record.username == null || record.username === "") && (record.email == null || record.email === "")) return { kind: "service-account", status: response.status, payload };
135686
+ return { kind: "inconclusive", payload };
135687
+ } catch {
135688
+ return { kind: "inconclusive" };
135689
+ }
135690
+ })();
135691
+ memo.set(key, pending);
135692
+ }
135693
+ const result = await pending;
135694
+ if (options.mode === "preflight" && result.kind === "inconclusive") memo.delete(key);
135695
+ return result;
135696
+ }
135697
+
135581
135698
  // src/lib/postman/credential-identity.ts
135582
135699
  var sessionPath = "/api/sessions/current";
135583
135700
  var SESSION_MAX_ATTEMPTS = 3;
@@ -135671,14 +135788,8 @@ async function resolvePmakIdentity(opts) {
135671
135788
  }
135672
135789
  async function probePmakIdentity(baseUrl, apiKey, fetchImpl) {
135673
135790
  try {
135674
- const response = await fetchImpl(`${baseUrl}/me`, {
135675
- method: "GET",
135676
- headers: { "X-Api-Key": apiKey }
135677
- });
135678
- if (!response.ok) {
135679
- return void 0;
135680
- }
135681
- const payload = asRecord(await response.json());
135791
+ const diagnostic = await inspectPmakIdentity({ apiBaseUrl: baseUrl, apiKey, fetchImpl });
135792
+ const payload = asRecord(diagnostic.payload);
135682
135793
  const user = asRecord(payload?.user);
135683
135794
  if (!user) {
135684
135795
  return void 0;
@@ -135710,7 +135821,8 @@ async function resolveSessionIdentity(opts) {
135710
135821
  opts.fetchImpl ?? fetch,
135711
135822
  Math.max(1, opts.maxAttempts ?? SESSION_MAX_ATTEMPTS),
135712
135823
  opts.sleepImpl ?? defaultSessionSleep,
135713
- opts.randomImpl ?? defaultRandom
135824
+ opts.randomImpl ?? defaultRandom,
135825
+ opts.onRetryEvent
135714
135826
  );
135715
135827
  sessionMemo.set(memoKey, pending);
135716
135828
  }
@@ -135744,7 +135856,7 @@ async function parseSessionResponse(response) {
135744
135856
  consumerType: coerceText(root.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
135745
135857
  };
135746
135858
  }
135747
- async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts, sleepImpl, random) {
135859
+ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts, sleepImpl, random, onRetryEvent) {
135748
135860
  let failure = "unavailable";
135749
135861
  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
135750
135862
  let response;
@@ -135756,7 +135868,9 @@ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts
135756
135868
  } catch {
135757
135869
  failure = "unavailable";
135758
135870
  if (attempt < maxAttempts) {
135759
- 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);
135760
135874
  continue;
135761
135875
  }
135762
135876
  break;
@@ -135778,7 +135892,9 @@ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts
135778
135892
  if (response.status === 429 || response.status >= 500) {
135779
135893
  failure = "unavailable";
135780
135894
  if (attempt < maxAttempts) {
135781
- 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);
135782
135898
  continue;
135783
135899
  }
135784
135900
  break;
@@ -135880,7 +135996,8 @@ async function runCredentialPreflight(args) {
135880
135996
  accessToken,
135881
135997
  fetchImpl: args.fetchImpl,
135882
135998
  ...args.sleepImpl ? { sleepImpl: args.sleepImpl } : {},
135883
- ...args.randomImpl ? { randomImpl: args.randomImpl } : {}
135999
+ ...args.randomImpl ? { randomImpl: args.randomImpl } : {},
136000
+ onRetryEvent: args.retryEvent ?? args.log.retryEvent
135884
136001
  });
135885
136002
  } catch (error2) {
135886
136003
  args.log.warning(
@@ -135980,6 +136097,39 @@ function adviseFromHttpError(err, ctx) {
135980
136097
  return new Error(ctx.mask(advice), { cause: err });
135981
136098
  }
135982
136099
 
136100
+ // src/lib/postman/app-version.ts
136101
+ var UPDATE_URL = "https://dl.pstmn.io/update/status?currentVersion=12.0.0&platform=osx_arm64";
136102
+ var FLOOR_VERSION = "12.0.0";
136103
+ var VERSION_PATTERN = /^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
136104
+ var PostmanAppVersionProvider = class {
136105
+ fetchImpl;
136106
+ requestTimeoutMs;
136107
+ pending;
136108
+ constructor(options = {}) {
136109
+ this.fetchImpl = options.fetchImpl ?? fetch;
136110
+ this.requestTimeoutMs = options.requestTimeoutMs ?? 2e3;
136111
+ }
136112
+ async get() {
136113
+ if (process.env.POSTMAN_GATEWAY_APP_VERSION === "off") return void 0;
136114
+ this.pending ??= this.resolve();
136115
+ return this.pending;
136116
+ }
136117
+ async resolve() {
136118
+ try {
136119
+ const response = await this.fetchImpl(UPDATE_URL, {
136120
+ signal: AbortSignal.timeout(this.requestTimeoutMs)
136121
+ });
136122
+ if (!response.ok) return FLOOR_VERSION;
136123
+ const payload = await response.json();
136124
+ const version = typeof payload.version === "string" ? payload.version : "";
136125
+ return VERSION_PATTERN.test(version) ? version : FLOOR_VERSION;
136126
+ } catch {
136127
+ return FLOOR_VERSION;
136128
+ }
136129
+ }
136130
+ };
136131
+ var defaultPostmanAppVersionProvider = new PostmanAppVersionProvider();
136132
+
135983
136133
  // src/lib/postman/internal-integration-adapter.ts
135984
136134
  function extractDuplicateWorkspaceId(body) {
135985
136135
  try {
@@ -135999,6 +136149,8 @@ var BifrostInternalIntegrationAdapter = class {
135999
136149
  secretMasker;
136000
136150
  teamId;
136001
136151
  workerBaseUrl;
136152
+ gateway;
136153
+ appVersionProvider;
136002
136154
  constructor(options) {
136003
136155
  this.accessToken = String(options.accessToken || "").trim();
136004
136156
  this.getAccessToken = options.getAccessToken;
@@ -136011,6 +136163,8 @@ var BifrostInternalIntegrationAdapter = class {
136011
136163
  this.workerBaseUrl = String(
136012
136164
  options.workerBaseUrl || "https://catalog-admin.postman-account2009.workers.dev"
136013
136165
  ).replace(/\/+$/, "");
136166
+ this.gateway = options.gateway;
136167
+ this.appVersionProvider = options.appVersionProvider ?? defaultPostmanAppVersionProvider;
136014
136168
  this.secretMasker = options.secretMasker ?? createSecretMasker([this.accessToken]);
136015
136169
  }
136016
136170
  /** Live access token: re-minted value when a provider accessor is wired, else the captured one. */
@@ -136018,7 +136172,7 @@ var BifrostInternalIntegrationAdapter = class {
136018
136172
  return this.getAccessToken ? String(this.getAccessToken() || "").trim() : this.accessToken;
136019
136173
  }
136020
136174
  /** Build Bifrost proxy headers. Only includes x-entity-team-id for org-mode teams. */
136021
- bifrostHeaders() {
136175
+ async bifrostHeaders() {
136022
136176
  const headers = {
136023
136177
  "Content-Type": "application/json",
136024
136178
  "x-access-token": this.currentToken()
@@ -136026,6 +136180,8 @@ var BifrostInternalIntegrationAdapter = class {
136026
136180
  if (this.teamId && this.orgMode) {
136027
136181
  headers["x-entity-team-id"] = this.teamId;
136028
136182
  }
136183
+ const appVersion = await this.appVersionProvider.get();
136184
+ if (appVersion) headers["x-app-version"] = appVersion;
136029
136185
  return headers;
136030
136186
  }
136031
136187
  /** Reactive error-advice context, enriched with the preflight session memo when present. */
@@ -136056,6 +136212,58 @@ var BifrostInternalIntegrationAdapter = class {
136056
136212
  if (associations.length === 0) {
136057
136213
  return;
136058
136214
  }
136215
+ const mode = process.env.POSTMAN_SYSTEM_ENV_ASSOCIATION_MODE ?? "direct";
136216
+ if (mode !== "direct" && mode !== "worker") {
136217
+ throw new Error("POSTMAN_SYSTEM_ENV_ASSOCIATION_MODE must be direct or worker");
136218
+ }
136219
+ if (mode === "direct") {
136220
+ if (!this.gateway) {
136221
+ throw new Error("Direct system-environment association requires the access-token gateway");
136222
+ }
136223
+ const groups = /* @__PURE__ */ new Map();
136224
+ for (const association of associations) {
136225
+ const systemEnvId = String(association.systemEnvId || "").trim();
136226
+ const uid = String(association.envUid || "").trim();
136227
+ if (!systemEnvId || !uid) continue;
136228
+ const key = `${systemEnvId}\0${workspaceId}`;
136229
+ const uids = groups.get(key) ?? /* @__PURE__ */ new Set();
136230
+ uids.add(uid);
136231
+ groups.set(key, uids);
136232
+ }
136233
+ for (const [key, uids] of [...groups.entries()].sort(([a], [b]) => a.localeCompare(b))) {
136234
+ const [systemEnvironmentId, groupedWorkspaceId] = key.split("\0");
136235
+ const postmanEnvironmentIds = [...uids].sort();
136236
+ let response2;
136237
+ try {
136238
+ response2 = await this.gateway.requestJson({
136239
+ service: "api-catalog",
136240
+ method: "post",
136241
+ path: "/api/system-envs/associations",
136242
+ body: {
136243
+ systemEnvironmentId,
136244
+ workspaceEntries: [{ workspaceId: groupedWorkspaceId, postmanEnvironmentIds }]
136245
+ },
136246
+ fallback: "none"
136247
+ }, { retryTransient: true });
136248
+ } catch (error2) {
136249
+ if (error2 instanceof HttpError) {
136250
+ throw adviseFromHttpError(error2, this.adviceContext("system environment association")) ?? error2;
136251
+ }
136252
+ throw error2;
136253
+ }
136254
+ if (!response2 || response2.success !== true) {
136255
+ throw new Error("SYSTEM_ENV_ASSOCIATION_INCOMPLETE");
136256
+ }
136257
+ if (response2.data !== void 0) {
136258
+ if (!Array.isArray(response2.data)) throw new Error("SYSTEM_ENV_ASSOCIATION_INCOMPLETE");
136259
+ const seen = new Set(response2.data.filter((row) => !!row && typeof row === "object").map((row) => `${row.systemEnvironmentId}\0${row.workspaceId}\0${row.postmanEnvironmentId}`));
136260
+ if (!postmanEnvironmentIds.every((uid) => seen.has(`${systemEnvironmentId}\0${groupedWorkspaceId}\0${uid}`))) {
136261
+ throw new Error("SYSTEM_ENV_ASSOCIATION_INCOMPLETE");
136262
+ }
136263
+ }
136264
+ }
136265
+ return;
136266
+ }
136059
136267
  const token = this.currentToken();
136060
136268
  const response = await this.fetchImpl(
136061
136269
  `${this.workerBaseUrl}/api/internal/system-envs/associate`,
@@ -136113,7 +136321,7 @@ var BifrostInternalIntegrationAdapter = class {
136113
136321
  try {
136114
136322
  const response = await this.fetchImpl(url, {
136115
136323
  method: "POST",
136116
- headers: this.bifrostHeaders(),
136324
+ headers: await this.bifrostHeaders(),
136117
136325
  body: JSON.stringify(payload)
136118
136326
  });
136119
136327
  let parsed = {};
@@ -136202,7 +136410,7 @@ var BifrostInternalIntegrationAdapter = class {
136202
136410
  versionControl: true
136203
136411
  }
136204
136412
  };
136205
- const headers = this.bifrostHeaders();
136413
+ const headers = await this.bifrostHeaders();
136206
136414
  const response = await this.fetchImpl(url, {
136207
136415
  method: "POST",
136208
136416
  headers,
@@ -136257,7 +136465,7 @@ var BifrostInternalIntegrationAdapter = class {
136257
136465
  try {
136258
136466
  const response = await this.fetchImpl(`${this.bifrostBaseUrl}/ws/proxy`, {
136259
136467
  method: "POST",
136260
- headers: this.bifrostHeaders(),
136468
+ headers: await this.bifrostHeaders(),
136261
136469
  body: JSON.stringify({
136262
136470
  service: "workspaces",
136263
136471
  method: "GET",
@@ -136288,7 +136496,7 @@ var BifrostInternalIntegrationAdapter = class {
136288
136496
  }
136289
136497
  async createApiKey(name) {
136290
136498
  const url = `${this.bifrostBaseUrl}/ws/proxy`;
136291
- const headers = this.bifrostHeaders();
136499
+ const headers = await this.bifrostHeaders();
136292
136500
  const payload = {
136293
136501
  service: "identity",
136294
136502
  method: "POST",
@@ -136373,6 +136581,16 @@ async function retry(operation, options = {}) {
136373
136581
  }
136374
136582
  throw new Error("Retry exhausted without returning or throwing");
136375
136583
  }
136584
+ function fullJitterDelayMs(attempt, baseMs, capMs, random = Math.random) {
136585
+ return Math.floor(random() * Math.max(0, Math.min(capMs, baseMs * 2 ** Math.max(0, attempt))));
136586
+ }
136587
+ function parseRetryAfterMs2(value) {
136588
+ const trimmed = value?.trim();
136589
+ if (!trimmed) return void 0;
136590
+ if (/^\d+$/.test(trimmed)) return Number(trimmed) * 1e3;
136591
+ const time = Date.parse(trimmed);
136592
+ return Number.isNaN(time) ? void 0 : Math.max(0, time - Date.now());
136593
+ }
136376
136594
 
136377
136595
  // src/contracts.ts
136378
136596
  var postmanRepoSyncActionContract = {
@@ -136431,6 +136649,11 @@ var postmanRepoSyncActionContract = {
136431
136649
  description: "Contract collection ID used for exported artifacts.",
136432
136650
  required: false
136433
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
+ },
136434
136657
  "collection-sync-mode": {
136435
136658
  description: "Collection sync lifecycle mode (refresh or version).",
136436
136659
  required: false,
@@ -136673,7 +136896,7 @@ var postmanRepoSyncActionContract = {
136673
136896
  "Create or update Postman environments from runtime URLs.",
136674
136897
  "Associate Postman environments to system environments through Postman integration APIs.",
136675
136898
  "Create mock servers and smoke monitors from generated collections.",
136676
- "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.",
136677
136900
  "Link the Postman workspace to the repository (GitHub or GitLab) through Postman integration APIs.",
136678
136901
  "Commit synced artifacts and push them back to the current checked out ref."
136679
136902
  ],
@@ -136802,6 +137025,17 @@ var PostmanGatewayAssetsClient = class {
136802
137025
  return data.map((entry) => this.asRecord(entry)).filter((entry) => entry !== null).map((entry) => ({ uid: String(entry.id ?? entry.uid ?? "").trim(), name: String(entry.name ?? "").trim() })).filter((entry) => entry.uid && entry.name);
136803
137026
  }
136804
137027
  async getSpecContent(specId) {
137028
+ if (process.env.POSTMAN_SPEC_TREE_FAST_PATH !== "off") {
137029
+ try {
137030
+ const treeContent = await this.getSpecContentFromTree(specId);
137031
+ if (treeContent !== void 0) return treeContent;
137032
+ } catch (error2) {
137033
+ if (!(error2 instanceof HttpError) || ![403, 404, 405, 501].includes(error2.status)) throw error2;
137034
+ }
137035
+ }
137036
+ return this.getSpecContentLegacy(specId);
137037
+ }
137038
+ async getSpecContentLegacy(specId) {
136805
137039
  const files = await this.gateway.requestJson({
136806
137040
  service: "specification",
136807
137041
  method: "get",
@@ -136820,6 +137054,46 @@ var PostmanGatewayAssetsClient = class {
136820
137054
  const record = this.dataOf(file);
136821
137055
  return typeof record?.content === "string" ? record.content : void 0;
136822
137056
  }
137057
+ /** Minimal `/tree` reader: validate the entire returned inventory before selecting ROOT. */
137058
+ async getSpecContentFromTree(specId) {
137059
+ const rows = [];
137060
+ const cursors = /* @__PURE__ */ new Set();
137061
+ let cursor;
137062
+ for (let page = 0; page < 100; page += 1) {
137063
+ const response = await this.gateway.requestJson({
137064
+ service: "specification",
137065
+ method: "get",
137066
+ path: `/specifications/${specId}/tree`,
137067
+ query: { fields: "id,name,type,path,parentId,fileType,content", limit: 100, ...cursor ? { cursor } : {} }
137068
+ });
137069
+ if (!Array.isArray(response?.data)) return void 0;
137070
+ for (const value of response.data) {
137071
+ const row = this.asRecord(value);
137072
+ if (!row || row.type === "FOLDER") continue;
137073
+ if (row.type !== "FILE" || typeof row.id !== "string" || !row.id.trim() || typeof row.path !== "string" || !row.path.trim() || typeof row.content !== "string" || typeof row.fileType !== "string" || !row.fileType.trim()) return void 0;
137074
+ const path9 = row.path.replace(/\\/g, "/").normalize("NFC");
137075
+ if (path9.startsWith("/") || path9.split("/").some((part) => part === ".." || !part)) throw new Error("CONTRACT_DEFINITION_PATH_INVALID");
137076
+ rows.push({ ...row, path: path9 });
137077
+ }
137078
+ const meta = this.asRecord(response?.meta);
137079
+ const cursorValue = this.asRecord(meta?.cursor)?.next;
137080
+ const next = typeof cursorValue === "string" && cursorValue.trim() ? cursorValue.trim() : void 0;
137081
+ if (!next) break;
137082
+ if (cursors.has(next)) throw new Error("SPEC_TREE_CURSOR_REPEATED");
137083
+ cursors.add(next);
137084
+ if (page === 99) throw new Error("SPEC_TREE_PAGE_LIMIT_EXCEEDED");
137085
+ cursor = next;
137086
+ }
137087
+ const paths = /* @__PURE__ */ new Set();
137088
+ for (const row of rows) {
137089
+ const path9 = String(row.path).toLocaleLowerCase();
137090
+ if (paths.has(path9)) throw new Error("CONTRACT_DEFINITION_DUPLICATE_PATH");
137091
+ paths.add(path9);
137092
+ }
137093
+ const roots = rows.filter((row) => row.fileType === "ROOT");
137094
+ if (roots.length !== 1) throw new Error("CONTRACT_DEFINITION_INVENTORY_INVALID");
137095
+ return String(roots[0]?.content);
137096
+ }
136823
137097
  async listSpecCollections(specId) {
136824
137098
  const response = await this.gateway.requestJson({
136825
137099
  service: "specification",
@@ -137379,10 +137653,12 @@ var PostmanGatewayAssetsClient = class {
137379
137653
  // src/lib/postman/token-provider.ts
137380
137654
  var MintError = class extends Error {
137381
137655
  permanent;
137382
- constructor(message, permanent) {
137656
+ status;
137657
+ constructor(message, permanent, status) {
137383
137658
  super(message);
137384
137659
  this.name = "MintError";
137385
137660
  this.permanent = permanent;
137661
+ this.status = status;
137386
137662
  }
137387
137663
  };
137388
137664
  function extractAccessToken(payload) {
@@ -137405,6 +137681,7 @@ var AccessTokenProvider = class {
137405
137681
  maxAttempts;
137406
137682
  onToken;
137407
137683
  sleep;
137684
+ onRetryEvent;
137408
137685
  inflight;
137409
137686
  constructor(options) {
137410
137687
  this.token = String(options.accessToken || "").trim();
@@ -137416,6 +137693,7 @@ var AccessTokenProvider = class {
137416
137693
  this.maxAttempts = Math.max(1, options.maxAttempts ?? 2);
137417
137694
  this.onToken = options.onToken;
137418
137695
  this.sleep = options.sleep;
137696
+ this.onRetryEvent = options.onRetryEvent;
137419
137697
  }
137420
137698
  current() {
137421
137699
  return this.token;
@@ -137441,7 +137719,12 @@ var AccessTokenProvider = class {
137441
137719
  delayMs: 1e3,
137442
137720
  backoffMultiplier: 2,
137443
137721
  ...this.sleep ? { sleep: this.sleep } : {},
137444
- 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
+ }
137445
137728
  });
137446
137729
  this.token = token;
137447
137730
  this.onToken?.(token);
@@ -137462,7 +137745,8 @@ var AccessTokenProvider = class {
137462
137745
  if (status === 401 || status === 403) {
137463
137746
  throw new MintError(
137464
137747
  `postman: re-mint failed because the postman-api-key was rejected (PMAK rejected, HTTP ${status}); confirm it is a valid, enabled service-account PMAK for the intended team.`,
137465
- true
137748
+ true,
137749
+ status
137466
137750
  );
137467
137751
  }
137468
137752
  if (status === 400 && body.toLowerCase().includes("service accounts not enabled")) {
@@ -137471,7 +137755,7 @@ var AccessTokenProvider = class {
137471
137755
  true
137472
137756
  );
137473
137757
  }
137474
- 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);
137475
137759
  }
137476
137760
  let parsed;
137477
137761
  try {
@@ -137487,26 +137771,9 @@ var AccessTokenProvider = class {
137487
137771
  }
137488
137772
  };
137489
137773
  async function describeMintFailure(mintError, apiKey, apiBaseUrl, fetchImpl) {
137490
- const raw = mintError instanceof Error ? mintError.message : String(mintError);
137491
- const rejected = /HTTP 40[13]|PMAK rejected/.test(raw);
137492
- if (!rejected) {
137493
- return raw;
137494
- }
137495
- try {
137496
- const me = await fetchImpl(`${apiBaseUrl}/me`, { headers: { "x-api-key": apiKey } });
137497
- if (me.ok) {
137498
- const body = await me.json().catch(() => void 0);
137499
- const user = body?.user;
137500
- const looksPersonal = Boolean(user && (user.username || user.email));
137501
- if (looksPersonal) {
137502
- return "Personal API key detected, cannot mint a service-account access token. POST /service-account-tokens only accepts a SERVICE-ACCOUNT API key; this postman-api-key belongs to a user account" + (user?.teamId ? ` (team ${user.teamId})` : "") + ". Create a service account in Team Settings and use its PMAK, or mint the token elsewhere and pass postman-access-token.";
137503
- }
137504
- return "The postman-api-key authenticates (GET /me OK) but was rejected by POST /service-account-tokens" + (user?.teamId ? ` (team ${user.teamId})` : "") + ". The service account likely lacks permission to mint access tokens, or service accounts are restricted for this team. Check the service account role in Team Settings, or pass a pre-minted postman-access-token.";
137505
- }
137506
- return "The postman-api-key is invalid, disabled, or expired (rejected by both POST /service-account-tokens and GET /me). Generate a fresh service-account PMAK in Team Settings and update the secret.";
137507
- } catch {
137508
- return raw;
137509
- }
137774
+ const raw = maskPmakDiagnostic(mintError instanceof Error ? mintError.message : String(mintError), [apiKey]);
137775
+ if (!(mintError instanceof MintError) || mintError.status !== 401 && mintError.status !== 403) return raw;
137776
+ return formatRejectedMint(raw, await inspectPmakIdentity({ apiBaseUrl, apiKey, fetchImpl }));
137510
137777
  }
137511
137778
  async function mintAccessTokenIfNeeded(inputs, log, setSecret2, fetchImpl = fetch) {
137512
137779
  if (inputs.postmanAccessToken || !inputs.postmanApiKey) {
@@ -137519,7 +137786,8 @@ async function mintAccessTokenIfNeeded(inputs, log, setSecret2, fetchImpl = fetc
137519
137786
  apiKey: inputs.postmanApiKey,
137520
137787
  apiBaseUrl,
137521
137788
  fetchImpl,
137522
- onToken: (token) => setSecret2?.(token)
137789
+ onToken: (token) => setSecret2?.(token),
137790
+ onRetryEvent: (event) => log.retryEvent?.(event)
137523
137791
  });
137524
137792
  try {
137525
137793
  inputs.postmanAccessToken = await provider.refresh();
@@ -137555,6 +137823,11 @@ var AccessTokenGatewayClient = class {
137555
137823
  fallbackBaseUrl;
137556
137824
  retryBaseDelayMs;
137557
137825
  sleepImpl;
137826
+ appVersionProvider;
137827
+ requestTimeoutMs;
137828
+ retryMaxDelayMs;
137829
+ randomImpl;
137830
+ onRetryEvent;
137558
137831
  constructor(options) {
137559
137832
  this.tokenProvider = options.tokenProvider;
137560
137833
  this.bifrostBaseUrl = String(
@@ -137569,16 +137842,23 @@ var AccessTokenGatewayClient = class {
137569
137842
  this.fallbackBaseUrl = fallbackEnv === "off" ? void 0 : options.fallbackBaseUrl?.replace(/\/+$/, "");
137570
137843
  this.retryBaseDelayMs = options.retryBaseDelayMs ?? 400;
137571
137844
  this.sleepImpl = options.sleepImpl ?? defaultSleep;
137845
+ this.appVersionProvider = options.appVersionProvider ?? defaultPostmanAppVersionProvider;
137846
+ this.requestTimeoutMs = options.requestTimeoutMs ?? 3e4;
137847
+ this.retryMaxDelayMs = options.retryMaxDelayMs ?? 5e3;
137848
+ this.randomImpl = options.randomImpl ?? Math.random;
137849
+ this.onRetryEvent = options.onRetryEvent;
137572
137850
  }
137573
137851
  configureTeamContext(teamId, orgMode) {
137574
137852
  this.teamId = String(teamId || "").trim();
137575
137853
  this.orgMode = orgMode;
137576
137854
  }
137577
- buildHeaders(extra) {
137855
+ async buildHeaders(extra) {
137856
+ const appVersion = await this.appVersionProvider.get();
137578
137857
  const headers = {
137579
137858
  "Content-Type": "application/json",
137580
137859
  "x-access-token": this.tokenProvider.current(),
137581
- ...extra || {}
137860
+ ...extra || {},
137861
+ ...appVersion ? { "x-app-version": appVersion } : {}
137582
137862
  };
137583
137863
  if (this.teamId && this.orgMode) {
137584
137864
  headers["x-entity-team-id"] = this.teamId;
@@ -137587,17 +137867,24 @@ var AccessTokenGatewayClient = class {
137587
137867
  }
137588
137868
  async send(request, baseUrl) {
137589
137869
  const url = `${baseUrl ?? this.bifrostBaseUrl}/ws/proxy`;
137590
- return this.fetchImpl(url, {
137591
- method: "POST",
137592
- headers: this.buildHeaders(request.headers),
137593
- body: JSON.stringify({
137594
- service: request.service,
137595
- method: request.method,
137596
- path: request.path,
137597
- ...request.query !== void 0 ? { query: request.query } : {},
137598
- ...request.body !== void 0 ? { body: request.body } : {}
137599
- })
137600
- });
137870
+ const controller = new AbortController();
137871
+ const timer = setTimeout(() => controller.abort(), this.requestTimeoutMs);
137872
+ try {
137873
+ return await this.fetchImpl(url, {
137874
+ method: "POST",
137875
+ headers: await this.buildHeaders(request.headers),
137876
+ signal: controller.signal,
137877
+ body: JSON.stringify({
137878
+ service: request.service,
137879
+ method: request.method,
137880
+ path: request.path,
137881
+ ...request.query !== void 0 ? { query: request.query } : {},
137882
+ ...request.body !== void 0 ? { body: request.body } : {}
137883
+ })
137884
+ });
137885
+ } finally {
137886
+ clearTimeout(timer);
137887
+ }
137601
137888
  }
137602
137889
  /**
137603
137890
  * One cold, serial attempt against the fallback base URL after the primary
@@ -137624,11 +137911,13 @@ var AccessTokenGatewayClient = class {
137624
137911
  * they are the freshest authoritative answer.
137625
137912
  */
137626
137913
  fallbackEligible(request, retryTransient) {
137914
+ if (request.fallback === "none") return false;
137627
137915
  if (!this.fallbackBaseUrl) return false;
137628
137916
  return retryTransient || request.fallback === "auto";
137629
137917
  }
137630
- async attemptFallback(request, retryTransient) {
137918
+ async attemptFallback(request, retryTransient, status) {
137631
137919
  if (!this.fallbackEligible(request, retryTransient)) return null;
137920
+ this.emitRetryEvent("fallback", status, 1, 0);
137632
137921
  const response = await this.tryFallback(request);
137633
137922
  if (!response) return null;
137634
137923
  if (response.ok) return response;
@@ -137653,7 +137942,8 @@ var AccessTokenGatewayClient = class {
137653
137942
  response = await this.send(request);
137654
137943
  } catch (error2) {
137655
137944
  if (retryTransient && attempt < this.maxRetries) {
137656
- const delay = this.retryBaseDelayMs * 2 ** attempt;
137945
+ const delay = this.retryDelayMs(attempt);
137946
+ this.emitRetryEvent("transport", void 0, attempt + 1, delay);
137657
137947
  attempt += 1;
137658
137948
  await this.sleepImpl(delay);
137659
137949
  continue;
@@ -137663,10 +137953,23 @@ var AccessTokenGatewayClient = class {
137663
137953
  throw error2;
137664
137954
  }
137665
137955
  if (response.ok) {
137666
- return response;
137956
+ const okBody = await response.text().catch(() => "");
137957
+ const inner = this.innerStatus(okBody);
137958
+ if (inner !== void 0) {
137959
+ if (retryTransient && this.isTransient(inner, okBody) && attempt < this.maxRetries) {
137960
+ const delay = this.retryDelayMs(attempt);
137961
+ this.emitRetryEvent("inner", inner, attempt + 1, delay);
137962
+ await this.sleepImpl(delay);
137963
+ attempt += 1;
137964
+ continue;
137965
+ }
137966
+ throw this.toInnerHttpError(request, inner, okBody);
137967
+ }
137968
+ return this.rebuildResponse(response, okBody);
137667
137969
  }
137668
137970
  const body = await response.text().catch(() => "");
137669
137971
  if (isExpiredAuthError(response.status, body) && this.tokenProvider.canRefresh()) {
137972
+ this.emitRetryEvent("auth", response.status, 1, 0);
137670
137973
  await this.tokenProvider.refresh();
137671
137974
  response = await this.send(request);
137672
137975
  if (response.ok) {
@@ -137675,17 +137978,44 @@ var AccessTokenGatewayClient = class {
137675
137978
  const retryBody = await response.text().catch(() => "");
137676
137979
  throw this.toHttpError(request, response, retryBody);
137677
137980
  }
137678
- if (retryTransient && isRetryableSafeReadResponse(response.status) && attempt < this.maxRetries) {
137679
- const delay = this.retryBaseDelayMs * 2 ** attempt;
137981
+ if (retryTransient && this.isTransient(response.status, body) && attempt < this.maxRetries) {
137982
+ const delay = this.retryDelayMs(attempt, parseRetryAfterMs2(response.headers.get("retry-after")));
137983
+ this.emitRetryEvent("http", response.status, attempt + 1, delay);
137680
137984
  attempt += 1;
137681
137985
  await this.sleepImpl(delay);
137682
137986
  continue;
137683
137987
  }
137684
- const fallbackResponse = await this.attemptFallback(request, retryTransient);
137988
+ const fallbackResponse = await this.attemptFallback(request, retryTransient, response.status);
137685
137989
  if (fallbackResponse) return fallbackResponse;
137686
137990
  throw this.toHttpError(request, response, body);
137687
137991
  }
137688
137992
  }
137993
+ retryDelayMs(attempt, retryAfter) {
137994
+ return retryAfter === void 0 ? fullJitterDelayMs(attempt, this.retryBaseDelayMs, this.retryMaxDelayMs, this.randomImpl) : Math.min(this.retryMaxDelayMs, retryAfter);
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
+ }
138004
+ isTransient(status, body) {
138005
+ return status === 408 || status === 429 || status >= 500 || /ESOCKETTIMEDOUT|ETIMEDOUT|ECONNRESET|serverError|downstream/.test(body);
138006
+ }
138007
+ innerStatus(body) {
138008
+ try {
138009
+ const value = JSON.parse(body);
138010
+ const status = Number(value.status ?? value.statusCode);
138011
+ return value.error || value.success === false || status >= 400 ? status >= 400 ? status : 502 : void 0;
138012
+ } catch {
138013
+ return void 0;
138014
+ }
138015
+ }
138016
+ rebuildResponse(response, body) {
138017
+ return new Response([204, 205, 304].includes(response.status) ? null : body, { status: response.status, statusText: response.statusText, headers: response.headers });
138018
+ }
137689
138019
  /** Send a gateway request and parse the JSON body, or null when empty. */
137690
138020
  async requestJson(request, options = {}) {
137691
138021
  const response = await this.request(request, options);
@@ -137732,11 +138062,19 @@ var AccessTokenGatewayClient = class {
137732
138062
  url: `${this.bifrostBaseUrl}/ws/proxy (${request.service}: ${request.method} ${request.path})`,
137733
138063
  status: response.status,
137734
138064
  statusText: response.statusText,
137735
- requestHeaders: this.buildHeaders(request.headers),
138065
+ requestHeaders: {
138066
+ "Content-Type": "application/json",
138067
+ "x-access-token": this.tokenProvider.current(),
138068
+ ...request.headers || {},
138069
+ ...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
138070
+ },
137736
138071
  responseBody: this.secretMasker(body),
137737
138072
  secretValues: [this.tokenProvider.current()]
137738
138073
  });
137739
138074
  }
138075
+ toInnerHttpError(request, status, body) {
138076
+ return new HttpError({ method: request.method.toUpperCase(), url: `${this.bifrostBaseUrl}/ws/proxy (${request.service}: ${request.method} ${request.path}) [inner]`, status, statusText: "Inner Error", requestHeaders: { "x-access-token": this.tokenProvider.current() }, responseBody: this.secretMasker(body), secretValues: [this.tokenProvider.current()] });
138077
+ }
137740
138078
  };
137741
138079
 
137742
138080
  // src/lib/ssl-validation.ts
@@ -137792,7 +138130,7 @@ function validateCertMaterial(certBase64, keyBase64, passphrase) {
137792
138130
  }
137793
138131
 
137794
138132
  // src/lib/repo/branch-decision.ts
137795
- var import_node_fs3 = require("node:fs");
138133
+ var import_node_fs4 = require("node:fs");
137796
138134
  var import_node_crypto3 = require("node:crypto");
137797
138135
  var ContractError = class extends Error {
137798
138136
  code;
@@ -137833,7 +138171,7 @@ function readGithubEvent(env) {
137833
138171
  const path9 = clean(env.GITHUB_EVENT_PATH);
137834
138172
  if (!path9) return void 0;
137835
138173
  try {
137836
- return JSON.parse((0, import_node_fs3.readFileSync)(path9, "utf8"));
138174
+ return JSON.parse((0, import_node_fs4.readFileSync)(path9, "utf8"));
137837
138175
  } catch {
137838
138176
  return void 0;
137839
138177
  }
@@ -138289,6 +138627,7 @@ function resolveInputs(env = process.env) {
138289
138627
  baselineCollectionId: getInput2("baseline-collection-id", env),
138290
138628
  smokeCollectionId: getInput2("smoke-collection-id", env),
138291
138629
  contractCollectionId: getInput2("contract-collection-id", env),
138630
+ prebuiltCollectionsJson: getInput2("prebuilt-collections-json", env),
138292
138631
  specId: getInput2("spec-id", env),
138293
138632
  specContentChanged: parseBooleanInput(getInput2("spec-content-changed", env), true),
138294
138633
  specPath: getInput2("spec-path", env),
@@ -138404,7 +138743,7 @@ var StateUnreadableError = class extends Error {
138404
138743
  function readResourcesState() {
138405
138744
  let raw;
138406
138745
  try {
138407
- raw = (0, import_node_fs4.readFileSync)(".postman/resources.yaml", "utf8");
138746
+ raw = (0, import_node_fs5.readFileSync)(".postman/resources.yaml", "utf8");
138408
138747
  } catch {
138409
138748
  return null;
138410
138749
  }
@@ -138463,12 +138802,15 @@ function getEnvironmentUidsFromResources(resourcesState) {
138463
138802
  function normalizeToPosix(filePath) {
138464
138803
  return filePath.split(path8.sep).join("/").replace(/\\/g, "/");
138465
138804
  }
138805
+ function canonicalizeRelativePath(value) {
138806
+ return normalizeToPosix(String(value ?? "").trim()).replace(/^\.\/+/, "").replace(/\/{2,}/g, "/").replace(/\/+$/g, "");
138807
+ }
138466
138808
  function isOpenApiSpecFile(filePath) {
138467
138809
  if (!(filePath.endsWith(".json") || filePath.endsWith(".yaml") || filePath.endsWith(".yml"))) {
138468
138810
  return false;
138469
138811
  }
138470
138812
  try {
138471
- const raw = (0, import_node_fs4.readFileSync)(filePath, "utf8");
138813
+ const raw = (0, import_node_fs5.readFileSync)(filePath, "utf8");
138472
138814
  const parsed = filePath.endsWith(".json") ? JSON.parse(raw) : load(raw);
138473
138815
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
138474
138816
  return false;
@@ -138497,7 +138839,7 @@ function scanLocalSpecReferences(baseDir = ".") {
138497
138839
  const found = /* @__PURE__ */ new Set();
138498
138840
  const refs = [];
138499
138841
  const visit2 = (currentDir) => {
138500
- 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 })) {
138501
138843
  if (ignoredDirs.has(entry.name)) {
138502
138844
  continue;
138503
138845
  }
@@ -138527,7 +138869,7 @@ function resolveMappedSpecReference(explicitSpecPath, discoveredSpecs) {
138527
138869
  const normalizedExplicitPath = normalizeToPosix(explicitSpecPath.trim());
138528
138870
  if (normalizedExplicitPath) {
138529
138871
  const explicitFullPath = path8.resolve(normalizedExplicitPath);
138530
- 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()) {
138531
138873
  return {
138532
138874
  repoRelativePath: normalizedExplicitPath,
138533
138875
  configRelativePath: normalizeToPosix(path8.join("..", normalizedExplicitPath))
@@ -138579,6 +138921,7 @@ function readActionInputs(actionCore) {
138579
138921
  INPUT_BASELINE_COLLECTION_ID: readInput(actionCore, "baseline-collection-id"),
138580
138922
  INPUT_SMOKE_COLLECTION_ID: readInput(actionCore, "smoke-collection-id"),
138581
138923
  INPUT_CONTRACT_COLLECTION_ID: readInput(actionCore, "contract-collection-id"),
138924
+ INPUT_PREBUILT_COLLECTIONS_JSON: readInput(actionCore, "prebuilt-collections-json"),
138582
138925
  INPUT_SPEC_ID: readInput(actionCore, "spec-id"),
138583
138926
  INPUT_SPEC_PATH: readInput(actionCore, "spec-path"),
138584
138927
  INPUT_COLLECTION_SYNC_MODE: readInput(actionCore, "collection-sync-mode") || "refresh",
@@ -138792,6 +139135,7 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
138792
139135
  );
138793
139136
  }
138794
139137
  envUids[envName] = existingUid;
139138
+ dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
138795
139139
  continue;
138796
139140
  }
138797
139141
  const values = buildEnvironmentValues(envName, runtimeUrl);
@@ -138802,6 +139146,7 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
138802
139146
  displayName,
138803
139147
  values
138804
139148
  );
139149
+ dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
138805
139150
  } catch (error2) {
138806
139151
  throw new Error(
138807
139152
  formatOrchestrationIssue({
@@ -138818,7 +139163,7 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
138818
139163
  return envUids;
138819
139164
  }
138820
139165
  function ensureDir(path9) {
138821
- (0, import_node_fs4.mkdirSync)(path9, { recursive: true });
139166
+ (0, import_node_fs5.mkdirSync)(path9, { recursive: true });
138822
139167
  }
138823
139168
  function getCollectionDirectoryName(kind, projectName) {
138824
139169
  if (kind === "Baseline") {
@@ -138853,9 +139198,9 @@ function stripVolatileFields(obj) {
138853
139198
  }
138854
139199
  return obj;
138855
139200
  }
138856
- function writeJsonFile(path9, content, normalize3 = false) {
138857
- const data = normalize3 ? stripVolatileFields(content) : content;
138858
- (0, import_node_fs4.writeFileSync)(path9, JSON.stringify(data, null, 2));
139201
+ function writeJsonFile(path9, content, normalize4 = false) {
139202
+ const data = normalize4 ? stripVolatileFields(content) : content;
139203
+ (0, import_node_fs5.writeFileSync)(path9, JSON.stringify(data, null, 2));
138859
139204
  }
138860
139205
  function buildMappedSpecCloudKey(mappedSource, specSyncMode, releaseLabel) {
138861
139206
  if (specSyncMode !== "version") {
@@ -138919,22 +139264,422 @@ function buildResourcesManifest(workspaceId, collectionMap, envMap, artifactDir,
138919
139264
  sortKeys: false
138920
139265
  });
138921
139266
  }
138922
- function buildSpecCollectionWorkflowManifest(specRef, collectionRefs) {
138923
- return dump(
138924
- {
138925
- workflows: {
138926
- syncSpecToCollection: collectionRefs.map((collectionRef) => ({
138927
- spec: specRef,
138928
- collection: collectionRef
138929
- }))
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
+ }
138930
139399
  }
138931
- },
138932
- {
138933
- lineWidth: -1,
138934
- noRefs: true,
138935
- sortKeys: false
138936
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
138937
139681
  );
139682
+ return `../${expectedPath}`;
138938
139683
  }
138939
139684
  function hasControlCharacter2(value) {
138940
139685
  for (let index = 0; index < value.length; index += 1) {
@@ -138952,21 +139697,21 @@ function assertPathWithinCwd(targetPath, fieldName) {
138952
139697
  if (!rawPath || hasControlCharacter2(originalPath) || path8.isAbsolute(rawPath) || path8.win32.isAbsolute(rawPath) || segments.includes("..") || rawPath.startsWith(":") || hasControlCharacter2(rawPath)) {
138953
139698
  throw new Error(`${fieldName} must stay within the repository root; received ${targetPath}`);
138954
139699
  }
138955
- const base = (0, import_node_fs4.realpathSync)(process.cwd());
139700
+ const base = (0, import_node_fs5.realpathSync)(process.cwd());
138956
139701
  const resolved = path8.resolve(base, rawPath);
138957
139702
  const relative4 = path8.relative(base, resolved);
138958
139703
  if (relative4.startsWith("..") || path8.isAbsolute(relative4)) {
138959
139704
  throw new Error(`${fieldName} must stay within the repository root; received ${targetPath}`);
138960
139705
  }
138961
139706
  let existingPath = resolved;
138962
- while (!(0, import_node_fs4.existsSync)(existingPath)) {
139707
+ while (!(0, import_node_fs5.existsSync)(existingPath)) {
138963
139708
  const parent = path8.dirname(existingPath);
138964
139709
  if (parent === existingPath) {
138965
139710
  break;
138966
139711
  }
138967
139712
  existingPath = parent;
138968
139713
  }
138969
- const realExistingPath = (0, import_node_fs4.realpathSync)(existingPath);
139714
+ const realExistingPath = (0, import_node_fs5.realpathSync)(existingPath);
138970
139715
  const realRelative = path8.relative(base, realExistingPath);
138971
139716
  if (realRelative.startsWith("..") || path8.isAbsolute(realRelative)) {
138972
139717
  throw new Error(`${fieldName} must stay within the repository root; received ${targetPath}`);
@@ -138994,8 +139739,8 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
138994
139739
  ensureDir(specsDir);
138995
139740
  ensureDir(".postman");
138996
139741
  const globalsFilePath = `${globalsDir}/workspace.globals.yaml`;
138997
- if (!(0, import_node_fs4.existsSync)(globalsFilePath)) {
138998
- (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");
138999
139744
  }
139000
139745
  if (inputs.generateCiWorkflow) {
139001
139746
  const ciDir = inputs.ciWorkflowPath.split("/").slice(0, -1).join("/");
@@ -139011,23 +139756,42 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
139011
139756
  inputs.specSyncMode,
139012
139757
  options.releaseLabel
139013
139758
  ) : void 0;
139014
- if (inputs.baselineCollectionId) {
139015
- const col = await dependencies.postman.getCollection(inputs.baselineCollectionId);
139016
- const dirName = getCollectionDirectoryName("Baseline", assetProjectName);
139017
- await convertAndSplitAnyCollection(col, `${collectionsDir}/${dirName}`);
139018
- manifestCollections[`../${collectionsDir}/${dirName}`] = inputs.baselineCollectionId;
139019
- }
139020
- if (inputs.smokeCollectionId) {
139021
- const col = await dependencies.postman.getCollection(inputs.smokeCollectionId);
139022
- const dirName = getCollectionDirectoryName("Smoke", assetProjectName);
139023
- await convertAndSplitAnyCollection(col, `${collectionsDir}/${dirName}`);
139024
- manifestCollections[`../${collectionsDir}/${dirName}`] = inputs.smokeCollectionId;
139025
- }
139026
- if (inputs.contractCollectionId) {
139027
- const col = await dependencies.postman.getCollection(inputs.contractCollectionId);
139028
- const dirName = getCollectionDirectoryName("Contract", assetProjectName);
139029
- await convertAndSplitAnyCollection(col, `${collectionsDir}/${dirName}`);
139030
- 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;
139031
139795
  }
139032
139796
  for (const [envName, envUid] of Object.entries(envUids)) {
139033
139797
  writeJsonFile(
@@ -139042,7 +139806,7 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
139042
139806
  workspaceLinkEnabled: inputs.workspaceLinkEnabled,
139043
139807
  workspaceLinkStatus: options.workspaceLinkStatus
139044
139808
  });
139045
- (0, import_node_fs4.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
139809
+ (0, import_node_fs5.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
139046
139810
  durableWorkspaceId,
139047
139811
  manifestCollections,
139048
139812
  envUids,
@@ -139054,11 +139818,18 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
139054
139818
  options.priorState
139055
139819
  ));
139056
139820
  if (mappedSpec && Object.keys(manifestCollections).length > 0) {
139057
- (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)(
139058
139828
  ".postman/workflows.yaml",
139059
139829
  buildSpecCollectionWorkflowManifest(
139060
139830
  mappedSpec.configRelativePath,
139061
- Object.keys(manifestCollections)
139831
+ Object.keys(manifestCollections),
139832
+ existingWorkflows
139062
139833
  )
139063
139834
  );
139064
139835
  }
@@ -139103,12 +139874,12 @@ async function commitAndPushGeneratedFiles(inputs, dependencies) {
139103
139874
  const dir = parts.slice(0, -1).join("/");
139104
139875
  ensureDir(dir);
139105
139876
  }
139106
- (0, import_node_fs4.writeFileSync)(inputs.ciWorkflowPath, ciWorkflow);
139877
+ (0, import_node_fs5.writeFileSync)(inputs.ciWorkflowPath, ciWorkflow);
139107
139878
  if (inputs.provider === "github" || inputs.provider === "unknown") {
139108
139879
  const gcPath = ".github/workflows/postman-preview-gc.yml";
139109
139880
  if (inputs.ciWorkflowPath.endsWith(".github/workflows/ci.yml") || inputs.ciWorkflowPath === ".github/workflows/ci.yml") {
139110
139881
  ensureDir(".github/workflows");
139111
- (0, import_node_fs4.writeFileSync)(gcPath, renderGcWorkflowTemplate());
139882
+ (0, import_node_fs5.writeFileSync)(gcPath, renderGcWorkflowTemplate());
139112
139883
  }
139113
139884
  }
139114
139885
  }
@@ -139116,16 +139887,16 @@ async function commitAndPushGeneratedFiles(inputs, dependencies) {
139116
139887
  return { commitSha: "", resolvedCurrentRef: "", pushed: false };
139117
139888
  }
139118
139889
  const provisionPath = ".github/workflows/provision.yml";
139119
- const provisionExists = inputs.provider === "github" && (0, import_node_fs4.existsSync)(provisionPath);
139890
+ const provisionExists = inputs.provider === "github" && (0, import_node_fs5.existsSync)(provisionPath);
139120
139891
  const gcWorkflowPath = ".github/workflows/postman-preview-gc.yml";
139121
- const gcExists = inputs.generateCiWorkflow && (0, import_node_fs4.existsSync)(gcWorkflowPath);
139892
+ const gcExists = inputs.generateCiWorkflow && (0, import_node_fs5.existsSync)(gcWorkflowPath);
139122
139893
  const stagePaths = [
139123
139894
  inputs.artifactDir,
139124
139895
  ".postman",
139125
139896
  inputs.generateCiWorkflow ? inputs.ciWorkflowPath : null,
139126
139897
  gcExists ? gcWorkflowPath : null,
139127
139898
  provisionExists ? provisionPath : null
139128
- ].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));
139129
139900
  if (stagePaths.length === 0) {
139130
139901
  dependencies.core.info("No generated repository paths were found; skipping repo mutation.");
139131
139902
  return {
@@ -139233,6 +140004,7 @@ async function runRepoSyncInner(inputs, dependencies) {
139233
140004
  }
139234
140005
  }
139235
140006
  }
140007
+ const preparedPrebuiltCollections = await preparePrebuiltCollections(inputs);
139236
140008
  let skipRepositoryLinkPost = false;
139237
140009
  let repositoryLinkPreflightWasFree = false;
139238
140010
  if (inputs.workspaceLinkEnabled && inputs.workspaceId && inputs.repoUrl && dependencies.internalIntegration?.findWorkspaceForRepo) {
@@ -139269,6 +140041,7 @@ async function runRepoSyncInner(inputs, dependencies) {
139269
140041
  const branchAssetMarker = buildBranchAssetMarker(branchDecision, inputs);
139270
140042
  const envUids = await upsertEnvironments(inputs, dependencies, resourcesState, branchAssetMarker);
139271
140043
  outputs["environment-uids-json"] = JSON.stringify(envUids);
140044
+ dependencies.core.setOutput("environment-uids-json", outputs["environment-uids-json"]);
139272
140045
  if (inputs.environmentSyncEnabled && inputs.workspaceId && dependencies.internalIntegration) {
139273
140046
  const associations = Object.entries(envUids).map(([envName, envUid]) => ({
139274
140047
  envUid,
@@ -139387,6 +140160,7 @@ async function runRepoSyncInner(inputs, dependencies) {
139387
140160
  }
139388
140161
  }
139389
140162
  outputs["mock-url"] = resolvedMockUrl;
140163
+ dependencies.core.setOutput("mock-url", resolvedMockUrl);
139390
140164
  }
139391
140165
  }
139392
140166
  if (inputs.workspaceId && inputs.smokeCollectionId && Object.keys(envUids).length > 0) {
@@ -139462,6 +140236,7 @@ async function runRepoSyncInner(inputs, dependencies) {
139462
140236
  }
139463
140237
  }
139464
140238
  outputs["monitor-id"] = resolvedMonitorId;
140239
+ dependencies.core.setOutput("monitor-id", resolvedMonitorId);
139465
140240
  if (!effectiveCron && resolvedMonitorId) {
139466
140241
  try {
139467
140242
  await dependencies.postman.runMonitor(resolvedMonitorId);
@@ -139519,7 +140294,8 @@ async function runRepoSyncInner(inputs, dependencies) {
139519
140294
  priorWorkspaceId: resourcesState?.workspace?.id,
139520
140295
  existingSpecs: resourcesState?.cloudResources?.specs,
139521
140296
  releaseLabel,
139522
- priorState: resourcesState
140297
+ priorState: resourcesState,
140298
+ preparedPrebuiltCollections
139523
140299
  });
139524
140300
  const commit = await commitAndPushGeneratedFiles(inputs, dependencies);
139525
140301
  outputs["commit-sha"] = commit.commitSha;
@@ -139745,7 +140521,12 @@ async function resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, mas
139745
140521
  bifrostBaseUrl: inputs.postmanBifrostBase,
139746
140522
  // No fallback on the org-mode probe: the expected non-org 400 must
139747
140523
  // surface verbatim, not be re-fired against the /_api alias.
139748
- 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
+ }
139749
140530
  });
139750
140531
  const squads = await gateway.getSquads(teamId);
139751
140532
  if (squads.length > 0) {
@@ -139809,7 +140590,12 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
139809
140590
  fallbackBaseUrl: inputs.postmanFallbackBase,
139810
140591
  teamId: resolved.teamId,
139811
140592
  orgMode: inputs.orgMode,
139812
- 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
+ }
139813
140599
  });
139814
140600
  const gatewayAssets = new PostmanGatewayAssetsClient({
139815
140601
  gateway,
@@ -139877,7 +140663,8 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
139877
140663
  bifrostBaseUrl: inputs.postmanBifrostBase,
139878
140664
  orgMode: inputs.orgMode,
139879
140665
  teamId: resolved.teamId,
139880
- secretMasker: masker
140666
+ secretMasker: masker,
140667
+ gateway
139881
140668
  });
139882
140669
  return {
139883
140670
  teamId: resolved.teamId,
@@ -139927,7 +140714,10 @@ async function runAction(actionCore = core_exports, actionExec = exec_exports) {
139927
140714
  }
139928
140715
  await mintAccessTokenIfNeeded(inputs, {
139929
140716
  info: (message) => actionCore.info(message),
139930
- 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
+ )
139931
140721
  }, (secret) => actionCore.setSecret(secret));
139932
140722
  const masker = createSecretMasker([
139933
140723
  inputs.postmanApiKey,
@@ -139948,7 +140738,12 @@ async function runAction(actionCore = core_exports, actionExec = exec_exports) {
139948
140738
  explicitTeamId: inputs.teamId || void 0,
139949
140739
  mode: inputs.credentialPreflight,
139950
140740
  mask: masker,
139951
- 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
+ }
139952
140747
  });
139953
140748
  const resolved = await resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, masker, {
139954
140749
  env: process.env
@@ -139989,6 +140784,7 @@ async function runAction(actionCore = core_exports, actionExec = exec_exports) {
139989
140784
  decideBranchTier,
139990
140785
  getInput,
139991
140786
  hasInput,
140787
+ prebuiltDirectoryTraversalIdentity,
139992
140788
  readActionInputs,
139993
140789
  resolveInputs,
139994
140790
  resolvePostmanApiKeyAndTeamId,