@ibertran/fortytwo-intra-client 4.1.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 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:
@@ -120,6 +140,27 @@ const allProjects = await client.getAll("projects", {
120
140
  });
121
141
  ```
122
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
+
123
164
  ## OAuth Authentication
124
165
 
125
166
  ### Authorization Flow
@@ -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
+ }
@@ -6,11 +6,7 @@ class FortytwoIntraClientValidationError extends Error {
6
6
  schemaErrors;
7
7
  data;
8
8
  constructor(schemaErrors, data) {
9
- // const errorMessages = schemaErrors.errors
10
- // .map((error) => `${error.path.join(".")} - ${error.message}`)
11
- // .join("; ");
12
- const message = `Schema validation failed: `;
13
- super(message);
9
+ super("Schema validation failed");
14
10
  this.name = "FortytwoIntraClientValidationError";
15
11
  this.schemaErrors = schemaErrors;
16
12
  this.data = data;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,9 @@
1
- import { inputOptions } from "./types";
2
- import { FortytwoIntraClientError, isFortytwoIntraClientError } from "./lib/errors";
3
- import { z } from "zod";
1
+ import { AxiosRequestConfig, AxiosResponse } from "axios";
2
+ import z from "zod";
3
+ import { inputOptions, userToken } from "./types";
4
+ export { FortytwoIntraV3Client } from "./intraV3";
5
+ export * from "./errors/httpError";
6
+ export * from "./errors/validationError";
4
7
  export interface FortytwoIntraClientConf {
5
8
  redirect_uri: string | null;
6
9
  base_url: string;
@@ -30,9 +33,12 @@ export declare class FortytwoIntraClient {
30
33
  private maxRetry;
31
34
  private logLine;
32
35
  private errLogBody;
33
- private access_token;
36
+ private authorization;
37
+ private tokenRequest;
34
38
  constructor(client_id: string, client_secret: string, conf: Partial<FortytwoIntraClientConf>);
35
39
  private generateToken;
40
+ private isTokenValid;
41
+ private getAccessToken;
36
42
  private fetch;
37
43
  private reqHandler;
38
44
  private logSuccess;
@@ -62,6 +68,7 @@ export declare class FortytwoIntraClient {
62
68
  getAll<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "body"> & {
63
69
  schema: S;
64
70
  }): Promise<z.infer<S>>;
71
+ rawRequest<T = any, D = any>(config: AxiosRequestConfig<D>, token?: userToken): Promise<AxiosResponse<T, D>>;
65
72
  URL(endpoint: string): URL;
66
73
  getOAuthUrl(options?: {
67
74
  redirect_uri?: string;
@@ -73,4 +80,3 @@ export declare class FortytwoIntraClient {
73
80
  exchangeOAuthCode(code: string, redirect_uri?: string): Promise<any>;
74
81
  tokenInfos(options?: Omit<inputOptions, "body" | "perPage" | "maxPages">): Promise<any>;
75
82
  }
76
- export { FortytwoIntraClientError, isFortytwoIntraClientError };
package/dist/index.js CHANGED
@@ -32,20 +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.isFortytwoIntraClientError = exports.FortytwoIntraClientError = exports.FortytwoIntraClient = void 0;
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 pagination_1 = require("./lib/pagination");
45
+ const zod_1 = __importDefault(require("zod"));
43
46
  const logs_1 = require("./lib/logs");
44
- const errors_1 = require("./lib/errors");
45
- Object.defineProperty(exports, "FortytwoIntraClientError", { enumerable: true, get: function () { return errors_1.FortytwoIntraClientError; } });
46
- Object.defineProperty(exports, "isFortytwoIntraClientError", { enumerable: true, get: function () { return errors_1.isFortytwoIntraClientError; } });
47
- const zod_1 = require("zod");
47
+ const pagination_1 = require("./lib/pagination");
48
+ const httpError_1 = require("./errors/httpError");
48
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);
49
54
  const defaultConf = {
50
55
  redirect_uri: null,
51
56
  base_url: "https://api.intra.42.fr/v2/",
@@ -75,7 +80,8 @@ class FortytwoIntraClient {
75
80
  maxRetry;
76
81
  logLine;
77
82
  errLogBody;
78
- access_token;
83
+ authorization;
84
+ tokenRequest = null;
79
85
  constructor(client_id, client_secret, conf) {
80
86
  this.client_id = client_id;
81
87
  this.client_secret = client_secret;
@@ -98,7 +104,7 @@ class FortytwoIntraClient {
98
104
  this.maxRetry = config.maxRetry;
99
105
  this.logLine = config.logLine;
100
106
  this.errLogBody = config.errLogBody;
101
- this.access_token = null;
107
+ this.authorization = null;
102
108
  }
103
109
  async generateToken() {
104
110
  const res = await this.axiosInstance.post(this.token_url, {
@@ -107,15 +113,31 @@ class FortytwoIntraClient {
107
113
  client_secret: this.client_secret,
108
114
  scope: this.scopes.join(" "),
109
115
  });
110
- return res.data.access_token;
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;
111
136
  }
112
137
  async fetch(url, options) {
113
138
  const { method, body, query } = options;
114
- if (!options.token && !this.access_token) {
115
- this.access_token = await this.generateToken();
116
- }
117
139
  // Attach access_token
118
- const accessToken = options.token ? options.token.access_token : this.access_token;
140
+ const accessToken = await this.getAccessToken(options.token);
119
141
  // Extract query parameters from URL and combine with options.query
120
142
  const urlParams = {};
121
143
  url.searchParams.forEach((value, key) => {
@@ -150,13 +172,13 @@ class FortytwoIntraClient {
150
172
  const status = err.response?.status;
151
173
  if (maxRetry > 0 && attempt < maxRetry && status && this.retryOn.includes(status)) {
152
174
  if (status === 401) {
153
- this.access_token = null;
175
+ this.authorization = null;
154
176
  }
155
177
  options.attempt++;
156
178
  return this.reqHandler(url, options);
157
179
  }
158
180
  else {
159
- throw new errors_1.FortytwoIntraClientError(err);
181
+ throw new httpError_1.FortytwoIntraClientHttpError(err);
160
182
  }
161
183
  }
162
184
  else {
@@ -191,7 +213,7 @@ class FortytwoIntraClient {
191
213
  return schema.parse(data);
192
214
  }
193
215
  catch (err) {
194
- if (err instanceof zod_1.z.ZodError) {
216
+ if (err instanceof zod_1.default.ZodError) {
195
217
  throw new validationError_1.FortytwoIntraClientValidationError(err, data);
196
218
  }
197
219
  throw err;
@@ -317,6 +339,17 @@ class FortytwoIntraClient {
317
339
  const allData = [...firstPage.data, ...otherPages.flatMap((res) => res.data)];
318
340
  return this.validate(allData, options.schema);
319
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
+ }
320
353
  URL(endpoint) {
321
354
  return new URL(endpoint, this.base_url);
322
355
  }
@@ -0,0 +1,62 @@
1
+ import { AxiosRequestConfig, AxiosResponse } from "axios";
2
+ import z from "zod";
3
+ import { inputOptions } from "../types";
4
+ export * from "../errors/httpError";
5
+ export * from "../errors/validationError";
6
+ export interface FortytwoIntraClientConf {
7
+ base_url: string | undefined;
8
+ token_url: string;
9
+ maxRetry: number;
10
+ logLine: boolean;
11
+ errLogBody: boolean;
12
+ }
13
+ type Credentials = {
14
+ client_id: string;
15
+ client_secret: string;
16
+ username: string;
17
+ password: string;
18
+ };
19
+ export declare class FortytwoIntraV3Client {
20
+ private credentials;
21
+ private base_url;
22
+ private token_url;
23
+ private axiosInstance;
24
+ private retryOn;
25
+ private maxRetry;
26
+ private logLine;
27
+ private errLogBody;
28
+ private authorization;
29
+ private tokenRequest;
30
+ constructor(credentials: Credentials, conf?: Partial<FortytwoIntraClientConf>);
31
+ private generateToken;
32
+ private isTokenValid;
33
+ private isRefreshTokenValid;
34
+ private getAccessToken;
35
+ private fetch;
36
+ private reqHandler;
37
+ private logSuccess;
38
+ private logError;
39
+ private validate;
40
+ get(endpoint: URL | string, options?: Omit<inputOptions, "body" | "perPage" | "maxPages" | "token">): Promise<any>;
41
+ get<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "body" | "perPage" | "maxPages" | "token"> & {
42
+ schema: S;
43
+ }): Promise<z.infer<S>>;
44
+ post(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "maxPages">): Promise<any>;
45
+ post<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "maxPages"> & {
46
+ schema: S;
47
+ }): Promise<z.infer<S>>;
48
+ put(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "maxPages">): Promise<any>;
49
+ put<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "maxPages"> & {
50
+ schema: S;
51
+ }): Promise<z.infer<S>>;
52
+ patch(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "maxPages">): Promise<any>;
53
+ patch<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "maxPages"> & {
54
+ schema: S;
55
+ }): Promise<z.infer<S>>;
56
+ delete(endpoint: URL | string, options?: Omit<inputOptions, "perPage" | "maxPages">): Promise<any>;
57
+ delete<S extends z.ZodType>(endpoint: URL | string, options: Omit<inputOptions, "perPage" | "maxPages"> & {
58
+ schema: S;
59
+ }): Promise<z.infer<S>>;
60
+ rawRequest<T = any, D = any>(config: AxiosRequestConfig<D>): Promise<AxiosResponse<T, D>>;
61
+ URL(endpoint: string): URL;
62
+ }
@@ -0,0 +1,285 @@
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
+ tokenRequest = null;
69
+ constructor(credentials, conf = {}) {
70
+ this.credentials = credentials;
71
+ const config = { ...defaultConf, ...conf };
72
+ this.base_url = config.base_url;
73
+ this.token_url = config.token_url;
74
+ this.axiosInstance = axios_1.default.create();
75
+ this.retryOn = [401, 429, 500];
76
+ this.maxRetry = config.maxRetry;
77
+ this.logLine = config.logLine;
78
+ this.errLogBody = config.errLogBody;
79
+ this.authorization = null;
80
+ }
81
+ async generateToken() {
82
+ const data = this.authorization && this.isRefreshTokenValid()
83
+ ? new URLSearchParams({
84
+ grant_type: "refresh_token",
85
+ refresh_token: this.authorization.refresh_token,
86
+ })
87
+ : new URLSearchParams({
88
+ grant_type: "password",
89
+ username: this.credentials.username,
90
+ password: this.credentials.password,
91
+ });
92
+ const res = await this.axiosInstance.post(this.token_url, data, {
93
+ headers: {
94
+ Authorization: `Basic ${Buffer.from(`${this.credentials.client_id}:${this.credentials.client_secret}`).toString("base64")}`,
95
+ "Content-Type": "application/x-www-form-urlencoded",
96
+ },
97
+ });
98
+ return schemas_1.tokenSchema.parse(res.data);
99
+ }
100
+ isTokenValid() {
101
+ return this.authorization !== null && this.authorization.expires_at - 30000 > Date.now();
102
+ }
103
+ isRefreshTokenValid() {
104
+ return (this.authorization !== null && this.authorization.refresh_expires_at - 30000 > Date.now());
105
+ }
106
+ async getAccessToken() {
107
+ if (!this.isTokenValid()) {
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;
113
+ }
114
+ return this.authorization.access_token;
115
+ }
116
+ async fetch(url, options) {
117
+ const { method, body, query } = options;
118
+ // Attach access_token
119
+ const accessToken = await this.getAccessToken();
120
+ // Extract query parameters from URL and combine with options.query
121
+ const urlParams = {};
122
+ url.searchParams.forEach((value, key) => {
123
+ urlParams[key] = value;
124
+ });
125
+ // Combine URL params with query params (query params take precedence)
126
+ const combinedParams = { ...urlParams, ...query };
127
+ // Create clean URL without query parameters
128
+ const cleanUrl = new URL(url);
129
+ cleanUrl.search = "";
130
+ return this.axiosInstance.request({
131
+ method: method.toLowerCase(),
132
+ url: cleanUrl.toString(),
133
+ headers: {
134
+ Authorization: `Bearer ${accessToken}`,
135
+ },
136
+ params: combinedParams,
137
+ data: body ? body : undefined,
138
+ });
139
+ }
140
+ async reqHandler(url, options) {
141
+ try {
142
+ const res = await this.fetch(url, options);
143
+ this.logSuccess(res, options);
144
+ return res;
145
+ }
146
+ catch (err) {
147
+ if ((0, axios_1.isAxiosError)(err)) {
148
+ this.logError(err, options);
149
+ const { attempt, maxRetry } = options;
150
+ const status = err.response?.status;
151
+ if (maxRetry > 0 && attempt < maxRetry && status && this.retryOn.includes(status)) {
152
+ if (status === 401) {
153
+ this.authorization = null;
154
+ }
155
+ options.attempt++;
156
+ return this.reqHandler(url, options);
157
+ }
158
+ else {
159
+ throw new httpError_1.FortytwoIntraClientHttpError(err);
160
+ }
161
+ }
162
+ else {
163
+ throw err;
164
+ }
165
+ }
166
+ }
167
+ logSuccess(res, options) {
168
+ if (!options.logLine)
169
+ return;
170
+ const line = (0, logs_1.getLogLine)(res, options);
171
+ console.log(line);
172
+ }
173
+ logError(err, options) {
174
+ if (!options.logLine)
175
+ return;
176
+ const line = (0, logs_1.getErrorLogLine)(err, options);
177
+ const body = err.response?.data;
178
+ const logBody = options.errLogBody && body && Object.keys(body).length;
179
+ try {
180
+ console.log(line, logBody ? JSON.stringify(body, null, 2) : "");
181
+ }
182
+ catch {
183
+ console.log(line, logBody ? body : "");
184
+ }
185
+ }
186
+ validate(data, schema) {
187
+ if (!schema) {
188
+ return data;
189
+ }
190
+ try {
191
+ return schema.parse(data);
192
+ }
193
+ catch (err) {
194
+ if (err instanceof zod_1.default.ZodError) {
195
+ throw new validationError_1.FortytwoIntraClientValidationError(err, data);
196
+ }
197
+ throw err;
198
+ }
199
+ }
200
+ async get(endpoint, options = {}) {
201
+ if (endpoint instanceof URL === false) {
202
+ endpoint = new URL(endpoint, this.base_url);
203
+ }
204
+ const res = await this.reqHandler(endpoint, {
205
+ method: "GET",
206
+ attempt: 0,
207
+ maxRetry: this.maxRetry,
208
+ logLine: this.logLine,
209
+ errLogBody: this.errLogBody,
210
+ ...options,
211
+ });
212
+ return this.validate(res.data, options.schema);
213
+ }
214
+ async post(endpoint, options = {}) {
215
+ if (endpoint instanceof URL === false) {
216
+ endpoint = new URL(endpoint, this.base_url);
217
+ }
218
+ const res = await this.reqHandler(endpoint, {
219
+ method: "POST",
220
+ attempt: 0,
221
+ maxRetry: this.maxRetry,
222
+ logLine: this.logLine,
223
+ errLogBody: this.errLogBody,
224
+ ...options,
225
+ });
226
+ return this.validate(res.data, options.schema);
227
+ }
228
+ async put(endpoint, options = {}) {
229
+ if (endpoint instanceof URL === false) {
230
+ endpoint = new URL(endpoint, this.base_url);
231
+ }
232
+ const res = await this.reqHandler(endpoint, {
233
+ method: "PUT",
234
+ attempt: 0,
235
+ maxRetry: this.maxRetry,
236
+ logLine: this.logLine,
237
+ errLogBody: this.errLogBody,
238
+ ...options,
239
+ });
240
+ return this.validate(res.data, options.schema);
241
+ }
242
+ async patch(endpoint, options = {}) {
243
+ if (endpoint instanceof URL === false) {
244
+ endpoint = new URL(endpoint, this.base_url);
245
+ }
246
+ const res = await this.reqHandler(endpoint, {
247
+ method: "PATCH",
248
+ attempt: 0,
249
+ maxRetry: this.maxRetry,
250
+ logLine: this.logLine,
251
+ errLogBody: this.errLogBody,
252
+ ...options,
253
+ });
254
+ return this.validate(res.data, options.schema);
255
+ }
256
+ async delete(endpoint, options = {}) {
257
+ if (endpoint instanceof URL === false) {
258
+ endpoint = new URL(endpoint, this.base_url);
259
+ }
260
+ const res = await this.reqHandler(endpoint, {
261
+ method: "DELETE",
262
+ attempt: 0,
263
+ maxRetry: this.maxRetry,
264
+ logLine: this.logLine,
265
+ errLogBody: this.errLogBody,
266
+ ...options,
267
+ });
268
+ return this.validate(res.data, options.schema);
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
+ }
281
+ URL(endpoint) {
282
+ return new URL(endpoint, this.base_url);
283
+ }
284
+ }
285
+ 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ibertran/fortytwo-intra-client",
3
- "version": "4.1.0",
3
+ "version": "5.1.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "author": {