@ahoo-wang/fetcher-cosec 0.8.2 → 0.8.3

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.
@@ -8,6 +8,12 @@ import { CoSecOptions } from './types';
8
8
  * - CoSec-App-Id: Application identifier
9
9
  * - Authorization: Bearer token
10
10
  * - CoSec-Request-Id: Unique request identifier for each request
11
+ *
12
+ * @remarks
13
+ * This interceptor runs after the basic request processing interceptors but before
14
+ * the actual HTTP request is made. The order is set to Number.MIN_SAFE_INTEGER + 1000
15
+ * to allow for other authentication or preprocessing interceptors to run earlier
16
+ * while ensuring it runs before FetchInterceptor.
11
17
  */
12
18
  export declare class CoSecRequestInterceptor implements Interceptor {
13
19
  name: string;
@@ -16,6 +22,15 @@ export declare class CoSecRequestInterceptor implements Interceptor {
16
22
  constructor(options: CoSecOptions);
17
23
  /**
18
24
  * Intercept requests to add CoSec authentication headers
25
+ *
26
+ * This method adds the following headers to each request:
27
+ * - CoSec-App-Id: The application identifier from the CoSec options
28
+ * - CoSec-Device-Id: A unique device identifier, either retrieved from storage or generated
29
+ * - CoSec-Request-Id: A unique identifier for this specific request
30
+ * - Authorization: Bearer token if available in token storage
31
+ *
32
+ * @param exchange - The fetch exchange containing the request to be processed
33
+ * @returns The modified exchange with CoSec authentication headers added
19
34
  */
20
35
  intercept(exchange: FetchExchange): FetchExchange;
21
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cosecRequestInterceptor.d.ts","sourceRoot":"","sources":["../src/cosecRequestInterceptor.ts"],"names":[],"mappings":"AAaA,OAAO,EAAkB,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAgB,YAAY,EAAE,MAAM,SAAS,CAAC;AAGrD;;;;;;;;GAQG;AACH,qBAAa,uBAAwB,YAAW,WAAW;IACzD,IAAI,SAA6B;IACjC,KAAK,SAA2B;IAChC,OAAO,CAAC,OAAO,CAAe;gBAElB,OAAO,EAAE,YAAY;IAIjC;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,aAAa;CAwBlD"}
1
+ {"version":3,"file":"cosecRequestInterceptor.d.ts","sourceRoot":"","sources":["../src/cosecRequestInterceptor.ts"],"names":[],"mappings":"AAaA,OAAO,EAAkB,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAgB,YAAY,EAAE,MAAM,SAAS,CAAC;AAGrD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,uBAAwB,YAAW,WAAW;IACzD,IAAI,SAA6B;IACjC,KAAK,SAAkC;IACvC,OAAO,CAAC,OAAO,CAAe;gBAElB,OAAO,EAAE,YAAY;IAIjC;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,aAAa;CAwBlD"}
@@ -4,12 +4,31 @@ import { FetchExchange, Interceptor } from '@ahoo-wang/fetcher';
4
4
  * CoSec Response Interceptor
5
5
  *
6
6
  * Handles automatic token refresh based on response codes
7
+ *
8
+ * @remarks
9
+ * This interceptor runs near the end of the response processing chain, just before
10
+ * the final response is returned. The order is set to Number.MAX_SAFE_INTEGER - 100
11
+ * to ensure it runs after most other response interceptors but still allows for
12
+ * final processing interceptors to run afterward. This order aligns with other
13
+ * response enhancement interceptors like EventStreamInterceptor.
7
14
  */
8
15
  export declare class CoSecResponseInterceptor implements Interceptor {
9
16
  name: string;
10
17
  order: number;
11
18
  private options;
12
19
  constructor(options: CoSecOptions);
20
+ /**
21
+ * Intercept responses to handle token refresh for unauthorized responses
22
+ *
23
+ * This method checks if a response has a 401 (UNAUTHORIZED) status code and attempts
24
+ * to refresh the authentication token if one is available. If token refresh is successful,
25
+ * the original request is retried with the new token. If token refresh fails, stored
26
+ * tokens are cleared and the original error is re-thrown.
27
+ *
28
+ * @param exchange - The fetch exchange containing the response to be processed
29
+ * @returns Promise<FetchExchange> The processed exchange, either with a refreshed token or original error
30
+ * @throws Error if token refresh fails or other errors occur during processing
31
+ */
13
32
  intercept(exchange: FetchExchange): Promise<FetchExchange>;
14
33
  }
15
34
  //# sourceMappingURL=cosecResponseInterceptor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cosecResponseInterceptor.d.ts","sourceRoot":"","sources":["../src/cosecResponseInterceptor.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAiB,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEhE;;;;GAIG;AACH,qBAAa,wBAAyB,YAAW,WAAW;IAC1D,IAAI,SAA8B;IAClC,KAAK,SAA2B;IAChC,OAAO,CAAC,OAAO,CAAe;gBAElB,OAAO,EAAE,YAAY;IAI3B,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;CAsBjE"}
1
+ {"version":3,"file":"cosecResponseInterceptor.d.ts","sourceRoot":"","sources":["../src/cosecResponseInterceptor.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAiB,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEhE;;;;;;;;;;;GAWG;AACH,qBAAa,wBAAyB,YAAW,WAAW;IAC1D,IAAI,SAA8B;IAClC,KAAK,SAAiC;IACtC,OAAO,CAAC,OAAO,CAAe;gBAElB,OAAO,EAAE,YAAY;IAIjC;;;;;;;;;;;OAWG;IACG,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;CAsBjE"}
package/dist/index.es.js CHANGED
@@ -23,10 +23,19 @@ class l {
23
23
  const I = new l();
24
24
  class T {
25
25
  constructor(e) {
26
- this.name = "CoSecRequestInterceptor", this.order = Number.MIN_SAFE_INTEGER, this.options = e;
26
+ this.name = "CoSecRequestInterceptor", this.order = Number.MIN_SAFE_INTEGER + 1e3, this.options = e;
27
27
  }
28
28
  /**
29
29
  * Intercept requests to add CoSec authentication headers
30
+ *
31
+ * This method adds the following headers to each request:
32
+ * - CoSec-App-Id: The application identifier from the CoSec options
33
+ * - CoSec-Device-Id: A unique device identifier, either retrieved from storage or generated
34
+ * - CoSec-Request-Id: A unique identifier for this specific request
35
+ * - Authorization: Bearer token if available in token storage
36
+ *
37
+ * @param exchange - The fetch exchange containing the request to be processed
38
+ * @returns The modified exchange with CoSec authentication headers added
30
39
  */
31
40
  intercept(e) {
32
41
  const r = I.generateId(), n = this.options.deviceIdStorage.getOrCreate(), s = this.options.tokenStorage.get(), a = {
@@ -40,8 +49,20 @@ class T {
40
49
  }
41
50
  class D {
42
51
  constructor(e) {
43
- this.name = "CoSecResponseInterceptor", this.order = Number.MAX_SAFE_INTEGER, this.options = e;
52
+ this.name = "CoSecResponseInterceptor", this.order = Number.MAX_SAFE_INTEGER - 100, this.options = e;
44
53
  }
54
+ /**
55
+ * Intercept responses to handle token refresh for unauthorized responses
56
+ *
57
+ * This method checks if a response has a 401 (UNAUTHORIZED) status code and attempts
58
+ * to refresh the authentication token if one is available. If token refresh is successful,
59
+ * the original request is retried with the new token. If token refresh fails, stored
60
+ * tokens are cleared and the original error is re-thrown.
61
+ *
62
+ * @param exchange - The fetch exchange containing the response to be processed
63
+ * @returns Promise<FetchExchange> The processed exchange, either with a refreshed token or original error
64
+ * @throws Error if token refresh fails or other errors occur during processing
65
+ */
45
66
  async intercept(e) {
46
67
  const r = e.response;
47
68
  if (!r || r.status !== c.UNAUTHORIZED)
package/dist/index.umd.js CHANGED
@@ -1 +1 @@
1
- (function(r,s){typeof exports=="object"&&typeof module<"u"?s(exports):typeof define=="function"&&define.amd?define(["exports"],s):(r=typeof globalThis<"u"?globalThis:r||self,s(r.FetcherCoSec={}))})(this,(function(r){"use strict";var s=(t=>(t.DEVICE_ID="CoSec-Device-Id",t.APP_ID="CoSec-App-Id",t.AUTHORIZATION="Authorization",t.REQUEST_ID="CoSec-Request-Id",t))(s||{}),c=(t=>(t[t.UNAUTHORIZED=401]="UNAUTHORIZED",t))(c||{});const g={ALLOW:{authorized:!0,reason:"Allow"},EXPLICIT_DENY:{authorized:!1,reason:"Explicit Deny"},IMPLICIT_DENY:{authorized:!1,reason:"Implicit Deny"},TOKEN_EXPIRED:{authorized:!1,reason:"Token Expired"},TOO_MANY_REQUESTS:{authorized:!1,reason:"Too Many Requests"}},T="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";let f=(t=21)=>{let e="",o=crypto.getRandomValues(new Uint8Array(t|=0));for(;t--;)e+=T[o[t]&63];return e};class d{generateId(){return f()}}const u=new d;class p{constructor(e){this.name="CoSecRequestInterceptor",this.order=Number.MIN_SAFE_INTEGER,this.options=e}intercept(e){const o=u.generateId(),i=this.options.deviceIdStorage.getOrCreate(),n=this.options.tokenStorage.get(),S={...e.request,headers:{...e.request.headers}},a=S.headers;return a[s.APP_ID]=this.options.appId,a[s.DEVICE_ID]=i,a[s.REQUEST_ID]=o,n&&(a[s.AUTHORIZATION]=`Bearer ${n.accessToken}`),e.request=S,e}}class D{constructor(e){this.name="CoSecResponseInterceptor",this.order=Number.MAX_SAFE_INTEGER,this.options=e}async intercept(e){const o=e.response;if(!o||o.status!==c.UNAUTHORIZED)return e;const i=this.options.tokenStorage.get();if(!i)return e;try{const n=await this.options.tokenRefresher.refresh(i);return this.options.tokenStorage.set(n),e.fetcher.request(e.url,e.request)}catch(n){throw this.options.tokenStorage.clear(),n}}}class h{constructor(){this.store=new Map}get length(){return this.store.size}clear(){this.store.clear()}getItem(e){const o=this.store.get(e);return o!==void 0?o:null}key(e){return Array.from(this.store.keys())[e]||null}removeItem(e){this.store.has(e)&&this.store.delete(e)}setItem(e,o){this.store.set(e,o)}}function I(){return typeof window<"u"&&window.localStorage?window.localStorage:new h}const l="cosec-device-id";class _{constructor(e=l,o=I()){this.deviceIdKey=e,this.storage=o}get(){return this.storage.getItem(this.deviceIdKey)}set(e){this.storage.setItem(this.deviceIdKey,e)}generateDeviceId(){return u.generateId()}getOrCreate(){let e=this.get();return e||(e=this.generateDeviceId(),this.set(e)),e}clear(){this.storage.removeItem(this.deviceIdKey)}}const E="cosec-token";class y{constructor(e=E,o=I()){this.tokenKey=e,this.storage=o}get(){const e=this.storage.getItem(this.tokenKey);return e?JSON.parse(e):null}set(e){const o=JSON.stringify(e);this.storage.setItem(this.tokenKey,o)}clear(){this.storage.removeItem(this.tokenKey)}}r.AuthorizeResults=g,r.CoSecHeaders=s,r.CoSecRequestInterceptor=p,r.CoSecResponseInterceptor=D,r.DEFAULT_COSEC_DEVICE_ID_KEY=l,r.DEFAULT_COSEC_TOKEN_KEY=E,r.DeviceIdStorage=_,r.InMemoryStorage=h,r.NanoIdGenerator=d,r.ResponseCodes=c,r.TokenStorage=y,r.getStorage=I,r.idGenerator=u,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(r,s){typeof exports=="object"&&typeof module<"u"?s(exports):typeof define=="function"&&define.amd?define(["exports"],s):(r=typeof globalThis<"u"?globalThis:r||self,s(r.FetcherCoSec={}))})(this,(function(r){"use strict";var s=(t=>(t.DEVICE_ID="CoSec-Device-Id",t.APP_ID="CoSec-App-Id",t.AUTHORIZATION="Authorization",t.REQUEST_ID="CoSec-Request-Id",t))(s||{}),c=(t=>(t[t.UNAUTHORIZED=401]="UNAUTHORIZED",t))(c||{});const g={ALLOW:{authorized:!0,reason:"Allow"},EXPLICIT_DENY:{authorized:!1,reason:"Explicit Deny"},IMPLICIT_DENY:{authorized:!1,reason:"Implicit Deny"},TOKEN_EXPIRED:{authorized:!1,reason:"Token Expired"},TOO_MANY_REQUESTS:{authorized:!1,reason:"Too Many Requests"}},T="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";let f=(t=21)=>{let e="",o=crypto.getRandomValues(new Uint8Array(t|=0));for(;t--;)e+=T[o[t]&63];return e};class d{generateId(){return f()}}const u=new d;class p{constructor(e){this.name="CoSecRequestInterceptor",this.order=Number.MIN_SAFE_INTEGER+1e3,this.options=e}intercept(e){const o=u.generateId(),i=this.options.deviceIdStorage.getOrCreate(),n=this.options.tokenStorage.get(),S={...e.request,headers:{...e.request.headers}},a=S.headers;return a[s.APP_ID]=this.options.appId,a[s.DEVICE_ID]=i,a[s.REQUEST_ID]=o,n&&(a[s.AUTHORIZATION]=`Bearer ${n.accessToken}`),e.request=S,e}}class D{constructor(e){this.name="CoSecResponseInterceptor",this.order=Number.MAX_SAFE_INTEGER-100,this.options=e}async intercept(e){const o=e.response;if(!o||o.status!==c.UNAUTHORIZED)return e;const i=this.options.tokenStorage.get();if(!i)return e;try{const n=await this.options.tokenRefresher.refresh(i);return this.options.tokenStorage.set(n),e.fetcher.request(e.url,e.request)}catch(n){throw this.options.tokenStorage.clear(),n}}}class h{constructor(){this.store=new Map}get length(){return this.store.size}clear(){this.store.clear()}getItem(e){const o=this.store.get(e);return o!==void 0?o:null}key(e){return Array.from(this.store.keys())[e]||null}removeItem(e){this.store.has(e)&&this.store.delete(e)}setItem(e,o){this.store.set(e,o)}}function I(){return typeof window<"u"&&window.localStorage?window.localStorage:new h}const l="cosec-device-id";class _{constructor(e=l,o=I()){this.deviceIdKey=e,this.storage=o}get(){return this.storage.getItem(this.deviceIdKey)}set(e){this.storage.setItem(this.deviceIdKey,e)}generateDeviceId(){return u.generateId()}getOrCreate(){let e=this.get();return e||(e=this.generateDeviceId(),this.set(e)),e}clear(){this.storage.removeItem(this.deviceIdKey)}}const E="cosec-token";class y{constructor(e=E,o=I()){this.tokenKey=e,this.storage=o}get(){const e=this.storage.getItem(this.tokenKey);return e?JSON.parse(e):null}set(e){const o=JSON.stringify(e);this.storage.setItem(this.tokenKey,o)}clear(){this.storage.removeItem(this.tokenKey)}}r.AuthorizeResults=g,r.CoSecHeaders=s,r.CoSecRequestInterceptor=p,r.CoSecResponseInterceptor=D,r.DEFAULT_COSEC_DEVICE_ID_KEY=l,r.DEFAULT_COSEC_TOKEN_KEY=E,r.DeviceIdStorage=_,r.InMemoryStorage=h,r.NanoIdGenerator=d,r.ResponseCodes=c,r.TokenStorage=y,r.getStorage=I,r.idGenerator=u,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ahoo-wang/fetcher-cosec",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "CoSec authentication integration for Fetcher HTTP client",
5
5
  "keywords": [
6
6
  "fetch",
@@ -35,7 +35,7 @@
35
35
  ],
36
36
  "dependencies": {
37
37
  "nanoid": "^5.1.5",
38
- "@ahoo-wang/fetcher": "0.8.2"
38
+ "@ahoo-wang/fetcher": "0.8.3"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@vitest/coverage-v8": "^3.2.4",