@postman-cse/onboarding-insights 1.0.3 → 2.0.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/cli.cjs CHANGED
@@ -12167,7 +12167,7 @@ var require_response = __commonJS({
12167
12167
  var assert = require("node:assert");
12168
12168
  var { types } = require("node:util");
12169
12169
  var textEncoder = new TextEncoder("utf-8");
12170
- var Response = class _Response {
12170
+ var Response2 = class _Response {
12171
12171
  // Creates network error Response.
12172
12172
  static error() {
12173
12173
  const responseObject = fromInnerResponse(makeNetworkError(), "immutable");
@@ -12310,8 +12310,8 @@ var require_response = __commonJS({
12310
12310
  return `Response ${nodeUtil.formatWithOptions(options, properties)}`;
12311
12311
  }
12312
12312
  };
12313
- mixinBody(Response);
12314
- Object.defineProperties(Response.prototype, {
12313
+ mixinBody(Response2);
12314
+ Object.defineProperties(Response2.prototype, {
12315
12315
  type: kEnumerableProperty,
12316
12316
  url: kEnumerableProperty,
12317
12317
  status: kEnumerableProperty,
@@ -12327,7 +12327,7 @@ var require_response = __commonJS({
12327
12327
  configurable: true
12328
12328
  }
12329
12329
  });
12330
- Object.defineProperties(Response, {
12330
+ Object.defineProperties(Response2, {
12331
12331
  json: kEnumerableProperty,
12332
12332
  redirect: kEnumerableProperty,
12333
12333
  error: kEnumerableProperty
@@ -12460,7 +12460,7 @@ var require_response = __commonJS({
12460
12460
  }
12461
12461
  }
12462
12462
  function fromInnerResponse(innerResponse, guard) {
12463
- const response = new Response(kConstruct);
12463
+ const response = new Response2(kConstruct);
12464
12464
  response[kState] = innerResponse;
12465
12465
  response[kHeaders] = new Headers3(kConstruct);
12466
12466
  setHeadersList(response[kHeaders], innerResponse.headersList);
@@ -12528,7 +12528,7 @@ var require_response = __commonJS({
12528
12528
  makeResponse,
12529
12529
  makeAppropriateNetworkError,
12530
12530
  filterResponse,
12531
- Response,
12531
+ Response: Response2,
12532
12532
  cloneResponse,
12533
12533
  fromInnerResponse
12534
12534
  };
@@ -15200,7 +15200,7 @@ var require_cache = __commonJS({
15200
15200
  var { urlEquals, getFieldValues } = require_util5();
15201
15201
  var { kEnumerableProperty, isDisturbed } = require_util();
15202
15202
  var { webidl } = require_webidl();
15203
- var { Response, cloneResponse, fromInnerResponse } = require_response();
15203
+ var { Response: Response2, cloneResponse, fromInnerResponse } = require_response();
15204
15204
  var { Request, fromInnerRequest } = require_request2();
15205
15205
  var { kState } = require_symbols2();
15206
15206
  var { fetching } = require_fetch();
@@ -15727,7 +15727,7 @@ var require_cache = __commonJS({
15727
15727
  converter: webidl.converters.DOMString
15728
15728
  }
15729
15729
  ]);
15730
- webidl.converters.Response = webidl.interfaceConverter(Response);
15730
+ webidl.converters.Response = webidl.interfaceConverter(Response2);
15731
15731
  webidl.converters["sequence<RequestInfo>"] = webidl.sequenceConverter(
15732
15732
  webidl.converters.RequestInfo
15733
15733
  );
@@ -18689,6 +18689,209 @@ var import_node_fs = require("node:fs");
18689
18689
  var import_promises = require("node:fs/promises");
18690
18690
  var import_node_path = __toESM(require("node:path"), 1);
18691
18691
 
18692
+ // src/lib/retry.ts
18693
+ function sleep(delayMs) {
18694
+ return new Promise((resolve2) => {
18695
+ setTimeout(resolve2, delayMs);
18696
+ });
18697
+ }
18698
+ function normalizeRetryOptions(options) {
18699
+ return {
18700
+ maxAttempts: Math.max(1, options.maxAttempts ?? 3),
18701
+ delayMs: Math.max(0, options.delayMs ?? 2e3),
18702
+ backoffMultiplier: Math.max(1, options.backoffMultiplier ?? 1),
18703
+ maxDelayMs: options.maxDelayMs === void 0 ? Number.POSITIVE_INFINITY : Math.max(0, options.maxDelayMs),
18704
+ onRetry: options.onRetry ?? (async () => void 0),
18705
+ shouldRetry: options.shouldRetry ?? (() => true),
18706
+ sleep: options.sleep ?? sleep
18707
+ };
18708
+ }
18709
+ async function retry(operation, options = {}) {
18710
+ const normalized = normalizeRetryOptions(options);
18711
+ let nextDelayMs = normalized.delayMs;
18712
+ for (let attempt = 1; attempt <= normalized.maxAttempts; attempt += 1) {
18713
+ try {
18714
+ return await operation();
18715
+ } catch (error2) {
18716
+ const shouldRetry = attempt < normalized.maxAttempts && normalized.shouldRetry(error2, {
18717
+ attempt,
18718
+ maxAttempts: normalized.maxAttempts
18719
+ });
18720
+ if (!shouldRetry) {
18721
+ throw error2;
18722
+ }
18723
+ await normalized.onRetry({
18724
+ attempt,
18725
+ maxAttempts: normalized.maxAttempts,
18726
+ delayMs: nextDelayMs,
18727
+ error: error2
18728
+ });
18729
+ await normalized.sleep(nextDelayMs);
18730
+ nextDelayMs = Math.min(
18731
+ normalized.maxDelayMs,
18732
+ Math.round(nextDelayMs * normalized.backoffMultiplier)
18733
+ );
18734
+ }
18735
+ }
18736
+ throw new Error("Retry exhausted without returning or throwing");
18737
+ }
18738
+
18739
+ // src/lib/postman/base-urls.ts
18740
+ var POSTMAN_ENDPOINT_PROFILES = {
18741
+ prod: {
18742
+ apiBaseUrl: "https://api.getpostman.com",
18743
+ bifrostBaseUrl: "https://bifrost-premium-https-v4.gw.postman.com",
18744
+ iapubBaseUrl: "https://iapub.postman.co",
18745
+ observabilityBaseUrl: "https://api.observability.postman.com",
18746
+ observabilityEnv: "production"
18747
+ },
18748
+ beta: {
18749
+ apiBaseUrl: "https://api.getpostman-beta.com",
18750
+ bifrostBaseUrl: "https://bifrost-https-v4.gw.postman-beta.com",
18751
+ iapubBaseUrl: "https://iapub.postman.co",
18752
+ observabilityBaseUrl: "https://api.observability.postman-beta.com",
18753
+ observabilityEnv: "beta"
18754
+ }
18755
+ };
18756
+ function parsePostmanRegion(value) {
18757
+ const normalized = String(value || "us").trim().toLowerCase();
18758
+ if (normalized === "us" || normalized === "eu") {
18759
+ return normalized;
18760
+ }
18761
+ throw new Error(`Unsupported postman-region "${value}". Supported values: us, eu`);
18762
+ }
18763
+ function parsePostmanStack(value) {
18764
+ const normalized = String(value || "prod").trim().toLowerCase();
18765
+ if (normalized === "prod" || normalized === "beta") {
18766
+ return normalized;
18767
+ }
18768
+ throw new Error(`Unsupported postman-stack "${value}". Supported values: prod, beta`);
18769
+ }
18770
+ function resolvePostmanEndpointProfile(stack, region = "us") {
18771
+ if (stack === "beta" && region !== "us") {
18772
+ throw new Error("postman-region=eu is only supported with postman-stack=prod");
18773
+ }
18774
+ const profile = POSTMAN_ENDPOINT_PROFILES[stack];
18775
+ if (region === "eu") {
18776
+ return {
18777
+ ...profile,
18778
+ apiBaseUrl: "https://api.eu.postman.com"
18779
+ };
18780
+ }
18781
+ return profile;
18782
+ }
18783
+
18784
+ // src/lib/postman/token-provider.ts
18785
+ var MintError = class extends Error {
18786
+ permanent;
18787
+ constructor(message, permanent) {
18788
+ super(message);
18789
+ this.name = "MintError";
18790
+ this.permanent = permanent;
18791
+ }
18792
+ };
18793
+ function extractAccessToken(payload) {
18794
+ if (!payload || typeof payload !== "object") return void 0;
18795
+ const record = payload;
18796
+ const direct = record.access_token;
18797
+ if (typeof direct === "string" && direct.trim()) return direct.trim();
18798
+ const session = record.session;
18799
+ if (session && typeof session === "object") {
18800
+ const token = session.token;
18801
+ if (typeof token === "string" && token.trim()) return token.trim();
18802
+ }
18803
+ return void 0;
18804
+ }
18805
+ var AccessTokenProvider = class {
18806
+ token;
18807
+ apiKey;
18808
+ apiBaseUrl;
18809
+ fetchImpl;
18810
+ maxAttempts;
18811
+ onToken;
18812
+ sleep;
18813
+ inflight;
18814
+ constructor(options) {
18815
+ this.token = String(options.accessToken || "").trim();
18816
+ this.apiKey = String(options.apiKey || "").trim();
18817
+ this.apiBaseUrl = String(
18818
+ options.apiBaseUrl || POSTMAN_ENDPOINT_PROFILES.prod.apiBaseUrl
18819
+ ).replace(/\/+$/, "");
18820
+ this.fetchImpl = options.fetchImpl ?? fetch;
18821
+ this.maxAttempts = Math.max(1, options.maxAttempts ?? 2);
18822
+ this.onToken = options.onToken;
18823
+ this.sleep = options.sleep;
18824
+ }
18825
+ current() {
18826
+ return this.token;
18827
+ }
18828
+ /** True when a PMAK is present, so an expired token can be re-minted. */
18829
+ canRefresh() {
18830
+ return Boolean(this.apiKey);
18831
+ }
18832
+ refresh() {
18833
+ this.inflight ??= this.mintWithRetry().finally(() => {
18834
+ this.inflight = void 0;
18835
+ });
18836
+ return this.inflight;
18837
+ }
18838
+ async mintWithRetry() {
18839
+ if (!this.apiKey) {
18840
+ throw new Error(
18841
+ "postman: the access token expired and cannot be refreshed because no postman-api-key is present. Service-account access tokens expire after about 1 to 1.5 hours. Re-mint a fresh token (postman-resolve-service-token-action) and re-run."
18842
+ );
18843
+ }
18844
+ const token = await retry(() => this.mintOnce(), {
18845
+ maxAttempts: this.maxAttempts,
18846
+ delayMs: 1e3,
18847
+ backoffMultiplier: 2,
18848
+ ...this.sleep ? { sleep: this.sleep } : {},
18849
+ shouldRetry: (error2) => !(error2 instanceof MintError && error2.permanent)
18850
+ });
18851
+ this.token = token;
18852
+ this.onToken?.(token);
18853
+ return token;
18854
+ }
18855
+ async mintOnce() {
18856
+ const response = await this.fetchImpl(`${this.apiBaseUrl}/service-account-tokens`, {
18857
+ method: "POST",
18858
+ headers: {
18859
+ "Content-Type": "application/json",
18860
+ "x-api-key": this.apiKey
18861
+ },
18862
+ body: JSON.stringify({ apiKey: this.apiKey })
18863
+ });
18864
+ const body = await response.text().catch(() => "");
18865
+ if (!response.ok) {
18866
+ const status = response.status;
18867
+ if (status === 401 || status === 403) {
18868
+ throw new MintError(
18869
+ `postman: re-mint failed because the postman-api-key was rejected (PMAK rejected, HTTP ${status}); confirm it is a valid, enabled service-account PMAK for the intended team.`,
18870
+ true
18871
+ );
18872
+ }
18873
+ if (status === 400 && body.toLowerCase().includes("service accounts not enabled")) {
18874
+ throw new MintError(
18875
+ "postman: re-mint failed because service accounts are not enabled for this team; enable them in Team Settings or use a team where they are.",
18876
+ true
18877
+ );
18878
+ }
18879
+ throw new MintError(`postman: re-mint failed (service-account-tokens HTTP ${status}).`, false);
18880
+ }
18881
+ let parsed;
18882
+ try {
18883
+ parsed = JSON.parse(body);
18884
+ } catch {
18885
+ parsed = void 0;
18886
+ }
18887
+ const token = extractAccessToken(parsed);
18888
+ if (!token) {
18889
+ throw new MintError("postman: re-mint succeeded but no access token was returned.", false);
18890
+ }
18891
+ return token;
18892
+ }
18893
+ };
18894
+
18692
18895
  // node_modules/@actions/core/lib/core.js
18693
18896
  var core_exports = {};
18694
18897
  __export(core_exports, {
@@ -21404,98 +21607,6 @@ var HttpError = class _HttpError extends Error {
21404
21607
  }
21405
21608
  };
21406
21609
 
21407
- // src/lib/retry.ts
21408
- function sleep(delayMs) {
21409
- return new Promise((resolve2) => {
21410
- setTimeout(resolve2, delayMs);
21411
- });
21412
- }
21413
- function normalizeRetryOptions(options) {
21414
- return {
21415
- maxAttempts: Math.max(1, options.maxAttempts ?? 3),
21416
- delayMs: Math.max(0, options.delayMs ?? 2e3),
21417
- backoffMultiplier: Math.max(1, options.backoffMultiplier ?? 1),
21418
- maxDelayMs: options.maxDelayMs === void 0 ? Number.POSITIVE_INFINITY : Math.max(0, options.maxDelayMs),
21419
- onRetry: options.onRetry ?? (async () => void 0),
21420
- shouldRetry: options.shouldRetry ?? (() => true),
21421
- sleep: options.sleep ?? sleep
21422
- };
21423
- }
21424
- async function retry(operation, options = {}) {
21425
- const normalized = normalizeRetryOptions(options);
21426
- let nextDelayMs = normalized.delayMs;
21427
- for (let attempt = 1; attempt <= normalized.maxAttempts; attempt += 1) {
21428
- try {
21429
- return await operation();
21430
- } catch (error2) {
21431
- const shouldRetry = attempt < normalized.maxAttempts && normalized.shouldRetry(error2, {
21432
- attempt,
21433
- maxAttempts: normalized.maxAttempts
21434
- });
21435
- if (!shouldRetry) {
21436
- throw error2;
21437
- }
21438
- await normalized.onRetry({
21439
- attempt,
21440
- maxAttempts: normalized.maxAttempts,
21441
- delayMs: nextDelayMs,
21442
- error: error2
21443
- });
21444
- await normalized.sleep(nextDelayMs);
21445
- nextDelayMs = Math.min(
21446
- normalized.maxDelayMs,
21447
- Math.round(nextDelayMs * normalized.backoffMultiplier)
21448
- );
21449
- }
21450
- }
21451
- throw new Error("Retry exhausted without returning or throwing");
21452
- }
21453
-
21454
- // src/lib/postman/base-urls.ts
21455
- var POSTMAN_ENDPOINT_PROFILES = {
21456
- prod: {
21457
- apiBaseUrl: "https://api.getpostman.com",
21458
- bifrostBaseUrl: "https://bifrost-premium-https-v4.gw.postman.com",
21459
- iapubBaseUrl: "https://iapub.postman.co",
21460
- observabilityBaseUrl: "https://api.observability.postman.com",
21461
- observabilityEnv: "production"
21462
- },
21463
- beta: {
21464
- apiBaseUrl: "https://api.getpostman-beta.com",
21465
- bifrostBaseUrl: "https://bifrost-https-v4.gw.postman-beta.com",
21466
- iapubBaseUrl: "https://iapub.postman.co",
21467
- observabilityBaseUrl: "https://api.observability.postman-beta.com",
21468
- observabilityEnv: "beta"
21469
- }
21470
- };
21471
- function parsePostmanRegion(value) {
21472
- const normalized = String(value || "us").trim().toLowerCase();
21473
- if (normalized === "us" || normalized === "eu") {
21474
- return normalized;
21475
- }
21476
- throw new Error(`Unsupported postman-region "${value}". Supported values: us, eu`);
21477
- }
21478
- function parsePostmanStack(value) {
21479
- const normalized = String(value || "prod").trim().toLowerCase();
21480
- if (normalized === "prod" || normalized === "beta") {
21481
- return normalized;
21482
- }
21483
- throw new Error(`Unsupported postman-stack "${value}". Supported values: prod, beta`);
21484
- }
21485
- function resolvePostmanEndpointProfile(stack, region = "us") {
21486
- if (stack === "beta" && region !== "us") {
21487
- throw new Error("postman-region=eu is only supported with postman-stack=prod");
21488
- }
21489
- const profile = POSTMAN_ENDPOINT_PROFILES[stack];
21490
- if (region === "eu") {
21491
- return {
21492
- ...profile,
21493
- apiBaseUrl: "https://api.eu.postman.com"
21494
- };
21495
- }
21496
- return profile;
21497
- }
21498
-
21499
21610
  // src/lib/bifrost-client.ts
21500
21611
  var DEFAULT_BIFROST_BASE_URL = POSTMAN_ENDPOINT_PROFILES.prod.bifrostBaseUrl;
21501
21612
  var BIFROST_PROXY_PATH = "/ws/proxy";
@@ -21503,8 +21614,11 @@ var DEFAULT_OBSERVABILITY_BASE_URL = POSTMAN_ENDPOINT_PROFILES.prod.observabilit
21503
21614
  var DEFAULT_OBSERVABILITY_ENV = POSTMAN_ENDPOINT_PROFILES.prod.observabilityEnv;
21504
21615
  var MAX_DISCOVERED_SERVICE_PAGES = 100;
21505
21616
  var MAX_PROVIDER_SERVICE_PAGES = 100;
21617
+ function isExpiredAuthError(status, body) {
21618
+ return status === 401 || body.includes("UNAUTHENTICATED") || body.includes("authenticationError");
21619
+ }
21506
21620
  var BifrostCatalogClient = class {
21507
- accessToken;
21621
+ tokenProvider;
21508
21622
  teamId;
21509
21623
  apiKey;
21510
21624
  fetchFn;
@@ -21513,11 +21627,14 @@ var BifrostCatalogClient = class {
21513
21627
  observabilityBaseUrl;
21514
21628
  observabilityEnv;
21515
21629
  constructor(options) {
21516
- this.accessToken = options.accessToken;
21630
+ this.tokenProvider = options.tokenProvider ?? new AccessTokenProvider({
21631
+ accessToken: options.accessToken,
21632
+ apiKey: options.apiKey
21633
+ });
21517
21634
  this.teamId = options.teamId;
21518
21635
  this.apiKey = options.apiKey;
21519
21636
  this.fetchFn = options.fetchFn ?? globalThis.fetch;
21520
- this.secretValues = [options.accessToken, options.apiKey].filter(Boolean);
21637
+ this.secretValues = [this.tokenProvider.current(), options.apiKey].filter(Boolean);
21521
21638
  const base = (options.bifrostBaseUrl || DEFAULT_BIFROST_BASE_URL).replace(/\/+$/, "");
21522
21639
  this.bifrostProxyUrl = `${base}${BIFROST_PROXY_PATH}`;
21523
21640
  this.observabilityBaseUrl = (options.observabilityBaseUrl || DEFAULT_OBSERVABILITY_BASE_URL).replace(/\/+$/, "");
@@ -21529,6 +21646,11 @@ var BifrostCatalogClient = class {
21529
21646
  this.secretValues.push(apiKey);
21530
21647
  }
21531
21648
  }
21649
+ registerAccessToken(token) {
21650
+ if (token && !this.secretValues.includes(token)) {
21651
+ this.secretValues.push(token);
21652
+ }
21653
+ }
21532
21654
  /**
21533
21655
  * Build Bifrost proxy headers.
21534
21656
  * x-entity-team-id is ONLY included when teamId is present (org-mode tokens).
@@ -21536,7 +21658,7 @@ var BifrostCatalogClient = class {
21536
21658
  */
21537
21659
  headers() {
21538
21660
  const h = {
21539
- "x-access-token": this.accessToken,
21661
+ "x-access-token": this.tokenProvider.current(),
21540
21662
  "Content-Type": "application/json"
21541
21663
  };
21542
21664
  if (this.teamId) {
@@ -21552,7 +21674,7 @@ var BifrostCatalogClient = class {
21552
21674
  const session = getMemoizedSessionIdentity();
21553
21675
  return {
21554
21676
  operation,
21555
- hasAccessToken: Boolean(this.accessToken),
21677
+ hasAccessToken: Boolean(this.tokenProvider.current()),
21556
21678
  sessionTeamId: session?.teamId,
21557
21679
  sessionRoles: session?.roles,
21558
21680
  sessionConsumerType: session?.consumerType,
@@ -21561,7 +21683,7 @@ var BifrostCatalogClient = class {
21561
21683
  };
21562
21684
  }
21563
21685
  async proxyRequest(method, path7, body = {}, operation = "api-catalog request") {
21564
- const response = await this.fetchFn(this.bifrostProxyUrl, {
21686
+ const send2 = async () => this.fetchFn(this.bifrostProxyUrl, {
21565
21687
  method: "POST",
21566
21688
  headers: this.headers(),
21567
21689
  body: JSON.stringify({
@@ -21571,6 +21693,39 @@ var BifrostCatalogClient = class {
21571
21693
  body
21572
21694
  })
21573
21695
  });
21696
+ let response = await send2();
21697
+ if (!response.ok) {
21698
+ const bodyText = await response.text().catch(() => "");
21699
+ if (isExpiredAuthError(response.status, bodyText) && this.tokenProvider.canRefresh()) {
21700
+ try {
21701
+ const refreshed = await this.tokenProvider.refresh();
21702
+ this.registerAccessToken(refreshed);
21703
+ response = await send2();
21704
+ } catch {
21705
+ const httpErr = await HttpError.fromResponse(
21706
+ new Response(bodyText, { status: response.status, headers: response.headers }),
21707
+ {
21708
+ method: "POST",
21709
+ url: `bifrost:api-catalog:${method} ${path7}`,
21710
+ secretValues: this.secretValues
21711
+ }
21712
+ );
21713
+ const advised = adviseFromHttpError(httpErr, this.adviceContext(operation));
21714
+ throw advised ?? httpErr;
21715
+ }
21716
+ } else {
21717
+ const httpErr = await HttpError.fromResponse(
21718
+ new Response(bodyText, { status: response.status, headers: response.headers }),
21719
+ {
21720
+ method: "POST",
21721
+ url: `bifrost:api-catalog:${method} ${path7}`,
21722
+ secretValues: this.secretValues
21723
+ }
21724
+ );
21725
+ const advised = adviseFromHttpError(httpErr, this.adviceContext(operation));
21726
+ throw advised ?? httpErr;
21727
+ }
21728
+ }
21574
21729
  if (!response.ok) {
21575
21730
  const httpErr = await HttpError.fromResponse(response, {
21576
21731
  method: "POST",
@@ -21593,7 +21748,7 @@ var BifrostCatalogClient = class {
21593
21748
  return data;
21594
21749
  }
21595
21750
  async akitaProxyRequest(method, path7, body = {}, operation = "Insights request") {
21596
- const response = await this.fetchFn(this.bifrostProxyUrl, {
21751
+ const send2 = async () => this.fetchFn(this.bifrostProxyUrl, {
21597
21752
  method: "POST",
21598
21753
  headers: this.headers(),
21599
21754
  body: JSON.stringify({
@@ -21603,8 +21758,30 @@ var BifrostCatalogClient = class {
21603
21758
  body
21604
21759
  })
21605
21760
  });
21761
+ let response = await send2();
21606
21762
  if (!response.ok) {
21607
21763
  const text = await response.text().catch(() => "");
21764
+ if (isExpiredAuthError(response.status, text) && this.tokenProvider.canRefresh()) {
21765
+ try {
21766
+ const refreshed = await this.tokenProvider.refresh();
21767
+ this.registerAccessToken(refreshed);
21768
+ response = await send2();
21769
+ if (response.ok) {
21770
+ const data2 = await response.json();
21771
+ return { ok: true, status: response.status, data: data2, errorText: "" };
21772
+ }
21773
+ const retryText = await response.text().catch(() => "");
21774
+ const advised2 = adviseFromBifrostBody(response.status, retryText, this.adviceContext(operation));
21775
+ const errorText2 = advised2 ? retryText ? `${retryText}
21776
+ ${advised2.message}` : advised2.message : retryText;
21777
+ return { ok: false, status: response.status, data: null, errorText: errorText2 };
21778
+ } catch {
21779
+ const advised2 = adviseFromBifrostBody(response.status, text, this.adviceContext(operation));
21780
+ const errorText2 = advised2 ? text ? `${text}
21781
+ ${advised2.message}` : advised2.message : text;
21782
+ return { ok: false, status: response.status, data: null, errorText: errorText2 };
21783
+ }
21784
+ }
21608
21785
  const advised = adviseFromBifrostBody(response.status, text, this.adviceContext(operation));
21609
21786
  const errorText = advised ? text ? `${text}
21610
21787
  ${advised.message}` : advised.message : text;
@@ -21703,12 +21880,19 @@ ${advised.message}` : advised.message : text;
21703
21880
  }
21704
21881
  page++;
21705
21882
  }
21706
- const fullName = clusterName ? `${clusterName}/${projectName}` : projectName;
21707
- const exactMatch = allServices.find((s) => s.name === fullName);
21708
- if (exactMatch) return exactMatch.id;
21709
- if (clusterName) return null;
21710
- const suffixMatch = allServices.find((s) => s.name.endsWith(`/${projectName}`));
21711
- return suffixMatch?.id || null;
21883
+ if (clusterName) {
21884
+ const fullName = `${clusterName}/${projectName}`;
21885
+ const exactMatch = allServices.find((s) => s.name === fullName);
21886
+ return exactMatch?.id || null;
21887
+ }
21888
+ const finalSegmentMatch = allServices.find(
21889
+ (s) => getFinalServiceSegment(s.name) === projectName
21890
+ );
21891
+ if (finalSegmentMatch) return finalSegmentMatch.id;
21892
+ const bracketedMatch = allServices.find(
21893
+ (s) => getFinalServiceSegment(s.name).includes(`[${projectName}]`)
21894
+ );
21895
+ return bracketedMatch?.id || null;
21712
21896
  }
21713
21897
  async acknowledgeOnboarding(providerServiceId, workspaceId, systemEnvironmentId) {
21714
21898
  const result = await this.akitaProxyRequest(
@@ -21738,6 +21922,14 @@ ${advised.message}` : advised.message : text;
21738
21922
  throw new Error(`Workspace acknowledge failed: ${result.status} ${result.errorText}`);
21739
21923
  }
21740
21924
  }
21925
+ // PMAK-only by proven exception. A live probe against the observability
21926
+ // application-binding endpoint (POST /v2/agent/api-catalog/workspaces/:id/
21927
+ // applications) showed x-access-token is rejected identically to the x-api-key
21928
+ // control: both return 401 {"message":"Postman User not found"} for a
21929
+ // service-account credential, because the observability service has no
21930
+ // "Postman User" for a service account. The access token offers no improvement
21931
+ // over the API key here, so this route is not migrated to access-token-primary
21932
+ // (the suite-wide migration explicitly leaves probe-failed routes on PMAK).
21741
21933
  async createApplication(workspaceId, systemEnv) {
21742
21934
  const response = await this.fetchFn(
21743
21935
  `${this.observabilityBaseUrl}/v2/agent/api-catalog/workspaces/${workspaceId}/applications`,
@@ -21805,7 +21997,17 @@ function findDiscoveredService(services, projectName, clusterName) {
21805
21997
  const fullName = `${clusterName}/${projectName}`;
21806
21998
  return services.find((s) => s.name === fullName);
21807
21999
  }
21808
- return services.find((s) => s.name.endsWith(`/${projectName}`));
22000
+ const finalSegmentMatch = services.find(
22001
+ (service) => getFinalServiceSegment(service.name) === projectName
22002
+ );
22003
+ if (finalSegmentMatch) return finalSegmentMatch;
22004
+ return services.find(
22005
+ (service) => getFinalServiceSegment(service.name).includes(`[${projectName}]`)
22006
+ );
22007
+ }
22008
+ function getFinalServiceSegment(serviceName) {
22009
+ const lastSlash = serviceName.lastIndexOf("/");
22010
+ return lastSlash === -1 ? serviceName : serviceName.slice(lastSlash + 1);
21809
22011
  }
21810
22012
 
21811
22013
  // node_modules/@postman-cse/automation-telemetry-core/dist/ci-context.js
@@ -21813,7 +22015,65 @@ function norm(value) {
21813
22015
  const trimmed = (value ?? "").trim();
21814
22016
  return trimmed.length > 0 ? trimmed : void 0;
21815
22017
  }
22018
+ function detectEventTrigger(env = process.env) {
22019
+ const ghEvent = norm(env.GITHUB_EVENT_NAME)?.toLowerCase();
22020
+ if (ghEvent) {
22021
+ if (ghEvent === "push")
22022
+ return "push";
22023
+ if (ghEvent === "pull_request" || ghEvent === "pull_request_target")
22024
+ return "pull_request";
22025
+ if (ghEvent === "schedule")
22026
+ return "schedule";
22027
+ if (ghEvent === "workflow_dispatch" || ghEvent === "repository_dispatch")
22028
+ return "manual";
22029
+ return "other";
22030
+ }
22031
+ const glSource = norm(env.CI_PIPELINE_SOURCE)?.toLowerCase();
22032
+ if (glSource) {
22033
+ if (glSource === "push")
22034
+ return "push";
22035
+ if (glSource === "merge_request_event")
22036
+ return "pull_request";
22037
+ if (glSource === "schedule")
22038
+ return "schedule";
22039
+ if (glSource === "web" || glSource === "api" || glSource === "trigger" || glSource === "pipeline") {
22040
+ return "manual";
22041
+ }
22042
+ return "other";
22043
+ }
22044
+ if (norm(env.BITBUCKET_PR_ID))
22045
+ return "pull_request";
22046
+ if (norm(env.CI) || norm(env.BUILD_BUILDID) || norm(env.JENKINS_URL) || norm(env.TEAMCITY_VERSION)) {
22047
+ return "other";
22048
+ }
22049
+ return "unknown";
22050
+ }
22051
+ function detectRunnerOs(env = process.env) {
22052
+ const runnerOs = norm(env.RUNNER_OS)?.toLowerCase();
22053
+ if (runnerOs === "linux")
22054
+ return "linux";
22055
+ if (runnerOs === "macos")
22056
+ return "macos";
22057
+ if (runnerOs === "windows")
22058
+ return "windows";
22059
+ const platform2 = typeof process !== "undefined" ? process.platform : void 0;
22060
+ if (platform2 === "linux")
22061
+ return "linux";
22062
+ if (platform2 === "darwin")
22063
+ return "macos";
22064
+ if (platform2 === "win32")
22065
+ return "windows";
22066
+ return "unknown";
22067
+ }
21816
22068
  function detectCiContext(env = process.env) {
22069
+ const provider = detectCiProviderContext(env);
22070
+ return {
22071
+ ...provider,
22072
+ eventTrigger: detectEventTrigger(env),
22073
+ runnerOs: detectRunnerOs(env)
22074
+ };
22075
+ }
22076
+ function detectCiProviderContext(env = process.env) {
21817
22077
  if (norm(env.GITHUB_ACTIONS)) {
21818
22078
  const runnerEnv = norm(env.RUNNER_ENVIRONMENT);
21819
22079
  const runnerKind = runnerEnv === "github-hosted" ? "hosted" : runnerEnv === "self-hosted" ? "self-hosted" : "unknown";
@@ -21951,25 +22211,49 @@ function parseProvider(explicitProvider, repoUrl, env) {
21951
22211
  }
21952
22212
  return "unknown";
21953
22213
  }
22214
+ function classifyRefKind(env = process.env) {
22215
+ const githubRefType = normalize(env.GITHUB_REF_TYPE)?.toLowerCase();
22216
+ const githubRef = normalize(env.GITHUB_REF);
22217
+ const azureRef = normalize(env.BUILD_SOURCEBRANCH);
22218
+ if (githubRefType === "tag" || githubRef?.startsWith("refs/tags/") || normalize(env.CI_COMMIT_TAG) || normalize(env.BITBUCKET_TAG) || azureRef?.startsWith("refs/tags/")) {
22219
+ return "tag";
22220
+ }
22221
+ const githubRefName = normalize(env.GITHUB_REF_NAME);
22222
+ const githubDefault = normalize(env.GITHUB_DEFAULT_BRANCH);
22223
+ if (githubRefName && githubDefault) {
22224
+ return githubRefName === githubDefault ? "default-branch" : "branch";
22225
+ }
22226
+ const gitlabRef = normalize(env.CI_COMMIT_REF_NAME);
22227
+ const gitlabDefault = normalize(env.CI_DEFAULT_BRANCH);
22228
+ if (gitlabRef && gitlabDefault) {
22229
+ return gitlabRef === gitlabDefault ? "default-branch" : "branch";
22230
+ }
22231
+ if (githubRefName || githubRef?.startsWith("refs/heads/") || gitlabRef || normalize(env.BITBUCKET_BRANCH) || normalize(env.BUILD_SOURCEBRANCHNAME) || azureRef?.startsWith("refs/heads/")) {
22232
+ return "branch";
22233
+ }
22234
+ return "unknown";
22235
+ }
21954
22236
  function detectRepoContext(input, env = process.env) {
21955
22237
  const repoUrl = normalizeRepoUrl(input.repoUrl) ?? normalizeRepoUrl(env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY ? `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}` : void 0) ?? normalizeRepoUrl(env.CI_PROJECT_URL) ?? normalizeRepoUrl(env.BITBUCKET_GIT_HTTP_ORIGIN) ?? normalizeRepoUrl(env.BUILD_REPOSITORY_URI);
21956
22238
  const repoSlug = normalize(input.repoSlug) ?? normalize(env.GITHUB_REPOSITORY) ?? normalize(env.CI_PROJECT_PATH) ?? (env.BITBUCKET_WORKSPACE && env.BITBUCKET_REPO_SLUG ? normalize(`${env.BITBUCKET_WORKSPACE}/${env.BITBUCKET_REPO_SLUG}`) : void 0) ?? normalize(env.BUILD_REPOSITORY_NAME);
21957
22239
  const ref = normalize(input.ref) ?? normalize(env.GITHUB_REF_NAME) ?? normalize(env.CI_COMMIT_REF_NAME) ?? normalize(env.BITBUCKET_BRANCH) ?? normalize(env.BUILD_SOURCEBRANCHNAME);
21958
22240
  const sha = normalize(input.sha) ?? normalize(env.GITHUB_SHA) ?? normalize(env.CI_COMMIT_SHA) ?? normalize(env.BITBUCKET_COMMIT) ?? normalize(env.BUILD_SOURCEVERSION);
21959
22241
  const provider = parseProvider(input.gitProvider, repoUrl, env);
22242
+ const refKind = classifyRefKind(env);
21960
22243
  return {
21961
22244
  provider,
21962
22245
  repoUrl,
21963
22246
  repoSlug,
21964
22247
  ref,
21965
- sha
22248
+ sha,
22249
+ refKind
21966
22250
  };
21967
22251
  }
21968
22252
 
21969
22253
  // node_modules/@postman-cse/automation-telemetry-core/dist/telemetry.js
21970
22254
  var import_node_crypto = require("node:crypto");
21971
22255
  var import_undici2 = __toESM(require_undici(), 1);
21972
- var SCHEMA_VERSION = 2;
22256
+ var SCHEMA_VERSION = 3;
21973
22257
  var DEFAULT_TIMEOUT_MS = 1500;
21974
22258
  var DEFAULT_ENDPOINT = "https://events.pm-cse.dev/v1/events";
21975
22259
  var proxyDispatcher;
@@ -21980,7 +22264,7 @@ function resolveActionVersion(explicit) {
21980
22264
  if (explicit) {
21981
22265
  return explicit;
21982
22266
  }
21983
- return "1.0.3" ? "1.0.3" : "unknown";
22267
+ return "2.0.0" ? "2.0.0" : "unknown";
21984
22268
  }
21985
22269
  function telemetryDisabled(env) {
21986
22270
  const flag = String(env.POSTMAN_ACTIONS_TELEMETRY ?? "").trim().toLowerCase();
@@ -22009,7 +22293,7 @@ function maybeNotice(logger) {
22009
22293
  return;
22010
22294
  }
22011
22295
  noticeShown = true;
22012
- logger.info("note: postman-actions sends anonymous usage data (team id, action, CI provider, account type). Disable with POSTMAN_ACTIONS_TELEMETRY=off or DO_NOT_TRACK=1.");
22296
+ logger.info("note: postman-actions sends anonymous usage data (team id, action, CI provider, account type, run trigger, runner OS). Disable with POSTMAN_ACTIONS_TELEMETRY=off or DO_NOT_TRACK=1.");
22013
22297
  }
22014
22298
  function buildTelemetryEvent(params) {
22015
22299
  const { action, actionVersion, teamId, accountType, outcome, env, now } = params;
@@ -22031,6 +22315,9 @@ function buildTelemetryEvent(params) {
22031
22315
  repo_id: repoSource ? sha256(repoSource) : void 0,
22032
22316
  org_id: owner ? sha256(owner) : void 0,
22033
22317
  account_type: accountType,
22318
+ event_trigger: ci.eventTrigger,
22319
+ runner_os: ci.runnerOs,
22320
+ ref_kind: repo.refKind,
22034
22321
  outcome,
22035
22322
  ts: now()
22036
22323
  };
@@ -22356,19 +22643,39 @@ async function resolveApiKeyAndTeamId(inputs, client, reporter = core_exports) {
22356
22643
  }
22357
22644
  return { apiKey, teamId: resolvedTeamId, pmakIdentity };
22358
22645
  }
22359
- async function runCredentialPreflightForInputs(inputs, pmak, reporter, fetchImpl) {
22646
+ async function runCredentialPreflightForInputs(inputs, pmak, reporter, fetchImpl, liveAccessToken) {
22647
+ const accessToken = liveAccessToken ?? inputs.postmanAccessToken;
22360
22648
  await runCredentialPreflight({
22361
22649
  apiBaseUrl: inputs.postmanApiBase || DEFAULT_POSTMAN_API_BASE,
22362
22650
  iapubBaseUrl: inputs.postmanIapubBase || DEFAULT_POSTMAN_IAPUB_BASE,
22363
22651
  pmak,
22364
- postmanAccessToken: inputs.postmanAccessToken,
22652
+ postmanAccessToken: accessToken,
22365
22653
  explicitTeamId: inputs.postmanTeamId || void 0,
22366
22654
  mode: inputs.credentialPreflight,
22367
- mask: createSecretMasker([inputs.postmanApiKey, inputs.postmanAccessToken]),
22655
+ mask: createSecretMasker([inputs.postmanApiKey, accessToken]),
22368
22656
  log: reporter,
22369
22657
  fetchImpl
22370
22658
  });
22371
22659
  }
22660
+ function createInsightsTokenProvider(inputs, reporter, apiKey = inputs.postmanApiKey) {
22661
+ return new AccessTokenProvider({
22662
+ accessToken: inputs.postmanAccessToken,
22663
+ apiKey,
22664
+ apiBaseUrl: inputs.postmanApiBase || DEFAULT_POSTMAN_API_BASE,
22665
+ onToken: (token) => reporter.setSecret(token)
22666
+ });
22667
+ }
22668
+ function createInsightsBifrostClient(inputs, tokenProvider, teamId, apiKey) {
22669
+ return new BifrostCatalogClient({
22670
+ tokenProvider,
22671
+ accessToken: tokenProvider.current(),
22672
+ teamId,
22673
+ apiKey,
22674
+ bifrostBaseUrl: inputs.postmanBifrostBase,
22675
+ observabilityBaseUrl: inputs.postmanObservabilityBase,
22676
+ observabilityEnv: inputs.postmanObservabilityEnv
22677
+ });
22678
+ }
22372
22679
 
22373
22680
  // src/cli.ts
22374
22681
  var ConsoleReporter = class {
@@ -22480,19 +22787,24 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
22480
22787
  if (inputs.githubToken) {
22481
22788
  reporter.setSecret(inputs.githubToken);
22482
22789
  }
22483
- const preliminaryClient = new BifrostCatalogClient({
22484
- accessToken: inputs.postmanAccessToken,
22485
- teamId: inputs.postmanTeamId,
22486
- apiKey: inputs.postmanApiKey,
22487
- bifrostBaseUrl: inputs.postmanBifrostBase,
22488
- observabilityBaseUrl: inputs.postmanObservabilityBase,
22489
- observabilityEnv: inputs.postmanObservabilityEnv
22490
- });
22790
+ const tokenProvider = createInsightsTokenProvider(inputs, reporter);
22791
+ const preliminaryClient = createInsightsBifrostClient(
22792
+ inputs,
22793
+ tokenProvider,
22794
+ inputs.postmanTeamId,
22795
+ inputs.postmanApiKey
22796
+ );
22491
22797
  const { apiKey, teamId, pmakIdentity } = await resolveApiKeyAndTeamId(
22492
22798
  inputs,
22493
22799
  preliminaryClient,
22494
22800
  reporter
22495
22801
  );
22802
+ const activeTokenProvider = apiKey !== inputs.postmanApiKey ? new AccessTokenProvider({
22803
+ accessToken: tokenProvider.current(),
22804
+ apiKey,
22805
+ apiBaseUrl: inputs.postmanApiBase || DEFAULT_POSTMAN_API_BASE,
22806
+ onToken: (token) => reporter.setSecret(token)
22807
+ }) : tokenProvider;
22496
22808
  const telemetry = createTelemetryContext({ action: "postman-insights-onboarding-action", logger: reporter });
22497
22809
  telemetry.setTeamId(inputs.postmanTeamId || pmakIdentity?.teamId);
22498
22810
  if (apiKey) {
@@ -22500,15 +22812,14 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
22500
22812
  }
22501
22813
  let result;
22502
22814
  try {
22503
- await runCredentialPreflightForInputs(inputs, pmakIdentity, reporter);
22504
- const client = new BifrostCatalogClient({
22505
- accessToken: inputs.postmanAccessToken,
22506
- teamId,
22507
- apiKey,
22508
- bifrostBaseUrl: inputs.postmanBifrostBase,
22509
- observabilityBaseUrl: inputs.postmanObservabilityBase,
22510
- observabilityEnv: inputs.postmanObservabilityEnv
22511
- });
22815
+ await runCredentialPreflightForInputs(
22816
+ inputs,
22817
+ pmakIdentity,
22818
+ reporter,
22819
+ void 0,
22820
+ activeTokenProvider.current()
22821
+ );
22822
+ const client = createInsightsBifrostClient(inputs, activeTokenProvider, teamId, apiKey);
22512
22823
  result = await (runtime.executeOnboarding ?? runOnboarding)(
22513
22824
  inputs,
22514
22825
  client,