@postman-cse/onboarding-bootstrap 0.14.2 → 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,34 +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
- );
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
- );
48336
+ if (err instanceof Error) {
48337
+ const advised = adviseFromWorkspaceCreateError(err, targetTeamId);
48338
+ if (advised) {
48339
+ throw advised;
48340
+ }
48034
48341
  }
48035
48342
  throw err;
48036
48343
  }
48037
- const createdWorkspace = asRecord(created?.workspace);
48344
+ const createdWorkspace = asRecord2(created?.workspace);
48038
48345
  const workspaceId = String(createdWorkspace?.id || "").trim();
48039
48346
  if (!workspaceId) {
48040
48347
  throw new Error("Workspace create did not return an id");
48041
48348
  }
48042
48349
  const workspace = await this.request(`/workspaces/${workspaceId}`);
48043
- let visibility = asRecord(workspace?.workspace)?.visibility;
48350
+ let visibility = asRecord2(workspace?.workspace)?.visibility;
48044
48351
  if (visibility !== "team") {
48045
48352
  await this.request(`/workspaces/${workspaceId}`, {
48046
48353
  method: "PUT",
48047
48354
  body: JSON.stringify(payload)
48048
48355
  });
48049
48356
  const reread = await this.request(`/workspaces/${workspaceId}`);
48050
- visibility = asRecord(reread?.workspace)?.visibility;
48357
+ visibility = asRecord2(reread?.workspace)?.visibility;
48051
48358
  }
48052
48359
  if (typeof visibility === "string" && visibility !== "team") {
48053
48360
  let cleanedUp = false;
@@ -48076,7 +48383,7 @@ var PostmanAssetsClient = class {
48076
48383
  async getWorkspaceVisibility(workspaceId) {
48077
48384
  try {
48078
48385
  const workspace = await this.request(`/workspaces/${workspaceId}`);
48079
- const visibility = asRecord(workspace?.workspace)?.visibility;
48386
+ const visibility = asRecord2(workspace?.workspace)?.visibility;
48080
48387
  return typeof visibility === "string" ? visibility : null;
48081
48388
  } catch {
48082
48389
  return null;
@@ -48098,7 +48405,7 @@ var PostmanAssetsClient = class {
48098
48405
  nextCursor = page.nextCursor;
48099
48406
  }
48100
48407
  } while (nextCursor);
48101
- 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) => ({
48102
48409
  id: String(workspace.id),
48103
48410
  name: String(workspace.name),
48104
48411
  type: String(workspace.type ?? "team")
@@ -48146,7 +48453,7 @@ var PostmanAssetsClient = class {
48146
48453
  async inviteRequesterToWorkspace(workspaceId, email) {
48147
48454
  const users = await this.request("/users");
48148
48455
  const userList = Array.isArray(users?.data) ? users.data : [];
48149
- 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);
48150
48457
  if (!user?.id) {
48151
48458
  return;
48152
48459
  }
@@ -48234,12 +48541,12 @@ var PostmanAssetsClient = class {
48234
48541
  }
48235
48542
  };
48236
48543
  const extractUid = (data) => {
48237
- const root = asRecord(data);
48238
- const details = asRecord(root?.details);
48544
+ const root = asRecord2(data);
48545
+ const details = asRecord2(root?.details);
48239
48546
  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);
48547
+ const firstResource = asRecord2(resources[0]);
48548
+ const collection = asRecord2(root?.collection);
48549
+ const resource = asRecord2(root?.resource);
48243
48550
  return String(
48244
48551
  firstResource?.id ?? collection?.id ?? collection?.uid ?? resource?.uid ?? resource?.id ?? ""
48245
48552
  ).trim() || void 0;
@@ -48273,9 +48580,9 @@ var PostmanAssetsClient = class {
48273
48580
  if (directUid) {
48274
48581
  return directUid;
48275
48582
  }
48276
- 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 ?? "");
48277
48584
  if (!taskUrl) {
48278
- const task = asRecord(generationResponse?.task);
48585
+ const task = asRecord2(generationResponse?.task);
48279
48586
  const taskId = generationResponse?.taskId || task?.id || generationResponse?.id;
48280
48587
  if (!taskId) {
48281
48588
  throw new Error(
@@ -48289,8 +48596,8 @@ var PostmanAssetsClient = class {
48289
48596
  setTimeout(resolve4, 2e3);
48290
48597
  });
48291
48598
  const task = await this.request(taskUrl);
48292
- const taskRecord = asRecord(task);
48293
- const taskNested = asRecord(taskRecord?.task);
48599
+ const taskRecord = asRecord2(task);
48600
+ const taskNested = asRecord2(taskRecord?.task);
48294
48601
  const status = String(taskRecord?.status || taskNested?.status || "").toLowerCase();
48295
48602
  if (status === "completed") {
48296
48603
  const taskUid = extractUid(task);
@@ -48321,7 +48628,7 @@ var PostmanAssetsClient = class {
48321
48628
  }
48322
48629
  async injectTests(collectionUid, type2) {
48323
48630
  const collectionResponse = await this.request(`/collections/${collectionUid}`);
48324
- const collection = asRecord(collectionResponse?.collection);
48631
+ const collection = asRecord2(collectionResponse?.collection);
48325
48632
  if (!collection) {
48326
48633
  throw new Error(`Failed to fetch collection ${collectionUid}`);
48327
48634
  }
@@ -48407,7 +48714,7 @@ var PostmanAssetsClient = class {
48407
48714
  });
48408
48715
  }
48409
48716
  if (Array.isArray(itemNode.item)) {
48410
- 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);
48411
48718
  }
48412
48719
  };
48413
48720
  if (Array.isArray(collection.item)) {
@@ -48435,7 +48742,7 @@ var PostmanAssetsClient = class {
48435
48742
  }
48436
48743
  })
48437
48744
  });
48438
- const environment = asRecord(response?.environment);
48745
+ const environment = asRecord2(response?.environment);
48439
48746
  const uid = String(environment?.uid || "").trim();
48440
48747
  if (!uid) {
48441
48748
  throw new Error("Environment create did not return a UID");
@@ -48468,7 +48775,7 @@ var PostmanAssetsClient = class {
48468
48775
  }
48469
48776
  })
48470
48777
  });
48471
- const monitor = asRecord(response?.monitor);
48778
+ const monitor = asRecord2(response?.monitor);
48472
48779
  const uid = String(monitor?.uid || "").trim();
48473
48780
  if (!uid) {
48474
48781
  throw new Error("Monitor create did not return a UID");
@@ -48487,8 +48794,8 @@ var PostmanAssetsClient = class {
48487
48794
  }
48488
48795
  })
48489
48796
  });
48490
- const mock = asRecord(response?.mock);
48491
- const mockConfig = asRecord(mock?.config);
48797
+ const mock = asRecord2(response?.mock);
48798
+ const mockConfig = asRecord2(mock?.config);
48492
48799
  const uid = String(mock?.uid || "").trim();
48493
48800
  if (!uid) {
48494
48801
  throw new Error("Mock create did not return a UID");
@@ -48559,6 +48866,18 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48559
48866
  this.teamId = String(teamId || "").trim();
48560
48867
  this.orgMode = orgMode;
48561
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
+ }
48562
48881
  async proxyRequest(service, method, requestPath2, body, options = {}) {
48563
48882
  const url = `${this.bifrostBaseUrl}/ws/proxy`;
48564
48883
  const headers = {
@@ -48625,7 +48944,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48625
48944
  { appVersion, query: { tag: "governance" } }
48626
48945
  );
48627
48946
  if (!listResponse.ok) {
48628
- throw await HttpError.fromResponse(listResponse, {
48947
+ const httpErr = await HttpError.fromResponse(listResponse, {
48629
48948
  method: "GET",
48630
48949
  requestHeaders: {
48631
48950
  "Content-Type": "application/json",
@@ -48636,6 +48955,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48636
48955
  secretValues: [this.accessToken],
48637
48956
  url: `${this.bifrostBaseUrl}/ws/proxy`
48638
48957
  });
48958
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("governance assignment"));
48959
+ throw advised ?? httpErr;
48639
48960
  }
48640
48961
  const groups = await listResponse.json();
48641
48962
  const group2 = (groups.workspaceGroups ?? groups.data)?.find(
@@ -48661,7 +48982,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48661
48982
  { appVersion }
48662
48983
  );
48663
48984
  if (!patchResponse.ok) {
48664
- throw await HttpError.fromResponse(patchResponse, {
48985
+ const httpErr = await HttpError.fromResponse(patchResponse, {
48665
48986
  method: "PATCH",
48666
48987
  requestHeaders: {
48667
48988
  "Content-Type": "application/json",
@@ -48672,6 +48993,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48672
48993
  secretValues: [this.accessToken],
48673
48994
  url: `${this.bifrostBaseUrl}/ws/proxy`
48674
48995
  });
48996
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("governance assignment"));
48997
+ throw advised ?? httpErr;
48675
48998
  }
48676
48999
  }
48677
49000
  async connectWorkspaceToRepository(workspaceId, repoUrl) {
@@ -48705,7 +49028,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48705
49028
  );
48706
49029
  }
48707
49030
  }
48708
- throw await HttpError.fromResponse(response, {
49031
+ const httpErr = await HttpError.fromResponse(response, {
48709
49032
  method: "POST",
48710
49033
  requestHeaders: {
48711
49034
  "Content-Type": "application/json",
@@ -48715,6 +49038,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48715
49038
  secretValues: [this.accessToken],
48716
49039
  url: `${this.bifrostBaseUrl}/ws/proxy`
48717
49040
  });
49041
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("workspace repository linking"));
49042
+ throw advised ?? httpErr;
48718
49043
  }
48719
49044
  async linkCollectionsToSpecification(specificationId, collections) {
48720
49045
  if (collections.length === 0) {
@@ -48732,7 +49057,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48732
49057
  if (response.ok) {
48733
49058
  return;
48734
49059
  }
48735
- throw await HttpError.fromResponse(response, {
49060
+ const httpErr = await HttpError.fromResponse(response, {
48736
49061
  method: "POST",
48737
49062
  requestHeaders: {
48738
49063
  "Content-Type": "application/json",
@@ -48742,6 +49067,11 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48742
49067
  secretValues: [this.accessToken],
48743
49068
  url: `${this.bifrostBaseUrl}/ws/proxy`
48744
49069
  });
49070
+ const advised = adviseFromHttpError(
49071
+ httpErr,
49072
+ this.adviceContext("collection-to-specification linking")
49073
+ );
49074
+ throw advised ?? httpErr;
48745
49075
  }
48746
49076
  async syncCollection(specificationId, collectionId) {
48747
49077
  const response = await this.proxyRequest(
@@ -48752,7 +49082,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48752
49082
  if (response.ok) {
48753
49083
  return;
48754
49084
  }
48755
- throw await HttpError.fromResponse(response, {
49085
+ const httpErr = await HttpError.fromResponse(response, {
48756
49086
  method: "POST",
48757
49087
  requestHeaders: {
48758
49088
  "Content-Type": "application/json",
@@ -48762,6 +49092,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48762
49092
  secretValues: [this.accessToken],
48763
49093
  url: `${this.bifrostBaseUrl}/ws/proxy`
48764
49094
  });
49095
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("collection sync"));
49096
+ throw advised ?? httpErr;
48765
49097
  }
48766
49098
  async getWorkspaceGitRepoUrl(workspaceId) {
48767
49099
  const response = await this.proxyRequest(
@@ -49335,7 +49667,7 @@ var STRIP_KEYS = /* @__PURE__ */ new Set([
49335
49667
  "discriminator",
49336
49668
  "format"
49337
49669
  ]);
49338
- function asRecord2(value) {
49670
+ function asRecord3(value) {
49339
49671
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
49340
49672
  return value;
49341
49673
  }
@@ -49347,7 +49679,7 @@ function decodePointerSegment(segment) {
49347
49679
  }
49348
49680
  function resolvePointer(root, ref) {
49349
49681
  if (!ref.startsWith("#/")) return void 0;
49350
- 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);
49351
49683
  }
49352
49684
  function unsupported(message) {
49353
49685
  return { unsupported: message };
@@ -49357,7 +49689,7 @@ function mergeRequiredWithoutWriteOnly(required, writeOnlyProperties) {
49357
49689
  return values.length > 0 ? values : void 0;
49358
49690
  }
49359
49691
  function hasUnsupported(child2) {
49360
- return asRecord2(child2)?.unsupported;
49692
+ return asRecord3(child2)?.unsupported;
49361
49693
  }
49362
49694
  function rootDialect(root, version, schemaRecord) {
49363
49695
  if (version === "3.0") return DRAFT_07_SCHEMA_URI;
@@ -49377,7 +49709,7 @@ function normalizeSchema(root, schema2, options) {
49377
49709
  const bad = normalized2.map(hasUnsupported).find(Boolean);
49378
49710
  return bad ? unsupported(bad) : normalized2;
49379
49711
  }
49380
- const record = asRecord2(schema2);
49712
+ const record = asRecord3(schema2);
49381
49713
  if (!record) return schema2;
49382
49714
  const ref = typeof record.$ref === "string" ? record.$ref : "";
49383
49715
  if (ref) {
@@ -49412,10 +49744,10 @@ function normalizeSchema(root, schema2, options) {
49412
49744
  const nullable = sourceSchema.nullable === true && options.version === "3.0";
49413
49745
  delete sourceSchema.nullable;
49414
49746
  const writeOnlyProperties = /* @__PURE__ */ new Set();
49415
- const rawProperties = asRecord2(sourceSchema.properties);
49747
+ const rawProperties = asRecord3(sourceSchema.properties);
49416
49748
  if (rawProperties) {
49417
49749
  for (const [propertyName, propertySchema] of Object.entries(rawProperties)) {
49418
- if (asRecord2(propertySchema)?.writeOnly === true) writeOnlyProperties.add(propertyName);
49750
+ if (asRecord3(propertySchema)?.writeOnly === true) writeOnlyProperties.add(propertyName);
49419
49751
  }
49420
49752
  }
49421
49753
  const normalized = {};
@@ -49447,7 +49779,7 @@ function normalizeSchema(root, schema2, options) {
49447
49779
  return unsupported("Tuple array items are unsupported in OpenAPI 3.0");
49448
49780
  }
49449
49781
  if (key === "properties") {
49450
- const properties = asRecord2(value);
49782
+ const properties = asRecord3(value);
49451
49783
  if (!properties) continue;
49452
49784
  const nextProperties = {};
49453
49785
  for (const [propertyName, propertySchema] of Object.entries(properties)) {
@@ -49490,7 +49822,7 @@ function normalizeSchema(root, schema2, options) {
49490
49822
  }
49491
49823
  function packSchema(root, schema2, version) {
49492
49824
  try {
49493
- const dialect = rootDialect(root, version, asRecord2(schema2) ?? void 0);
49825
+ const dialect = rootDialect(root, version, asRecord3(schema2) ?? void 0);
49494
49826
  const normalized = normalizeSchema(root, schema2, { version, rootSchema: true, dialect });
49495
49827
  const message = hasUnsupported(normalized);
49496
49828
  return message ? unsupported(message) : { schema: normalized };
@@ -49501,7 +49833,7 @@ function packSchema(root, schema2, version) {
49501
49833
 
49502
49834
  // src/lib/spec/contract-index.ts
49503
49835
  var HTTP_METHODS = /* @__PURE__ */ new Set(["get", "put", "post", "delete", "options", "head", "patch", "trace"]);
49504
- function asRecord3(value) {
49836
+ function asRecord4(value) {
49505
49837
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
49506
49838
  return value;
49507
49839
  }
@@ -49518,12 +49850,12 @@ function detectOpenApiVersion(root) {
49518
49850
  return match[1] === "1" ? "3.1" : "3.0";
49519
49851
  }
49520
49852
  function resolveInternalRef(root, value) {
49521
- const record = asRecord3(value);
49853
+ const record = asRecord4(value);
49522
49854
  if (!record) return null;
49523
49855
  const ref = typeof record.$ref === "string" ? record.$ref : "";
49524
49856
  if (!ref) return record;
49525
49857
  if (!ref.startsWith("#/")) throw new Error(`CONTRACT_UNRESOLVED_REF: External ref remained after bundling: ${ref}`);
49526
- const resolved = asRecord3(resolvePointer(root, ref));
49858
+ const resolved = asRecord4(resolvePointer(root, ref));
49527
49859
  if (!resolved) throw new Error(`CONTRACT_UNRESOLVED_REF: Unresolved OpenAPI $ref: ${ref}`);
49528
49860
  return resolved;
49529
49861
  }
@@ -49543,11 +49875,11 @@ function normalizePath(path8) {
49543
49875
  return trimmed.split("/").map((segment, index) => index === 0 ? "" : safeDecodeSegment(segment)).join("/") || "/";
49544
49876
  }
49545
49877
  function pathItemServers(pathItem) {
49546
- 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);
49547
49879
  }
49548
49880
  function operationServers(root, pathItem, operation) {
49549
49881
  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);
49882
+ const values = rawServers.map((entry) => asRecord4(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
49551
49883
  return values.length > 0 ? values : [""];
49552
49884
  }
49553
49885
  function serverPathPrefix(url) {
@@ -49568,10 +49900,10 @@ function normalizeResponseKey(status) {
49568
49900
  return /^[1-5]xx$/i.test(raw) ? raw.toUpperCase() : raw;
49569
49901
  }
49570
49902
  function collectSecurityApiKeys(root, operation) {
49571
- const securitySchemes = asRecord3(asRecord3(root.components)?.securitySchemes);
49903
+ const securitySchemes = asRecord4(asRecord4(root.components)?.securitySchemes);
49572
49904
  const requirements = operation.security === void 0 ? asArray2(root.security) : asArray2(operation.security);
49573
49905
  const names = /* @__PURE__ */ new Set();
49574
- for (const requirement of requirements.map((entry) => asRecord3(entry)).filter(Boolean)) {
49906
+ for (const requirement of requirements.map((entry) => asRecord4(entry)).filter(Boolean)) {
49575
49907
  for (const schemeName of Object.keys(requirement)) {
49576
49908
  const scheme = resolveInternalRef(root, securitySchemes?.[schemeName]);
49577
49909
  if (scheme?.type === "apiKey" && typeof scheme.name === "string" && ["query", "header"].includes(String(scheme.in))) {
@@ -49589,10 +49921,10 @@ function securitySchemeKind(scheme) {
49589
49921
  return type2;
49590
49922
  }
49591
49923
  function collectSecuritySchemeWarnings(root, operation) {
49592
- const securitySchemes = asRecord3(asRecord3(root.components)?.securitySchemes);
49924
+ const securitySchemes = asRecord4(asRecord4(root.components)?.securitySchemes);
49593
49925
  const requirements = operation.security === void 0 ? asArray2(root.security) : asArray2(operation.security);
49594
49926
  const warnings = /* @__PURE__ */ new Set();
49595
- for (const requirement of requirements.map((entry) => asRecord3(entry)).filter(Boolean)) {
49927
+ for (const requirement of requirements.map((entry) => asRecord4(entry)).filter(Boolean)) {
49596
49928
  for (const schemeName of Object.keys(requirement)) {
49597
49929
  const scheme = resolveInternalRef(root, securitySchemes?.[schemeName]);
49598
49930
  warnings.add(
@@ -49628,24 +49960,24 @@ function collectParameters(root, pathItem, operation) {
49628
49960
  function collectRequestBody(root, operation) {
49629
49961
  const body = resolveInternalRef(root, operation.requestBody);
49630
49962
  if (!body || body.required !== true) return void 0;
49631
- const content = asRecord3(body.content);
49963
+ const content = asRecord4(body.content);
49632
49964
  return {
49633
49965
  required: true,
49634
49966
  contentTypes: content ? Object.keys(content) : []
49635
49967
  };
49636
49968
  }
49637
49969
  function responseContent(root, version, response) {
49638
- const content = asRecord3(response.content);
49970
+ const content = asRecord4(response.content);
49639
49971
  if (!content) return {};
49640
49972
  const media = {};
49641
49973
  for (const [contentType, mediaObject] of Object.entries(content)) {
49642
- const schema2 = asRecord3(mediaObject)?.schema;
49974
+ const schema2 = asRecord4(mediaObject)?.schema;
49643
49975
  media[contentType] = schema2 === void 0 ? {} : packSchema(root, schema2, version);
49644
49976
  }
49645
49977
  return media;
49646
49978
  }
49647
49979
  function responseHeaders(root, version, response) {
49648
- const headers = asRecord3(response.headers);
49980
+ const headers = asRecord4(response.headers);
49649
49981
  if (!headers) return [];
49650
49982
  return Object.entries(headers).map(([name, rawHeader]) => {
49651
49983
  const header = resolveInternalRef(root, rawHeader);
@@ -49660,10 +49992,10 @@ function buildContractIndex(root) {
49660
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)");
49661
49993
  if (!("openapi" in root)) throw new Error("CONTRACT_UNSUPPORTED_OPENAPI_VERSION: Dynamic contract tests require OpenAPI 3.0 or 3.1 (missing openapi)");
49662
49994
  const version = detectOpenApiVersion(root);
49663
- const paths = asRecord3(root.paths);
49995
+ const paths = asRecord4(root.paths);
49664
49996
  const operations = [];
49665
49997
  const warnings = [];
49666
- 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");
49667
49999
  if (paths) {
49668
50000
  for (const [path8, rawPathItem] of Object.entries(paths)) {
49669
50001
  const pathItem = resolveInternalRef(root, rawPathItem);
@@ -49674,7 +50006,7 @@ function buildContractIndex(root) {
49674
50006
  const operation = resolveInternalRef(root, rawOperation);
49675
50007
  if (!operation) continue;
49676
50008
  if (operation.callbacks) warnings.push(`CONTRACT_CALLBACKS_NOT_VALIDATED: callbacks are not validated for ${lowerMethod.toUpperCase()} ${path8}`);
49677
- const responses = asRecord3(operation.responses);
50009
+ const responses = asRecord4(operation.responses);
49678
50010
  if (!responses || Object.keys(responses).length === 0) {
49679
50011
  throw new Error(`CONTRACT_OPERATION_NO_RESPONSES: ${lowerMethod.toUpperCase()} ${path8} must define at least one response`);
49680
50012
  }
@@ -49764,7 +50096,7 @@ var CONTRACT_SIZE_LIMITS = {
49764
50096
  maxTestScriptBytes: 9e5,
49765
50097
  maxCollectionUpdateBytes: 4e6
49766
50098
  };
49767
- function asRecord4(value) {
50099
+ function asRecord5(value) {
49768
50100
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
49769
50101
  return value;
49770
50102
  }
@@ -49773,7 +50105,7 @@ function asArray3(value) {
49773
50105
  }
49774
50106
  function stringifyPathSegment(segment) {
49775
50107
  if (typeof segment === "string") return segment;
49776
- const record = asRecord4(segment);
50108
+ const record = asRecord5(segment);
49777
50109
  if (!record) return String(segment ?? "");
49778
50110
  for (const key of ["value", "key", "name"]) {
49779
50111
  if (typeof record[key] === "string" && record[key]) return String(record[key]);
@@ -49791,10 +50123,10 @@ function pathFromRaw(raw) {
49791
50123
  }
49792
50124
  }
49793
50125
  function requestPath(request) {
49794
- const record = asRecord4(request);
50126
+ const record = asRecord5(request);
49795
50127
  const url = record?.url ?? request;
49796
50128
  if (typeof url === "string") return pathFromRaw(url);
49797
- const urlRecord = asRecord4(url);
50129
+ const urlRecord = asRecord5(url);
49798
50130
  if (!urlRecord) return "/";
49799
50131
  if (Array.isArray(urlRecord.path)) return normalizePath(`/${urlRecord.path.map(stringifyPathSegment).filter(Boolean).join("/")}`);
49800
50132
  if (typeof urlRecord.path === "string") return normalizePath(urlRecord.path);
@@ -49826,7 +50158,7 @@ function matchCandidate(candidate, request) {
49826
50158
  return { matched: true, staticCount, templateCount };
49827
50159
  }
49828
50160
  function matchOperation(index, request) {
49829
- const record = asRecord4(request);
50161
+ const record = asRecord5(request);
49830
50162
  const method = String(record?.method || "").toUpperCase();
49831
50163
  const path8 = requestPath(request);
49832
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) => {
@@ -49977,17 +50309,17 @@ function createSecretsResolverItem() {
49977
50309
  }
49978
50310
  function isResolverItem(item) {
49979
50311
  if (item.name !== "00 - Resolve Secrets") return false;
49980
- const request = asRecord4(item.request);
50312
+ const request = asRecord5(item.request);
49981
50313
  if (String(request?.method || "").toUpperCase() !== "POST") return false;
49982
- const headers = asArray3(request?.header).map((entry) => asRecord4(entry));
50314
+ const headers = asArray3(request?.header).map((entry) => asRecord5(entry));
49983
50315
  const target = headers.find((entry) => entry?.key === "X-Amz-Target");
49984
50316
  return String(target?.value || "") === "secretsmanager.GetSecretValue" && !requestPath(request).includes("secretsmanager");
49985
50317
  }
49986
50318
  function requestQueryNames(request) {
49987
- const url = asRecord4(request.url);
50319
+ const url = asRecord5(request.url);
49988
50320
  const names = /* @__PURE__ */ new Set();
49989
50321
  if (Array.isArray(url?.query)) {
49990
- 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)) {
49991
50323
  if (entry.disabled !== true && typeof entry.key === "string") names.add(entry.key.toLowerCase());
49992
50324
  }
49993
50325
  }
@@ -50002,17 +50334,17 @@ function requestQueryNames(request) {
50002
50334
  }
50003
50335
  function requestHeaderNames(request) {
50004
50336
  const names = /* @__PURE__ */ new Set();
50005
- 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)) {
50006
50338
  if (entry.disabled !== true && typeof entry.key === "string") names.add(entry.key.toLowerCase());
50007
50339
  }
50008
50340
  return names;
50009
50341
  }
50010
50342
  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);
50343
+ const match = asArray3(request.header).map((item) => asRecord5(item)).filter(Boolean).find((entry) => String(entry.key || "").toLowerCase() === name.toLowerCase() && entry.disabled !== true);
50012
50344
  return typeof match?.value === "string" ? match.value : void 0;
50013
50345
  }
50014
50346
  function hasRequestBody(request) {
50015
- const body = asRecord4(request.body);
50347
+ const body = asRecord5(request.body);
50016
50348
  if (!body) return false;
50017
50349
  if (typeof body.raw === "string" && body.raw.trim()) return true;
50018
50350
  return ["urlencoded", "formdata", "graphql"].some((key) => Array.isArray(body[key]) ? body[key].length > 0 : Boolean(body[key]));
@@ -50063,21 +50395,21 @@ function validateScript(script) {
50063
50395
  return void 0;
50064
50396
  }
50065
50397
  function scriptExecLines(script) {
50066
- const record = asRecord4(script);
50398
+ const record = asRecord5(script);
50067
50399
  if (!record) return [];
50068
50400
  if (Array.isArray(record.exec)) return record.exec.map((line) => String(line));
50069
50401
  if (typeof record.exec === "string") return [record.exec];
50070
50402
  return [];
50071
50403
  }
50072
50404
  function scanExecutableScripts(node, warnings) {
50073
- 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)) {
50074
50406
  const lines = scriptExecLines(event.script);
50075
50407
  if (lines.length === 0) continue;
50076
50408
  const warning2 = validateScript(lines);
50077
50409
  if (warning2) warnings.push(warning2);
50078
50410
  }
50079
50411
  for (const child2 of asArray3(node.item)) {
50080
- const childRecord = asRecord4(child2);
50412
+ const childRecord = asRecord5(child2);
50081
50413
  if (childRecord) scanExecutableScripts(childRecord, warnings);
50082
50414
  }
50083
50415
  }
@@ -50087,7 +50419,7 @@ function instrumentContractCollection(collection, index) {
50087
50419
  const inject = (item) => {
50088
50420
  if (isResolverItem(item)) return;
50089
50421
  if (item.request) {
50090
- const request = asRecord4(item.request) ?? {};
50422
+ const request = asRecord5(item.request) ?? {};
50091
50423
  const result = matchOperation(index, request);
50092
50424
  let script;
50093
50425
  if (result.operation) {
@@ -50101,15 +50433,15 @@ function instrumentContractCollection(collection, index) {
50101
50433
  } else {
50102
50434
  script = createMappingFailureScript(`No OpenAPI operation matched request ${result.method} ${result.path}`);
50103
50435
  }
50104
- const events2 = asArray3(item.event).filter((entry) => asRecord4(entry)?.listen !== "test");
50436
+ const events2 = asArray3(item.event).filter((entry) => asRecord5(entry)?.listen !== "test");
50105
50437
  item.event = [...events2, { listen: "test", script: { type: "text/javascript", exec: script } }];
50106
50438
  }
50107
50439
  for (const child2 of asArray3(item.item)) {
50108
- const childRecord = asRecord4(child2);
50440
+ const childRecord = asRecord5(child2);
50109
50441
  if (childRecord) inject(childRecord);
50110
50442
  }
50111
50443
  };
50112
- 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));
50113
50445
  collection.item = items;
50114
50446
  for (const item of items) inject(item);
50115
50447
  const missing = index.operations.filter((operation) => !covered.has(operation.id));
@@ -62473,7 +62805,7 @@ function compileErrors(result) {
62473
62805
 
62474
62806
  // src/lib/spec/openapi-loader.ts
62475
62807
  var import_yaml2 = __toESM(require_dist(), 1);
62476
- function asRecord5(value) {
62808
+ function asRecord6(value) {
62477
62809
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
62478
62810
  return value;
62479
62811
  }
@@ -62488,7 +62820,7 @@ function parseOpenApiDocument(content) {
62488
62820
  throw new Error("CONTRACT_SPEC_PARSE_FAILED: Spec content is not valid JSON or YAML");
62489
62821
  }
62490
62822
  }
62491
- const doc = asRecord5(parsed);
62823
+ const doc = asRecord6(parsed);
62492
62824
  if (!doc) throw new Error("CONTRACT_SPEC_PARSE_FAILED: Spec content must be a JSON or YAML object");
62493
62825
  return doc;
62494
62826
  }
@@ -62516,7 +62848,7 @@ function collectExternalRefs(node, baseUrl, refs) {
62516
62848
  node.forEach((entry) => collectExternalRefs(entry, baseUrl, refs));
62517
62849
  return;
62518
62850
  }
62519
- const record = asRecord5(node);
62851
+ const record = asRecord6(node);
62520
62852
  if (!record) return;
62521
62853
  const ref = typeof record.$ref === "string" ? record.$ref : "";
62522
62854
  if (ref && !ref.startsWith("#")) {
@@ -62854,6 +63186,11 @@ function resolveInputs(env = process.env) {
62854
63186
  governanceMappingJson: parseGovernanceMappingJson(getInput2("governance-mapping-json", env)),
62855
63187
  postmanApiKey: getInput2("postman-api-key", env) ?? "",
62856
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
+ ),
62857
63194
  integrationBackend,
62858
63195
  folderStrategy: parseEnumInput("folder-strategy", getInput2("folder-strategy", env), "Paths"),
62859
63196
  nestedFolderHierarchy: parseBooleanInput("nested-folder-hierarchy", getInput2("nested-folder-hierarchy", env), false),
@@ -62863,6 +63200,7 @@ function resolveInputs(env = process.env) {
62863
63200
  postmanBifrostBase: endpointProfile.bifrostBaseUrl,
62864
63201
  postmanGatewayBase: endpointProfile.gatewayBaseUrl,
62865
63202
  postmanCliInstallUrl: endpointProfile.cliInstallUrl,
63203
+ postmanIapubBase: endpointProfile.iapubBaseUrl,
62866
63204
  githubRefName: env.GITHUB_REF_NAME,
62867
63205
  githubHeadRef: env.GITHUB_HEAD_REF,
62868
63206
  githubRef: env.GITHUB_REF,
@@ -62951,6 +63289,7 @@ function readActionInputs(actionCore) {
62951
63289
  INPUT_GOVERNANCE_MAPPING_JSON: optionalInput(actionCore, "governance-mapping-json") ?? customerPreviewActionContract.inputs["governance-mapping-json"].default,
62952
63290
  INPUT_POSTMAN_API_KEY: postmanApiKey,
62953
63291
  INPUT_POSTMAN_ACCESS_TOKEN: postmanAccessToken,
63292
+ INPUT_CREDENTIAL_PREFLIGHT: optionalInput(actionCore, "credential-preflight") ?? customerPreviewActionContract.inputs["credential-preflight"].default,
62954
63293
  INPUT_INTEGRATION_BACKEND: optionalInput(actionCore, "integration-backend") ?? customerPreviewActionContract.inputs["integration-backend"].default,
62955
63294
  INPUT_FOLDER_STRATEGY: optionalInput(actionCore, "folder-strategy") ?? customerPreviewActionContract.inputs["folder-strategy"].default,
62956
63295
  INPUT_NESTED_FOLDER_HIERARCHY: optionalInput(actionCore, "nested-folder-hierarchy") ?? customerPreviewActionContract.inputs["nested-folder-hierarchy"].default,
@@ -63462,8 +63801,20 @@ For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID
63462
63801
  governanceGroupName
63463
63802
  );
63464
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;
63465
63816
  dependencies.core.warning(
63466
- `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)}`
63467
63818
  );
63468
63819
  }
63469
63820
  }
@@ -64050,6 +64401,17 @@ For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID
64050
64401
  }
64051
64402
  async function runAction(actionCore = core_exports, actionExec = exec_exports, actionIo = io_exports) {
64052
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
+ });
64053
64415
  let orgMode = false;
64054
64416
  if (inputs.postmanAccessToken && inputs.teamId) {
64055
64417
  try {