@postman-cse/onboarding-bootstrap 2.9.4 → 2.9.5
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 +9 -0
- package/action.yml +24 -0
- package/dist/action.cjs +1123 -154
- package/dist/cli.cjs +1145 -164
- package/dist/index.cjs +1140 -156
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -99990,11 +99990,11 @@ var require_valid = __commonJS({
|
|
|
99990
99990
|
var require_clean = __commonJS({
|
|
99991
99991
|
"node_modules/postman-collection/node_modules/semver/functions/clean.js"(exports2, module2) {
|
|
99992
99992
|
var parse10 = require_parse6();
|
|
99993
|
-
var
|
|
99993
|
+
var clean2 = (version, options) => {
|
|
99994
99994
|
const s = parse10(version.trim().replace(/^[=v]+/, ""), options);
|
|
99995
99995
|
return s ? s.version : null;
|
|
99996
99996
|
};
|
|
99997
|
-
module2.exports =
|
|
99997
|
+
module2.exports = clean2;
|
|
99998
99998
|
}
|
|
99999
99999
|
});
|
|
100000
100000
|
|
|
@@ -101305,7 +101305,7 @@ var require_semver2 = __commonJS({
|
|
|
101305
101305
|
var identifiers = require_identifiers();
|
|
101306
101306
|
var parse10 = require_parse6();
|
|
101307
101307
|
var valid = require_valid();
|
|
101308
|
-
var
|
|
101308
|
+
var clean2 = require_clean();
|
|
101309
101309
|
var inc = require_inc();
|
|
101310
101310
|
var diff = require_diff();
|
|
101311
101311
|
var major = require_major();
|
|
@@ -101343,7 +101343,7 @@ var require_semver2 = __commonJS({
|
|
|
101343
101343
|
module2.exports = {
|
|
101344
101344
|
parse: parse10,
|
|
101345
101345
|
valid,
|
|
101346
|
-
clean,
|
|
101346
|
+
clean: clean2,
|
|
101347
101347
|
inc,
|
|
101348
101348
|
diff,
|
|
101349
101349
|
major,
|
|
@@ -253789,7 +253789,7 @@ __export(cli_exports, {
|
|
|
253789
253789
|
toDotenv: () => toDotenv
|
|
253790
253790
|
});
|
|
253791
253791
|
module.exports = __toCommonJS(cli_exports);
|
|
253792
|
-
var
|
|
253792
|
+
var import_node_fs7 = require("node:fs");
|
|
253793
253793
|
var import_promises4 = require("node:fs/promises");
|
|
253794
253794
|
var import_node_child_process = require("node:child_process");
|
|
253795
253795
|
var import_node_path5 = __toESM(require("node:path"), 1);
|
|
@@ -254515,8 +254515,8 @@ var ExitCode;
|
|
|
254515
254515
|
})(ExitCode || (ExitCode = {}));
|
|
254516
254516
|
|
|
254517
254517
|
// src/index.ts
|
|
254518
|
-
var
|
|
254519
|
-
var
|
|
254518
|
+
var import_node_crypto6 = require("node:crypto");
|
|
254519
|
+
var import_node_fs6 = require("node:fs");
|
|
254520
254520
|
var path6 = __toESM(require("node:path"), 1);
|
|
254521
254521
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
254522
254522
|
|
|
@@ -254624,6 +254624,12 @@ var bootstrapActionContract = {
|
|
|
254624
254624
|
default: "",
|
|
254625
254625
|
allowedValues: ["3.0", "3.1"]
|
|
254626
254626
|
},
|
|
254627
|
+
"preserve-oas30-type-null": {
|
|
254628
|
+
description: "Opt-in compatibility mode for legacy OpenAPI 3.0 oneOf schemas that pair a normal schema with type: null. The original source bytes are uploaded unchanged while an internal nullable view is used for validation and generated artifacts.",
|
|
254629
|
+
required: false,
|
|
254630
|
+
default: "false",
|
|
254631
|
+
allowedValues: ["true", "false"]
|
|
254632
|
+
},
|
|
254627
254633
|
"breaking-change-mode": {
|
|
254628
254634
|
description: "OpenAPI breaking-change comparison mode.",
|
|
254629
254635
|
required: false,
|
|
@@ -254680,6 +254686,20 @@ var bootstrapActionContract = {
|
|
|
254680
254686
|
default: "warn",
|
|
254681
254687
|
allowedValues: ["enforce", "warn"]
|
|
254682
254688
|
},
|
|
254689
|
+
"branch-strategy": {
|
|
254690
|
+
description: "Branch-aware sync strategy. legacy (default) keeps branch-blind behavior; publish-gate restricts canonical writes to the canonical branch and runs credential-free static validation on other branches; preview additionally maintains suffixed per-branch preview asset sets.",
|
|
254691
|
+
required: false,
|
|
254692
|
+
default: "legacy",
|
|
254693
|
+
allowedValues: ["legacy", "preview", "publish-gate"]
|
|
254694
|
+
},
|
|
254695
|
+
"canonical-branch": {
|
|
254696
|
+
description: "Explicit canonical branch (the sole writer of canonical assets). Defaults to the provider-resolved default branch; required on providers without a default-branch variable (Bitbucket, Azure DevOps) when branch-strategy is not legacy.",
|
|
254697
|
+
required: false
|
|
254698
|
+
},
|
|
254699
|
+
"channels": {
|
|
254700
|
+
description: 'Comma-separated channel map for long-lived promotion branches, e.g. "develop=DEV, staging=STAGE, release/*=RC". Channel branches maintain prefix-named parallel asset sets and never mutate canonical assets.',
|
|
254701
|
+
required: false
|
|
254702
|
+
},
|
|
254683
254703
|
"integration-backend": {
|
|
254684
254704
|
description: "Integration backend for downstream workspace connectivity.",
|
|
254685
254705
|
required: false,
|
|
@@ -254749,6 +254769,21 @@ var bootstrapActionContract = {
|
|
|
254749
254769
|
},
|
|
254750
254770
|
"breaking-change-summary-json": {
|
|
254751
254771
|
description: "JSON summary of the OpenAPI breaking-change check."
|
|
254772
|
+
},
|
|
254773
|
+
"sync-status": {
|
|
254774
|
+
description: "Branch-aware sync status: synced (canonical/channel/preview write ran), skipped-branch-gate (gated run, credential-free validation only), or empty under branch-strategy legacy."
|
|
254775
|
+
},
|
|
254776
|
+
"branch-decision": {
|
|
254777
|
+
description: "Serialized BranchDecision JSON for downstream actions (also exported as POSTMAN_BRANCH_DECISION)."
|
|
254778
|
+
},
|
|
254779
|
+
"spec-version-tag": {
|
|
254780
|
+
description: "Native Spec Hub version tag applied on this canonical publish (tag-per-publish), empty when tagging was skipped (no-op sync, non-canonical run, or legacy client)."
|
|
254781
|
+
},
|
|
254782
|
+
"spec-version-url": {
|
|
254783
|
+
description: "Reserved for the repo-sync finalizer; bootstrap does not tag before complete onboarding."
|
|
254784
|
+
},
|
|
254785
|
+
"spec-content-changed": {
|
|
254786
|
+
description: "Whether bootstrap changed canonical spec content; repo-sync uses this to skip native version tags on no-op syncs."
|
|
254752
254787
|
}
|
|
254753
254788
|
},
|
|
254754
254789
|
retainedBehavior: [
|
|
@@ -255875,6 +255910,15 @@ function assertSupportedLocalViewContract(node, options) {
|
|
|
255875
255910
|
}
|
|
255876
255911
|
|
|
255877
255912
|
// src/lib/postman/additional-collections.ts
|
|
255913
|
+
var RESOURCES_STATE_VERSION = 2;
|
|
255914
|
+
var SUPPORTED_STATE_VERSIONS = /* @__PURE__ */ new Set([1, RESOURCES_STATE_VERSION]);
|
|
255915
|
+
var StateUnreadableError = class extends Error {
|
|
255916
|
+
code = "CONTRACT_STATE_UNREADABLE";
|
|
255917
|
+
constructor(message) {
|
|
255918
|
+
super(`CONTRACT_STATE_UNREADABLE: ${message}`);
|
|
255919
|
+
this.name = "StateUnreadableError";
|
|
255920
|
+
}
|
|
255921
|
+
};
|
|
255878
255922
|
var ADDITIONAL_COLLECTION_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".yaml", ".yml"]);
|
|
255879
255923
|
var POSTMAN_COLLECTION_V21_SCHEMA_FRAGMENT = "/collection/v2.1.0/collection.json";
|
|
255880
255924
|
var V3_DEFINITION_PATH = import_node_path2.default.join(".resources", "definition.yaml");
|
|
@@ -255930,16 +255974,46 @@ function resourcesStatePath() {
|
|
|
255930
255974
|
return import_node_path2.default.join(workspaceRootForLocalInputs(), RESOURCES_PATH);
|
|
255931
255975
|
}
|
|
255932
255976
|
function readResourcesState() {
|
|
255977
|
+
let raw;
|
|
255933
255978
|
try {
|
|
255934
|
-
|
|
255979
|
+
raw = (0, import_node_fs2.readFileSync)(resourcesStatePath(), "utf8");
|
|
255935
255980
|
} catch {
|
|
255936
255981
|
return null;
|
|
255937
255982
|
}
|
|
255983
|
+
let parsed;
|
|
255984
|
+
try {
|
|
255985
|
+
parsed = (0, import_yaml.parse)(raw);
|
|
255986
|
+
} catch (error) {
|
|
255987
|
+
throw new StateUnreadableError(
|
|
255988
|
+
`.postman/resources.yaml exists but is not parseable YAML (${error instanceof Error ? error.message : String(error)}). Fix or delete the file; refusing to treat tracked state as absent.`
|
|
255989
|
+
);
|
|
255990
|
+
}
|
|
255991
|
+
if (parsed === null || parsed === void 0) {
|
|
255992
|
+
return null;
|
|
255993
|
+
}
|
|
255994
|
+
if (typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
255995
|
+
throw new StateUnreadableError(
|
|
255996
|
+
".postman/resources.yaml exists but does not contain a YAML mapping. Fix or delete the file; refusing to treat tracked state as absent."
|
|
255997
|
+
);
|
|
255998
|
+
}
|
|
255999
|
+
const state = parsed;
|
|
256000
|
+
if (state.version !== void 0 && !SUPPORTED_STATE_VERSIONS.has(Number(state.version))) {
|
|
256001
|
+
throw new StateUnreadableError(
|
|
256002
|
+
`.postman/resources.yaml declares unsupported state version ${String(state.version)} (supported: 1, ${RESOURCES_STATE_VERSION}). Upgrade the action or fix the file.`
|
|
256003
|
+
);
|
|
256004
|
+
}
|
|
256005
|
+
if (state.canonical && !state.cloudResources) {
|
|
256006
|
+
state.cloudResources = { ...state.canonical };
|
|
256007
|
+
}
|
|
256008
|
+
return state;
|
|
255938
256009
|
}
|
|
255939
256010
|
function writeResourcesState(state) {
|
|
255940
256011
|
const target = resourcesStatePath();
|
|
255941
256012
|
(0, import_node_fs2.mkdirSync)(import_node_path2.default.dirname(target), { recursive: true });
|
|
255942
|
-
|
|
256013
|
+
const canonical = state.cloudResources ?? state.canonical ?? {};
|
|
256014
|
+
const persisted = { ...state, version: RESOURCES_STATE_VERSION, canonical };
|
|
256015
|
+
delete persisted.cloudResources;
|
|
256016
|
+
(0, import_node_fs2.writeFileSync)(target, (0, import_yaml.stringify)(persisted), "utf8");
|
|
255943
256017
|
}
|
|
255944
256018
|
function findCloudResourceId(map, matcher) {
|
|
255945
256019
|
if (!map) {
|
|
@@ -255949,7 +256023,7 @@ function findCloudResourceId(map, matcher) {
|
|
|
255949
256023
|
return match?.[1];
|
|
255950
256024
|
}
|
|
255951
256025
|
function findExistingAdditionalCollectionId(resourcesState, resourcePath) {
|
|
255952
|
-
return resourcesState?.cloudResources?.additionalCollections?.[resourcePath] ?? resourcesState?.cloudResources?.collections?.[resourcePath];
|
|
256026
|
+
return resourcesState?.canonical?.additionalCollections?.[resourcePath] ?? resourcesState?.canonical?.collections?.[resourcePath] ?? resourcesState?.cloudResources?.additionalCollections?.[resourcePath] ?? resourcesState?.cloudResources?.collections?.[resourcePath];
|
|
255953
256027
|
}
|
|
255954
256028
|
function resolveAdditionalCollectionsDir(directoryInput) {
|
|
255955
256029
|
const workspaceRoot = workspaceRootForLocalInputs();
|
|
@@ -256951,6 +257025,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
256951
257025
|
* endpoint aborts rather than blocking the run forever. */
|
|
256952
257026
|
static REQUEST_TIMEOUT_MS = 3e4;
|
|
256953
257027
|
static POSTMAN_APP_VERSION_URL = `https://dl.pstmn.io/update/status?currentVersion=${_BifrostInternalIntegrationAdapter.MINIMUM_POSTMAN_APP_VERSION}&platform=osx_arm64`;
|
|
257028
|
+
/** Concurrent dual-trigger previews share one spec; peer sync holds a 423 lock. */
|
|
257029
|
+
static SYNC_LOCKED_MAX_RETRIES = 6;
|
|
256954
257030
|
accessToken;
|
|
256955
257031
|
tokenProvider;
|
|
256956
257032
|
appVersionPromise;
|
|
@@ -256959,6 +257035,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
256959
257035
|
gatewayBaseUrl;
|
|
256960
257036
|
orgMode;
|
|
256961
257037
|
secretMasker;
|
|
257038
|
+
sleep;
|
|
256962
257039
|
teamId;
|
|
256963
257040
|
constructor(options) {
|
|
256964
257041
|
this.accessToken = String(options.accessToken || "").trim();
|
|
@@ -256972,6 +257049,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
256972
257049
|
).replace(/\/+$/, "");
|
|
256973
257050
|
this.orgMode = options.orgMode ?? false;
|
|
256974
257051
|
this.secretMasker = options.secretMasker ?? createSecretMasker([this.accessToken]);
|
|
257052
|
+
this.sleep = options.sleep ?? ((delayMs) => new Promise((resolve4) => setTimeout(resolve4, delayMs)));
|
|
256975
257053
|
this.teamId = String(options.teamId || "").trim();
|
|
256976
257054
|
}
|
|
256977
257055
|
configureTeamContext(teamId, orgMode) {
|
|
@@ -257178,55 +257256,72 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
257178
257256
|
if (collections.length === 0) {
|
|
257179
257257
|
return;
|
|
257180
257258
|
}
|
|
257181
|
-
const
|
|
257182
|
-
|
|
257183
|
-
|
|
257184
|
-
|
|
257185
|
-
|
|
257186
|
-
|
|
257187
|
-
|
|
257188
|
-
|
|
257189
|
-
|
|
257190
|
-
|
|
257191
|
-
|
|
257259
|
+
const body2 = collections.map((collection) => ({
|
|
257260
|
+
collectionId: collection.collectionId,
|
|
257261
|
+
...collection.syncOptions ? { syncOptions: collection.syncOptions } : {}
|
|
257262
|
+
}));
|
|
257263
|
+
for (let lockedAttempt = 0; ; lockedAttempt += 1) {
|
|
257264
|
+
const response = await this.proxyRequest(
|
|
257265
|
+
"specification",
|
|
257266
|
+
"put",
|
|
257267
|
+
`/specifications/${specificationId}/collections`,
|
|
257268
|
+
body2
|
|
257269
|
+
);
|
|
257270
|
+
if (response.ok) {
|
|
257271
|
+
return;
|
|
257272
|
+
}
|
|
257273
|
+
const httpErr = await HttpError.fromResponse(response, {
|
|
257274
|
+
method: "POST",
|
|
257275
|
+
requestHeaders: {
|
|
257276
|
+
"Content-Type": "application/json",
|
|
257277
|
+
"x-access-token": this.currentToken(),
|
|
257278
|
+
...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
|
|
257279
|
+
},
|
|
257280
|
+
secretValues: [this.currentToken()],
|
|
257281
|
+
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
257282
|
+
});
|
|
257283
|
+
if (httpErr.status === 423 && lockedAttempt < _BifrostInternalIntegrationAdapter.SYNC_LOCKED_MAX_RETRIES) {
|
|
257284
|
+
await this.sleep(2e3 * Math.pow(2, lockedAttempt));
|
|
257285
|
+
continue;
|
|
257286
|
+
}
|
|
257287
|
+
const advised = adviseFromHttpError(
|
|
257288
|
+
httpErr,
|
|
257289
|
+
this.adviceContext("collection-to-specification linking")
|
|
257290
|
+
);
|
|
257291
|
+
throw advised ?? httpErr;
|
|
257192
257292
|
}
|
|
257193
|
-
const httpErr = await HttpError.fromResponse(response, {
|
|
257194
|
-
method: "POST",
|
|
257195
|
-
requestHeaders: {
|
|
257196
|
-
"Content-Type": "application/json",
|
|
257197
|
-
"x-access-token": this.currentToken(),
|
|
257198
|
-
...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
|
|
257199
|
-
},
|
|
257200
|
-
secretValues: [this.currentToken()],
|
|
257201
|
-
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
257202
|
-
});
|
|
257203
|
-
const advised = adviseFromHttpError(
|
|
257204
|
-
httpErr,
|
|
257205
|
-
this.adviceContext("collection-to-specification linking")
|
|
257206
|
-
);
|
|
257207
|
-
throw advised ?? httpErr;
|
|
257208
257293
|
}
|
|
257209
257294
|
async syncCollection(specificationId, collectionId) {
|
|
257210
|
-
|
|
257211
|
-
|
|
257212
|
-
|
|
257213
|
-
|
|
257214
|
-
|
|
257215
|
-
|
|
257216
|
-
|
|
257295
|
+
for (let lockedAttempt = 0; ; lockedAttempt += 1) {
|
|
257296
|
+
const response = await this.proxyRequest(
|
|
257297
|
+
"specification",
|
|
257298
|
+
"post",
|
|
257299
|
+
`/specifications/${specificationId}/collections/${collectionId}/sync`
|
|
257300
|
+
);
|
|
257301
|
+
if (response.ok) {
|
|
257302
|
+
return;
|
|
257303
|
+
}
|
|
257304
|
+
const bodyText = await response.clone().text().catch(() => "");
|
|
257305
|
+
if (response.status === 400 && /already in sync/i.test(bodyText)) {
|
|
257306
|
+
return;
|
|
257307
|
+
}
|
|
257308
|
+
const httpErr = await HttpError.fromResponse(response, {
|
|
257309
|
+
method: "POST",
|
|
257310
|
+
requestHeaders: {
|
|
257311
|
+
"Content-Type": "application/json",
|
|
257312
|
+
"x-access-token": this.currentToken(),
|
|
257313
|
+
...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
|
|
257314
|
+
},
|
|
257315
|
+
secretValues: [this.currentToken()],
|
|
257316
|
+
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
257317
|
+
});
|
|
257318
|
+
if (httpErr.status === 423 && lockedAttempt < _BifrostInternalIntegrationAdapter.SYNC_LOCKED_MAX_RETRIES) {
|
|
257319
|
+
await this.sleep(2e3 * Math.pow(2, lockedAttempt));
|
|
257320
|
+
continue;
|
|
257321
|
+
}
|
|
257322
|
+
const advised = adviseFromHttpError(httpErr, this.adviceContext("collection sync"));
|
|
257323
|
+
throw advised ?? httpErr;
|
|
257217
257324
|
}
|
|
257218
|
-
const httpErr = await HttpError.fromResponse(response, {
|
|
257219
|
-
method: "POST",
|
|
257220
|
-
requestHeaders: {
|
|
257221
|
-
"Content-Type": "application/json",
|
|
257222
|
-
"x-access-token": this.currentToken(),
|
|
257223
|
-
...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
|
|
257224
|
-
},
|
|
257225
|
-
secretValues: [this.currentToken()],
|
|
257226
|
-
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
257227
|
-
});
|
|
257228
|
-
const advised = adviseFromHttpError(httpErr, this.adviceContext("collection sync"));
|
|
257229
|
-
throw advised ?? httpErr;
|
|
257230
257325
|
}
|
|
257231
257326
|
async getWorkspaceGitRepoUrl(workspaceId) {
|
|
257232
257327
|
const response = await this.proxyRequest(
|
|
@@ -262371,6 +262466,16 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
|
|
|
262371
262466
|
if (openapiVersion !== "3.0" && openapiVersion !== "3.1") {
|
|
262372
262467
|
throw new Error(`uploadSpec: unsupported openapiVersion "${openapiVersion}". Expected '3.0' or '3.1'.`);
|
|
262373
262468
|
}
|
|
262469
|
+
const before = await this.findSpecificationsByExactName(workspaceId, projectName);
|
|
262470
|
+
const existing = adoptExactMatch(
|
|
262471
|
+
`specification:${workspaceId}:${projectName}`,
|
|
262472
|
+
before,
|
|
262473
|
+
(entry) => entry.id
|
|
262474
|
+
);
|
|
262475
|
+
if (existing) {
|
|
262476
|
+
await this.updateSpec(existing.id, specContent, workspaceId);
|
|
262477
|
+
return existing.id;
|
|
262478
|
+
}
|
|
262374
262479
|
const specType = openapiVersion === "3.1" ? "OPENAPI:3.1" : "OPENAPI:3.0";
|
|
262375
262480
|
let created;
|
|
262376
262481
|
try {
|
|
@@ -262395,10 +262500,49 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
|
|
|
262395
262500
|
if (!match) throw error;
|
|
262396
262501
|
created = { data: { id: match.id } };
|
|
262397
262502
|
}
|
|
262398
|
-
|
|
262503
|
+
let specId = String(asRecord8(created?.data)?.id ?? created?.id ?? "").trim();
|
|
262399
262504
|
if (!specId) {
|
|
262400
262505
|
throw new Error("Spec upload did not return an ID");
|
|
262401
262506
|
}
|
|
262507
|
+
let matches = await this.findSpecificationsByExactName(workspaceId, projectName);
|
|
262508
|
+
if (before.length === 0 && matches.length <= 1) {
|
|
262509
|
+
await this.sleep(1e3);
|
|
262510
|
+
const settled = await this.findSpecificationsByExactName(workspaceId, projectName);
|
|
262511
|
+
if (settled.length > 0) matches = settled;
|
|
262512
|
+
}
|
|
262513
|
+
if (matches.length > 1 && before.length === 0) {
|
|
262514
|
+
for (const duplicate of matches.slice(1)) {
|
|
262515
|
+
try {
|
|
262516
|
+
await this.deleteSpecification(duplicate.id);
|
|
262517
|
+
} catch (error) {
|
|
262518
|
+
if (!(error instanceof HttpError && error.status === 404)) throw error;
|
|
262519
|
+
}
|
|
262520
|
+
}
|
|
262521
|
+
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
262522
|
+
matches = await this.findSpecificationsByExactName(workspaceId, projectName);
|
|
262523
|
+
if (matches.length <= 1) break;
|
|
262524
|
+
await this.sleep(250 * (attempt + 1));
|
|
262525
|
+
}
|
|
262526
|
+
const converged = adoptExactMatch(
|
|
262527
|
+
`specification:${workspaceId}:${projectName}`,
|
|
262528
|
+
matches,
|
|
262529
|
+
(entry) => entry.id
|
|
262530
|
+
);
|
|
262531
|
+
if (!converged) {
|
|
262532
|
+
throw new Error(`Concurrent specification create for ${projectName} did not converge`);
|
|
262533
|
+
}
|
|
262534
|
+
specId = converged.id;
|
|
262535
|
+
if (specId !== String(asRecord8(created?.data)?.id ?? created?.id ?? "").trim()) {
|
|
262536
|
+
await this.updateSpec(specId, specContent, workspaceId);
|
|
262537
|
+
}
|
|
262538
|
+
} else {
|
|
262539
|
+
const verified = adoptExactMatch(
|
|
262540
|
+
`specification:${workspaceId}:${projectName}`,
|
|
262541
|
+
matches,
|
|
262542
|
+
(entry) => entry.id
|
|
262543
|
+
);
|
|
262544
|
+
if (verified) specId = verified.id;
|
|
262545
|
+
}
|
|
262402
262546
|
await this.gateway.requestJson({
|
|
262403
262547
|
service: "specification",
|
|
262404
262548
|
method: "get",
|
|
@@ -262406,6 +262550,14 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
|
|
|
262406
262550
|
});
|
|
262407
262551
|
return specId;
|
|
262408
262552
|
}
|
|
262553
|
+
async deleteSpecification(specId) {
|
|
262554
|
+
await this.gateway.requestJson({
|
|
262555
|
+
service: "specification",
|
|
262556
|
+
method: "delete",
|
|
262557
|
+
path: `/specifications/${specId}`,
|
|
262558
|
+
retry: "none"
|
|
262559
|
+
});
|
|
262560
|
+
}
|
|
262409
262561
|
async findSpecificationsByExactName(workspaceId, name) {
|
|
262410
262562
|
const response = await this.gateway.requestJson({
|
|
262411
262563
|
service: "specification",
|
|
@@ -262469,6 +262621,41 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
|
|
|
262469
262621
|
return void 0;
|
|
262470
262622
|
}
|
|
262471
262623
|
}
|
|
262624
|
+
/**
|
|
262625
|
+
* Native Spec Hub version tags (branch-aware sync P3.5). Tags attach to the
|
|
262626
|
+
* LATEST changelog group; the backend 409s when that group is already tagged
|
|
262627
|
+
* (VersionControlService). Callers handle 409 as idempotent-by-group.
|
|
262628
|
+
*/
|
|
262629
|
+
async tagSpecVersion(specId, name) {
|
|
262630
|
+
const trimmed = name.trim().slice(0, 255);
|
|
262631
|
+
const created = await this.gateway.requestJson({
|
|
262632
|
+
service: "specification",
|
|
262633
|
+
method: "post",
|
|
262634
|
+
path: `/specifications/${specId}/tags`,
|
|
262635
|
+
retry: "none",
|
|
262636
|
+
body: { name: trimmed }
|
|
262637
|
+
});
|
|
262638
|
+
const record = asRecord8(created?.data) ?? created ?? {};
|
|
262639
|
+
return {
|
|
262640
|
+
id: String(record.id ?? "").trim(),
|
|
262641
|
+
name: String(record.name ?? trimmed).trim()
|
|
262642
|
+
};
|
|
262643
|
+
}
|
|
262644
|
+
/** List a spec's native version tags (newest first per backend ordering). */
|
|
262645
|
+
async listSpecVersionTags(specId) {
|
|
262646
|
+
const response = await this.gateway.requestJson({
|
|
262647
|
+
service: "specification",
|
|
262648
|
+
method: "get",
|
|
262649
|
+
path: `/specifications/${specId}/tags`,
|
|
262650
|
+
query: { limit: "50" }
|
|
262651
|
+
});
|
|
262652
|
+
const entries = Array.isArray(response?.data) ? response.data : [];
|
|
262653
|
+
return entries.map((value) => asRecord8(value)).filter((value) => value !== null).map((value) => ({
|
|
262654
|
+
id: String(value.id ?? "").trim(),
|
|
262655
|
+
// listTags returns `message`; createTag returns `name`. Accept both.
|
|
262656
|
+
name: String(value.name ?? value.message ?? "").trim()
|
|
262657
|
+
})).filter((value) => value.id || value.name);
|
|
262658
|
+
}
|
|
262472
262659
|
/** Resolve a specification's ROOT file uuid via the files list. */
|
|
262473
262660
|
async resolveRootFileId(specId) {
|
|
262474
262661
|
const files = await this.gateway.requestJson({
|
|
@@ -262488,79 +262675,182 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
|
|
|
262488
262675
|
*/
|
|
262489
262676
|
async generateCollection(specId, projectName, prefix, folderStrategy, nestedFolderHierarchy, requestNameSource) {
|
|
262490
262677
|
const name = [prefix.trim(), projectName.trim()].filter(Boolean).join(" ");
|
|
262491
|
-
const submittedName = `${name} [bootstrap:${this.createIdentity()}]`;
|
|
262492
|
-
const body2 = {
|
|
262493
|
-
name: submittedName,
|
|
262494
|
-
options: {
|
|
262495
|
-
requestNameSource,
|
|
262496
|
-
folderStrategy,
|
|
262497
|
-
...folderStrategy === "Tags" ? { nestedFolderHierarchy } : {}
|
|
262498
|
-
}
|
|
262499
|
-
};
|
|
262500
262678
|
const before = await this.listGeneratedCollectionRefs(specId);
|
|
262501
|
-
|
|
262502
|
-
|
|
262503
|
-
|
|
262504
|
-
|
|
262505
|
-
|
|
262506
|
-
|
|
262507
|
-
|
|
262508
|
-
|
|
262509
|
-
)
|
|
262510
|
-
const
|
|
262511
|
-
|
|
262679
|
+
const existing = adoptExactMatch(
|
|
262680
|
+
`generated-collection:${specId}:${name}`,
|
|
262681
|
+
await this.filterGeneratedCollectionsByExactName(before, name),
|
|
262682
|
+
(entry) => entry.id
|
|
262683
|
+
);
|
|
262684
|
+
if (existing) return this.convergeGeneratedCollections(specId, name, existing.id);
|
|
262685
|
+
let lastError;
|
|
262686
|
+
for (let taskAttempt = 0; taskAttempt < 2; taskAttempt += 1) {
|
|
262687
|
+
const submittedName = `${name} [bootstrap:${this.createIdentity()}]`;
|
|
262688
|
+
const body2 = {
|
|
262689
|
+
name: submittedName,
|
|
262690
|
+
options: {
|
|
262691
|
+
requestNameSource,
|
|
262692
|
+
folderStrategy,
|
|
262693
|
+
...folderStrategy === "Tags" ? { nestedFolderHierarchy } : {}
|
|
262694
|
+
}
|
|
262695
|
+
};
|
|
262696
|
+
let taskId;
|
|
262697
|
+
try {
|
|
262698
|
+
const generation = await this.postGenerationWithLockRetry(specId, body2, name);
|
|
262699
|
+
if (generation.adoptedId) {
|
|
262700
|
+
return this.convergeGeneratedCollections(specId, name, generation.adoptedId);
|
|
262701
|
+
}
|
|
262702
|
+
taskId = generation.taskId ?? "";
|
|
262703
|
+
} catch (error) {
|
|
262704
|
+
if (!isAmbiguousTransportError(error)) throw error;
|
|
262705
|
+
const beforeIds2 = new Set(before.map((entry) => entry.id));
|
|
262706
|
+
const appeared2 = (await this.listGeneratedCollectionRefs(specId)).filter(
|
|
262707
|
+
(entry) => !beforeIds2.has(entry.id)
|
|
262708
|
+
);
|
|
262709
|
+
const exactAppeared = await this.filterGeneratedCollectionsByExactName(
|
|
262710
|
+
appeared2,
|
|
262711
|
+
submittedName
|
|
262712
|
+
);
|
|
262713
|
+
const match = adoptExactMatch(
|
|
262714
|
+
`generated-collection:${specId}:${submittedName}`,
|
|
262715
|
+
exactAppeared,
|
|
262716
|
+
(entry) => entry.id
|
|
262717
|
+
);
|
|
262718
|
+
if (!match) throw error;
|
|
262719
|
+
await this.renameGeneratedCollection(match.id, name);
|
|
262720
|
+
return this.convergeGeneratedCollections(specId, name, match.id);
|
|
262721
|
+
}
|
|
262722
|
+
let taskFailed = false;
|
|
262723
|
+
if (taskId) {
|
|
262724
|
+
for (let attempt = 0; attempt < this.generationPollAttempts; attempt += 1) {
|
|
262725
|
+
await this.sleep(this.generationPollDelayMs);
|
|
262726
|
+
const task = await this.gateway.requestJson({
|
|
262727
|
+
service: "specification",
|
|
262728
|
+
method: "get",
|
|
262729
|
+
path: "/tasks",
|
|
262730
|
+
query: { entityId: specId, entityType: "specification", type: "collection-generation" }
|
|
262731
|
+
});
|
|
262732
|
+
const status = String(asRecord8(task?.data)?.[taskId] ?? "").toLowerCase();
|
|
262733
|
+
if (status === "failed" || status === "error") {
|
|
262734
|
+
taskFailed = true;
|
|
262735
|
+
lastError = new Error(`Collection generation task failed for ${prefix}`);
|
|
262736
|
+
break;
|
|
262737
|
+
}
|
|
262738
|
+
if (status && status !== "in-progress" && status !== "pending" && status !== "queued") {
|
|
262739
|
+
break;
|
|
262740
|
+
}
|
|
262741
|
+
if (attempt === this.generationPollAttempts - 1) {
|
|
262742
|
+
throw new Error(`Collection generation timed out for ${prefix}`);
|
|
262743
|
+
}
|
|
262744
|
+
}
|
|
262745
|
+
}
|
|
262746
|
+
if (taskFailed) {
|
|
262747
|
+
await this.sleep(1e3 * (taskAttempt + 1));
|
|
262748
|
+
continue;
|
|
262749
|
+
}
|
|
262750
|
+
const beforeIds = new Set(before.map((entry) => entry.id));
|
|
262751
|
+
const after = await this.listGeneratedCollectionRefs(specId);
|
|
262752
|
+
const appeared = after.filter((entry) => !beforeIds.has(entry.id));
|
|
262753
|
+
const candidates = await this.filterGeneratedCollectionsByExactName(
|
|
262754
|
+
appeared,
|
|
262512
262755
|
submittedName
|
|
262513
262756
|
);
|
|
262514
|
-
const
|
|
262757
|
+
const uid = adoptExactMatch(
|
|
262515
262758
|
`generated-collection:${specId}:${submittedName}`,
|
|
262516
|
-
|
|
262759
|
+
candidates,
|
|
262517
262760
|
(entry) => entry.id
|
|
262518
|
-
);
|
|
262519
|
-
if (!
|
|
262520
|
-
|
|
262521
|
-
|
|
262761
|
+
)?.id;
|
|
262762
|
+
if (!uid) {
|
|
262763
|
+
throw new Error(`Collection generation did not yield a collection uid for ${prefix}`);
|
|
262764
|
+
}
|
|
262765
|
+
await this.renameGeneratedCollection(uid, name);
|
|
262766
|
+
return this.convergeGeneratedCollections(specId, name, uid);
|
|
262522
262767
|
}
|
|
262523
|
-
|
|
262524
|
-
|
|
262525
|
-
|
|
262526
|
-
|
|
262527
|
-
|
|
262528
|
-
|
|
262529
|
-
|
|
262530
|
-
|
|
262531
|
-
|
|
262532
|
-
|
|
262533
|
-
|
|
262534
|
-
|
|
262535
|
-
|
|
262536
|
-
|
|
262537
|
-
|
|
262538
|
-
|
|
262539
|
-
|
|
262540
|
-
|
|
262768
|
+
throw lastError ?? new Error(`Collection generation task failed for ${prefix}`);
|
|
262769
|
+
}
|
|
262770
|
+
/**
|
|
262771
|
+
* Re-elect the durable generated collection for a final name. Call after
|
|
262772
|
+
* concurrent dual-trigger generates and before description/inject/tag so a
|
|
262773
|
+
* peer orphan-sweep cannot leave this runner holding a deleted id.
|
|
262774
|
+
*/
|
|
262775
|
+
async adoptGeneratedCollection(specId, projectName, prefix, preferredId = "") {
|
|
262776
|
+
const name = [prefix.trim(), projectName.trim()].filter(Boolean).join(" ");
|
|
262777
|
+
return this.convergeGeneratedCollections(specId, name, preferredId);
|
|
262778
|
+
}
|
|
262779
|
+
/**
|
|
262780
|
+
* Concurrent dual-trigger previews can each generate+rename the same final
|
|
262781
|
+
* collection identity. Elect the stable lowest-id winner.
|
|
262782
|
+
*
|
|
262783
|
+
* Losers only delete *their own* preferred collection (never a peer's still-
|
|
262784
|
+
* in-use id). Winners wait briefly for peers to self-delete, then clean any
|
|
262785
|
+
* leftover same-identity orphans (temps + extra finals).
|
|
262786
|
+
*/
|
|
262787
|
+
async convergeGeneratedCollections(specId, finalName, preferredId) {
|
|
262788
|
+
const tempPrefix = `${finalName} [bootstrap:`;
|
|
262789
|
+
const hydrate = async () => {
|
|
262790
|
+
const linked = await this.listGeneratedCollectionRefs(specId);
|
|
262791
|
+
return Promise.all(
|
|
262792
|
+
linked.map(async (entry) => {
|
|
262793
|
+
if (entry.name) return { id: entry.id, name: entry.name };
|
|
262794
|
+
try {
|
|
262795
|
+
const collection = await this.gateway.requestJson({
|
|
262796
|
+
service: "collection",
|
|
262797
|
+
method: "get",
|
|
262798
|
+
path: `/v3/collections/${this.bareModelId(entry.id)}`
|
|
262799
|
+
});
|
|
262800
|
+
return {
|
|
262801
|
+
id: entry.id,
|
|
262802
|
+
name: String(asRecord8(collection?.data)?.name ?? "").trim()
|
|
262803
|
+
};
|
|
262804
|
+
} catch (error) {
|
|
262805
|
+
if (error instanceof HttpError && error.status === 404) {
|
|
262806
|
+
return { id: entry.id, name: "" };
|
|
262807
|
+
}
|
|
262808
|
+
throw error;
|
|
262809
|
+
}
|
|
262810
|
+
})
|
|
262811
|
+
);
|
|
262812
|
+
};
|
|
262813
|
+
const selectSameIdentity = (entries) => entries.filter(
|
|
262814
|
+
(entry) => entry.name === finalName || entry.name.startsWith(tempPrefix)
|
|
262815
|
+
).sort((a, b) => a.id.localeCompare(b.id));
|
|
262816
|
+
let sameIdentity = selectSameIdentity(await hydrate());
|
|
262817
|
+
if (sameIdentity.length === 0) return preferredId;
|
|
262818
|
+
if (sameIdentity.length === 1) {
|
|
262819
|
+
await this.sleep(1e3);
|
|
262820
|
+
sameIdentity = selectSameIdentity(await hydrate());
|
|
262821
|
+
if (sameIdentity.length === 0) return preferredId;
|
|
262822
|
+
}
|
|
262823
|
+
const winner = sameIdentity[0];
|
|
262824
|
+
if (winner.name !== finalName) {
|
|
262825
|
+
await this.renameGeneratedCollection(winner.id, finalName);
|
|
262826
|
+
}
|
|
262827
|
+
if (preferredId && preferredId !== winner.id) {
|
|
262828
|
+
const own = sameIdentity.find((entry) => entry.id === preferredId);
|
|
262829
|
+
if (own) {
|
|
262830
|
+
try {
|
|
262831
|
+
await this.deleteCollection(preferredId);
|
|
262832
|
+
} catch (error) {
|
|
262833
|
+
if (!(error instanceof HttpError && error.status === 404)) throw error;
|
|
262541
262834
|
}
|
|
262542
262835
|
}
|
|
262836
|
+
return winner.id;
|
|
262543
262837
|
}
|
|
262544
|
-
|
|
262545
|
-
|
|
262546
|
-
|
|
262547
|
-
|
|
262548
|
-
|
|
262549
|
-
|
|
262550
|
-
|
|
262551
|
-
|
|
262552
|
-
|
|
262553
|
-
|
|
262554
|
-
|
|
262555
|
-
)?.id;
|
|
262556
|
-
if (!uid) {
|
|
262557
|
-
throw new Error(`Collection generation did not yield a collection uid for ${prefix}`);
|
|
262838
|
+
if (sameIdentity.length > 1) {
|
|
262839
|
+
await this.sleep(1500);
|
|
262840
|
+
sameIdentity = selectSameIdentity(await hydrate());
|
|
262841
|
+
for (const duplicate of sameIdentity) {
|
|
262842
|
+
if (duplicate.id === winner.id) continue;
|
|
262843
|
+
try {
|
|
262844
|
+
await this.deleteCollection(duplicate.id);
|
|
262845
|
+
} catch (error) {
|
|
262846
|
+
if (!(error instanceof HttpError && error.status === 404)) throw error;
|
|
262847
|
+
}
|
|
262848
|
+
}
|
|
262558
262849
|
}
|
|
262559
|
-
|
|
262560
|
-
return uid;
|
|
262850
|
+
return winner.id;
|
|
262561
262851
|
}
|
|
262562
262852
|
/** POST the generation request, retrying a 423-locked spec; returns the task id. */
|
|
262563
|
-
async postGenerationWithLockRetry(specId, body2) {
|
|
262853
|
+
async postGenerationWithLockRetry(specId, body2, finalName) {
|
|
262564
262854
|
for (let lockedAttempt = 0; ; lockedAttempt += 1) {
|
|
262565
262855
|
try {
|
|
262566
262856
|
const created = await this.gateway.requestJson({
|
|
@@ -262570,13 +262860,22 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
|
|
|
262570
262860
|
retry: "none",
|
|
262571
262861
|
body: body2
|
|
262572
262862
|
});
|
|
262573
|
-
return String(asRecord8(created?.data)?.taskId ?? "").trim();
|
|
262863
|
+
return { taskId: String(asRecord8(created?.data)?.taskId ?? "").trim() };
|
|
262574
262864
|
} catch (error) {
|
|
262575
262865
|
const locked = error instanceof HttpError && error.status === 423;
|
|
262576
262866
|
if (!locked || lockedAttempt >= _PostmanGatewayAssetsClient.GENERATION_LOCKED_MAX_RETRIES) {
|
|
262577
262867
|
throw error;
|
|
262578
262868
|
}
|
|
262579
262869
|
await this.sleep(5e3 * Math.pow(2, lockedAttempt));
|
|
262870
|
+
const adopted = adoptExactMatch(
|
|
262871
|
+
`generated-collection:${specId}:${finalName}`,
|
|
262872
|
+
await this.filterGeneratedCollectionsByExactName(
|
|
262873
|
+
await this.listGeneratedCollectionRefs(specId),
|
|
262874
|
+
finalName
|
|
262875
|
+
),
|
|
262876
|
+
(entry) => entry.id
|
|
262877
|
+
);
|
|
262878
|
+
if (adopted) return { adoptedId: adopted.id };
|
|
262580
262879
|
}
|
|
262581
262880
|
}
|
|
262582
262881
|
}
|
|
@@ -262613,14 +262912,24 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
|
|
|
262613
262912
|
return hydrated.filter((entry) => entry.name === expectedName);
|
|
262614
262913
|
}
|
|
262615
262914
|
async renameGeneratedCollection(collectionId, name) {
|
|
262616
|
-
|
|
262617
|
-
|
|
262618
|
-
|
|
262619
|
-
|
|
262620
|
-
|
|
262621
|
-
|
|
262622
|
-
|
|
262623
|
-
|
|
262915
|
+
try {
|
|
262916
|
+
await this.gateway.requestJson({
|
|
262917
|
+
service: "collection",
|
|
262918
|
+
method: "patch",
|
|
262919
|
+
path: `/v3/collections/${this.bareModelId(collectionId)}`,
|
|
262920
|
+
// Replacing a generated collection's name with the same value is idempotent.
|
|
262921
|
+
retry: "safe",
|
|
262922
|
+
body: [{ op: "replace", path: "/name", value: name }]
|
|
262923
|
+
});
|
|
262924
|
+
} catch (error) {
|
|
262925
|
+
if (error instanceof HttpError && error.status === 400 && /must update at least one|REJECTED_PATCH/i.test(
|
|
262926
|
+
`${error.message}
|
|
262927
|
+
${error.responseBody ?? ""}`
|
|
262928
|
+
)) {
|
|
262929
|
+
return;
|
|
262930
|
+
}
|
|
262931
|
+
throw error;
|
|
262932
|
+
}
|
|
262624
262933
|
}
|
|
262625
262934
|
/**
|
|
262626
262935
|
* Create a team-visible workspace through the gateway workspaces service.
|
|
@@ -262895,6 +263204,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
|
|
|
262895
263204
|
service: "tagging",
|
|
262896
263205
|
method: "put",
|
|
262897
263206
|
path: `/v1/tags/collections/${collectionUid}`,
|
|
263207
|
+
retry: "safe",
|
|
262898
263208
|
body: { tags: normalized.map((slug) => ({ slug })) }
|
|
262899
263209
|
});
|
|
262900
263210
|
}
|
|
@@ -263521,6 +263831,15 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
|
|
|
263521
263831
|
async createCollection(workspaceId, collection, options = {}) {
|
|
263522
263832
|
const v3 = this.normalizeCollectionForWrite(collection);
|
|
263523
263833
|
const desiredName = String(v3.name ?? "Untitled Collection");
|
|
263834
|
+
const existing = adoptExactMatch(
|
|
263835
|
+
`collection:${workspaceId}:${desiredName}`,
|
|
263836
|
+
await this.findCollectionsByExactName(workspaceId, desiredName),
|
|
263837
|
+
(entry) => entry.id
|
|
263838
|
+
);
|
|
263839
|
+
if (existing) {
|
|
263840
|
+
await this.updateCollection(existing.id, collection);
|
|
263841
|
+
return existing.id;
|
|
263842
|
+
}
|
|
263524
263843
|
const submittedName = `${desiredName} [bootstrap:${this.createIdentity()}]`;
|
|
263525
263844
|
const rootBody = { name: submittedName };
|
|
263526
263845
|
let created;
|
|
@@ -263571,6 +263890,10 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
|
|
|
263571
263890
|
}
|
|
263572
263891
|
return rawId;
|
|
263573
263892
|
}
|
|
263893
|
+
/** Patch only the durable collection description without reconciling its item tree. */
|
|
263894
|
+
async updateCollectionDescription(collectionUid, description) {
|
|
263895
|
+
await this.applyCollectionLevelSettings(this.bareModelId(collectionUid), { description });
|
|
263896
|
+
}
|
|
263574
263897
|
/**
|
|
263575
263898
|
* Full-replace reconcile of a curated local v2.1.0 or collection v3 payload: delete every
|
|
263576
263899
|
* root-level item (deleting a folder cascades its children server-side —
|
|
@@ -263795,7 +264118,8 @@ var AccessTokenGatewayClient = class {
|
|
|
263795
264118
|
* `requestJson` can still parse it.
|
|
263796
264119
|
*/
|
|
263797
264120
|
rebuildResponse(response, body2) {
|
|
263798
|
-
|
|
264121
|
+
const nullBody = response.status === 204 || response.status === 205 || response.status === 304;
|
|
264122
|
+
return new Response(nullBody ? null : body2, {
|
|
263799
264123
|
status: response.status,
|
|
263800
264124
|
statusText: response.statusText,
|
|
263801
264125
|
headers: response.headers
|
|
@@ -280247,6 +280571,61 @@ function serializeOpenApiDocument(document2) {
|
|
|
280247
280571
|
return `${JSON.stringify(document2, null, 2)}
|
|
280248
280572
|
`;
|
|
280249
280573
|
}
|
|
280574
|
+
function typeNullPath(pathSegments) {
|
|
280575
|
+
return pathSegments.map(String).join(".");
|
|
280576
|
+
}
|
|
280577
|
+
function isNullOnlySchema(value) {
|
|
280578
|
+
const record = asRecord10(value);
|
|
280579
|
+
if (!record || record.type !== "null") return false;
|
|
280580
|
+
return Object.keys(record).every((key) => key === "type" || key.startsWith("x-"));
|
|
280581
|
+
}
|
|
280582
|
+
function createOas30TypeNullCompatibilityDocument(sourceDocument) {
|
|
280583
|
+
const document2 = structuredClone(sourceDocument);
|
|
280584
|
+
const sourceTypeNullPaths = [];
|
|
280585
|
+
const visit4 = (value, pathSegments) => {
|
|
280586
|
+
if (Array.isArray(value)) {
|
|
280587
|
+
value.forEach((entry, index) => visit4(entry, [...pathSegments, index]));
|
|
280588
|
+
return;
|
|
280589
|
+
}
|
|
280590
|
+
const record = asRecord10(value);
|
|
280591
|
+
if (!record) return;
|
|
280592
|
+
const oneOf = Array.isArray(record.oneOf) ? record.oneOf : void 0;
|
|
280593
|
+
const nullIndexes = oneOf ? oneOf.flatMap((entry, index) => isNullOnlySchema(entry) ? [index] : []) : [];
|
|
280594
|
+
if (nullIndexes.length > 0) {
|
|
280595
|
+
if (oneOf?.length !== 2 || nullIndexes.length !== 1) {
|
|
280596
|
+
throw new Error(
|
|
280597
|
+
`CONTRACT_OAS30_TYPE_NULL_UNSUPPORTED: ${typeNullPath(pathSegments)} must use oneOf with exactly one null-only member and one non-null schema`
|
|
280598
|
+
);
|
|
280599
|
+
}
|
|
280600
|
+
const nullIndex = nullIndexes[0];
|
|
280601
|
+
const nonNullIndex = nullIndex === 0 ? 1 : 0;
|
|
280602
|
+
const nonNullSchema = asRecord10(oneOf[nonNullIndex]);
|
|
280603
|
+
if (!nonNullSchema || nonNullSchema.type === "null") {
|
|
280604
|
+
throw new Error(
|
|
280605
|
+
`CONTRACT_OAS30_TYPE_NULL_UNSUPPORTED: ${typeNullPath(pathSegments)} must pair the null-only member with one non-null schema`
|
|
280606
|
+
);
|
|
280607
|
+
}
|
|
280608
|
+
const siblings = Object.fromEntries(
|
|
280609
|
+
Object.entries(record).filter(([key]) => key !== "oneOf")
|
|
280610
|
+
);
|
|
280611
|
+
for (const key of Object.keys(record)) delete record[key];
|
|
280612
|
+
Object.assign(record, structuredClone(nonNullSchema), siblings, { nullable: true });
|
|
280613
|
+
sourceTypeNullPaths.push(typeNullPath([...pathSegments, "oneOf", nullIndex, "type"]));
|
|
280614
|
+
visit4(record, pathSegments);
|
|
280615
|
+
return;
|
|
280616
|
+
}
|
|
280617
|
+
if (record.type === "null") {
|
|
280618
|
+
throw new Error(
|
|
280619
|
+
`CONTRACT_OAS30_TYPE_NULL_UNSUPPORTED: ${typeNullPath([...pathSegments, "type"])} is not a supported nullable oneOf member`
|
|
280620
|
+
);
|
|
280621
|
+
}
|
|
280622
|
+
for (const [key, child3] of Object.entries(record)) {
|
|
280623
|
+
visit4(child3, [...pathSegments, key]);
|
|
280624
|
+
}
|
|
280625
|
+
};
|
|
280626
|
+
visit4(document2, []);
|
|
280627
|
+
return { document: document2, sourceTypeNullPaths };
|
|
280628
|
+
}
|
|
280250
280629
|
async function bundleSpec(baseUrl, document2, options) {
|
|
280251
280630
|
const budget = options.budget ?? { refs: 0, totalBytes: Buffer.byteLength(JSON.stringify(document2), "utf8") };
|
|
280252
280631
|
const fetchText = options.fetchText ?? safeFetchText;
|
|
@@ -280288,7 +280667,14 @@ function createCachedFetchText(options) {
|
|
|
280288
280667
|
async function buildLoadedSpec(content, baseRef, options, fetchText, budget) {
|
|
280289
280668
|
const document2 = parseOpenApiDocument(content);
|
|
280290
280669
|
const version = detectOpenApiVersion2(document2);
|
|
280291
|
-
|
|
280670
|
+
let contractDocument = document2;
|
|
280671
|
+
let sourceTypeNullPaths = [];
|
|
280672
|
+
if (options.preserveOas30TypeNull && version === "3.0") {
|
|
280673
|
+
const compatibility = createOas30TypeNullCompatibilityDocument(document2);
|
|
280674
|
+
contractDocument = compatibility.document;
|
|
280675
|
+
sourceTypeNullPaths = compatibility.sourceTypeNullPaths;
|
|
280676
|
+
}
|
|
280677
|
+
const bundledDocument = await bundleSpec(baseRef, contractDocument, { ...options, budget, fetchText });
|
|
280292
280678
|
const validation = await validate(bundledDocument, {
|
|
280293
280679
|
resolve: { external: false, file: false },
|
|
280294
280680
|
dereference: { circular: "ignore" },
|
|
@@ -280302,6 +280688,7 @@ async function buildLoadedSpec(content, baseRef, options, fetchText, budget) {
|
|
|
280302
280688
|
bundledDocument,
|
|
280303
280689
|
contractIndex: buildContractIndex(bundledDocument),
|
|
280304
280690
|
content,
|
|
280691
|
+
sourceTypeNullPaths,
|
|
280305
280692
|
version
|
|
280306
280693
|
};
|
|
280307
280694
|
}
|
|
@@ -280427,6 +280814,309 @@ function looksLikeIntrospection(record) {
|
|
|
280427
280814
|
return Boolean(data && typeof data === "object" && data.__schema);
|
|
280428
280815
|
}
|
|
280429
280816
|
|
|
280817
|
+
// src/lib/repo/branch-decision.ts
|
|
280818
|
+
var import_node_fs5 = require("node:fs");
|
|
280819
|
+
var import_node_crypto4 = require("node:crypto");
|
|
280820
|
+
var ContractError = class extends Error {
|
|
280821
|
+
code;
|
|
280822
|
+
constructor(code, message) {
|
|
280823
|
+
super(`${code}: ${message}`);
|
|
280824
|
+
this.code = code;
|
|
280825
|
+
this.name = "ContractError";
|
|
280826
|
+
}
|
|
280827
|
+
};
|
|
280828
|
+
function clean(value) {
|
|
280829
|
+
const trimmed = (value ?? "").trim();
|
|
280830
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
280831
|
+
}
|
|
280832
|
+
function stripRefPrefix(ref) {
|
|
280833
|
+
const raw = clean(ref);
|
|
280834
|
+
if (!raw) {
|
|
280835
|
+
return { kind: "unknown" };
|
|
280836
|
+
}
|
|
280837
|
+
if (raw.startsWith("refs/heads/")) {
|
|
280838
|
+
return { name: raw.slice("refs/heads/".length), kind: "branch" };
|
|
280839
|
+
}
|
|
280840
|
+
if (raw.startsWith("refs/tags/")) {
|
|
280841
|
+
return { name: raw.slice("refs/tags/".length), kind: "tag" };
|
|
280842
|
+
}
|
|
280843
|
+
if (raw.startsWith("refs/pull/") || raw.startsWith("refs/merge")) {
|
|
280844
|
+
return { kind: "unknown" };
|
|
280845
|
+
}
|
|
280846
|
+
return { name: raw, kind: "branch" };
|
|
280847
|
+
}
|
|
280848
|
+
function detectProvider(env) {
|
|
280849
|
+
if (clean(env.GITHUB_ACTIONS) || clean(env.GITHUB_REPOSITORY)) return "github";
|
|
280850
|
+
if (clean(env.GITLAB_CI) || clean(env.CI_PROJECT_PATH)) return "gitlab";
|
|
280851
|
+
if (clean(env.BITBUCKET_REPO_SLUG) || clean(env.BITBUCKET_BRANCH)) return "bitbucket";
|
|
280852
|
+
if (clean(env.TF_BUILD) || clean(env.BUILD_REPOSITORY_URI)) return "azure-devops";
|
|
280853
|
+
return "unknown";
|
|
280854
|
+
}
|
|
280855
|
+
function readGithubEvent(env) {
|
|
280856
|
+
const path8 = clean(env.GITHUB_EVENT_PATH);
|
|
280857
|
+
if (!path8) return void 0;
|
|
280858
|
+
try {
|
|
280859
|
+
return JSON.parse((0, import_node_fs5.readFileSync)(path8, "utf8"));
|
|
280860
|
+
} catch {
|
|
280861
|
+
return void 0;
|
|
280862
|
+
}
|
|
280863
|
+
}
|
|
280864
|
+
function resolveBranchIdentity(env = process.env, overrides = {}) {
|
|
280865
|
+
const provider = detectProvider(env);
|
|
280866
|
+
const explicitDefault = clean(overrides.defaultBranch);
|
|
280867
|
+
let headBranch;
|
|
280868
|
+
let rawRef;
|
|
280869
|
+
let refKind;
|
|
280870
|
+
let isPrContext = false;
|
|
280871
|
+
let isForkPr = false;
|
|
280872
|
+
let defaultBranch = explicitDefault;
|
|
280873
|
+
let headSha;
|
|
280874
|
+
switch (provider) {
|
|
280875
|
+
case "github": {
|
|
280876
|
+
const event2 = readGithubEvent(env);
|
|
280877
|
+
headSha = clean(env.GITHUB_SHA);
|
|
280878
|
+
defaultBranch ??= clean(event2?.repository?.default_branch);
|
|
280879
|
+
const headRef = clean(env.GITHUB_HEAD_REF);
|
|
280880
|
+
if (headRef) {
|
|
280881
|
+
isPrContext = true;
|
|
280882
|
+
headBranch = headRef;
|
|
280883
|
+
rawRef = clean(env.GITHUB_REF) ?? headRef;
|
|
280884
|
+
refKind = "branch";
|
|
280885
|
+
const headRepo = event2?.pull_request?.head?.repo?.full_name;
|
|
280886
|
+
const baseRepo = event2?.pull_request?.base?.repo?.full_name ?? event2?.repository?.full_name;
|
|
280887
|
+
isForkPr = Boolean(headRepo && baseRepo && headRepo !== baseRepo);
|
|
280888
|
+
headSha = clean(event2?.pull_request?.head?.sha) ?? headSha;
|
|
280889
|
+
} else {
|
|
280890
|
+
rawRef = clean(env.GITHUB_REF) ?? clean(env.GITHUB_REF_NAME);
|
|
280891
|
+
const parsed = stripRefPrefix(rawRef);
|
|
280892
|
+
headBranch = parsed.kind === "branch" ? parsed.name : void 0;
|
|
280893
|
+
refKind = parsed.kind;
|
|
280894
|
+
}
|
|
280895
|
+
break;
|
|
280896
|
+
}
|
|
280897
|
+
case "gitlab": {
|
|
280898
|
+
headSha = clean(env.CI_COMMIT_SHA);
|
|
280899
|
+
defaultBranch ??= clean(env.CI_DEFAULT_BRANCH);
|
|
280900
|
+
const mrSource = clean(env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME);
|
|
280901
|
+
if (mrSource) {
|
|
280902
|
+
isPrContext = true;
|
|
280903
|
+
headBranch = mrSource;
|
|
280904
|
+
rawRef = mrSource;
|
|
280905
|
+
refKind = "branch";
|
|
280906
|
+
const sourceProject = clean(env.CI_MERGE_REQUEST_SOURCE_PROJECT_ID);
|
|
280907
|
+
const targetProject = clean(env.CI_MERGE_REQUEST_PROJECT_ID);
|
|
280908
|
+
isForkPr = Boolean(sourceProject && targetProject && sourceProject !== targetProject);
|
|
280909
|
+
} else if (clean(env.CI_COMMIT_TAG)) {
|
|
280910
|
+
rawRef = clean(env.CI_COMMIT_TAG);
|
|
280911
|
+
refKind = "tag";
|
|
280912
|
+
} else {
|
|
280913
|
+
headBranch = clean(env.CI_COMMIT_BRANCH) ?? clean(env.CI_COMMIT_REF_NAME);
|
|
280914
|
+
rawRef = headBranch;
|
|
280915
|
+
refKind = headBranch ? "branch" : "unknown";
|
|
280916
|
+
}
|
|
280917
|
+
break;
|
|
280918
|
+
}
|
|
280919
|
+
case "bitbucket": {
|
|
280920
|
+
headSha = clean(env.BITBUCKET_COMMIT);
|
|
280921
|
+
if (clean(env.BITBUCKET_TAG)) {
|
|
280922
|
+
rawRef = clean(env.BITBUCKET_TAG);
|
|
280923
|
+
refKind = "tag";
|
|
280924
|
+
} else {
|
|
280925
|
+
headBranch = clean(env.BITBUCKET_BRANCH);
|
|
280926
|
+
rawRef = headBranch;
|
|
280927
|
+
refKind = headBranch ? "branch" : "unknown";
|
|
280928
|
+
isPrContext = Boolean(clean(env.BITBUCKET_PR_ID));
|
|
280929
|
+
}
|
|
280930
|
+
break;
|
|
280931
|
+
}
|
|
280932
|
+
case "azure-devops": {
|
|
280933
|
+
headSha = clean(env.BUILD_SOURCEVERSION);
|
|
280934
|
+
const prSource = clean(env.SYSTEM_PULLREQUEST_SOURCEBRANCH);
|
|
280935
|
+
if (prSource) {
|
|
280936
|
+
isPrContext = true;
|
|
280937
|
+
const parsed = stripRefPrefix(prSource);
|
|
280938
|
+
headBranch = parsed.kind === "branch" ? parsed.name : void 0;
|
|
280939
|
+
rawRef = prSource;
|
|
280940
|
+
refKind = parsed.kind;
|
|
280941
|
+
const forkFlag = clean(env.SYSTEM_PULLREQUEST_ISFORK);
|
|
280942
|
+
isForkPr = forkFlag?.toLowerCase() === "true";
|
|
280943
|
+
} else {
|
|
280944
|
+
rawRef = clean(env.BUILD_SOURCEBRANCH);
|
|
280945
|
+
const parsed = stripRefPrefix(rawRef);
|
|
280946
|
+
headBranch = parsed.kind === "branch" ? parsed.name : void 0;
|
|
280947
|
+
refKind = parsed.kind;
|
|
280948
|
+
}
|
|
280949
|
+
break;
|
|
280950
|
+
}
|
|
280951
|
+
default: {
|
|
280952
|
+
refKind = "unknown";
|
|
280953
|
+
}
|
|
280954
|
+
}
|
|
280955
|
+
if (refKind === "branch" && headBranch && defaultBranch && headBranch === defaultBranch) {
|
|
280956
|
+
refKind = "default-branch";
|
|
280957
|
+
}
|
|
280958
|
+
return { provider, headBranch, rawRef, defaultBranch, refKind, isPrContext, isForkPr, headSha };
|
|
280959
|
+
}
|
|
280960
|
+
function parseChannelRules(input) {
|
|
280961
|
+
const raw = clean(input);
|
|
280962
|
+
const rules = [];
|
|
280963
|
+
for (const part of raw ? raw.split(",") : []) {
|
|
280964
|
+
const entry = part.trim();
|
|
280965
|
+
if (!entry) continue;
|
|
280966
|
+
const eq = entry.indexOf("=");
|
|
280967
|
+
if (eq <= 0 || eq === entry.length - 1) {
|
|
280968
|
+
throw new ContractError(
|
|
280969
|
+
"CONTRACT_CHANNELS_INPUT_INVALID",
|
|
280970
|
+
`channels entry "${entry}" must be <branch-or-glob>=<CODE>`
|
|
280971
|
+
);
|
|
280972
|
+
}
|
|
280973
|
+
const pattern = entry.slice(0, eq).trim();
|
|
280974
|
+
const code = entry.slice(eq + 1).trim().toUpperCase();
|
|
280975
|
+
if (!/^[A-Z][A-Z0-9_-]{0,15}$/.test(code)) {
|
|
280976
|
+
throw new ContractError(
|
|
280977
|
+
"CONTRACT_CHANNELS_INPUT_INVALID",
|
|
280978
|
+
`channel code "${code}" must be 1-16 chars, A-Z 0-9 _ -, starting with a letter`
|
|
280979
|
+
);
|
|
280980
|
+
}
|
|
280981
|
+
rules.push({ pattern, code });
|
|
280982
|
+
}
|
|
280983
|
+
if (!rules.some((rule) => rule.pattern === "release/*")) {
|
|
280984
|
+
rules.push({ pattern: "release/*", code: "RC" });
|
|
280985
|
+
}
|
|
280986
|
+
return rules;
|
|
280987
|
+
}
|
|
280988
|
+
function matchChannel(branch, rules) {
|
|
280989
|
+
for (const rule of rules) {
|
|
280990
|
+
if (rule.pattern.endsWith("*")) {
|
|
280991
|
+
const prefix = rule.pattern.slice(0, -1);
|
|
280992
|
+
if (branch.startsWith(prefix)) return rule;
|
|
280993
|
+
} else if (branch === rule.pattern) {
|
|
280994
|
+
return rule;
|
|
280995
|
+
}
|
|
280996
|
+
}
|
|
280997
|
+
return void 0;
|
|
280998
|
+
}
|
|
280999
|
+
function resolveBranchDecision(options) {
|
|
281000
|
+
const { strategy, identity } = options;
|
|
281001
|
+
const channels = options.channels ?? [];
|
|
281002
|
+
if (strategy === "legacy") {
|
|
281003
|
+
return {
|
|
281004
|
+
tier: "legacy",
|
|
281005
|
+
strategy,
|
|
281006
|
+
identity,
|
|
281007
|
+
canonicalBranch: clean(options.canonicalBranch) ?? identity.defaultBranch,
|
|
281008
|
+
reason: "branch-strategy legacy: branch-blind pre-v2 behavior"
|
|
281009
|
+
};
|
|
281010
|
+
}
|
|
281011
|
+
const canonicalBranch = clean(options.canonicalBranch) ?? identity.defaultBranch;
|
|
281012
|
+
if (!canonicalBranch) {
|
|
281013
|
+
throw new ContractError(
|
|
281014
|
+
"CONTRACT_DEFAULT_BRANCH_UNRESOLVED",
|
|
281015
|
+
`cannot resolve the canonical branch on ${identity.provider} (no explicit canonical-branch input and the provider exposes no default-branch variable). Set the canonical-branch input.`
|
|
281016
|
+
);
|
|
281017
|
+
}
|
|
281018
|
+
if (identity.refKind === "tag" || identity.refKind === "unknown" || !identity.headBranch) {
|
|
281019
|
+
return {
|
|
281020
|
+
tier: "gated",
|
|
281021
|
+
strategy,
|
|
281022
|
+
identity,
|
|
281023
|
+
canonicalBranch,
|
|
281024
|
+
reason: `ref kind ${identity.refKind}: never canonical/preview-eligible; no-op with annotation`
|
|
281025
|
+
};
|
|
281026
|
+
}
|
|
281027
|
+
if (identity.headBranch === canonicalBranch) {
|
|
281028
|
+
return {
|
|
281029
|
+
tier: "canonical",
|
|
281030
|
+
strategy,
|
|
281031
|
+
identity,
|
|
281032
|
+
canonicalBranch,
|
|
281033
|
+
reason: `head branch equals canonical branch ${canonicalBranch}`
|
|
281034
|
+
};
|
|
281035
|
+
}
|
|
281036
|
+
const channel = matchChannel(identity.headBranch, channels);
|
|
281037
|
+
if (channel) {
|
|
281038
|
+
return {
|
|
281039
|
+
tier: "channel",
|
|
281040
|
+
strategy,
|
|
281041
|
+
identity,
|
|
281042
|
+
canonicalBranch,
|
|
281043
|
+
channel,
|
|
281044
|
+
reason: `branch ${identity.headBranch} matches channel ${channel.pattern}=${channel.code}`
|
|
281045
|
+
};
|
|
281046
|
+
}
|
|
281047
|
+
if (strategy === "preview") {
|
|
281048
|
+
if (identity.isForkPr) {
|
|
281049
|
+
return {
|
|
281050
|
+
tier: "gated",
|
|
281051
|
+
strategy,
|
|
281052
|
+
identity,
|
|
281053
|
+
canonicalBranch,
|
|
281054
|
+
reason: "fork PR: preview-ineligible (same-repo gate), gated instead"
|
|
281055
|
+
};
|
|
281056
|
+
}
|
|
281057
|
+
return {
|
|
281058
|
+
tier: "preview",
|
|
281059
|
+
strategy,
|
|
281060
|
+
identity,
|
|
281061
|
+
canonicalBranch,
|
|
281062
|
+
reason: `branch ${identity.headBranch} under branch-strategy preview`
|
|
281063
|
+
};
|
|
281064
|
+
}
|
|
281065
|
+
return {
|
|
281066
|
+
tier: "gated",
|
|
281067
|
+
strategy,
|
|
281068
|
+
identity,
|
|
281069
|
+
canonicalBranch,
|
|
281070
|
+
reason: `branch ${identity.headBranch} under branch-strategy publish-gate`
|
|
281071
|
+
};
|
|
281072
|
+
}
|
|
281073
|
+
var BRANCH_DECISION_ENV = "POSTMAN_BRANCH_DECISION";
|
|
281074
|
+
function serializeBranchDecision(decision) {
|
|
281075
|
+
return JSON.stringify(decision);
|
|
281076
|
+
}
|
|
281077
|
+
function parseBranchDecision(raw) {
|
|
281078
|
+
const value = clean(raw);
|
|
281079
|
+
if (!value) return void 0;
|
|
281080
|
+
let parsed;
|
|
281081
|
+
try {
|
|
281082
|
+
parsed = JSON.parse(value);
|
|
281083
|
+
} catch {
|
|
281084
|
+
throw new ContractError("CONTRACT_BRANCH_DECISION_INVALID", "POSTMAN_BRANCH_DECISION is not valid JSON");
|
|
281085
|
+
}
|
|
281086
|
+
const candidate = parsed;
|
|
281087
|
+
const tiers = ["canonical", "channel", "preview", "gated", "legacy"];
|
|
281088
|
+
if (!candidate || typeof candidate !== "object" || !tiers.includes(candidate.tier) || !candidate.identity) {
|
|
281089
|
+
throw new ContractError("CONTRACT_BRANCH_DECISION_INVALID", "POSTMAN_BRANCH_DECISION does not carry a valid BranchDecision");
|
|
281090
|
+
}
|
|
281091
|
+
return candidate;
|
|
281092
|
+
}
|
|
281093
|
+
function resolveEffectiveBranchDecision(options, env = process.env) {
|
|
281094
|
+
const inherited = parseBranchDecision(env[BRANCH_DECISION_ENV]);
|
|
281095
|
+
if (inherited) return inherited;
|
|
281096
|
+
return resolveBranchDecision(options);
|
|
281097
|
+
}
|
|
281098
|
+
var PREVIEW_SLUG_MAX = 30;
|
|
281099
|
+
function buildBranchSlug(rawBranch) {
|
|
281100
|
+
const sanitized = rawBranch.replace(/^refs\/heads\//, "").replace(/\s+/g, "-").replace(/[^A-Za-z0-9._-]/g, "-").replace(/-+/g, "-").replace(/^[._-]+|[._-]+$/g, "");
|
|
281101
|
+
const truncated = sanitized.slice(0, PREVIEW_SLUG_MAX);
|
|
281102
|
+
const lossy = truncated !== rawBranch.replace(/^refs\/heads\//, "");
|
|
281103
|
+
if (!lossy) {
|
|
281104
|
+
return { suffix: truncated, slug: truncated, lossy };
|
|
281105
|
+
}
|
|
281106
|
+
const hash = (0, import_node_crypto4.createHash)("sha256").update(rawBranch).digest("hex").slice(0, 6);
|
|
281107
|
+
return { suffix: `${truncated}-${hash}`, slug: truncated, lossy };
|
|
281108
|
+
}
|
|
281109
|
+
function previewAssetName(baseName, rawBranch) {
|
|
281110
|
+
return `${baseName} @${buildBranchSlug(rawBranch).suffix}`;
|
|
281111
|
+
}
|
|
281112
|
+
function channelAssetName(baseName, code) {
|
|
281113
|
+
return `[${code}] ${baseName}`;
|
|
281114
|
+
}
|
|
281115
|
+
var MARKER_KEY = "x-pm-onboarding";
|
|
281116
|
+
function renderAssetMarker(marker) {
|
|
281117
|
+
return `${MARKER_KEY}: ${JSON.stringify(marker)}`;
|
|
281118
|
+
}
|
|
281119
|
+
|
|
280430
281120
|
// node_modules/graphql/jsutils/inspect.mjs
|
|
280431
281121
|
var MAX_ARRAY_LENGTH = 10;
|
|
280432
281122
|
var MAX_RECURSIVE_DEPTH = 2;
|
|
@@ -303758,7 +304448,7 @@ function parseWsdl(content, opts) {
|
|
|
303758
304448
|
}
|
|
303759
304449
|
|
|
303760
304450
|
// src/lib/protocols/soap/builder.ts
|
|
303761
|
-
var
|
|
304451
|
+
var import_node_crypto5 = require("node:crypto");
|
|
303762
304452
|
var COLLECTION_V210_SCHEMA2 = "https://schema.getpostman.com/json/collection/v2.1.0/collection.json";
|
|
303763
304453
|
var SOAP11_ENVELOPE_NS = "http://schemas.xmlsoap.org/soap/envelope/";
|
|
303764
304454
|
var SOAP12_ENVELOPE_NS = "http://www.w3.org/2003/05/soap-envelope";
|
|
@@ -303766,7 +304456,7 @@ var SOAP11_CONTENT_TYPE = "text/xml; charset=UTF-8";
|
|
|
303766
304456
|
var SOAP12_CONTENT_TYPE = "application/soap+xml; charset=UTF-8";
|
|
303767
304457
|
var WSA_NS = "http://www.w3.org/2005/08/addressing";
|
|
303768
304458
|
function stableId2(seed) {
|
|
303769
|
-
return (0,
|
|
304459
|
+
return (0, import_node_crypto5.createHash)("sha256").update(seed).digest("hex").slice(0, 32);
|
|
303770
304460
|
}
|
|
303771
304461
|
function envelopeNamespace(version) {
|
|
303772
304462
|
return version === "1.2" ? SOAP12_ENVELOPE_NS : SOAP11_ENVELOPE_NS;
|
|
@@ -310523,6 +311213,11 @@ function resolveInputs(env = process.env) {
|
|
|
310523
311213
|
),
|
|
310524
311214
|
protocolEndpointUrl: getInput("protocol-endpoint-url", env),
|
|
310525
311215
|
openapiVersion: resolveOpenapiVersion(getInput("openapi-version", env)),
|
|
311216
|
+
preserveOas30TypeNull: parseBooleanInput(
|
|
311217
|
+
"preserve-oas30-type-null",
|
|
311218
|
+
getInput("preserve-oas30-type-null", env),
|
|
311219
|
+
false
|
|
311220
|
+
),
|
|
310526
311221
|
breakingChangeMode: parseBreakingChangeMode(getInput("breaking-change-mode", env)),
|
|
310527
311222
|
breakingBaselineSpecPath: getInput("breaking-baseline-spec-path", env),
|
|
310528
311223
|
breakingRulesPath: getInput("breaking-rules-path", env) ?? bootstrapActionContract.inputs["breaking-rules-path"].default,
|
|
@@ -310553,9 +311248,72 @@ function resolveInputs(env = process.env) {
|
|
|
310553
311248
|
githubRef: env.GITHUB_REF,
|
|
310554
311249
|
githubSha: env.GITHUB_SHA,
|
|
310555
311250
|
githubToken: getInput("github-token", env) || env.GITHUB_TOKEN || "",
|
|
310556
|
-
ghFallbackToken: getInput("gh-fallback-token", env) || env.GH_FALLBACK_TOKEN || ""
|
|
311251
|
+
ghFallbackToken: getInput("gh-fallback-token", env) || env.GH_FALLBACK_TOKEN || "",
|
|
311252
|
+
branchStrategy: parseEnumInput(
|
|
311253
|
+
"branch-strategy",
|
|
311254
|
+
getInput("branch-strategy", env),
|
|
311255
|
+
"legacy"
|
|
311256
|
+
),
|
|
311257
|
+
canonicalBranch: getInput("canonical-branch", env),
|
|
311258
|
+
channels: getInput("channels", env)
|
|
310557
311259
|
};
|
|
310558
311260
|
}
|
|
311261
|
+
function decideBranchTier(inputs, env = process.env) {
|
|
311262
|
+
return resolveEffectiveBranchDecision(
|
|
311263
|
+
{
|
|
311264
|
+
// Tolerate hand-built inputs objects (tests, embedders) that omit the
|
|
311265
|
+
// field: absent means legacy, exactly like the action default.
|
|
311266
|
+
strategy: inputs.branchStrategy ?? "legacy",
|
|
311267
|
+
identity: resolveBranchIdentity(env, { defaultBranch: inputs.canonicalBranch }),
|
|
311268
|
+
canonicalBranch: inputs.canonicalBranch,
|
|
311269
|
+
channels: parseChannelRules(inputs.channels)
|
|
311270
|
+
},
|
|
311271
|
+
env
|
|
311272
|
+
);
|
|
311273
|
+
}
|
|
311274
|
+
function embedSpecBranchMarker(content, decision, repo) {
|
|
311275
|
+
if (decision.tier !== "preview" && decision.tier !== "channel" || !decision.identity.headBranch || !repo) {
|
|
311276
|
+
return content;
|
|
311277
|
+
}
|
|
311278
|
+
const rawBranch = decision.identity.headBranch;
|
|
311279
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
311280
|
+
const marker = {
|
|
311281
|
+
repo,
|
|
311282
|
+
rawBranch,
|
|
311283
|
+
sanitizedBranch: rawBranch.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/-+/g, "-").slice(0, 30),
|
|
311284
|
+
role: decision.tier,
|
|
311285
|
+
headSha: decision.identity.headSha,
|
|
311286
|
+
createdAt: now,
|
|
311287
|
+
lastSyncedAt: now
|
|
311288
|
+
};
|
|
311289
|
+
try {
|
|
311290
|
+
if (content.trim().startsWith("{")) {
|
|
311291
|
+
return `${JSON.stringify({ ...JSON.parse(content), "x-postman-onboarding": marker }, null, 2)}
|
|
311292
|
+
`;
|
|
311293
|
+
}
|
|
311294
|
+
const document2 = (0, import_yaml4.parse)(content);
|
|
311295
|
+
if (!document2 || typeof document2 !== "object" || Array.isArray(document2)) return content;
|
|
311296
|
+
return (0, import_yaml4.stringify)({ ...document2, "x-postman-onboarding": marker });
|
|
311297
|
+
} catch {
|
|
311298
|
+
return content;
|
|
311299
|
+
}
|
|
311300
|
+
}
|
|
311301
|
+
function renderCollectionBranchMarker(decision, repo, now = /* @__PURE__ */ new Date()) {
|
|
311302
|
+
if (decision.tier !== "preview" && decision.tier !== "channel" || !decision.identity.headBranch || !repo) {
|
|
311303
|
+
return void 0;
|
|
311304
|
+
}
|
|
311305
|
+
const rawBranch = decision.identity.headBranch;
|
|
311306
|
+
const timestamp = now.toISOString();
|
|
311307
|
+
return renderAssetMarker({
|
|
311308
|
+
repo,
|
|
311309
|
+
rawBranch,
|
|
311310
|
+
sanitizedBranch: rawBranch.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/-+/g, "-").slice(0, 30),
|
|
311311
|
+
role: decision.tier,
|
|
311312
|
+
headSha: decision.identity.headSha,
|
|
311313
|
+
createdAt: timestamp,
|
|
311314
|
+
lastSyncedAt: timestamp
|
|
311315
|
+
});
|
|
311316
|
+
}
|
|
310559
311317
|
function createPlannedOutputs(inputs) {
|
|
310560
311318
|
const workspaceName = inputs.domainCode ? `[${inputs.domainCode}] ${inputs.projectName}` : inputs.projectName;
|
|
310561
311319
|
return {
|
|
@@ -310587,7 +311345,12 @@ function createPlannedOutputs(inputs) {
|
|
|
310587
311345
|
mode: inputs.breakingChangeMode,
|
|
310588
311346
|
status: "skipped",
|
|
310589
311347
|
summaryPath: ""
|
|
310590
|
-
})
|
|
311348
|
+
}),
|
|
311349
|
+
"sync-status": "",
|
|
311350
|
+
"branch-decision": "",
|
|
311351
|
+
"spec-version-tag": "",
|
|
311352
|
+
"spec-version-url": "",
|
|
311353
|
+
"spec-content-changed": ""
|
|
310591
311354
|
};
|
|
310592
311355
|
}
|
|
310593
311356
|
async function mintAccessTokenIfNeeded2(inputs, log, setSecret2) {
|
|
@@ -310692,6 +311455,27 @@ async function lintSpecViaCli(dependencies, workspaceId, specId) {
|
|
|
310692
311455
|
warnings
|
|
310693
311456
|
};
|
|
310694
311457
|
}
|
|
311458
|
+
function normalizeLintPath(value) {
|
|
311459
|
+
return value.trim().replace(/^\$\.?/, "").replace(/\[(\d+)\]/g, ".$1").replace(/^\./, "");
|
|
311460
|
+
}
|
|
311461
|
+
function applyOas30TypeNullLintCompatibility(summary2, sourceTypeNullPaths) {
|
|
311462
|
+
const acceptedPaths = new Set(sourceTypeNullPaths.map(normalizeLintPath));
|
|
311463
|
+
if (acceptedPaths.size === 0) return summary2;
|
|
311464
|
+
const violations = summary2.violations.map((violation) => {
|
|
311465
|
+
const path8 = normalizeLintPath(violation.path ?? "");
|
|
311466
|
+
const issue2 = violation.issue ?? "";
|
|
311467
|
+
const isTypeEnumFinding = /["']?type["']? property/i.test(issue2) && /allowed values|must be equal to one of/i.test(issue2);
|
|
311468
|
+
if (violation.severity === "ERROR" && acceptedPaths.has(path8) && isTypeEnumFinding) {
|
|
311469
|
+
return { ...violation, severity: "WARNING" };
|
|
311470
|
+
}
|
|
311471
|
+
return violation;
|
|
311472
|
+
});
|
|
311473
|
+
return {
|
|
311474
|
+
errors: violations.filter((entry) => entry.severity === "ERROR").length,
|
|
311475
|
+
violations,
|
|
311476
|
+
warnings: violations.filter((entry) => entry.severity === "WARNING").length
|
|
311477
|
+
};
|
|
311478
|
+
}
|
|
310695
311479
|
function shouldRetrySpecFetch(error) {
|
|
310696
311480
|
const retryability = classifySafeFetchRetryability(error);
|
|
310697
311481
|
return retryability === "retryable" || retryability === "unknown";
|
|
@@ -311172,7 +311956,7 @@ async function runProtocolBootstrap(specType, rawSpecContent, inputs, dependenci
|
|
|
311172
311956
|
const workspaceRoot = path6.resolve(process.env.GITHUB_WORKSPACE ?? process.cwd());
|
|
311173
311957
|
const serviceConfigPath = path6.join(path6.dirname(path6.resolve(workspaceRoot, inputs.specPath)), "grpc_service_config.json");
|
|
311174
311958
|
try {
|
|
311175
|
-
grpcServiceConfigJson = (0,
|
|
311959
|
+
grpcServiceConfigJson = (0, import_node_fs6.readFileSync)(serviceConfigPath, "utf8");
|
|
311176
311960
|
dependencies.core.info(`Found gRPC service config at ${serviceConfigPath}; validating it against the proto contract`);
|
|
311177
311961
|
} catch {
|
|
311178
311962
|
}
|
|
@@ -311186,7 +311970,7 @@ async function runProtocolBootstrap(specType, rawSpecContent, inputs, dependenci
|
|
|
311186
311970
|
const resolved = path6.resolve(specDir, location2);
|
|
311187
311971
|
if (!resolved.startsWith(specDir + path6.sep)) return void 0;
|
|
311188
311972
|
try {
|
|
311189
|
-
return (0,
|
|
311973
|
+
return (0, import_node_fs6.readFileSync)(resolved, "utf8");
|
|
311190
311974
|
} catch {
|
|
311191
311975
|
return void 0;
|
|
311192
311976
|
}
|
|
@@ -311327,6 +312111,42 @@ async function createExtensibleContractCollection(workspaceId, built, inputs, de
|
|
|
311327
312111
|
}
|
|
311328
312112
|
async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
311329
312113
|
const outputs = createPlannedOutputs(inputs);
|
|
312114
|
+
const branchDecision = decideBranchTier(inputs);
|
|
312115
|
+
const isCanonicalWriter = branchDecision.tier === "legacy" || branchDecision.tier === "canonical";
|
|
312116
|
+
const canonicalProjectName = inputs.projectName;
|
|
312117
|
+
const workspaceName = createWorkspaceName(inputs);
|
|
312118
|
+
const aboutText = `Auto-provisioned by Postman for ${inputs.projectName}`;
|
|
312119
|
+
if (branchDecision.tier === "preview" && branchDecision.identity.headBranch) {
|
|
312120
|
+
inputs = {
|
|
312121
|
+
...inputs,
|
|
312122
|
+
projectName: previewAssetName(inputs.projectName, branchDecision.identity.headBranch)
|
|
312123
|
+
};
|
|
312124
|
+
dependencies.core.info(`branch-aware sync: preview asset set "${inputs.projectName}"`);
|
|
312125
|
+
} else if (branchDecision.tier === "channel" && branchDecision.channel) {
|
|
312126
|
+
inputs = {
|
|
312127
|
+
...inputs,
|
|
312128
|
+
projectName: channelAssetName(inputs.projectName, branchDecision.channel.code)
|
|
312129
|
+
};
|
|
312130
|
+
dependencies.core.info(`branch-aware sync: channel asset set "${inputs.projectName}"`);
|
|
312131
|
+
}
|
|
312132
|
+
const collectionBranchMarker = renderCollectionBranchMarker(branchDecision, inputs.repoUrl);
|
|
312133
|
+
if (branchDecision.tier !== "legacy") {
|
|
312134
|
+
outputs["sync-status"] = "synced";
|
|
312135
|
+
outputs["branch-decision"] = serializeBranchDecision(branchDecision);
|
|
312136
|
+
}
|
|
312137
|
+
if (!isCanonicalWriter) {
|
|
312138
|
+
const explicitCanonicalIds = [
|
|
312139
|
+
["spec-id", inputs.specId],
|
|
312140
|
+
["baseline-collection-id", inputs.baselineCollectionId],
|
|
312141
|
+
["smoke-collection-id", inputs.smokeCollectionId],
|
|
312142
|
+
["contract-collection-id", inputs.contractCollectionId]
|
|
312143
|
+
].filter(([, value]) => Boolean(value));
|
|
312144
|
+
if (explicitCanonicalIds.length > 0) {
|
|
312145
|
+
throw new Error(
|
|
312146
|
+
`CONTRACT_BRANCH_CANONICAL_WRITE: a ${branchDecision.tier} run must not mutate canonical assets, but explicit asset id input(s) were provided: ${explicitCanonicalIds.map(([name]) => name).join(", ")}. Remove them (preview/channel runs discover or create their own suffixed asset sets).`
|
|
312147
|
+
);
|
|
312148
|
+
}
|
|
312149
|
+
}
|
|
311330
312150
|
const requiresReleaseLabel = inputs.collectionSyncMode === "version" || inputs.specSyncMode === "version";
|
|
311331
312151
|
const releaseLabel = requiresReleaseLabel ? deriveReleaseLabel(inputs) : void 0;
|
|
311332
312152
|
if (requiresReleaseLabel && !releaseLabel) {
|
|
@@ -311334,11 +312154,23 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311334
312154
|
"Versioned spec or collection sync requires a release-label or derivable GitHub ref metadata"
|
|
311335
312155
|
);
|
|
311336
312156
|
}
|
|
311337
|
-
const collectionAssetProjectName = inputs.collectionSyncMode === "version" ? createAssetProjectName(inputs, releaseLabel) : inputs.projectName;
|
|
311338
|
-
const
|
|
311339
|
-
const
|
|
311340
|
-
const stateStore =
|
|
311341
|
-
|
|
312157
|
+
const collectionAssetProjectName = branchDecision.tier === "channel" ? canonicalProjectName : inputs.collectionSyncMode === "version" ? createAssetProjectName(inputs, releaseLabel) : inputs.projectName;
|
|
312158
|
+
const rawStateStore = resolveResourcesStateStore(dependencies);
|
|
312159
|
+
const trackedState = rawStateStore.read();
|
|
312160
|
+
const stateStore = isCanonicalWriter ? rawStateStore : {
|
|
312161
|
+
read: rawStateStore.read,
|
|
312162
|
+
write: () => {
|
|
312163
|
+
dependencies.core.info(
|
|
312164
|
+
`branch-aware sync: skipping .postman/resources.yaml write on ${branchDecision.tier} run (canonical-only tracked state)`
|
|
312165
|
+
);
|
|
312166
|
+
}
|
|
312167
|
+
};
|
|
312168
|
+
const resourcesState = isCanonicalWriter ? trackedState : trackedState?.workspace ? { workspace: trackedState.workspace } : null;
|
|
312169
|
+
if (!isCanonicalWriter && trackedState?.cloudResources) {
|
|
312170
|
+
dependencies.core.info(
|
|
312171
|
+
"branch-aware sync: canonical asset ids in .postman/resources.yaml are not resolved on a non-canonical run"
|
|
312172
|
+
);
|
|
312173
|
+
}
|
|
311342
312174
|
const writableResourcesState = resourcesState ?? {};
|
|
311343
312175
|
const additionalCollections = loadAdditionalCollectionFiles(
|
|
311344
312176
|
inputs.additionalCollectionsDir,
|
|
@@ -311358,16 +312190,19 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311358
312190
|
}
|
|
311359
312191
|
let previousSpecContent;
|
|
311360
312192
|
let previousSpecRollbackHash;
|
|
312193
|
+
let specContentUnchanged = false;
|
|
311361
312194
|
let detectedOpenapiVersion = "3.0";
|
|
311362
312195
|
let contractIndex;
|
|
311363
312196
|
let sourceSpecContent = "";
|
|
312197
|
+
let sourceTypeNullPaths = [];
|
|
312198
|
+
let preserveSourceSpecBytes = false;
|
|
311364
312199
|
const rawSpecContent = await runGroup(
|
|
311365
312200
|
dependencies.core,
|
|
311366
312201
|
"Read API Spec",
|
|
311367
312202
|
async () => {
|
|
311368
312203
|
if (inputs.specPath) {
|
|
311369
312204
|
const workspaceRoot = path6.resolve(process.env.GITHUB_WORKSPACE ?? process.cwd());
|
|
311370
|
-
return (0,
|
|
312205
|
+
return (0, import_node_fs6.readFileSync)(path6.resolve(workspaceRoot, inputs.specPath), "utf8");
|
|
311371
312206
|
}
|
|
311372
312207
|
if (dependencies.specFetcher === fetch) {
|
|
311373
312208
|
return safeFetchText(inputs.specUrl, { depth: 0 });
|
|
@@ -311403,6 +312238,7 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311403
312238
|
};
|
|
311404
312239
|
const rootKey = inputs.specPath ? void 0 : normalizeRef(inputs.specUrl);
|
|
311405
312240
|
const loaderOptions = {
|
|
312241
|
+
preserveOas30TypeNull: Boolean(inputs.preserveOas30TypeNull),
|
|
311406
312242
|
fetchText: async (url, fetchOptions) => {
|
|
311407
312243
|
if (rootKey && normalizeRef(url) === rootKey) return rawSpecContent;
|
|
311408
312244
|
if (dependencies.specFetcher === fetch) return safeFetchText(url, fetchOptions);
|
|
@@ -311411,6 +312247,8 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311411
312247
|
};
|
|
311412
312248
|
const loaded = inputs.specPath ? await loadOpenApiContractSpecFromPath(inputs.specPath, loaderOptions) : await loadOpenApiContractSpec(inputs.specUrl, loaderOptions);
|
|
311413
312249
|
sourceSpecContent = loaded.content;
|
|
312250
|
+
sourceTypeNullPaths = loaded.sourceTypeNullPaths;
|
|
312251
|
+
preserveSourceSpecBytes = sourceTypeNullPaths.length > 0;
|
|
311414
312252
|
const document2 = normalizeSpecDocument(
|
|
311415
312253
|
loaded.bundledContent,
|
|
311416
312254
|
(msg) => dependencies.core.warning(msg)
|
|
@@ -311433,11 +312271,11 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311433
312271
|
`Unable to verify existing Spec Hub OpenAPI version for spec-id ${specId}; clear spec-id to create a fresh spec`
|
|
311434
312272
|
);
|
|
311435
312273
|
}
|
|
311436
|
-
previousSpecContent = normalizeSpecDocument(
|
|
312274
|
+
previousSpecContent = preserveSourceSpecBytes ? previousRaw : normalizeSpecDocument(
|
|
311437
312275
|
previousRaw,
|
|
311438
312276
|
(msg) => dependencies.core.warning(`Previous spec normalization: ${msg}`)
|
|
311439
312277
|
);
|
|
311440
|
-
previousSpecRollbackHash = (0,
|
|
312278
|
+
previousSpecRollbackHash = (0, import_node_crypto6.createHash)("sha256").update(previousSpecContent).digest("hex");
|
|
311441
312279
|
const existingSpecType = normalizeSpecTypeFromContent(previousSpecContent);
|
|
311442
312280
|
if (existingSpecType !== incomingSpecType) {
|
|
311443
312281
|
throw new Error(
|
|
@@ -311448,6 +312286,12 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311448
312286
|
dependencies.core.info(
|
|
311449
312287
|
`Auto-detected OpenAPI version from spec content: ${detectedOpenapiVersion}`
|
|
311450
312288
|
);
|
|
312289
|
+
if (preserveSourceSpecBytes) {
|
|
312290
|
+
dependencies.core.info(
|
|
312291
|
+
`Preserving original OpenAPI source bytes; accepted ${sourceTypeNullPaths.length} legacy type: null member(s) for internal validation`
|
|
312292
|
+
);
|
|
312293
|
+
return loaded.content;
|
|
312294
|
+
}
|
|
311451
312295
|
return document2;
|
|
311452
312296
|
}
|
|
311453
312297
|
);
|
|
@@ -311483,6 +312327,11 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311483
312327
|
`OpenAPI breaking-change check failed: ${breakingChangeResult.message || "breaking changes detected"}`
|
|
311484
312328
|
);
|
|
311485
312329
|
}
|
|
312330
|
+
const uploadSpecContent = embedSpecBranchMarker(
|
|
312331
|
+
specContent,
|
|
312332
|
+
branchDecision,
|
|
312333
|
+
inputs.repoUrl
|
|
312334
|
+
);
|
|
311486
312335
|
const provisioned = await provisionWorkspace(
|
|
311487
312336
|
inputs,
|
|
311488
312337
|
dependencies,
|
|
@@ -311607,10 +312456,17 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311607
312456
|
specId ? "Update Spec in Spec Hub" : "Upload Spec to Spec Hub",
|
|
311608
312457
|
async () => {
|
|
311609
312458
|
if (specId) {
|
|
311610
|
-
|
|
311611
|
-
|
|
311612
|
-
|
|
311613
|
-
|
|
312459
|
+
if (previousSpecContent !== void 0 && (0, import_node_crypto6.createHash)("sha256").update(uploadSpecContent).digest("hex") === (0, import_node_crypto6.createHash)("sha256").update(previousSpecContent).digest("hex")) {
|
|
312460
|
+
specContentUnchanged = true;
|
|
312461
|
+
dependencies.core.info(
|
|
312462
|
+
`Spec content unchanged (sha256 match); skipping Spec Hub update and version tag for ${specId}.`
|
|
312463
|
+
);
|
|
312464
|
+
} else {
|
|
312465
|
+
dependencies.core.info(
|
|
312466
|
+
`Updating existing spec ${specId} (detected version: ${detectedOpenapiVersion}). Note: the spec type (OPENAPI:3.0 / OPENAPI:3.1) is set at creation and cannot be changed on update. If you changed OpenAPI versions, clear the spec-id input to create a fresh spec.`
|
|
312467
|
+
);
|
|
312468
|
+
await dependencies.postman.updateSpec(specId, uploadSpecContent, workspaceId);
|
|
312469
|
+
}
|
|
311614
312470
|
} else {
|
|
311615
312471
|
specId = await dependencies.postman.uploadSpec(
|
|
311616
312472
|
workspaceId || "",
|
|
@@ -311618,7 +312474,7 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311618
312474
|
inputs,
|
|
311619
312475
|
inputs.specSyncMode === "version" ? releaseLabel : void 0
|
|
311620
312476
|
),
|
|
311621
|
-
|
|
312477
|
+
uploadSpecContent,
|
|
311622
312478
|
detectedOpenapiVersion
|
|
311623
312479
|
);
|
|
311624
312480
|
}
|
|
@@ -311635,8 +312491,9 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311635
312491
|
}
|
|
311636
312492
|
)
|
|
311637
312493
|
);
|
|
312494
|
+
outputs["spec-content-changed"] = isCanonicalWriter && !specContentUnchanged ? "true" : "false";
|
|
311638
312495
|
if (lintEnabled) {
|
|
311639
|
-
|
|
312496
|
+
let lintSummary = await runRollbackStage(
|
|
311640
312497
|
"Lint Spec via Postman CLI",
|
|
311641
312498
|
async () => runGroup(
|
|
311642
312499
|
dependencies.core,
|
|
@@ -311644,6 +312501,16 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311644
312501
|
async () => lintSpecViaCli(dependencies, workspaceId || "", outputs["spec-id"])
|
|
311645
312502
|
)
|
|
311646
312503
|
);
|
|
312504
|
+
if (preserveSourceSpecBytes) {
|
|
312505
|
+
const originalErrorCount = lintSummary.errors;
|
|
312506
|
+
lintSummary = applyOas30TypeNullLintCompatibility(lintSummary, sourceTypeNullPaths);
|
|
312507
|
+
const acceptedCount = originalErrorCount - lintSummary.errors;
|
|
312508
|
+
if (acceptedCount > 0) {
|
|
312509
|
+
dependencies.core.info(
|
|
312510
|
+
`Accepted ${acceptedCount} Postman CLI type: null finding(s) covered by preserve-oas30-type-null`
|
|
312511
|
+
);
|
|
312512
|
+
}
|
|
312513
|
+
}
|
|
311647
312514
|
outputs["lint-summary-json"] = JSON.stringify({
|
|
311648
312515
|
errors: lintSummary.errors,
|
|
311649
312516
|
total: lintSummary.violations.length,
|
|
@@ -311668,7 +312535,12 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311668
312535
|
});
|
|
311669
312536
|
dependencies.core.warning("lint skipped: governance errors not enforced (no postman-api-key)");
|
|
311670
312537
|
}
|
|
311671
|
-
|
|
312538
|
+
if (specContentUnchanged) {
|
|
312539
|
+
outputs["baseline-collection-id"] = baselineCollectionId || "";
|
|
312540
|
+
outputs["smoke-collection-id"] = smokeCollectionId || "";
|
|
312541
|
+
outputs["contract-collection-id"] = contractCollectionId || "";
|
|
312542
|
+
dependencies.core.info("Spec content unchanged; skipping collection regeneration and version finalization.");
|
|
312543
|
+
} else await runRollbackStage(
|
|
311672
312544
|
"Generate Collections from Spec",
|
|
311673
312545
|
async () => runGroup(
|
|
311674
312546
|
dependencies.core,
|
|
@@ -311707,10 +312579,11 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311707
312579
|
return;
|
|
311708
312580
|
}
|
|
311709
312581
|
}
|
|
312582
|
+
const effectivePrefix = branchDecision.tier === "channel" && branchDecision.channel ? channelAssetName(prefix, branchDecision.channel.code).trim() : prefix;
|
|
311710
312583
|
outputs[outputKey] = await dependencies.postman.generateCollection(
|
|
311711
312584
|
specId2,
|
|
311712
312585
|
assetProjectName,
|
|
311713
|
-
|
|
312586
|
+
effectivePrefix,
|
|
311714
312587
|
inputs.folderStrategy,
|
|
311715
312588
|
inputs.nestedFolderHierarchy,
|
|
311716
312589
|
inputs.requestNameSource
|
|
@@ -311731,6 +312604,32 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311731
312604
|
await ensureCollection(BASELINE_COLLECTION_PREFIX, baselineCollectionId, "baseline-collection-id");
|
|
311732
312605
|
await ensureCollection(SMOKE_COLLECTION_PREFIX, smokeCollectionId, "smoke-collection-id");
|
|
311733
312606
|
await ensureCollection(CONTRACT_COLLECTION_PREFIX, contractCollectionId, "contract-collection-id");
|
|
312607
|
+
if (dependencies.postman.adoptGeneratedCollection) {
|
|
312608
|
+
const reelect = async (prefix, outputKey) => {
|
|
312609
|
+
const effectivePrefix = branchDecision.tier === "channel" && branchDecision.channel ? channelAssetName(prefix, branchDecision.channel.code).trim() : prefix;
|
|
312610
|
+
const preferred = outputs[outputKey];
|
|
312611
|
+
if (!preferred) return;
|
|
312612
|
+
outputs[outputKey] = await dependencies.postman.adoptGeneratedCollection(
|
|
312613
|
+
specId2,
|
|
312614
|
+
assetProjectName,
|
|
312615
|
+
effectivePrefix,
|
|
312616
|
+
preferred
|
|
312617
|
+
);
|
|
312618
|
+
};
|
|
312619
|
+
await reelect(BASELINE_COLLECTION_PREFIX, "baseline-collection-id");
|
|
312620
|
+
await reelect(SMOKE_COLLECTION_PREFIX, "smoke-collection-id");
|
|
312621
|
+
await reelect(CONTRACT_COLLECTION_PREFIX, "contract-collection-id");
|
|
312622
|
+
}
|
|
312623
|
+
if (collectionBranchMarker) {
|
|
312624
|
+
if (!dependencies.postman.updateCollectionDescription) {
|
|
312625
|
+
throw new Error("Branch-scoped collections require updateCollectionDescription support");
|
|
312626
|
+
}
|
|
312627
|
+
await Promise.all([
|
|
312628
|
+
outputs["baseline-collection-id"],
|
|
312629
|
+
outputs["smoke-collection-id"],
|
|
312630
|
+
outputs["contract-collection-id"]
|
|
312631
|
+
].filter(Boolean).map((id) => dependencies.postman.updateCollectionDescription(id, collectionBranchMarker)));
|
|
312632
|
+
}
|
|
311734
312633
|
if (!dependencies.postman.injectContractTests) {
|
|
311735
312634
|
throw new Error(
|
|
311736
312635
|
"Dynamic contract tests require injectContractTests support from the access-token gateway client"
|
|
@@ -311833,6 +312732,12 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311833
312732
|
workspaceId: workspaceId || ""
|
|
311834
312733
|
});
|
|
311835
312734
|
for (const result of additionalResults) {
|
|
312735
|
+
if (collectionBranchMarker) {
|
|
312736
|
+
if (!dependencies.postman.updateCollectionDescription) {
|
|
312737
|
+
throw new Error("Branch-scoped collections require updateCollectionDescription support");
|
|
312738
|
+
}
|
|
312739
|
+
await dependencies.postman.updateCollectionDescription(result.collectionId, collectionBranchMarker);
|
|
312740
|
+
}
|
|
311836
312741
|
completedExternalSideEffects.push(
|
|
311837
312742
|
`${result.operation}AdditionalCollection(${result.collectionId} from ${result.displayPath})`
|
|
311838
312743
|
);
|
|
@@ -311908,6 +312813,53 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
311908
312813
|
}
|
|
311909
312814
|
return outputs;
|
|
311910
312815
|
}
|
|
312816
|
+
async function runGatedValidation(inputs, decision, actionCore) {
|
|
312817
|
+
actionCore.info(`branch-aware sync: gated run (${decision.reason}) \u2014 credential-free static validation, zero workspace writes`);
|
|
312818
|
+
const outputs = createPlannedOutputs(inputs);
|
|
312819
|
+
outputs["sync-status"] = "skipped-branch-gate";
|
|
312820
|
+
outputs["branch-decision"] = serializeBranchDecision(decision);
|
|
312821
|
+
let violations = [];
|
|
312822
|
+
let validated = false;
|
|
312823
|
+
try {
|
|
312824
|
+
let content;
|
|
312825
|
+
if (inputs.specPath) {
|
|
312826
|
+
content = (0, import_node_fs6.readFileSync)(inputs.specPath, "utf8");
|
|
312827
|
+
} else if (inputs.specUrl) {
|
|
312828
|
+
content = await safeFetchText(inputs.specUrl, { depth: 0 });
|
|
312829
|
+
}
|
|
312830
|
+
if (content) {
|
|
312831
|
+
const specType = detectSpecType(content, inputs.specPath);
|
|
312832
|
+
if (specType === "openapi") {
|
|
312833
|
+
const document2 = parseOpenApiDocument(content);
|
|
312834
|
+
const index = buildContractIndex(document2);
|
|
312835
|
+
violations = index.warnings;
|
|
312836
|
+
validated = true;
|
|
312837
|
+
} else {
|
|
312838
|
+
actionCore.info(`branch gate: static lint for spec type ${specType} runs through its protocol builder on publish; parse-only gate applied`);
|
|
312839
|
+
validated = true;
|
|
312840
|
+
}
|
|
312841
|
+
} else {
|
|
312842
|
+
actionCore.info("branch gate: no spec-url/spec-path provided; nothing to validate");
|
|
312843
|
+
}
|
|
312844
|
+
} catch (error) {
|
|
312845
|
+
throw new Error(
|
|
312846
|
+
`branch gate: static validation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
312847
|
+
{ cause: error }
|
|
312848
|
+
);
|
|
312849
|
+
}
|
|
312850
|
+
outputs["lint-summary-json"] = JSON.stringify({
|
|
312851
|
+
status: validated ? "static-only" : "skipped",
|
|
312852
|
+
reason: "branch-gated run: governance lint requires upload and runs on publish/preview syncs",
|
|
312853
|
+
errors: 0,
|
|
312854
|
+
warnings: violations.length,
|
|
312855
|
+
total: violations.length,
|
|
312856
|
+
violations: violations.map((issue2) => ({ issue: issue2, severity: "WARNING" }))
|
|
312857
|
+
});
|
|
312858
|
+
for (const [name, value] of Object.entries(outputs)) {
|
|
312859
|
+
actionCore.setOutput(name, value);
|
|
312860
|
+
}
|
|
312861
|
+
return outputs;
|
|
312862
|
+
}
|
|
311911
312863
|
function createRoutingPostmanClient(options) {
|
|
311912
312864
|
const { gateway } = options;
|
|
311913
312865
|
const requireAccessToken = (operation) => async () => {
|
|
@@ -311925,6 +312877,7 @@ function createRoutingPostmanClient(options) {
|
|
|
311925
312877
|
updateSpec: requireAccessToken("updateSpec"),
|
|
311926
312878
|
getSpecContent: requireAccessToken("getSpecContent"),
|
|
311927
312879
|
generateCollection: requireAccessToken("generateCollection"),
|
|
312880
|
+
adoptGeneratedCollection: requireAccessToken("adoptGeneratedCollection"),
|
|
311928
312881
|
createWorkspace: requireAccessToken("createWorkspace"),
|
|
311929
312882
|
getWorkspaceVisibility: requireAccessToken("getWorkspaceVisibility"),
|
|
311930
312883
|
getWorkspaceGitRepoUrl: requireAccessToken("getWorkspaceGitRepoUrl"),
|
|
@@ -311934,10 +312887,13 @@ function createRoutingPostmanClient(options) {
|
|
|
311934
312887
|
inviteRequesterToWorkspace: requireAccessToken("inviteRequesterToWorkspace"),
|
|
311935
312888
|
injectTests: requireAccessToken("injectTests"),
|
|
311936
312889
|
tagCollection: requireAccessToken("tagCollection"),
|
|
312890
|
+
tagSpecVersion: requireAccessToken("tagSpecVersion"),
|
|
312891
|
+
listSpecVersionTags: requireAccessToken("listSpecVersionTags"),
|
|
311937
312892
|
deleteCollection: requireAccessToken("deleteCollection"),
|
|
311938
312893
|
injectContractTests: requireAccessToken("injectContractTests"),
|
|
311939
312894
|
createCollection: requireAccessToken("createCollection"),
|
|
311940
|
-
updateCollection: requireAccessToken("updateCollection")
|
|
312895
|
+
updateCollection: requireAccessToken("updateCollection"),
|
|
312896
|
+
updateCollectionDescription: requireAccessToken("updateCollectionDescription")
|
|
311941
312897
|
};
|
|
311942
312898
|
}
|
|
311943
312899
|
return {
|
|
@@ -311949,6 +312905,7 @@ function createRoutingPostmanClient(options) {
|
|
|
311949
312905
|
// not a reason to reach for the API key.
|
|
311950
312906
|
uploadSpec: (workspaceId, projectName, specContent, openapiVersion) => gateway.uploadSpec(workspaceId, projectName, specContent, openapiVersion ?? "3.0"),
|
|
311951
312907
|
generateCollection: (specId, projectName, prefix, folderStrategy, nestedFolderHierarchy, requestNameSource) => gateway.generateCollection(specId, projectName, prefix, folderStrategy, nestedFolderHierarchy, requestNameSource),
|
|
312908
|
+
adoptGeneratedCollection: (specId, projectName, prefix, preferredId) => gateway.adoptGeneratedCollection(specId, projectName, prefix, preferredId),
|
|
311952
312909
|
updateSpec: (specId, specContent, workspaceId) => gateway.updateSpec(specId, specContent, workspaceId),
|
|
311953
312910
|
getSpecContent: (specId) => gateway.getSpecContent(specId),
|
|
311954
312911
|
createWorkspace: (name, about, targetTeamId) => gateway.createWorkspace(name, about, targetTeamId),
|
|
@@ -311960,6 +312917,8 @@ function createRoutingPostmanClient(options) {
|
|
|
311960
312917
|
// + tagging surfaces (live-proven). PMAK is reserved for token minting, so
|
|
311961
312918
|
// these never fall back to the API key even when one is present.
|
|
311962
312919
|
injectTests: (collectionId, type) => gateway.injectTests(collectionId, type),
|
|
312920
|
+
tagSpecVersion: (specId, name) => gateway.tagSpecVersion(specId, name),
|
|
312921
|
+
listSpecVersionTags: (specId) => gateway.listSpecVersionTags(specId),
|
|
311963
312922
|
tagCollection: (collectionId, tags) => gateway.tagCollection(collectionId, tags),
|
|
311964
312923
|
// Sub-team (squad) enumeration over the gateway `ums` service. Access-token
|
|
311965
312924
|
// only — never PMAK — so org-mode detection no longer needs a PMAK GET /teams.
|
|
@@ -311977,7 +312936,8 @@ function createRoutingPostmanClient(options) {
|
|
|
311977
312936
|
// so no asset op ever reaches for the API key.
|
|
311978
312937
|
injectContractTests: (collectionUid, index) => gateway.injectContractTests(collectionUid, index),
|
|
311979
312938
|
createCollection: (workspaceId, collection, options2) => gateway.createCollection(workspaceId, collection, options2),
|
|
311980
|
-
updateCollection: (collectionUid, collection) => gateway.updateCollection(collectionUid, collection)
|
|
312939
|
+
updateCollection: (collectionUid, collection) => gateway.updateCollection(collectionUid, collection),
|
|
312940
|
+
updateCollectionDescription: (collectionUid, description) => gateway.updateCollectionDescription(collectionUid, description)
|
|
311981
312941
|
};
|
|
311982
312942
|
}
|
|
311983
312943
|
function createBootstrapDependencies(inputs, factories, orgMode = false) {
|
|
@@ -312080,7 +313040,7 @@ function resolvePackageVersion() {
|
|
|
312080
313040
|
candidates.push(import_node_path5.default.join(process.cwd(), "package.json"));
|
|
312081
313041
|
for (const packageJsonPath of candidates) {
|
|
312082
313042
|
try {
|
|
312083
|
-
const packageJson = JSON.parse((0,
|
|
313043
|
+
const packageJson = JSON.parse((0, import_node_fs7.readFileSync)(packageJsonPath, "utf8"));
|
|
312084
313044
|
if (packageJson.name === "@postman-cse/onboarding-bootstrap" && packageJson.version) {
|
|
312085
313045
|
return String(packageJson.version).trim();
|
|
312086
313046
|
}
|
|
@@ -312131,6 +313091,9 @@ var cliInputNames = [
|
|
|
312131
313091
|
"postman-api-key",
|
|
312132
313092
|
"postman-access-token",
|
|
312133
313093
|
"credential-preflight",
|
|
313094
|
+
"branch-strategy",
|
|
313095
|
+
"canonical-branch",
|
|
313096
|
+
"channels",
|
|
312134
313097
|
"workspace-id",
|
|
312135
313098
|
"spec-id",
|
|
312136
313099
|
"baseline-collection-id",
|
|
@@ -312156,6 +313119,7 @@ var cliInputNames = [
|
|
|
312156
313119
|
"workspace-team-id",
|
|
312157
313120
|
"repo-url",
|
|
312158
313121
|
"openapi-version",
|
|
313122
|
+
"preserve-oas30-type-null",
|
|
312159
313123
|
"breaking-change-mode",
|
|
312160
313124
|
"breaking-baseline-spec-path",
|
|
312161
313125
|
"breaking-rules-path",
|
|
@@ -312292,11 +313256,11 @@ function nearestExistingPath2(candidate) {
|
|
|
312292
313256
|
return current;
|
|
312293
313257
|
}
|
|
312294
313258
|
function pathExists(candidate) {
|
|
312295
|
-
if ((0,
|
|
313259
|
+
if ((0, import_node_fs7.existsSync)(candidate)) {
|
|
312296
313260
|
return true;
|
|
312297
313261
|
}
|
|
312298
313262
|
try {
|
|
312299
|
-
(0,
|
|
313263
|
+
(0, import_node_fs7.lstatSync)(candidate);
|
|
312300
313264
|
return true;
|
|
312301
313265
|
} catch {
|
|
312302
313266
|
return false;
|
|
@@ -312304,10 +313268,10 @@ function pathExists(candidate) {
|
|
|
312304
313268
|
}
|
|
312305
313269
|
function checkedRealPath(existingPath, workspaceRealPath) {
|
|
312306
313270
|
try {
|
|
312307
|
-
return (0,
|
|
313271
|
+
return (0, import_node_fs7.realpathSync)(existingPath);
|
|
312308
313272
|
} catch (error) {
|
|
312309
|
-
if ((0,
|
|
312310
|
-
const linkTarget = (0,
|
|
313273
|
+
if ((0, import_node_fs7.lstatSync)(existingPath).isSymbolicLink()) {
|
|
313274
|
+
const linkTarget = (0, import_node_fs7.readlinkSync)(existingPath);
|
|
312311
313275
|
const resolvedTarget = import_node_path5.default.resolve(import_node_path5.default.dirname(existingPath), linkTarget);
|
|
312312
313276
|
ensureInsideWorkspace(workspaceRealPath, resolvedTarget);
|
|
312313
313277
|
}
|
|
@@ -312319,7 +313283,7 @@ function assertOutputFileAllowed2(filePath) {
|
|
|
312319
313283
|
return void 0;
|
|
312320
313284
|
}
|
|
312321
313285
|
const workspaceRoot = import_node_path5.default.resolve(process.cwd());
|
|
312322
|
-
const workspaceRealPath = (0,
|
|
313286
|
+
const workspaceRealPath = (0, import_node_fs7.realpathSync)(workspaceRoot);
|
|
312323
313287
|
const resolved = import_node_path5.default.isAbsolute(filePath) ? import_node_path5.default.resolve(filePath) : import_node_path5.default.resolve(workspaceRoot, filePath);
|
|
312324
313288
|
const existingPath = nearestExistingPath2(resolved);
|
|
312325
313289
|
ensureInsideWorkspace(workspaceRealPath, checkedRealPath(existingPath, workspaceRealPath));
|
|
@@ -312331,7 +313295,7 @@ async function writeOptionalFile(filePath, content) {
|
|
|
312331
313295
|
return;
|
|
312332
313296
|
}
|
|
312333
313297
|
await (0, import_promises4.mkdir)(import_node_path5.default.dirname(resolved), { recursive: true });
|
|
312334
|
-
ensureInsideWorkspace((0,
|
|
313298
|
+
ensureInsideWorkspace((0, import_node_fs7.realpathSync)(import_node_path5.default.resolve(process.cwd())), (0, import_node_fs7.realpathSync)(import_node_path5.default.dirname(resolved)));
|
|
312335
313299
|
await (0, import_promises4.writeFile)(resolved, content, "utf8");
|
|
312336
313300
|
}
|
|
312337
313301
|
function requireCliInput(name, value) {
|
|
@@ -312339,7 +313303,7 @@ function requireCliInput(name, value) {
|
|
|
312339
313303
|
throw new Error(`${name} is required`);
|
|
312340
313304
|
}
|
|
312341
313305
|
}
|
|
312342
|
-
function validateCliInputs(inputs) {
|
|
313306
|
+
function validateCliInputs(inputs, options = {}) {
|
|
312343
313307
|
requireCliInput("project-name", inputs.projectName);
|
|
312344
313308
|
if (!inputs.specUrl && !inputs.specPath) {
|
|
312345
313309
|
throw new Error("One of spec-url or spec-path is required");
|
|
@@ -312347,7 +313311,7 @@ function validateCliInputs(inputs) {
|
|
|
312347
313311
|
if (inputs.specUrl && inputs.specPath) {
|
|
312348
313312
|
throw new Error("Provide either spec-url or spec-path, not both.");
|
|
312349
313313
|
}
|
|
312350
|
-
if (!inputs.postmanApiKey && !inputs.postmanAccessToken) {
|
|
313314
|
+
if (options.requireCredentials !== false && !inputs.postmanApiKey && !inputs.postmanAccessToken) {
|
|
312351
313315
|
throw new Error("One of postman-api-key or postman-access-token is required.");
|
|
312352
313316
|
}
|
|
312353
313317
|
}
|
|
@@ -312368,9 +313332,26 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
312368
313332
|
const env = runtime.env ?? process.env;
|
|
312369
313333
|
const config = parseCliArgs(argv, env);
|
|
312370
313334
|
const inputs = resolveInputs(config.inputEnv);
|
|
312371
|
-
|
|
313335
|
+
const branchDecision = decideBranchTier(inputs, config.inputEnv);
|
|
313336
|
+
validateCliInputs(inputs, { requireCredentials: branchDecision.tier !== "gated" });
|
|
312372
313337
|
assertOutputFileAllowed2(config.resultJsonPath);
|
|
312373
313338
|
assertOutputFileAllowed2(config.dotenvPath);
|
|
313339
|
+
if (branchDecision.tier === "gated") {
|
|
313340
|
+
const gatedReporter = new ConsoleReporter();
|
|
313341
|
+
const gated = await runGatedValidation(inputs, branchDecision, {
|
|
313342
|
+
info: (m) => gatedReporter.info(m),
|
|
313343
|
+
warning: (m) => gatedReporter.warning(m),
|
|
313344
|
+
setOutput: () => void 0
|
|
313345
|
+
});
|
|
313346
|
+
await writeOptionalFile(config.resultJsonPath, JSON.stringify(gated, null, 2));
|
|
313347
|
+
await writeOptionalFile(config.dotenvPath, toDotenv(gated));
|
|
313348
|
+
writeStdout(`${JSON.stringify(gated, null, 2)}
|
|
313349
|
+
`);
|
|
313350
|
+
return;
|
|
313351
|
+
}
|
|
313352
|
+
if (branchDecision.tier !== "legacy") {
|
|
313353
|
+
process.env[BRANCH_DECISION_ENV] = serializeBranchDecision(branchDecision);
|
|
313354
|
+
}
|
|
312374
313355
|
const mintReporter = new ConsoleReporter();
|
|
312375
313356
|
await mintAccessTokenIfNeeded2(inputs, mintReporter);
|
|
312376
313357
|
const dependencies = createCliDependencies(inputs);
|
|
@@ -312403,7 +313384,7 @@ function isEntrypoint(currentPath, entrypointPath) {
|
|
|
312403
313384
|
return false;
|
|
312404
313385
|
}
|
|
312405
313386
|
try {
|
|
312406
|
-
return (0,
|
|
313387
|
+
return (0, import_node_fs7.realpathSync)(currentPath) === (0, import_node_fs7.realpathSync)(entrypointPath);
|
|
312407
313388
|
} catch {
|
|
312408
313389
|
return import_node_path5.default.resolve(currentPath) === import_node_path5.default.resolve(entrypointPath);
|
|
312409
313390
|
}
|