@patchstack/connect 0.3.23 → 0.3.24

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.js CHANGED
@@ -907,6 +907,88 @@ function compareSegments(a, b) {
907
907
  return 0;
908
908
  }
909
909
 
910
+ // src/pulse-token.ts
911
+ var TOKEN_SKEW_MS = 6e4;
912
+ function buildTokenUrl(manifestEndpoint) {
913
+ const url = new URL(manifestEndpoint);
914
+ const path8 = url.pathname.replace(/\/$/, "");
915
+ url.pathname = path8.endsWith("/manifest") ? `${path8.slice(0, -"/manifest".length)}/token` : "/monitor/pulse/token";
916
+ url.search = "";
917
+ url.hash = "";
918
+ return url.toString();
919
+ }
920
+ function parsePulseAuth(credential) {
921
+ const index = credential.lastIndexOf("-");
922
+ if (index <= 0 || index === credential.length - 1) return null;
923
+ const clientId = credential.slice(index + 1);
924
+ if (!/^\d+$/.test(clientId)) return null;
925
+ return { clientId, clientSecret: credential.slice(0, index) };
926
+ }
927
+ var cached = null;
928
+ var inflight = null;
929
+ function clearPulseToken() {
930
+ cached = null;
931
+ }
932
+ async function getPulseToken(config, fetchImpl = fetch) {
933
+ if (typeof config.pulseAuth !== "string" || config.pulseAuth.length === 0) return null;
934
+ if (cached !== null && Date.now() < cached.expiresAt - TOKEN_SKEW_MS) {
935
+ return cached.token;
936
+ }
937
+ if (inflight !== null) return inflight;
938
+ const credentials = parsePulseAuth(config.pulseAuth);
939
+ if (credentials === null) return null;
940
+ inflight = (async () => {
941
+ try {
942
+ const response = await fetchImpl(buildTokenUrl(config.endpoint), {
943
+ method: "POST",
944
+ headers: {
945
+ "Content-Type": "application/json",
946
+ Accept: "application/json",
947
+ "User-Agent": "@patchstack/connect"
948
+ },
949
+ body: JSON.stringify({
950
+ grant_type: "client_credentials",
951
+ client_id: credentials.clientId,
952
+ client_secret: credentials.clientSecret
953
+ }),
954
+ signal: AbortSignal.timeout(config.timeoutMs)
955
+ });
956
+ if (!response.ok) return null;
957
+ const body = await response.json();
958
+ if (typeof body.access_token !== "string" || body.access_token.length === 0) return null;
959
+ const expiresIn = Number(body.expires_in);
960
+ const ttlMs = Number.isFinite(expiresIn) && expiresIn > 0 ? expiresIn * 1e3 : 36e5;
961
+ cached = { token: body.access_token, expiresAt: Date.now() + ttlMs };
962
+ return body.access_token;
963
+ } catch {
964
+ return null;
965
+ } finally {
966
+ inflight = null;
967
+ }
968
+ })();
969
+ return inflight;
970
+ }
971
+ async function pulseAuthHeader(config, fetchImpl = fetch) {
972
+ const token = await getPulseToken(config, fetchImpl);
973
+ return token === null ? {} : { Authorization: `Bearer ${token}` };
974
+ }
975
+ async function pulseFetch(config, url, init, fetchImpl = fetch) {
976
+ const send = async () => {
977
+ const auth = await pulseAuthHeader(config, fetchImpl);
978
+ const response = await fetchImpl(url, {
979
+ ...init,
980
+ headers: { ...init.headers, ...auth }
981
+ });
982
+ return { response, authenticated: auth.Authorization !== void 0 };
983
+ };
984
+ const first = await send();
985
+ if (first.response.status === 401 && first.authenticated) {
986
+ clearPulseToken();
987
+ return (await send()).response;
988
+ }
989
+ return first.response;
990
+ }
991
+
910
992
  // src/client.ts
911
993
  var DEFAULT_ENDPOINT = "https://api.patchstack.com/monitor/pulse/manifest";
912
994
  var DEFAULT_TIMEOUT_MS = 3e4;
@@ -923,7 +1005,7 @@ async function postManifest(config, payload) {
923
1005
  const timeoutMs = config.timeoutMs;
924
1006
  let response;
925
1007
  try {
926
- response = await fetch(url, {
1008
+ response = await pulseFetch(config, url, {
927
1009
  method: "POST",
928
1010
  headers: {
929
1011
  "Content-Type": "application/json",
@@ -1016,9 +1098,11 @@ async function resolveConfig(options) {
1016
1098
  );
1017
1099
  }
1018
1100
  const apiKeyRaw = fromEnv.apiKey ?? fromFile.apiKey ?? null;
1101
+ const pulseAuthRaw = fromEnv.pulseAuth ?? fromFile.pulseAuth ?? apiKeyRaw;
1019
1102
  return {
1020
1103
  siteUuid: siteUuid === null || siteUuid.length === 0 ? null : siteUuid,
1021
1104
  apiKey: apiKeyRaw === null || apiKeyRaw.length === 0 ? null : apiKeyRaw,
1105
+ pulseAuth: pulseAuthRaw === null || pulseAuthRaw.length === 0 ? null : pulseAuthRaw,
1022
1106
  endpoint,
1023
1107
  timeoutMs,
1024
1108
  environment,
@@ -1039,6 +1123,10 @@ async function persistApiKey(cwd, apiKey) {
1039
1123
  const existing = await readConfigFile(cwd);
1040
1124
  return writeConfigFile(cwd, { ...existing, apiKey });
1041
1125
  }
1126
+ async function persistPulseAuth(cwd, pulseAuth) {
1127
+ const existing = await readConfigFile(cwd);
1128
+ return writeConfigFile(cwd, { ...existing, pulseAuth });
1129
+ }
1042
1130
  async function readConfigFile(cwd) {
1043
1131
  const target = path6.join(cwd, CONFIG_FILENAME);
1044
1132
  let raw;
@@ -1081,6 +1169,7 @@ function readEnv() {
1081
1169
  return {
1082
1170
  siteUuid: process.env.PATCHSTACK_SITE_UUID ?? void 0,
1083
1171
  apiKey: process.env.PATCHSTACK_API_KEY ?? void 0,
1172
+ pulseAuth: process.env.PATCHSTACK_PULSE_AUTH ?? void 0,
1084
1173
  endpoint: process.env.PATCHSTACK_ENDPOINT ?? void 0,
1085
1174
  timeoutMs,
1086
1175
  environment: environmentRaw !== void 0 && environmentRaw.length > 0 ? environmentRaw : void 0
@@ -1251,6 +1340,7 @@ async function scanAndReport(options = {}) {
1251
1340
  }
1252
1341
  if (typeof response.api_key === "string" && response.api_key.length > 0) {
1253
1342
  await persistApiKey(cwd, response.api_key);
1343
+ await persistPulseAuth(cwd, response.api_key);
1254
1344
  }
1255
1345
  return {
1256
1346
  manifest,
@@ -1278,6 +1368,7 @@ export {
1278
1368
  findSourceShell,
1279
1369
  isEmptyStack,
1280
1370
  persistApiKey,
1371
+ persistPulseAuth,
1281
1372
  persistSiteUuid,
1282
1373
  postManifest,
1283
1374
  resolveConfig,