@postman-cse/onboarding-insights 0.7.2 → 0.9.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/README.md CHANGED
@@ -122,7 +122,7 @@ Output is JSON to stdout. Use `--result-json` to write the same payload to a fil
122
122
 
123
123
  ```yaml
124
124
  onboarding:
125
- image: node:20
125
+ image: node:24
126
126
  script:
127
127
  - npm install -g postman-insights-onboarding-action
128
128
  - postman-insights-onboard --project-name af-cards-activation --workspace-id "$WORKSPACE_ID" --environment-id "$ENVIRONMENT_ID" --postman-access-token "$POSTMAN_ACCESS_TOKEN" --postman-api-key "$POSTMAN_API_KEY" --cluster-name "$CLUSTER_NAME" --repo-url "$CI_PROJECT_URL" --poll-timeout-seconds 180 --result-json insights-result.json --dotenv-path insights.env
@@ -131,7 +131,7 @@ onboarding:
131
131
  ### Bitbucket Pipelines
132
132
 
133
133
  ```yaml
134
- image: node:20
134
+ image: node:24
135
135
 
136
136
  pipelines:
137
137
  default:
@@ -166,8 +166,7 @@ steps:
166
166
  | `environment-id` | Yes | | Postman environment UID for the onboarding association. |
167
167
  | `system-environment-id` | No | | Postman system environment UUID for service-level Insights acknowledgment. Falls back to the value from the discovered service record. |
168
168
  | `cluster-name` | No | | Insights cluster name. When set, the action matches `{cluster-name}/{project-name}` exactly. When omitted, falls back to suffix matching. |
169
- | `git-owner` | No | `$GITHUB_REPOSITORY_OWNER` | GitHub organization or user for the repository URL. |
170
- | `git-repository-name` | No | `project-name` | GitHub repository name. Defaults to the project name. |
169
+ | `repo-url` | No | Auto-detected from CI when available | Repository URL used for Git onboarding. |
171
170
  | `postman-access-token` | Yes | | Postman session token for Bifrost API calls. See [Obtaining postman-access-token](#obtaining-postman-access-token-open-alpha). |
172
171
  | `postman-team-id` | No | | Explicit Postman team ID for org-mode Bifrost requests. When omitted, the action leaves `x-entity-team-id` unset so Bifrost resolves team context from the access token. |
173
172
  | `github-token` | No | ambient `GITHUB_TOKEN` env when exported by the workflow | Optional GitHub token passed as `git_api_key` only when repository auth is required by the onboarding endpoint. |
@@ -238,6 +237,17 @@ The action calls the following API endpoints in order:
238
237
  7. **Workspace acknowledge** -- `POST /v2/workspaces/{id}/onboarding/acknowledge` (Bifrost akita) to activate the Insights project.
239
238
  8. **Team verification token** -- `GET /v2/workspaces/{id}/team-verification-token` (Bifrost akita) to retrieve the DaemonSet telemetry token.
240
239
 
240
+ ## Contract smoke monitoring
241
+
242
+ This repo includes `.github/workflows/contract-smoke.yml`, a scheduled live contract check for the upstream APIs used by Insights onboarding.
243
+
244
+ Configure these repository secrets before enabling the workflow:
245
+
246
+ - `SMOKE_ORG_API_KEY`
247
+ - `SMOKE_ORG_ACCESS_TOKEN`
248
+
249
+ The smoke workflow verifies `/me`, `/teams`, `iapub.postman.co/api/sessions/current`, and Bifrost API key creation so auth or payload drift shows up in CI before it hits production onboarding runs.
250
+
241
251
  ## Local development
242
252
 
243
253
  ```bash
package/action.yml CHANGED
@@ -16,11 +16,8 @@ inputs:
16
16
  cluster-name:
17
17
  description: 'Insights cluster name. Matches {cluster}/{project-name} in discovered services'
18
18
  required: false
19
- git-owner:
20
- description: 'GitHub organization or user that owns the repository'
21
- required: false
22
- git-repository-name:
23
- description: 'GitHub repository name. Defaults to project-name'
19
+ repo-url:
20
+ description: 'Repository URL for Git onboarding. Auto-detected from CI context when omitted.'
24
21
  required: false
25
22
  postman-access-token:
26
23
  description: 'Postman access token for Bifrost API calls'
@@ -42,6 +39,10 @@ inputs:
42
39
  description: 'Seconds between discovery polling attempts'
43
40
  required: false
44
41
  default: '10'
42
+ postman-stack:
43
+ description: 'Postman stack profile.'
44
+ required: false
45
+ default: 'prod'
45
46
  outputs:
46
47
  discovered-service-id:
47
48
  description: 'Numeric ID from the API Catalog discovered-services list'
@@ -56,5 +57,5 @@ outputs:
56
57
  status:
57
58
  description: 'Onboarding result: success, not-found, or error'
58
59
  runs:
59
- using: 'node20'
60
+ using: 'node24'
60
61
  main: 'dist/index.cjs'
package/dist/cli.cjs CHANGED
@@ -27347,9 +27347,6 @@ function redactSecrets(input, secretValues, replacement = REDACTED) {
27347
27347
  return sanitized.split(secret).join(replacement);
27348
27348
  }, source);
27349
27349
  }
27350
- function createSecretMasker(secretValues, replacement = REDACTED) {
27351
- return (input) => redactSecrets(input, secretValues, replacement);
27352
- }
27353
27350
  function headerEntries(headers) {
27354
27351
  if (headers instanceof Headers) {
27355
27352
  return Array.from(headers.entries());
@@ -27476,20 +27473,58 @@ async function retry(operation, options = {}) {
27476
27473
  throw new Error("Retry exhausted without returning or throwing");
27477
27474
  }
27478
27475
 
27476
+ // src/lib/postman/base-urls.ts
27477
+ var POSTMAN_ENDPOINT_PROFILES = {
27478
+ prod: {
27479
+ apiBaseUrl: "https://api.getpostman.com",
27480
+ bifrostBaseUrl: "https://bifrost-premium-https-v4.gw.postman.com",
27481
+ observabilityBaseUrl: "https://api.observability.postman.com",
27482
+ observabilityEnv: "production"
27483
+ },
27484
+ beta: {
27485
+ apiBaseUrl: "https://api.getpostman-beta.com",
27486
+ bifrostBaseUrl: "https://bifrost-https-v4.gw.postman-beta.com",
27487
+ observabilityBaseUrl: "https://api.observability.postman-beta.com",
27488
+ observabilityEnv: "beta"
27489
+ }
27490
+ };
27491
+ function parsePostmanStack(value) {
27492
+ const normalized = String(value || "prod").trim().toLowerCase();
27493
+ if (normalized === "prod" || normalized === "beta") {
27494
+ return normalized;
27495
+ }
27496
+ throw new Error(`Unsupported postman-stack "${value}". Supported values: prod, beta`);
27497
+ }
27498
+ function resolvePostmanEndpointProfile(stack) {
27499
+ return POSTMAN_ENDPOINT_PROFILES[stack];
27500
+ }
27501
+
27479
27502
  // src/lib/bifrost-client.ts
27480
- var BIFROST_BASE = "https://bifrost-premium-https-v4.gw.postman.com/ws/proxy";
27503
+ var DEFAULT_BIFROST_BASE_URL = POSTMAN_ENDPOINT_PROFILES.prod.bifrostBaseUrl;
27504
+ var BIFROST_PROXY_PATH = "/ws/proxy";
27505
+ var DEFAULT_OBSERVABILITY_BASE_URL = POSTMAN_ENDPOINT_PROFILES.prod.observabilityBaseUrl;
27506
+ var DEFAULT_OBSERVABILITY_ENV = POSTMAN_ENDPOINT_PROFILES.prod.observabilityEnv;
27507
+ var MAX_DISCOVERED_SERVICE_PAGES = 100;
27508
+ var MAX_PROVIDER_SERVICE_PAGES = 100;
27481
27509
  var BifrostCatalogClient = class {
27482
27510
  accessToken;
27483
27511
  teamId;
27484
27512
  apiKey;
27485
27513
  fetchFn;
27486
27514
  secretValues;
27515
+ bifrostProxyUrl;
27516
+ observabilityBaseUrl;
27517
+ observabilityEnv;
27487
27518
  constructor(options) {
27488
27519
  this.accessToken = options.accessToken;
27489
27520
  this.teamId = options.teamId;
27490
27521
  this.apiKey = options.apiKey;
27491
27522
  this.fetchFn = options.fetchFn ?? globalThis.fetch;
27492
27523
  this.secretValues = [options.accessToken, options.apiKey].filter(Boolean);
27524
+ const base = (options.bifrostBaseUrl || DEFAULT_BIFROST_BASE_URL).replace(/\/+$/, "");
27525
+ this.bifrostProxyUrl = `${base}${BIFROST_PROXY_PATH}`;
27526
+ this.observabilityBaseUrl = (options.observabilityBaseUrl || DEFAULT_OBSERVABILITY_BASE_URL).replace(/\/+$/, "");
27527
+ this.observabilityEnv = options.observabilityEnv || DEFAULT_OBSERVABILITY_ENV;
27493
27528
  }
27494
27529
  setApiKey(apiKey) {
27495
27530
  this.apiKey = apiKey;
@@ -27513,7 +27548,7 @@ var BifrostCatalogClient = class {
27513
27548
  return h;
27514
27549
  }
27515
27550
  async proxyRequest(method, path7, body = {}) {
27516
- const response = await this.fetchFn(BIFROST_BASE, {
27551
+ const response = await this.fetchFn(this.bifrostProxyUrl, {
27517
27552
  method: "POST",
27518
27553
  headers: this.headers(),
27519
27554
  body: JSON.stringify({
@@ -27538,7 +27573,7 @@ var BifrostCatalogClient = class {
27538
27573
  return data;
27539
27574
  }
27540
27575
  async akitaProxyRequest(method, path7, body = {}) {
27541
- const response = await this.fetchFn(BIFROST_BASE, {
27576
+ const response = await this.fetchFn(this.bifrostProxyUrl, {
27542
27577
  method: "POST",
27543
27578
  headers: this.headers(),
27544
27579
  body: JSON.stringify({
@@ -27560,16 +27595,23 @@ var BifrostCatalogClient = class {
27560
27595
  async () => {
27561
27596
  const allItems = [];
27562
27597
  let cursor = null;
27563
- let hasMore = true;
27564
- while (hasMore) {
27598
+ const seenCursors = /* @__PURE__ */ new Set();
27599
+ for (let page = 0; page < MAX_DISCOVERED_SERVICE_PAGES; page += 1) {
27565
27600
  const cursorParam = cursor ? `&cursor=${encodeURIComponent(cursor)}` : "";
27566
27601
  const data = await this.proxyRequest(
27567
27602
  "GET",
27568
27603
  `/api/v1/onboarding/discovered-services?status=discovered${cursorParam}`
27569
27604
  );
27570
27605
  allItems.push(...data.items || []);
27571
- cursor = data.nextCursor || null;
27572
- hasMore = cursor !== null;
27606
+ if (data.total && allItems.length >= data.total) {
27607
+ break;
27608
+ }
27609
+ const nextCursor = data.nextCursor || null;
27610
+ if (!nextCursor || seenCursors.has(nextCursor)) {
27611
+ break;
27612
+ }
27613
+ seenCursors.add(nextCursor);
27614
+ cursor = nextCursor;
27573
27615
  }
27574
27616
  return allItems;
27575
27617
  },
@@ -27616,8 +27658,7 @@ var BifrostCatalogClient = class {
27616
27658
  const allServices = [];
27617
27659
  let page = 1;
27618
27660
  const pageSize = 100;
27619
- let hasMore = true;
27620
- while (hasMore) {
27661
+ for (let pageCount = 0; pageCount < MAX_PROVIDER_SERVICE_PAGES; pageCount += 1) {
27621
27662
  const result = await this.akitaProxyRequest(
27622
27663
  "GET",
27623
27664
  `/v2/api-catalog/services?status=discovered&populate_endpoints=false&populate_discovery_metadata=true&page=${page}&page_size=${pageSize}`
@@ -27625,7 +27666,12 @@ var BifrostCatalogClient = class {
27625
27666
  if (!result.ok || !result.data) return null;
27626
27667
  const services = result.data.services || [];
27627
27668
  allServices.push(...services);
27628
- hasMore = services.length >= pageSize;
27669
+ if (result.data.total && allServices.length >= result.data.total) {
27670
+ break;
27671
+ }
27672
+ if (services.length < pageSize) {
27673
+ break;
27674
+ }
27629
27675
  page++;
27630
27676
  }
27631
27677
  const fullName = clusterName ? `${clusterName}/${projectName}` : projectName;
@@ -27662,12 +27708,12 @@ var BifrostCatalogClient = class {
27662
27708
  }
27663
27709
  async createApplication(workspaceId, systemEnv) {
27664
27710
  const response = await this.fetchFn(
27665
- `https://api.observability.postman.com/v2/agent/api-catalog/workspaces/${workspaceId}/applications`,
27711
+ `${this.observabilityBaseUrl}/v2/agent/api-catalog/workspaces/${workspaceId}/applications`,
27666
27712
  {
27667
27713
  method: "POST",
27668
27714
  headers: {
27669
27715
  "x-api-key": this.apiKey,
27670
- "x-postman-env": "production",
27716
+ "x-postman-env": this.observabilityEnv,
27671
27717
  "Content-Type": "application/json"
27672
27718
  },
27673
27719
  body: JSON.stringify({ system_env: systemEnv })
@@ -27691,7 +27737,7 @@ var BifrostCatalogClient = class {
27691
27737
  return result.data.team_verification_token || null;
27692
27738
  }
27693
27739
  async createApiKey(name) {
27694
- const response = await this.fetchFn(BIFROST_BASE, {
27740
+ const response = await this.fetchFn(this.bifrostProxyUrl, {
27695
27741
  method: "POST",
27696
27742
  headers: this.headers(),
27697
27743
  body: JSON.stringify({
@@ -27731,8 +27777,15 @@ var POLL_TIMEOUT_DEFAULT = 120;
27731
27777
  var POLL_INTERVAL_MIN = 2;
27732
27778
  var POLL_INTERVAL_MAX = 60;
27733
27779
  var POLL_INTERVAL_DEFAULT = 10;
27734
- async function validateApiKey(apiKey) {
27735
- const res = await fetch("https://api.getpostman.com/me", {
27780
+ var PROD_ENDPOINTS = resolvePostmanEndpointProfile("prod");
27781
+ var DEFAULT_POSTMAN_API_BASE = PROD_ENDPOINTS.apiBaseUrl;
27782
+ var DEFAULT_POSTMAN_BIFROST_BASE = PROD_ENDPOINTS.bifrostBaseUrl;
27783
+ var DEFAULT_POSTMAN_OBSERVABILITY_BASE = PROD_ENDPOINTS.observabilityBaseUrl;
27784
+ function trimTrailingSlash(value) {
27785
+ return value.replace(/\/+$/, "");
27786
+ }
27787
+ async function validateApiKey(apiKey, apiBase = DEFAULT_POSTMAN_API_BASE) {
27788
+ const res = await fetch(`${trimTrailingSlash(apiBase)}/me`, {
27736
27789
  method: "GET",
27737
27790
  headers: { "x-api-key": apiKey }
27738
27791
  });
@@ -27746,6 +27799,23 @@ async function validateApiKey(apiKey) {
27746
27799
  const teamId = data?.user?.teamId ? String(data.user.teamId) : void 0;
27747
27800
  return { valid: true, teamId };
27748
27801
  }
27802
+ async function getTeams(apiKey, apiBase = DEFAULT_POSTMAN_API_BASE) {
27803
+ try {
27804
+ const res = await fetch(`${trimTrailingSlash(apiBase)}/teams`, {
27805
+ method: "GET",
27806
+ headers: { "x-api-key": apiKey }
27807
+ });
27808
+ if (!res.ok) return [];
27809
+ const data = await res.json();
27810
+ return (data?.data ?? []).filter((t) => t?.id && t?.name).map((t) => ({
27811
+ id: Number(t.id),
27812
+ name: String(t.name),
27813
+ ...t.organizationId != null ? { organizationId: Number(t.organizationId) } : {}
27814
+ }));
27815
+ } catch {
27816
+ return [];
27817
+ }
27818
+ }
27749
27819
  function clamp(value, min, max, fallback) {
27750
27820
  const parsed = Number.isFinite(value) ? value : fallback;
27751
27821
  return Math.min(max, Math.max(min, parsed));
@@ -27758,33 +27828,42 @@ function resolveInputs(env = process.env) {
27758
27828
  if (!postmanAccessToken) throw new Error("postman-access-token is required");
27759
27829
  const postmanApiKey = get("postman-api-key");
27760
27830
  const postmanTeamId = get("postman-team-id") || env.POSTMAN_TEAM_ID?.trim() || "";
27761
- const workspaceId = get("workspace-id");
27762
- if (!workspaceId) throw new Error("workspace-id is required");
27763
- const environmentId = get("environment-id");
27764
- if (!environmentId) throw new Error("environment-id is required");
27765
- const repoSlug = env.GITHUB_REPOSITORY || env.CI_PROJECT_PATH || (env.BITBUCKET_WORKSPACE && env.BITBUCKET_REPO_SLUG ? `${env.BITBUCKET_WORKSPACE}/${env.BITBUCKET_REPO_SLUG}` : "") || env.BUILD_REPOSITORY_NAME || "";
27766
- const repoOwner = repoSlug.split("/")[0] || "";
27767
- const gitOwner = get("git-owner", repoOwner);
27768
- const gitRepositoryName = get("git-repository-name", projectName);
27831
+ const workspaceId = get("workspace-id") || env.POSTMAN_WORKSPACE_ID?.trim() || "";
27832
+ if (!workspaceId) {
27833
+ throw new Error(
27834
+ "workspace-id is required. Provide it as an input, or set the POSTMAN_WORKSPACE_ID environment variable."
27835
+ );
27836
+ }
27837
+ const environmentId = get("environment-id") || env.POSTMAN_ENVIRONMENT_ID?.trim() || "";
27838
+ if (!environmentId) {
27839
+ throw new Error(
27840
+ "environment-id is required. Provide it as an input, or set the POSTMAN_ENVIRONMENT_ID environment variable."
27841
+ );
27842
+ }
27769
27843
  const detectedRepoUrl = (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY ? `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}` : "") || env.CI_PROJECT_URL || env.BITBUCKET_GIT_HTTP_ORIGIN || env.BUILD_REPOSITORY_URI || "";
27770
- const repoUrl = get("repo-url", detectedRepoUrl || `https://github.com/${gitOwner}/${gitRepositoryName}`);
27844
+ const repoUrl = get("repo-url", detectedRepoUrl);
27771
27845
  const rawTimeout = parseInt(get("poll-timeout-seconds", String(POLL_TIMEOUT_DEFAULT)), 10);
27772
27846
  const rawInterval = parseInt(get("poll-interval-seconds", String(POLL_INTERVAL_DEFAULT)), 10);
27847
+ const postmanStack = parsePostmanStack(get("postman-stack"));
27848
+ const endpointProfile = resolvePostmanEndpointProfile(postmanStack);
27773
27849
  return {
27774
27850
  projectName,
27775
27851
  workspaceId,
27776
27852
  environmentId,
27777
27853
  systemEnvironmentId: get("system-environment-id", ""),
27778
27854
  clusterName: get("cluster-name", ""),
27779
- gitOwner,
27780
- gitRepositoryName,
27781
27855
  repoUrl,
27782
27856
  postmanAccessToken,
27783
27857
  postmanApiKey,
27784
27858
  postmanTeamId,
27785
27859
  githubToken: get("github-token", env.GITHUB_TOKEN || ""),
27786
27860
  pollTimeoutSeconds: clamp(rawTimeout, POLL_TIMEOUT_MIN, POLL_TIMEOUT_MAX, POLL_TIMEOUT_DEFAULT),
27787
- pollIntervalSeconds: clamp(rawInterval, POLL_INTERVAL_MIN, POLL_INTERVAL_MAX, POLL_INTERVAL_DEFAULT)
27861
+ pollIntervalSeconds: clamp(rawInterval, POLL_INTERVAL_MIN, POLL_INTERVAL_MAX, POLL_INTERVAL_DEFAULT),
27862
+ postmanStack,
27863
+ postmanApiBase: endpointProfile.apiBaseUrl,
27864
+ postmanBifrostBase: endpointProfile.bifrostBaseUrl,
27865
+ postmanObservabilityBase: endpointProfile.observabilityBaseUrl,
27866
+ postmanObservabilityEnv: endpointProfile.observabilityEnv
27788
27867
  };
27789
27868
  }
27790
27869
  function createPlannedOutputs(inputs) {
@@ -27888,15 +27967,12 @@ async function resolveApiKeyAndTeamId(inputs, client, reporter = core_exports) {
27888
27967
  let apiKey = inputs.postmanApiKey;
27889
27968
  const teamId = inputs.postmanTeamId;
27890
27969
  let keyValid = false;
27970
+ const apiBase = inputs.postmanApiBase || DEFAULT_POSTMAN_API_BASE;
27891
27971
  if (apiKey) {
27892
- try {
27893
- const result = await validateApiKey(apiKey);
27894
- keyValid = result.valid;
27895
- if (!keyValid) {
27896
- reporter.warning("Provided postman-api-key is invalid or expired.");
27897
- }
27898
- } catch (error2) {
27899
- throw error2;
27972
+ const result = await validateApiKey(apiKey, apiBase);
27973
+ keyValid = result.valid;
27974
+ if (!keyValid) {
27975
+ reporter.warning("Provided postman-api-key is invalid or expired.");
27900
27976
  }
27901
27977
  }
27902
27978
  if (!keyValid) {
@@ -27907,12 +27983,42 @@ async function resolveApiKeyAndTeamId(inputs, client, reporter = core_exports) {
27907
27983
  client.setApiKey(apiKey);
27908
27984
  reporter.info("New API key created successfully.");
27909
27985
  }
27910
- if (teamId) {
27911
- reporter.info(`Using explicit postman-team-id for Bifrost headers: ${teamId}`);
27986
+ let resolvedTeamId = teamId;
27987
+ if (!resolvedTeamId && apiKey) {
27988
+ try {
27989
+ const teams = await getTeams(apiKey, apiBase);
27990
+ if (teams.length > 1 && teams.every((t) => t.organizationId == null)) {
27991
+ reporter.warning(
27992
+ "GET /teams returned multiple teams but none include organizationId. Org-mode auto-detection may be degraded due to an upstream API change. Set postman-team-id explicitly if Bifrost calls fail."
27993
+ );
27994
+ }
27995
+ const isOrgMode = teams.some((t) => t.organizationId != null);
27996
+ if (isOrgMode) {
27997
+ if (teams.length === 1) {
27998
+ resolvedTeamId = String(teams[0].id);
27999
+ reporter.info(
28000
+ `Org-mode account detected. Using sub-team ${teams[0].id} (${teams[0].name ?? "unknown"}) for Bifrost calls.`
28001
+ );
28002
+ } else {
28003
+ const meResult = await validateApiKey(apiKey, apiBase);
28004
+ const meTeamId = meResult.teamId ? parseInt(meResult.teamId, 10) : NaN;
28005
+ if (!Number.isNaN(meTeamId) && teams.some((t) => t.id === meTeamId)) {
28006
+ resolvedTeamId = String(meTeamId);
28007
+ reporter.info(
28008
+ `Org-mode account detected. Using sub-team ${meTeamId} (from /me) for Bifrost calls.`
28009
+ );
28010
+ }
28011
+ }
28012
+ }
28013
+ } catch {
28014
+ }
28015
+ }
28016
+ if (resolvedTeamId) {
28017
+ reporter.info(`Using postman-team-id for Bifrost headers: ${resolvedTeamId}`);
27912
28018
  } else {
27913
- reporter.info("No explicit postman-team-id provided; omitting x-entity-team-id so Bifrost resolves team from the access token.");
28019
+ reporter.info("No postman-team-id resolved; omitting x-entity-team-id so Bifrost resolves team from the access token.");
27914
28020
  }
27915
- return { apiKey, teamId };
28021
+ return { apiKey, teamId: resolvedTeamId };
27916
28022
  }
27917
28023
  async function runAction() {
27918
28024
  const inputs = resolveInputs();
@@ -27920,11 +28026,6 @@ async function runAction() {
27920
28026
  for (const [key, value] of Object.entries(planned)) {
27921
28027
  setOutput(key, value);
27922
28028
  }
27923
- const maskSecret = createSecretMasker([
27924
- inputs.postmanAccessToken,
27925
- inputs.postmanApiKey,
27926
- inputs.githubToken
27927
- ].filter(Boolean));
27928
28029
  setSecret(inputs.postmanAccessToken);
27929
28030
  if (inputs.postmanApiKey) setSecret(inputs.postmanApiKey);
27930
28031
  if (inputs.githubToken) setSecret(inputs.githubToken);
@@ -27932,14 +28033,18 @@ async function runAction() {
27932
28033
  accessToken: inputs.postmanAccessToken,
27933
28034
  teamId: inputs.postmanTeamId,
27934
28035
  apiKey: inputs.postmanApiKey,
27935
- maskSecret
28036
+ bifrostBaseUrl: inputs.postmanBifrostBase,
28037
+ observabilityBaseUrl: inputs.postmanObservabilityBase,
28038
+ observabilityEnv: inputs.postmanObservabilityEnv
27936
28039
  });
27937
28040
  const { apiKey, teamId } = await resolveApiKeyAndTeamId(inputs, preliminaryClient, core_exports);
27938
28041
  const client = new BifrostCatalogClient({
27939
28042
  accessToken: inputs.postmanAccessToken,
27940
28043
  teamId,
27941
28044
  apiKey,
27942
- maskSecret
28045
+ bifrostBaseUrl: inputs.postmanBifrostBase,
28046
+ observabilityBaseUrl: inputs.postmanObservabilityBase,
28047
+ observabilityEnv: inputs.postmanObservabilityEnv
27943
28048
  });
27944
28049
  let result;
27945
28050
  try {
@@ -28014,15 +28119,14 @@ function parseCliArgs(argv, env = process.env) {
28014
28119
  "environment-id",
28015
28120
  "system-environment-id",
28016
28121
  "cluster-name",
28017
- "git-owner",
28018
- "git-repository-name",
28019
28122
  "repo-url",
28020
28123
  "postman-access-token",
28021
28124
  "postman-api-key",
28022
28125
  "postman-team-id",
28023
28126
  "github-token",
28024
28127
  "poll-timeout-seconds",
28025
- "poll-interval-seconds"
28128
+ "poll-interval-seconds",
28129
+ "postman-stack"
28026
28130
  ];
28027
28131
  const inputEnv = { ...env };
28028
28132
  for (const name of inputNames) {
@@ -28078,31 +28182,25 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
28078
28182
  if (inputs.githubToken) {
28079
28183
  reporter.setSecret(inputs.githubToken);
28080
28184
  }
28081
- const preliminaryMaskSecret = createSecretMasker([
28082
- inputs.postmanAccessToken,
28083
- inputs.postmanApiKey,
28084
- inputs.githubToken
28085
- ]);
28086
28185
  const preliminaryClient = new BifrostCatalogClient({
28087
28186
  accessToken: inputs.postmanAccessToken,
28088
28187
  teamId: inputs.postmanTeamId,
28089
28188
  apiKey: inputs.postmanApiKey,
28090
- maskSecret: preliminaryMaskSecret
28189
+ bifrostBaseUrl: inputs.postmanBifrostBase,
28190
+ observabilityBaseUrl: inputs.postmanObservabilityBase,
28191
+ observabilityEnv: inputs.postmanObservabilityEnv
28091
28192
  });
28092
28193
  const { apiKey, teamId } = await resolveApiKeyAndTeamId(inputs, preliminaryClient, reporter);
28093
28194
  if (apiKey) {
28094
28195
  reporter.setSecret(apiKey);
28095
28196
  }
28096
- const maskSecret = createSecretMasker([
28097
- inputs.postmanAccessToken,
28098
- inputs.githubToken,
28099
- apiKey
28100
- ]);
28101
28197
  const client = new BifrostCatalogClient({
28102
28198
  accessToken: inputs.postmanAccessToken,
28103
28199
  teamId,
28104
28200
  apiKey,
28105
- maskSecret
28201
+ bifrostBaseUrl: inputs.postmanBifrostBase,
28202
+ observabilityBaseUrl: inputs.postmanObservabilityBase,
28203
+ observabilityEnv: inputs.postmanObservabilityEnv
28106
28204
  });
28107
28205
  const result = await (runtime.executeOnboarding ?? runOnboarding)(
28108
28206
  inputs,
package/dist/index.cjs CHANGED
@@ -25012,9 +25012,11 @@ ${captureLines}` : capture.stack;
25012
25012
  // src/index.ts
25013
25013
  var index_exports = {};
25014
25014
  __export(index_exports, {
25015
+ DEFAULT_POSTMAN_API_BASE: () => DEFAULT_POSTMAN_API_BASE,
25016
+ DEFAULT_POSTMAN_BIFROST_BASE: () => DEFAULT_POSTMAN_BIFROST_BASE,
25017
+ DEFAULT_POSTMAN_OBSERVABILITY_BASE: () => DEFAULT_POSTMAN_OBSERVABILITY_BASE,
25015
25018
  createPlannedOutputs: () => createPlannedOutputs,
25016
- deriveTeamId: () => deriveTeamId,
25017
- deriveTeamIdFromSession: () => deriveTeamIdFromSession,
25019
+ getTeams: () => getTeams,
25018
25020
  resolveApiKeyAndTeamId: () => resolveApiKeyAndTeamId,
25019
25021
  resolveInputs: () => resolveInputs,
25020
25022
  runOnboarding: () => runOnboarding,
@@ -27347,9 +27349,6 @@ function redactSecrets(input, secretValues, replacement = REDACTED) {
27347
27349
  return sanitized.split(secret).join(replacement);
27348
27350
  }, source);
27349
27351
  }
27350
- function createSecretMasker(secretValues, replacement = REDACTED) {
27351
- return (input) => redactSecrets(input, secretValues, replacement);
27352
- }
27353
27352
  function headerEntries(headers) {
27354
27353
  if (headers instanceof Headers) {
27355
27354
  return Array.from(headers.entries());
@@ -27476,20 +27475,58 @@ async function retry(operation, options = {}) {
27476
27475
  throw new Error("Retry exhausted without returning or throwing");
27477
27476
  }
27478
27477
 
27478
+ // src/lib/postman/base-urls.ts
27479
+ var POSTMAN_ENDPOINT_PROFILES = {
27480
+ prod: {
27481
+ apiBaseUrl: "https://api.getpostman.com",
27482
+ bifrostBaseUrl: "https://bifrost-premium-https-v4.gw.postman.com",
27483
+ observabilityBaseUrl: "https://api.observability.postman.com",
27484
+ observabilityEnv: "production"
27485
+ },
27486
+ beta: {
27487
+ apiBaseUrl: "https://api.getpostman-beta.com",
27488
+ bifrostBaseUrl: "https://bifrost-https-v4.gw.postman-beta.com",
27489
+ observabilityBaseUrl: "https://api.observability.postman-beta.com",
27490
+ observabilityEnv: "beta"
27491
+ }
27492
+ };
27493
+ function parsePostmanStack(value) {
27494
+ const normalized = String(value || "prod").trim().toLowerCase();
27495
+ if (normalized === "prod" || normalized === "beta") {
27496
+ return normalized;
27497
+ }
27498
+ throw new Error(`Unsupported postman-stack "${value}". Supported values: prod, beta`);
27499
+ }
27500
+ function resolvePostmanEndpointProfile(stack) {
27501
+ return POSTMAN_ENDPOINT_PROFILES[stack];
27502
+ }
27503
+
27479
27504
  // src/lib/bifrost-client.ts
27480
- var BIFROST_BASE = "https://bifrost-premium-https-v4.gw.postman.com/ws/proxy";
27505
+ var DEFAULT_BIFROST_BASE_URL = POSTMAN_ENDPOINT_PROFILES.prod.bifrostBaseUrl;
27506
+ var BIFROST_PROXY_PATH = "/ws/proxy";
27507
+ var DEFAULT_OBSERVABILITY_BASE_URL = POSTMAN_ENDPOINT_PROFILES.prod.observabilityBaseUrl;
27508
+ var DEFAULT_OBSERVABILITY_ENV = POSTMAN_ENDPOINT_PROFILES.prod.observabilityEnv;
27509
+ var MAX_DISCOVERED_SERVICE_PAGES = 100;
27510
+ var MAX_PROVIDER_SERVICE_PAGES = 100;
27481
27511
  var BifrostCatalogClient = class {
27482
27512
  accessToken;
27483
27513
  teamId;
27484
27514
  apiKey;
27485
27515
  fetchFn;
27486
27516
  secretValues;
27517
+ bifrostProxyUrl;
27518
+ observabilityBaseUrl;
27519
+ observabilityEnv;
27487
27520
  constructor(options) {
27488
27521
  this.accessToken = options.accessToken;
27489
27522
  this.teamId = options.teamId;
27490
27523
  this.apiKey = options.apiKey;
27491
27524
  this.fetchFn = options.fetchFn ?? globalThis.fetch;
27492
27525
  this.secretValues = [options.accessToken, options.apiKey].filter(Boolean);
27526
+ const base = (options.bifrostBaseUrl || DEFAULT_BIFROST_BASE_URL).replace(/\/+$/, "");
27527
+ this.bifrostProxyUrl = `${base}${BIFROST_PROXY_PATH}`;
27528
+ this.observabilityBaseUrl = (options.observabilityBaseUrl || DEFAULT_OBSERVABILITY_BASE_URL).replace(/\/+$/, "");
27529
+ this.observabilityEnv = options.observabilityEnv || DEFAULT_OBSERVABILITY_ENV;
27493
27530
  }
27494
27531
  setApiKey(apiKey) {
27495
27532
  this.apiKey = apiKey;
@@ -27513,7 +27550,7 @@ var BifrostCatalogClient = class {
27513
27550
  return h;
27514
27551
  }
27515
27552
  async proxyRequest(method, path6, body = {}) {
27516
- const response = await this.fetchFn(BIFROST_BASE, {
27553
+ const response = await this.fetchFn(this.bifrostProxyUrl, {
27517
27554
  method: "POST",
27518
27555
  headers: this.headers(),
27519
27556
  body: JSON.stringify({
@@ -27538,7 +27575,7 @@ var BifrostCatalogClient = class {
27538
27575
  return data;
27539
27576
  }
27540
27577
  async akitaProxyRequest(method, path6, body = {}) {
27541
- const response = await this.fetchFn(BIFROST_BASE, {
27578
+ const response = await this.fetchFn(this.bifrostProxyUrl, {
27542
27579
  method: "POST",
27543
27580
  headers: this.headers(),
27544
27581
  body: JSON.stringify({
@@ -27560,16 +27597,23 @@ var BifrostCatalogClient = class {
27560
27597
  async () => {
27561
27598
  const allItems = [];
27562
27599
  let cursor = null;
27563
- let hasMore = true;
27564
- while (hasMore) {
27600
+ const seenCursors = /* @__PURE__ */ new Set();
27601
+ for (let page = 0; page < MAX_DISCOVERED_SERVICE_PAGES; page += 1) {
27565
27602
  const cursorParam = cursor ? `&cursor=${encodeURIComponent(cursor)}` : "";
27566
27603
  const data = await this.proxyRequest(
27567
27604
  "GET",
27568
27605
  `/api/v1/onboarding/discovered-services?status=discovered${cursorParam}`
27569
27606
  );
27570
27607
  allItems.push(...data.items || []);
27571
- cursor = data.nextCursor || null;
27572
- hasMore = cursor !== null;
27608
+ if (data.total && allItems.length >= data.total) {
27609
+ break;
27610
+ }
27611
+ const nextCursor = data.nextCursor || null;
27612
+ if (!nextCursor || seenCursors.has(nextCursor)) {
27613
+ break;
27614
+ }
27615
+ seenCursors.add(nextCursor);
27616
+ cursor = nextCursor;
27573
27617
  }
27574
27618
  return allItems;
27575
27619
  },
@@ -27616,8 +27660,7 @@ var BifrostCatalogClient = class {
27616
27660
  const allServices = [];
27617
27661
  let page = 1;
27618
27662
  const pageSize = 100;
27619
- let hasMore = true;
27620
- while (hasMore) {
27663
+ for (let pageCount = 0; pageCount < MAX_PROVIDER_SERVICE_PAGES; pageCount += 1) {
27621
27664
  const result = await this.akitaProxyRequest(
27622
27665
  "GET",
27623
27666
  `/v2/api-catalog/services?status=discovered&populate_endpoints=false&populate_discovery_metadata=true&page=${page}&page_size=${pageSize}`
@@ -27625,7 +27668,12 @@ var BifrostCatalogClient = class {
27625
27668
  if (!result.ok || !result.data) return null;
27626
27669
  const services = result.data.services || [];
27627
27670
  allServices.push(...services);
27628
- hasMore = services.length >= pageSize;
27671
+ if (result.data.total && allServices.length >= result.data.total) {
27672
+ break;
27673
+ }
27674
+ if (services.length < pageSize) {
27675
+ break;
27676
+ }
27629
27677
  page++;
27630
27678
  }
27631
27679
  const fullName = clusterName ? `${clusterName}/${projectName}` : projectName;
@@ -27662,12 +27710,12 @@ var BifrostCatalogClient = class {
27662
27710
  }
27663
27711
  async createApplication(workspaceId, systemEnv) {
27664
27712
  const response = await this.fetchFn(
27665
- `https://api.observability.postman.com/v2/agent/api-catalog/workspaces/${workspaceId}/applications`,
27713
+ `${this.observabilityBaseUrl}/v2/agent/api-catalog/workspaces/${workspaceId}/applications`,
27666
27714
  {
27667
27715
  method: "POST",
27668
27716
  headers: {
27669
27717
  "x-api-key": this.apiKey,
27670
- "x-postman-env": "production",
27718
+ "x-postman-env": this.observabilityEnv,
27671
27719
  "Content-Type": "application/json"
27672
27720
  },
27673
27721
  body: JSON.stringify({ system_env: systemEnv })
@@ -27691,7 +27739,7 @@ var BifrostCatalogClient = class {
27691
27739
  return result.data.team_verification_token || null;
27692
27740
  }
27693
27741
  async createApiKey(name) {
27694
- const response = await this.fetchFn(BIFROST_BASE, {
27742
+ const response = await this.fetchFn(this.bifrostProxyUrl, {
27695
27743
  method: "POST",
27696
27744
  headers: this.headers(),
27697
27745
  body: JSON.stringify({
@@ -27731,21 +27779,15 @@ var POLL_TIMEOUT_DEFAULT = 120;
27731
27779
  var POLL_INTERVAL_MIN = 2;
27732
27780
  var POLL_INTERVAL_MAX = 60;
27733
27781
  var POLL_INTERVAL_DEFAULT = 10;
27734
- async function deriveTeamId(apiKey) {
27735
- try {
27736
- const res = await fetch("https://api.getpostman.com/me", {
27737
- method: "GET",
27738
- headers: { "x-api-key": apiKey }
27739
- });
27740
- if (!res.ok) return void 0;
27741
- const data = await res.json();
27742
- if (data?.user?.teamId) return String(data.user.teamId);
27743
- } catch {
27744
- }
27745
- return void 0;
27782
+ var PROD_ENDPOINTS = resolvePostmanEndpointProfile("prod");
27783
+ var DEFAULT_POSTMAN_API_BASE = PROD_ENDPOINTS.apiBaseUrl;
27784
+ var DEFAULT_POSTMAN_BIFROST_BASE = PROD_ENDPOINTS.bifrostBaseUrl;
27785
+ var DEFAULT_POSTMAN_OBSERVABILITY_BASE = PROD_ENDPOINTS.observabilityBaseUrl;
27786
+ function trimTrailingSlash(value) {
27787
+ return value.replace(/\/+$/, "");
27746
27788
  }
27747
- async function validateApiKey(apiKey) {
27748
- const res = await fetch("https://api.getpostman.com/me", {
27789
+ async function validateApiKey(apiKey, apiBase = DEFAULT_POSTMAN_API_BASE) {
27790
+ const res = await fetch(`${trimTrailingSlash(apiBase)}/me`, {
27749
27791
  method: "GET",
27750
27792
  headers: { "x-api-key": apiKey }
27751
27793
  });
@@ -27759,18 +27801,22 @@ async function validateApiKey(apiKey) {
27759
27801
  const teamId = data?.user?.teamId ? String(data.user.teamId) : void 0;
27760
27802
  return { valid: true, teamId };
27761
27803
  }
27762
- async function deriveTeamIdFromSession(accessToken) {
27804
+ async function getTeams(apiKey, apiBase = DEFAULT_POSTMAN_API_BASE) {
27763
27805
  try {
27764
- const res = await fetch("https://iapub.postman.co/api/sessions/current", {
27806
+ const res = await fetch(`${trimTrailingSlash(apiBase)}/teams`, {
27765
27807
  method: "GET",
27766
- headers: { "x-access-token": accessToken }
27808
+ headers: { "x-api-key": apiKey }
27767
27809
  });
27768
- if (!res.ok) return void 0;
27810
+ if (!res.ok) return [];
27769
27811
  const data = await res.json();
27770
- if (data?.session?.identity?.team) return String(data.session.identity.team);
27812
+ return (data?.data ?? []).filter((t) => t?.id && t?.name).map((t) => ({
27813
+ id: Number(t.id),
27814
+ name: String(t.name),
27815
+ ...t.organizationId != null ? { organizationId: Number(t.organizationId) } : {}
27816
+ }));
27771
27817
  } catch {
27818
+ return [];
27772
27819
  }
27773
- return void 0;
27774
27820
  }
27775
27821
  function clamp(value, min, max, fallback) {
27776
27822
  const parsed = Number.isFinite(value) ? value : fallback;
@@ -27784,33 +27830,42 @@ function resolveInputs(env = process.env) {
27784
27830
  if (!postmanAccessToken) throw new Error("postman-access-token is required");
27785
27831
  const postmanApiKey = get("postman-api-key");
27786
27832
  const postmanTeamId = get("postman-team-id") || env.POSTMAN_TEAM_ID?.trim() || "";
27787
- const workspaceId = get("workspace-id");
27788
- if (!workspaceId) throw new Error("workspace-id is required");
27789
- const environmentId = get("environment-id");
27790
- if (!environmentId) throw new Error("environment-id is required");
27791
- const repoSlug = env.GITHUB_REPOSITORY || env.CI_PROJECT_PATH || (env.BITBUCKET_WORKSPACE && env.BITBUCKET_REPO_SLUG ? `${env.BITBUCKET_WORKSPACE}/${env.BITBUCKET_REPO_SLUG}` : "") || env.BUILD_REPOSITORY_NAME || "";
27792
- const repoOwner = repoSlug.split("/")[0] || "";
27793
- const gitOwner = get("git-owner", repoOwner);
27794
- const gitRepositoryName = get("git-repository-name", projectName);
27833
+ const workspaceId = get("workspace-id") || env.POSTMAN_WORKSPACE_ID?.trim() || "";
27834
+ if (!workspaceId) {
27835
+ throw new Error(
27836
+ "workspace-id is required. Provide it as an input, or set the POSTMAN_WORKSPACE_ID environment variable."
27837
+ );
27838
+ }
27839
+ const environmentId = get("environment-id") || env.POSTMAN_ENVIRONMENT_ID?.trim() || "";
27840
+ if (!environmentId) {
27841
+ throw new Error(
27842
+ "environment-id is required. Provide it as an input, or set the POSTMAN_ENVIRONMENT_ID environment variable."
27843
+ );
27844
+ }
27795
27845
  const detectedRepoUrl = (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY ? `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}` : "") || env.CI_PROJECT_URL || env.BITBUCKET_GIT_HTTP_ORIGIN || env.BUILD_REPOSITORY_URI || "";
27796
- const repoUrl = get("repo-url", detectedRepoUrl || `https://github.com/${gitOwner}/${gitRepositoryName}`);
27846
+ const repoUrl = get("repo-url", detectedRepoUrl);
27797
27847
  const rawTimeout = parseInt(get("poll-timeout-seconds", String(POLL_TIMEOUT_DEFAULT)), 10);
27798
27848
  const rawInterval = parseInt(get("poll-interval-seconds", String(POLL_INTERVAL_DEFAULT)), 10);
27849
+ const postmanStack = parsePostmanStack(get("postman-stack"));
27850
+ const endpointProfile = resolvePostmanEndpointProfile(postmanStack);
27799
27851
  return {
27800
27852
  projectName,
27801
27853
  workspaceId,
27802
27854
  environmentId,
27803
27855
  systemEnvironmentId: get("system-environment-id", ""),
27804
27856
  clusterName: get("cluster-name", ""),
27805
- gitOwner,
27806
- gitRepositoryName,
27807
27857
  repoUrl,
27808
27858
  postmanAccessToken,
27809
27859
  postmanApiKey,
27810
27860
  postmanTeamId,
27811
27861
  githubToken: get("github-token", env.GITHUB_TOKEN || ""),
27812
27862
  pollTimeoutSeconds: clamp(rawTimeout, POLL_TIMEOUT_MIN, POLL_TIMEOUT_MAX, POLL_TIMEOUT_DEFAULT),
27813
- pollIntervalSeconds: clamp(rawInterval, POLL_INTERVAL_MIN, POLL_INTERVAL_MAX, POLL_INTERVAL_DEFAULT)
27863
+ pollIntervalSeconds: clamp(rawInterval, POLL_INTERVAL_MIN, POLL_INTERVAL_MAX, POLL_INTERVAL_DEFAULT),
27864
+ postmanStack,
27865
+ postmanApiBase: endpointProfile.apiBaseUrl,
27866
+ postmanBifrostBase: endpointProfile.bifrostBaseUrl,
27867
+ postmanObservabilityBase: endpointProfile.observabilityBaseUrl,
27868
+ postmanObservabilityEnv: endpointProfile.observabilityEnv
27814
27869
  };
27815
27870
  }
27816
27871
  function createPlannedOutputs(inputs) {
@@ -27914,15 +27969,12 @@ async function resolveApiKeyAndTeamId(inputs, client, reporter = core_exports) {
27914
27969
  let apiKey = inputs.postmanApiKey;
27915
27970
  const teamId = inputs.postmanTeamId;
27916
27971
  let keyValid = false;
27972
+ const apiBase = inputs.postmanApiBase || DEFAULT_POSTMAN_API_BASE;
27917
27973
  if (apiKey) {
27918
- try {
27919
- const result = await validateApiKey(apiKey);
27920
- keyValid = result.valid;
27921
- if (!keyValid) {
27922
- reporter.warning("Provided postman-api-key is invalid or expired.");
27923
- }
27924
- } catch (error2) {
27925
- throw error2;
27974
+ const result = await validateApiKey(apiKey, apiBase);
27975
+ keyValid = result.valid;
27976
+ if (!keyValid) {
27977
+ reporter.warning("Provided postman-api-key is invalid or expired.");
27926
27978
  }
27927
27979
  }
27928
27980
  if (!keyValid) {
@@ -27933,12 +27985,42 @@ async function resolveApiKeyAndTeamId(inputs, client, reporter = core_exports) {
27933
27985
  client.setApiKey(apiKey);
27934
27986
  reporter.info("New API key created successfully.");
27935
27987
  }
27936
- if (teamId) {
27937
- reporter.info(`Using explicit postman-team-id for Bifrost headers: ${teamId}`);
27988
+ let resolvedTeamId = teamId;
27989
+ if (!resolvedTeamId && apiKey) {
27990
+ try {
27991
+ const teams = await getTeams(apiKey, apiBase);
27992
+ if (teams.length > 1 && teams.every((t) => t.organizationId == null)) {
27993
+ reporter.warning(
27994
+ "GET /teams returned multiple teams but none include organizationId. Org-mode auto-detection may be degraded due to an upstream API change. Set postman-team-id explicitly if Bifrost calls fail."
27995
+ );
27996
+ }
27997
+ const isOrgMode = teams.some((t) => t.organizationId != null);
27998
+ if (isOrgMode) {
27999
+ if (teams.length === 1) {
28000
+ resolvedTeamId = String(teams[0].id);
28001
+ reporter.info(
28002
+ `Org-mode account detected. Using sub-team ${teams[0].id} (${teams[0].name ?? "unknown"}) for Bifrost calls.`
28003
+ );
28004
+ } else {
28005
+ const meResult = await validateApiKey(apiKey, apiBase);
28006
+ const meTeamId = meResult.teamId ? parseInt(meResult.teamId, 10) : NaN;
28007
+ if (!Number.isNaN(meTeamId) && teams.some((t) => t.id === meTeamId)) {
28008
+ resolvedTeamId = String(meTeamId);
28009
+ reporter.info(
28010
+ `Org-mode account detected. Using sub-team ${meTeamId} (from /me) for Bifrost calls.`
28011
+ );
28012
+ }
28013
+ }
28014
+ }
28015
+ } catch {
28016
+ }
28017
+ }
28018
+ if (resolvedTeamId) {
28019
+ reporter.info(`Using postman-team-id for Bifrost headers: ${resolvedTeamId}`);
27938
28020
  } else {
27939
- reporter.info("No explicit postman-team-id provided; omitting x-entity-team-id so Bifrost resolves team from the access token.");
28021
+ reporter.info("No postman-team-id resolved; omitting x-entity-team-id so Bifrost resolves team from the access token.");
27940
28022
  }
27941
- return { apiKey, teamId };
28023
+ return { apiKey, teamId: resolvedTeamId };
27942
28024
  }
27943
28025
  async function runAction() {
27944
28026
  const inputs = resolveInputs();
@@ -27946,11 +28028,6 @@ async function runAction() {
27946
28028
  for (const [key, value] of Object.entries(planned)) {
27947
28029
  setOutput(key, value);
27948
28030
  }
27949
- const maskSecret = createSecretMasker([
27950
- inputs.postmanAccessToken,
27951
- inputs.postmanApiKey,
27952
- inputs.githubToken
27953
- ].filter(Boolean));
27954
28031
  setSecret(inputs.postmanAccessToken);
27955
28032
  if (inputs.postmanApiKey) setSecret(inputs.postmanApiKey);
27956
28033
  if (inputs.githubToken) setSecret(inputs.githubToken);
@@ -27958,14 +28035,18 @@ async function runAction() {
27958
28035
  accessToken: inputs.postmanAccessToken,
27959
28036
  teamId: inputs.postmanTeamId,
27960
28037
  apiKey: inputs.postmanApiKey,
27961
- maskSecret
28038
+ bifrostBaseUrl: inputs.postmanBifrostBase,
28039
+ observabilityBaseUrl: inputs.postmanObservabilityBase,
28040
+ observabilityEnv: inputs.postmanObservabilityEnv
27962
28041
  });
27963
28042
  const { apiKey, teamId } = await resolveApiKeyAndTeamId(inputs, preliminaryClient, core_exports);
27964
28043
  const client = new BifrostCatalogClient({
27965
28044
  accessToken: inputs.postmanAccessToken,
27966
28045
  teamId,
27967
28046
  apiKey,
27968
- maskSecret
28047
+ bifrostBaseUrl: inputs.postmanBifrostBase,
28048
+ observabilityBaseUrl: inputs.postmanObservabilityBase,
28049
+ observabilityEnv: inputs.postmanObservabilityEnv
27969
28050
  });
27970
28051
  let result;
27971
28052
  try {
@@ -27996,9 +28077,11 @@ runAction().catch((error2) => {
27996
28077
  });
27997
28078
  // Annotate the CommonJS export names for ESM import in node:
27998
28079
  0 && (module.exports = {
28080
+ DEFAULT_POSTMAN_API_BASE,
28081
+ DEFAULT_POSTMAN_BIFROST_BASE,
28082
+ DEFAULT_POSTMAN_OBSERVABILITY_BASE,
27999
28083
  createPlannedOutputs,
28000
- deriveTeamId,
28001
- deriveTeamIdFromSession,
28084
+ getTeams,
28002
28085
  resolveApiKeyAndTeamId,
28003
28086
  resolveInputs,
28004
28087
  runOnboarding,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postman-cse/onboarding-insights",
3
- "version": "0.7.2",
3
+ "version": "0.9.0",
4
4
  "description": "GitHub Action to onboard Postman Insights discovered services to API Catalog workspaces.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -11,9 +11,14 @@
11
11
  "action.yml",
12
12
  "dist"
13
13
  ],
14
+ "engines": {
15
+ "node": ">=24"
16
+ },
14
17
  "scripts": {
15
- "build": "rm -rf dist && esbuild src/index.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/index.cjs && esbuild src/cli.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/cli.cjs",
18
+ "build": "rm -rf dist && esbuild src/index.ts --bundle --platform=node --target=node24 --format=cjs --outfile=dist/index.cjs && esbuild src/cli.ts --bundle --platform=node --target=node24 --format=cjs --outfile=dist/cli.cjs",
16
19
  "check:dist": "npm run build && git diff --exit-code -- dist",
20
+ "lint": "eslint .",
21
+ "lint:fix": "eslint . --fix",
17
22
  "test": "vitest run",
18
23
  "typecheck": "tsc --noEmit -p tsconfig.json"
19
24
  },
@@ -31,12 +36,18 @@
31
36
  "@actions/core": "^3.0.0"
32
37
  },
33
38
  "overrides": {
34
- "undici": ">=6.24.0"
39
+ "undici": ">=6.24.0",
40
+ "picomatch": ">=4.0.4"
35
41
  },
36
42
  "devDependencies": {
43
+ "@commitlint/cli": "^20.5.0",
44
+ "@commitlint/config-conventional": "^20.5.0",
45
+ "@eslint/js": "^10.0.1",
37
46
  "@types/node": "^25.3.5",
38
47
  "esbuild": "^0.27.3",
48
+ "eslint": "^10.1.0",
39
49
  "typescript": "^5.9.3",
50
+ "typescript-eslint": "^8.57.2",
40
51
  "vitest": "^4.0.18",
41
52
  "yaml": "^2.8.2"
42
53
  },