@ibertran/fortytwo-intra-client 4.0.0 → 5.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 +20 -0
- package/dist/errors/httpError.d.ts +8 -0
- package/dist/errors/httpError.js +25 -0
- package/dist/errors/validationError.d.ts +7 -0
- package/dist/errors/validationError.js +18 -0
- package/dist/index.d.ts +16 -14
- package/dist/index.js +40 -46
- package/dist/intraV3/index.d.ts +58 -0
- package/dist/intraV3/index.js +266 -0
- package/dist/intraV3/schemas.d.ts +27 -0
- package/dist/intraV3/schemas.js +28 -0
- package/dist/lib/errors.js +1 -3
- package/dist/lib/logs.js +1 -1
- package/dist/lib/pagination.js +1 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,26 @@ const user = await client.get("users/ibertran");
|
|
|
20
20
|
console.log(user);
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
## Intra V3
|
|
24
|
+
|
|
25
|
+
The library also exports `FortytwoIntraV3Client` for staff-only Intra V3 endpoints that use the 42 Auth token flow.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { FortytwoIntraV3Client } from "@ibertran/fortytwo-intra-client";
|
|
29
|
+
|
|
30
|
+
const client = new FortytwoIntraV3Client({
|
|
31
|
+
client_id: "staff-42-campus",
|
|
32
|
+
client_secret: "your_client_secret",
|
|
33
|
+
username: "your_staff_login",
|
|
34
|
+
password: "your_staff_password",
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const response = await client.get("some/v3/endpoint");
|
|
38
|
+
console.log(response);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The V3 client automatically requests a bearer token, reuses it while valid, and falls back to the refresh token when available.
|
|
42
|
+
|
|
23
43
|
## Configuration
|
|
24
44
|
|
|
25
45
|
The `FortytwoIntraClient` class accepts three parameters:
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AxiosError } from "axios";
|
|
2
|
+
export declare class FortytwoIntraClientHttpError extends Error {
|
|
3
|
+
statusCode: number;
|
|
4
|
+
statusText: string;
|
|
5
|
+
data: unknown;
|
|
6
|
+
constructor(error: AxiosError);
|
|
7
|
+
}
|
|
8
|
+
export declare function isFortytwoIntraClientHttpError(error: unknown): error is FortytwoIntraClientHttpError;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FortytwoIntraClientHttpError = void 0;
|
|
4
|
+
exports.isFortytwoIntraClientHttpError = isFortytwoIntraClientHttpError;
|
|
5
|
+
class FortytwoIntraClientHttpError extends Error {
|
|
6
|
+
statusCode;
|
|
7
|
+
statusText;
|
|
8
|
+
data;
|
|
9
|
+
constructor(error) {
|
|
10
|
+
const method = error.config?.method?.toUpperCase() ?? null;
|
|
11
|
+
const route = error.config?.url ?? null;
|
|
12
|
+
const statusCode = error.response?.status ?? NaN;
|
|
13
|
+
const statusText = error.response?.statusText ?? "Unknown";
|
|
14
|
+
const message = method && route ? `${method} ${route} - HTTP ${statusCode} ${statusText}` : error.message;
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "FortytwoIntraClientHttpError";
|
|
17
|
+
this.statusCode = statusCode;
|
|
18
|
+
this.statusText = statusText;
|
|
19
|
+
this.data = error.response?.data;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.FortytwoIntraClientHttpError = FortytwoIntraClientHttpError;
|
|
23
|
+
function isFortytwoIntraClientHttpError(error) {
|
|
24
|
+
return error instanceof FortytwoIntraClientHttpError;
|
|
25
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ZodError } from "zod";
|
|
2
|
+
export declare class FortytwoIntraClientValidationError extends Error {
|
|
3
|
+
schemaErrors: ZodError;
|
|
4
|
+
data: unknown;
|
|
5
|
+
constructor(schemaErrors: ZodError, data: unknown);
|
|
6
|
+
}
|
|
7
|
+
export declare function isFortytwoIntraClientValidationError(error: unknown): error is FortytwoIntraClientValidationError;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FortytwoIntraClientValidationError = void 0;
|
|
4
|
+
exports.isFortytwoIntraClientValidationError = isFortytwoIntraClientValidationError;
|
|
5
|
+
class FortytwoIntraClientValidationError extends Error {
|
|
6
|
+
schemaErrors;
|
|
7
|
+
data;
|
|
8
|
+
constructor(schemaErrors, data) {
|
|
9
|
+
super("Schema validation failed");
|
|
10
|
+
this.name = "FortytwoIntraClientValidationError";
|
|
11
|
+
this.schemaErrors = schemaErrors;
|
|
12
|
+
this.data = data;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.FortytwoIntraClientValidationError = FortytwoIntraClientValidationError;
|
|
16
|
+
function isFortytwoIntraClientValidationError(error) {
|
|
17
|
+
return error instanceof FortytwoIntraClientValidationError;
|
|
18
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import z from "zod";
|
|
1
2
|
import { inputOptions } from "./types";
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
export { FortytwoIntraV3Client } from "./intraV3";
|
|
4
|
+
export * from "./errors/httpError";
|
|
5
|
+
export * from "./errors/validationError";
|
|
4
6
|
export interface FortytwoIntraClientConf {
|
|
5
7
|
redirect_uri: string | null;
|
|
6
8
|
base_url: string;
|
|
@@ -37,24 +39,25 @@ export declare class FortytwoIntraClient {
|
|
|
37
39
|
private reqHandler;
|
|
38
40
|
private logSuccess;
|
|
39
41
|
private logError;
|
|
40
|
-
|
|
41
|
-
get
|
|
42
|
+
private validate;
|
|
43
|
+
get(endpoint: URL | string, options?: Omit<inputOptions, "body" | "perPage" | "maxPages">): Promise<any>;
|
|
44
|
+
get<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "body" | "perPage" | "maxPages"> & {
|
|
42
45
|
schema: S;
|
|
43
46
|
}): Promise<z.infer<S>>;
|
|
44
|
-
post(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "
|
|
45
|
-
post<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "
|
|
47
|
+
post(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "maxPages">): Promise<any>;
|
|
48
|
+
post<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "maxPages"> & {
|
|
46
49
|
schema: S;
|
|
47
50
|
}): Promise<z.infer<S>>;
|
|
48
|
-
put(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "
|
|
49
|
-
put<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "
|
|
51
|
+
put(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "maxPages">): Promise<any>;
|
|
52
|
+
put<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "maxPages"> & {
|
|
50
53
|
schema: S;
|
|
51
54
|
}): Promise<z.infer<S>>;
|
|
52
|
-
patch(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "
|
|
53
|
-
patch<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "
|
|
55
|
+
patch(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "maxPages">): Promise<any>;
|
|
56
|
+
patch<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "maxPages"> & {
|
|
54
57
|
schema: S;
|
|
55
58
|
}): Promise<z.infer<S>>;
|
|
56
|
-
delete(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "
|
|
57
|
-
delete<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "
|
|
59
|
+
delete(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "maxPages">): Promise<any>;
|
|
60
|
+
delete<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "maxPages"> & {
|
|
58
61
|
schema: S;
|
|
59
62
|
}): Promise<z.infer<S>>;
|
|
60
63
|
getAll(endpoint: URL | string, options?: Omit<inputOptions, "body">): Promise<any>;
|
|
@@ -70,6 +73,5 @@ export declare class FortytwoIntraClient {
|
|
|
70
73
|
state: string | null;
|
|
71
74
|
};
|
|
72
75
|
exchangeOAuthCode(code: string, redirect_uri?: string): Promise<any>;
|
|
73
|
-
tokenInfos(options?: Omit<inputOptions, "body" | "perPage" | "
|
|
76
|
+
tokenInfos(options?: Omit<inputOptions, "body" | "perPage" | "maxPages">): Promise<any>;
|
|
74
77
|
}
|
|
75
|
-
export { FortytwoIntraClientError, isFortytwoIntraClientError };
|
package/dist/index.js
CHANGED
|
@@ -32,18 +32,25 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
36
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
|
+
};
|
|
35
38
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
39
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
40
|
};
|
|
38
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.
|
|
42
|
+
exports.FortytwoIntraClient = exports.FortytwoIntraV3Client = void 0;
|
|
40
43
|
const axios_1 = __importStar(require("axios"));
|
|
41
44
|
const axios_rate_limit_1 = __importDefault(require("axios-rate-limit"));
|
|
42
|
-
const
|
|
45
|
+
const zod_1 = __importDefault(require("zod"));
|
|
43
46
|
const logs_1 = require("./lib/logs");
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
const pagination_1 = require("./lib/pagination");
|
|
48
|
+
const httpError_1 = require("./errors/httpError");
|
|
49
|
+
const validationError_1 = require("./errors/validationError");
|
|
50
|
+
var intraV3_1 = require("./intraV3");
|
|
51
|
+
Object.defineProperty(exports, "FortytwoIntraV3Client", { enumerable: true, get: function () { return intraV3_1.FortytwoIntraV3Client; } });
|
|
52
|
+
__exportStar(require("./errors/httpError"), exports);
|
|
53
|
+
__exportStar(require("./errors/validationError"), exports);
|
|
47
54
|
const defaultConf = {
|
|
48
55
|
redirect_uri: null,
|
|
49
56
|
base_url: "https://api.intra.42.fr/v2/",
|
|
@@ -113,9 +120,7 @@ class FortytwoIntraClient {
|
|
|
113
120
|
this.access_token = await this.generateToken();
|
|
114
121
|
}
|
|
115
122
|
// Attach access_token
|
|
116
|
-
const accessToken = options.token
|
|
117
|
-
? options.token.access_token
|
|
118
|
-
: this.access_token;
|
|
123
|
+
const accessToken = options.token ? options.token.access_token : this.access_token;
|
|
119
124
|
// Extract query parameters from URL and combine with options.query
|
|
120
125
|
const urlParams = {};
|
|
121
126
|
url.searchParams.forEach((value, key) => {
|
|
@@ -125,7 +130,7 @@ class FortytwoIntraClient {
|
|
|
125
130
|
const combinedParams = { ...urlParams, ...query };
|
|
126
131
|
// Create clean URL without query parameters
|
|
127
132
|
const cleanUrl = new URL(url);
|
|
128
|
-
cleanUrl.search =
|
|
133
|
+
cleanUrl.search = "";
|
|
129
134
|
// Use the rate-limited axios instance
|
|
130
135
|
return this.axiosInstance.request({
|
|
131
136
|
method: method.toLowerCase(),
|
|
@@ -156,7 +161,7 @@ class FortytwoIntraClient {
|
|
|
156
161
|
return this.reqHandler(url, options);
|
|
157
162
|
}
|
|
158
163
|
else {
|
|
159
|
-
throw new
|
|
164
|
+
throw new httpError_1.FortytwoIntraClientHttpError(err);
|
|
160
165
|
}
|
|
161
166
|
}
|
|
162
167
|
else {
|
|
@@ -183,6 +188,20 @@ class FortytwoIntraClient {
|
|
|
183
188
|
console.log(line, logBody ? body : "");
|
|
184
189
|
}
|
|
185
190
|
}
|
|
191
|
+
validate(data, schema) {
|
|
192
|
+
if (!schema) {
|
|
193
|
+
return data;
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
return schema.parse(data);
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
if (err instanceof zod_1.default.ZodError) {
|
|
200
|
+
throw new validationError_1.FortytwoIntraClientValidationError(err, data);
|
|
201
|
+
}
|
|
202
|
+
throw err;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
186
205
|
async get(endpoint, options = {}) {
|
|
187
206
|
if (endpoint instanceof URL === false) {
|
|
188
207
|
endpoint = new URL(endpoint, this.base_url);
|
|
@@ -195,10 +214,7 @@ class FortytwoIntraClient {
|
|
|
195
214
|
errLogBody: this.errLogBody,
|
|
196
215
|
...options,
|
|
197
216
|
});
|
|
198
|
-
|
|
199
|
-
return options.schema.parse(res.data);
|
|
200
|
-
}
|
|
201
|
-
return res.data;
|
|
217
|
+
return this.validate(res.data, options.schema);
|
|
202
218
|
}
|
|
203
219
|
async post(endpoint, options = {}) {
|
|
204
220
|
if (endpoint instanceof URL === false) {
|
|
@@ -212,10 +228,7 @@ class FortytwoIntraClient {
|
|
|
212
228
|
errLogBody: this.errLogBody,
|
|
213
229
|
...options,
|
|
214
230
|
});
|
|
215
|
-
|
|
216
|
-
return options.schema.parse(res.data);
|
|
217
|
-
}
|
|
218
|
-
return res.data;
|
|
231
|
+
return this.validate(res.data, options.schema);
|
|
219
232
|
}
|
|
220
233
|
async put(endpoint, options = {}) {
|
|
221
234
|
if (endpoint instanceof URL === false) {
|
|
@@ -229,10 +242,7 @@ class FortytwoIntraClient {
|
|
|
229
242
|
errLogBody: this.errLogBody,
|
|
230
243
|
...options,
|
|
231
244
|
});
|
|
232
|
-
|
|
233
|
-
return options.schema.parse(res.data);
|
|
234
|
-
}
|
|
235
|
-
return res.data;
|
|
245
|
+
return this.validate(res.data, options.schema);
|
|
236
246
|
}
|
|
237
247
|
async patch(endpoint, options = {}) {
|
|
238
248
|
if (endpoint instanceof URL === false) {
|
|
@@ -246,10 +256,7 @@ class FortytwoIntraClient {
|
|
|
246
256
|
errLogBody: this.errLogBody,
|
|
247
257
|
...options,
|
|
248
258
|
});
|
|
249
|
-
|
|
250
|
-
return options.schema.parse(res.data);
|
|
251
|
-
}
|
|
252
|
-
return res.data;
|
|
259
|
+
return this.validate(res.data, options.schema);
|
|
253
260
|
}
|
|
254
261
|
async delete(endpoint, options = {}) {
|
|
255
262
|
if (endpoint instanceof URL === false) {
|
|
@@ -263,10 +270,7 @@ class FortytwoIntraClient {
|
|
|
263
270
|
errLogBody: this.errLogBody,
|
|
264
271
|
...options,
|
|
265
272
|
});
|
|
266
|
-
|
|
267
|
-
return options.schema.parse(res.data);
|
|
268
|
-
}
|
|
269
|
-
return res.data;
|
|
273
|
+
return this.validate(res.data, options.schema);
|
|
270
274
|
}
|
|
271
275
|
async getAll(endpoint, options = {}) {
|
|
272
276
|
if (endpoint instanceof URL === false) {
|
|
@@ -287,26 +291,19 @@ class FortytwoIntraClient {
|
|
|
287
291
|
...options.query,
|
|
288
292
|
page: 1,
|
|
289
293
|
per_page: perPage,
|
|
290
|
-
}
|
|
294
|
+
},
|
|
291
295
|
});
|
|
292
296
|
if (!Array.isArray(firstPage.data)) {
|
|
293
|
-
|
|
294
|
-
return options.schema.parse(firstPage.data);
|
|
295
|
-
}
|
|
296
|
-
return firstPage.data;
|
|
297
|
+
return this.validate(firstPage.data, options.schema);
|
|
297
298
|
}
|
|
298
299
|
let lastPage;
|
|
299
300
|
try {
|
|
300
301
|
lastPage = Math.min((0, pagination_1.getLastPage)(firstPage.headers["link"]), options.maxPages || Infinity);
|
|
301
302
|
}
|
|
302
303
|
catch (err) {
|
|
303
|
-
|
|
304
|
-
return options.schema.parse(firstPage.data);
|
|
305
|
-
}
|
|
306
|
-
return firstPage.data;
|
|
304
|
+
return this.validate(firstPage.data, options.schema);
|
|
307
305
|
}
|
|
308
|
-
const promises = Array.from({ length: lastPage - 1 }, (_, i) => i + 2)
|
|
309
|
-
.map(pageNumber => this.reqHandler(url, {
|
|
306
|
+
const promises = Array.from({ length: lastPage - 1 }, (_, i) => i + 2).map((pageNumber) => this.reqHandler(url, {
|
|
310
307
|
method: "GET",
|
|
311
308
|
attempt: 0,
|
|
312
309
|
currpage: pageNumber,
|
|
@@ -319,14 +316,11 @@ class FortytwoIntraClient {
|
|
|
319
316
|
...options.query,
|
|
320
317
|
page: pageNumber,
|
|
321
318
|
per_page: perPage,
|
|
322
|
-
}
|
|
319
|
+
},
|
|
323
320
|
}));
|
|
324
321
|
const otherPages = await Promise.all(promises);
|
|
325
322
|
const allData = [...firstPage.data, ...otherPages.flatMap((res) => res.data)];
|
|
326
|
-
|
|
327
|
-
return options.schema.parse(allData);
|
|
328
|
-
}
|
|
329
|
-
return allData;
|
|
323
|
+
return this.validate(allData, options.schema);
|
|
330
324
|
}
|
|
331
325
|
URL(endpoint) {
|
|
332
326
|
return new URL(endpoint, this.base_url);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
import { inputOptions } from "../types";
|
|
3
|
+
export * from "../errors/httpError";
|
|
4
|
+
export * from "../errors/validationError";
|
|
5
|
+
export interface FortytwoIntraClientConf {
|
|
6
|
+
base_url: string | undefined;
|
|
7
|
+
token_url: string;
|
|
8
|
+
maxRetry: number;
|
|
9
|
+
logLine: boolean;
|
|
10
|
+
errLogBody: boolean;
|
|
11
|
+
}
|
|
12
|
+
type Credentials = {
|
|
13
|
+
client_id: string;
|
|
14
|
+
client_secret: string;
|
|
15
|
+
username: string;
|
|
16
|
+
password: string;
|
|
17
|
+
};
|
|
18
|
+
export declare class FortytwoIntraV3Client {
|
|
19
|
+
private credentials;
|
|
20
|
+
private base_url;
|
|
21
|
+
private token_url;
|
|
22
|
+
private axiosInstance;
|
|
23
|
+
private retryOn;
|
|
24
|
+
private maxRetry;
|
|
25
|
+
private logLine;
|
|
26
|
+
private errLogBody;
|
|
27
|
+
private authorization;
|
|
28
|
+
constructor(credentials: Credentials, conf?: Partial<FortytwoIntraClientConf>);
|
|
29
|
+
private generateToken;
|
|
30
|
+
private isTokenValid;
|
|
31
|
+
private isRefreshTokenValid;
|
|
32
|
+
private fetch;
|
|
33
|
+
private reqHandler;
|
|
34
|
+
private logSuccess;
|
|
35
|
+
private logError;
|
|
36
|
+
private validate;
|
|
37
|
+
get(endpoint: URL | string, options?: Omit<inputOptions, "body" | "perPage" | "maxPages" | "token">): Promise<any>;
|
|
38
|
+
get<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "body" | "perPage" | "maxPages" | "token"> & {
|
|
39
|
+
schema: S;
|
|
40
|
+
}): Promise<z.infer<S>>;
|
|
41
|
+
post(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "maxPages">): Promise<any>;
|
|
42
|
+
post<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "maxPages"> & {
|
|
43
|
+
schema: S;
|
|
44
|
+
}): Promise<z.infer<S>>;
|
|
45
|
+
put(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "maxPages">): Promise<any>;
|
|
46
|
+
put<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "maxPages"> & {
|
|
47
|
+
schema: S;
|
|
48
|
+
}): Promise<z.infer<S>>;
|
|
49
|
+
patch(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "maxPages">): Promise<any>;
|
|
50
|
+
patch<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "maxPages"> & {
|
|
51
|
+
schema: S;
|
|
52
|
+
}): Promise<z.infer<S>>;
|
|
53
|
+
delete(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "maxPages">): Promise<any>;
|
|
54
|
+
delete<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "maxPages"> & {
|
|
55
|
+
schema: S;
|
|
56
|
+
}): Promise<z.infer<S>>;
|
|
57
|
+
URL(endpoint: string): URL;
|
|
58
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
36
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
|
+
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.FortytwoIntraV3Client = void 0;
|
|
43
|
+
const axios_1 = __importStar(require("axios"));
|
|
44
|
+
const zod_1 = __importDefault(require("zod"));
|
|
45
|
+
const logs_1 = require("../lib/logs");
|
|
46
|
+
const httpError_1 = require("../errors/httpError");
|
|
47
|
+
const validationError_1 = require("../errors/validationError");
|
|
48
|
+
const schemas_1 = require("./schemas");
|
|
49
|
+
__exportStar(require("../errors/httpError"), exports);
|
|
50
|
+
__exportStar(require("../errors/validationError"), exports);
|
|
51
|
+
const defaultConf = {
|
|
52
|
+
base_url: undefined,
|
|
53
|
+
token_url: "https://auth.42.fr/auth/realms/staff-42/protocol/openid-connect/token",
|
|
54
|
+
maxRetry: 5,
|
|
55
|
+
logLine: true,
|
|
56
|
+
errLogBody: true,
|
|
57
|
+
};
|
|
58
|
+
class FortytwoIntraV3Client {
|
|
59
|
+
credentials;
|
|
60
|
+
base_url;
|
|
61
|
+
token_url;
|
|
62
|
+
axiosInstance;
|
|
63
|
+
retryOn;
|
|
64
|
+
maxRetry;
|
|
65
|
+
logLine;
|
|
66
|
+
errLogBody;
|
|
67
|
+
authorization;
|
|
68
|
+
constructor(credentials, conf = {}) {
|
|
69
|
+
this.credentials = credentials;
|
|
70
|
+
const config = { ...defaultConf, ...conf };
|
|
71
|
+
this.base_url = config.base_url;
|
|
72
|
+
this.token_url = config.token_url;
|
|
73
|
+
this.axiosInstance = axios_1.default.create();
|
|
74
|
+
this.retryOn = [401, 429, 500];
|
|
75
|
+
this.maxRetry = config.maxRetry;
|
|
76
|
+
this.logLine = config.logLine;
|
|
77
|
+
this.errLogBody = config.errLogBody;
|
|
78
|
+
this.authorization = null;
|
|
79
|
+
}
|
|
80
|
+
async generateToken() {
|
|
81
|
+
const data = this.authorization && this.isRefreshTokenValid()
|
|
82
|
+
? new URLSearchParams({
|
|
83
|
+
grant_type: "refresh_token",
|
|
84
|
+
refresh_token: this.authorization.refresh_token,
|
|
85
|
+
})
|
|
86
|
+
: new URLSearchParams({
|
|
87
|
+
grant_type: "password",
|
|
88
|
+
username: this.credentials.username,
|
|
89
|
+
password: this.credentials.password,
|
|
90
|
+
});
|
|
91
|
+
const res = await this.axiosInstance.post(this.token_url, data, {
|
|
92
|
+
headers: {
|
|
93
|
+
Authorization: `Basic ${Buffer.from(`${this.credentials.client_id}:${this.credentials.client_secret}`).toString("base64")}`,
|
|
94
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
return schemas_1.tokenSchema.parse(res.data);
|
|
98
|
+
}
|
|
99
|
+
isTokenValid() {
|
|
100
|
+
return this.authorization !== null && this.authorization.expires_at - 30000 > Date.now();
|
|
101
|
+
}
|
|
102
|
+
isRefreshTokenValid() {
|
|
103
|
+
return (this.authorization !== null && this.authorization.refresh_expires_at - 30000 > Date.now());
|
|
104
|
+
}
|
|
105
|
+
async fetch(url, options) {
|
|
106
|
+
const { method, body, query } = options;
|
|
107
|
+
if (!this.isTokenValid()) {
|
|
108
|
+
this.authorization = await this.generateToken();
|
|
109
|
+
}
|
|
110
|
+
// Attach access_token
|
|
111
|
+
const accessToken = this.authorization?.access_token;
|
|
112
|
+
// Extract query parameters from URL and combine with options.query
|
|
113
|
+
const urlParams = {};
|
|
114
|
+
url.searchParams.forEach((value, key) => {
|
|
115
|
+
urlParams[key] = value;
|
|
116
|
+
});
|
|
117
|
+
// Combine URL params with query params (query params take precedence)
|
|
118
|
+
const combinedParams = { ...urlParams, ...query };
|
|
119
|
+
// Create clean URL without query parameters
|
|
120
|
+
const cleanUrl = new URL(url);
|
|
121
|
+
cleanUrl.search = "";
|
|
122
|
+
return this.axiosInstance.request({
|
|
123
|
+
method: method.toLowerCase(),
|
|
124
|
+
url: cleanUrl.toString(),
|
|
125
|
+
headers: {
|
|
126
|
+
Authorization: `Bearer ${accessToken}`,
|
|
127
|
+
},
|
|
128
|
+
params: combinedParams,
|
|
129
|
+
data: body ? body : undefined,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
async reqHandler(url, options) {
|
|
133
|
+
try {
|
|
134
|
+
const res = await this.fetch(url, options);
|
|
135
|
+
this.logSuccess(res, options);
|
|
136
|
+
return res;
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
if ((0, axios_1.isAxiosError)(err)) {
|
|
140
|
+
this.logError(err, options);
|
|
141
|
+
const { attempt, maxRetry } = options;
|
|
142
|
+
const status = err.response?.status;
|
|
143
|
+
if (maxRetry > 0 && attempt < maxRetry && status && this.retryOn.includes(status)) {
|
|
144
|
+
if (status === 401) {
|
|
145
|
+
this.authorization = null;
|
|
146
|
+
}
|
|
147
|
+
options.attempt++;
|
|
148
|
+
return this.reqHandler(url, options);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
throw new httpError_1.FortytwoIntraClientHttpError(err);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
throw err;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
logSuccess(res, options) {
|
|
160
|
+
if (!options.logLine)
|
|
161
|
+
return;
|
|
162
|
+
const line = (0, logs_1.getLogLine)(res, options);
|
|
163
|
+
console.log(line);
|
|
164
|
+
}
|
|
165
|
+
logError(err, options) {
|
|
166
|
+
if (!options.logLine)
|
|
167
|
+
return;
|
|
168
|
+
const line = (0, logs_1.getErrorLogLine)(err, options);
|
|
169
|
+
const body = err.response?.data;
|
|
170
|
+
const logBody = options.errLogBody && body && Object.keys(body).length;
|
|
171
|
+
try {
|
|
172
|
+
console.log(line, logBody ? JSON.stringify(body, null, 2) : "");
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
console.log(line, logBody ? body : "");
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
validate(data, schema) {
|
|
179
|
+
if (!schema) {
|
|
180
|
+
return data;
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
return schema.parse(data);
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
if (err instanceof zod_1.default.ZodError) {
|
|
187
|
+
throw new validationError_1.FortytwoIntraClientValidationError(err, data);
|
|
188
|
+
}
|
|
189
|
+
throw err;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async get(endpoint, options = {}) {
|
|
193
|
+
if (endpoint instanceof URL === false) {
|
|
194
|
+
endpoint = new URL(endpoint, this.base_url);
|
|
195
|
+
}
|
|
196
|
+
const res = await this.reqHandler(endpoint, {
|
|
197
|
+
method: "GET",
|
|
198
|
+
attempt: 0,
|
|
199
|
+
maxRetry: this.maxRetry,
|
|
200
|
+
logLine: this.logLine,
|
|
201
|
+
errLogBody: this.errLogBody,
|
|
202
|
+
...options,
|
|
203
|
+
});
|
|
204
|
+
return this.validate(res.data, options.schema);
|
|
205
|
+
}
|
|
206
|
+
async post(endpoint, options = {}) {
|
|
207
|
+
if (endpoint instanceof URL === false) {
|
|
208
|
+
endpoint = new URL(endpoint, this.base_url);
|
|
209
|
+
}
|
|
210
|
+
const res = await this.reqHandler(endpoint, {
|
|
211
|
+
method: "POST",
|
|
212
|
+
attempt: 0,
|
|
213
|
+
maxRetry: this.maxRetry,
|
|
214
|
+
logLine: this.logLine,
|
|
215
|
+
errLogBody: this.errLogBody,
|
|
216
|
+
...options,
|
|
217
|
+
});
|
|
218
|
+
return this.validate(res.data, options.schema);
|
|
219
|
+
}
|
|
220
|
+
async put(endpoint, options = {}) {
|
|
221
|
+
if (endpoint instanceof URL === false) {
|
|
222
|
+
endpoint = new URL(endpoint, this.base_url);
|
|
223
|
+
}
|
|
224
|
+
const res = await this.reqHandler(endpoint, {
|
|
225
|
+
method: "PUT",
|
|
226
|
+
attempt: 0,
|
|
227
|
+
maxRetry: this.maxRetry,
|
|
228
|
+
logLine: this.logLine,
|
|
229
|
+
errLogBody: this.errLogBody,
|
|
230
|
+
...options,
|
|
231
|
+
});
|
|
232
|
+
return this.validate(res.data, options.schema);
|
|
233
|
+
}
|
|
234
|
+
async patch(endpoint, options = {}) {
|
|
235
|
+
if (endpoint instanceof URL === false) {
|
|
236
|
+
endpoint = new URL(endpoint, this.base_url);
|
|
237
|
+
}
|
|
238
|
+
const res = await this.reqHandler(endpoint, {
|
|
239
|
+
method: "PATCH",
|
|
240
|
+
attempt: 0,
|
|
241
|
+
maxRetry: this.maxRetry,
|
|
242
|
+
logLine: this.logLine,
|
|
243
|
+
errLogBody: this.errLogBody,
|
|
244
|
+
...options,
|
|
245
|
+
});
|
|
246
|
+
return this.validate(res.data, options.schema);
|
|
247
|
+
}
|
|
248
|
+
async delete(endpoint, options = {}) {
|
|
249
|
+
if (endpoint instanceof URL === false) {
|
|
250
|
+
endpoint = new URL(endpoint, this.base_url);
|
|
251
|
+
}
|
|
252
|
+
const res = await this.reqHandler(endpoint, {
|
|
253
|
+
method: "DELETE",
|
|
254
|
+
attempt: 0,
|
|
255
|
+
maxRetry: this.maxRetry,
|
|
256
|
+
logLine: this.logLine,
|
|
257
|
+
errLogBody: this.errLogBody,
|
|
258
|
+
...options,
|
|
259
|
+
});
|
|
260
|
+
return this.validate(res.data, options.schema);
|
|
261
|
+
}
|
|
262
|
+
URL(endpoint) {
|
|
263
|
+
return new URL(endpoint, this.base_url);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
exports.FortytwoIntraV3Client = FortytwoIntraV3Client;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
export declare const tokenSchema: z.ZodPipe<z.ZodObject<{
|
|
3
|
+
access_token: z.ZodString;
|
|
4
|
+
expires_in: z.ZodNumber;
|
|
5
|
+
refresh_expires_in: z.ZodNumber;
|
|
6
|
+
refresh_token: z.ZodString;
|
|
7
|
+
token_type: z.ZodString;
|
|
8
|
+
"not-before-policy": z.ZodNumber;
|
|
9
|
+
session_state: z.ZodString;
|
|
10
|
+
scope: z.ZodString;
|
|
11
|
+
}, z.core.$strict>, z.ZodTransform<{
|
|
12
|
+
access_token: string;
|
|
13
|
+
expires_at: number;
|
|
14
|
+
refresh_token: string;
|
|
15
|
+
refresh_expires_at: number;
|
|
16
|
+
token_type: string;
|
|
17
|
+
}, {
|
|
18
|
+
access_token: string;
|
|
19
|
+
expires_in: number;
|
|
20
|
+
refresh_expires_in: number;
|
|
21
|
+
refresh_token: string;
|
|
22
|
+
token_type: string;
|
|
23
|
+
"not-before-policy": number;
|
|
24
|
+
session_state: string;
|
|
25
|
+
scope: string;
|
|
26
|
+
}>>;
|
|
27
|
+
export type Token = z.infer<typeof tokenSchema>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.tokenSchema = void 0;
|
|
7
|
+
const zod_1 = __importDefault(require("zod"));
|
|
8
|
+
exports.tokenSchema = zod_1.default
|
|
9
|
+
.strictObject({
|
|
10
|
+
access_token: zod_1.default.string(),
|
|
11
|
+
expires_in: zod_1.default.number(),
|
|
12
|
+
refresh_expires_in: zod_1.default.number(),
|
|
13
|
+
refresh_token: zod_1.default.string(),
|
|
14
|
+
token_type: zod_1.default.string(),
|
|
15
|
+
"not-before-policy": zod_1.default.number(),
|
|
16
|
+
session_state: zod_1.default.string(),
|
|
17
|
+
scope: zod_1.default.string(),
|
|
18
|
+
})
|
|
19
|
+
.transform((obj) => {
|
|
20
|
+
const now = Date.now();
|
|
21
|
+
return {
|
|
22
|
+
access_token: obj.access_token,
|
|
23
|
+
expires_at: now + obj.expires_in * 1000,
|
|
24
|
+
refresh_token: obj.refresh_token,
|
|
25
|
+
refresh_expires_at: now + obj.refresh_expires_in * 1000,
|
|
26
|
+
token_type: obj.token_type,
|
|
27
|
+
};
|
|
28
|
+
});
|
package/dist/lib/errors.js
CHANGED
|
@@ -11,9 +11,7 @@ class FortytwoIntraClientError extends Error {
|
|
|
11
11
|
const route = error.config?.url ?? null;
|
|
12
12
|
const statusCode = error.response?.status ?? NaN;
|
|
13
13
|
const statusText = error.response?.statusText ?? "Unknown";
|
|
14
|
-
const message = method && route
|
|
15
|
-
? `${method} ${route} - HTTP ${statusCode} ${statusText}`
|
|
16
|
-
: error.message;
|
|
14
|
+
const message = method && route ? `${method} ${route} - HTTP ${statusCode} ${statusText}` : error.message;
|
|
17
15
|
super(message);
|
|
18
16
|
this.name = "FortytwoIntraClientError";
|
|
19
17
|
this.statusCode = statusCode;
|
package/dist/lib/logs.js
CHANGED
package/dist/lib/pagination.js
CHANGED
|
@@ -5,9 +5,7 @@ function getLastPage(header) {
|
|
|
5
5
|
if (!header) {
|
|
6
6
|
throw Error("No pagination link header");
|
|
7
7
|
}
|
|
8
|
-
const paginationlinks = header
|
|
9
|
-
.split(",")
|
|
10
|
-
.reduce((links, part) => {
|
|
8
|
+
const paginationlinks = header.split(",").reduce((links, part) => {
|
|
11
9
|
const match = part.match(/<([^>]+)>\s*;\s*rel="([^"]+)"/);
|
|
12
10
|
if (match) {
|
|
13
11
|
const url = match[1];
|