@postman-cse/onboarding-bootstrap 0.14.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -46792,6 +46792,12 @@ var customerPreviewActionContract = {
46792
46792
  description: "Postman access token used for governance and workspace mutations.",
46793
46793
  required: false
46794
46794
  },
46795
+ "credential-preflight": {
46796
+ 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.",
46797
+ required: false,
46798
+ default: "warn",
46799
+ allowedValues: ["enforce", "warn", "off"]
46800
+ },
46795
46801
  "integration-backend": {
46796
46802
  description: "Integration backend for downstream workspace connectivity.",
46797
46803
  required: false,
@@ -47815,13 +47821,15 @@ var POSTMAN_ENDPOINT_PROFILES = {
47815
47821
  apiBaseUrl: "https://api.getpostman.com",
47816
47822
  bifrostBaseUrl: "https://bifrost-premium-https-v4.gw.postman.com",
47817
47823
  cliInstallUrl: "https://dl-cli.pstmn.io/install/unix.sh",
47818
- gatewayBaseUrl: "https://gateway.postman.com"
47824
+ gatewayBaseUrl: "https://gateway.postman.com",
47825
+ iapubBaseUrl: "https://iapub.postman.co"
47819
47826
  },
47820
47827
  beta: {
47821
47828
  apiBaseUrl: "https://api.getpostman-beta.com",
47822
47829
  bifrostBaseUrl: "https://bifrost-https-v4.gw.postman-beta.com",
47823
47830
  cliInstallUrl: "https://dl-cli.pstmn-beta.io/install/unix.sh",
47824
- gatewayBaseUrl: "https://gateway.postman-beta.com"
47831
+ gatewayBaseUrl: "https://gateway.postman-beta.com",
47832
+ iapubBaseUrl: "https://iapub.postman.co"
47825
47833
  }
47826
47834
  };
47827
47835
  function parsePostmanStack(value) {
@@ -47835,6 +47843,311 @@ function resolvePostmanEndpointProfile(stack) {
47835
47843
  return POSTMAN_ENDPOINT_PROFILES[stack];
47836
47844
  }
47837
47845
 
47846
+ // src/lib/postman/credential-identity.ts
47847
+ var sessionPath = "/api/sessions/current";
47848
+ var pmakMemo = /* @__PURE__ */ new Map();
47849
+ var sessionMemo = /* @__PURE__ */ new Map();
47850
+ var memoizedSessionIdentity;
47851
+ function getMemoizedSessionIdentity() {
47852
+ return memoizedSessionIdentity;
47853
+ }
47854
+ function asRecord(value) {
47855
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
47856
+ return void 0;
47857
+ }
47858
+ return value;
47859
+ }
47860
+ function coerceId(raw) {
47861
+ return raw ? String(raw) : void 0;
47862
+ }
47863
+ function coerceText(raw) {
47864
+ if (typeof raw !== "string") {
47865
+ return void 0;
47866
+ }
47867
+ const trimmed = raw.trim();
47868
+ return trimmed ? trimmed : void 0;
47869
+ }
47870
+ function normalizeBaseUrl(raw) {
47871
+ return String(raw || "").replace(/\/+$/, "");
47872
+ }
47873
+ async function resolvePmakIdentity(opts) {
47874
+ const apiKey = String(opts.apiKey || "").trim();
47875
+ if (!apiKey) {
47876
+ return void 0;
47877
+ }
47878
+ const baseUrl = normalizeBaseUrl(opts.apiBaseUrl);
47879
+ const memoKey = `${baseUrl}::${apiKey}`;
47880
+ let pending = pmakMemo.get(memoKey);
47881
+ if (!pending) {
47882
+ pending = probePmakIdentity(baseUrl, apiKey, opts.fetchImpl ?? fetch);
47883
+ pmakMemo.set(memoKey, pending);
47884
+ }
47885
+ return pending;
47886
+ }
47887
+ async function probePmakIdentity(baseUrl, apiKey, fetchImpl) {
47888
+ try {
47889
+ const response = await fetchImpl(`${baseUrl}/me`, {
47890
+ method: "GET",
47891
+ headers: { "X-Api-Key": apiKey }
47892
+ });
47893
+ if (!response.ok) {
47894
+ return void 0;
47895
+ }
47896
+ const payload = asRecord(await response.json());
47897
+ const user = asRecord(payload?.user);
47898
+ if (!user) {
47899
+ return void 0;
47900
+ }
47901
+ return {
47902
+ source: "pmak/me",
47903
+ userId: coerceId(user.id),
47904
+ fullName: coerceText(user.fullName) ?? coerceText(user.username),
47905
+ teamId: coerceId(user.teamId),
47906
+ teamName: coerceText(user.teamName),
47907
+ teamDomain: coerceText(user.teamDomain)
47908
+ };
47909
+ } catch {
47910
+ return void 0;
47911
+ }
47912
+ }
47913
+ async function resolveSessionIdentity(opts) {
47914
+ const accessToken = String(opts.accessToken || "").trim();
47915
+ if (!accessToken) {
47916
+ return void 0;
47917
+ }
47918
+ const baseUrl = normalizeBaseUrl(opts.iapubBaseUrl);
47919
+ const memoKey = `${baseUrl}::${accessToken}`;
47920
+ let pending = sessionMemo.get(memoKey);
47921
+ if (!pending) {
47922
+ pending = probeSessionIdentity(baseUrl, accessToken, opts.fetchImpl ?? fetch);
47923
+ sessionMemo.set(memoKey, pending);
47924
+ }
47925
+ return pending;
47926
+ }
47927
+ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl) {
47928
+ try {
47929
+ const response = await fetchImpl(`${baseUrl}${sessionPath}`, {
47930
+ method: "GET",
47931
+ headers: { "x-access-token": accessToken }
47932
+ });
47933
+ if (!response.ok) {
47934
+ return void 0;
47935
+ }
47936
+ const payload = asRecord(await response.json());
47937
+ if (!payload) {
47938
+ return void 0;
47939
+ }
47940
+ const identity = asRecord(payload.identity);
47941
+ const data = asRecord(payload.data);
47942
+ const user = asRecord(data?.user);
47943
+ const roleEntries = Array.isArray(user?.roles) ? user.roles.map((entry) => coerceText(entry) ?? coerceId(entry)).filter((entry) => Boolean(entry)) : [];
47944
+ const singleRole = coerceText(user?.role);
47945
+ const roles = roleEntries.length > 0 ? roleEntries : singleRole ? [singleRole] : void 0;
47946
+ const resolved = {
47947
+ source: "iapub/sessions",
47948
+ userId: coerceId(user?.id),
47949
+ fullName: coerceText(user?.fullName) ?? coerceText(user?.name) ?? coerceText(user?.username),
47950
+ teamId: coerceId(identity?.team),
47951
+ teamDomain: coerceText(identity?.domain),
47952
+ ...roles ? { roles } : {},
47953
+ consumerType: coerceText(payload.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
47954
+ };
47955
+ memoizedSessionIdentity = resolved;
47956
+ return resolved;
47957
+ } catch {
47958
+ return void 0;
47959
+ }
47960
+ }
47961
+ function describeTeam(id) {
47962
+ const label = id?.teamName ?? id?.teamDomain;
47963
+ return `team ${id?.teamId ?? "unresolved"}${label ? ` (${label})` : ""}`;
47964
+ }
47965
+ function formatIdentityLine(id, mask) {
47966
+ const teamPart = id.teamId ? describeTeam(id) : "team unresolved";
47967
+ const domainPart = id.teamDomain ? `, domain ${id.teamDomain}` : "";
47968
+ if (id.source === "pmak/me") {
47969
+ const userPart = id.userId ? `user ${id.userId}${id.fullName ? ` (${id.fullName})` : ""}, ` : "";
47970
+ return mask(`postman: PMAK identity - ${userPart}${teamPart}${domainPart}`);
47971
+ }
47972
+ return mask(
47973
+ `postman: access-token session identity - ${teamPart}${domainPart} [source: iapub/sessions]`
47974
+ );
47975
+ }
47976
+ function crossCheckIdentities(args) {
47977
+ if (args.mode === "off") {
47978
+ return { ok: true, level: "ok", message: "" };
47979
+ }
47980
+ const pmakTeamId = args.pmak?.teamId;
47981
+ const sessionTeamId = args.session?.teamId;
47982
+ if (pmakTeamId && sessionTeamId && pmakTeamId !== sessionTeamId) {
47983
+ const level = args.mode === "enforce" ? "fail" : "note";
47984
+ const lead = level === "fail" ? "credential preflight FAILED" : "credential preflight note";
47985
+ 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.";
47986
+ return {
47987
+ ok: false,
47988
+ level,
47989
+ message: args.mask(
47990
+ `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
47991
+ )
47992
+ };
47993
+ }
47994
+ if (pmakTeamId && sessionTeamId) {
47995
+ const scope = args.workspaceTeamId || args.explicitTeamId ? "parent org team" : "team";
47996
+ const label = args.pmak?.teamName ?? args.pmak?.teamDomain ?? args.session?.teamName ?? args.session?.teamDomain;
47997
+ return {
47998
+ ok: true,
47999
+ level: "ok",
48000
+ message: args.mask(
48001
+ `postman: credential preflight OK - PMAK and access token both resolve to ${scope} ${pmakTeamId}${label ? ` (${label})` : ""}`
48002
+ )
48003
+ };
48004
+ }
48005
+ const missing = [
48006
+ !pmakTeamId ? "PMAK identity" : void 0,
48007
+ !sessionTeamId ? "access-token session identity" : void 0
48008
+ ].filter(Boolean).join(" and ");
48009
+ return {
48010
+ ok: false,
48011
+ level: "note",
48012
+ message: args.mask(
48013
+ `postman: credential preflight note - cross-check skipped because the ${missing} did not resolve a team id; continuing with reactive error guidance only`
48014
+ )
48015
+ };
48016
+ }
48017
+ async function runCredentialPreflight(args) {
48018
+ if (args.mode === "off") {
48019
+ return;
48020
+ }
48021
+ const mask = args.mask;
48022
+ const apiKey = String(args.postmanApiKey || "").trim();
48023
+ const accessToken = String(args.postmanAccessToken || "").trim();
48024
+ let pmak;
48025
+ if (apiKey) {
48026
+ try {
48027
+ pmak = await resolvePmakIdentity({
48028
+ apiBaseUrl: args.apiBaseUrl,
48029
+ apiKey,
48030
+ fetchImpl: args.fetchImpl
48031
+ });
48032
+ } catch (error2) {
48033
+ args.log.warning(
48034
+ mask(
48035
+ `postman: credential preflight could not resolve PMAK identity: ${error2 instanceof Error ? error2.message : String(error2)}`
48036
+ )
48037
+ );
48038
+ }
48039
+ if (pmak) {
48040
+ args.log.info(formatIdentityLine(pmak, mask));
48041
+ } else {
48042
+ args.log.warning(
48043
+ mask("postman: credential preflight could not resolve PMAK identity from GET /me; continuing")
48044
+ );
48045
+ }
48046
+ }
48047
+ if (!accessToken) {
48048
+ args.log.info(mask("postman: Bifrost diagnostics limited: no access token"));
48049
+ return;
48050
+ }
48051
+ let session;
48052
+ try {
48053
+ session = await resolveSessionIdentity({
48054
+ iapubBaseUrl: args.iapubBaseUrl,
48055
+ accessToken,
48056
+ fetchImpl: args.fetchImpl
48057
+ });
48058
+ } catch (error2) {
48059
+ args.log.warning(
48060
+ mask(
48061
+ `postman: credential preflight could not resolve access-token session identity: ${error2 instanceof Error ? error2.message : String(error2)}`
48062
+ )
48063
+ );
48064
+ }
48065
+ if (session) {
48066
+ args.log.info(formatIdentityLine(session, mask));
48067
+ } else {
48068
+ args.log.warning(
48069
+ mask(
48070
+ "postman: credential preflight could not resolve the access-token session identity from iapub; continuing with reactive error guidance only"
48071
+ )
48072
+ );
48073
+ }
48074
+ const result = crossCheckIdentities({
48075
+ pmak,
48076
+ session,
48077
+ workspaceTeamId: args.workspaceTeamId,
48078
+ explicitTeamId: args.explicitTeamId,
48079
+ mode: args.mode,
48080
+ mask
48081
+ });
48082
+ if (!result.message) {
48083
+ return;
48084
+ }
48085
+ if (result.level === "fail") {
48086
+ throw new Error(result.message);
48087
+ }
48088
+ if (result.level === "note") {
48089
+ args.log.warning(result.message);
48090
+ return;
48091
+ }
48092
+ args.log.info(result.message);
48093
+ }
48094
+
48095
+ // src/lib/postman/error-advice.ts
48096
+ 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.";
48097
+ function workspaceTeamIdUnauthorizedAdvice(targetTeamId) {
48098
+ 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.`;
48099
+ }
48100
+ function adviseFromWorkspaceCreateError(err, targetTeamId) {
48101
+ if (err.message.includes("Only personal workspaces")) {
48102
+ return new Error(WORKSPACE_PERSONAL_ONLY_ADVICE, { cause: err });
48103
+ }
48104
+ if (targetTeamId != null && err.message.includes("You are not authorized to perform this action")) {
48105
+ return new Error(workspaceTeamIdUnauthorizedAdvice(targetTeamId), { cause: err });
48106
+ }
48107
+ return void 0;
48108
+ }
48109
+ function expiryAdvice(code) {
48110
+ 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.`;
48111
+ }
48112
+ function forbiddenAdvice(ctx) {
48113
+ 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)` : "";
48114
+ const scopedTeamId = ctx.workspaceTeamId || ctx.explicitTeamId;
48115
+ 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";
48116
+ 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.`;
48117
+ }
48118
+ function buildAdvice(status, body, ctx) {
48119
+ if (body.includes("UNAUTHENTICATED")) {
48120
+ return expiryAdvice("UNAUTHENTICATED");
48121
+ }
48122
+ if (body.includes("authenticationError")) {
48123
+ return expiryAdvice("authenticationError");
48124
+ }
48125
+ if (body.includes("Only personal workspaces")) {
48126
+ return WORKSPACE_PERSONAL_ONLY_ADVICE;
48127
+ }
48128
+ if (body.includes("projectAlreadyConnected")) {
48129
+ 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.`;
48130
+ }
48131
+ if (body.includes("invalidParamError") && body.includes("already exists")) {
48132
+ 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.`;
48133
+ }
48134
+ if (body.includes("Team feature is not available for your organization")) {
48135
+ 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.`;
48136
+ }
48137
+ if (body.includes("You are not authorized to perform this action") || status === 403 && ctx.hasAccessToken) {
48138
+ return forbiddenAdvice(ctx);
48139
+ }
48140
+ return void 0;
48141
+ }
48142
+ function adviseFromHttpError(err, ctx) {
48143
+ const body = err.responseBody || err.message || "";
48144
+ const advice = buildAdvice(err.status, body, ctx);
48145
+ if (!advice) {
48146
+ return void 0;
48147
+ }
48148
+ return new Error(ctx.mask(advice), { cause: err });
48149
+ }
48150
+
47838
48151
  // src/lib/retry.ts
47839
48152
  function sleep(delayMs) {
47840
48153
  return new Promise((resolve4) => {
@@ -47883,7 +48196,7 @@ async function retry(operation, options = {}) {
47883
48196
  }
47884
48197
 
47885
48198
  // src/lib/postman/postman-assets-client.ts
47886
- function asRecord(value) {
48199
+ function asRecord2(value) {
47887
48200
  if (!value || typeof value !== "object" || Array.isArray(value)) {
47888
48201
  return null;
47889
48202
  }
@@ -47891,8 +48204,8 @@ function asRecord(value) {
47891
48204
  }
47892
48205
  function extractWorkspacesPage(data) {
47893
48206
  const workspaces = Array.isArray(data?.workspaces) ? data.workspaces : [];
47894
- const meta = asRecord(data?.meta);
47895
- const pagination = asRecord(data?.pagination);
48207
+ const meta = asRecord2(data?.meta);
48208
+ const pagination = asRecord2(data?.pagination);
47896
48209
  const nextCursor = String(
47897
48210
  data?.nextCursor ?? data?.next_cursor ?? meta?.nextCursor ?? meta?.next_cursor ?? pagination?.nextCursor ?? pagination?.next_cursor ?? ""
47898
48211
  ).trim() || void 0;
@@ -47984,7 +48297,7 @@ var PostmanAssetsClient = class {
47984
48297
  async getTeams() {
47985
48298
  const data = await this.request("/teams");
47986
48299
  const teams = data?.data ?? [];
47987
- return Array.isArray(teams) ? teams.map((entry) => asRecord(entry)).filter((team) => Boolean(team?.id && team?.name)).map((team) => ({
48300
+ return Array.isArray(teams) ? teams.map((entry) => asRecord2(entry)).filter((team) => Boolean(team?.id && team?.name)).map((team) => ({
47988
48301
  id: Number(team.id),
47989
48302
  name: String(team.name),
47990
48303
  handle: String(team.handle || ""),
@@ -48036,28 +48349,28 @@ var PostmanAssetsClient = class {
48036
48349
  body: JSON.stringify(payload)
48037
48350
  });
48038
48351
  } catch (err) {
48039
- if (err instanceof Error && err.message.includes("Only personal workspaces")) {
48040
- throw new Error(
48041
- "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.",
48042
- { cause: err }
48043
- );
48352
+ if (err instanceof Error) {
48353
+ const advised = adviseFromWorkspaceCreateError(err, targetTeamId);
48354
+ if (advised) {
48355
+ throw advised;
48356
+ }
48044
48357
  }
48045
48358
  throw err;
48046
48359
  }
48047
- const createdWorkspace = asRecord(created?.workspace);
48360
+ const createdWorkspace = asRecord2(created?.workspace);
48048
48361
  const workspaceId = String(createdWorkspace?.id || "").trim();
48049
48362
  if (!workspaceId) {
48050
48363
  throw new Error("Workspace create did not return an id");
48051
48364
  }
48052
48365
  const workspace = await this.request(`/workspaces/${workspaceId}`);
48053
- let visibility = asRecord(workspace?.workspace)?.visibility;
48366
+ let visibility = asRecord2(workspace?.workspace)?.visibility;
48054
48367
  if (visibility !== "team") {
48055
48368
  await this.request(`/workspaces/${workspaceId}`, {
48056
48369
  method: "PUT",
48057
48370
  body: JSON.stringify(payload)
48058
48371
  });
48059
48372
  const reread = await this.request(`/workspaces/${workspaceId}`);
48060
- visibility = asRecord(reread?.workspace)?.visibility;
48373
+ visibility = asRecord2(reread?.workspace)?.visibility;
48061
48374
  }
48062
48375
  if (typeof visibility === "string" && visibility !== "team") {
48063
48376
  let cleanedUp = false;
@@ -48086,7 +48399,7 @@ var PostmanAssetsClient = class {
48086
48399
  async getWorkspaceVisibility(workspaceId) {
48087
48400
  try {
48088
48401
  const workspace = await this.request(`/workspaces/${workspaceId}`);
48089
- const visibility = asRecord(workspace?.workspace)?.visibility;
48402
+ const visibility = asRecord2(workspace?.workspace)?.visibility;
48090
48403
  return typeof visibility === "string" ? visibility : null;
48091
48404
  } catch {
48092
48405
  return null;
@@ -48108,7 +48421,7 @@ var PostmanAssetsClient = class {
48108
48421
  nextCursor = page.nextCursor;
48109
48422
  }
48110
48423
  } while (nextCursor);
48111
- return allWorkspaces.map((entry) => asRecord(entry)).filter((workspace) => Boolean(workspace?.id && workspace?.name)).map((workspace) => ({
48424
+ return allWorkspaces.map((entry) => asRecord2(entry)).filter((workspace) => Boolean(workspace?.id && workspace?.name)).map((workspace) => ({
48112
48425
  id: String(workspace.id),
48113
48426
  name: String(workspace.name),
48114
48427
  type: String(workspace.type ?? "team")
@@ -48156,7 +48469,7 @@ var PostmanAssetsClient = class {
48156
48469
  async inviteRequesterToWorkspace(workspaceId, email) {
48157
48470
  const users = await this.request("/users");
48158
48471
  const userList = Array.isArray(users?.data) ? users.data : [];
48159
- const user = userList.map((entry) => asRecord(entry)).find((entry) => entry?.email === email);
48472
+ const user = userList.map((entry) => asRecord2(entry)).find((entry) => entry?.email === email);
48160
48473
  if (!user?.id) {
48161
48474
  return;
48162
48475
  }
@@ -48244,12 +48557,12 @@ var PostmanAssetsClient = class {
48244
48557
  }
48245
48558
  };
48246
48559
  const extractUid = (data) => {
48247
- const root = asRecord(data);
48248
- const details = asRecord(root?.details);
48560
+ const root = asRecord2(data);
48561
+ const details = asRecord2(root?.details);
48249
48562
  const resources = Array.isArray(details?.resources) ? details.resources : [];
48250
- const firstResource = asRecord(resources[0]);
48251
- const collection = asRecord(root?.collection);
48252
- const resource = asRecord(root?.resource);
48563
+ const firstResource = asRecord2(resources[0]);
48564
+ const collection = asRecord2(root?.collection);
48565
+ const resource = asRecord2(root?.resource);
48253
48566
  return String(
48254
48567
  firstResource?.id ?? collection?.id ?? collection?.uid ?? resource?.uid ?? resource?.id ?? ""
48255
48568
  ).trim() || void 0;
@@ -48283,9 +48596,9 @@ var PostmanAssetsClient = class {
48283
48596
  if (directUid) {
48284
48597
  return directUid;
48285
48598
  }
48286
- let taskUrl = String(generationResponse?.url ?? "") || String(generationResponse?.task_url ?? "") || String(generationResponse?.taskUrl ?? "") || String(asRecord(generationResponse?.links)?.task ?? "");
48599
+ let taskUrl = String(generationResponse?.url ?? "") || String(generationResponse?.task_url ?? "") || String(generationResponse?.taskUrl ?? "") || String(asRecord2(generationResponse?.links)?.task ?? "");
48287
48600
  if (!taskUrl) {
48288
- const task = asRecord(generationResponse?.task);
48601
+ const task = asRecord2(generationResponse?.task);
48289
48602
  const taskId = generationResponse?.taskId || task?.id || generationResponse?.id;
48290
48603
  if (!taskId) {
48291
48604
  throw new Error(
@@ -48299,8 +48612,8 @@ var PostmanAssetsClient = class {
48299
48612
  setTimeout(resolve4, 2e3);
48300
48613
  });
48301
48614
  const task = await this.request(taskUrl);
48302
- const taskRecord = asRecord(task);
48303
- const taskNested = asRecord(taskRecord?.task);
48615
+ const taskRecord = asRecord2(task);
48616
+ const taskNested = asRecord2(taskRecord?.task);
48304
48617
  const status = String(taskRecord?.status || taskNested?.status || "").toLowerCase();
48305
48618
  if (status === "completed") {
48306
48619
  const taskUid = extractUid(task);
@@ -48331,7 +48644,7 @@ var PostmanAssetsClient = class {
48331
48644
  }
48332
48645
  async injectTests(collectionUid, type2) {
48333
48646
  const collectionResponse = await this.request(`/collections/${collectionUid}`);
48334
- const collection = asRecord(collectionResponse?.collection);
48647
+ const collection = asRecord2(collectionResponse?.collection);
48335
48648
  if (!collection) {
48336
48649
  throw new Error(`Failed to fetch collection ${collectionUid}`);
48337
48650
  }
@@ -48417,7 +48730,7 @@ var PostmanAssetsClient = class {
48417
48730
  });
48418
48731
  }
48419
48732
  if (Array.isArray(itemNode.item)) {
48420
- itemNode.item.map((entry) => asRecord(entry)).filter((entry) => Boolean(entry)).forEach(injectScripts);
48733
+ itemNode.item.map((entry) => asRecord2(entry)).filter((entry) => Boolean(entry)).forEach(injectScripts);
48421
48734
  }
48422
48735
  };
48423
48736
  if (Array.isArray(collection.item)) {
@@ -48445,7 +48758,7 @@ var PostmanAssetsClient = class {
48445
48758
  }
48446
48759
  })
48447
48760
  });
48448
- const environment = asRecord(response?.environment);
48761
+ const environment = asRecord2(response?.environment);
48449
48762
  const uid = String(environment?.uid || "").trim();
48450
48763
  if (!uid) {
48451
48764
  throw new Error("Environment create did not return a UID");
@@ -48478,7 +48791,7 @@ var PostmanAssetsClient = class {
48478
48791
  }
48479
48792
  })
48480
48793
  });
48481
- const monitor = asRecord(response?.monitor);
48794
+ const monitor = asRecord2(response?.monitor);
48482
48795
  const uid = String(monitor?.uid || "").trim();
48483
48796
  if (!uid) {
48484
48797
  throw new Error("Monitor create did not return a UID");
@@ -48497,8 +48810,8 @@ var PostmanAssetsClient = class {
48497
48810
  }
48498
48811
  })
48499
48812
  });
48500
- const mock = asRecord(response?.mock);
48501
- const mockConfig = asRecord(mock?.config);
48813
+ const mock = asRecord2(response?.mock);
48814
+ const mockConfig = asRecord2(mock?.config);
48502
48815
  const uid = String(mock?.uid || "").trim();
48503
48816
  if (!uid) {
48504
48817
  throw new Error("Mock create did not return a UID");
@@ -48569,6 +48882,18 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48569
48882
  this.teamId = String(teamId || "").trim();
48570
48883
  this.orgMode = orgMode;
48571
48884
  }
48885
+ adviceContext(operation) {
48886
+ const session = getMemoizedSessionIdentity();
48887
+ return {
48888
+ operation,
48889
+ hasAccessToken: Boolean(this.accessToken),
48890
+ sessionTeamId: session?.teamId,
48891
+ sessionRoles: session?.roles,
48892
+ sessionConsumerType: session?.consumerType,
48893
+ explicitTeamId: this.teamId || void 0,
48894
+ mask: this.secretMasker
48895
+ };
48896
+ }
48572
48897
  async proxyRequest(service, method, requestPath2, body, options = {}) {
48573
48898
  const url = `${this.bifrostBaseUrl}/ws/proxy`;
48574
48899
  const headers = {
@@ -48635,7 +48960,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48635
48960
  { appVersion, query: { tag: "governance" } }
48636
48961
  );
48637
48962
  if (!listResponse.ok) {
48638
- throw await HttpError.fromResponse(listResponse, {
48963
+ const httpErr = await HttpError.fromResponse(listResponse, {
48639
48964
  method: "GET",
48640
48965
  requestHeaders: {
48641
48966
  "Content-Type": "application/json",
@@ -48646,6 +48971,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48646
48971
  secretValues: [this.accessToken],
48647
48972
  url: `${this.bifrostBaseUrl}/ws/proxy`
48648
48973
  });
48974
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("governance assignment"));
48975
+ throw advised ?? httpErr;
48649
48976
  }
48650
48977
  const groups = await listResponse.json();
48651
48978
  const group2 = (groups.workspaceGroups ?? groups.data)?.find(
@@ -48671,7 +48998,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48671
48998
  { appVersion }
48672
48999
  );
48673
49000
  if (!patchResponse.ok) {
48674
- throw await HttpError.fromResponse(patchResponse, {
49001
+ const httpErr = await HttpError.fromResponse(patchResponse, {
48675
49002
  method: "PATCH",
48676
49003
  requestHeaders: {
48677
49004
  "Content-Type": "application/json",
@@ -48682,6 +49009,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48682
49009
  secretValues: [this.accessToken],
48683
49010
  url: `${this.bifrostBaseUrl}/ws/proxy`
48684
49011
  });
49012
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("governance assignment"));
49013
+ throw advised ?? httpErr;
48685
49014
  }
48686
49015
  }
48687
49016
  async connectWorkspaceToRepository(workspaceId, repoUrl) {
@@ -48715,7 +49044,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48715
49044
  );
48716
49045
  }
48717
49046
  }
48718
- throw await HttpError.fromResponse(response, {
49047
+ const httpErr = await HttpError.fromResponse(response, {
48719
49048
  method: "POST",
48720
49049
  requestHeaders: {
48721
49050
  "Content-Type": "application/json",
@@ -48725,6 +49054,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48725
49054
  secretValues: [this.accessToken],
48726
49055
  url: `${this.bifrostBaseUrl}/ws/proxy`
48727
49056
  });
49057
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("workspace repository linking"));
49058
+ throw advised ?? httpErr;
48728
49059
  }
48729
49060
  async linkCollectionsToSpecification(specificationId, collections) {
48730
49061
  if (collections.length === 0) {
@@ -48742,7 +49073,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48742
49073
  if (response.ok) {
48743
49074
  return;
48744
49075
  }
48745
- throw await HttpError.fromResponse(response, {
49076
+ const httpErr = await HttpError.fromResponse(response, {
48746
49077
  method: "POST",
48747
49078
  requestHeaders: {
48748
49079
  "Content-Type": "application/json",
@@ -48752,6 +49083,11 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48752
49083
  secretValues: [this.accessToken],
48753
49084
  url: `${this.bifrostBaseUrl}/ws/proxy`
48754
49085
  });
49086
+ const advised = adviseFromHttpError(
49087
+ httpErr,
49088
+ this.adviceContext("collection-to-specification linking")
49089
+ );
49090
+ throw advised ?? httpErr;
48755
49091
  }
48756
49092
  async syncCollection(specificationId, collectionId) {
48757
49093
  const response = await this.proxyRequest(
@@ -48762,7 +49098,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48762
49098
  if (response.ok) {
48763
49099
  return;
48764
49100
  }
48765
- throw await HttpError.fromResponse(response, {
49101
+ const httpErr = await HttpError.fromResponse(response, {
48766
49102
  method: "POST",
48767
49103
  requestHeaders: {
48768
49104
  "Content-Type": "application/json",
@@ -48772,6 +49108,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
48772
49108
  secretValues: [this.accessToken],
48773
49109
  url: `${this.bifrostBaseUrl}/ws/proxy`
48774
49110
  });
49111
+ const advised = adviseFromHttpError(httpErr, this.adviceContext("collection sync"));
49112
+ throw advised ?? httpErr;
48775
49113
  }
48776
49114
  async getWorkspaceGitRepoUrl(workspaceId) {
48777
49115
  const response = await this.proxyRequest(
@@ -49345,7 +49683,7 @@ var STRIP_KEYS = /* @__PURE__ */ new Set([
49345
49683
  "discriminator",
49346
49684
  "format"
49347
49685
  ]);
49348
- function asRecord2(value) {
49686
+ function asRecord3(value) {
49349
49687
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
49350
49688
  return value;
49351
49689
  }
@@ -49357,7 +49695,7 @@ function decodePointerSegment(segment) {
49357
49695
  }
49358
49696
  function resolvePointer(root, ref) {
49359
49697
  if (!ref.startsWith("#/")) return void 0;
49360
- return ref.slice(2).split("/").map(decodePointerSegment).reduce((node, segment) => asRecord2(node)?.[segment], root);
49698
+ return ref.slice(2).split("/").map(decodePointerSegment).reduce((node, segment) => asRecord3(node)?.[segment], root);
49361
49699
  }
49362
49700
  function unsupported(message) {
49363
49701
  return { unsupported: message };
@@ -49367,7 +49705,7 @@ function mergeRequiredWithoutWriteOnly(required, writeOnlyProperties) {
49367
49705
  return values.length > 0 ? values : void 0;
49368
49706
  }
49369
49707
  function hasUnsupported(child2) {
49370
- return asRecord2(child2)?.unsupported;
49708
+ return asRecord3(child2)?.unsupported;
49371
49709
  }
49372
49710
  function rootDialect(root, version, schemaRecord) {
49373
49711
  if (version === "3.0") return DRAFT_07_SCHEMA_URI;
@@ -49387,7 +49725,7 @@ function normalizeSchema(root, schema2, options) {
49387
49725
  const bad = normalized2.map(hasUnsupported).find(Boolean);
49388
49726
  return bad ? unsupported(bad) : normalized2;
49389
49727
  }
49390
- const record = asRecord2(schema2);
49728
+ const record = asRecord3(schema2);
49391
49729
  if (!record) return schema2;
49392
49730
  const ref = typeof record.$ref === "string" ? record.$ref : "";
49393
49731
  if (ref) {
@@ -49422,10 +49760,10 @@ function normalizeSchema(root, schema2, options) {
49422
49760
  const nullable = sourceSchema.nullable === true && options.version === "3.0";
49423
49761
  delete sourceSchema.nullable;
49424
49762
  const writeOnlyProperties = /* @__PURE__ */ new Set();
49425
- const rawProperties = asRecord2(sourceSchema.properties);
49763
+ const rawProperties = asRecord3(sourceSchema.properties);
49426
49764
  if (rawProperties) {
49427
49765
  for (const [propertyName, propertySchema] of Object.entries(rawProperties)) {
49428
- if (asRecord2(propertySchema)?.writeOnly === true) writeOnlyProperties.add(propertyName);
49766
+ if (asRecord3(propertySchema)?.writeOnly === true) writeOnlyProperties.add(propertyName);
49429
49767
  }
49430
49768
  }
49431
49769
  const normalized = {};
@@ -49457,7 +49795,7 @@ function normalizeSchema(root, schema2, options) {
49457
49795
  return unsupported("Tuple array items are unsupported in OpenAPI 3.0");
49458
49796
  }
49459
49797
  if (key === "properties") {
49460
- const properties = asRecord2(value);
49798
+ const properties = asRecord3(value);
49461
49799
  if (!properties) continue;
49462
49800
  const nextProperties = {};
49463
49801
  for (const [propertyName, propertySchema] of Object.entries(properties)) {
@@ -49500,7 +49838,7 @@ function normalizeSchema(root, schema2, options) {
49500
49838
  }
49501
49839
  function packSchema(root, schema2, version) {
49502
49840
  try {
49503
- const dialect = rootDialect(root, version, asRecord2(schema2) ?? void 0);
49841
+ const dialect = rootDialect(root, version, asRecord3(schema2) ?? void 0);
49504
49842
  const normalized = normalizeSchema(root, schema2, { version, rootSchema: true, dialect });
49505
49843
  const message = hasUnsupported(normalized);
49506
49844
  return message ? unsupported(message) : { schema: normalized };
@@ -49511,7 +49849,7 @@ function packSchema(root, schema2, version) {
49511
49849
 
49512
49850
  // src/lib/spec/contract-index.ts
49513
49851
  var HTTP_METHODS = /* @__PURE__ */ new Set(["get", "put", "post", "delete", "options", "head", "patch", "trace"]);
49514
- function asRecord3(value) {
49852
+ function asRecord4(value) {
49515
49853
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
49516
49854
  return value;
49517
49855
  }
@@ -49528,12 +49866,12 @@ function detectOpenApiVersion(root) {
49528
49866
  return match[1] === "1" ? "3.1" : "3.0";
49529
49867
  }
49530
49868
  function resolveInternalRef(root, value) {
49531
- const record = asRecord3(value);
49869
+ const record = asRecord4(value);
49532
49870
  if (!record) return null;
49533
49871
  const ref = typeof record.$ref === "string" ? record.$ref : "";
49534
49872
  if (!ref) return record;
49535
49873
  if (!ref.startsWith("#/")) throw new Error(`CONTRACT_UNRESOLVED_REF: External ref remained after bundling: ${ref}`);
49536
- const resolved = asRecord3(resolvePointer(root, ref));
49874
+ const resolved = asRecord4(resolvePointer(root, ref));
49537
49875
  if (!resolved) throw new Error(`CONTRACT_UNRESOLVED_REF: Unresolved OpenAPI $ref: ${ref}`);
49538
49876
  return resolved;
49539
49877
  }
@@ -49553,11 +49891,11 @@ function normalizePath(path8) {
49553
49891
  return trimmed.split("/").map((segment, index) => index === 0 ? "" : safeDecodeSegment(segment)).join("/") || "/";
49554
49892
  }
49555
49893
  function pathItemServers(pathItem) {
49556
- return asArray2(pathItem.servers).map((entry) => asRecord3(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
49894
+ return asArray2(pathItem.servers).map((entry) => asRecord4(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
49557
49895
  }
49558
49896
  function operationServers(root, pathItem, operation) {
49559
49897
  const rawServers = asArray2(operation.servers).length > 0 ? asArray2(operation.servers) : pathItemServers(pathItem).length > 0 ? asArray2(pathItem.servers) : asArray2(root.servers);
49560
- const values = rawServers.map((entry) => asRecord3(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
49898
+ const values = rawServers.map((entry) => asRecord4(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
49561
49899
  return values.length > 0 ? values : [""];
49562
49900
  }
49563
49901
  function serverPathPrefix(url) {
@@ -49578,10 +49916,10 @@ function normalizeResponseKey(status) {
49578
49916
  return /^[1-5]xx$/i.test(raw) ? raw.toUpperCase() : raw;
49579
49917
  }
49580
49918
  function collectSecurityApiKeys(root, operation) {
49581
- const securitySchemes = asRecord3(asRecord3(root.components)?.securitySchemes);
49919
+ const securitySchemes = asRecord4(asRecord4(root.components)?.securitySchemes);
49582
49920
  const requirements = operation.security === void 0 ? asArray2(root.security) : asArray2(operation.security);
49583
49921
  const names = /* @__PURE__ */ new Set();
49584
- for (const requirement of requirements.map((entry) => asRecord3(entry)).filter(Boolean)) {
49922
+ for (const requirement of requirements.map((entry) => asRecord4(entry)).filter(Boolean)) {
49585
49923
  for (const schemeName of Object.keys(requirement)) {
49586
49924
  const scheme = resolveInternalRef(root, securitySchemes?.[schemeName]);
49587
49925
  if (scheme?.type === "apiKey" && typeof scheme.name === "string" && ["query", "header"].includes(String(scheme.in))) {
@@ -49599,10 +49937,10 @@ function securitySchemeKind(scheme) {
49599
49937
  return type2;
49600
49938
  }
49601
49939
  function collectSecuritySchemeWarnings(root, operation) {
49602
- const securitySchemes = asRecord3(asRecord3(root.components)?.securitySchemes);
49940
+ const securitySchemes = asRecord4(asRecord4(root.components)?.securitySchemes);
49603
49941
  const requirements = operation.security === void 0 ? asArray2(root.security) : asArray2(operation.security);
49604
49942
  const warnings = /* @__PURE__ */ new Set();
49605
- for (const requirement of requirements.map((entry) => asRecord3(entry)).filter(Boolean)) {
49943
+ for (const requirement of requirements.map((entry) => asRecord4(entry)).filter(Boolean)) {
49606
49944
  for (const schemeName of Object.keys(requirement)) {
49607
49945
  const scheme = resolveInternalRef(root, securitySchemes?.[schemeName]);
49608
49946
  warnings.add(
@@ -49638,24 +49976,24 @@ function collectParameters(root, pathItem, operation) {
49638
49976
  function collectRequestBody(root, operation) {
49639
49977
  const body = resolveInternalRef(root, operation.requestBody);
49640
49978
  if (!body || body.required !== true) return void 0;
49641
- const content = asRecord3(body.content);
49979
+ const content = asRecord4(body.content);
49642
49980
  return {
49643
49981
  required: true,
49644
49982
  contentTypes: content ? Object.keys(content) : []
49645
49983
  };
49646
49984
  }
49647
49985
  function responseContent(root, version, response) {
49648
- const content = asRecord3(response.content);
49986
+ const content = asRecord4(response.content);
49649
49987
  if (!content) return {};
49650
49988
  const media = {};
49651
49989
  for (const [contentType, mediaObject] of Object.entries(content)) {
49652
- const schema2 = asRecord3(mediaObject)?.schema;
49990
+ const schema2 = asRecord4(mediaObject)?.schema;
49653
49991
  media[contentType] = schema2 === void 0 ? {} : packSchema(root, schema2, version);
49654
49992
  }
49655
49993
  return media;
49656
49994
  }
49657
49995
  function responseHeaders(root, version, response) {
49658
- const headers = asRecord3(response.headers);
49996
+ const headers = asRecord4(response.headers);
49659
49997
  if (!headers) return [];
49660
49998
  return Object.entries(headers).map(([name, rawHeader]) => {
49661
49999
  const header = resolveInternalRef(root, rawHeader);
@@ -49670,10 +50008,10 @@ function buildContractIndex(root) {
49670
50008
  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)");
49671
50009
  if (!("openapi" in root)) throw new Error("CONTRACT_UNSUPPORTED_OPENAPI_VERSION: Dynamic contract tests require OpenAPI 3.0 or 3.1 (missing openapi)");
49672
50010
  const version = detectOpenApiVersion(root);
49673
- const paths = asRecord3(root.paths);
50011
+ const paths = asRecord4(root.paths);
49674
50012
  const operations = [];
49675
50013
  const warnings = [];
49676
- if (asRecord3(root.webhooks)) warnings.push("CONTRACT_WEBHOOKS_NOT_VALIDATED: OpenAPI webhooks are not validated by dynamic contract tests");
50014
+ if (asRecord4(root.webhooks)) warnings.push("CONTRACT_WEBHOOKS_NOT_VALIDATED: OpenAPI webhooks are not validated by dynamic contract tests");
49677
50015
  if (paths) {
49678
50016
  for (const [path8, rawPathItem] of Object.entries(paths)) {
49679
50017
  const pathItem = resolveInternalRef(root, rawPathItem);
@@ -49684,7 +50022,7 @@ function buildContractIndex(root) {
49684
50022
  const operation = resolveInternalRef(root, rawOperation);
49685
50023
  if (!operation) continue;
49686
50024
  if (operation.callbacks) warnings.push(`CONTRACT_CALLBACKS_NOT_VALIDATED: callbacks are not validated for ${lowerMethod.toUpperCase()} ${path8}`);
49687
- const responses = asRecord3(operation.responses);
50025
+ const responses = asRecord4(operation.responses);
49688
50026
  if (!responses || Object.keys(responses).length === 0) {
49689
50027
  throw new Error(`CONTRACT_OPERATION_NO_RESPONSES: ${lowerMethod.toUpperCase()} ${path8} must define at least one response`);
49690
50028
  }
@@ -49774,7 +50112,7 @@ var CONTRACT_SIZE_LIMITS = {
49774
50112
  maxTestScriptBytes: 9e5,
49775
50113
  maxCollectionUpdateBytes: 4e6
49776
50114
  };
49777
- function asRecord4(value) {
50115
+ function asRecord5(value) {
49778
50116
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
49779
50117
  return value;
49780
50118
  }
@@ -49783,7 +50121,7 @@ function asArray3(value) {
49783
50121
  }
49784
50122
  function stringifyPathSegment(segment) {
49785
50123
  if (typeof segment === "string") return segment;
49786
- const record = asRecord4(segment);
50124
+ const record = asRecord5(segment);
49787
50125
  if (!record) return String(segment ?? "");
49788
50126
  for (const key of ["value", "key", "name"]) {
49789
50127
  if (typeof record[key] === "string" && record[key]) return String(record[key]);
@@ -49801,10 +50139,10 @@ function pathFromRaw(raw) {
49801
50139
  }
49802
50140
  }
49803
50141
  function requestPath(request) {
49804
- const record = asRecord4(request);
50142
+ const record = asRecord5(request);
49805
50143
  const url = record?.url ?? request;
49806
50144
  if (typeof url === "string") return pathFromRaw(url);
49807
- const urlRecord = asRecord4(url);
50145
+ const urlRecord = asRecord5(url);
49808
50146
  if (!urlRecord) return "/";
49809
50147
  if (Array.isArray(urlRecord.path)) return normalizePath(`/${urlRecord.path.map(stringifyPathSegment).filter(Boolean).join("/")}`);
49810
50148
  if (typeof urlRecord.path === "string") return normalizePath(urlRecord.path);
@@ -49836,7 +50174,7 @@ function matchCandidate(candidate, request) {
49836
50174
  return { matched: true, staticCount, templateCount };
49837
50175
  }
49838
50176
  function matchOperation(index, request) {
49839
- const record = asRecord4(request);
50177
+ const record = asRecord5(request);
49840
50178
  const method = String(record?.method || "").toUpperCase();
49841
50179
  const path8 = requestPath(request);
49842
50180
  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) => {
@@ -49987,17 +50325,17 @@ function createSecretsResolverItem() {
49987
50325
  }
49988
50326
  function isResolverItem(item) {
49989
50327
  if (item.name !== "00 - Resolve Secrets") return false;
49990
- const request = asRecord4(item.request);
50328
+ const request = asRecord5(item.request);
49991
50329
  if (String(request?.method || "").toUpperCase() !== "POST") return false;
49992
- const headers = asArray3(request?.header).map((entry) => asRecord4(entry));
50330
+ const headers = asArray3(request?.header).map((entry) => asRecord5(entry));
49993
50331
  const target = headers.find((entry) => entry?.key === "X-Amz-Target");
49994
50332
  return String(target?.value || "") === "secretsmanager.GetSecretValue" && !requestPath(request).includes("secretsmanager");
49995
50333
  }
49996
50334
  function requestQueryNames(request) {
49997
- const url = asRecord4(request.url);
50335
+ const url = asRecord5(request.url);
49998
50336
  const names = /* @__PURE__ */ new Set();
49999
50337
  if (Array.isArray(url?.query)) {
50000
- for (const entry of url.query.map((item) => asRecord4(item)).filter(Boolean)) {
50338
+ for (const entry of url.query.map((item) => asRecord5(item)).filter(Boolean)) {
50001
50339
  if (entry.disabled !== true && typeof entry.key === "string") names.add(entry.key.toLowerCase());
50002
50340
  }
50003
50341
  }
@@ -50012,17 +50350,17 @@ function requestQueryNames(request) {
50012
50350
  }
50013
50351
  function requestHeaderNames(request) {
50014
50352
  const names = /* @__PURE__ */ new Set();
50015
- for (const entry of asArray3(request.header).map((item) => asRecord4(item)).filter(Boolean)) {
50353
+ for (const entry of asArray3(request.header).map((item) => asRecord5(item)).filter(Boolean)) {
50016
50354
  if (entry.disabled !== true && typeof entry.key === "string") names.add(entry.key.toLowerCase());
50017
50355
  }
50018
50356
  return names;
50019
50357
  }
50020
50358
  function requestHeaderValue(request, name) {
50021
- const match = asArray3(request.header).map((item) => asRecord4(item)).filter(Boolean).find((entry) => String(entry.key || "").toLowerCase() === name.toLowerCase() && entry.disabled !== true);
50359
+ const match = asArray3(request.header).map((item) => asRecord5(item)).filter(Boolean).find((entry) => String(entry.key || "").toLowerCase() === name.toLowerCase() && entry.disabled !== true);
50022
50360
  return typeof match?.value === "string" ? match.value : void 0;
50023
50361
  }
50024
50362
  function hasRequestBody(request) {
50025
- const body = asRecord4(request.body);
50363
+ const body = asRecord5(request.body);
50026
50364
  if (!body) return false;
50027
50365
  if (typeof body.raw === "string" && body.raw.trim()) return true;
50028
50366
  return ["urlencoded", "formdata", "graphql"].some((key) => Array.isArray(body[key]) ? body[key].length > 0 : Boolean(body[key]));
@@ -50073,21 +50411,21 @@ function validateScript(script) {
50073
50411
  return void 0;
50074
50412
  }
50075
50413
  function scriptExecLines(script) {
50076
- const record = asRecord4(script);
50414
+ const record = asRecord5(script);
50077
50415
  if (!record) return [];
50078
50416
  if (Array.isArray(record.exec)) return record.exec.map((line) => String(line));
50079
50417
  if (typeof record.exec === "string") return [record.exec];
50080
50418
  return [];
50081
50419
  }
50082
50420
  function scanExecutableScripts(node, warnings) {
50083
- for (const event of asArray3(node.event).map((entry) => asRecord4(entry)).filter(Boolean)) {
50421
+ for (const event of asArray3(node.event).map((entry) => asRecord5(entry)).filter(Boolean)) {
50084
50422
  const lines = scriptExecLines(event.script);
50085
50423
  if (lines.length === 0) continue;
50086
50424
  const warning2 = validateScript(lines);
50087
50425
  if (warning2) warnings.push(warning2);
50088
50426
  }
50089
50427
  for (const child2 of asArray3(node.item)) {
50090
- const childRecord = asRecord4(child2);
50428
+ const childRecord = asRecord5(child2);
50091
50429
  if (childRecord) scanExecutableScripts(childRecord, warnings);
50092
50430
  }
50093
50431
  }
@@ -50097,7 +50435,7 @@ function instrumentContractCollection(collection, index) {
50097
50435
  const inject = (item) => {
50098
50436
  if (isResolverItem(item)) return;
50099
50437
  if (item.request) {
50100
- const request = asRecord4(item.request) ?? {};
50438
+ const request = asRecord5(item.request) ?? {};
50101
50439
  const result = matchOperation(index, request);
50102
50440
  let script;
50103
50441
  if (result.operation) {
@@ -50111,15 +50449,15 @@ function instrumentContractCollection(collection, index) {
50111
50449
  } else {
50112
50450
  script = createMappingFailureScript(`No OpenAPI operation matched request ${result.method} ${result.path}`);
50113
50451
  }
50114
- const events2 = asArray3(item.event).filter((entry) => asRecord4(entry)?.listen !== "test");
50452
+ const events2 = asArray3(item.event).filter((entry) => asRecord5(entry)?.listen !== "test");
50115
50453
  item.event = [...events2, { listen: "test", script: { type: "text/javascript", exec: script } }];
50116
50454
  }
50117
50455
  for (const child2 of asArray3(item.item)) {
50118
- const childRecord = asRecord4(child2);
50456
+ const childRecord = asRecord5(child2);
50119
50457
  if (childRecord) inject(childRecord);
50120
50458
  }
50121
50459
  };
50122
- const items = asArray3(collection.item).map((entry) => asRecord4(entry)).filter((entry) => Boolean(entry)).filter((entry) => !isResolverItem(entry));
50460
+ const items = asArray3(collection.item).map((entry) => asRecord5(entry)).filter((entry) => Boolean(entry)).filter((entry) => !isResolverItem(entry));
50123
50461
  collection.item = items;
50124
50462
  for (const item of items) inject(item);
50125
50463
  const missing = index.operations.filter((operation) => !covered.has(operation.id));
@@ -62483,7 +62821,7 @@ function compileErrors(result) {
62483
62821
 
62484
62822
  // src/lib/spec/openapi-loader.ts
62485
62823
  var import_yaml2 = __toESM(require_dist(), 1);
62486
- function asRecord5(value) {
62824
+ function asRecord6(value) {
62487
62825
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
62488
62826
  return value;
62489
62827
  }
@@ -62498,7 +62836,7 @@ function parseOpenApiDocument(content) {
62498
62836
  throw new Error("CONTRACT_SPEC_PARSE_FAILED: Spec content is not valid JSON or YAML");
62499
62837
  }
62500
62838
  }
62501
- const doc = asRecord5(parsed);
62839
+ const doc = asRecord6(parsed);
62502
62840
  if (!doc) throw new Error("CONTRACT_SPEC_PARSE_FAILED: Spec content must be a JSON or YAML object");
62503
62841
  return doc;
62504
62842
  }
@@ -62526,7 +62864,7 @@ function collectExternalRefs(node, baseUrl, refs) {
62526
62864
  node.forEach((entry) => collectExternalRefs(entry, baseUrl, refs));
62527
62865
  return;
62528
62866
  }
62529
- const record = asRecord5(node);
62867
+ const record = asRecord6(node);
62530
62868
  if (!record) return;
62531
62869
  const ref = typeof record.$ref === "string" ? record.$ref : "";
62532
62870
  if (ref && !ref.startsWith("#")) {
@@ -62864,6 +63202,11 @@ function resolveInputs(env = process.env) {
62864
63202
  governanceMappingJson: parseGovernanceMappingJson(getInput2("governance-mapping-json", env)),
62865
63203
  postmanApiKey: getInput2("postman-api-key", env) ?? "",
62866
63204
  postmanAccessToken: getInput2("postman-access-token", env),
63205
+ credentialPreflight: parseEnumInput(
63206
+ "credential-preflight",
63207
+ getInput2("credential-preflight", env),
63208
+ customerPreviewActionContract.inputs["credential-preflight"].default ?? "warn"
63209
+ ),
62867
63210
  integrationBackend,
62868
63211
  folderStrategy: parseEnumInput("folder-strategy", getInput2("folder-strategy", env), "Paths"),
62869
63212
  nestedFolderHierarchy: parseBooleanInput("nested-folder-hierarchy", getInput2("nested-folder-hierarchy", env), false),
@@ -62873,6 +63216,7 @@ function resolveInputs(env = process.env) {
62873
63216
  postmanBifrostBase: endpointProfile.bifrostBaseUrl,
62874
63217
  postmanGatewayBase: endpointProfile.gatewayBaseUrl,
62875
63218
  postmanCliInstallUrl: endpointProfile.cliInstallUrl,
63219
+ postmanIapubBase: endpointProfile.iapubBaseUrl,
62876
63220
  githubRefName: env.GITHUB_REF_NAME,
62877
63221
  githubHeadRef: env.GITHUB_HEAD_REF,
62878
63222
  githubRef: env.GITHUB_REF,
@@ -62961,6 +63305,7 @@ function readActionInputs(actionCore) {
62961
63305
  INPUT_GOVERNANCE_MAPPING_JSON: optionalInput(actionCore, "governance-mapping-json") ?? customerPreviewActionContract.inputs["governance-mapping-json"].default,
62962
63306
  INPUT_POSTMAN_API_KEY: postmanApiKey,
62963
63307
  INPUT_POSTMAN_ACCESS_TOKEN: postmanAccessToken,
63308
+ INPUT_CREDENTIAL_PREFLIGHT: optionalInput(actionCore, "credential-preflight") ?? customerPreviewActionContract.inputs["credential-preflight"].default,
62964
63309
  INPUT_INTEGRATION_BACKEND: optionalInput(actionCore, "integration-backend") ?? customerPreviewActionContract.inputs["integration-backend"].default,
62965
63310
  INPUT_FOLDER_STRATEGY: optionalInput(actionCore, "folder-strategy") ?? customerPreviewActionContract.inputs["folder-strategy"].default,
62966
63311
  INPUT_NESTED_FOLDER_HIERARCHY: optionalInput(actionCore, "nested-folder-hierarchy") ?? customerPreviewActionContract.inputs["nested-folder-hierarchy"].default,
@@ -63472,8 +63817,20 @@ For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID
63472
63817
  governanceGroupName
63473
63818
  );
63474
63819
  } catch (error2) {
63820
+ const session = getMemoizedSessionIdentity();
63821
+ const advised = error2 instanceof HttpError ? adviseFromHttpError(error2, {
63822
+ operation: "governance assignment",
63823
+ hasAccessToken: Boolean(inputs.postmanAccessToken),
63824
+ sessionTeamId: session?.teamId,
63825
+ sessionRoles: session?.roles,
63826
+ sessionConsumerType: session?.consumerType,
63827
+ workspaceTeamId: inputs.workspaceTeamId,
63828
+ explicitTeamId: inputs.teamId || void 0,
63829
+ mask: createSecretMasker([inputs.postmanApiKey, inputs.postmanAccessToken])
63830
+ }) : void 0;
63831
+ const reported = advised ?? error2;
63475
63832
  dependencies.core.warning(
63476
- `Failed to assign governance group: ${error2 instanceof Error ? error2.message : String(error2)}`
63833
+ `Failed to assign governance group: ${reported instanceof Error ? reported.message : String(reported)}`
63477
63834
  );
63478
63835
  }
63479
63836
  }
@@ -64060,6 +64417,17 @@ For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID
64060
64417
  }
64061
64418
  async function runAction(actionCore = core_exports, actionExec = exec_exports, actionIo = io_exports) {
64062
64419
  const inputs = readActionInputs(actionCore);
64420
+ await runCredentialPreflight({
64421
+ apiBaseUrl: inputs.postmanApiBase,
64422
+ iapubBaseUrl: inputs.postmanIapubBase,
64423
+ postmanApiKey: inputs.postmanApiKey,
64424
+ postmanAccessToken: inputs.postmanAccessToken,
64425
+ workspaceTeamId: inputs.workspaceTeamId,
64426
+ explicitTeamId: inputs.teamId || void 0,
64427
+ mode: inputs.credentialPreflight,
64428
+ mask: createSecretMasker([inputs.postmanApiKey, inputs.postmanAccessToken]),
64429
+ log: actionCore
64430
+ });
64063
64431
  let orgMode = false;
64064
64432
  if (inputs.postmanAccessToken && inputs.teamId) {
64065
64433
  try {