@ahoo-wang/fetcher-cosec 3.0.3 → 3.0.6
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 +125 -0
- package/README.zh-CN.md +125 -0
- package/dist/cosecConfigurer.d.ts +169 -0
- package/dist/cosecConfigurer.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +312 -218
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/resourceAttributionRequestInterceptor.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.es.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { REQUEST_BODY_INTERCEPTOR_ORDER as
|
|
2
|
-
import { nanoid as
|
|
1
|
+
import { REQUEST_BODY_INTERCEPTOR_ORDER as w, FetcherError as D, ResultExtractors as y } from "@ahoo-wang/fetcher";
|
|
2
|
+
import { nanoid as U } from "nanoid";
|
|
3
3
|
import { KeyStorage as f } from "@ahoo-wang/fetcher-storage";
|
|
4
4
|
import { BroadcastTypedEventBus as O, SerialTypedEventBus as _ } from "@ahoo-wang/fetcher-eventbus";
|
|
5
5
|
const a = class a {
|
|
6
6
|
};
|
|
7
7
|
a.DEVICE_ID = "CoSec-Device-Id", a.APP_ID = "CoSec-App-Id", a.AUTHORIZATION = "Authorization", a.REQUEST_ID = "CoSec-Request-Id";
|
|
8
8
|
let n = a;
|
|
9
|
-
const
|
|
9
|
+
const u = class u {
|
|
10
10
|
};
|
|
11
|
-
|
|
12
|
-
let h =
|
|
13
|
-
const
|
|
11
|
+
u.UNAUTHORIZED = 401, u.FORBIDDEN = 403;
|
|
12
|
+
let h = u;
|
|
13
|
+
const ne = {
|
|
14
14
|
ALLOW: { authorized: !0, reason: "Allow" },
|
|
15
15
|
EXPLICIT_DENY: { authorized: !1, reason: "Explicit Deny" },
|
|
16
16
|
IMPLICIT_DENY: { authorized: !1, reason: "Implicit Deny" },
|
|
@@ -24,17 +24,17 @@ class C {
|
|
|
24
24
|
* @returns A unique request ID
|
|
25
25
|
*/
|
|
26
26
|
generateId() {
|
|
27
|
-
return
|
|
27
|
+
return U();
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
const N = new C(), m = "CoSecRequestInterceptor",
|
|
31
|
-
class
|
|
30
|
+
const N = new C(), m = "CoSecRequestInterceptor", g = w + 1e3, k = "Ignore-Refresh-Token";
|
|
31
|
+
class b {
|
|
32
32
|
/**
|
|
33
33
|
* Creates a new CoSecRequestInterceptor instance.
|
|
34
34
|
* @param options - The CoSec configuration options including appId, deviceIdStorage, and tokenManager
|
|
35
35
|
*/
|
|
36
36
|
constructor(e) {
|
|
37
|
-
this.name = m, this.order =
|
|
37
|
+
this.name = m, this.order = g, this.options = e;
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
40
|
* Intercept requests to add CoSec authentication headers.
|
|
@@ -59,19 +59,19 @@ class G {
|
|
|
59
59
|
* It will attempt to refresh the token before adding the Authorization header to the request.
|
|
60
60
|
*/
|
|
61
61
|
async intercept(e) {
|
|
62
|
-
const t = N.generateId(),
|
|
63
|
-
o[n.APP_ID] = this.options.appId, o[n.DEVICE_ID] =
|
|
62
|
+
const t = N.generateId(), s = this.options.deviceIdStorage.getOrCreate(), o = e.ensureRequestHeaders();
|
|
63
|
+
o[n.APP_ID] = this.options.appId, o[n.DEVICE_ID] = s, o[n.REQUEST_ID] = t;
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
const
|
|
67
|
-
class
|
|
66
|
+
const M = "AuthorizationRequestInterceptor", z = g + 1e3;
|
|
67
|
+
class v {
|
|
68
68
|
/**
|
|
69
69
|
* Creates an AuthorizationRequestInterceptor instance.
|
|
70
70
|
*
|
|
71
71
|
* @param options - Configuration options containing the token manager
|
|
72
72
|
*/
|
|
73
73
|
constructor(e) {
|
|
74
|
-
this.options = e, this.name =
|
|
74
|
+
this.options = e, this.name = M, this.order = z;
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
77
|
* Intercepts the request exchange to add authorization headers.
|
|
@@ -86,18 +86,18 @@ class V {
|
|
|
86
86
|
*/
|
|
87
87
|
async intercept(e) {
|
|
88
88
|
let t = this.options.tokenManager.currentToken;
|
|
89
|
-
const
|
|
90
|
-
!t ||
|
|
89
|
+
const s = e.ensureRequestHeaders();
|
|
90
|
+
!t || s[n.AUTHORIZATION] || (!e.attributes.has(k) && t.isRefreshNeeded && t.isRefreshable && await this.options.tokenManager.refresh(), t = this.options.tokenManager.currentToken, t && (s[n.AUTHORIZATION] = `Bearer ${t.access.token}`));
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
-
const
|
|
94
|
-
class
|
|
93
|
+
const q = "AuthorizationResponseInterceptor", F = Number.MIN_SAFE_INTEGER + 1e3;
|
|
94
|
+
class B {
|
|
95
95
|
/**
|
|
96
96
|
* Creates a new AuthorizationResponseInterceptor instance.
|
|
97
97
|
* @param options - The CoSec configuration options including token storage and refresher
|
|
98
98
|
*/
|
|
99
99
|
constructor(e) {
|
|
100
|
-
this.options = e, this.name =
|
|
100
|
+
this.options = e, this.name = q, this.order = F;
|
|
101
101
|
}
|
|
102
102
|
/**
|
|
103
103
|
* Intercepts the response and handles unauthorized responses by refreshing tokens.
|
|
@@ -108,16 +108,16 @@ class X {
|
|
|
108
108
|
if (t && t.status === h.UNAUTHORIZED && this.options.tokenManager.isRefreshable)
|
|
109
109
|
try {
|
|
110
110
|
await this.options.tokenManager.refresh(), await e.fetcher.interceptors.exchange(e);
|
|
111
|
-
} catch (
|
|
112
|
-
throw this.options.tokenManager.tokenStorage.remove(),
|
|
111
|
+
} catch (s) {
|
|
112
|
+
throw this.options.tokenManager.tokenStorage.remove(), s;
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
const
|
|
117
|
-
class
|
|
116
|
+
const T = "cosec-device-id";
|
|
117
|
+
class K extends f {
|
|
118
118
|
constructor(e = {
|
|
119
|
-
key:
|
|
120
|
-
eventBus: new O({ delegate: new _(
|
|
119
|
+
key: T,
|
|
120
|
+
eventBus: new O({ delegate: new _(T) })
|
|
121
121
|
}) {
|
|
122
122
|
super(e);
|
|
123
123
|
}
|
|
@@ -139,99 +139,74 @@ class W extends f {
|
|
|
139
139
|
return e || (e = this.generateDeviceId(), this.set(e)), e;
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (typeof s != "string")
|
|
145
|
-
return null;
|
|
146
|
-
const e = s.split(".");
|
|
147
|
-
if (e.length !== 3)
|
|
148
|
-
return null;
|
|
149
|
-
const r = e[1].replace(/-/g, "+").replace(/_/g, "/"), o = r.padEnd(
|
|
150
|
-
r.length + (4 - r.length % 4) % 4,
|
|
151
|
-
"="
|
|
152
|
-
), c = decodeURIComponent(
|
|
153
|
-
atob(o).split("").map(function(i) {
|
|
154
|
-
return "%" + ("00" + i.charCodeAt(0).toString(16)).slice(-2);
|
|
155
|
-
}).join("")
|
|
156
|
-
);
|
|
157
|
-
return JSON.parse(c);
|
|
158
|
-
} catch (e) {
|
|
159
|
-
return console.error("Failed to parse JWT token", e), null;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
function v(s, e = 0) {
|
|
163
|
-
const t = typeof s == "string" ? k(s) : s;
|
|
164
|
-
if (!t)
|
|
165
|
-
return !0;
|
|
166
|
-
const r = t.exp;
|
|
167
|
-
return r ? Date.now() / 1e3 > r - e : !1;
|
|
168
|
-
}
|
|
169
|
-
class p {
|
|
170
|
-
/**
|
|
171
|
-
* Creates a new JwtToken instance
|
|
172
|
-
*/
|
|
173
|
-
constructor(e, t = 0) {
|
|
174
|
-
this.token = e, this.earlyPeriod = t, this.payload = k(e);
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Checks if the token is expired
|
|
178
|
-
* @returns true if the token is expired, false otherwise
|
|
179
|
-
*/
|
|
180
|
-
get isExpired() {
|
|
181
|
-
return this.payload ? v(this.payload, this.earlyPeriod) : !0;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
class g {
|
|
185
|
-
/**
|
|
186
|
-
* Creates a new JwtCompositeToken instance
|
|
187
|
-
*/
|
|
188
|
-
constructor(e, t = 0) {
|
|
189
|
-
this.token = e, this.earlyPeriod = t, this.access = new p(e.accessToken, t), this.refresh = new p(e.refreshToken, t);
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Checks if the access token needs to be refreshed
|
|
193
|
-
* @returns true if the access token is expired, false otherwise
|
|
194
|
-
*/
|
|
195
|
-
get isRefreshNeeded() {
|
|
196
|
-
return this.access.isExpired;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Checks if the refresh token is still valid and can be used to refresh the access token
|
|
200
|
-
* @returns true if the refresh token is not expired, false otherwise
|
|
201
|
-
*/
|
|
202
|
-
get isRefreshable() {
|
|
203
|
-
return !this.refresh.isExpired;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
class y {
|
|
207
|
-
constructor(e = 0) {
|
|
208
|
-
this.earlyPeriod = e;
|
|
209
|
-
}
|
|
142
|
+
const H = "ForbiddenErrorInterceptor", Z = 0;
|
|
143
|
+
class J {
|
|
210
144
|
/**
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* @
|
|
145
|
+
* Creates a new ForbiddenErrorInterceptor instance.
|
|
146
|
+
*
|
|
147
|
+
* @param options - Configuration options containing the callback to handle forbidden responses.
|
|
148
|
+
* Must include the `onForbidden` callback function.
|
|
149
|
+
*
|
|
150
|
+
* @throws Will throw an error if options are not provided or if `onForbidden` callback is missing.
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* const interceptor = new ForbiddenErrorInterceptor({
|
|
155
|
+
* onForbidden: async (exchange) => {
|
|
156
|
+
* // Handle forbidden access
|
|
157
|
+
* }
|
|
158
|
+
* });
|
|
159
|
+
* ```
|
|
214
160
|
*/
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return new g(t, this.earlyPeriod);
|
|
161
|
+
constructor(e) {
|
|
162
|
+
this.options = e, this.name = H, this.order = Z;
|
|
218
163
|
}
|
|
219
164
|
/**
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
165
|
+
* Intercepts fetch exchanges to detect and handle forbidden (403) responses.
|
|
166
|
+
*
|
|
167
|
+
* This method examines the response status code and invokes the configured `onForbidden`
|
|
168
|
+
* callback when a 403 Forbidden response is detected. The method is asynchronous to
|
|
169
|
+
* allow the callback to perform async operations like API calls, redirects, or UI updates.
|
|
170
|
+
*
|
|
171
|
+
* The interceptor only acts on responses with status code 403. Other error codes are
|
|
172
|
+
* ignored and passed through to other error interceptors in the chain.
|
|
173
|
+
*
|
|
174
|
+
* @param exchange - The fetch exchange containing request, response, and error information
|
|
175
|
+
* to be inspected for forbidden status codes. The exchange object provides
|
|
176
|
+
* access to the original request, response details, and any error information.
|
|
177
|
+
* @returns Promise that resolves when the forbidden error handling is complete.
|
|
178
|
+
* Returns void - the method does not modify the exchange or return values.
|
|
179
|
+
*
|
|
180
|
+
* @remarks
|
|
181
|
+
* - Only responds to HTTP 403 status codes
|
|
182
|
+
* - Does not retry requests or modify responses
|
|
183
|
+
* - Allows async operations in the callback
|
|
184
|
+
* - Does not throw exceptions - delegates all error handling to the callback
|
|
185
|
+
* - Safe to use with other error interceptors
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* // The intercept method is called automatically by the fetcher
|
|
190
|
+
* // No manual invocation needed - this is for documentation purposes
|
|
191
|
+
* const interceptor = new ForbiddenErrorInterceptor({
|
|
192
|
+
* onForbidden: async (exchange) => {
|
|
193
|
+
* // exchange.response.status === 403
|
|
194
|
+
* // exchange.request contains original request details
|
|
195
|
+
* await handleForbiddenAccess(exchange);
|
|
196
|
+
* }
|
|
197
|
+
* });
|
|
198
|
+
* ```
|
|
223
199
|
*/
|
|
224
|
-
|
|
225
|
-
|
|
200
|
+
async intercept(e) {
|
|
201
|
+
e.response?.status === h.FORBIDDEN && await this.options.onForbidden(e);
|
|
226
202
|
}
|
|
227
203
|
}
|
|
228
|
-
|
|
229
|
-
class u extends S {
|
|
204
|
+
class E extends D {
|
|
230
205
|
constructor(e, t) {
|
|
231
|
-
super("Refresh token failed.", t), this.token = e, this.name = "RefreshTokenError", Object.setPrototypeOf(this,
|
|
206
|
+
super("Refresh token failed.", t), this.token = e, this.name = "RefreshTokenError", Object.setPrototypeOf(this, E.prototype);
|
|
232
207
|
}
|
|
233
208
|
}
|
|
234
|
-
class
|
|
209
|
+
class Q {
|
|
235
210
|
/**
|
|
236
211
|
* Creates a new JwtTokenManager instance
|
|
237
212
|
* @param tokenStorage The storage used to persist tokens
|
|
@@ -259,7 +234,7 @@ class ee {
|
|
|
259
234
|
return this.refreshInProgress ? this.refreshInProgress : (this.refreshInProgress = this.tokenRefresher.refresh(e.token).then((t) => {
|
|
260
235
|
this.tokenStorage.setCompositeToken(t);
|
|
261
236
|
}).catch((t) => {
|
|
262
|
-
throw this.tokenStorage.remove(), new
|
|
237
|
+
throw this.tokenStorage.remove(), new E(e, t);
|
|
263
238
|
}).finally(() => {
|
|
264
239
|
this.refreshInProgress = void 0;
|
|
265
240
|
}), this.refreshInProgress);
|
|
@@ -279,18 +254,18 @@ class ee {
|
|
|
279
254
|
return this.currentToken ? this.currentToken.isRefreshable : !1;
|
|
280
255
|
}
|
|
281
256
|
}
|
|
282
|
-
const
|
|
283
|
-
class
|
|
257
|
+
const x = "tenantId", Y = "ownerId", L = "ResourceAttributionRequestInterceptor", j = Number.MAX_SAFE_INTEGER;
|
|
258
|
+
class G {
|
|
284
259
|
/**
|
|
285
260
|
* Creates a new ResourceAttributionRequestInterceptor
|
|
286
261
|
* @param options - Configuration options for resource attribution including tenantId, ownerId and tokenStorage
|
|
287
262
|
*/
|
|
288
263
|
constructor({
|
|
289
|
-
tenantId: e =
|
|
290
|
-
ownerId: t =
|
|
291
|
-
tokenStorage:
|
|
264
|
+
tenantId: e = x,
|
|
265
|
+
ownerId: t = Y,
|
|
266
|
+
tokenStorage: s
|
|
292
267
|
}) {
|
|
293
|
-
this.name =
|
|
268
|
+
this.name = L, this.order = j, this.tenantIdPathKey = e, this.ownerIdPathKey = t, this.tokenStorage = s;
|
|
294
269
|
}
|
|
295
270
|
/**
|
|
296
271
|
* Intercepts outgoing requests and automatically adds tenant and owner ID path parameters
|
|
@@ -301,69 +276,127 @@ class te {
|
|
|
301
276
|
const t = this.tokenStorage.get();
|
|
302
277
|
if (!t)
|
|
303
278
|
return;
|
|
304
|
-
const
|
|
305
|
-
if (!
|
|
279
|
+
const s = t.access.payload;
|
|
280
|
+
if (!s || !s.tenantId && !s.sub)
|
|
306
281
|
return;
|
|
307
282
|
const o = e.fetcher.urlBuilder.urlTemplateResolver.extractPathParams(
|
|
308
283
|
e.request.url
|
|
309
|
-
), c = this.tenantIdPathKey, i = e.ensureRequestUrlParams().path,
|
|
310
|
-
|
|
311
|
-
const R = this.ownerIdPathKey,
|
|
312
|
-
|
|
284
|
+
), c = this.tenantIdPathKey, i = e.ensureRequestUrlParams().path, d = s.tenantId;
|
|
285
|
+
d && o.includes(c) && !i[c] && (i[c] = d);
|
|
286
|
+
const R = this.ownerIdPathKey, I = s.sub;
|
|
287
|
+
I && o.includes(R) && !i[R] && (i[R] = I);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function S(r) {
|
|
291
|
+
try {
|
|
292
|
+
if (typeof r != "string")
|
|
293
|
+
return null;
|
|
294
|
+
const e = r.split(".");
|
|
295
|
+
if (e.length !== 3)
|
|
296
|
+
return null;
|
|
297
|
+
const s = e[1].replace(/-/g, "+").replace(/_/g, "/"), o = s.padEnd(
|
|
298
|
+
s.length + (4 - s.length % 4) % 4,
|
|
299
|
+
"="
|
|
300
|
+
), c = decodeURIComponent(
|
|
301
|
+
atob(o).split("").map(function(i) {
|
|
302
|
+
return "%" + ("00" + i.charCodeAt(0).toString(16)).slice(-2);
|
|
303
|
+
}).join("")
|
|
304
|
+
);
|
|
305
|
+
return JSON.parse(c);
|
|
306
|
+
} catch (e) {
|
|
307
|
+
return console.error("Failed to parse JWT token", e), null;
|
|
313
308
|
}
|
|
314
309
|
}
|
|
315
|
-
|
|
310
|
+
function V(r, e = 0) {
|
|
311
|
+
const t = typeof r == "string" ? S(r) : r;
|
|
312
|
+
if (!t)
|
|
313
|
+
return !0;
|
|
314
|
+
const s = t.exp;
|
|
315
|
+
return s ? Date.now() / 1e3 > s - e : !1;
|
|
316
|
+
}
|
|
317
|
+
class p {
|
|
316
318
|
/**
|
|
317
|
-
* Creates a new instance
|
|
318
|
-
*
|
|
319
|
-
* @param options The configuration options for the token refresher including fetcher and endpoint
|
|
319
|
+
* Creates a new JwtToken instance
|
|
320
320
|
*/
|
|
321
|
-
constructor(e) {
|
|
322
|
-
this.
|
|
321
|
+
constructor(e, t = 0) {
|
|
322
|
+
this.token = e, this.earlyPeriod = t, this.payload = S(e);
|
|
323
323
|
}
|
|
324
324
|
/**
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
* @param token The token to refresh
|
|
328
|
-
* @returns A Promise that resolves to a new CompositeToken
|
|
325
|
+
* Checks if the token is expired
|
|
326
|
+
* @returns true if the token is expired, false otherwise
|
|
329
327
|
*/
|
|
330
|
-
|
|
331
|
-
return this.
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
328
|
+
get isExpired() {
|
|
329
|
+
return this.payload ? V(this.payload, this.earlyPeriod) : !0;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
class A {
|
|
333
|
+
/**
|
|
334
|
+
* Creates a new JwtCompositeToken instance
|
|
335
|
+
*/
|
|
336
|
+
constructor(e, t = 0) {
|
|
337
|
+
this.token = e, this.earlyPeriod = t, this.access = new p(e.accessToken, t), this.refresh = new p(e.refreshToken, t);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Checks if the access token needs to be refreshed
|
|
341
|
+
* @returns true if the access token is expired, false otherwise
|
|
342
|
+
*/
|
|
343
|
+
get isRefreshNeeded() {
|
|
344
|
+
return this.access.isExpired;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Checks if the refresh token is still valid and can be used to refresh the access token
|
|
348
|
+
* @returns true if the refresh token is not expired, false otherwise
|
|
349
|
+
*/
|
|
350
|
+
get isRefreshable() {
|
|
351
|
+
return !this.refresh.isExpired;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
class P {
|
|
355
|
+
constructor(e = 0) {
|
|
356
|
+
this.earlyPeriod = e;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Deserializes a JSON string to a JwtCompositeToken
|
|
360
|
+
* @param value The JSON string representation of a composite token
|
|
361
|
+
* @returns A JwtCompositeToken instance
|
|
362
|
+
*/
|
|
363
|
+
deserialize(e) {
|
|
364
|
+
const t = JSON.parse(e);
|
|
365
|
+
return new A(t, this.earlyPeriod);
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Serializes a JwtCompositeToken to a JSON string
|
|
369
|
+
* @param value The JwtCompositeToken to serialize
|
|
370
|
+
* @returns A JSON string representation of the composite token
|
|
371
|
+
*/
|
|
372
|
+
serialize(e) {
|
|
373
|
+
return JSON.stringify(e.token);
|
|
341
374
|
}
|
|
342
375
|
}
|
|
343
|
-
const l = "cosec-token";
|
|
344
|
-
class
|
|
376
|
+
const ie = new P(), l = "cosec-token";
|
|
377
|
+
class W extends f {
|
|
345
378
|
constructor(e = {
|
|
346
379
|
key: l,
|
|
347
380
|
eventBus: new O({ delegate: new _(l) })
|
|
348
381
|
}) {
|
|
349
382
|
super({
|
|
350
|
-
serializer: new
|
|
383
|
+
serializer: new P(e.earlyPeriod),
|
|
351
384
|
...e
|
|
352
385
|
}), this.earlyPeriod = e.earlyPeriod ?? 0;
|
|
353
386
|
}
|
|
354
387
|
setCompositeToken(e) {
|
|
355
|
-
this.set(new
|
|
388
|
+
this.set(new A(e, this.earlyPeriod));
|
|
356
389
|
}
|
|
357
390
|
}
|
|
358
|
-
const
|
|
359
|
-
class
|
|
391
|
+
const X = "UnauthorizedErrorInterceptor", $ = 0;
|
|
392
|
+
class ee {
|
|
360
393
|
/**
|
|
361
394
|
* Creates a new UnauthorizedErrorInterceptor instance.
|
|
362
395
|
*
|
|
363
396
|
* @param options - Configuration options containing the callback to handle unauthorized responses
|
|
364
397
|
*/
|
|
365
398
|
constructor(e) {
|
|
366
|
-
this.options = e, this.name =
|
|
399
|
+
this.options = e, this.name = X, this.order = $;
|
|
367
400
|
}
|
|
368
401
|
/**
|
|
369
402
|
* Intercepts fetch exchanges to detect and handle unauthorized (401) responses
|
|
@@ -389,108 +422,169 @@ class oe {
|
|
|
389
422
|
* ```
|
|
390
423
|
*/
|
|
391
424
|
async intercept(e) {
|
|
392
|
-
(e.response?.status === h.UNAUTHORIZED || e.error instanceof
|
|
425
|
+
(e.response?.status === h.UNAUTHORIZED || e.error instanceof E) && await this.options.onUnauthorized(e);
|
|
393
426
|
}
|
|
394
427
|
}
|
|
395
|
-
|
|
396
|
-
class ne {
|
|
428
|
+
class ae {
|
|
397
429
|
/**
|
|
398
|
-
* Creates a new
|
|
430
|
+
* Creates a new CoSecConfigurer instance with the provided configuration.
|
|
399
431
|
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
432
|
+
* This constructor conditionally creates dependencies based on the configuration:
|
|
433
|
+
* - TokenStorage and DeviceIdStorage are always created (using defaults if not provided)
|
|
434
|
+
* - JwtTokenManager is only created if tokenRefresher is provided
|
|
402
435
|
*
|
|
403
|
-
* @
|
|
436
|
+
* @param config - CoSec configuration object
|
|
404
437
|
*
|
|
405
438
|
* @example
|
|
406
439
|
* ```typescript
|
|
407
|
-
*
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
*
|
|
440
|
+
* // Full setup with all dependencies
|
|
441
|
+
* const configurer = new CoSecConfigurer({
|
|
442
|
+
* appId: 'my-app',
|
|
443
|
+
* tokenRefresher: myTokenRefresher,
|
|
444
|
+
* });
|
|
445
|
+
*
|
|
446
|
+
* // Minimal setup with custom storage
|
|
447
|
+
* const configurer = new CoSecConfigurer({
|
|
448
|
+
* appId: 'my-app',
|
|
449
|
+
* tokenStorage: customStorage,
|
|
450
|
+
* deviceIdStorage: customDeviceStorage,
|
|
411
451
|
* });
|
|
412
452
|
* ```
|
|
413
453
|
*/
|
|
414
454
|
constructor(e) {
|
|
415
|
-
this.
|
|
455
|
+
this.config = e, this.tokenStorage = e.tokenStorage ?? new W(), this.deviceIdStorage = e.deviceIdStorage ?? new K(), e.tokenRefresher && (this.tokenManager = new Q(
|
|
456
|
+
this.tokenStorage,
|
|
457
|
+
e.tokenRefresher
|
|
458
|
+
));
|
|
416
459
|
}
|
|
417
460
|
/**
|
|
418
|
-
*
|
|
461
|
+
* Applies CoSec interceptors to the provided Fetcher instance.
|
|
419
462
|
*
|
|
420
|
-
* This method
|
|
421
|
-
* callback when a 403 Forbidden response is detected. The method is asynchronous to
|
|
422
|
-
* allow the callback to perform async operations like API calls, redirects, or UI updates.
|
|
463
|
+
* This method conditionally configures interceptors based on the provided configuration:
|
|
423
464
|
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
465
|
+
* Always added:
|
|
466
|
+
* 1. CoSecRequestInterceptor - Adds CoSec headers (appId, deviceId, requestId)
|
|
467
|
+
* 2. ResourceAttributionRequestInterceptor - Adds tenant/owner path parameters
|
|
426
468
|
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
* @returns Promise that resolves when the forbidden error handling is complete.
|
|
431
|
-
* Returns void - the method does not modify the exchange or return values.
|
|
469
|
+
* Only when `tokenRefresher` is provided:
|
|
470
|
+
* 3. AuthorizationRequestInterceptor - Adds Bearer token authentication
|
|
471
|
+
* 4. AuthorizationResponseInterceptor - Handles token refresh on 401 responses
|
|
432
472
|
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
*
|
|
436
|
-
*
|
|
437
|
-
*
|
|
438
|
-
* - Safe to use with other error interceptors
|
|
473
|
+
* Only when corresponding handlers are provided:
|
|
474
|
+
* 5. UnauthorizedErrorInterceptor - Handles 401 unauthorized errors
|
|
475
|
+
* 6. ForbiddenErrorInterceptor - Handles 403 forbidden errors
|
|
476
|
+
*
|
|
477
|
+
* @param fetcher - The Fetcher instance to configure
|
|
439
478
|
*
|
|
440
479
|
* @example
|
|
441
480
|
* ```typescript
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
* await handleForbiddenAccess(exchange);
|
|
449
|
-
* }
|
|
481
|
+
* const fetcher = new Fetcher({ baseURL: '/api' });
|
|
482
|
+
* const configurer = new CoSecConfigurer({
|
|
483
|
+
* appId: 'my-app',
|
|
484
|
+
* tokenRefresher: myTokenRefresher,
|
|
485
|
+
* onUnauthorized: handle401,
|
|
486
|
+
* onForbidden: handle403,
|
|
450
487
|
* });
|
|
488
|
+
*
|
|
489
|
+
* configurer.applyTo(fetcher);
|
|
490
|
+
* // Now fetcher has all CoSec interceptors configured
|
|
451
491
|
* ```
|
|
452
492
|
*/
|
|
453
|
-
|
|
454
|
-
e.
|
|
493
|
+
applyTo(e) {
|
|
494
|
+
e.interceptors.request.use(
|
|
495
|
+
new b({
|
|
496
|
+
appId: this.config.appId,
|
|
497
|
+
deviceIdStorage: this.deviceIdStorage
|
|
498
|
+
})
|
|
499
|
+
), e.interceptors.request.use(
|
|
500
|
+
new G({
|
|
501
|
+
tokenStorage: this.tokenStorage
|
|
502
|
+
})
|
|
503
|
+
), this.tokenManager && (e.interceptors.request.use(
|
|
504
|
+
new v({
|
|
505
|
+
tokenManager: this.tokenManager
|
|
506
|
+
})
|
|
507
|
+
), e.interceptors.response.use(
|
|
508
|
+
new B({
|
|
509
|
+
tokenManager: this.tokenManager
|
|
510
|
+
})
|
|
511
|
+
)), this.config.onUnauthorized && e.interceptors.error.use(
|
|
512
|
+
new ee({
|
|
513
|
+
onUnauthorized: this.config.onUnauthorized
|
|
514
|
+
})
|
|
515
|
+
), this.config.onForbidden && e.interceptors.error.use(
|
|
516
|
+
new J({
|
|
517
|
+
onForbidden: this.config.onForbidden
|
|
518
|
+
})
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
class ce {
|
|
523
|
+
/**
|
|
524
|
+
* Creates a new instance of CoSecTokenRefresher.
|
|
525
|
+
*
|
|
526
|
+
* @param options The configuration options for the token refresher including fetcher and endpoint
|
|
527
|
+
*/
|
|
528
|
+
constructor(e) {
|
|
529
|
+
this.options = e;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Refresh the given token and return a new CompositeToken.
|
|
533
|
+
*
|
|
534
|
+
* @param token The token to refresh
|
|
535
|
+
* @returns A Promise that resolves to a new CompositeToken
|
|
536
|
+
*/
|
|
537
|
+
refresh(e) {
|
|
538
|
+
return this.options.fetcher.post(
|
|
539
|
+
this.options.endpoint,
|
|
540
|
+
{
|
|
541
|
+
body: e
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
resultExtractor: y.Json,
|
|
545
|
+
attributes: /* @__PURE__ */ new Map([[k, !0]])
|
|
546
|
+
}
|
|
547
|
+
);
|
|
455
548
|
}
|
|
456
549
|
}
|
|
457
550
|
export {
|
|
458
|
-
|
|
551
|
+
M as AUTHORIZATION_REQUEST_INTERCEPTOR_NAME,
|
|
459
552
|
z as AUTHORIZATION_REQUEST_INTERCEPTOR_ORDER,
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
553
|
+
q as AUTHORIZATION_RESPONSE_INTERCEPTOR_NAME,
|
|
554
|
+
F as AUTHORIZATION_RESPONSE_INTERCEPTOR_ORDER,
|
|
555
|
+
v as AuthorizationRequestInterceptor,
|
|
556
|
+
B as AuthorizationResponseInterceptor,
|
|
557
|
+
ne as AuthorizeResults,
|
|
465
558
|
m as COSEC_REQUEST_INTERCEPTOR_NAME,
|
|
466
|
-
|
|
559
|
+
g as COSEC_REQUEST_INTERCEPTOR_ORDER,
|
|
560
|
+
ae as CoSecConfigurer,
|
|
467
561
|
n as CoSecHeaders,
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
562
|
+
b as CoSecRequestInterceptor,
|
|
563
|
+
ce as CoSecTokenRefresher,
|
|
564
|
+
T as DEFAULT_COSEC_DEVICE_ID_KEY,
|
|
471
565
|
l as DEFAULT_COSEC_TOKEN_KEY,
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
566
|
+
K as DeviceIdStorage,
|
|
567
|
+
H as FORBIDDEN_ERROR_INTERCEPTOR_NAME,
|
|
568
|
+
Z as FORBIDDEN_ERROR_INTERCEPTOR_ORDER,
|
|
569
|
+
J as ForbiddenErrorInterceptor,
|
|
570
|
+
k as IGNORE_REFRESH_TOKEN_ATTRIBUTE_KEY,
|
|
571
|
+
A as JwtCompositeToken,
|
|
572
|
+
P as JwtCompositeTokenSerializer,
|
|
479
573
|
p as JwtToken,
|
|
480
|
-
|
|
574
|
+
Q as JwtTokenManager,
|
|
481
575
|
C as NanoIdGenerator,
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
576
|
+
L as RESOURCE_ATTRIBUTION_REQUEST_INTERCEPTOR_NAME,
|
|
577
|
+
j as RESOURCE_ATTRIBUTION_REQUEST_INTERCEPTOR_ORDER,
|
|
578
|
+
E as RefreshTokenError,
|
|
579
|
+
G as ResourceAttributionRequestInterceptor,
|
|
486
580
|
h as ResponseCodes,
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
581
|
+
W as TokenStorage,
|
|
582
|
+
X as UNAUTHORIZED_ERROR_INTERCEPTOR_NAME,
|
|
583
|
+
$ as UNAUTHORIZED_ERROR_INTERCEPTOR_ORDER,
|
|
584
|
+
ee as UnauthorizedErrorInterceptor,
|
|
491
585
|
N as idGenerator,
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
586
|
+
V as isTokenExpired,
|
|
587
|
+
ie as jwtCompositeTokenSerializer,
|
|
588
|
+
S as parseJwtPayload
|
|
495
589
|
};
|
|
496
590
|
//# sourceMappingURL=index.es.js.map
|