@postman-cse/onboarding-bootstrap 0.14.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/action.cjs CHANGED
@@ -46776,6 +46776,12 @@ var customerPreviewActionContract = {
46776
46776
  description: "Postman access token used for governance and workspace mutations.",
46777
46777
  required: false
46778
46778
  },
46779
+ "credential-preflight": {
46780
+ description: "Credential identity preflight policy. warn (default) logs a note and continues when postman-api-key and postman-access-token resolve to different parent orgs; enforce fails the run on that condition before any workspace is created; off skips the identity probes entirely (the reactive error guidance still applies). Promotion of the default to enforce is planned once the live e2e legs prove both directions.",
46781
+ required: false,
46782
+ default: "warn",
46783
+ allowedValues: ["enforce", "warn", "off"]
46784
+ },
46779
46785
  "integration-backend": {
46780
46786
  description: "Integration backend for downstream workspace connectivity.",
46781
46787
  required: false,
@@ -47799,13 +47805,15 @@ var POSTMAN_ENDPOINT_PROFILES = {
47799
47805
  apiBaseUrl: "https://api.getpostman.com",
47800
47806
  bifrostBaseUrl: "https://bifrost-premium-https-v4.gw.postman.com",
47801
47807
  cliInstallUrl: "https://dl-cli.pstmn.io/install/unix.sh",
47802
- gatewayBaseUrl: "https://gateway.postman.com"
47808
+ gatewayBaseUrl: "https://gateway.postman.com",
47809
+ iapubBaseUrl: "https://iapub.postman.co"
47803
47810
  },
47804
47811
  beta: {
47805
47812
  apiBaseUrl: "https://api.getpostman-beta.com",
47806
47813
  bifrostBaseUrl: "https://bifrost-https-v4.gw.postman-beta.com",
47807
47814
  cliInstallUrl: "https://dl-cli.pstmn-beta.io/install/unix.sh",
47808
- gatewayBaseUrl: "https://gateway.postman-beta.com"
47815
+ gatewayBaseUrl: "https://gateway.postman-beta.com",
47816
+ iapubBaseUrl: "https://iapub.postman.co"
47809
47817
  }
47810
47818
  };
47811
47819
  function parsePostmanStack(value) {
@@ -47819,6 +47827,311 @@ function resolvePostmanEndpointProfile(stack) {
47819
47827
  return POSTMAN_ENDPOINT_PROFILES[stack];
47820
47828
  }
47821
47829
 
47830
+ // src/lib/postman/credential-identity.ts
47831
+ var sessionPath = "/api/sessions/current";
47832
+ var pmakMemo = /* @__PURE__ */ new Map();
47833
+ var sessionMemo = /* @__PURE__ */ new Map();
47834
+ var memoizedSessionIdentity;
47835
+ function getMemoizedSessionIdentity() {
47836
+ return memoizedSessionIdentity;
47837
+ }
47838
+ function asRecord(value) {
47839
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
47840
+ return void 0;
47841
+ }
47842
+ return value;
47843
+ }
47844
+ function coerceId(raw) {
47845
+ return raw ? String(raw) : void 0;
47846
+ }
47847
+ function coerceText(raw) {
47848
+ if (typeof raw !== "string") {
47849
+ return void 0;
47850
+ }
47851
+ const trimmed = raw.trim();
47852
+ return trimmed ? trimmed : void 0;
47853
+ }
47854
+ function normalizeBaseUrl(raw) {
47855
+ return String(raw || "").replace(/\/+$/, "");
47856
+ }
47857
+ async function resolvePmakIdentity(opts) {
47858
+ const apiKey = String(opts.apiKey || "").trim();
47859
+ if (!apiKey) {
47860
+ return void 0;
47861
+ }
47862
+ const baseUrl = normalizeBaseUrl(opts.apiBaseUrl);
47863
+ const memoKey = `${baseUrl}::${apiKey}`;
47864
+ let pending = pmakMemo.get(memoKey);
47865
+ if (!pending) {
47866
+ pending = probePmakIdentity(baseUrl, apiKey, opts.fetchImpl ?? fetch);
47867
+ pmakMemo.set(memoKey, pending);
47868
+ }
47869
+ return pending;
47870
+ }
47871
+ async function probePmakIdentity(baseUrl, apiKey, fetchImpl) {
47872
+ try {
47873
+ const response = await fetchImpl(`${baseUrl}/me`, {
47874
+ method: "GET",
47875
+ headers: { "X-Api-Key": apiKey }
47876
+ });
47877
+ if (!response.ok) {
47878
+ return void 0;
47879
+ }
47880
+ const payload = asRecord(await response.json());
47881
+ const user = asRecord(payload?.user);
47882
+ if (!user) {
47883
+ return void 0;
47884
+ }
47885
+ return {
47886
+ source: "pmak/me",
47887
+ userId: coerceId(user.id),
47888
+ fullName: coerceText(user.fullName) ?? coerceText(user.username),
47889
+ teamId: coerceId(user.teamId),
47890
+ teamName: coerceText(user.teamName),
47891
+ teamDomain: coerceText(user.teamDomain)
47892
+ };
47893
+ } catch {
47894
+ return void 0;
47895
+ }
47896
+ }
47897
+ async function resolveSessionIdentity(opts) {
47898
+ const accessToken = String(opts.accessToken || "").trim();
47899
+ if (!accessToken) {
47900
+ return void 0;
47901
+ }
47902
+ const baseUrl = normalizeBaseUrl(opts.iapubBaseUrl);
47903
+ const memoKey = `${baseUrl}::${accessToken}`;
47904
+ let pending = sessionMemo.get(memoKey);
47905
+ if (!pending) {
47906
+ pending = probeSessionIdentity(baseUrl, accessToken, opts.fetchImpl ?? fetch);
47907
+ sessionMemo.set(memoKey, pending);
47908
+ }
47909
+ return pending;
47910
+ }
47911
+ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl) {
47912
+ try {
47913
+ const response = await fetchImpl(`${baseUrl}${sessionPath}`, {
47914
+ method: "GET",
47915
+ headers: { "x-access-token": accessToken }
47916
+ });
47917
+ if (!response.ok) {
47918
+ return void 0;
47919
+ }
47920
+ const payload = asRecord(await response.json());
47921
+ if (!payload) {
47922
+ return void 0;
47923
+ }
47924
+ const identity = asRecord(payload.identity);
47925
+ const data = asRecord(payload.data);
47926
+ const user = asRecord(data?.user);
47927
+ const roleEntries = Array.isArray(user?.roles) ? user.roles.map((entry) => coerceText(entry) ?? coerceId(entry)).filter((entry) => Boolean(entry)) : [];
47928
+ const singleRole = coerceText(user?.role);
47929
+ const roles = roleEntries.length > 0 ? roleEntries : singleRole ? [singleRole] : void 0;
47930
+ const resolved = {
47931
+ source: "iapub/sessions",
47932
+ userId: coerceId(user?.id),
47933
+ fullName: coerceText(user?.fullName) ?? coerceText(user?.name) ?? coerceText(user?.username),
47934
+ teamId: coerceId(identity?.team),
47935
+ teamDomain: coerceText(identity?.domain),
47936
+ ...roles ? { roles } : {},
47937
+ consumerType: coerceText(payload.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
47938
+ };
47939
+ memoizedSessionIdentity = resolved;
47940
+ return resolved;
47941
+ } catch {
47942
+ return void 0;
47943
+ }
47944
+ }
47945
+ function describeTeam(id) {
47946
+ const label = id?.teamName ?? id?.teamDomain;
47947
+ return `team ${id?.teamId ?? "unresolved"}${label ? ` (${label})` : ""}`;
47948
+ }
47949
+ function formatIdentityLine(id, mask) {
47950
+ const teamPart = id.teamId ? describeTeam(id) : "team unresolved";
47951
+ const domainPart = id.teamDomain ? `, domain ${id.teamDomain}` : "";
47952
+ if (id.source === "pmak/me") {
47953
+ const userPart = id.userId ? `user ${id.userId}${id.fullName ? ` (${id.fullName})` : ""}, ` : "";
47954
+ return mask(`postman: PMAK identity - ${userPart}${teamPart}${domainPart}`);
47955
+ }
47956
+ return mask(
47957
+ `postman: access-token session identity - ${teamPart}${domainPart} [source: iapub/sessions]`
47958
+ );
47959
+ }
47960
+ function crossCheckIdentities(args) {
47961
+ if (args.mode === "off") {
47962
+ return { ok: true, level: "ok", message: "" };
47963
+ }
47964
+ const pmakTeamId = args.pmak?.teamId;
47965
+ const sessionTeamId = args.session?.teamId;
47966
+ if (pmakTeamId && sessionTeamId && pmakTeamId !== sessionTeamId) {
47967
+ const level = args.mode === "enforce" ? "fail" : "note";
47968
+ const lead = level === "fail" ? "credential preflight FAILED" : "credential preflight note";
47969
+ const fix = level === "fail" ? "Use one credential pair from a single parent org: re-mint the access token from the same parent org as postman-api-key (postman-resolve-service-token-action, or POST https://api.getpostman.com/service-account-tokens with that team's PMAK), or set postman-api-key to the matching parent org." : "Use one credential pair from a single parent org. Set credential-preflight: enforce to fail the run on this condition.";
47970
+ return {
47971
+ ok: false,
47972
+ level,
47973
+ message: args.mask(
47974
+ `postman: ${lead} - PMAK belongs to ${describeTeam(args.pmak)} but the access token's session belongs to a different parent org, ${describeTeam(args.session)}. Assets would be created against one team while Bifrost linking and governance act under the other, producing duplicate-link 400s and workspaces not visible to the other credential. ` + fix
47975
+ )
47976
+ };
47977
+ }
47978
+ if (pmakTeamId && sessionTeamId) {
47979
+ const scope = args.workspaceTeamId || args.explicitTeamId ? "parent org team" : "team";
47980
+ const label = args.pmak?.teamName ?? args.pmak?.teamDomain ?? args.session?.teamName ?? args.session?.teamDomain;
47981
+ return {
47982
+ ok: true,
47983
+ level: "ok",
47984
+ message: args.mask(
47985
+ `postman: credential preflight OK - PMAK and access token both resolve to ${scope} ${pmakTeamId}${label ? ` (${label})` : ""}`
47986
+ )
47987
+ };
47988
+ }
47989
+ const missing = [
47990
+ !pmakTeamId ? "PMAK identity" : void 0,
47991
+ !sessionTeamId ? "access-token session identity" : void 0
47992
+ ].filter(Boolean).join(" and ");
47993
+ return {
47994
+ ok: false,
47995
+ level: "note",
47996
+ message: args.mask(
47997
+ `postman: credential preflight note - cross-check skipped because the ${missing} did not resolve a team id; continuing with reactive error guidance only`
47998
+ )
47999
+ };
48000
+ }
48001
+ async function runCredentialPreflight(args) {
48002
+ if (args.mode === "off") {
48003
+ return;
48004
+ }
48005
+ const mask = args.mask;
48006
+ const apiKey = String(args.postmanApiKey || "").trim();
48007
+ const accessToken = String(args.postmanAccessToken || "").trim();
48008
+ let pmak;
48009
+ if (apiKey) {
48010
+ try {
48011
+ pmak = await resolvePmakIdentity({
48012
+ apiBaseUrl: args.apiBaseUrl,
48013
+ apiKey,
48014
+ fetchImpl: args.fetchImpl
48015
+ });
48016
+ } catch (error2) {
48017
+ args.log.warning(
48018
+ mask(
48019
+ `postman: credential preflight could not resolve PMAK identity: ${error2 instanceof Error ? error2.message : String(error2)}`
48020
+ )
48021
+ );
48022
+ }
48023
+ if (pmak) {
48024
+ args.log.info(formatIdentityLine(pmak, mask));
48025
+ } else {
48026
+ args.log.warning(
48027
+ mask("postman: credential preflight could not resolve PMAK identity from GET /me; continuing")
48028
+ );
48029
+ }
48030
+ }
48031
+ if (!accessToken) {
48032
+ args.log.info(mask("postman: Bifrost diagnostics limited: no access token"));
48033
+ return;
48034
+ }
48035
+ let session;
48036
+ try {
48037
+ session = await resolveSessionIdentity({
48038
+ iapubBaseUrl: args.iapubBaseUrl,
48039
+ accessToken,
48040
+ fetchImpl: args.fetchImpl
48041
+ });
48042
+ } catch (error2) {
48043
+ args.log.warning(
48044
+ mask(
48045
+ `postman: credential preflight could not resolve access-token session identity: ${error2 instanceof Error ? error2.message : String(error2)}`
48046
+ )
48047
+ );
48048
+ }
48049
+ if (session) {
48050
+ args.log.info(formatIdentityLine(session, mask));
48051
+ } else {
48052
+ args.log.warning(
48053
+ mask(
48054
+ "postman: credential preflight could not resolve the access-token session identity from iapub; continuing with reactive error guidance only"
48055
+ )
48056
+ );
48057
+ }
48058
+ const result = crossCheckIdentities({
48059
+ pmak,
48060
+ session,
48061
+ workspaceTeamId: args.workspaceTeamId,
48062
+ explicitTeamId: args.explicitTeamId,
48063
+ mode: args.mode,
48064
+ mask
48065
+ });
48066
+ if (!result.message) {
48067
+ return;
48068
+ }
48069
+ if (result.level === "fail") {
48070
+ throw new Error(result.message);
48071
+ }
48072
+ if (result.level === "note") {
48073
+ args.log.warning(result.message);
48074
+ return;
48075
+ }
48076
+ args.log.info(result.message);
48077
+ }
48078
+
48079
+ // src/lib/postman/error-advice.ts
48080
+ var WORKSPACE_PERSONAL_ONLY_ADVICE = "Workspace creation failed: This may be an Org-mode account that requires a workspace-team-id input. The Postman API does not allow creating team workspaces at the organization level. Use the workspace-team-id input to specify which sub-team should own this workspace.";
48081
+ function workspaceTeamIdUnauthorizedAdvice(targetTeamId) {
48082
+ return `The workspace-team-id input (${targetTeamId}) was rejected as unauthorized by the Postman API. In org-mode accounts it must be the numeric id of a sub-team this API key can access; GET https://api.getpostman.com/teams lists the available sub-teams. Fix the workspace-team-id value and re-run.`;
48083
+ }
48084
+ function adviseFromWorkspaceCreateError(err, targetTeamId) {
48085
+ if (err.message.includes("Only personal workspaces")) {
48086
+ return new Error(WORKSPACE_PERSONAL_ONLY_ADVICE, { cause: err });
48087
+ }
48088
+ if (targetTeamId != null && err.message.includes("You are not authorized to perform this action")) {
48089
+ return new Error(workspaceTeamIdUnauthorizedAdvice(targetTeamId), { cause: err });
48090
+ }
48091
+ return void 0;
48092
+ }
48093
+ function expiryAdvice(code) {
48094
+ return `postman: Bifrost rejected the access token (${code}). Service-account access tokens expire after about 1 to 1.5 hours; this run likely outlived its token. Re-mint a fresh token (postman-resolve-service-token-action, or POST https://api.getpostman.com/service-account-tokens) and re-run. If it was just minted, confirm postman-access-token is the token for the same parent org as postman-api-key.`;
48095
+ }
48096
+ function forbiddenAdvice(ctx) {
48097
+ const sessionDetail = ctx.sessionTeamId ? ` while the access token is valid (it resolved to team ${ctx.sessionTeamId}${ctx.sessionRoles && ctx.sessionRoles.length > 0 ? `, roles [${ctx.sessionRoles.join(", ")}]` : ""}${ctx.sessionConsumerType ? `, consumerType ${ctx.sessionConsumerType}` : ""} at preflight)` : "";
48098
+ const scopedTeamId = ctx.workspaceTeamId || ctx.explicitTeamId;
48099
+ const teamClause = scopedTeamId ? `, or workspace-team-id ${scopedTeamId} names a sub-team it cannot act in` : ", or the workspace-team-id / POSTMAN_TEAM_ID in use names a sub-team it cannot act in";
48100
+ return `postman: Bifrost refused ${ctx.operation || "this operation"} with 403${sessionDetail}. The token's identity lacks permission for this endpoint${teamClause}. Verify the token's role and that workspace-team-id / POSTMAN_TEAM_ID matches a sub-team from GET https://api.getpostman.com/teams.`;
48101
+ }
48102
+ function buildAdvice(status, body, ctx) {
48103
+ if (body.includes("UNAUTHENTICATED")) {
48104
+ return expiryAdvice("UNAUTHENTICATED");
48105
+ }
48106
+ if (body.includes("authenticationError")) {
48107
+ return expiryAdvice("authenticationError");
48108
+ }
48109
+ if (body.includes("Only personal workspaces")) {
48110
+ return WORKSPACE_PERSONAL_ONLY_ADVICE;
48111
+ }
48112
+ if (body.includes("projectAlreadyConnected")) {
48113
+ return `postman: ${ctx.operation || "this operation"} reports projectAlreadyConnected with no workspace id in the error body. The repository is already linked to a workspace this credential cannot see, usually one created by a different credential pair or sub-team. Delete the stale link or its workspace, then re-run with one credential pair from a single parent org.`;
48114
+ }
48115
+ if (body.includes("invalidParamError") && body.includes("already exists")) {
48116
+ return `postman: ${ctx.operation || "this operation"} hit a duplicate resource error (invalidParamError: already exists). A matching resource already exists, possibly under another credential pair or sub-team where this credential cannot see it. Identify which workspace holds the existing resource and re-run with one credential pair from a single parent org.`;
48117
+ }
48118
+ if (body.includes("Team feature is not available for your organization")) {
48119
+ return `postman: ${ctx.operation || "this operation"} failed because the team feature is not available for this organization. The credential belongs to an account whose plan lacks team features; use credentials from the intended team and confirm the plan supports this operation.`;
48120
+ }
48121
+ if (body.includes("You are not authorized to perform this action") || status === 403 && ctx.hasAccessToken) {
48122
+ return forbiddenAdvice(ctx);
48123
+ }
48124
+ return void 0;
48125
+ }
48126
+ function adviseFromHttpError(err, ctx) {
48127
+ const body = err.responseBody || err.message || "";
48128
+ const advice = buildAdvice(err.status, body, ctx);
48129
+ if (!advice) {
48130
+ return void 0;
48131
+ }
48132
+ return new Error(ctx.mask(advice), { cause: err });
48133
+ }
48134
+
47822
48135
  // src/lib/retry.ts
47823
48136
  function sleep(delayMs) {
47824
48137
  return new Promise((resolve4) => {
@@ -47867,7 +48180,7 @@ async function retry(operation, options = {}) {
47867
48180
  }
47868
48181
 
47869
48182
  // src/lib/postman/postman-assets-client.ts
47870
- function asRecord(value) {
48183
+ function asRecord2(value) {
47871
48184
  if (!value || typeof value !== "object" || Array.isArray(value)) {
47872
48185
  return null;
47873
48186
  }
@@ -47875,8 +48188,8 @@ function asRecord(value) {
47875
48188
  }
47876
48189
  function extractWorkspacesPage(data) {
47877
48190
  const workspaces = Array.isArray(data?.workspaces) ? data.workspaces : [];
47878
- const meta = asRecord(data?.meta);
47879
- const pagination = asRecord(data?.pagination);
48191
+ const meta = asRecord2(data?.meta);
48192
+ const pagination = asRecord2(data?.pagination);
47880
48193
  const nextCursor = String(
47881
48194
  data?.nextCursor ?? data?.next_cursor ?? meta?.nextCursor ?? meta?.next_cursor ?? pagination?.nextCursor ?? pagination?.next_cursor ?? ""
47882
48195
  ).trim() || void 0;
@@ -47968,7 +48281,7 @@ var PostmanAssetsClient = class {
47968
48281
  async getTeams() {
47969
48282
  const data = await this.request("/teams");
47970
48283
  const teams = data?.data ?? [];
47971
- return Array.isArray(teams) ? teams.map((entry) => asRecord(entry)).filter((team) => Boolean(team?.id && team?.name)).map((team) => ({
48284
+ return Array.isArray(teams) ? teams.map((entry) => asRecord2(entry)).filter((team) => Boolean(team?.id && team?.name)).map((team) => ({
47972
48285
  id: Number(team.id),
47973
48286
  name: String(team.name),
47974
48287
  handle: String(team.handle || ""),
@@ -48020,28 +48333,28 @@ var PostmanAssetsClient = class {
48020
48333
  body: JSON.stringify(payload)
48021
48334
  });
48022
48335
  } catch (err) {
48023
- if (err instanceof Error && err.message.includes("Only personal workspaces")) {
48024
- throw new Error(
48025
- "Workspace creation failed: This may be an Org-mode account that requires a workspace-team-id input. The Postman API does not allow creating team workspaces at the organization level. Use the workspace-team-id input to specify which sub-team should own this workspace.",
48026
- { cause: err }
48027
- );
48336
+ if (err instanceof Error) {
48337
+ const advised = adviseFromWorkspaceCreateError(err, targetTeamId);
48338
+ if (advised) {
48339
+ throw advised;
48340
+ }
48028
48341
  }
48029
48342
  throw err;
48030
48343
  }
48031
- const createdWorkspace = asRecord(created?.workspace);
48344
+ const createdWorkspace = asRecord2(created?.workspace);
48032
48345
  const workspaceId = String(createdWorkspace?.id || "").trim();
48033
48346
  if (!workspaceId) {
48034
48347
  throw new Error("Workspace create did not return an id");
48035
48348
  }
48036
48349
  const workspace = await this.request(`/workspaces/${workspaceId}`);
48037
- let visibility = asRecord(workspace?.workspace)?.visibility;
48350
+ let visibility = asRecord2(workspace?.workspace)?.visibility;
48038
48351
  if (visibility !== "team") {
48039
48352
  await this.request(`/workspaces/${workspaceId}`, {
48040
48353
  method: "PUT",
48041
48354
  body: JSON.stringify(payload)
48042
48355
  });
48043
48356
  const reread = await this.request(`/workspaces/${workspaceId}`);
48044
- visibility = asRecord(reread?.workspace)?.visibility;
48357
+ visibility = asRecord2(reread?.workspace)?.visibility;
48045
48358
  }
48046
48359
  if (typeof visibility === "string" && visibility !== "team") {
48047
48360
  let cleanedUp = false;
@@ -48070,7 +48383,7 @@ var PostmanAssetsClient = class {
48070
48383
  async getWorkspaceVisibility(workspaceId) {
48071
48384
  try {
48072
48385
  const workspace = await this.request(`/workspaces/${workspaceId}`);
48073
- const visibility = asRecord(workspace?.workspace)?.visibility;
48386
+ const visibility = asRecord2(workspace?.workspace)?.visibility;
48074
48387
  return typeof visibility === "string" ? visibility : null;
48075
48388
  } catch {
48076
48389
  return null;
@@ -48092,7 +48405,7 @@ var PostmanAssetsClient = class {
48092
48405
  nextCursor = page.nextCursor;
48093
48406
  }
48094
48407
  } while (nextCursor);
48095
- return allWorkspaces.map((entry) => asRecord(entry)).filter((workspace) => Boolean(workspace?.id && workspace?.name)).map((workspace) => ({
48408
+ return allWorkspaces.map((entry) => asRecord2(entry)).filter((workspace) => Boolean(workspace?.id && workspace?.name)).map((workspace) => ({
48096
48409
  id: String(workspace.id),
48097
48410
  name: String(workspace.name),
48098
48411
  type: String(workspace.type ?? "team")
@@ -48140,7 +48453,7 @@ var PostmanAssetsClient = class {
48140
48453
  async inviteRequesterToWorkspace(workspaceId, email) {
48141
48454
  const users = await this.request("/users");
48142
48455
  const userList = Array.isArray(users?.data) ? users.data : [];
48143
- const user = userList.map((entry) => asRecord(entry)).find((entry) => entry?.email === email);
48456
+ const user = userList.map((entry) => asRecord2(entry)).find((entry) => entry?.email === email);
48144
48457
  if (!user?.id) {
48145
48458
  return;
48146
48459
  }
@@ -48228,12 +48541,12 @@ var PostmanAssetsClient = class {
48228
48541
  }
48229
48542
  };
48230
48543
  const extractUid = (data) => {
48231
- const root = asRecord(data);
48232
- const details = asRecord(root?.details);
48544
+ const root = asRecord2(data);
48545
+ const details = asRecord2(root?.details);
48233
48546
  const resources = Array.isArray(details?.resources) ? details.resources : [];
48234
- const firstResource = asRecord(resources[0]);
48235
- const collection = asRecord(root?.collection);
48236
- const resource = asRecord(root?.resource);
48547
+ const firstResource = asRecord2(resources[0]);
48548
+ const collection = asRecord2(root?.collection);
48549
+ const resource = asRecord2(root?.resource);
48237
48550
  return String(
48238
48551
  firstResource?.id ?? collection?.id ?? collection?.uid ?? resource?.uid ?? resource?.id ?? ""
48239
48552
  ).trim() || void 0;
@@ -48267,9 +48580,9 @@ var PostmanAssetsClient = class {
48267
48580
  if (directUid) {
48268
48581
  return directUid;
48269
48582
  }
48270
- let taskUrl = String(generationResponse?.url ?? "") || String(generationResponse?.task_url ?? "") || String(generationResponse?.taskUrl ?? "") || String(asRecord(generationResponse?.links)?.task ?? "");
48583
+ let taskUrl = String(generationResponse?.url ?? "") || String(generationResponse?.task_url ?? "") || String(generationResponse?.taskUrl ?? "") || String(asRecord2(generationResponse?.links)?.task ?? "");
48271
48584
  if (!taskUrl) {
48272
- const task = asRecord(generationResponse?.task);
48585
+ const task = asRecord2(generationResponse?.task);
48273
48586
  const taskId = generationResponse?.taskId || task?.id || generationResponse?.id;
48274
48587
  if (!taskId) {
48275
48588
  throw new Error(
@@ -48283,8 +48596,8 @@ var PostmanAssetsClient = class {
48283
48596
  setTimeout(resolve4, 2e3);
48284
48597
  });
48285
48598
  const task = await this.request(taskUrl);
48286
- const taskRecord = asRecord(task);
48287
- const taskNested = asRecord(taskRecord?.task);
48599
+ const taskRecord = asRecord2(task);
48600
+ const taskNested = asRecord2(taskRecord?.task);
48288
48601
  const status = String(taskRecord?.status || taskNested?.status || "").toLowerCase();
48289
48602
  if (status === "completed") {
48290
48603
  const taskUid = extractUid(task);
@@ -48315,7 +48628,7 @@ var PostmanAssetsClient = class {
48315
48628
  }
48316
48629
  async injectTests(collectionUid, type2) {
48317
48630
  const collectionResponse = await this.request(`/collections/${collectionUid}`);
48318
- const collection = asRecord(collectionResponse?.collection);
48631
+ const collection = asRecord2(collectionResponse?.collection);
48319
48632
  if (!collection) {
48320
48633
  throw new Error(`Failed to fetch collection ${collectionUid}`);
48321
48634
  }
@@ -48401,7 +48714,7 @@ var PostmanAssetsClient = class {
48401
48714
  });
48402
48715
  }
48403
48716
  if (Array.isArray(itemNode.item)) {
48404
- itemNode.item.map((entry) => asRecord(entry)).filter((entry) => Boolean(entry)).forEach(injectScripts);
48717
+ itemNode.item.map((entry) => asRecord2(entry)).filter((entry) => Boolean(entry)).forEach(injectScripts);
48405
48718
  }
48406
48719
  };
48407
48720
  if (Array.isArray(collection.item)) {
@@ -48429,7 +48742,7 @@ var PostmanAssetsClient = class {
48429
48742
  }
48430
48743
  })
48431
48744
  });
48432
- const environment = asRecord(response?.environment);
48745
+ const environment = asRecord2(response?.environment);
48433
48746
  const uid = String(environment?.uid || "").trim();
48434
48747
  if (!uid) {
48435
48748
  throw new Error("Environment create did not return a UID");
@@ -48462,7 +48775,7 @@ var PostmanAssetsClient = class {
48462
48775
  }
48463
48776
  })
48464
48777
  });
48465
- const monitor = asRecord(response?.monitor);
48778
+ const monitor = asRecord2(response?.monitor);
48466
48779
  const uid = String(monitor?.uid || "").trim();
48467
48780
  if (!uid) {
48468
48781
  throw new Error("Monitor create did not return a UID");
@@ -48481,8 +48794,8 @@ var PostmanAssetsClient = class {
48481
48794
  }
48482
48795
  })
48483
48796
  });
48484
- const mock = asRecord(response?.mock);
48485
- const mockConfig = asRecord(mock?.config);
48797
+ const mock = asRecord2(response?.mock);
48798
+ const mockConfig = asRecord2(mock?.config);
48486
48799
  const uid = String(mock?.uid || "").trim();
48487
48800
  if (!uid) {
48488
48801
  throw new Error("Mock create did not return a UID");
@@ -48553,6 +48866,18 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48553
48866
  this.teamId = String(teamId || "").trim();
48554
48867
  this.orgMode = orgMode;
48555
48868
  }
48869
+ adviceContext(operation) {
48870
+ const session = getMemoizedSessionIdentity();
48871
+ return {
48872
+ operation,
48873
+ hasAccessToken: Boolean(this.accessToken),
48874
+ sessionTeamId: session?.teamId,
48875
+ sessionRoles: session?.roles,
48876
+ sessionConsumerType: session?.consumerType,
48877
+ explicitTeamId: this.teamId || void 0,
48878
+ mask: this.secretMasker
48879
+ };
48880
+ }
48556
48881
  async proxyRequest(service, method, requestPath2, body, options = {}) {
48557
48882
  const url = `${this.bifrostBaseUrl}/ws/proxy`;
48558
48883
  const headers = {
@@ -48619,7 +48944,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48619
48944
  { appVersion, query: { tag: "governance" } }
48620
48945
  );
48621
48946
  if (!listResponse.ok) {
48622
- throw await HttpError.fromResponse(listResponse, {
48947
+ const httpErr = await HttpError.fromResponse(listResponse, {
48623
48948
  method: "GET",
48624
48949
  requestHeaders: {
48625
48950
  "Content-Type": "application/json",
@@ -48630,6 +48955,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48630
48955
  secretValues: [this.accessToken],
48631
48956
  url: `${this.bifrostBaseUrl}/ws/proxy`
48632
48957
  });
48958
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("governance assignment"));
48959
+ throw advised ?? httpErr;
48633
48960
  }
48634
48961
  const groups = await listResponse.json();
48635
48962
  const group2 = (groups.workspaceGroups ?? groups.data)?.find(
@@ -48655,7 +48982,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48655
48982
  { appVersion }
48656
48983
  );
48657
48984
  if (!patchResponse.ok) {
48658
- throw await HttpError.fromResponse(patchResponse, {
48985
+ const httpErr = await HttpError.fromResponse(patchResponse, {
48659
48986
  method: "PATCH",
48660
48987
  requestHeaders: {
48661
48988
  "Content-Type": "application/json",
@@ -48666,6 +48993,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48666
48993
  secretValues: [this.accessToken],
48667
48994
  url: `${this.bifrostBaseUrl}/ws/proxy`
48668
48995
  });
48996
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("governance assignment"));
48997
+ throw advised ?? httpErr;
48669
48998
  }
48670
48999
  }
48671
49000
  async connectWorkspaceToRepository(workspaceId, repoUrl) {
@@ -48699,7 +49028,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48699
49028
  );
48700
49029
  }
48701
49030
  }
48702
- throw await HttpError.fromResponse(response, {
49031
+ const httpErr = await HttpError.fromResponse(response, {
48703
49032
  method: "POST",
48704
49033
  requestHeaders: {
48705
49034
  "Content-Type": "application/json",
@@ -48709,6 +49038,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48709
49038
  secretValues: [this.accessToken],
48710
49039
  url: `${this.bifrostBaseUrl}/ws/proxy`
48711
49040
  });
49041
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("workspace repository linking"));
49042
+ throw advised ?? httpErr;
48712
49043
  }
48713
49044
  async linkCollectionsToSpecification(specificationId, collections) {
48714
49045
  if (collections.length === 0) {
@@ -48726,7 +49057,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48726
49057
  if (response.ok) {
48727
49058
  return;
48728
49059
  }
48729
- throw await HttpError.fromResponse(response, {
49060
+ const httpErr = await HttpError.fromResponse(response, {
48730
49061
  method: "POST",
48731
49062
  requestHeaders: {
48732
49063
  "Content-Type": "application/json",
@@ -48736,6 +49067,11 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48736
49067
  secretValues: [this.accessToken],
48737
49068
  url: `${this.bifrostBaseUrl}/ws/proxy`
48738
49069
  });
49070
+ const advised = adviseFromHttpError(
49071
+ httpErr,
49072
+ this.adviceContext("collection-to-specification linking")
49073
+ );
49074
+ throw advised ?? httpErr;
48739
49075
  }
48740
49076
  async syncCollection(specificationId, collectionId) {
48741
49077
  const response = await this.proxyRequest(
@@ -48746,7 +49082,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48746
49082
  if (response.ok) {
48747
49083
  return;
48748
49084
  }
48749
- throw await HttpError.fromResponse(response, {
49085
+ const httpErr = await HttpError.fromResponse(response, {
48750
49086
  method: "POST",
48751
49087
  requestHeaders: {
48752
49088
  "Content-Type": "application/json",
@@ -48756,6 +49092,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48756
49092
  secretValues: [this.accessToken],
48757
49093
  url: `${this.bifrostBaseUrl}/ws/proxy`
48758
49094
  });
49095
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("collection sync"));
49096
+ throw advised ?? httpErr;
48759
49097
  }
48760
49098
  async getWorkspaceGitRepoUrl(workspaceId) {
48761
49099
  const response = await this.proxyRequest(
@@ -49329,7 +49667,7 @@ var STRIP_KEYS = /* @__PURE__ */ new Set([
49329
49667
  "discriminator",
49330
49668
  "format"
49331
49669
  ]);
49332
- function asRecord2(value) {
49670
+ function asRecord3(value) {
49333
49671
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
49334
49672
  return value;
49335
49673
  }
@@ -49341,7 +49679,7 @@ function decodePointerSegment(segment) {
49341
49679
  }
49342
49680
  function resolvePointer(root, ref) {
49343
49681
  if (!ref.startsWith("#/")) return void 0;
49344
- return ref.slice(2).split("/").map(decodePointerSegment).reduce((node, segment) => asRecord2(node)?.[segment], root);
49682
+ return ref.slice(2).split("/").map(decodePointerSegment).reduce((node, segment) => asRecord3(node)?.[segment], root);
49345
49683
  }
49346
49684
  function unsupported(message) {
49347
49685
  return { unsupported: message };
@@ -49351,7 +49689,7 @@ function mergeRequiredWithoutWriteOnly(required, writeOnlyProperties) {
49351
49689
  return values.length > 0 ? values : void 0;
49352
49690
  }
49353
49691
  function hasUnsupported(child2) {
49354
- return asRecord2(child2)?.unsupported;
49692
+ return asRecord3(child2)?.unsupported;
49355
49693
  }
49356
49694
  function rootDialect(root, version, schemaRecord) {
49357
49695
  if (version === "3.0") return DRAFT_07_SCHEMA_URI;
@@ -49371,7 +49709,7 @@ function normalizeSchema(root, schema2, options) {
49371
49709
  const bad = normalized2.map(hasUnsupported).find(Boolean);
49372
49710
  return bad ? unsupported(bad) : normalized2;
49373
49711
  }
49374
- const record = asRecord2(schema2);
49712
+ const record = asRecord3(schema2);
49375
49713
  if (!record) return schema2;
49376
49714
  const ref = typeof record.$ref === "string" ? record.$ref : "";
49377
49715
  if (ref) {
@@ -49406,10 +49744,10 @@ function normalizeSchema(root, schema2, options) {
49406
49744
  const nullable = sourceSchema.nullable === true && options.version === "3.0";
49407
49745
  delete sourceSchema.nullable;
49408
49746
  const writeOnlyProperties = /* @__PURE__ */ new Set();
49409
- const rawProperties = asRecord2(sourceSchema.properties);
49747
+ const rawProperties = asRecord3(sourceSchema.properties);
49410
49748
  if (rawProperties) {
49411
49749
  for (const [propertyName, propertySchema] of Object.entries(rawProperties)) {
49412
- if (asRecord2(propertySchema)?.writeOnly === true) writeOnlyProperties.add(propertyName);
49750
+ if (asRecord3(propertySchema)?.writeOnly === true) writeOnlyProperties.add(propertyName);
49413
49751
  }
49414
49752
  }
49415
49753
  const normalized = {};
@@ -49441,7 +49779,7 @@ function normalizeSchema(root, schema2, options) {
49441
49779
  return unsupported("Tuple array items are unsupported in OpenAPI 3.0");
49442
49780
  }
49443
49781
  if (key === "properties") {
49444
- const properties = asRecord2(value);
49782
+ const properties = asRecord3(value);
49445
49783
  if (!properties) continue;
49446
49784
  const nextProperties = {};
49447
49785
  for (const [propertyName, propertySchema] of Object.entries(properties)) {
@@ -49484,7 +49822,7 @@ function normalizeSchema(root, schema2, options) {
49484
49822
  }
49485
49823
  function packSchema(root, schema2, version) {
49486
49824
  try {
49487
- const dialect = rootDialect(root, version, asRecord2(schema2) ?? void 0);
49825
+ const dialect = rootDialect(root, version, asRecord3(schema2) ?? void 0);
49488
49826
  const normalized = normalizeSchema(root, schema2, { version, rootSchema: true, dialect });
49489
49827
  const message = hasUnsupported(normalized);
49490
49828
  return message ? unsupported(message) : { schema: normalized };
@@ -49495,7 +49833,7 @@ function packSchema(root, schema2, version) {
49495
49833
 
49496
49834
  // src/lib/spec/contract-index.ts
49497
49835
  var HTTP_METHODS = /* @__PURE__ */ new Set(["get", "put", "post", "delete", "options", "head", "patch", "trace"]);
49498
- function asRecord3(value) {
49836
+ function asRecord4(value) {
49499
49837
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
49500
49838
  return value;
49501
49839
  }
@@ -49512,12 +49850,12 @@ function detectOpenApiVersion(root) {
49512
49850
  return match[1] === "1" ? "3.1" : "3.0";
49513
49851
  }
49514
49852
  function resolveInternalRef(root, value) {
49515
- const record = asRecord3(value);
49853
+ const record = asRecord4(value);
49516
49854
  if (!record) return null;
49517
49855
  const ref = typeof record.$ref === "string" ? record.$ref : "";
49518
49856
  if (!ref) return record;
49519
49857
  if (!ref.startsWith("#/")) throw new Error(`CONTRACT_UNRESOLVED_REF: External ref remained after bundling: ${ref}`);
49520
- const resolved = asRecord3(resolvePointer(root, ref));
49858
+ const resolved = asRecord4(resolvePointer(root, ref));
49521
49859
  if (!resolved) throw new Error(`CONTRACT_UNRESOLVED_REF: Unresolved OpenAPI $ref: ${ref}`);
49522
49860
  return resolved;
49523
49861
  }
@@ -49537,11 +49875,11 @@ function normalizePath(path8) {
49537
49875
  return trimmed.split("/").map((segment, index) => index === 0 ? "" : safeDecodeSegment(segment)).join("/") || "/";
49538
49876
  }
49539
49877
  function pathItemServers(pathItem) {
49540
- return asArray2(pathItem.servers).map((entry) => asRecord3(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
49878
+ return asArray2(pathItem.servers).map((entry) => asRecord4(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
49541
49879
  }
49542
49880
  function operationServers(root, pathItem, operation) {
49543
49881
  const rawServers = asArray2(operation.servers).length > 0 ? asArray2(operation.servers) : pathItemServers(pathItem).length > 0 ? asArray2(pathItem.servers) : asArray2(root.servers);
49544
- const values = rawServers.map((entry) => asRecord3(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
49882
+ const values = rawServers.map((entry) => asRecord4(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
49545
49883
  return values.length > 0 ? values : [""];
49546
49884
  }
49547
49885
  function serverPathPrefix(url) {
@@ -49562,10 +49900,10 @@ function normalizeResponseKey(status) {
49562
49900
  return /^[1-5]xx$/i.test(raw) ? raw.toUpperCase() : raw;
49563
49901
  }
49564
49902
  function collectSecurityApiKeys(root, operation) {
49565
- const securitySchemes = asRecord3(asRecord3(root.components)?.securitySchemes);
49903
+ const securitySchemes = asRecord4(asRecord4(root.components)?.securitySchemes);
49566
49904
  const requirements = operation.security === void 0 ? asArray2(root.security) : asArray2(operation.security);
49567
49905
  const names = /* @__PURE__ */ new Set();
49568
- for (const requirement of requirements.map((entry) => asRecord3(entry)).filter(Boolean)) {
49906
+ for (const requirement of requirements.map((entry) => asRecord4(entry)).filter(Boolean)) {
49569
49907
  for (const schemeName of Object.keys(requirement)) {
49570
49908
  const scheme = resolveInternalRef(root, securitySchemes?.[schemeName]);
49571
49909
  if (scheme?.type === "apiKey" && typeof scheme.name === "string" && ["query", "header"].includes(String(scheme.in))) {
@@ -49583,10 +49921,10 @@ function securitySchemeKind(scheme) {
49583
49921
  return type2;
49584
49922
  }
49585
49923
  function collectSecuritySchemeWarnings(root, operation) {
49586
- const securitySchemes = asRecord3(asRecord3(root.components)?.securitySchemes);
49924
+ const securitySchemes = asRecord4(asRecord4(root.components)?.securitySchemes);
49587
49925
  const requirements = operation.security === void 0 ? asArray2(root.security) : asArray2(operation.security);
49588
49926
  const warnings = /* @__PURE__ */ new Set();
49589
- for (const requirement of requirements.map((entry) => asRecord3(entry)).filter(Boolean)) {
49927
+ for (const requirement of requirements.map((entry) => asRecord4(entry)).filter(Boolean)) {
49590
49928
  for (const schemeName of Object.keys(requirement)) {
49591
49929
  const scheme = resolveInternalRef(root, securitySchemes?.[schemeName]);
49592
49930
  warnings.add(
@@ -49622,24 +49960,24 @@ function collectParameters(root, pathItem, operation) {
49622
49960
  function collectRequestBody(root, operation) {
49623
49961
  const body = resolveInternalRef(root, operation.requestBody);
49624
49962
  if (!body || body.required !== true) return void 0;
49625
- const content = asRecord3(body.content);
49963
+ const content = asRecord4(body.content);
49626
49964
  return {
49627
49965
  required: true,
49628
49966
  contentTypes: content ? Object.keys(content) : []
49629
49967
  };
49630
49968
  }
49631
49969
  function responseContent(root, version, response) {
49632
- const content = asRecord3(response.content);
49970
+ const content = asRecord4(response.content);
49633
49971
  if (!content) return {};
49634
49972
  const media = {};
49635
49973
  for (const [contentType, mediaObject] of Object.entries(content)) {
49636
- const schema2 = asRecord3(mediaObject)?.schema;
49974
+ const schema2 = asRecord4(mediaObject)?.schema;
49637
49975
  media[contentType] = schema2 === void 0 ? {} : packSchema(root, schema2, version);
49638
49976
  }
49639
49977
  return media;
49640
49978
  }
49641
49979
  function responseHeaders(root, version, response) {
49642
- const headers = asRecord3(response.headers);
49980
+ const headers = asRecord4(response.headers);
49643
49981
  if (!headers) return [];
49644
49982
  return Object.entries(headers).map(([name, rawHeader]) => {
49645
49983
  const header = resolveInternalRef(root, rawHeader);
@@ -49654,10 +49992,10 @@ function buildContractIndex(root) {
49654
49992
  if (root.swagger === "2.0") throw new Error("CONTRACT_UNSUPPORTED_OPENAPI_VERSION: Dynamic contract tests require OpenAPI 3.0 or 3.1 (found swagger 2.0)");
49655
49993
  if (!("openapi" in root)) throw new Error("CONTRACT_UNSUPPORTED_OPENAPI_VERSION: Dynamic contract tests require OpenAPI 3.0 or 3.1 (missing openapi)");
49656
49994
  const version = detectOpenApiVersion(root);
49657
- const paths = asRecord3(root.paths);
49995
+ const paths = asRecord4(root.paths);
49658
49996
  const operations = [];
49659
49997
  const warnings = [];
49660
- if (asRecord3(root.webhooks)) warnings.push("CONTRACT_WEBHOOKS_NOT_VALIDATED: OpenAPI webhooks are not validated by dynamic contract tests");
49998
+ if (asRecord4(root.webhooks)) warnings.push("CONTRACT_WEBHOOKS_NOT_VALIDATED: OpenAPI webhooks are not validated by dynamic contract tests");
49661
49999
  if (paths) {
49662
50000
  for (const [path8, rawPathItem] of Object.entries(paths)) {
49663
50001
  const pathItem = resolveInternalRef(root, rawPathItem);
@@ -49668,7 +50006,7 @@ function buildContractIndex(root) {
49668
50006
  const operation = resolveInternalRef(root, rawOperation);
49669
50007
  if (!operation) continue;
49670
50008
  if (operation.callbacks) warnings.push(`CONTRACT_CALLBACKS_NOT_VALIDATED: callbacks are not validated for ${lowerMethod.toUpperCase()} ${path8}`);
49671
- const responses = asRecord3(operation.responses);
50009
+ const responses = asRecord4(operation.responses);
49672
50010
  if (!responses || Object.keys(responses).length === 0) {
49673
50011
  throw new Error(`CONTRACT_OPERATION_NO_RESPONSES: ${lowerMethod.toUpperCase()} ${path8} must define at least one response`);
49674
50012
  }
@@ -49758,7 +50096,7 @@ var CONTRACT_SIZE_LIMITS = {
49758
50096
  maxTestScriptBytes: 9e5,
49759
50097
  maxCollectionUpdateBytes: 4e6
49760
50098
  };
49761
- function asRecord4(value) {
50099
+ function asRecord5(value) {
49762
50100
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
49763
50101
  return value;
49764
50102
  }
@@ -49767,7 +50105,7 @@ function asArray3(value) {
49767
50105
  }
49768
50106
  function stringifyPathSegment(segment) {
49769
50107
  if (typeof segment === "string") return segment;
49770
- const record = asRecord4(segment);
50108
+ const record = asRecord5(segment);
49771
50109
  if (!record) return String(segment ?? "");
49772
50110
  for (const key of ["value", "key", "name"]) {
49773
50111
  if (typeof record[key] === "string" && record[key]) return String(record[key]);
@@ -49785,10 +50123,10 @@ function pathFromRaw(raw) {
49785
50123
  }
49786
50124
  }
49787
50125
  function requestPath(request) {
49788
- const record = asRecord4(request);
50126
+ const record = asRecord5(request);
49789
50127
  const url = record?.url ?? request;
49790
50128
  if (typeof url === "string") return pathFromRaw(url);
49791
- const urlRecord = asRecord4(url);
50129
+ const urlRecord = asRecord5(url);
49792
50130
  if (!urlRecord) return "/";
49793
50131
  if (Array.isArray(urlRecord.path)) return normalizePath(`/${urlRecord.path.map(stringifyPathSegment).filter(Boolean).join("/")}`);
49794
50132
  if (typeof urlRecord.path === "string") return normalizePath(urlRecord.path);
@@ -49820,7 +50158,7 @@ function matchCandidate(candidate, request) {
49820
50158
  return { matched: true, staticCount, templateCount };
49821
50159
  }
49822
50160
  function matchOperation(index, request) {
49823
- const record = asRecord4(request);
50161
+ const record = asRecord5(request);
49824
50162
  const method = String(record?.method || "").toUpperCase();
49825
50163
  const path8 = requestPath(request);
49826
50164
  const candidates = index.operations.filter((operation) => operation.method === method).flatMap((operation) => operation.candidates.map((candidate) => ({ operation, score: matchCandidate(candidate, path8), serverFull: candidate !== normalizePath(operation.path) }))).filter((entry) => entry.score.matched).map((entry) => ({ operation: entry.operation, score: [entry.score.staticCount, entry.serverFull ? 2 : 1, -entry.score.templateCount] })).sort((a, b) => {
@@ -49971,17 +50309,17 @@ function createSecretsResolverItem() {
49971
50309
  }
49972
50310
  function isResolverItem(item) {
49973
50311
  if (item.name !== "00 - Resolve Secrets") return false;
49974
- const request = asRecord4(item.request);
50312
+ const request = asRecord5(item.request);
49975
50313
  if (String(request?.method || "").toUpperCase() !== "POST") return false;
49976
- const headers = asArray3(request?.header).map((entry) => asRecord4(entry));
50314
+ const headers = asArray3(request?.header).map((entry) => asRecord5(entry));
49977
50315
  const target = headers.find((entry) => entry?.key === "X-Amz-Target");
49978
50316
  return String(target?.value || "") === "secretsmanager.GetSecretValue" && !requestPath(request).includes("secretsmanager");
49979
50317
  }
49980
50318
  function requestQueryNames(request) {
49981
- const url = asRecord4(request.url);
50319
+ const url = asRecord5(request.url);
49982
50320
  const names = /* @__PURE__ */ new Set();
49983
50321
  if (Array.isArray(url?.query)) {
49984
- for (const entry of url.query.map((item) => asRecord4(item)).filter(Boolean)) {
50322
+ for (const entry of url.query.map((item) => asRecord5(item)).filter(Boolean)) {
49985
50323
  if (entry.disabled !== true && typeof entry.key === "string") names.add(entry.key.toLowerCase());
49986
50324
  }
49987
50325
  }
@@ -49996,17 +50334,17 @@ function requestQueryNames(request) {
49996
50334
  }
49997
50335
  function requestHeaderNames(request) {
49998
50336
  const names = /* @__PURE__ */ new Set();
49999
- for (const entry of asArray3(request.header).map((item) => asRecord4(item)).filter(Boolean)) {
50337
+ for (const entry of asArray3(request.header).map((item) => asRecord5(item)).filter(Boolean)) {
50000
50338
  if (entry.disabled !== true && typeof entry.key === "string") names.add(entry.key.toLowerCase());
50001
50339
  }
50002
50340
  return names;
50003
50341
  }
50004
50342
  function requestHeaderValue(request, name) {
50005
- const match = asArray3(request.header).map((item) => asRecord4(item)).filter(Boolean).find((entry) => String(entry.key || "").toLowerCase() === name.toLowerCase() && entry.disabled !== true);
50343
+ const match = asArray3(request.header).map((item) => asRecord5(item)).filter(Boolean).find((entry) => String(entry.key || "").toLowerCase() === name.toLowerCase() && entry.disabled !== true);
50006
50344
  return typeof match?.value === "string" ? match.value : void 0;
50007
50345
  }
50008
50346
  function hasRequestBody(request) {
50009
- const body = asRecord4(request.body);
50347
+ const body = asRecord5(request.body);
50010
50348
  if (!body) return false;
50011
50349
  if (typeof body.raw === "string" && body.raw.trim()) return true;
50012
50350
  return ["urlencoded", "formdata", "graphql"].some((key) => Array.isArray(body[key]) ? body[key].length > 0 : Boolean(body[key]));
@@ -50057,21 +50395,21 @@ function validateScript(script) {
50057
50395
  return void 0;
50058
50396
  }
50059
50397
  function scriptExecLines(script) {
50060
- const record = asRecord4(script);
50398
+ const record = asRecord5(script);
50061
50399
  if (!record) return [];
50062
50400
  if (Array.isArray(record.exec)) return record.exec.map((line) => String(line));
50063
50401
  if (typeof record.exec === "string") return [record.exec];
50064
50402
  return [];
50065
50403
  }
50066
50404
  function scanExecutableScripts(node, warnings) {
50067
- for (const event of asArray3(node.event).map((entry) => asRecord4(entry)).filter(Boolean)) {
50405
+ for (const event of asArray3(node.event).map((entry) => asRecord5(entry)).filter(Boolean)) {
50068
50406
  const lines = scriptExecLines(event.script);
50069
50407
  if (lines.length === 0) continue;
50070
50408
  const warning2 = validateScript(lines);
50071
50409
  if (warning2) warnings.push(warning2);
50072
50410
  }
50073
50411
  for (const child2 of asArray3(node.item)) {
50074
- const childRecord = asRecord4(child2);
50412
+ const childRecord = asRecord5(child2);
50075
50413
  if (childRecord) scanExecutableScripts(childRecord, warnings);
50076
50414
  }
50077
50415
  }
@@ -50081,7 +50419,7 @@ function instrumentContractCollection(collection, index) {
50081
50419
  const inject = (item) => {
50082
50420
  if (isResolverItem(item)) return;
50083
50421
  if (item.request) {
50084
- const request = asRecord4(item.request) ?? {};
50422
+ const request = asRecord5(item.request) ?? {};
50085
50423
  const result = matchOperation(index, request);
50086
50424
  let script;
50087
50425
  if (result.operation) {
@@ -50095,15 +50433,15 @@ function instrumentContractCollection(collection, index) {
50095
50433
  } else {
50096
50434
  script = createMappingFailureScript(`No OpenAPI operation matched request ${result.method} ${result.path}`);
50097
50435
  }
50098
- const events2 = asArray3(item.event).filter((entry) => asRecord4(entry)?.listen !== "test");
50436
+ const events2 = asArray3(item.event).filter((entry) => asRecord5(entry)?.listen !== "test");
50099
50437
  item.event = [...events2, { listen: "test", script: { type: "text/javascript", exec: script } }];
50100
50438
  }
50101
50439
  for (const child2 of asArray3(item.item)) {
50102
- const childRecord = asRecord4(child2);
50440
+ const childRecord = asRecord5(child2);
50103
50441
  if (childRecord) inject(childRecord);
50104
50442
  }
50105
50443
  };
50106
- const items = asArray3(collection.item).map((entry) => asRecord4(entry)).filter((entry) => Boolean(entry)).filter((entry) => !isResolverItem(entry));
50444
+ const items = asArray3(collection.item).map((entry) => asRecord5(entry)).filter((entry) => Boolean(entry)).filter((entry) => !isResolverItem(entry));
50107
50445
  collection.item = items;
50108
50446
  for (const item of items) inject(item);
50109
50447
  const missing = index.operations.filter((operation) => !covered.has(operation.id));
@@ -62467,7 +62805,7 @@ function compileErrors(result) {
62467
62805
 
62468
62806
  // src/lib/spec/openapi-loader.ts
62469
62807
  var import_yaml2 = __toESM(require_dist(), 1);
62470
- function asRecord5(value) {
62808
+ function asRecord6(value) {
62471
62809
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
62472
62810
  return value;
62473
62811
  }
@@ -62482,7 +62820,7 @@ function parseOpenApiDocument(content) {
62482
62820
  throw new Error("CONTRACT_SPEC_PARSE_FAILED: Spec content is not valid JSON or YAML");
62483
62821
  }
62484
62822
  }
62485
- const doc = asRecord5(parsed);
62823
+ const doc = asRecord6(parsed);
62486
62824
  if (!doc) throw new Error("CONTRACT_SPEC_PARSE_FAILED: Spec content must be a JSON or YAML object");
62487
62825
  return doc;
62488
62826
  }
@@ -62510,7 +62848,7 @@ function collectExternalRefs(node, baseUrl, refs) {
62510
62848
  node.forEach((entry) => collectExternalRefs(entry, baseUrl, refs));
62511
62849
  return;
62512
62850
  }
62513
- const record = asRecord5(node);
62851
+ const record = asRecord6(node);
62514
62852
  if (!record) return;
62515
62853
  const ref = typeof record.$ref === "string" ? record.$ref : "";
62516
62854
  if (ref && !ref.startsWith("#")) {
@@ -62848,6 +63186,11 @@ function resolveInputs(env = process.env) {
62848
63186
  governanceMappingJson: parseGovernanceMappingJson(getInput2("governance-mapping-json", env)),
62849
63187
  postmanApiKey: getInput2("postman-api-key", env) ?? "",
62850
63188
  postmanAccessToken: getInput2("postman-access-token", env),
63189
+ credentialPreflight: parseEnumInput(
63190
+ "credential-preflight",
63191
+ getInput2("credential-preflight", env),
63192
+ customerPreviewActionContract.inputs["credential-preflight"].default ?? "warn"
63193
+ ),
62851
63194
  integrationBackend,
62852
63195
  folderStrategy: parseEnumInput("folder-strategy", getInput2("folder-strategy", env), "Paths"),
62853
63196
  nestedFolderHierarchy: parseBooleanInput("nested-folder-hierarchy", getInput2("nested-folder-hierarchy", env), false),
@@ -62857,6 +63200,7 @@ function resolveInputs(env = process.env) {
62857
63200
  postmanBifrostBase: endpointProfile.bifrostBaseUrl,
62858
63201
  postmanGatewayBase: endpointProfile.gatewayBaseUrl,
62859
63202
  postmanCliInstallUrl: endpointProfile.cliInstallUrl,
63203
+ postmanIapubBase: endpointProfile.iapubBaseUrl,
62860
63204
  githubRefName: env.GITHUB_REF_NAME,
62861
63205
  githubHeadRef: env.GITHUB_HEAD_REF,
62862
63206
  githubRef: env.GITHUB_REF,
@@ -62945,6 +63289,7 @@ function readActionInputs(actionCore) {
62945
63289
  INPUT_GOVERNANCE_MAPPING_JSON: optionalInput(actionCore, "governance-mapping-json") ?? customerPreviewActionContract.inputs["governance-mapping-json"].default,
62946
63290
  INPUT_POSTMAN_API_KEY: postmanApiKey,
62947
63291
  INPUT_POSTMAN_ACCESS_TOKEN: postmanAccessToken,
63292
+ INPUT_CREDENTIAL_PREFLIGHT: optionalInput(actionCore, "credential-preflight") ?? customerPreviewActionContract.inputs["credential-preflight"].default,
62948
63293
  INPUT_INTEGRATION_BACKEND: optionalInput(actionCore, "integration-backend") ?? customerPreviewActionContract.inputs["integration-backend"].default,
62949
63294
  INPUT_FOLDER_STRATEGY: optionalInput(actionCore, "folder-strategy") ?? customerPreviewActionContract.inputs["folder-strategy"].default,
62950
63295
  INPUT_NESTED_FOLDER_HIERARCHY: optionalInput(actionCore, "nested-folder-hierarchy") ?? customerPreviewActionContract.inputs["nested-folder-hierarchy"].default,
@@ -63456,8 +63801,20 @@ For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID
63456
63801
  governanceGroupName
63457
63802
  );
63458
63803
  } catch (error2) {
63804
+ const session = getMemoizedSessionIdentity();
63805
+ const advised = error2 instanceof HttpError ? adviseFromHttpError(error2, {
63806
+ operation: "governance assignment",
63807
+ hasAccessToken: Boolean(inputs.postmanAccessToken),
63808
+ sessionTeamId: session?.teamId,
63809
+ sessionRoles: session?.roles,
63810
+ sessionConsumerType: session?.consumerType,
63811
+ workspaceTeamId: inputs.workspaceTeamId,
63812
+ explicitTeamId: inputs.teamId || void 0,
63813
+ mask: createSecretMasker([inputs.postmanApiKey, inputs.postmanAccessToken])
63814
+ }) : void 0;
63815
+ const reported = advised ?? error2;
63459
63816
  dependencies.core.warning(
63460
- `Failed to assign governance group: ${error2 instanceof Error ? error2.message : String(error2)}`
63817
+ `Failed to assign governance group: ${reported instanceof Error ? reported.message : String(reported)}`
63461
63818
  );
63462
63819
  }
63463
63820
  }
@@ -64044,6 +64401,17 @@ For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID
64044
64401
  }
64045
64402
  async function runAction(actionCore = core_exports, actionExec = exec_exports, actionIo = io_exports) {
64046
64403
  const inputs = readActionInputs(actionCore);
64404
+ await runCredentialPreflight({
64405
+ apiBaseUrl: inputs.postmanApiBase,
64406
+ iapubBaseUrl: inputs.postmanIapubBase,
64407
+ postmanApiKey: inputs.postmanApiKey,
64408
+ postmanAccessToken: inputs.postmanAccessToken,
64409
+ workspaceTeamId: inputs.workspaceTeamId,
64410
+ explicitTeamId: inputs.teamId || void 0,
64411
+ mode: inputs.credentialPreflight,
64412
+ mask: createSecretMasker([inputs.postmanApiKey, inputs.postmanAccessToken]),
64413
+ log: actionCore
64414
+ });
64047
64415
  let orgMode = false;
64048
64416
  if (inputs.postmanAccessToken && inputs.teamId) {
64049
64417
  try {