@winwinmbs/portal-api 1.0.0 → 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/README.md +367 -12
- package/dist/_tsup-dts-rollup.d.mts +73 -1
- package/dist/_tsup-dts-rollup.d.ts +73 -1
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +76 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +75 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +18 -9
package/dist/index.mjs
CHANGED
|
@@ -1953,8 +1953,8 @@ var PortalApiClient = class {
|
|
|
1953
1953
|
timeout: config.timeout ?? 3e4,
|
|
1954
1954
|
withCredentials: true
|
|
1955
1955
|
});
|
|
1956
|
-
this.axios.interceptors.request.use((cfg) => {
|
|
1957
|
-
const token = config.getToken();
|
|
1956
|
+
this.axios.interceptors.request.use(async (cfg) => {
|
|
1957
|
+
const token = config.getToken ? await config.getToken() : null;
|
|
1958
1958
|
if (token) cfg.headers.Authorization = `Bearer ${token}`;
|
|
1959
1959
|
if (config.apiKey) cfg.headers["X-API-Key"] = config.apiKey;
|
|
1960
1960
|
return cfg;
|
|
@@ -1992,6 +1992,78 @@ var PortalApiClient = class {
|
|
|
1992
1992
|
}
|
|
1993
1993
|
};
|
|
1994
1994
|
|
|
1995
|
+
// src/client-credentials.ts
|
|
1996
|
+
var ClientCredentialsTokenProvider = class {
|
|
1997
|
+
constructor(config) {
|
|
1998
|
+
this.config = config;
|
|
1999
|
+
this.token = null;
|
|
2000
|
+
this.expiresAtMs = 0;
|
|
2001
|
+
this.inflight = null;
|
|
2002
|
+
if (!config.clientId || !config.clientSecret) {
|
|
2003
|
+
throw new Error("ClientCredentialsTokenProvider requires clientId and clientSecret");
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
/**
|
|
2007
|
+
* Returns a valid access token, fetching or refreshing as needed. Safe to call
|
|
2008
|
+
* on every request — cached until shortly before expiry. Concurrent calls
|
|
2009
|
+
* share a single in-flight request.
|
|
2010
|
+
*/
|
|
2011
|
+
async getAccessToken() {
|
|
2012
|
+
const skewMs = (this.config.refreshSkewSeconds ?? 60) * 1e3;
|
|
2013
|
+
if (this.token && Date.now() < this.expiresAtMs - skewMs) {
|
|
2014
|
+
return this.token;
|
|
2015
|
+
}
|
|
2016
|
+
if (!this.inflight) {
|
|
2017
|
+
this.inflight = this.fetchToken().finally(() => {
|
|
2018
|
+
this.inflight = null;
|
|
2019
|
+
});
|
|
2020
|
+
}
|
|
2021
|
+
return this.inflight;
|
|
2022
|
+
}
|
|
2023
|
+
/** Last cached token without triggering a fetch (may be stale or null). */
|
|
2024
|
+
getCachedToken() {
|
|
2025
|
+
return this.token;
|
|
2026
|
+
}
|
|
2027
|
+
/** Forget the cached token so the next `getAccessToken()` fetches a fresh one. */
|
|
2028
|
+
reset() {
|
|
2029
|
+
this.token = null;
|
|
2030
|
+
this.expiresAtMs = 0;
|
|
2031
|
+
}
|
|
2032
|
+
async fetchToken() {
|
|
2033
|
+
const fetchFn = this.config.fetchFn ?? globalThis.fetch;
|
|
2034
|
+
if (typeof fetchFn !== "function") {
|
|
2035
|
+
throw new Error("No fetch implementation available \u2014 pass config.fetchFn");
|
|
2036
|
+
}
|
|
2037
|
+
const endpoint = this.config.tokenEndpoint ?? `${this.config.apiUrl.replace(/\/$/, "")}/oauth/token`;
|
|
2038
|
+
const body = {
|
|
2039
|
+
grant_type: "client_credentials",
|
|
2040
|
+
client_id: this.config.clientId,
|
|
2041
|
+
client_secret: this.config.clientSecret
|
|
2042
|
+
};
|
|
2043
|
+
if (this.config.scope) body.scope = this.config.scope;
|
|
2044
|
+
const res = await fetchFn(endpoint, {
|
|
2045
|
+
method: "POST",
|
|
2046
|
+
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
2047
|
+
body: JSON.stringify(body)
|
|
2048
|
+
});
|
|
2049
|
+
if (!res.ok) {
|
|
2050
|
+
let detail = "";
|
|
2051
|
+
try {
|
|
2052
|
+
detail = JSON.stringify(await res.json());
|
|
2053
|
+
} catch {
|
|
2054
|
+
}
|
|
2055
|
+
throw new Error(`client_credentials token request failed (HTTP ${res.status}) ${detail}`.trim());
|
|
2056
|
+
}
|
|
2057
|
+
const data = await res.json();
|
|
2058
|
+
if (!data.access_token) {
|
|
2059
|
+
throw new Error("client_credentials response did not include an access_token");
|
|
2060
|
+
}
|
|
2061
|
+
this.token = data.access_token;
|
|
2062
|
+
this.expiresAtMs = Date.now() + (data.expires_in ?? 3600) * 1e3;
|
|
2063
|
+
return this.token;
|
|
2064
|
+
}
|
|
2065
|
+
};
|
|
2066
|
+
|
|
1995
2067
|
// ../../shared/src/enums/common.enums.ts
|
|
1996
2068
|
var OrganizationType = /* @__PURE__ */ ((OrganizationType2) => {
|
|
1997
2069
|
OrganizationType2["GROUP"] = "group";
|
|
@@ -2059,6 +2131,7 @@ var TodoPriority = /* @__PURE__ */ ((TodoPriority2) => {
|
|
|
2059
2131
|
})(TodoPriority || {});
|
|
2060
2132
|
export {
|
|
2061
2133
|
ActorType,
|
|
2134
|
+
ClientCredentialsTokenProvider,
|
|
2062
2135
|
EmailAPI,
|
|
2063
2136
|
EventCategory,
|
|
2064
2137
|
EventLogApi,
|