@postman-cs/onboarding-repo-sync 2.10.7 → 2.10.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -109084,7 +109084,7 @@ var import_node_child_process = require("node:child_process");
109084
109084
  var import_node_fs7 = require("node:fs");
109085
109085
  var import_promises = require("node:fs/promises");
109086
109086
  var import_node_path4 = __toESM(require("node:path"), 1);
109087
- var import_node_util = require("node:util");
109087
+ var import_node_util2 = require("node:util");
109088
109088
 
109089
109089
  // node_modules/@actions/http-client/lib/index.js
109090
109090
  var tunnel = __toESM(require_tunnel2(), 1);
@@ -115824,6 +115824,7 @@ var path = __toESM(require("node:path"), 1);
115824
115824
  var V2 = __toESM(require_v2(), 1);
115825
115825
  var import_transforms = __toESM(require_transforms(), 1);
115826
115826
  var import_v3 = __toESM(require_node2(), 1);
115827
+ var V2_COLLECTION_MODEL = V2.Collection;
115827
115828
  function asArray(value) {
115828
115829
  return Array.isArray(value) ? value : [];
115829
115830
  }
@@ -115844,13 +115845,23 @@ function normalizeGraphqlRequests(node) {
115844
115845
  }
115845
115846
  }
115846
115847
  async function convertAndSplitCollection(v2Collection, outputDir) {
115847
- const model = V2.Collection;
115848
- const parsed = model.parse(v2Collection ?? {});
115849
- const v3 = (0, import_transforms.transform)(model, import_transforms.FormatVersion.V3, parsed);
115848
+ const v3 = convertV2CollectionToV3Collection(v2Collection);
115849
+ await writeSplitCollection(v3, outputDir);
115850
+ }
115851
+ function convertV2CollectionToV3Collection(v2Collection) {
115852
+ const parsed = V2_COLLECTION_MODEL.parse(v2Collection ?? {});
115853
+ const v3 = (0, import_transforms.transform)(
115854
+ V2_COLLECTION_MODEL,
115855
+ import_transforms.FormatVersion.V3,
115856
+ parsed
115857
+ );
115850
115858
  for (const item of asArray(v3.items)) {
115851
115859
  normalizeGraphqlRequests(item);
115852
115860
  }
115853
- await writeSplitCollection(v3, outputDir);
115861
+ return v3;
115862
+ }
115863
+ function assertV2CollectionModel(value) {
115864
+ V2_COLLECTION_MODEL.parse(value ?? {});
115854
115865
  }
115855
115866
  function normalizeV3ExportIds(node) {
115856
115867
  if (!node || typeof node !== "object") return;
@@ -119408,7 +119419,7 @@ var postmanRepoSyncActionContract = {
119408
119419
  allowedValues: ["full", "spec-only"]
119409
119420
  },
119410
119421
  "prebuilt-collections-json": {
119411
- 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.",
119422
+ 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 a cloud snapshot read.",
119412
119423
  required: false,
119413
119424
  default: ""
119414
119425
  },
@@ -119743,6 +119754,9 @@ var PostmanAssetsClient = class {
119743
119754
  }
119744
119755
  };
119745
119756
 
119757
+ // src/lib/postman/postman-gateway-assets-client.ts
119758
+ var import_node_util = require("node:util");
119759
+
119746
119760
  // node_modules/acorn/dist/acorn.mjs
119747
119761
  var astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 574, 3, 9, 9, 7, 9, 32, 4, 318, 1, 78, 5, 71, 10, 50, 3, 123, 2, 54, 14, 32, 10, 3, 1, 11, 3, 46, 10, 8, 0, 46, 9, 7, 2, 37, 13, 2, 9, 6, 1, 45, 0, 13, 2, 49, 13, 9, 3, 2, 11, 83, 11, 7, 0, 3, 0, 158, 11, 6, 9, 7, 3, 56, 1, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 68, 8, 2, 0, 3, 0, 2, 3, 2, 4, 2, 0, 15, 1, 83, 17, 10, 9, 5, 0, 82, 19, 13, 9, 214, 6, 3, 8, 28, 1, 83, 16, 16, 9, 82, 12, 9, 9, 7, 19, 58, 14, 5, 9, 243, 14, 166, 9, 71, 5, 2, 1, 3, 3, 2, 0, 2, 1, 13, 9, 120, 6, 3, 6, 4, 0, 29, 9, 41, 6, 2, 3, 9, 0, 10, 10, 47, 15, 199, 7, 137, 9, 54, 7, 2, 7, 17, 9, 57, 21, 2, 13, 123, 5, 4, 0, 2, 1, 2, 6, 2, 0, 9, 9, 49, 4, 2, 1, 2, 4, 9, 9, 55, 9, 266, 3, 10, 1, 2, 0, 49, 6, 4, 4, 14, 10, 5350, 0, 7, 14, 11465, 27, 2343, 9, 87, 9, 39, 4, 60, 6, 26, 9, 535, 9, 470, 0, 2, 54, 8, 3, 82, 0, 12, 1, 19628, 1, 4178, 9, 519, 45, 3, 22, 543, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 513, 54, 5, 49, 9, 0, 15, 0, 23, 4, 2, 14, 1361, 6, 2, 16, 3, 6, 2, 1, 2, 4, 101, 0, 161, 6, 10, 9, 357, 0, 62, 13, 499, 13, 245, 1, 2, 9, 233, 0, 3, 0, 8, 1, 6, 0, 475, 6, 110, 6, 6, 9, 4759, 9, 787719, 239];
119748
119762
  var astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 14, 29, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 13, 10, 2, 14, 2, 6, 2, 1, 2, 10, 2, 14, 2, 6, 2, 1, 4, 51, 13, 310, 10, 21, 11, 7, 25, 5, 2, 41, 2, 8, 70, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 66, 18, 2, 1, 11, 21, 11, 25, 7, 25, 39, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 28, 43, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 56, 50, 14, 50, 14, 35, 39, 27, 10, 22, 251, 41, 7, 1, 17, 5, 57, 28, 11, 0, 9, 21, 43, 17, 47, 20, 28, 22, 13, 52, 58, 1, 3, 0, 14, 44, 33, 24, 27, 35, 30, 0, 3, 0, 9, 34, 4, 0, 13, 47, 15, 3, 22, 0, 2, 0, 36, 17, 2, 24, 20, 1, 64, 6, 2, 0, 2, 3, 2, 14, 2, 9, 8, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 19, 0, 13, 4, 31, 9, 2, 0, 3, 0, 2, 37, 2, 0, 26, 0, 2, 0, 45, 52, 19, 3, 21, 2, 31, 47, 21, 1, 2, 0, 185, 46, 42, 3, 37, 47, 21, 0, 60, 42, 14, 0, 72, 26, 38, 6, 186, 43, 117, 63, 32, 7, 3, 0, 3, 7, 2, 1, 2, 23, 16, 0, 2, 0, 95, 7, 3, 38, 17, 0, 2, 0, 29, 0, 11, 39, 8, 0, 22, 0, 12, 45, 20, 0, 19, 72, 200, 32, 32, 8, 2, 36, 18, 0, 50, 29, 113, 6, 2, 1, 2, 37, 22, 0, 26, 5, 2, 1, 2, 31, 15, 0, 24, 43, 261, 18, 16, 0, 2, 12, 2, 33, 125, 0, 80, 921, 103, 110, 18, 195, 2637, 96, 16, 1071, 18, 5, 26, 3994, 6, 582, 6842, 29, 1763, 568, 8, 30, 18, 78, 18, 29, 19, 47, 17, 3, 32, 20, 6, 18, 433, 44, 212, 63, 33, 24, 3, 24, 45, 74, 6, 0, 67, 12, 65, 1, 2, 0, 15, 4, 10, 7381, 42, 31, 98, 114, 8702, 3, 2, 6, 2, 1, 2, 290, 16, 0, 30, 2, 3, 0, 15, 3, 9, 395, 2309, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 1845, 30, 7, 5, 262, 61, 147, 44, 11, 6, 17, 0, 322, 29, 19, 43, 485, 27, 229, 29, 3, 0, 208, 30, 2, 2, 2, 1, 2, 6, 3, 4, 10, 1, 225, 6, 2, 3, 2, 1, 2, 14, 2, 196, 60, 67, 8, 0, 1205, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42719, 33, 4381, 3, 5773, 3, 7472, 16, 621, 2467, 541, 1507, 4938, 6, 8489];
@@ -125939,8 +125953,8 @@ var PostmanGatewayAssetsClient = class {
125939
125953
  }
125940
125954
  /**
125941
125955
  * Validate and normalize a collection public UID for routes that require the
125942
- * full owner-prefixed UID (`<owner>-<uuid>`, 6 hyphen segments): collection
125943
- * GET export, collection-root PATCH/read, and private-mock runtime auth.
125956
+ * full owner-prefixed UID (`<owner>-<uuid>`, 6 hyphen segments): populated
125957
+ * collection snapshot, collection-root PATCH/read, and private-mock runtime auth.
125944
125958
  *
125945
125959
  * - Trims once.
125946
125960
  * - Rejects empty values.
@@ -126252,32 +126266,52 @@ var PostmanGatewayAssetsClient = class {
126252
126266
  );
126253
126267
  return match?.uid ? { uid: match.uid, name: match.name } : null;
126254
126268
  }
126255
- // --- collection read (service: collection, v3 export) ---
126269
+ // --- collection read (service: sync, populated v2.1 snapshot) ---
126256
126270
  //
126257
- // The gateway `collection` service does NOT serve spec-generated uids on the
126258
- // v2 `/collections/:uid` path (404 RESOURCE_NOT_FOUND, live-probed). It DOES
126259
- // serve `GET /v3/collections/:id/export`, which returns the canonical v3
126260
- // collection IR (`{ data: { collection: { ... } } }`). That v3 IR is fed
126261
- // straight to `convertAndSplitV3Collection` — never round-tripped back to v2.
126262
- // The full owner-prefixed public UID must be sent verbatim; the bare model id
126263
- // is rejected on root mutation routes (403 FORBIDDEN) and must not be used
126264
- // here either, so the caller is responsible for passing the public UID.
126271
+ // This is the canonical full collection read used by
126272
+ // api-specification-service before whole-tree Sync updates. Collection v3
126273
+ // `/export` performs an expensive projection and has returned 500s for fresh
126274
+ // roots under provider load. The populated Sync read returns the complete
126275
+ // v2.1 model directly and is transformed in memory through the official
126276
+ // runtime.models V2 -> V3 pipeline before repository materialization.
126265
126277
  /**
126266
- * Fetch a collection's v3 IR through the gateway v3 export endpoint.
126267
- * Returns the `data.collection` object (canonical v3 shape with `$kind`
126268
- * discriminators, `items`, `variables`, `references`). Caller writes it to
126269
- * disk via `convertAndSplitV3Collection`. PMAK is never used for collection
126270
- * reads.
126278
+ * Fetch one complete v2.1 collection through a single retry-free populated
126279
+ * Sync GET. The response must be a v2.1 model for the requested public UID;
126280
+ * malformed or foreign snapshots fail closed. PMAK is never used.
126271
126281
  */
126272
126282
  async getCollection(uid) {
126273
126283
  const id = this.requireCollectionPublicUid(uid);
126274
126284
  const response = await this.gateway.requestJson({
126275
- service: "collection",
126285
+ service: "sync",
126276
126286
  method: "get",
126277
- path: `/v3/collections/${id}/export`
126278
- });
126279
- const data2 = this.asRecord(response?.data);
126280
- return data2?.collection ?? null;
126287
+ path: `/collection/${encodeURIComponent(id)}`,
126288
+ query: { populate: "true", format: "2.1.0", uid: "false" },
126289
+ retry: "none",
126290
+ fallback: "none"
126291
+ });
126292
+ const collection = this.asRecord(response?.data);
126293
+ const info = this.asRecord(collection?.info);
126294
+ const schema = typeof info?.schema === "string" ? info.schema.trim() : "";
126295
+ if (!collection || !info || typeof info.name !== "string" || !info.name.trim() || !/\/collection\/v2\.1\.0\/collection\.json\/?$/i.test(schema) || !Array.isArray(collection.item)) {
126296
+ throw new Error(
126297
+ "COLLECTION_SNAPSHOT_INVALID: populated Sync read did not return a complete v2.1 collection"
126298
+ );
126299
+ }
126300
+ try {
126301
+ assertV2CollectionModel(collection);
126302
+ } catch (error) {
126303
+ throw new Error(
126304
+ "COLLECTION_SNAPSHOT_INVALID: populated Sync payload failed v2.1 schema validation",
126305
+ { cause: error }
126306
+ );
126307
+ }
126308
+ const observedId = String(info._postman_id ?? collection.id ?? "").trim();
126309
+ if (!observedId || this.toModelId(observedId).toLowerCase() !== this.toModelId(id).toLowerCase()) {
126310
+ throw new Error(
126311
+ "COLLECTION_SNAPSHOT_INVALID: populated Sync read returned a different collection identity"
126312
+ );
126313
+ }
126314
+ return collection;
126281
126315
  }
126282
126316
  // --- mocks (service: mock) ---
126283
126317
  async createMock(workspaceId, name, collectionUid, environmentUid, requestedVisibility = "private") {
@@ -126345,79 +126379,160 @@ var PostmanGatewayAssetsClient = class {
126345
126379
  isAmbiguousTransportError(error) {
126346
126380
  return this.isRetryableIdempotentWriteOutcome(error);
126347
126381
  }
126348
- normalizeCollectionScripts(scripts) {
126349
- if (!Array.isArray(scripts)) return [];
126350
- return scripts.map((entry) => this.asRecord(entry)).filter((entry) => entry !== null);
126382
+ isRootPatchSnapshotConflict(error) {
126383
+ return error instanceof HttpError && [400, 409, 412].includes(error.status);
126384
+ }
126385
+ normalizeCollectionScripts(scripts, operation) {
126386
+ if (scripts === void 0 || scripts === null) return [];
126387
+ if (!Array.isArray(scripts)) {
126388
+ throw new Error(
126389
+ `PRIVATE_MOCK_AUTH_ROOT_INVALID: ${operation} returned a non-array scripts field.`
126390
+ );
126391
+ }
126392
+ const normalized = scripts.map((entry) => this.asRecord(entry));
126393
+ if (normalized.some((entry) => entry === null)) {
126394
+ throw new Error(
126395
+ `PRIVATE_MOCK_AUTH_ROOT_INVALID: ${operation} returned a non-object script entry.`
126396
+ );
126397
+ }
126398
+ return normalized;
126351
126399
  }
126352
126400
  rootScriptsIncludeManagedAuthHook(scripts) {
126353
126401
  return scripts.some((script) => isManagedPrivateMockAuthRootHook(script));
126354
126402
  }
126355
- buildPrivateMockRootScripts(existingScripts) {
126356
- const managedScript = {
126357
- type: PRIVATE_MOCK_AUTH_ROOT_TYPE,
126358
- code: PRIVATE_MOCK_AUTH_ROOT_SCRIPT,
126359
- language: "text/javascript"
126360
- };
126361
- return [...existingScripts, managedScript];
126403
+ expectedPrivateMockRootScripts(existingScripts) {
126404
+ return [
126405
+ ...existingScripts,
126406
+ {
126407
+ type: PRIVATE_MOCK_AUTH_ROOT_TYPE,
126408
+ code: PRIVATE_MOCK_AUTH_ROOT_SCRIPT,
126409
+ language: "text/javascript"
126410
+ }
126411
+ ];
126412
+ }
126413
+ assertAtMostOneManagedRootHook(scripts, operation) {
126414
+ const count = scripts.filter((script) => isManagedPrivateMockAuthRootHook(script)).length;
126415
+ if (count > 1) {
126416
+ throw new Error(
126417
+ `PRIVATE_MOCK_AUTH_ROOT_DUPLICATE: ${operation} contains ${count} exact managed hooks.`
126418
+ );
126419
+ }
126362
126420
  }
126363
126421
  async readCollectionRootScripts(collectionUid) {
126364
126422
  const id = this.requireCollectionPublicUid(collectionUid);
126365
- const response = await this.gateway.requestJson({
126366
- service: "collection",
126367
- method: "get",
126368
- path: `/v3/collections/${id}/export`
126369
- });
126423
+ const response = await this.gateway.requestJson(
126424
+ {
126425
+ service: "collection",
126426
+ method: "get",
126427
+ path: `/v3/collections/${id}`
126428
+ },
126429
+ // Root reconciliation is evidence, not a transient-success mechanism.
126430
+ // One response must prove the current state; never hide a 5xx by retrying.
126431
+ { retryTransient: false }
126432
+ );
126370
126433
  const data2 = this.asRecord(response?.data);
126371
- const collection = this.asRecord(data2?.collection);
126372
- if (!collection) {
126434
+ if (!data2) {
126373
126435
  throw new Error(
126374
- `PRIVATE_MOCK_AUTH_EXPORT_INVALID: Collection ${id} export did not return data.collection; refusing to configure private-mock root auth from an unexpected envelope.`
126436
+ `PRIVATE_MOCK_AUTH_ROOT_INVALID: Collection ${id} root read did not return data; refusing to configure private-mock root auth from an unexpected envelope.`
126375
126437
  );
126376
126438
  }
126377
- return this.normalizeCollectionScripts(collection.scripts);
126439
+ return this.normalizeCollectionScripts(data2.scripts, `Collection ${id} root read`);
126378
126440
  }
126379
- async patchCollectionRootScripts(collectionUid, scripts) {
126441
+ async patchCollectionRootScripts(collectionUid, existingScripts) {
126380
126442
  const id = this.requireCollectionPublicUid(collectionUid);
126381
- await this.gateway.requestJson(
126443
+ const expectedScripts = this.expectedPrivateMockRootScripts(existingScripts);
126444
+ const managedScript = expectedScripts.at(-1);
126445
+ const response = await this.gateway.requestJson(
126382
126446
  {
126383
126447
  service: "collection",
126384
126448
  method: "patch",
126385
126449
  path: `/v3/collections/${id}`,
126386
- body: [{ op: "add", path: "/scripts", value: scripts }]
126450
+ // Bootstrap creates these HTTP collections through Sync. Its current
126451
+ // collection-service wire projection materializes absent/null scripts
126452
+ // as `[]` before applying RFC 6902, so this pair is one atomic
126453
+ // compare-and-append. If that contract ever changes, `test` fails and
126454
+ // the append cannot overwrite or manufacture a scripts field.
126455
+ body: [
126456
+ { op: "test", path: "/scripts", value: existingScripts },
126457
+ { op: "add", path: "/scripts/-", value: managedScript }
126458
+ ]
126387
126459
  },
126388
126460
  { retryTransient: false }
126389
126461
  );
126462
+ const data2 = this.asRecord(response?.data);
126463
+ if (!data2) {
126464
+ throw new Error(
126465
+ `PRIVATE_MOCK_AUTH_ROOT_PATCH_INVALID: Collection ${id} root patch did not return data.`
126466
+ );
126467
+ }
126468
+ const scripts = this.normalizeCollectionScripts(data2.scripts, `Collection ${id} root patch`);
126469
+ if (!(0, import_node_util.isDeepStrictEqual)(scripts, expectedScripts)) {
126470
+ throw new Error(
126471
+ `PRIVATE_MOCK_AUTH_ROOT_PATCH_UNVERIFIED: Collection ${id} root patch response did not exactly preserve the prior scripts and append one managed hook.`
126472
+ );
126473
+ }
126474
+ return scripts;
126390
126475
  }
126391
126476
  /**
126392
126477
  * Add a secret-free runtime hook at the collection root. The PMAK value is
126393
126478
  * supplied only by the runner as a transient variable; this method persists
126394
126479
  * the variable name and header wiring, never the credential.
126395
126480
  */
126396
- async configurePrivateMockRuntimeAuth(collectionUid) {
126481
+ async configurePrivateMockRuntimeAuth(collectionUid, trustedRootScripts) {
126397
126482
  const cid = this.requireCollectionPublicUid(collectionUid);
126398
- const installFromFreshRoot = async (existingScripts) => {
126483
+ const installFromRootSnapshot = async (existingScripts) => {
126484
+ this.assertAtMostOneManagedRootHook(existingScripts, `Collection ${cid} root snapshot`);
126399
126485
  if (this.rootScriptsIncludeManagedAuthHook(existingScripts)) {
126400
126486
  return 0;
126401
126487
  }
126402
- const nextScripts = this.buildPrivateMockRootScripts(existingScripts);
126488
+ const expectedScripts = this.expectedPrivateMockRootScripts(existingScripts);
126403
126489
  try {
126404
- await this.patchCollectionRootScripts(cid, nextScripts);
126490
+ await this.patchCollectionRootScripts(cid, existingScripts);
126405
126491
  return 1;
126406
126492
  } catch (error) {
126493
+ if (this.isRootPatchSnapshotConflict(error)) {
126494
+ const currentScripts = await this.readCollectionRootScripts(cid);
126495
+ if ((0, import_node_util.isDeepStrictEqual)(currentScripts, expectedScripts)) {
126496
+ return 0;
126497
+ }
126498
+ throw error;
126499
+ }
126407
126500
  if (!this.isAmbiguousTransportError(error)) {
126408
126501
  throw error;
126409
126502
  }
126410
126503
  const freshScripts = await this.readCollectionRootScripts(cid);
126411
- if (this.rootScriptsIncludeManagedAuthHook(freshScripts)) {
126504
+ if ((0, import_node_util.isDeepStrictEqual)(freshScripts, expectedScripts)) {
126412
126505
  return 1;
126413
126506
  }
126414
- const recomputed = this.buildPrivateMockRootScripts(freshScripts);
126415
- await this.patchCollectionRootScripts(cid, recomputed);
126416
- return 1;
126507
+ if (!(0, import_node_util.isDeepStrictEqual)(freshScripts, existingScripts)) {
126508
+ throw new Error(
126509
+ `PRIVATE_MOCK_AUTH_ROOT_RECONCILE_DIVERGED: Collection ${cid} root scripts changed while reconciling an ambiguous patch.`,
126510
+ { cause: error }
126511
+ );
126512
+ }
126513
+ try {
126514
+ await this.patchCollectionRootScripts(cid, existingScripts);
126515
+ return 1;
126516
+ } catch (resendError) {
126517
+ if (!this.isAmbiguousTransportError(resendError)) {
126518
+ throw resendError;
126519
+ }
126520
+ const finalScripts = await this.readCollectionRootScripts(cid);
126521
+ if ((0, import_node_util.isDeepStrictEqual)(finalScripts, expectedScripts)) {
126522
+ return 1;
126523
+ }
126524
+ if (!(0, import_node_util.isDeepStrictEqual)(finalScripts, existingScripts)) {
126525
+ throw new Error(
126526
+ `PRIVATE_MOCK_AUTH_ROOT_RECONCILE_DIVERGED: Collection ${cid} root scripts changed after the ambiguous patch resend.`,
126527
+ { cause: resendError }
126528
+ );
126529
+ }
126530
+ throw resendError;
126531
+ }
126417
126532
  }
126418
126533
  };
126419
- const scripts = await this.readCollectionRootScripts(cid);
126420
- return installFromFreshRoot(scripts);
126534
+ const scripts = trustedRootScripts === void 0 ? await this.readCollectionRootScripts(cid) : this.normalizeCollectionScripts(trustedRootScripts, `Trusted collection ${cid} root`);
126535
+ return installFromRootSnapshot(scripts);
126421
126536
  }
126422
126537
  async listMocks() {
126423
126538
  const response = await this.gateway.requestJson({
@@ -126755,6 +126870,45 @@ function cloneCollection(collection) {
126755
126870
  return cloneCollectionNodeIterative(collection);
126756
126871
  }
126757
126872
  }
126873
+ function cleanManagedItemAuthScriptsInPlace(item, stripManagedBlocks) {
126874
+ if (!stripManagedBlocks) {
126875
+ return 0;
126876
+ }
126877
+ const scripts = item.scripts;
126878
+ if (!Array.isArray(scripts)) {
126879
+ return 0;
126880
+ }
126881
+ let strippedBlocks = 0;
126882
+ const nextScripts = [];
126883
+ for (const script of scripts) {
126884
+ if (!script || typeof script !== "object" || Array.isArray(script)) {
126885
+ nextScripts.push(script);
126886
+ continue;
126887
+ }
126888
+ const record = script;
126889
+ if (String(record.type ?? "") !== "beforeRequest") {
126890
+ nextScripts.push(record);
126891
+ continue;
126892
+ }
126893
+ const originalCode = String(record.code ?? "");
126894
+ const cleaned = stripManagedItemAuthBlocks(originalCode);
126895
+ if (cleaned === originalCode) {
126896
+ nextScripts.push(record);
126897
+ continue;
126898
+ }
126899
+ strippedBlocks += countManagedItemAuthBlocks(originalCode);
126900
+ if (!cleaned) {
126901
+ continue;
126902
+ }
126903
+ nextScripts.push({ ...record, code: cleaned });
126904
+ }
126905
+ if (nextScripts.length === 0) {
126906
+ delete item.scripts;
126907
+ } else {
126908
+ item.scripts = nextScripts;
126909
+ }
126910
+ return strippedBlocks;
126911
+ }
126758
126912
  function isPrivateMockLegacyExportCleanupEnabled() {
126759
126913
  const value = String(process.env.POSTMAN_PRIVATE_MOCK_LEGACY_EXPORT_CLEANUP ?? "").trim().toLowerCase();
126760
126914
  return value !== "off";
@@ -126763,52 +126917,23 @@ function verifyPrivateMockRootHook(collection) {
126763
126917
  const scripts = asArray2(collection.scripts);
126764
126918
  return scripts.some((script) => isManagedPrivateMockAuthRootHook(script));
126765
126919
  }
126920
+ function applyPrivateMockArtifactNodeCleanup(node, options = {}) {
126921
+ const stripManagedBlocks = options.stripManagedBlocks ?? isPrivateMockLegacyExportCleanupEnabled();
126922
+ const cloned = cloneCollection(node);
126923
+ return {
126924
+ node: cloned,
126925
+ strippedBlocks: cleanManagedItemAuthScriptsInPlace(cloned, stripManagedBlocks)
126926
+ };
126927
+ }
126766
126928
  function applyPrivateMockExportCleanup(collection, options = {}) {
126767
126929
  const stripManagedBlocks = options.stripManagedBlocks ?? isPrivateMockLegacyExportCleanupEnabled();
126768
126930
  const cloned = cloneCollection(collection);
126769
126931
  let strippedBlocks = 0;
126770
- const visitItem = (item) => {
126771
- if (!stripManagedBlocks) {
126772
- return;
126773
- }
126774
- const scripts = item.scripts;
126775
- if (!Array.isArray(scripts)) {
126776
- return;
126777
- }
126778
- const nextScripts = [];
126779
- for (const script of scripts) {
126780
- if (!script || typeof script !== "object" || Array.isArray(script)) {
126781
- nextScripts.push(script);
126782
- continue;
126783
- }
126784
- const record = script;
126785
- if (String(record.type ?? "") !== "beforeRequest") {
126786
- nextScripts.push(record);
126787
- continue;
126788
- }
126789
- const originalCode = String(record.code ?? "");
126790
- const cleaned = stripManagedItemAuthBlocks(originalCode);
126791
- if (cleaned === originalCode) {
126792
- nextScripts.push(record);
126793
- continue;
126794
- }
126795
- strippedBlocks += countManagedItemAuthBlocks(originalCode);
126796
- if (!cleaned) {
126797
- continue;
126798
- }
126799
- nextScripts.push({ ...record, code: cleaned });
126800
- }
126801
- if (nextScripts.length === 0) {
126802
- delete item.scripts;
126803
- } else {
126804
- item.scripts = nextScripts;
126805
- }
126806
- };
126807
126932
  const walkItemsIteratively = (rootItems) => {
126808
126933
  const stack = [...rootItems].reverse();
126809
126934
  while (stack.length > 0) {
126810
126935
  const item = stack.pop();
126811
- visitItem(item);
126936
+ strippedBlocks += cleanManagedItemAuthScriptsInPlace(item, stripManagedBlocks);
126812
126937
  for (const key of ["items", "children"]) {
126813
126938
  const nested = asArray2(item[key]);
126814
126939
  for (let i3 = nested.length - 1; i3 >= 0; i3 -= 1) {
@@ -128780,7 +128905,7 @@ function validateCanonicalV3CollectionFile(relative3, bytes) {
128780
128905
  );
128781
128906
  }
128782
128907
  }
128783
- async function digestAndValidatePrebuiltCollectionTree(files) {
128908
+ async function digestAndValidatePrebuiltCollectionTree(files, onFile) {
128784
128909
  if (!files.some((file) => file.relative === ".resources/definition.yaml")) {
128785
128910
  failPrebuiltCollections("prebuilt collection tree is missing .resources/definition.yaml");
128786
128911
  }
@@ -128808,6 +128933,7 @@ async function digestAndValidatePrebuiltCollectionTree(files) {
128808
128933
  );
128809
128934
  }
128810
128935
  validateCanonicalV3CollectionFile(file.relative, bytes);
128936
+ onFile?.(file, bytes);
128811
128937
  }
128812
128938
  return hash.digest("hex");
128813
128939
  }
@@ -128855,14 +128981,156 @@ function tryReusePrebuiltCollection(options) {
128855
128981
  }
128856
128982
  return prepared.artifactDigest === entry.artifactDigest;
128857
128983
  }
128984
+ function normalizeTrustedPrivateMockRootScripts(value, role) {
128985
+ if (value === void 0 || value === null) {
128986
+ return [];
128987
+ }
128988
+ if (!Array.isArray(value) || value.some((entry) => !isPlainObject2(entry))) {
128989
+ failPrebuiltCollections(
128990
+ `prebuilt ${role} collection root scripts must be an array of mappings`
128991
+ );
128992
+ }
128993
+ return value.map((entry) => ({ ...entry }));
128994
+ }
128995
+ function serializePrivateMockArtifactNode(node) {
128996
+ return Buffer.from(dump(node, {
128997
+ lineWidth: -1,
128998
+ noRefs: true,
128999
+ sortKeys: false
129000
+ }));
129001
+ }
129002
+ async function planPrivateMockPrebuiltArtifact(options) {
129003
+ const { role, collectionId, expectedPath, artifactDir, prepared } = options;
129004
+ if (!prepared || !tryReusePrebuiltCollection({
129005
+ prepared,
129006
+ expectedPath,
129007
+ expectedCloudId: collectionId
129008
+ })) {
129009
+ return void 0;
129010
+ }
129011
+ const files = listPrebuiltCollectionTreeFiles(prepared.confinedPath, artifactDir);
129012
+ const updates = [];
129013
+ let rootScripts;
129014
+ const stripManagedBlocks = isPrivateMockLegacyExportCleanupEnabled();
129015
+ const currentDigest = await digestAndValidatePrebuiltCollectionTree(files, (file, original) => {
129016
+ let parsed;
129017
+ try {
129018
+ parsed = load(original.toString("utf8"));
129019
+ } catch (error) {
129020
+ failPrebuiltCollections(
129021
+ `prebuilt ${role} collection changed to malformed YAML at ${file.relative} (${error instanceof Error ? error.message : String(error)})`
129022
+ );
129023
+ }
129024
+ if (!isPlainObject2(parsed)) {
129025
+ failPrebuiltCollections(
129026
+ `prebuilt ${role} collection file ${file.relative} must contain a YAML mapping`
129027
+ );
129028
+ }
129029
+ let nextNode;
129030
+ if (file.relative === ".resources/definition.yaml") {
129031
+ rootScripts = normalizeTrustedPrivateMockRootScripts(parsed.scripts, role);
129032
+ if (!rootScripts.some((script) => isManagedPrivateMockAuthRootHook(script))) {
129033
+ nextNode = {
129034
+ ...parsed,
129035
+ scripts: [
129036
+ ...rootScripts,
129037
+ {
129038
+ type: PRIVATE_MOCK_AUTH_ROOT_TYPE,
129039
+ code: PRIVATE_MOCK_AUTH_ROOT_SCRIPT,
129040
+ language: "text/javascript"
129041
+ }
129042
+ ]
129043
+ };
129044
+ }
129045
+ } else {
129046
+ const cleaned = applyPrivateMockArtifactNodeCleanup(parsed, { stripManagedBlocks });
129047
+ if (cleaned.strippedBlocks > 0) {
129048
+ nextNode = cleaned.node;
129049
+ }
129050
+ }
129051
+ if (nextNode) {
129052
+ const next = serializePrivateMockArtifactNode(nextNode);
129053
+ if (!next.equals(original)) {
129054
+ updates.push({
129055
+ absolute: file.absolute,
129056
+ relative: file.relative,
129057
+ original: Buffer.from(original),
129058
+ next
129059
+ });
129060
+ }
129061
+ }
129062
+ });
129063
+ if (currentDigest !== prepared.entry.artifactDigest) {
129064
+ failPrebuiltCollections(
129065
+ `prebuilt ${role} collection changed after initial validation; expected artifactDigest ${prepared.entry.artifactDigest}, observed ${currentDigest}`
129066
+ );
129067
+ }
129068
+ if (!rootScripts) {
129069
+ failPrebuiltCollections(`prebuilt ${role} collection root definition disappeared`);
129070
+ }
129071
+ return { prepared, rootScripts, updates };
129072
+ }
129073
+ function applyPrivateMockPrebuiltPlans(plans) {
129074
+ const updates = plans.flatMap((plan) => plan.updates);
129075
+ const seen = /* @__PURE__ */ new Set();
129076
+ for (const update of updates) {
129077
+ if (seen.has(update.absolute)) {
129078
+ failPrebuiltCollections(
129079
+ `private-mock artifact plan addressed ${update.relative} more than once`
129080
+ );
129081
+ }
129082
+ seen.add(update.absolute);
129083
+ let current2;
129084
+ try {
129085
+ const stat2 = (0, import_node_fs6.lstatSync)(update.absolute);
129086
+ if (stat2.isSymbolicLink() || !stat2.isFile()) {
129087
+ failPrebuiltCollections(
129088
+ `prebuilt collection tree file changed or became unsupported at ${update.relative}`
129089
+ );
129090
+ }
129091
+ current2 = (0, import_node_fs6.readFileSync)(update.absolute);
129092
+ } catch (error) {
129093
+ if (error instanceof Error && error.message.startsWith("CONTRACT_PREBUILT_COLLECTIONS_INVALID:")) {
129094
+ throw error;
129095
+ }
129096
+ failPrebuiltCollections(
129097
+ `prebuilt collection tree file changed or became unreadable at ${update.relative}`
129098
+ );
129099
+ }
129100
+ if (!current2.equals(update.original)) {
129101
+ failPrebuiltCollections(
129102
+ `prebuilt collection tree file changed before private-mock reconciliation at ${update.relative}`
129103
+ );
129104
+ }
129105
+ }
129106
+ const written = [];
129107
+ try {
129108
+ for (const update of updates) {
129109
+ (0, import_node_fs6.writeFileSync)(update.absolute, update.next);
129110
+ written.push(update);
129111
+ }
129112
+ } catch (error) {
129113
+ for (const update of written.reverse()) {
129114
+ try {
129115
+ (0, import_node_fs6.writeFileSync)(update.absolute, update.original);
129116
+ } catch {
129117
+ }
129118
+ }
129119
+ throw error;
129120
+ }
129121
+ for (const plan of plans) {
129122
+ plan.prepared.privateMockArtifactReady = true;
129123
+ }
129124
+ }
128858
129125
  async function preparePrivateMockCloudCollection(role, collectionId, postman) {
128859
- const col = await postman.getCollection(collectionId);
128860
- const { collection } = applyPrivateMockExportCleanup(col, {
129126
+ const snapshot = await postman.getCollection(collectionId);
129127
+ const v3Collection = convertV2CollectionToV3Collection(snapshot);
129128
+ const { collection } = applyPrivateMockExportCleanup(v3Collection, {
128861
129129
  stripManagedBlocks: isPrivateMockLegacyExportCleanupEnabled()
128862
129130
  });
128863
129131
  if (!verifyPrivateMockRootHook(collection)) {
128864
129132
  throw new Error(
128865
- `PRIVATE_MOCK_AUTH_ROOT_UNVERIFIED: Managed root hook missing from exported ${role} collection ${collectionId}`
129133
+ `PRIVATE_MOCK_AUTH_ROOT_UNVERIFIED: Managed root hook missing from populated ${role} collection snapshot ${collectionId}`
128866
129134
  );
128867
129135
  }
128868
129136
  return collection;
@@ -128894,20 +129162,23 @@ async function runBoundedInOrder(items, width, worker) {
128894
129162
  async function acquireCollectionArtifact(options) {
128895
129163
  const { role, collectionId, dirName, collectionsDir, prebuiltByRole, postman, core, privateMockAuth = false } = options;
128896
129164
  const expectedPath = `${collectionsDir}/${dirName}`;
128897
- const forceCloudExport = privateMockAuth;
128898
129165
  const entry = prebuiltByRole.get(role);
128899
- if (entry && !forceCloudExport && tryReusePrebuiltCollection({
129166
+ const exactPrebuilt = Boolean(entry && tryReusePrebuiltCollection({
128900
129167
  prepared: entry,
128901
129168
  expectedPath,
128902
129169
  expectedCloudId: collectionId
128903
- })) {
128904
- core.info(`Reusing prebuilt ${role} collection tree at ${expectedPath} (artifactDigest match)`);
129170
+ }));
129171
+ const reusePrebuilt = exactPrebuilt && (!privateMockAuth || entry?.privateMockArtifactReady === true);
129172
+ if (reusePrebuilt) {
129173
+ core.info(
129174
+ privateMockAuth ? `Reusing locally reconciled private-mock ${role} collection tree at ${expectedPath} (source artifactDigest match)` : `Reusing prebuilt ${role} collection tree at ${expectedPath} (artifactDigest match)`
129175
+ );
128905
129176
  return { reusePrebuilt: true };
128906
129177
  }
128907
129178
  if (entry) {
128908
- core.info(forceCloudExport ? `Private mock requires cloud export for ${role} collection to reconcile managed root hook; exporting from cloud` : `Prebuilt ${role} collection entry present but did not exactly match; exporting from cloud`);
129179
+ core.info(privateMockAuth ? `Private mock has no locally reconciled exact prebuilt ${role} collection; reading populated cloud snapshot` : `Prebuilt ${role} collection entry present but did not exactly match; reading populated cloud snapshot`);
128909
129180
  }
128910
- const cloud = forceCloudExport ? await preparePrivateMockCloudCollection(role, collectionId, postman) : await postman.getCollection(collectionId);
129181
+ const cloud = privateMockAuth ? await preparePrivateMockCloudCollection(role, collectionId, postman) : await postman.getCollection(collectionId);
128911
129182
  return { reusePrebuilt: false, cloudCollection: cloud };
128912
129183
  }
128913
129184
  async function exportCollectionArtifact(options) {
@@ -129582,19 +129853,49 @@ async function runRepoSyncInner(inputs, dependencies, executionContext) {
129582
129853
  "PRIVATE_MOCK_RUNTIME_AUTH_UNAVAILABLE: The Postman client cannot configure runtime x-api-key injection."
129583
129854
  );
129584
129855
  }
129856
+ const collectionTargets = [
129857
+ { role: "baseline", collectionUid: inputs.baselineCollectionId, kind: "Baseline" },
129858
+ { role: "smoke", collectionUid: inputs.smokeCollectionId, kind: "Smoke" },
129859
+ { role: "contract", collectionUid: inputs.contractCollectionId, kind: "Contract" }
129860
+ ].filter((target) => Boolean(target.collectionUid));
129861
+ const prebuiltPlans = /* @__PURE__ */ new Map();
129862
+ for (const target of collectionTargets) {
129863
+ const plan = await planPrivateMockPrebuiltArtifact({
129864
+ role: target.role,
129865
+ collectionId: target.collectionUid,
129866
+ expectedPath: `${inputs.artifactDir}/collections/${getCollectionDirectoryName(target.kind, assetProjectName)}`,
129867
+ artifactDir: inputs.artifactDir,
129868
+ prepared: preparedPrebuiltCollections.get(target.role)
129869
+ });
129870
+ if (plan) {
129871
+ prebuiltPlans.set(target.role, plan);
129872
+ }
129873
+ }
129585
129874
  const configured = [];
129586
129875
  const configuredUids = /* @__PURE__ */ new Set();
129587
- for (const { role, collectionUid } of [
129588
- { role: "baseline", collectionUid: inputs.baselineCollectionId },
129589
- { role: "smoke", collectionUid: inputs.smokeCollectionId },
129590
- { role: "contract", collectionUid: inputs.contractCollectionId }
129591
- ]) {
129592
- if (!collectionUid || configuredUids.has(collectionUid)) {
129876
+ for (const { role, collectionUid } of collectionTargets) {
129877
+ if (configuredUids.has(collectionUid)) {
129593
129878
  continue;
129594
129879
  }
129595
129880
  configuredUids.add(collectionUid);
129596
129881
  try {
129597
- await dependencies.postman.configurePrivateMockRuntimeAuth(collectionUid);
129882
+ const plansForUid = collectionTargets.filter((target) => target.collectionUid === collectionUid).map((target) => prebuiltPlans.get(target.role)).filter((plan) => Boolean(plan));
129883
+ const trustedRootScripts = plansForUid[0]?.rootScripts;
129884
+ if (trustedRootScripts && plansForUid.some(
129885
+ (plan) => JSON.stringify(plan.rootScripts) !== JSON.stringify(trustedRootScripts)
129886
+ )) {
129887
+ failPrebuiltCollections(
129888
+ `roles sharing collection ${collectionUid} disagree on trusted root scripts`
129889
+ );
129890
+ }
129891
+ if (trustedRootScripts) {
129892
+ await dependencies.postman.configurePrivateMockRuntimeAuth(
129893
+ collectionUid,
129894
+ trustedRootScripts
129895
+ );
129896
+ } else {
129897
+ await dependencies.postman.configurePrivateMockRuntimeAuth(collectionUid);
129898
+ }
129598
129899
  configured.push(collectionUid);
129599
129900
  } catch (error) {
129600
129901
  throw new Error(
@@ -129603,6 +129904,7 @@ async function runRepoSyncInner(inputs, dependencies, executionContext) {
129603
129904
  );
129604
129905
  }
129605
129906
  }
129907
+ applyPrivateMockPrebuiltPlans([...prebuiltPlans.values()]);
129606
129908
  if (configured.length > 0) {
129607
129909
  (dependencies.core.notice ?? dependencies.core.info)(
129608
129910
  `Private mock: installed a request hook on ${configured.length} collection(s) that sends the ${PRIVATE_MOCK_AUTH_VARIABLE2} variable as x-api-key, and only to *.mock.pstmn.io hosts. The generated CI workflow supplies it from the POSTMAN_API_KEY secret. For manual runs in the Postman app, set that variable to a key with access to the mock. No key is stored in the collection, environment, outputs, or repository.`
@@ -130121,9 +130423,9 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
130121
130423
  getEnvironment: gatewayAssets.getEnvironment.bind(gatewayAssets),
130122
130424
  updateEnvironment: gatewayAssets.updateEnvironment.bind(gatewayAssets),
130123
130425
  findEnvironmentByName: gatewayAssets.findEnvironmentByName.bind(gatewayAssets),
130124
- // Collection read via the v3 export endpoint — returns canonical v3 IR,
130125
- // written to disk by `convertAndSplitAnyCollection`. PMAK is never used for
130126
- // collection reads.
130426
+ // Collection read via one retry-free populated Sync GET — returns a full
130427
+ // v2.1 snapshot that the official runtime.models transform converts to v3
130428
+ // before repository materialization. PMAK is never used for reads.
130127
130429
  getCollection: gatewayAssets.getCollection.bind(gatewayAssets),
130128
130430
  // Mocks via the `mock` service, collection-based monitors via the `monitors`
130129
130431
  // service (jobTemplates). Both reference the collection by its full public
@@ -130682,7 +130984,7 @@ async function runGc(options) {
130682
130984
  }
130683
130985
 
130684
130986
  // src/cli.ts
130685
- var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
130987
+ var execFileAsync = (0, import_node_util2.promisify)(import_node_child_process.execFile);
130686
130988
  var CLI_INPUT_NAMES = [
130687
130989
  "working-directory",
130688
130990
  "project-name",