@postman-cse/onboarding-bootstrap 0.14.2 → 0.15.2

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,313 @@ 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 root = asRecord(payload.session) ?? payload;
47925
+ const identity = asRecord(root.identity);
47926
+ const data = asRecord(root.data);
47927
+ const user = asRecord(data?.user);
47928
+ const roleEntries = Array.isArray(user?.roles) ? user.roles.map((entry) => coerceText(entry) ?? coerceId(entry)).filter((entry) => Boolean(entry)) : [];
47929
+ const singleRole = coerceText(user?.role);
47930
+ const roles = roleEntries.length > 0 ? roleEntries : singleRole ? [singleRole] : void 0;
47931
+ const resolved = {
47932
+ source: "iapub/sessions",
47933
+ userId: coerceId(identity?.user) ?? coerceId(user?.id),
47934
+ fullName: coerceText(user?.fullName) ?? coerceText(user?.name) ?? coerceText(user?.username),
47935
+ teamId: coerceId(identity?.team),
47936
+ teamName: coerceText(user?.teamName),
47937
+ teamDomain: coerceText(identity?.domain),
47938
+ ...roles ? { roles } : {},
47939
+ consumerType: coerceText(root.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
47940
+ };
47941
+ memoizedSessionIdentity = resolved;
47942
+ return resolved;
47943
+ } catch {
47944
+ return void 0;
47945
+ }
47946
+ }
47947
+ function describeTeam(id) {
47948
+ const label = id?.teamName ?? id?.teamDomain;
47949
+ return `team ${id?.teamId ?? "unresolved"}${label ? ` (${label})` : ""}`;
47950
+ }
47951
+ function formatIdentityLine(id, mask) {
47952
+ const teamPart = id.teamId ? describeTeam(id) : "team unresolved";
47953
+ const domainPart = id.teamDomain ? `, domain ${id.teamDomain}` : "";
47954
+ if (id.source === "pmak/me") {
47955
+ const userPart = id.userId ? `user ${id.userId}${id.fullName ? ` (${id.fullName})` : ""}, ` : "";
47956
+ return mask(`postman: PMAK identity - ${userPart}${teamPart}${domainPart}`);
47957
+ }
47958
+ return mask(
47959
+ `postman: access-token session identity - ${teamPart}${domainPart} [source: iapub/sessions]`
47960
+ );
47961
+ }
47962
+ function crossCheckIdentities(args) {
47963
+ if (args.mode === "off") {
47964
+ return { ok: true, level: "ok", message: "" };
47965
+ }
47966
+ const pmakTeamId = args.pmak?.teamId;
47967
+ const sessionTeamId = args.session?.teamId;
47968
+ if (pmakTeamId && sessionTeamId && pmakTeamId !== sessionTeamId) {
47969
+ const level = args.mode === "enforce" ? "fail" : "note";
47970
+ const lead = level === "fail" ? "credential preflight FAILED" : "credential preflight note";
47971
+ 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.";
47972
+ return {
47973
+ ok: false,
47974
+ level,
47975
+ message: args.mask(
47976
+ `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
47977
+ )
47978
+ };
47979
+ }
47980
+ if (pmakTeamId && sessionTeamId) {
47981
+ const scope = args.workspaceTeamId || args.explicitTeamId ? "parent org team" : "team";
47982
+ const label = args.pmak?.teamName ?? args.pmak?.teamDomain ?? args.session?.teamName ?? args.session?.teamDomain;
47983
+ return {
47984
+ ok: true,
47985
+ level: "ok",
47986
+ message: args.mask(
47987
+ `postman: credential preflight OK - PMAK and access token both resolve to ${scope} ${pmakTeamId}${label ? ` (${label})` : ""}`
47988
+ )
47989
+ };
47990
+ }
47991
+ const missing = [
47992
+ !pmakTeamId ? "PMAK identity" : void 0,
47993
+ !sessionTeamId ? "access-token session identity" : void 0
47994
+ ].filter(Boolean).join(" and ");
47995
+ return {
47996
+ ok: false,
47997
+ level: "note",
47998
+ message: args.mask(
47999
+ `postman: credential preflight note - cross-check skipped because the ${missing} did not resolve a team id; continuing with reactive error guidance only`
48000
+ )
48001
+ };
48002
+ }
48003
+ async function runCredentialPreflight(args) {
48004
+ if (args.mode === "off") {
48005
+ return;
48006
+ }
48007
+ const mask = args.mask;
48008
+ const apiKey = String(args.postmanApiKey || "").trim();
48009
+ const accessToken = String(args.postmanAccessToken || "").trim();
48010
+ let pmak;
48011
+ if (apiKey) {
48012
+ try {
48013
+ pmak = await resolvePmakIdentity({
48014
+ apiBaseUrl: args.apiBaseUrl,
48015
+ apiKey,
48016
+ fetchImpl: args.fetchImpl
48017
+ });
48018
+ } catch (error2) {
48019
+ args.log.warning(
48020
+ mask(
48021
+ `postman: credential preflight could not resolve PMAK identity: ${error2 instanceof Error ? error2.message : String(error2)}`
48022
+ )
48023
+ );
48024
+ }
48025
+ if (pmak) {
48026
+ args.log.info(formatIdentityLine(pmak, mask));
48027
+ } else {
48028
+ args.log.warning(
48029
+ mask("postman: credential preflight could not resolve PMAK identity from GET /me; continuing")
48030
+ );
48031
+ }
48032
+ }
48033
+ if (!accessToken) {
48034
+ args.log.info(mask("postman: Bifrost diagnostics limited: no access token"));
48035
+ return;
48036
+ }
48037
+ let session;
48038
+ try {
48039
+ session = await resolveSessionIdentity({
48040
+ iapubBaseUrl: args.iapubBaseUrl,
48041
+ accessToken,
48042
+ fetchImpl: args.fetchImpl
48043
+ });
48044
+ } catch (error2) {
48045
+ args.log.warning(
48046
+ mask(
48047
+ `postman: credential preflight could not resolve access-token session identity: ${error2 instanceof Error ? error2.message : String(error2)}`
48048
+ )
48049
+ );
48050
+ }
48051
+ if (session) {
48052
+ args.log.info(formatIdentityLine(session, mask));
48053
+ } else {
48054
+ args.log.warning(
48055
+ mask(
48056
+ "postman: credential preflight could not resolve the access-token session identity from iapub; continuing with reactive error guidance only"
48057
+ )
48058
+ );
48059
+ }
48060
+ const result = crossCheckIdentities({
48061
+ pmak,
48062
+ session,
48063
+ workspaceTeamId: args.workspaceTeamId,
48064
+ explicitTeamId: args.explicitTeamId,
48065
+ mode: args.mode,
48066
+ mask
48067
+ });
48068
+ if (!result.message) {
48069
+ return;
48070
+ }
48071
+ if (result.level === "fail") {
48072
+ throw new Error(result.message);
48073
+ }
48074
+ if (result.level === "note") {
48075
+ args.log.warning(result.message);
48076
+ return;
48077
+ }
48078
+ args.log.info(result.message);
48079
+ }
48080
+
48081
+ // src/lib/postman/error-advice.ts
48082
+ 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.";
48083
+ function workspaceTeamIdUnauthorizedAdvice(targetTeamId) {
48084
+ 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.`;
48085
+ }
48086
+ function adviseFromWorkspaceCreateError(err, targetTeamId) {
48087
+ if (err.message.includes("Only personal workspaces")) {
48088
+ return new Error(WORKSPACE_PERSONAL_ONLY_ADVICE, { cause: err });
48089
+ }
48090
+ if (targetTeamId != null && err.message.includes("You are not authorized to perform this action")) {
48091
+ return new Error(workspaceTeamIdUnauthorizedAdvice(targetTeamId), { cause: err });
48092
+ }
48093
+ return void 0;
48094
+ }
48095
+ function expiryAdvice(code) {
48096
+ 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.`;
48097
+ }
48098
+ function forbiddenAdvice(ctx) {
48099
+ 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)` : "";
48100
+ const scopedTeamId = ctx.workspaceTeamId || ctx.explicitTeamId;
48101
+ 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";
48102
+ 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.`;
48103
+ }
48104
+ function buildAdvice(status, body, ctx) {
48105
+ if (body.includes("UNAUTHENTICATED")) {
48106
+ return expiryAdvice("UNAUTHENTICATED");
48107
+ }
48108
+ if (body.includes("authenticationError")) {
48109
+ return expiryAdvice("authenticationError");
48110
+ }
48111
+ if (body.includes("Only personal workspaces")) {
48112
+ return WORKSPACE_PERSONAL_ONLY_ADVICE;
48113
+ }
48114
+ if (body.includes("projectAlreadyConnected")) {
48115
+ 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.`;
48116
+ }
48117
+ if (body.includes("invalidParamError") && body.includes("already exists")) {
48118
+ 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.`;
48119
+ }
48120
+ if (body.includes("Team feature is not available for your organization")) {
48121
+ 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.`;
48122
+ }
48123
+ if (body.includes("You are not authorized to perform this action") || status === 403 && ctx.hasAccessToken) {
48124
+ return forbiddenAdvice(ctx);
48125
+ }
48126
+ return void 0;
48127
+ }
48128
+ function adviseFromHttpError(err, ctx) {
48129
+ const body = err.responseBody || err.message || "";
48130
+ const advice = buildAdvice(err.status, body, ctx);
48131
+ if (!advice) {
48132
+ return void 0;
48133
+ }
48134
+ return new Error(ctx.mask(advice), { cause: err });
48135
+ }
48136
+
47822
48137
  // src/lib/retry.ts
47823
48138
  function sleep(delayMs) {
47824
48139
  return new Promise((resolve4) => {
@@ -47867,7 +48182,7 @@ async function retry(operation, options = {}) {
47867
48182
  }
47868
48183
 
47869
48184
  // src/lib/postman/postman-assets-client.ts
47870
- function asRecord(value) {
48185
+ function asRecord2(value) {
47871
48186
  if (!value || typeof value !== "object" || Array.isArray(value)) {
47872
48187
  return null;
47873
48188
  }
@@ -47875,8 +48190,8 @@ function asRecord(value) {
47875
48190
  }
47876
48191
  function extractWorkspacesPage(data) {
47877
48192
  const workspaces = Array.isArray(data?.workspaces) ? data.workspaces : [];
47878
- const meta = asRecord(data?.meta);
47879
- const pagination = asRecord(data?.pagination);
48193
+ const meta = asRecord2(data?.meta);
48194
+ const pagination = asRecord2(data?.pagination);
47880
48195
  const nextCursor = String(
47881
48196
  data?.nextCursor ?? data?.next_cursor ?? meta?.nextCursor ?? meta?.next_cursor ?? pagination?.nextCursor ?? pagination?.next_cursor ?? ""
47882
48197
  ).trim() || void 0;
@@ -47968,7 +48283,7 @@ var PostmanAssetsClient = class {
47968
48283
  async getTeams() {
47969
48284
  const data = await this.request("/teams");
47970
48285
  const teams = data?.data ?? [];
47971
- return Array.isArray(teams) ? teams.map((entry) => asRecord(entry)).filter((team) => Boolean(team?.id && team?.name)).map((team) => ({
48286
+ return Array.isArray(teams) ? teams.map((entry) => asRecord2(entry)).filter((team) => Boolean(team?.id && team?.name)).map((team) => ({
47972
48287
  id: Number(team.id),
47973
48288
  name: String(team.name),
47974
48289
  handle: String(team.handle || ""),
@@ -48020,34 +48335,28 @@ var PostmanAssetsClient = class {
48020
48335
  body: JSON.stringify(payload)
48021
48336
  });
48022
48337
  } 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
- );
48028
- }
48029
- if (targetTeamId != null && err instanceof Error && err.message.includes("You are not authorized to perform this action")) {
48030
- throw new Error(
48031
- `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.`,
48032
- { cause: err }
48033
- );
48338
+ if (err instanceof Error) {
48339
+ const advised = adviseFromWorkspaceCreateError(err, targetTeamId);
48340
+ if (advised) {
48341
+ throw advised;
48342
+ }
48034
48343
  }
48035
48344
  throw err;
48036
48345
  }
48037
- const createdWorkspace = asRecord(created?.workspace);
48346
+ const createdWorkspace = asRecord2(created?.workspace);
48038
48347
  const workspaceId = String(createdWorkspace?.id || "").trim();
48039
48348
  if (!workspaceId) {
48040
48349
  throw new Error("Workspace create did not return an id");
48041
48350
  }
48042
48351
  const workspace = await this.request(`/workspaces/${workspaceId}`);
48043
- let visibility = asRecord(workspace?.workspace)?.visibility;
48352
+ let visibility = asRecord2(workspace?.workspace)?.visibility;
48044
48353
  if (visibility !== "team") {
48045
48354
  await this.request(`/workspaces/${workspaceId}`, {
48046
48355
  method: "PUT",
48047
48356
  body: JSON.stringify(payload)
48048
48357
  });
48049
48358
  const reread = await this.request(`/workspaces/${workspaceId}`);
48050
- visibility = asRecord(reread?.workspace)?.visibility;
48359
+ visibility = asRecord2(reread?.workspace)?.visibility;
48051
48360
  }
48052
48361
  if (typeof visibility === "string" && visibility !== "team") {
48053
48362
  let cleanedUp = false;
@@ -48076,7 +48385,7 @@ var PostmanAssetsClient = class {
48076
48385
  async getWorkspaceVisibility(workspaceId) {
48077
48386
  try {
48078
48387
  const workspace = await this.request(`/workspaces/${workspaceId}`);
48079
- const visibility = asRecord(workspace?.workspace)?.visibility;
48388
+ const visibility = asRecord2(workspace?.workspace)?.visibility;
48080
48389
  return typeof visibility === "string" ? visibility : null;
48081
48390
  } catch {
48082
48391
  return null;
@@ -48098,7 +48407,7 @@ var PostmanAssetsClient = class {
48098
48407
  nextCursor = page.nextCursor;
48099
48408
  }
48100
48409
  } while (nextCursor);
48101
- return allWorkspaces.map((entry) => asRecord(entry)).filter((workspace) => Boolean(workspace?.id && workspace?.name)).map((workspace) => ({
48410
+ return allWorkspaces.map((entry) => asRecord2(entry)).filter((workspace) => Boolean(workspace?.id && workspace?.name)).map((workspace) => ({
48102
48411
  id: String(workspace.id),
48103
48412
  name: String(workspace.name),
48104
48413
  type: String(workspace.type ?? "team")
@@ -48146,7 +48455,7 @@ var PostmanAssetsClient = class {
48146
48455
  async inviteRequesterToWorkspace(workspaceId, email) {
48147
48456
  const users = await this.request("/users");
48148
48457
  const userList = Array.isArray(users?.data) ? users.data : [];
48149
- const user = userList.map((entry) => asRecord(entry)).find((entry) => entry?.email === email);
48458
+ const user = userList.map((entry) => asRecord2(entry)).find((entry) => entry?.email === email);
48150
48459
  if (!user?.id) {
48151
48460
  return;
48152
48461
  }
@@ -48234,12 +48543,12 @@ var PostmanAssetsClient = class {
48234
48543
  }
48235
48544
  };
48236
48545
  const extractUid = (data) => {
48237
- const root = asRecord(data);
48238
- const details = asRecord(root?.details);
48546
+ const root = asRecord2(data);
48547
+ const details = asRecord2(root?.details);
48239
48548
  const resources = Array.isArray(details?.resources) ? details.resources : [];
48240
- const firstResource = asRecord(resources[0]);
48241
- const collection = asRecord(root?.collection);
48242
- const resource = asRecord(root?.resource);
48549
+ const firstResource = asRecord2(resources[0]);
48550
+ const collection = asRecord2(root?.collection);
48551
+ const resource = asRecord2(root?.resource);
48243
48552
  return String(
48244
48553
  firstResource?.id ?? collection?.id ?? collection?.uid ?? resource?.uid ?? resource?.id ?? ""
48245
48554
  ).trim() || void 0;
@@ -48273,9 +48582,9 @@ var PostmanAssetsClient = class {
48273
48582
  if (directUid) {
48274
48583
  return directUid;
48275
48584
  }
48276
- let taskUrl = String(generationResponse?.url ?? "") || String(generationResponse?.task_url ?? "") || String(generationResponse?.taskUrl ?? "") || String(asRecord(generationResponse?.links)?.task ?? "");
48585
+ let taskUrl = String(generationResponse?.url ?? "") || String(generationResponse?.task_url ?? "") || String(generationResponse?.taskUrl ?? "") || String(asRecord2(generationResponse?.links)?.task ?? "");
48277
48586
  if (!taskUrl) {
48278
- const task = asRecord(generationResponse?.task);
48587
+ const task = asRecord2(generationResponse?.task);
48279
48588
  const taskId = generationResponse?.taskId || task?.id || generationResponse?.id;
48280
48589
  if (!taskId) {
48281
48590
  throw new Error(
@@ -48289,8 +48598,8 @@ var PostmanAssetsClient = class {
48289
48598
  setTimeout(resolve4, 2e3);
48290
48599
  });
48291
48600
  const task = await this.request(taskUrl);
48292
- const taskRecord = asRecord(task);
48293
- const taskNested = asRecord(taskRecord?.task);
48601
+ const taskRecord = asRecord2(task);
48602
+ const taskNested = asRecord2(taskRecord?.task);
48294
48603
  const status = String(taskRecord?.status || taskNested?.status || "").toLowerCase();
48295
48604
  if (status === "completed") {
48296
48605
  const taskUid = extractUid(task);
@@ -48321,7 +48630,7 @@ var PostmanAssetsClient = class {
48321
48630
  }
48322
48631
  async injectTests(collectionUid, type2) {
48323
48632
  const collectionResponse = await this.request(`/collections/${collectionUid}`);
48324
- const collection = asRecord(collectionResponse?.collection);
48633
+ const collection = asRecord2(collectionResponse?.collection);
48325
48634
  if (!collection) {
48326
48635
  throw new Error(`Failed to fetch collection ${collectionUid}`);
48327
48636
  }
@@ -48407,7 +48716,7 @@ var PostmanAssetsClient = class {
48407
48716
  });
48408
48717
  }
48409
48718
  if (Array.isArray(itemNode.item)) {
48410
- itemNode.item.map((entry) => asRecord(entry)).filter((entry) => Boolean(entry)).forEach(injectScripts);
48719
+ itemNode.item.map((entry) => asRecord2(entry)).filter((entry) => Boolean(entry)).forEach(injectScripts);
48411
48720
  }
48412
48721
  };
48413
48722
  if (Array.isArray(collection.item)) {
@@ -48435,7 +48744,7 @@ var PostmanAssetsClient = class {
48435
48744
  }
48436
48745
  })
48437
48746
  });
48438
- const environment = asRecord(response?.environment);
48747
+ const environment = asRecord2(response?.environment);
48439
48748
  const uid = String(environment?.uid || "").trim();
48440
48749
  if (!uid) {
48441
48750
  throw new Error("Environment create did not return a UID");
@@ -48468,7 +48777,7 @@ var PostmanAssetsClient = class {
48468
48777
  }
48469
48778
  })
48470
48779
  });
48471
- const monitor = asRecord(response?.monitor);
48780
+ const monitor = asRecord2(response?.monitor);
48472
48781
  const uid = String(monitor?.uid || "").trim();
48473
48782
  if (!uid) {
48474
48783
  throw new Error("Monitor create did not return a UID");
@@ -48487,8 +48796,8 @@ var PostmanAssetsClient = class {
48487
48796
  }
48488
48797
  })
48489
48798
  });
48490
- const mock = asRecord(response?.mock);
48491
- const mockConfig = asRecord(mock?.config);
48799
+ const mock = asRecord2(response?.mock);
48800
+ const mockConfig = asRecord2(mock?.config);
48492
48801
  const uid = String(mock?.uid || "").trim();
48493
48802
  if (!uid) {
48494
48803
  throw new Error("Mock create did not return a UID");
@@ -48559,6 +48868,18 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48559
48868
  this.teamId = String(teamId || "").trim();
48560
48869
  this.orgMode = orgMode;
48561
48870
  }
48871
+ adviceContext(operation) {
48872
+ const session = getMemoizedSessionIdentity();
48873
+ return {
48874
+ operation,
48875
+ hasAccessToken: Boolean(this.accessToken),
48876
+ sessionTeamId: session?.teamId,
48877
+ sessionRoles: session?.roles,
48878
+ sessionConsumerType: session?.consumerType,
48879
+ explicitTeamId: this.teamId || void 0,
48880
+ mask: this.secretMasker
48881
+ };
48882
+ }
48562
48883
  async proxyRequest(service, method, requestPath2, body, options = {}) {
48563
48884
  const url = `${this.bifrostBaseUrl}/ws/proxy`;
48564
48885
  const headers = {
@@ -48625,7 +48946,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48625
48946
  { appVersion, query: { tag: "governance" } }
48626
48947
  );
48627
48948
  if (!listResponse.ok) {
48628
- throw await HttpError.fromResponse(listResponse, {
48949
+ const httpErr = await HttpError.fromResponse(listResponse, {
48629
48950
  method: "GET",
48630
48951
  requestHeaders: {
48631
48952
  "Content-Type": "application/json",
@@ -48636,6 +48957,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48636
48957
  secretValues: [this.accessToken],
48637
48958
  url: `${this.bifrostBaseUrl}/ws/proxy`
48638
48959
  });
48960
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("governance assignment"));
48961
+ throw advised ?? httpErr;
48639
48962
  }
48640
48963
  const groups = await listResponse.json();
48641
48964
  const group2 = (groups.workspaceGroups ?? groups.data)?.find(
@@ -48661,7 +48984,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48661
48984
  { appVersion }
48662
48985
  );
48663
48986
  if (!patchResponse.ok) {
48664
- throw await HttpError.fromResponse(patchResponse, {
48987
+ const httpErr = await HttpError.fromResponse(patchResponse, {
48665
48988
  method: "PATCH",
48666
48989
  requestHeaders: {
48667
48990
  "Content-Type": "application/json",
@@ -48672,6 +48995,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48672
48995
  secretValues: [this.accessToken],
48673
48996
  url: `${this.bifrostBaseUrl}/ws/proxy`
48674
48997
  });
48998
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("governance assignment"));
48999
+ throw advised ?? httpErr;
48675
49000
  }
48676
49001
  }
48677
49002
  async connectWorkspaceToRepository(workspaceId, repoUrl) {
@@ -48705,7 +49030,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48705
49030
  );
48706
49031
  }
48707
49032
  }
48708
- throw await HttpError.fromResponse(response, {
49033
+ const httpErr = await HttpError.fromResponse(response, {
48709
49034
  method: "POST",
48710
49035
  requestHeaders: {
48711
49036
  "Content-Type": "application/json",
@@ -48715,6 +49040,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48715
49040
  secretValues: [this.accessToken],
48716
49041
  url: `${this.bifrostBaseUrl}/ws/proxy`
48717
49042
  });
49043
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("workspace repository linking"));
49044
+ throw advised ?? httpErr;
48718
49045
  }
48719
49046
  async linkCollectionsToSpecification(specificationId, collections) {
48720
49047
  if (collections.length === 0) {
@@ -48732,7 +49059,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48732
49059
  if (response.ok) {
48733
49060
  return;
48734
49061
  }
48735
- throw await HttpError.fromResponse(response, {
49062
+ const httpErr = await HttpError.fromResponse(response, {
48736
49063
  method: "POST",
48737
49064
  requestHeaders: {
48738
49065
  "Content-Type": "application/json",
@@ -48742,6 +49069,11 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48742
49069
  secretValues: [this.accessToken],
48743
49070
  url: `${this.bifrostBaseUrl}/ws/proxy`
48744
49071
  });
49072
+ const advised = adviseFromHttpError(
49073
+ httpErr,
49074
+ this.adviceContext("collection-to-specification linking")
49075
+ );
49076
+ throw advised ?? httpErr;
48745
49077
  }
48746
49078
  async syncCollection(specificationId, collectionId) {
48747
49079
  const response = await this.proxyRequest(
@@ -48752,7 +49084,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48752
49084
  if (response.ok) {
48753
49085
  return;
48754
49086
  }
48755
- throw await HttpError.fromResponse(response, {
49087
+ const httpErr = await HttpError.fromResponse(response, {
48756
49088
  method: "POST",
48757
49089
  requestHeaders: {
48758
49090
  "Content-Type": "application/json",
@@ -48762,6 +49094,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48762
49094
  secretValues: [this.accessToken],
48763
49095
  url: `${this.bifrostBaseUrl}/ws/proxy`
48764
49096
  });
49097
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("collection sync"));
49098
+ throw advised ?? httpErr;
48765
49099
  }
48766
49100
  async getWorkspaceGitRepoUrl(workspaceId) {
48767
49101
  const response = await this.proxyRequest(
@@ -49335,7 +49669,7 @@ var STRIP_KEYS = /* @__PURE__ */ new Set([
49335
49669
  "discriminator",
49336
49670
  "format"
49337
49671
  ]);
49338
- function asRecord2(value) {
49672
+ function asRecord3(value) {
49339
49673
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
49340
49674
  return value;
49341
49675
  }
@@ -49347,7 +49681,7 @@ function decodePointerSegment(segment) {
49347
49681
  }
49348
49682
  function resolvePointer(root, ref) {
49349
49683
  if (!ref.startsWith("#/")) return void 0;
49350
- return ref.slice(2).split("/").map(decodePointerSegment).reduce((node, segment) => asRecord2(node)?.[segment], root);
49684
+ return ref.slice(2).split("/").map(decodePointerSegment).reduce((node, segment) => asRecord3(node)?.[segment], root);
49351
49685
  }
49352
49686
  function unsupported(message) {
49353
49687
  return { unsupported: message };
@@ -49357,7 +49691,7 @@ function mergeRequiredWithoutWriteOnly(required, writeOnlyProperties) {
49357
49691
  return values.length > 0 ? values : void 0;
49358
49692
  }
49359
49693
  function hasUnsupported(child2) {
49360
- return asRecord2(child2)?.unsupported;
49694
+ return asRecord3(child2)?.unsupported;
49361
49695
  }
49362
49696
  function rootDialect(root, version, schemaRecord) {
49363
49697
  if (version === "3.0") return DRAFT_07_SCHEMA_URI;
@@ -49377,7 +49711,7 @@ function normalizeSchema(root, schema2, options) {
49377
49711
  const bad = normalized2.map(hasUnsupported).find(Boolean);
49378
49712
  return bad ? unsupported(bad) : normalized2;
49379
49713
  }
49380
- const record = asRecord2(schema2);
49714
+ const record = asRecord3(schema2);
49381
49715
  if (!record) return schema2;
49382
49716
  const ref = typeof record.$ref === "string" ? record.$ref : "";
49383
49717
  if (ref) {
@@ -49412,10 +49746,10 @@ function normalizeSchema(root, schema2, options) {
49412
49746
  const nullable = sourceSchema.nullable === true && options.version === "3.0";
49413
49747
  delete sourceSchema.nullable;
49414
49748
  const writeOnlyProperties = /* @__PURE__ */ new Set();
49415
- const rawProperties = asRecord2(sourceSchema.properties);
49749
+ const rawProperties = asRecord3(sourceSchema.properties);
49416
49750
  if (rawProperties) {
49417
49751
  for (const [propertyName, propertySchema] of Object.entries(rawProperties)) {
49418
- if (asRecord2(propertySchema)?.writeOnly === true) writeOnlyProperties.add(propertyName);
49752
+ if (asRecord3(propertySchema)?.writeOnly === true) writeOnlyProperties.add(propertyName);
49419
49753
  }
49420
49754
  }
49421
49755
  const normalized = {};
@@ -49447,7 +49781,7 @@ function normalizeSchema(root, schema2, options) {
49447
49781
  return unsupported("Tuple array items are unsupported in OpenAPI 3.0");
49448
49782
  }
49449
49783
  if (key === "properties") {
49450
- const properties = asRecord2(value);
49784
+ const properties = asRecord3(value);
49451
49785
  if (!properties) continue;
49452
49786
  const nextProperties = {};
49453
49787
  for (const [propertyName, propertySchema] of Object.entries(properties)) {
@@ -49490,7 +49824,7 @@ function normalizeSchema(root, schema2, options) {
49490
49824
  }
49491
49825
  function packSchema(root, schema2, version) {
49492
49826
  try {
49493
- const dialect = rootDialect(root, version, asRecord2(schema2) ?? void 0);
49827
+ const dialect = rootDialect(root, version, asRecord3(schema2) ?? void 0);
49494
49828
  const normalized = normalizeSchema(root, schema2, { version, rootSchema: true, dialect });
49495
49829
  const message = hasUnsupported(normalized);
49496
49830
  return message ? unsupported(message) : { schema: normalized };
@@ -49501,7 +49835,7 @@ function packSchema(root, schema2, version) {
49501
49835
 
49502
49836
  // src/lib/spec/contract-index.ts
49503
49837
  var HTTP_METHODS = /* @__PURE__ */ new Set(["get", "put", "post", "delete", "options", "head", "patch", "trace"]);
49504
- function asRecord3(value) {
49838
+ function asRecord4(value) {
49505
49839
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
49506
49840
  return value;
49507
49841
  }
@@ -49518,12 +49852,12 @@ function detectOpenApiVersion(root) {
49518
49852
  return match[1] === "1" ? "3.1" : "3.0";
49519
49853
  }
49520
49854
  function resolveInternalRef(root, value) {
49521
- const record = asRecord3(value);
49855
+ const record = asRecord4(value);
49522
49856
  if (!record) return null;
49523
49857
  const ref = typeof record.$ref === "string" ? record.$ref : "";
49524
49858
  if (!ref) return record;
49525
49859
  if (!ref.startsWith("#/")) throw new Error(`CONTRACT_UNRESOLVED_REF: External ref remained after bundling: ${ref}`);
49526
- const resolved = asRecord3(resolvePointer(root, ref));
49860
+ const resolved = asRecord4(resolvePointer(root, ref));
49527
49861
  if (!resolved) throw new Error(`CONTRACT_UNRESOLVED_REF: Unresolved OpenAPI $ref: ${ref}`);
49528
49862
  return resolved;
49529
49863
  }
@@ -49543,11 +49877,11 @@ function normalizePath(path8) {
49543
49877
  return trimmed.split("/").map((segment, index) => index === 0 ? "" : safeDecodeSegment(segment)).join("/") || "/";
49544
49878
  }
49545
49879
  function pathItemServers(pathItem) {
49546
- return asArray2(pathItem.servers).map((entry) => asRecord3(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
49880
+ return asArray2(pathItem.servers).map((entry) => asRecord4(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
49547
49881
  }
49548
49882
  function operationServers(root, pathItem, operation) {
49549
49883
  const rawServers = asArray2(operation.servers).length > 0 ? asArray2(operation.servers) : pathItemServers(pathItem).length > 0 ? asArray2(pathItem.servers) : asArray2(root.servers);
49550
- const values = rawServers.map((entry) => asRecord3(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
49884
+ const values = rawServers.map((entry) => asRecord4(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
49551
49885
  return values.length > 0 ? values : [""];
49552
49886
  }
49553
49887
  function serverPathPrefix(url) {
@@ -49568,10 +49902,10 @@ function normalizeResponseKey(status) {
49568
49902
  return /^[1-5]xx$/i.test(raw) ? raw.toUpperCase() : raw;
49569
49903
  }
49570
49904
  function collectSecurityApiKeys(root, operation) {
49571
- const securitySchemes = asRecord3(asRecord3(root.components)?.securitySchemes);
49905
+ const securitySchemes = asRecord4(asRecord4(root.components)?.securitySchemes);
49572
49906
  const requirements = operation.security === void 0 ? asArray2(root.security) : asArray2(operation.security);
49573
49907
  const names = /* @__PURE__ */ new Set();
49574
- for (const requirement of requirements.map((entry) => asRecord3(entry)).filter(Boolean)) {
49908
+ for (const requirement of requirements.map((entry) => asRecord4(entry)).filter(Boolean)) {
49575
49909
  for (const schemeName of Object.keys(requirement)) {
49576
49910
  const scheme = resolveInternalRef(root, securitySchemes?.[schemeName]);
49577
49911
  if (scheme?.type === "apiKey" && typeof scheme.name === "string" && ["query", "header"].includes(String(scheme.in))) {
@@ -49589,10 +49923,10 @@ function securitySchemeKind(scheme) {
49589
49923
  return type2;
49590
49924
  }
49591
49925
  function collectSecuritySchemeWarnings(root, operation) {
49592
- const securitySchemes = asRecord3(asRecord3(root.components)?.securitySchemes);
49926
+ const securitySchemes = asRecord4(asRecord4(root.components)?.securitySchemes);
49593
49927
  const requirements = operation.security === void 0 ? asArray2(root.security) : asArray2(operation.security);
49594
49928
  const warnings = /* @__PURE__ */ new Set();
49595
- for (const requirement of requirements.map((entry) => asRecord3(entry)).filter(Boolean)) {
49929
+ for (const requirement of requirements.map((entry) => asRecord4(entry)).filter(Boolean)) {
49596
49930
  for (const schemeName of Object.keys(requirement)) {
49597
49931
  const scheme = resolveInternalRef(root, securitySchemes?.[schemeName]);
49598
49932
  warnings.add(
@@ -49628,24 +49962,24 @@ function collectParameters(root, pathItem, operation) {
49628
49962
  function collectRequestBody(root, operation) {
49629
49963
  const body = resolveInternalRef(root, operation.requestBody);
49630
49964
  if (!body || body.required !== true) return void 0;
49631
- const content = asRecord3(body.content);
49965
+ const content = asRecord4(body.content);
49632
49966
  return {
49633
49967
  required: true,
49634
49968
  contentTypes: content ? Object.keys(content) : []
49635
49969
  };
49636
49970
  }
49637
49971
  function responseContent(root, version, response) {
49638
- const content = asRecord3(response.content);
49972
+ const content = asRecord4(response.content);
49639
49973
  if (!content) return {};
49640
49974
  const media = {};
49641
49975
  for (const [contentType, mediaObject] of Object.entries(content)) {
49642
- const schema2 = asRecord3(mediaObject)?.schema;
49976
+ const schema2 = asRecord4(mediaObject)?.schema;
49643
49977
  media[contentType] = schema2 === void 0 ? {} : packSchema(root, schema2, version);
49644
49978
  }
49645
49979
  return media;
49646
49980
  }
49647
49981
  function responseHeaders(root, version, response) {
49648
- const headers = asRecord3(response.headers);
49982
+ const headers = asRecord4(response.headers);
49649
49983
  if (!headers) return [];
49650
49984
  return Object.entries(headers).map(([name, rawHeader]) => {
49651
49985
  const header = resolveInternalRef(root, rawHeader);
@@ -49660,10 +49994,10 @@ function buildContractIndex(root) {
49660
49994
  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)");
49661
49995
  if (!("openapi" in root)) throw new Error("CONTRACT_UNSUPPORTED_OPENAPI_VERSION: Dynamic contract tests require OpenAPI 3.0 or 3.1 (missing openapi)");
49662
49996
  const version = detectOpenApiVersion(root);
49663
- const paths = asRecord3(root.paths);
49997
+ const paths = asRecord4(root.paths);
49664
49998
  const operations = [];
49665
49999
  const warnings = [];
49666
- if (asRecord3(root.webhooks)) warnings.push("CONTRACT_WEBHOOKS_NOT_VALIDATED: OpenAPI webhooks are not validated by dynamic contract tests");
50000
+ if (asRecord4(root.webhooks)) warnings.push("CONTRACT_WEBHOOKS_NOT_VALIDATED: OpenAPI webhooks are not validated by dynamic contract tests");
49667
50001
  if (paths) {
49668
50002
  for (const [path8, rawPathItem] of Object.entries(paths)) {
49669
50003
  const pathItem = resolveInternalRef(root, rawPathItem);
@@ -49674,7 +50008,7 @@ function buildContractIndex(root) {
49674
50008
  const operation = resolveInternalRef(root, rawOperation);
49675
50009
  if (!operation) continue;
49676
50010
  if (operation.callbacks) warnings.push(`CONTRACT_CALLBACKS_NOT_VALIDATED: callbacks are not validated for ${lowerMethod.toUpperCase()} ${path8}`);
49677
- const responses = asRecord3(operation.responses);
50011
+ const responses = asRecord4(operation.responses);
49678
50012
  if (!responses || Object.keys(responses).length === 0) {
49679
50013
  throw new Error(`CONTRACT_OPERATION_NO_RESPONSES: ${lowerMethod.toUpperCase()} ${path8} must define at least one response`);
49680
50014
  }
@@ -49764,7 +50098,7 @@ var CONTRACT_SIZE_LIMITS = {
49764
50098
  maxTestScriptBytes: 9e5,
49765
50099
  maxCollectionUpdateBytes: 4e6
49766
50100
  };
49767
- function asRecord4(value) {
50101
+ function asRecord5(value) {
49768
50102
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
49769
50103
  return value;
49770
50104
  }
@@ -49773,7 +50107,7 @@ function asArray3(value) {
49773
50107
  }
49774
50108
  function stringifyPathSegment(segment) {
49775
50109
  if (typeof segment === "string") return segment;
49776
- const record = asRecord4(segment);
50110
+ const record = asRecord5(segment);
49777
50111
  if (!record) return String(segment ?? "");
49778
50112
  for (const key of ["value", "key", "name"]) {
49779
50113
  if (typeof record[key] === "string" && record[key]) return String(record[key]);
@@ -49791,10 +50125,10 @@ function pathFromRaw(raw) {
49791
50125
  }
49792
50126
  }
49793
50127
  function requestPath(request) {
49794
- const record = asRecord4(request);
50128
+ const record = asRecord5(request);
49795
50129
  const url = record?.url ?? request;
49796
50130
  if (typeof url === "string") return pathFromRaw(url);
49797
- const urlRecord = asRecord4(url);
50131
+ const urlRecord = asRecord5(url);
49798
50132
  if (!urlRecord) return "/";
49799
50133
  if (Array.isArray(urlRecord.path)) return normalizePath(`/${urlRecord.path.map(stringifyPathSegment).filter(Boolean).join("/")}`);
49800
50134
  if (typeof urlRecord.path === "string") return normalizePath(urlRecord.path);
@@ -49826,7 +50160,7 @@ function matchCandidate(candidate, request) {
49826
50160
  return { matched: true, staticCount, templateCount };
49827
50161
  }
49828
50162
  function matchOperation(index, request) {
49829
- const record = asRecord4(request);
50163
+ const record = asRecord5(request);
49830
50164
  const method = String(record?.method || "").toUpperCase();
49831
50165
  const path8 = requestPath(request);
49832
50166
  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) => {
@@ -49977,17 +50311,17 @@ function createSecretsResolverItem() {
49977
50311
  }
49978
50312
  function isResolverItem(item) {
49979
50313
  if (item.name !== "00 - Resolve Secrets") return false;
49980
- const request = asRecord4(item.request);
50314
+ const request = asRecord5(item.request);
49981
50315
  if (String(request?.method || "").toUpperCase() !== "POST") return false;
49982
- const headers = asArray3(request?.header).map((entry) => asRecord4(entry));
50316
+ const headers = asArray3(request?.header).map((entry) => asRecord5(entry));
49983
50317
  const target = headers.find((entry) => entry?.key === "X-Amz-Target");
49984
50318
  return String(target?.value || "") === "secretsmanager.GetSecretValue" && !requestPath(request).includes("secretsmanager");
49985
50319
  }
49986
50320
  function requestQueryNames(request) {
49987
- const url = asRecord4(request.url);
50321
+ const url = asRecord5(request.url);
49988
50322
  const names = /* @__PURE__ */ new Set();
49989
50323
  if (Array.isArray(url?.query)) {
49990
- for (const entry of url.query.map((item) => asRecord4(item)).filter(Boolean)) {
50324
+ for (const entry of url.query.map((item) => asRecord5(item)).filter(Boolean)) {
49991
50325
  if (entry.disabled !== true && typeof entry.key === "string") names.add(entry.key.toLowerCase());
49992
50326
  }
49993
50327
  }
@@ -50002,17 +50336,17 @@ function requestQueryNames(request) {
50002
50336
  }
50003
50337
  function requestHeaderNames(request) {
50004
50338
  const names = /* @__PURE__ */ new Set();
50005
- for (const entry of asArray3(request.header).map((item) => asRecord4(item)).filter(Boolean)) {
50339
+ for (const entry of asArray3(request.header).map((item) => asRecord5(item)).filter(Boolean)) {
50006
50340
  if (entry.disabled !== true && typeof entry.key === "string") names.add(entry.key.toLowerCase());
50007
50341
  }
50008
50342
  return names;
50009
50343
  }
50010
50344
  function requestHeaderValue(request, name) {
50011
- const match = asArray3(request.header).map((item) => asRecord4(item)).filter(Boolean).find((entry) => String(entry.key || "").toLowerCase() === name.toLowerCase() && entry.disabled !== true);
50345
+ const match = asArray3(request.header).map((item) => asRecord5(item)).filter(Boolean).find((entry) => String(entry.key || "").toLowerCase() === name.toLowerCase() && entry.disabled !== true);
50012
50346
  return typeof match?.value === "string" ? match.value : void 0;
50013
50347
  }
50014
50348
  function hasRequestBody(request) {
50015
- const body = asRecord4(request.body);
50349
+ const body = asRecord5(request.body);
50016
50350
  if (!body) return false;
50017
50351
  if (typeof body.raw === "string" && body.raw.trim()) return true;
50018
50352
  return ["urlencoded", "formdata", "graphql"].some((key) => Array.isArray(body[key]) ? body[key].length > 0 : Boolean(body[key]));
@@ -50063,21 +50397,21 @@ function validateScript(script) {
50063
50397
  return void 0;
50064
50398
  }
50065
50399
  function scriptExecLines(script) {
50066
- const record = asRecord4(script);
50400
+ const record = asRecord5(script);
50067
50401
  if (!record) return [];
50068
50402
  if (Array.isArray(record.exec)) return record.exec.map((line) => String(line));
50069
50403
  if (typeof record.exec === "string") return [record.exec];
50070
50404
  return [];
50071
50405
  }
50072
50406
  function scanExecutableScripts(node, warnings) {
50073
- for (const event of asArray3(node.event).map((entry) => asRecord4(entry)).filter(Boolean)) {
50407
+ for (const event of asArray3(node.event).map((entry) => asRecord5(entry)).filter(Boolean)) {
50074
50408
  const lines = scriptExecLines(event.script);
50075
50409
  if (lines.length === 0) continue;
50076
50410
  const warning2 = validateScript(lines);
50077
50411
  if (warning2) warnings.push(warning2);
50078
50412
  }
50079
50413
  for (const child2 of asArray3(node.item)) {
50080
- const childRecord = asRecord4(child2);
50414
+ const childRecord = asRecord5(child2);
50081
50415
  if (childRecord) scanExecutableScripts(childRecord, warnings);
50082
50416
  }
50083
50417
  }
@@ -50087,7 +50421,7 @@ function instrumentContractCollection(collection, index) {
50087
50421
  const inject = (item) => {
50088
50422
  if (isResolverItem(item)) return;
50089
50423
  if (item.request) {
50090
- const request = asRecord4(item.request) ?? {};
50424
+ const request = asRecord5(item.request) ?? {};
50091
50425
  const result = matchOperation(index, request);
50092
50426
  let script;
50093
50427
  if (result.operation) {
@@ -50101,15 +50435,15 @@ function instrumentContractCollection(collection, index) {
50101
50435
  } else {
50102
50436
  script = createMappingFailureScript(`No OpenAPI operation matched request ${result.method} ${result.path}`);
50103
50437
  }
50104
- const events2 = asArray3(item.event).filter((entry) => asRecord4(entry)?.listen !== "test");
50438
+ const events2 = asArray3(item.event).filter((entry) => asRecord5(entry)?.listen !== "test");
50105
50439
  item.event = [...events2, { listen: "test", script: { type: "text/javascript", exec: script } }];
50106
50440
  }
50107
50441
  for (const child2 of asArray3(item.item)) {
50108
- const childRecord = asRecord4(child2);
50442
+ const childRecord = asRecord5(child2);
50109
50443
  if (childRecord) inject(childRecord);
50110
50444
  }
50111
50445
  };
50112
- const items = asArray3(collection.item).map((entry) => asRecord4(entry)).filter((entry) => Boolean(entry)).filter((entry) => !isResolverItem(entry));
50446
+ const items = asArray3(collection.item).map((entry) => asRecord5(entry)).filter((entry) => Boolean(entry)).filter((entry) => !isResolverItem(entry));
50113
50447
  collection.item = items;
50114
50448
  for (const item of items) inject(item);
50115
50449
  const missing = index.operations.filter((operation) => !covered.has(operation.id));
@@ -62473,7 +62807,7 @@ function compileErrors(result) {
62473
62807
 
62474
62808
  // src/lib/spec/openapi-loader.ts
62475
62809
  var import_yaml2 = __toESM(require_dist(), 1);
62476
- function asRecord5(value) {
62810
+ function asRecord6(value) {
62477
62811
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
62478
62812
  return value;
62479
62813
  }
@@ -62488,7 +62822,7 @@ function parseOpenApiDocument(content) {
62488
62822
  throw new Error("CONTRACT_SPEC_PARSE_FAILED: Spec content is not valid JSON or YAML");
62489
62823
  }
62490
62824
  }
62491
- const doc = asRecord5(parsed);
62825
+ const doc = asRecord6(parsed);
62492
62826
  if (!doc) throw new Error("CONTRACT_SPEC_PARSE_FAILED: Spec content must be a JSON or YAML object");
62493
62827
  return doc;
62494
62828
  }
@@ -62516,7 +62850,7 @@ function collectExternalRefs(node, baseUrl, refs) {
62516
62850
  node.forEach((entry) => collectExternalRefs(entry, baseUrl, refs));
62517
62851
  return;
62518
62852
  }
62519
- const record = asRecord5(node);
62853
+ const record = asRecord6(node);
62520
62854
  if (!record) return;
62521
62855
  const ref = typeof record.$ref === "string" ? record.$ref : "";
62522
62856
  if (ref && !ref.startsWith("#")) {
@@ -62854,6 +63188,11 @@ function resolveInputs(env = process.env) {
62854
63188
  governanceMappingJson: parseGovernanceMappingJson(getInput2("governance-mapping-json", env)),
62855
63189
  postmanApiKey: getInput2("postman-api-key", env) ?? "",
62856
63190
  postmanAccessToken: getInput2("postman-access-token", env),
63191
+ credentialPreflight: parseEnumInput(
63192
+ "credential-preflight",
63193
+ getInput2("credential-preflight", env),
63194
+ customerPreviewActionContract.inputs["credential-preflight"].default ?? "warn"
63195
+ ),
62857
63196
  integrationBackend,
62858
63197
  folderStrategy: parseEnumInput("folder-strategy", getInput2("folder-strategy", env), "Paths"),
62859
63198
  nestedFolderHierarchy: parseBooleanInput("nested-folder-hierarchy", getInput2("nested-folder-hierarchy", env), false),
@@ -62863,6 +63202,7 @@ function resolveInputs(env = process.env) {
62863
63202
  postmanBifrostBase: endpointProfile.bifrostBaseUrl,
62864
63203
  postmanGatewayBase: endpointProfile.gatewayBaseUrl,
62865
63204
  postmanCliInstallUrl: endpointProfile.cliInstallUrl,
63205
+ postmanIapubBase: endpointProfile.iapubBaseUrl,
62866
63206
  githubRefName: env.GITHUB_REF_NAME,
62867
63207
  githubHeadRef: env.GITHUB_HEAD_REF,
62868
63208
  githubRef: env.GITHUB_REF,
@@ -62951,6 +63291,7 @@ function readActionInputs(actionCore) {
62951
63291
  INPUT_GOVERNANCE_MAPPING_JSON: optionalInput(actionCore, "governance-mapping-json") ?? customerPreviewActionContract.inputs["governance-mapping-json"].default,
62952
63292
  INPUT_POSTMAN_API_KEY: postmanApiKey,
62953
63293
  INPUT_POSTMAN_ACCESS_TOKEN: postmanAccessToken,
63294
+ INPUT_CREDENTIAL_PREFLIGHT: optionalInput(actionCore, "credential-preflight") ?? customerPreviewActionContract.inputs["credential-preflight"].default,
62954
63295
  INPUT_INTEGRATION_BACKEND: optionalInput(actionCore, "integration-backend") ?? customerPreviewActionContract.inputs["integration-backend"].default,
62955
63296
  INPUT_FOLDER_STRATEGY: optionalInput(actionCore, "folder-strategy") ?? customerPreviewActionContract.inputs["folder-strategy"].default,
62956
63297
  INPUT_NESTED_FOLDER_HIERARCHY: optionalInput(actionCore, "nested-folder-hierarchy") ?? customerPreviewActionContract.inputs["nested-folder-hierarchy"].default,
@@ -63462,8 +63803,20 @@ For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID
63462
63803
  governanceGroupName
63463
63804
  );
63464
63805
  } catch (error2) {
63806
+ const session = getMemoizedSessionIdentity();
63807
+ const advised = error2 instanceof HttpError ? adviseFromHttpError(error2, {
63808
+ operation: "governance assignment",
63809
+ hasAccessToken: Boolean(inputs.postmanAccessToken),
63810
+ sessionTeamId: session?.teamId,
63811
+ sessionRoles: session?.roles,
63812
+ sessionConsumerType: session?.consumerType,
63813
+ workspaceTeamId: inputs.workspaceTeamId,
63814
+ explicitTeamId: inputs.teamId || void 0,
63815
+ mask: createSecretMasker([inputs.postmanApiKey, inputs.postmanAccessToken])
63816
+ }) : void 0;
63817
+ const reported = advised ?? error2;
63465
63818
  dependencies.core.warning(
63466
- `Failed to assign governance group: ${error2 instanceof Error ? error2.message : String(error2)}`
63819
+ `Failed to assign governance group: ${reported instanceof Error ? reported.message : String(reported)}`
63467
63820
  );
63468
63821
  }
63469
63822
  }
@@ -64050,6 +64403,17 @@ For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID
64050
64403
  }
64051
64404
  async function runAction(actionCore = core_exports, actionExec = exec_exports, actionIo = io_exports) {
64052
64405
  const inputs = readActionInputs(actionCore);
64406
+ await runCredentialPreflight({
64407
+ apiBaseUrl: inputs.postmanApiBase,
64408
+ iapubBaseUrl: inputs.postmanIapubBase,
64409
+ postmanApiKey: inputs.postmanApiKey,
64410
+ postmanAccessToken: inputs.postmanAccessToken,
64411
+ workspaceTeamId: inputs.workspaceTeamId,
64412
+ explicitTeamId: inputs.teamId || void 0,
64413
+ mode: inputs.credentialPreflight,
64414
+ mask: createSecretMasker([inputs.postmanApiKey, inputs.postmanAccessToken]),
64415
+ log: actionCore
64416
+ });
64053
64417
  let orgMode = false;
64054
64418
  if (inputs.postmanAccessToken && inputs.teamId) {
64055
64419
  try {