@postman-cse/onboarding-repo-sync 2.1.18 → 2.1.19
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/README.md +3 -1
- package/dist/action.cjs +155 -23
- package/dist/cli.cjs +155 -23
- package/dist/index.cjs +155 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -113,6 +113,8 @@ with:
|
|
|
113
113
|
monitor-id: 1e2f3a4b-monitor-id
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
+
Repo-sync supports public mocks for anonymous validation. An explicit `mock-url` must match one mock in the resolved workspace and reference the expected baseline collection and environment. Discovered and newly created mocks pass the same live visibility check. Private mocks, responses without a recognized visibility field, stale URLs, and identity mismatches fail before `mock-url` is emitted; repo-sync never places a Postman API key in a collection or environment to make a private mock callable.
|
|
117
|
+
|
|
116
118
|
### mTLS certificates for Postman CLI runs
|
|
117
119
|
|
|
118
120
|
The generated CI workflow can run [Postman CLI collection runs](https://learning.postman.com/docs/postman-cli/postman-cli-collections/) with client certificates. Pass the cert material as inputs; when a GitHub token and repository context are available, the action persists them as repository secrets (`POSTMAN_SSL_CLIENT_CERT_B64`, `POSTMAN_SSL_CLIENT_KEY_B64`, `POSTMAN_SSL_CLIENT_PASSPHRASE`, `POSTMAN_SSL_EXTRA_CA_CERTS_B64`) for the generated workflow:
|
|
@@ -283,7 +285,7 @@ For `commit-and-push`, the push target is resolved from `current-ref`, then `GIT
|
|
|
283
285
|
|
|
284
286
|
Mocks and monitors: when `baseline-collection-id`, `workspace-id`, and at least one environment are available, the action creates or reuses a mock server. When `smoke-collection-id` is also available, it creates or reuses a cloud smoke monitor unless `monitor-type: cli` is set. With an empty `monitor-cron`, a new cloud monitor is created disabled and triggered once per workflow invocation.
|
|
285
287
|
|
|
286
|
-
Asset reuse priority is explicit inputs (`environment-uids-json`, `mock-url`, `monitor-id`), then live discovery by exact workspace-scoped name, collection UID, and environment UID, then create. Creates submit once and reconcile on ambiguous gateway errors; overlapping compatible creates inside one process share a single in-flight promise. Adopted environments are updated to the requested values. Mock environment assignment has no verified patch route, so a mock is reused only when its live environment already matches; mismatches are never claimed as converged. Concurrent jobs against the same workspace can still race because Postman does not expose create idempotency keys—serialize those workflows with GitHub Actions `concurrency` (or an equivalent CI lock) when duplicate mocks/monitors/environments would be harmful.
|
|
288
|
+
Asset reuse priority is explicit inputs (`environment-uids-json`, `mock-url`, `monitor-id`), then live discovery by exact workspace-scoped name, collection UID, and environment UID, then create. Mock reuse is public-only: the gateway's live `published` field must confirm public visibility, and explicit URLs must match the expected workspace, collection, and environment. Private or unknown visibility fails closed without injecting credentials. Creates submit once and reconcile on ambiguous gateway errors; overlapping compatible creates inside one process share a single in-flight promise. Adopted environments are updated to the requested values. Mock environment assignment has no verified patch route, so a mock is reused only when its live environment already matches; mismatches are never claimed as converged. Concurrent jobs against the same workspace can still race because Postman does not expose create idempotency keys—serialize those workflows with GitHub Actions `concurrency` (or an equivalent CI lock) when duplicate mocks/monitors/environments would be harmful.
|
|
287
289
|
|
|
288
290
|
Deeper reference:
|
|
289
291
|
|
package/dist/action.cjs
CHANGED
|
@@ -136941,6 +136941,25 @@ var PostmanAssetsClient = class {
|
|
|
136941
136941
|
};
|
|
136942
136942
|
|
|
136943
136943
|
// src/lib/postman/postman-gateway-assets-client.ts
|
|
136944
|
+
var MockContractError = class extends Error {
|
|
136945
|
+
constructor(message) {
|
|
136946
|
+
super(message);
|
|
136947
|
+
this.name = "MockContractError";
|
|
136948
|
+
}
|
|
136949
|
+
};
|
|
136950
|
+
function requirePublicMock(mock) {
|
|
136951
|
+
if (mock.visibility === "private") {
|
|
136952
|
+
throw new MockContractError(
|
|
136953
|
+
`MOCK_NOT_PUBLIC: Mock ${mock.uid} is private. Make it public in Postman or remove/rename it so repo-sync can create the canonical public mock.`
|
|
136954
|
+
);
|
|
136955
|
+
}
|
|
136956
|
+
if (mock.visibility !== "public") {
|
|
136957
|
+
throw new MockContractError(
|
|
136958
|
+
`MOCK_VISIBILITY_UNKNOWN: Mock ${mock.uid} did not expose a supported visibility field. Refusing to assume it is publicly callable.`
|
|
136959
|
+
);
|
|
136960
|
+
}
|
|
136961
|
+
return mock;
|
|
136962
|
+
}
|
|
136944
136963
|
var MAX_CREATE_FLIGHTS = 256;
|
|
136945
136964
|
var createFlights = /* @__PURE__ */ new Map();
|
|
136946
136965
|
var PostmanGatewayAssetsClient = class {
|
|
@@ -137122,6 +137141,41 @@ var PostmanGatewayAssetsClient = class {
|
|
|
137122
137141
|
const id = record.uid ?? record.id;
|
|
137123
137142
|
return typeof id === "string" ? id.trim() : String(id ?? "").trim();
|
|
137124
137143
|
}
|
|
137144
|
+
decodeMockRecord(value, operation) {
|
|
137145
|
+
const record = this.asRecord(value);
|
|
137146
|
+
if (!record) {
|
|
137147
|
+
throw new MockContractError(
|
|
137148
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned a non-object mock record`
|
|
137149
|
+
);
|
|
137150
|
+
}
|
|
137151
|
+
const uid = this.idOf(record);
|
|
137152
|
+
const name = typeof record.name === "string" ? record.name.trim() : "";
|
|
137153
|
+
const collection = typeof record.collection === "string" ? record.collection.trim() : "";
|
|
137154
|
+
const mockUrl = typeof (record.url ?? record.mockUrl) === "string" ? String(record.url ?? record.mockUrl).trim() : "";
|
|
137155
|
+
const environment = typeof record.environment === "string" ? record.environment.trim() : "";
|
|
137156
|
+
if (!uid) {
|
|
137157
|
+
throw new MockContractError(
|
|
137158
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned a mock without a UID`
|
|
137159
|
+
);
|
|
137160
|
+
}
|
|
137161
|
+
if (!name) {
|
|
137162
|
+
throw new MockContractError(
|
|
137163
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned mock ${uid} without a name`
|
|
137164
|
+
);
|
|
137165
|
+
}
|
|
137166
|
+
if (!collection) {
|
|
137167
|
+
throw new MockContractError(
|
|
137168
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned mock ${uid} without a collection UID`
|
|
137169
|
+
);
|
|
137170
|
+
}
|
|
137171
|
+
if (!mockUrl) {
|
|
137172
|
+
throw new MockContractError(
|
|
137173
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned mock ${uid} without a URL`
|
|
137174
|
+
);
|
|
137175
|
+
}
|
|
137176
|
+
const visibility = typeof record.published === "boolean" ? record.published ? "public" : "private" : "unknown";
|
|
137177
|
+
return { uid, name, collection, mockUrl, environment, visibility };
|
|
137178
|
+
}
|
|
137125
137179
|
/**
|
|
137126
137180
|
* Reduce a Postman public uid (`<owner>-<uuid>`, 6 hyphen groups) to the bare
|
|
137127
137181
|
* model id (`<uuid>`, 5 groups), mirroring `decomposeUID`. Used ONLY for the
|
|
@@ -137422,7 +137476,8 @@ var PostmanGatewayAssetsClient = class {
|
|
|
137422
137476
|
return this.singleFlight(flightKey, flightKey, "mock", async () => {
|
|
137423
137477
|
const existing = await this.findMockByCollection(collection, environment, mockName);
|
|
137424
137478
|
if (existing) {
|
|
137425
|
-
|
|
137479
|
+
const reusable = requirePublicMock(existing);
|
|
137480
|
+
return { uid: reusable.uid, url: reusable.mockUrl };
|
|
137426
137481
|
}
|
|
137427
137482
|
const body = {
|
|
137428
137483
|
name: mockName,
|
|
@@ -137445,13 +137500,12 @@ var PostmanGatewayAssetsClient = class {
|
|
|
137445
137500
|
);
|
|
137446
137501
|
const parseMock = (response) => {
|
|
137447
137502
|
const record = this.dataOf(response);
|
|
137448
|
-
const
|
|
137449
|
-
|
|
137450
|
-
|
|
137451
|
-
}
|
|
137503
|
+
const created = requirePublicMock(
|
|
137504
|
+
this.decodeMockRecord(record, "Mock create")
|
|
137505
|
+
);
|
|
137452
137506
|
return {
|
|
137453
|
-
uid,
|
|
137454
|
-
url:
|
|
137507
|
+
uid: created.uid,
|
|
137508
|
+
url: created.mockUrl
|
|
137455
137509
|
};
|
|
137456
137510
|
};
|
|
137457
137511
|
try {
|
|
@@ -137462,7 +137516,8 @@ var PostmanGatewayAssetsClient = class {
|
|
|
137462
137516
|
error2
|
|
137463
137517
|
);
|
|
137464
137518
|
if (adopted) {
|
|
137465
|
-
|
|
137519
|
+
const reusable = requirePublicMock(adopted);
|
|
137520
|
+
return { uid: reusable.uid, url: reusable.mockUrl };
|
|
137466
137521
|
}
|
|
137467
137522
|
if (adopted === void 0) {
|
|
137468
137523
|
const retried = await this.resendAbsentCreate(async () => parseMock(await send2("auto")));
|
|
@@ -137478,14 +137533,14 @@ var PostmanGatewayAssetsClient = class {
|
|
|
137478
137533
|
method: "get",
|
|
137479
137534
|
path: `/mocks?workspace=${this.workspaceId}`
|
|
137480
137535
|
});
|
|
137481
|
-
const
|
|
137482
|
-
|
|
137483
|
-
|
|
137484
|
-
|
|
137485
|
-
|
|
137486
|
-
|
|
137487
|
-
|
|
137488
|
-
|
|
137536
|
+
const envelope = this.asRecord(response);
|
|
137537
|
+
const items = Array.isArray(response) ? response : Array.isArray(envelope?.data) ? envelope.data : null;
|
|
137538
|
+
if (!items) {
|
|
137539
|
+
throw new MockContractError(
|
|
137540
|
+
"CONTRACT_MOCK_RESPONSE_INVALID: Mock list envelope must be an array or contain a data array"
|
|
137541
|
+
);
|
|
137542
|
+
}
|
|
137543
|
+
return items.map((raw) => this.decodeMockRecord(raw, "Mock list"));
|
|
137489
137544
|
}
|
|
137490
137545
|
/**
|
|
137491
137546
|
* Delete an environment through the sync service (GC path). The path id is
|
|
@@ -137539,7 +137594,7 @@ var PostmanGatewayAssetsClient = class {
|
|
|
137539
137594
|
`workspace ${this.workspaceId}, name "${mockName}", collection ${want}, and environment ${environment || "(none)"}`,
|
|
137540
137595
|
matches
|
|
137541
137596
|
);
|
|
137542
|
-
return match
|
|
137597
|
+
return match;
|
|
137543
137598
|
}
|
|
137544
137599
|
// --- monitors (service: monitors; collection-based = jobTemplates) ---
|
|
137545
137600
|
/** Map raw jobTemplate records to the facade shape; `collection` is a flat public uid. */
|
|
@@ -138469,6 +138524,61 @@ function resolveRepoSyncMasker(dependencies) {
|
|
|
138469
138524
|
function causeText(cause) {
|
|
138470
138525
|
return cause instanceof Error ? cause.message : String(cause);
|
|
138471
138526
|
}
|
|
138527
|
+
function normalizeMockUrl(value, source) {
|
|
138528
|
+
let url;
|
|
138529
|
+
try {
|
|
138530
|
+
url = new URL(String(value || "").trim());
|
|
138531
|
+
} catch {
|
|
138532
|
+
throw new MockContractError(
|
|
138533
|
+
`EXPLICIT_MOCK_URL_INVALID: ${source} is not a valid absolute URL`
|
|
138534
|
+
);
|
|
138535
|
+
}
|
|
138536
|
+
if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash) {
|
|
138537
|
+
throw new MockContractError(
|
|
138538
|
+
`EXPLICIT_MOCK_URL_INVALID: ${source} must be an HTTPS URL without credentials, query parameters, or a fragment`
|
|
138539
|
+
);
|
|
138540
|
+
}
|
|
138541
|
+
url.pathname = url.pathname.replace(/\/+$/g, "") || "/";
|
|
138542
|
+
return url.toString();
|
|
138543
|
+
}
|
|
138544
|
+
function resolveExplicitPublicMock(mocks, explicitUrl, collectionUid, environmentUid) {
|
|
138545
|
+
const normalized = normalizeMockUrl(explicitUrl, "mock-url");
|
|
138546
|
+
const matches = mocks.filter(
|
|
138547
|
+
(mock) => normalizeMockUrl(mock.mockUrl, `mock ${mock.uid} URL`) === normalized
|
|
138548
|
+
);
|
|
138549
|
+
if (matches.length === 0) {
|
|
138550
|
+
throw new MockContractError(
|
|
138551
|
+
`EXPLICIT_MOCK_URL_NOT_FOUND: mock-url was not found in the resolved workspace mock inventory`
|
|
138552
|
+
);
|
|
138553
|
+
}
|
|
138554
|
+
if (matches.length > 1) {
|
|
138555
|
+
throw new MockContractError(
|
|
138556
|
+
`EXPLICIT_MOCK_URL_AMBIGUOUS: mock-url matched multiple workspace mocks (${matches.map((mock) => mock.uid).join(", ")})`
|
|
138557
|
+
);
|
|
138558
|
+
}
|
|
138559
|
+
const match = matches[0];
|
|
138560
|
+
if (match.collection !== collectionUid) {
|
|
138561
|
+
throw new MockContractError(
|
|
138562
|
+
`EXPLICIT_MOCK_IDENTITY_MISMATCH: Mock ${match.uid} references collection ${match.collection || "(none)"}, expected ${collectionUid}`
|
|
138563
|
+
);
|
|
138564
|
+
}
|
|
138565
|
+
if (match.environment !== environmentUid) {
|
|
138566
|
+
throw new MockContractError(
|
|
138567
|
+
`EXPLICIT_MOCK_IDENTITY_MISMATCH: Mock ${match.uid} references environment ${match.environment || "(none)"}, expected ${environmentUid}`
|
|
138568
|
+
);
|
|
138569
|
+
}
|
|
138570
|
+
return requirePublicMock(match);
|
|
138571
|
+
}
|
|
138572
|
+
function shouldRetryMockCreate(error2) {
|
|
138573
|
+
if (error2 instanceof MockContractError) return false;
|
|
138574
|
+
if (error2 instanceof HttpError) {
|
|
138575
|
+
return error2.status === 408 || error2.status === 429 || error2.status >= 500;
|
|
138576
|
+
}
|
|
138577
|
+
if (error2 instanceof Error && error2.message.startsWith("Multiple mocks match ")) {
|
|
138578
|
+
return false;
|
|
138579
|
+
}
|
|
138580
|
+
return true;
|
|
138581
|
+
}
|
|
138472
138582
|
function toOneLineDisplay(value) {
|
|
138473
138583
|
return String(value ?? "").replace(/[\r\n\u0085\u2028\u2029\v\f]+/g, " ").replace(/[ \t]{2,}/g, " ").trim();
|
|
138474
138584
|
}
|
|
@@ -140095,20 +140205,37 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
140095
140205
|
let resolvedMockUrl = "";
|
|
140096
140206
|
const mockName = `${assetProjectName} Mock`;
|
|
140097
140207
|
if (inputs.mockUrl) {
|
|
140098
|
-
|
|
140208
|
+
let mocks;
|
|
140209
|
+
try {
|
|
140210
|
+
mocks = await dependencies.postman.listMocks();
|
|
140211
|
+
} catch (error2) {
|
|
140212
|
+
throw new Error(
|
|
140213
|
+
formatOrchestrationIssue({
|
|
140214
|
+
operation: "Explicit mock-url lookup",
|
|
140215
|
+
entity: `mock-url ${inputs.mockUrl} workspace ${inputs.workspaceId} collection ${inputs.baselineCollectionId} environment ${mockEnvUid}`,
|
|
140216
|
+
cause: error2,
|
|
140217
|
+
remediation: "verify the URL and mock access then rerun",
|
|
140218
|
+
mask
|
|
140219
|
+
}),
|
|
140220
|
+
{ cause: error2 }
|
|
140221
|
+
);
|
|
140222
|
+
}
|
|
140223
|
+
resolvedMockUrl = resolveExplicitPublicMock(
|
|
140224
|
+
mocks,
|
|
140225
|
+
inputs.mockUrl,
|
|
140226
|
+
inputs.baselineCollectionId,
|
|
140227
|
+
mockEnvUid
|
|
140228
|
+
).mockUrl;
|
|
140099
140229
|
dependencies.core.info(`Reusing mock from explicit input: ${resolvedMockUrl}`);
|
|
140100
140230
|
}
|
|
140101
140231
|
if (!resolvedMockUrl && inputs.baselineCollectionId) {
|
|
140232
|
+
let discovered;
|
|
140102
140233
|
try {
|
|
140103
|
-
|
|
140234
|
+
discovered = await dependencies.postman.findMockByCollection(
|
|
140104
140235
|
inputs.baselineCollectionId,
|
|
140105
140236
|
mockEnvUid,
|
|
140106
140237
|
mockName
|
|
140107
140238
|
);
|
|
140108
|
-
if (discovered) {
|
|
140109
|
-
resolvedMockUrl = discovered.mockUrl;
|
|
140110
|
-
dependencies.core.info(`Discovered existing mock for collection ${inputs.baselineCollectionId}: ${resolvedMockUrl}`);
|
|
140111
|
-
}
|
|
140112
140239
|
} catch (error2) {
|
|
140113
140240
|
throw new Error(
|
|
140114
140241
|
formatOrchestrationIssue({
|
|
@@ -140121,6 +140248,10 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
140121
140248
|
{ cause: error2 }
|
|
140122
140249
|
);
|
|
140123
140250
|
}
|
|
140251
|
+
if (discovered) {
|
|
140252
|
+
resolvedMockUrl = requirePublicMock(discovered).mockUrl;
|
|
140253
|
+
dependencies.core.info(`Discovered existing mock for collection ${inputs.baselineCollectionId}: ${resolvedMockUrl}`);
|
|
140254
|
+
}
|
|
140124
140255
|
}
|
|
140125
140256
|
if (!resolvedMockUrl) {
|
|
140126
140257
|
const mockEntity = `mock "${mockName}" workspace ${inputs.workspaceId} collection ${inputs.baselineCollectionId} environment ${mockEnvUid}`;
|
|
@@ -140137,6 +140268,7 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
140137
140268
|
maxAttempts: 3,
|
|
140138
140269
|
delayMs: 2e3,
|
|
140139
140270
|
backoffMultiplier: 2,
|
|
140271
|
+
shouldRetry: (error2) => shouldRetryMockCreate(error2),
|
|
140140
140272
|
onRetry: ({ attempt, maxAttempts, error: error2 }) => {
|
|
140141
140273
|
dependencies.core.warning(
|
|
140142
140274
|
formatOrchestrationIssue({
|
package/dist/cli.cjs
CHANGED
|
@@ -135046,6 +135046,25 @@ var PostmanAssetsClient = class {
|
|
|
135046
135046
|
};
|
|
135047
135047
|
|
|
135048
135048
|
// src/lib/postman/postman-gateway-assets-client.ts
|
|
135049
|
+
var MockContractError = class extends Error {
|
|
135050
|
+
constructor(message) {
|
|
135051
|
+
super(message);
|
|
135052
|
+
this.name = "MockContractError";
|
|
135053
|
+
}
|
|
135054
|
+
};
|
|
135055
|
+
function requirePublicMock(mock) {
|
|
135056
|
+
if (mock.visibility === "private") {
|
|
135057
|
+
throw new MockContractError(
|
|
135058
|
+
`MOCK_NOT_PUBLIC: Mock ${mock.uid} is private. Make it public in Postman or remove/rename it so repo-sync can create the canonical public mock.`
|
|
135059
|
+
);
|
|
135060
|
+
}
|
|
135061
|
+
if (mock.visibility !== "public") {
|
|
135062
|
+
throw new MockContractError(
|
|
135063
|
+
`MOCK_VISIBILITY_UNKNOWN: Mock ${mock.uid} did not expose a supported visibility field. Refusing to assume it is publicly callable.`
|
|
135064
|
+
);
|
|
135065
|
+
}
|
|
135066
|
+
return mock;
|
|
135067
|
+
}
|
|
135049
135068
|
var MAX_CREATE_FLIGHTS = 256;
|
|
135050
135069
|
var createFlights = /* @__PURE__ */ new Map();
|
|
135051
135070
|
var PostmanGatewayAssetsClient = class {
|
|
@@ -135227,6 +135246,41 @@ var PostmanGatewayAssetsClient = class {
|
|
|
135227
135246
|
const id = record.uid ?? record.id;
|
|
135228
135247
|
return typeof id === "string" ? id.trim() : String(id ?? "").trim();
|
|
135229
135248
|
}
|
|
135249
|
+
decodeMockRecord(value, operation) {
|
|
135250
|
+
const record = this.asRecord(value);
|
|
135251
|
+
if (!record) {
|
|
135252
|
+
throw new MockContractError(
|
|
135253
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned a non-object mock record`
|
|
135254
|
+
);
|
|
135255
|
+
}
|
|
135256
|
+
const uid = this.idOf(record);
|
|
135257
|
+
const name = typeof record.name === "string" ? record.name.trim() : "";
|
|
135258
|
+
const collection = typeof record.collection === "string" ? record.collection.trim() : "";
|
|
135259
|
+
const mockUrl = typeof (record.url ?? record.mockUrl) === "string" ? String(record.url ?? record.mockUrl).trim() : "";
|
|
135260
|
+
const environment = typeof record.environment === "string" ? record.environment.trim() : "";
|
|
135261
|
+
if (!uid) {
|
|
135262
|
+
throw new MockContractError(
|
|
135263
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned a mock without a UID`
|
|
135264
|
+
);
|
|
135265
|
+
}
|
|
135266
|
+
if (!name) {
|
|
135267
|
+
throw new MockContractError(
|
|
135268
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned mock ${uid} without a name`
|
|
135269
|
+
);
|
|
135270
|
+
}
|
|
135271
|
+
if (!collection) {
|
|
135272
|
+
throw new MockContractError(
|
|
135273
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned mock ${uid} without a collection UID`
|
|
135274
|
+
);
|
|
135275
|
+
}
|
|
135276
|
+
if (!mockUrl) {
|
|
135277
|
+
throw new MockContractError(
|
|
135278
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned mock ${uid} without a URL`
|
|
135279
|
+
);
|
|
135280
|
+
}
|
|
135281
|
+
const visibility = typeof record.published === "boolean" ? record.published ? "public" : "private" : "unknown";
|
|
135282
|
+
return { uid, name, collection, mockUrl, environment, visibility };
|
|
135283
|
+
}
|
|
135230
135284
|
/**
|
|
135231
135285
|
* Reduce a Postman public uid (`<owner>-<uuid>`, 6 hyphen groups) to the bare
|
|
135232
135286
|
* model id (`<uuid>`, 5 groups), mirroring `decomposeUID`. Used ONLY for the
|
|
@@ -135527,7 +135581,8 @@ var PostmanGatewayAssetsClient = class {
|
|
|
135527
135581
|
return this.singleFlight(flightKey, flightKey, "mock", async () => {
|
|
135528
135582
|
const existing = await this.findMockByCollection(collection, environment, mockName);
|
|
135529
135583
|
if (existing) {
|
|
135530
|
-
|
|
135584
|
+
const reusable = requirePublicMock(existing);
|
|
135585
|
+
return { uid: reusable.uid, url: reusable.mockUrl };
|
|
135531
135586
|
}
|
|
135532
135587
|
const body = {
|
|
135533
135588
|
name: mockName,
|
|
@@ -135550,13 +135605,12 @@ var PostmanGatewayAssetsClient = class {
|
|
|
135550
135605
|
);
|
|
135551
135606
|
const parseMock = (response) => {
|
|
135552
135607
|
const record = this.dataOf(response);
|
|
135553
|
-
const
|
|
135554
|
-
|
|
135555
|
-
|
|
135556
|
-
}
|
|
135608
|
+
const created = requirePublicMock(
|
|
135609
|
+
this.decodeMockRecord(record, "Mock create")
|
|
135610
|
+
);
|
|
135557
135611
|
return {
|
|
135558
|
-
uid,
|
|
135559
|
-
url:
|
|
135612
|
+
uid: created.uid,
|
|
135613
|
+
url: created.mockUrl
|
|
135560
135614
|
};
|
|
135561
135615
|
};
|
|
135562
135616
|
try {
|
|
@@ -135567,7 +135621,8 @@ var PostmanGatewayAssetsClient = class {
|
|
|
135567
135621
|
error
|
|
135568
135622
|
);
|
|
135569
135623
|
if (adopted) {
|
|
135570
|
-
|
|
135624
|
+
const reusable = requirePublicMock(adopted);
|
|
135625
|
+
return { uid: reusable.uid, url: reusable.mockUrl };
|
|
135571
135626
|
}
|
|
135572
135627
|
if (adopted === void 0) {
|
|
135573
135628
|
const retried = await this.resendAbsentCreate(async () => parseMock(await send2("auto")));
|
|
@@ -135583,14 +135638,14 @@ var PostmanGatewayAssetsClient = class {
|
|
|
135583
135638
|
method: "get",
|
|
135584
135639
|
path: `/mocks?workspace=${this.workspaceId}`
|
|
135585
135640
|
});
|
|
135586
|
-
const
|
|
135587
|
-
|
|
135588
|
-
|
|
135589
|
-
|
|
135590
|
-
|
|
135591
|
-
|
|
135592
|
-
|
|
135593
|
-
|
|
135641
|
+
const envelope = this.asRecord(response);
|
|
135642
|
+
const items = Array.isArray(response) ? response : Array.isArray(envelope?.data) ? envelope.data : null;
|
|
135643
|
+
if (!items) {
|
|
135644
|
+
throw new MockContractError(
|
|
135645
|
+
"CONTRACT_MOCK_RESPONSE_INVALID: Mock list envelope must be an array or contain a data array"
|
|
135646
|
+
);
|
|
135647
|
+
}
|
|
135648
|
+
return items.map((raw) => this.decodeMockRecord(raw, "Mock list"));
|
|
135594
135649
|
}
|
|
135595
135650
|
/**
|
|
135596
135651
|
* Delete an environment through the sync service (GC path). The path id is
|
|
@@ -135644,7 +135699,7 @@ var PostmanGatewayAssetsClient = class {
|
|
|
135644
135699
|
`workspace ${this.workspaceId}, name "${mockName}", collection ${want}, and environment ${environment || "(none)"}`,
|
|
135645
135700
|
matches
|
|
135646
135701
|
);
|
|
135647
|
-
return match
|
|
135702
|
+
return match;
|
|
135648
135703
|
}
|
|
135649
135704
|
// --- monitors (service: monitors; collection-based = jobTemplates) ---
|
|
135650
135705
|
/** Map raw jobTemplate records to the facade shape; `collection` is a flat public uid. */
|
|
@@ -136522,6 +136577,61 @@ function resolveRepoSyncMasker(dependencies) {
|
|
|
136522
136577
|
function causeText(cause) {
|
|
136523
136578
|
return cause instanceof Error ? cause.message : String(cause);
|
|
136524
136579
|
}
|
|
136580
|
+
function normalizeMockUrl(value, source) {
|
|
136581
|
+
let url;
|
|
136582
|
+
try {
|
|
136583
|
+
url = new URL(String(value || "").trim());
|
|
136584
|
+
} catch {
|
|
136585
|
+
throw new MockContractError(
|
|
136586
|
+
`EXPLICIT_MOCK_URL_INVALID: ${source} is not a valid absolute URL`
|
|
136587
|
+
);
|
|
136588
|
+
}
|
|
136589
|
+
if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash) {
|
|
136590
|
+
throw new MockContractError(
|
|
136591
|
+
`EXPLICIT_MOCK_URL_INVALID: ${source} must be an HTTPS URL without credentials, query parameters, or a fragment`
|
|
136592
|
+
);
|
|
136593
|
+
}
|
|
136594
|
+
url.pathname = url.pathname.replace(/\/+$/g, "") || "/";
|
|
136595
|
+
return url.toString();
|
|
136596
|
+
}
|
|
136597
|
+
function resolveExplicitPublicMock(mocks, explicitUrl, collectionUid, environmentUid) {
|
|
136598
|
+
const normalized = normalizeMockUrl(explicitUrl, "mock-url");
|
|
136599
|
+
const matches = mocks.filter(
|
|
136600
|
+
(mock) => normalizeMockUrl(mock.mockUrl, `mock ${mock.uid} URL`) === normalized
|
|
136601
|
+
);
|
|
136602
|
+
if (matches.length === 0) {
|
|
136603
|
+
throw new MockContractError(
|
|
136604
|
+
`EXPLICIT_MOCK_URL_NOT_FOUND: mock-url was not found in the resolved workspace mock inventory`
|
|
136605
|
+
);
|
|
136606
|
+
}
|
|
136607
|
+
if (matches.length > 1) {
|
|
136608
|
+
throw new MockContractError(
|
|
136609
|
+
`EXPLICIT_MOCK_URL_AMBIGUOUS: mock-url matched multiple workspace mocks (${matches.map((mock) => mock.uid).join(", ")})`
|
|
136610
|
+
);
|
|
136611
|
+
}
|
|
136612
|
+
const match = matches[0];
|
|
136613
|
+
if (match.collection !== collectionUid) {
|
|
136614
|
+
throw new MockContractError(
|
|
136615
|
+
`EXPLICIT_MOCK_IDENTITY_MISMATCH: Mock ${match.uid} references collection ${match.collection || "(none)"}, expected ${collectionUid}`
|
|
136616
|
+
);
|
|
136617
|
+
}
|
|
136618
|
+
if (match.environment !== environmentUid) {
|
|
136619
|
+
throw new MockContractError(
|
|
136620
|
+
`EXPLICIT_MOCK_IDENTITY_MISMATCH: Mock ${match.uid} references environment ${match.environment || "(none)"}, expected ${environmentUid}`
|
|
136621
|
+
);
|
|
136622
|
+
}
|
|
136623
|
+
return requirePublicMock(match);
|
|
136624
|
+
}
|
|
136625
|
+
function shouldRetryMockCreate(error) {
|
|
136626
|
+
if (error instanceof MockContractError) return false;
|
|
136627
|
+
if (error instanceof HttpError) {
|
|
136628
|
+
return error.status === 408 || error.status === 429 || error.status >= 500;
|
|
136629
|
+
}
|
|
136630
|
+
if (error instanceof Error && error.message.startsWith("Multiple mocks match ")) {
|
|
136631
|
+
return false;
|
|
136632
|
+
}
|
|
136633
|
+
return true;
|
|
136634
|
+
}
|
|
136525
136635
|
function toOneLineDisplay(value) {
|
|
136526
136636
|
return String(value ?? "").replace(/[\r\n\u0085\u2028\u2029\v\f]+/g, " ").replace(/[ \t]{2,}/g, " ").trim();
|
|
136527
136637
|
}
|
|
@@ -138005,20 +138115,37 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
138005
138115
|
let resolvedMockUrl = "";
|
|
138006
138116
|
const mockName = `${assetProjectName} Mock`;
|
|
138007
138117
|
if (inputs.mockUrl) {
|
|
138008
|
-
|
|
138118
|
+
let mocks;
|
|
138119
|
+
try {
|
|
138120
|
+
mocks = await dependencies.postman.listMocks();
|
|
138121
|
+
} catch (error) {
|
|
138122
|
+
throw new Error(
|
|
138123
|
+
formatOrchestrationIssue({
|
|
138124
|
+
operation: "Explicit mock-url lookup",
|
|
138125
|
+
entity: `mock-url ${inputs.mockUrl} workspace ${inputs.workspaceId} collection ${inputs.baselineCollectionId} environment ${mockEnvUid}`,
|
|
138126
|
+
cause: error,
|
|
138127
|
+
remediation: "verify the URL and mock access then rerun",
|
|
138128
|
+
mask
|
|
138129
|
+
}),
|
|
138130
|
+
{ cause: error }
|
|
138131
|
+
);
|
|
138132
|
+
}
|
|
138133
|
+
resolvedMockUrl = resolveExplicitPublicMock(
|
|
138134
|
+
mocks,
|
|
138135
|
+
inputs.mockUrl,
|
|
138136
|
+
inputs.baselineCollectionId,
|
|
138137
|
+
mockEnvUid
|
|
138138
|
+
).mockUrl;
|
|
138009
138139
|
dependencies.core.info(`Reusing mock from explicit input: ${resolvedMockUrl}`);
|
|
138010
138140
|
}
|
|
138011
138141
|
if (!resolvedMockUrl && inputs.baselineCollectionId) {
|
|
138142
|
+
let discovered;
|
|
138012
138143
|
try {
|
|
138013
|
-
|
|
138144
|
+
discovered = await dependencies.postman.findMockByCollection(
|
|
138014
138145
|
inputs.baselineCollectionId,
|
|
138015
138146
|
mockEnvUid,
|
|
138016
138147
|
mockName
|
|
138017
138148
|
);
|
|
138018
|
-
if (discovered) {
|
|
138019
|
-
resolvedMockUrl = discovered.mockUrl;
|
|
138020
|
-
dependencies.core.info(`Discovered existing mock for collection ${inputs.baselineCollectionId}: ${resolvedMockUrl}`);
|
|
138021
|
-
}
|
|
138022
138149
|
} catch (error) {
|
|
138023
138150
|
throw new Error(
|
|
138024
138151
|
formatOrchestrationIssue({
|
|
@@ -138031,6 +138158,10 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
138031
138158
|
{ cause: error }
|
|
138032
138159
|
);
|
|
138033
138160
|
}
|
|
138161
|
+
if (discovered) {
|
|
138162
|
+
resolvedMockUrl = requirePublicMock(discovered).mockUrl;
|
|
138163
|
+
dependencies.core.info(`Discovered existing mock for collection ${inputs.baselineCollectionId}: ${resolvedMockUrl}`);
|
|
138164
|
+
}
|
|
138034
138165
|
}
|
|
138035
138166
|
if (!resolvedMockUrl) {
|
|
138036
138167
|
const mockEntity = `mock "${mockName}" workspace ${inputs.workspaceId} collection ${inputs.baselineCollectionId} environment ${mockEnvUid}`;
|
|
@@ -138047,6 +138178,7 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
138047
138178
|
maxAttempts: 3,
|
|
138048
138179
|
delayMs: 2e3,
|
|
138049
138180
|
backoffMultiplier: 2,
|
|
138181
|
+
shouldRetry: (error) => shouldRetryMockCreate(error),
|
|
138050
138182
|
onRetry: ({ attempt, maxAttempts, error }) => {
|
|
138051
138183
|
dependencies.core.warning(
|
|
138052
138184
|
formatOrchestrationIssue({
|
package/dist/index.cjs
CHANGED
|
@@ -136963,6 +136963,25 @@ var PostmanAssetsClient = class {
|
|
|
136963
136963
|
};
|
|
136964
136964
|
|
|
136965
136965
|
// src/lib/postman/postman-gateway-assets-client.ts
|
|
136966
|
+
var MockContractError = class extends Error {
|
|
136967
|
+
constructor(message) {
|
|
136968
|
+
super(message);
|
|
136969
|
+
this.name = "MockContractError";
|
|
136970
|
+
}
|
|
136971
|
+
};
|
|
136972
|
+
function requirePublicMock(mock) {
|
|
136973
|
+
if (mock.visibility === "private") {
|
|
136974
|
+
throw new MockContractError(
|
|
136975
|
+
`MOCK_NOT_PUBLIC: Mock ${mock.uid} is private. Make it public in Postman or remove/rename it so repo-sync can create the canonical public mock.`
|
|
136976
|
+
);
|
|
136977
|
+
}
|
|
136978
|
+
if (mock.visibility !== "public") {
|
|
136979
|
+
throw new MockContractError(
|
|
136980
|
+
`MOCK_VISIBILITY_UNKNOWN: Mock ${mock.uid} did not expose a supported visibility field. Refusing to assume it is publicly callable.`
|
|
136981
|
+
);
|
|
136982
|
+
}
|
|
136983
|
+
return mock;
|
|
136984
|
+
}
|
|
136966
136985
|
var MAX_CREATE_FLIGHTS = 256;
|
|
136967
136986
|
var createFlights = /* @__PURE__ */ new Map();
|
|
136968
136987
|
var PostmanGatewayAssetsClient = class {
|
|
@@ -137144,6 +137163,41 @@ var PostmanGatewayAssetsClient = class {
|
|
|
137144
137163
|
const id = record.uid ?? record.id;
|
|
137145
137164
|
return typeof id === "string" ? id.trim() : String(id ?? "").trim();
|
|
137146
137165
|
}
|
|
137166
|
+
decodeMockRecord(value, operation) {
|
|
137167
|
+
const record = this.asRecord(value);
|
|
137168
|
+
if (!record) {
|
|
137169
|
+
throw new MockContractError(
|
|
137170
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned a non-object mock record`
|
|
137171
|
+
);
|
|
137172
|
+
}
|
|
137173
|
+
const uid = this.idOf(record);
|
|
137174
|
+
const name = typeof record.name === "string" ? record.name.trim() : "";
|
|
137175
|
+
const collection = typeof record.collection === "string" ? record.collection.trim() : "";
|
|
137176
|
+
const mockUrl = typeof (record.url ?? record.mockUrl) === "string" ? String(record.url ?? record.mockUrl).trim() : "";
|
|
137177
|
+
const environment = typeof record.environment === "string" ? record.environment.trim() : "";
|
|
137178
|
+
if (!uid) {
|
|
137179
|
+
throw new MockContractError(
|
|
137180
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned a mock without a UID`
|
|
137181
|
+
);
|
|
137182
|
+
}
|
|
137183
|
+
if (!name) {
|
|
137184
|
+
throw new MockContractError(
|
|
137185
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned mock ${uid} without a name`
|
|
137186
|
+
);
|
|
137187
|
+
}
|
|
137188
|
+
if (!collection) {
|
|
137189
|
+
throw new MockContractError(
|
|
137190
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned mock ${uid} without a collection UID`
|
|
137191
|
+
);
|
|
137192
|
+
}
|
|
137193
|
+
if (!mockUrl) {
|
|
137194
|
+
throw new MockContractError(
|
|
137195
|
+
`CONTRACT_MOCK_RESPONSE_INVALID: ${operation} returned mock ${uid} without a URL`
|
|
137196
|
+
);
|
|
137197
|
+
}
|
|
137198
|
+
const visibility = typeof record.published === "boolean" ? record.published ? "public" : "private" : "unknown";
|
|
137199
|
+
return { uid, name, collection, mockUrl, environment, visibility };
|
|
137200
|
+
}
|
|
137147
137201
|
/**
|
|
137148
137202
|
* Reduce a Postman public uid (`<owner>-<uuid>`, 6 hyphen groups) to the bare
|
|
137149
137203
|
* model id (`<uuid>`, 5 groups), mirroring `decomposeUID`. Used ONLY for the
|
|
@@ -137444,7 +137498,8 @@ var PostmanGatewayAssetsClient = class {
|
|
|
137444
137498
|
return this.singleFlight(flightKey, flightKey, "mock", async () => {
|
|
137445
137499
|
const existing = await this.findMockByCollection(collection, environment, mockName);
|
|
137446
137500
|
if (existing) {
|
|
137447
|
-
|
|
137501
|
+
const reusable = requirePublicMock(existing);
|
|
137502
|
+
return { uid: reusable.uid, url: reusable.mockUrl };
|
|
137448
137503
|
}
|
|
137449
137504
|
const body = {
|
|
137450
137505
|
name: mockName,
|
|
@@ -137467,13 +137522,12 @@ var PostmanGatewayAssetsClient = class {
|
|
|
137467
137522
|
);
|
|
137468
137523
|
const parseMock = (response) => {
|
|
137469
137524
|
const record = this.dataOf(response);
|
|
137470
|
-
const
|
|
137471
|
-
|
|
137472
|
-
|
|
137473
|
-
}
|
|
137525
|
+
const created = requirePublicMock(
|
|
137526
|
+
this.decodeMockRecord(record, "Mock create")
|
|
137527
|
+
);
|
|
137474
137528
|
return {
|
|
137475
|
-
uid,
|
|
137476
|
-
url:
|
|
137529
|
+
uid: created.uid,
|
|
137530
|
+
url: created.mockUrl
|
|
137477
137531
|
};
|
|
137478
137532
|
};
|
|
137479
137533
|
try {
|
|
@@ -137484,7 +137538,8 @@ var PostmanGatewayAssetsClient = class {
|
|
|
137484
137538
|
error2
|
|
137485
137539
|
);
|
|
137486
137540
|
if (adopted) {
|
|
137487
|
-
|
|
137541
|
+
const reusable = requirePublicMock(adopted);
|
|
137542
|
+
return { uid: reusable.uid, url: reusable.mockUrl };
|
|
137488
137543
|
}
|
|
137489
137544
|
if (adopted === void 0) {
|
|
137490
137545
|
const retried = await this.resendAbsentCreate(async () => parseMock(await send2("auto")));
|
|
@@ -137500,14 +137555,14 @@ var PostmanGatewayAssetsClient = class {
|
|
|
137500
137555
|
method: "get",
|
|
137501
137556
|
path: `/mocks?workspace=${this.workspaceId}`
|
|
137502
137557
|
});
|
|
137503
|
-
const
|
|
137504
|
-
|
|
137505
|
-
|
|
137506
|
-
|
|
137507
|
-
|
|
137508
|
-
|
|
137509
|
-
|
|
137510
|
-
|
|
137558
|
+
const envelope = this.asRecord(response);
|
|
137559
|
+
const items = Array.isArray(response) ? response : Array.isArray(envelope?.data) ? envelope.data : null;
|
|
137560
|
+
if (!items) {
|
|
137561
|
+
throw new MockContractError(
|
|
137562
|
+
"CONTRACT_MOCK_RESPONSE_INVALID: Mock list envelope must be an array or contain a data array"
|
|
137563
|
+
);
|
|
137564
|
+
}
|
|
137565
|
+
return items.map((raw) => this.decodeMockRecord(raw, "Mock list"));
|
|
137511
137566
|
}
|
|
137512
137567
|
/**
|
|
137513
137568
|
* Delete an environment through the sync service (GC path). The path id is
|
|
@@ -137561,7 +137616,7 @@ var PostmanGatewayAssetsClient = class {
|
|
|
137561
137616
|
`workspace ${this.workspaceId}, name "${mockName}", collection ${want}, and environment ${environment || "(none)"}`,
|
|
137562
137617
|
matches
|
|
137563
137618
|
);
|
|
137564
|
-
return match
|
|
137619
|
+
return match;
|
|
137565
137620
|
}
|
|
137566
137621
|
// --- monitors (service: monitors; collection-based = jobTemplates) ---
|
|
137567
137622
|
/** Map raw jobTemplate records to the facade shape; `collection` is a flat public uid. */
|
|
@@ -138491,6 +138546,61 @@ function resolveRepoSyncMasker(dependencies) {
|
|
|
138491
138546
|
function causeText(cause) {
|
|
138492
138547
|
return cause instanceof Error ? cause.message : String(cause);
|
|
138493
138548
|
}
|
|
138549
|
+
function normalizeMockUrl(value, source) {
|
|
138550
|
+
let url;
|
|
138551
|
+
try {
|
|
138552
|
+
url = new URL(String(value || "").trim());
|
|
138553
|
+
} catch {
|
|
138554
|
+
throw new MockContractError(
|
|
138555
|
+
`EXPLICIT_MOCK_URL_INVALID: ${source} is not a valid absolute URL`
|
|
138556
|
+
);
|
|
138557
|
+
}
|
|
138558
|
+
if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash) {
|
|
138559
|
+
throw new MockContractError(
|
|
138560
|
+
`EXPLICIT_MOCK_URL_INVALID: ${source} must be an HTTPS URL without credentials, query parameters, or a fragment`
|
|
138561
|
+
);
|
|
138562
|
+
}
|
|
138563
|
+
url.pathname = url.pathname.replace(/\/+$/g, "") || "/";
|
|
138564
|
+
return url.toString();
|
|
138565
|
+
}
|
|
138566
|
+
function resolveExplicitPublicMock(mocks, explicitUrl, collectionUid, environmentUid) {
|
|
138567
|
+
const normalized = normalizeMockUrl(explicitUrl, "mock-url");
|
|
138568
|
+
const matches = mocks.filter(
|
|
138569
|
+
(mock) => normalizeMockUrl(mock.mockUrl, `mock ${mock.uid} URL`) === normalized
|
|
138570
|
+
);
|
|
138571
|
+
if (matches.length === 0) {
|
|
138572
|
+
throw new MockContractError(
|
|
138573
|
+
`EXPLICIT_MOCK_URL_NOT_FOUND: mock-url was not found in the resolved workspace mock inventory`
|
|
138574
|
+
);
|
|
138575
|
+
}
|
|
138576
|
+
if (matches.length > 1) {
|
|
138577
|
+
throw new MockContractError(
|
|
138578
|
+
`EXPLICIT_MOCK_URL_AMBIGUOUS: mock-url matched multiple workspace mocks (${matches.map((mock) => mock.uid).join(", ")})`
|
|
138579
|
+
);
|
|
138580
|
+
}
|
|
138581
|
+
const match = matches[0];
|
|
138582
|
+
if (match.collection !== collectionUid) {
|
|
138583
|
+
throw new MockContractError(
|
|
138584
|
+
`EXPLICIT_MOCK_IDENTITY_MISMATCH: Mock ${match.uid} references collection ${match.collection || "(none)"}, expected ${collectionUid}`
|
|
138585
|
+
);
|
|
138586
|
+
}
|
|
138587
|
+
if (match.environment !== environmentUid) {
|
|
138588
|
+
throw new MockContractError(
|
|
138589
|
+
`EXPLICIT_MOCK_IDENTITY_MISMATCH: Mock ${match.uid} references environment ${match.environment || "(none)"}, expected ${environmentUid}`
|
|
138590
|
+
);
|
|
138591
|
+
}
|
|
138592
|
+
return requirePublicMock(match);
|
|
138593
|
+
}
|
|
138594
|
+
function shouldRetryMockCreate(error2) {
|
|
138595
|
+
if (error2 instanceof MockContractError) return false;
|
|
138596
|
+
if (error2 instanceof HttpError) {
|
|
138597
|
+
return error2.status === 408 || error2.status === 429 || error2.status >= 500;
|
|
138598
|
+
}
|
|
138599
|
+
if (error2 instanceof Error && error2.message.startsWith("Multiple mocks match ")) {
|
|
138600
|
+
return false;
|
|
138601
|
+
}
|
|
138602
|
+
return true;
|
|
138603
|
+
}
|
|
138494
138604
|
function toOneLineDisplay(value) {
|
|
138495
138605
|
return String(value ?? "").replace(/[\r\n\u0085\u2028\u2029\v\f]+/g, " ").replace(/[ \t]{2,}/g, " ").trim();
|
|
138496
138606
|
}
|
|
@@ -140117,20 +140227,37 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
140117
140227
|
let resolvedMockUrl = "";
|
|
140118
140228
|
const mockName = `${assetProjectName} Mock`;
|
|
140119
140229
|
if (inputs.mockUrl) {
|
|
140120
|
-
|
|
140230
|
+
let mocks;
|
|
140231
|
+
try {
|
|
140232
|
+
mocks = await dependencies.postman.listMocks();
|
|
140233
|
+
} catch (error2) {
|
|
140234
|
+
throw new Error(
|
|
140235
|
+
formatOrchestrationIssue({
|
|
140236
|
+
operation: "Explicit mock-url lookup",
|
|
140237
|
+
entity: `mock-url ${inputs.mockUrl} workspace ${inputs.workspaceId} collection ${inputs.baselineCollectionId} environment ${mockEnvUid}`,
|
|
140238
|
+
cause: error2,
|
|
140239
|
+
remediation: "verify the URL and mock access then rerun",
|
|
140240
|
+
mask
|
|
140241
|
+
}),
|
|
140242
|
+
{ cause: error2 }
|
|
140243
|
+
);
|
|
140244
|
+
}
|
|
140245
|
+
resolvedMockUrl = resolveExplicitPublicMock(
|
|
140246
|
+
mocks,
|
|
140247
|
+
inputs.mockUrl,
|
|
140248
|
+
inputs.baselineCollectionId,
|
|
140249
|
+
mockEnvUid
|
|
140250
|
+
).mockUrl;
|
|
140121
140251
|
dependencies.core.info(`Reusing mock from explicit input: ${resolvedMockUrl}`);
|
|
140122
140252
|
}
|
|
140123
140253
|
if (!resolvedMockUrl && inputs.baselineCollectionId) {
|
|
140254
|
+
let discovered;
|
|
140124
140255
|
try {
|
|
140125
|
-
|
|
140256
|
+
discovered = await dependencies.postman.findMockByCollection(
|
|
140126
140257
|
inputs.baselineCollectionId,
|
|
140127
140258
|
mockEnvUid,
|
|
140128
140259
|
mockName
|
|
140129
140260
|
);
|
|
140130
|
-
if (discovered) {
|
|
140131
|
-
resolvedMockUrl = discovered.mockUrl;
|
|
140132
|
-
dependencies.core.info(`Discovered existing mock for collection ${inputs.baselineCollectionId}: ${resolvedMockUrl}`);
|
|
140133
|
-
}
|
|
140134
140261
|
} catch (error2) {
|
|
140135
140262
|
throw new Error(
|
|
140136
140263
|
formatOrchestrationIssue({
|
|
@@ -140143,6 +140270,10 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
140143
140270
|
{ cause: error2 }
|
|
140144
140271
|
);
|
|
140145
140272
|
}
|
|
140273
|
+
if (discovered) {
|
|
140274
|
+
resolvedMockUrl = requirePublicMock(discovered).mockUrl;
|
|
140275
|
+
dependencies.core.info(`Discovered existing mock for collection ${inputs.baselineCollectionId}: ${resolvedMockUrl}`);
|
|
140276
|
+
}
|
|
140146
140277
|
}
|
|
140147
140278
|
if (!resolvedMockUrl) {
|
|
140148
140279
|
const mockEntity = `mock "${mockName}" workspace ${inputs.workspaceId} collection ${inputs.baselineCollectionId} environment ${mockEnvUid}`;
|
|
@@ -140159,6 +140290,7 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
140159
140290
|
maxAttempts: 3,
|
|
140160
140291
|
delayMs: 2e3,
|
|
140161
140292
|
backoffMultiplier: 2,
|
|
140293
|
+
shouldRetry: (error2) => shouldRetryMockCreate(error2),
|
|
140162
140294
|
onRetry: ({ attempt, maxAttempts, error: error2 }) => {
|
|
140163
140295
|
dependencies.core.warning(
|
|
140164
140296
|
formatOrchestrationIssue({
|