@ibertran/fortytwo-intra-client 5.0.0 → 5.1.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 +21 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.js +36 -8
- package/dist/intraV3/index.d.ts +4 -0
- package/dist/intraV3/index.js +23 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -140,6 +140,27 @@ const allProjects = await client.getAll("projects", {
|
|
|
140
140
|
});
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
+
### Raw Requests
|
|
144
|
+
|
|
145
|
+
The `rawRequest` method takes a plain [axios request config](https://axios-http.com/docs/req_config), injects the access token, and returns the raw `AxiosResponse`. Relative URLs are resolved against the client's `base_url` unless `baseURL` is set in the config.
|
|
146
|
+
|
|
147
|
+
Unlike the other methods, it does not retry, log, validate, or wrap errors: failures are thrown as `AxiosError`.
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// Full axios config, raw response
|
|
151
|
+
const res = await client.rawRequest({
|
|
152
|
+
method: "get",
|
|
153
|
+
url: "campus/9/users",
|
|
154
|
+
params: { "page[size]": 100 },
|
|
155
|
+
});
|
|
156
|
+
console.log(res.status, res.headers["x-total"], res.data);
|
|
157
|
+
|
|
158
|
+
// With a user token (V2 client only)
|
|
159
|
+
const me = await client.rawRequest({ url: "me" }, tokens);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`rawRequest` is available on both `FortytwoIntraClient` and `FortytwoIntraV3Client`. On the V2 client, requests still go through the rate limiter.
|
|
163
|
+
|
|
143
164
|
## OAuth Authentication
|
|
144
165
|
|
|
145
166
|
### Authorization Flow
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { AxiosRequestConfig, AxiosResponse } from "axios";
|
|
1
2
|
import z from "zod";
|
|
2
|
-
import { inputOptions } from "./types";
|
|
3
|
+
import { inputOptions, userToken } from "./types";
|
|
3
4
|
export { FortytwoIntraV3Client } from "./intraV3";
|
|
4
5
|
export * from "./errors/httpError";
|
|
5
6
|
export * from "./errors/validationError";
|
|
@@ -32,9 +33,12 @@ export declare class FortytwoIntraClient {
|
|
|
32
33
|
private maxRetry;
|
|
33
34
|
private logLine;
|
|
34
35
|
private errLogBody;
|
|
35
|
-
private
|
|
36
|
+
private authorization;
|
|
37
|
+
private tokenRequest;
|
|
36
38
|
constructor(client_id: string, client_secret: string, conf: Partial<FortytwoIntraClientConf>);
|
|
37
39
|
private generateToken;
|
|
40
|
+
private isTokenValid;
|
|
41
|
+
private getAccessToken;
|
|
38
42
|
private fetch;
|
|
39
43
|
private reqHandler;
|
|
40
44
|
private logSuccess;
|
|
@@ -64,6 +68,7 @@ export declare class FortytwoIntraClient {
|
|
|
64
68
|
getAll<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "body"> & {
|
|
65
69
|
schema: S;
|
|
66
70
|
}): Promise<z.infer<S>>;
|
|
71
|
+
rawRequest<T = any, D = any>(config: AxiosRequestConfig<D>, token?: userToken): Promise<AxiosResponse<T, D>>;
|
|
67
72
|
URL(endpoint: string): URL;
|
|
68
73
|
getOAuthUrl(options?: {
|
|
69
74
|
redirect_uri?: string;
|
package/dist/index.js
CHANGED
|
@@ -80,7 +80,8 @@ class FortytwoIntraClient {
|
|
|
80
80
|
maxRetry;
|
|
81
81
|
logLine;
|
|
82
82
|
errLogBody;
|
|
83
|
-
|
|
83
|
+
authorization;
|
|
84
|
+
tokenRequest = null;
|
|
84
85
|
constructor(client_id, client_secret, conf) {
|
|
85
86
|
this.client_id = client_id;
|
|
86
87
|
this.client_secret = client_secret;
|
|
@@ -103,7 +104,7 @@ class FortytwoIntraClient {
|
|
|
103
104
|
this.maxRetry = config.maxRetry;
|
|
104
105
|
this.logLine = config.logLine;
|
|
105
106
|
this.errLogBody = config.errLogBody;
|
|
106
|
-
this.
|
|
107
|
+
this.authorization = null;
|
|
107
108
|
}
|
|
108
109
|
async generateToken() {
|
|
109
110
|
const res = await this.axiosInstance.post(this.token_url, {
|
|
@@ -112,15 +113,31 @@ class FortytwoIntraClient {
|
|
|
112
113
|
client_secret: this.client_secret,
|
|
113
114
|
scope: this.scopes.join(" "),
|
|
114
115
|
});
|
|
115
|
-
|
|
116
|
+
const { access_token, expires_in } = zod_1.default
|
|
117
|
+
.object({ access_token: zod_1.default.string(), expires_in: zod_1.default.number() })
|
|
118
|
+
.parse(res.data);
|
|
119
|
+
return { access_token, expires_at: Date.now() + expires_in * 1_000 };
|
|
120
|
+
}
|
|
121
|
+
isTokenValid() {
|
|
122
|
+
return this.authorization !== null && this.authorization.expires_at - 30_000 > Date.now();
|
|
123
|
+
}
|
|
124
|
+
async getAccessToken(token) {
|
|
125
|
+
if (token) {
|
|
126
|
+
return token.access_token;
|
|
127
|
+
}
|
|
128
|
+
if (!this.isTokenValid()) {
|
|
129
|
+
// Share a single in-flight token request between concurrent callers
|
|
130
|
+
this.tokenRequest ??= this.generateToken().finally(() => {
|
|
131
|
+
this.tokenRequest = null;
|
|
132
|
+
});
|
|
133
|
+
this.authorization = await this.tokenRequest;
|
|
134
|
+
}
|
|
135
|
+
return this.authorization.access_token;
|
|
116
136
|
}
|
|
117
137
|
async fetch(url, options) {
|
|
118
138
|
const { method, body, query } = options;
|
|
119
|
-
if (!options.token && !this.access_token) {
|
|
120
|
-
this.access_token = await this.generateToken();
|
|
121
|
-
}
|
|
122
139
|
// Attach access_token
|
|
123
|
-
const accessToken =
|
|
140
|
+
const accessToken = await this.getAccessToken(options.token);
|
|
124
141
|
// Extract query parameters from URL and combine with options.query
|
|
125
142
|
const urlParams = {};
|
|
126
143
|
url.searchParams.forEach((value, key) => {
|
|
@@ -155,7 +172,7 @@ class FortytwoIntraClient {
|
|
|
155
172
|
const status = err.response?.status;
|
|
156
173
|
if (maxRetry > 0 && attempt < maxRetry && status && this.retryOn.includes(status)) {
|
|
157
174
|
if (status === 401) {
|
|
158
|
-
this.
|
|
175
|
+
this.authorization = null;
|
|
159
176
|
}
|
|
160
177
|
options.attempt++;
|
|
161
178
|
return this.reqHandler(url, options);
|
|
@@ -322,6 +339,17 @@ class FortytwoIntraClient {
|
|
|
322
339
|
const allData = [...firstPage.data, ...otherPages.flatMap((res) => res.data)];
|
|
323
340
|
return this.validate(allData, options.schema);
|
|
324
341
|
}
|
|
342
|
+
async rawRequest(config, token) {
|
|
343
|
+
const accessToken = await this.getAccessToken(token);
|
|
344
|
+
return this.axiosInstance.request({
|
|
345
|
+
baseURL: this.base_url,
|
|
346
|
+
...config,
|
|
347
|
+
headers: {
|
|
348
|
+
...config.headers,
|
|
349
|
+
Authorization: `Bearer ${accessToken}`,
|
|
350
|
+
},
|
|
351
|
+
});
|
|
352
|
+
}
|
|
325
353
|
URL(endpoint) {
|
|
326
354
|
return new URL(endpoint, this.base_url);
|
|
327
355
|
}
|
package/dist/intraV3/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AxiosRequestConfig, AxiosResponse } from "axios";
|
|
1
2
|
import z from "zod";
|
|
2
3
|
import { inputOptions } from "../types";
|
|
3
4
|
export * from "../errors/httpError";
|
|
@@ -25,10 +26,12 @@ export declare class FortytwoIntraV3Client {
|
|
|
25
26
|
private logLine;
|
|
26
27
|
private errLogBody;
|
|
27
28
|
private authorization;
|
|
29
|
+
private tokenRequest;
|
|
28
30
|
constructor(credentials: Credentials, conf?: Partial<FortytwoIntraClientConf>);
|
|
29
31
|
private generateToken;
|
|
30
32
|
private isTokenValid;
|
|
31
33
|
private isRefreshTokenValid;
|
|
34
|
+
private getAccessToken;
|
|
32
35
|
private fetch;
|
|
33
36
|
private reqHandler;
|
|
34
37
|
private logSuccess;
|
|
@@ -54,5 +57,6 @@ export declare class FortytwoIntraV3Client {
|
|
|
54
57
|
delete<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "maxPages"> & {
|
|
55
58
|
schema: S;
|
|
56
59
|
}): Promise<z.infer<S>>;
|
|
60
|
+
rawRequest<T = any, D = any>(config: AxiosRequestConfig<D>): Promise<AxiosResponse<T, D>>;
|
|
57
61
|
URL(endpoint: string): URL;
|
|
58
62
|
}
|
package/dist/intraV3/index.js
CHANGED
|
@@ -65,6 +65,7 @@ class FortytwoIntraV3Client {
|
|
|
65
65
|
logLine;
|
|
66
66
|
errLogBody;
|
|
67
67
|
authorization;
|
|
68
|
+
tokenRequest = null;
|
|
68
69
|
constructor(credentials, conf = {}) {
|
|
69
70
|
this.credentials = credentials;
|
|
70
71
|
const config = { ...defaultConf, ...conf };
|
|
@@ -102,13 +103,20 @@ class FortytwoIntraV3Client {
|
|
|
102
103
|
isRefreshTokenValid() {
|
|
103
104
|
return (this.authorization !== null && this.authorization.refresh_expires_at - 30000 > Date.now());
|
|
104
105
|
}
|
|
105
|
-
async
|
|
106
|
-
const { method, body, query } = options;
|
|
106
|
+
async getAccessToken() {
|
|
107
107
|
if (!this.isTokenValid()) {
|
|
108
|
-
|
|
108
|
+
// Share a single in-flight token request between concurrent callers
|
|
109
|
+
this.tokenRequest ??= this.generateToken().finally(() => {
|
|
110
|
+
this.tokenRequest = null;
|
|
111
|
+
});
|
|
112
|
+
this.authorization = await this.tokenRequest;
|
|
109
113
|
}
|
|
114
|
+
return this.authorization.access_token;
|
|
115
|
+
}
|
|
116
|
+
async fetch(url, options) {
|
|
117
|
+
const { method, body, query } = options;
|
|
110
118
|
// Attach access_token
|
|
111
|
-
const accessToken = this.
|
|
119
|
+
const accessToken = await this.getAccessToken();
|
|
112
120
|
// Extract query parameters from URL and combine with options.query
|
|
113
121
|
const urlParams = {};
|
|
114
122
|
url.searchParams.forEach((value, key) => {
|
|
@@ -259,6 +267,17 @@ class FortytwoIntraV3Client {
|
|
|
259
267
|
});
|
|
260
268
|
return this.validate(res.data, options.schema);
|
|
261
269
|
}
|
|
270
|
+
async rawRequest(config) {
|
|
271
|
+
const accessToken = await this.getAccessToken();
|
|
272
|
+
return this.axiosInstance.request({
|
|
273
|
+
baseURL: this.base_url,
|
|
274
|
+
...config,
|
|
275
|
+
headers: {
|
|
276
|
+
...config.headers,
|
|
277
|
+
Authorization: `Bearer ${accessToken}`,
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
}
|
|
262
281
|
URL(endpoint) {
|
|
263
282
|
return new URL(endpoint, this.base_url);
|
|
264
283
|
}
|