@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 CHANGED
@@ -26,6 +26,7 @@ This package provides seamless integration between the Fetcher HTTP client and t
26
26
  - **⚡ Performance Optimized**: Minimal overhead with connection pooling and caching
27
27
  - **🛠️ TypeScript First**: Complete type definitions with strict type safety
28
28
  - **🔌 Pluggable Architecture**: Modular design for easy integration and customization
29
+ - **⚙️ Simplified Configuration**: One-line setup with `CoSecConfigurer` for minimal configuration overhead
29
30
 
30
31
  ## 🚀 Quick Start
31
32
 
@@ -112,6 +113,78 @@ fetcher.interceptors.response.use(
112
113
  );
113
114
  ```
114
115
 
116
+ ## 🚀 Simplified Setup (Recommended)
117
+
118
+ For a much simpler setup experience, use the `CoSecConfigurer` class which automatically handles all the complex dependency creation and interceptor configuration:
119
+
120
+ ```typescript
121
+ import { Fetcher } from '@ahoo-wang/fetcher';
122
+ import { CoSecConfigurer } from '@ahoo-wang/fetcher-cosec';
123
+
124
+ // Create a Fetcher instance
125
+ const fetcher = new Fetcher({
126
+ baseURL: 'https://api.example.com',
127
+ });
128
+
129
+ // Create CoSec configurer with flexible configuration
130
+ const configurer = new CoSecConfigurer({
131
+ appId: 'your-app-id',
132
+
133
+ // Optional: Custom storage implementations
134
+ tokenStorage: new TokenStorage('my-app-tokens'),
135
+ deviceIdStorage: new DeviceIdStorage('my-app-devices'),
136
+
137
+ // Optional: Token refresher (enables authentication interceptors)
138
+ tokenRefresher: {
139
+ refresh: async token => {
140
+ // Implement your token refresh logic
141
+ const response = await fetch('/api/auth/refresh', {
142
+ method: 'POST',
143
+ headers: { 'Content-Type': 'application/json' },
144
+ body: JSON.stringify({ refreshToken: token.refreshToken }),
145
+ });
146
+
147
+ if (!response.ok) {
148
+ throw new Error('Token refresh failed');
149
+ }
150
+
151
+ const tokens = await response.json();
152
+ return {
153
+ accessToken: tokens.accessToken,
154
+ refreshToken: tokens.refreshToken,
155
+ };
156
+ },
157
+ },
158
+
159
+ // Optional: Custom error handlers (only add interceptors if provided)
160
+ onUnauthorized: exchange => {
161
+ console.error('Unauthorized access:', exchange.request.url);
162
+ // Redirect to login or handle as needed
163
+ window.location.href = '/login';
164
+ },
165
+ onForbidden: async exchange => {
166
+ console.error('Forbidden access:', exchange.request.url);
167
+ // Show permission error
168
+ alert('You do not have permission to access this resource');
169
+ },
170
+ });
171
+
172
+ // Apply all CoSec interceptors with one call
173
+ configurer.applyTo(fetcher);
174
+
175
+ // Now you can use the fetcher with full CoSec authentication
176
+ const response = await fetcher.get('/protected-endpoint');
177
+ ```
178
+
179
+ ### Benefits of CoSecConfigurer
180
+
181
+ - ✅ **Flexible configuration**: Support for full auth setup or minimal CoSec headers only
182
+ - ✅ **Custom storage**: Optional custom TokenStorage and DeviceIdStorage implementations
183
+ - ✅ **Conditional interceptors**: Authentication interceptors only added when tokenRefresher is provided
184
+ - ✅ **Error handler control**: Choose which error interceptors to add based on your needs
185
+ - ✅ **Type-safe**: Full TypeScript support with intelligent defaults
186
+ - ✅ **Backward compatible**: Original manual setup still works
187
+
115
188
  ## 🔧 Configuration
116
189
 
117
190
  ### CoSecOptions Interface
@@ -163,6 +236,58 @@ The interceptor automatically adds the following headers to requests:
163
236
 
164
237
  ### Core Classes
165
238
 
239
+ #### CoSecConfigurer
240
+
241
+ The recommended way to configure CoSec authentication. Provides a simplified API that automatically creates and configures all necessary interceptors and dependencies.
242
+
243
+ ```typescript
244
+ const configurer = new CoSecConfigurer({
245
+ appId: 'your-app-id',
246
+
247
+ // Optional: Custom storage implementations
248
+ tokenStorage: new TokenStorage('custom-prefix'),
249
+ deviceIdStorage: new DeviceIdStorage('custom-prefix'),
250
+
251
+ // Optional: Token refresher (enables auth interceptors)
252
+ tokenRefresher: {
253
+ refresh: async token => {
254
+ // Your token refresh implementation
255
+ return {
256
+ accessToken: 'new-access-token',
257
+ refreshToken: 'new-refresh-token',
258
+ };
259
+ },
260
+ },
261
+
262
+ // Optional error handlers (interceptors only added if provided)
263
+ onUnauthorized: exchange => {
264
+ /* handle 401 */
265
+ },
266
+ onForbidden: async exchange => {
267
+ /* handle 403 */
268
+ },
269
+ });
270
+
271
+ configurer.applyTo(fetcher);
272
+ ```
273
+
274
+ **Conditionally Configured Interceptors:**
275
+
276
+ Always added:
277
+
278
+ - `CoSecRequestInterceptor` - Adds CoSec headers (appId, deviceId, requestId)
279
+ - `ResourceAttributionRequestInterceptor` - Adds tenant/owner path parameters
280
+
281
+ Only when `tokenRefresher` is provided:
282
+
283
+ - `AuthorizationRequestInterceptor` - Adds Bearer token authentication
284
+ - `AuthorizationResponseInterceptor` - Handles token refresh on 401 responses
285
+
286
+ Only when corresponding handlers are provided:
287
+
288
+ - `UnauthorizedErrorInterceptor` - Handles 401 unauthorized errors
289
+ - `ForbiddenErrorInterceptor` - Handles 403 forbidden errors
290
+
166
291
  #### AuthorizationRequestInterceptor
167
292
 
168
293
  Automatically adds CoSec authentication headers to outgoing HTTP requests.
package/README.zh-CN.md CHANGED
@@ -26,6 +26,7 @@
26
26
  - **⚡ 性能优化**:最小开销,支持连接池和缓存
27
27
  - **🛠️ TypeScript 优先**:完整类型定义,严格类型安全
28
28
  - **🔌 可插拔架构**:模块化设计,易于集成和定制
29
+ - **⚙️ 简化配置**:使用 `CoSecConfigurer` 的一行设置,最小化配置开销
29
30
 
30
31
  ## 🚀 快速开始
31
32
 
@@ -112,6 +113,78 @@ fetcher.interceptors.response.use(
112
113
  );
113
114
  ```
114
115
 
116
+ ## 🚀 简化设置(推荐)
117
+
118
+ 为了获得更简单的设置体验,请使用 `CoSecConfigurer` 类,它会自动处理所有复杂的依赖创建和拦截器配置:
119
+
120
+ ```typescript
121
+ import { Fetcher } from '@ahoo-wang/fetcher';
122
+ import { CoSecConfigurer } from '@ahoo-wang/fetcher-cosec';
123
+
124
+ // 创建 Fetcher 实例
125
+ const fetcher = new Fetcher({
126
+ baseURL: 'https://api.example.com',
127
+ });
128
+
129
+ // 使用灵活的配置创建 CoSec 配置器
130
+ const configurer = new CoSecConfigurer({
131
+ appId: 'your-app-id',
132
+
133
+ // 可选:自定义存储实现
134
+ tokenStorage: new TokenStorage('my-app-tokens'),
135
+ deviceIdStorage: new DeviceIdStorage('my-app-devices'),
136
+
137
+ // 可选:令牌刷新器(启用认证拦截器)
138
+ tokenRefresher: {
139
+ refresh: async token => {
140
+ // 实现您的令牌刷新逻辑
141
+ const response = await fetch('/api/auth/refresh', {
142
+ method: 'POST',
143
+ headers: { 'Content-Type': 'application/json' },
144
+ body: JSON.stringify({ refreshToken: token.refreshToken }),
145
+ });
146
+
147
+ if (!response.ok) {
148
+ throw new Error('Token refresh failed');
149
+ }
150
+
151
+ const tokens = await response.json();
152
+ return {
153
+ accessToken: tokens.accessToken,
154
+ refreshToken: tokens.refreshToken,
155
+ };
156
+ },
157
+ },
158
+
159
+ // 可选:自定义错误处理器(仅在提供时才添加拦截器)
160
+ onUnauthorized: exchange => {
161
+ console.error('未授权访问:', exchange.request.url);
162
+ // 重定向到登录或根据需要处理
163
+ window.location.href = '/login';
164
+ },
165
+ onForbidden: async exchange => {
166
+ console.error('禁止访问:', exchange.request.url);
167
+ // 显示权限错误
168
+ alert('您没有权限访问此资源');
169
+ },
170
+ });
171
+
172
+ // 使用一次调用应用所有 CoSec 拦截器
173
+ configurer.applyTo(fetcher);
174
+
175
+ // 现在您可以使用具有完整 CoSec 认证的 fetcher
176
+ const response = await fetcher.get('/protected-endpoint');
177
+ ```
178
+
179
+ ### CoSecConfigurer 的优势
180
+
181
+ - ✅ **灵活配置**:支持完整认证设置或仅最小的 CoSec 头部
182
+ - ✅ **自定义存储**:可选的自定义 TokenStorage 和 DeviceIdStorage 实现
183
+ - ✅ **条件拦截器**:仅在提供 tokenRefresher 时才添加认证拦截器
184
+ - ✅ **错误处理器控制**:根据需要选择添加哪些错误拦截器
185
+ - ✅ **类型安全**:完整的 TypeScript 支持和智能默认值
186
+ - ✅ **向后兼容**:原始手动设置仍然有效
187
+
115
188
  ## 🔧 配置
116
189
 
117
190
  ### CoSecOptions 接口
@@ -163,6 +236,58 @@ interface JwtTokenManagerCapable {
163
236
 
164
237
  ### 核心类
165
238
 
239
+ #### CoSecConfigurer
240
+
241
+ 配置 CoSec 认证的推荐方式。提供简化的 API,自动创建和配置所有必要的拦截器和依赖项。
242
+
243
+ ```typescript
244
+ const configurer = new CoSecConfigurer({
245
+ appId: 'your-app-id',
246
+
247
+ // 可选:自定义存储实现
248
+ tokenStorage: new TokenStorage('custom-prefix'),
249
+ deviceIdStorage: new DeviceIdStorage('custom-prefix'),
250
+
251
+ // 可选:令牌刷新器(启用认证拦截器)
252
+ tokenRefresher: {
253
+ refresh: async token => {
254
+ // 您的令牌刷新实现
255
+ return {
256
+ accessToken: 'new-access-token',
257
+ refreshToken: 'new-refresh-token',
258
+ };
259
+ },
260
+ },
261
+
262
+ // 可选错误处理器(仅在提供时才添加拦截器)
263
+ onUnauthorized: exchange => {
264
+ /* 处理 401 */
265
+ },
266
+ onForbidden: async exchange => {
267
+ /* 处理 403 */
268
+ },
269
+ });
270
+
271
+ configurer.applyTo(fetcher);
272
+ ```
273
+
274
+ **条件配置的拦截器:**
275
+
276
+ 始终添加:
277
+
278
+ - `CoSecRequestInterceptor` - 添加 CoSec 头部(appId、deviceId、requestId)
279
+ - `ResourceAttributionRequestInterceptor` - 添加租户/所有者路径参数
280
+
281
+ 仅在提供 `tokenRefresher` 时添加:
282
+
283
+ - `AuthorizationRequestInterceptor` - 添加 Bearer 令牌认证
284
+ - `AuthorizationResponseInterceptor` - 处理 401 响应时的令牌刷新
285
+
286
+ 仅在提供相应处理器时添加:
287
+
288
+ - `UnauthorizedErrorInterceptor` - 处理 401 未授权错误
289
+ - `ForbiddenErrorInterceptor` - 处理 403 禁止错误
290
+
166
291
  #### AuthorizationRequestInterceptor
167
292
 
168
293
  自动向传出 HTTP 请求添加 CoSec 认证头部。
@@ -0,0 +1,169 @@
1
+ import { Fetcher, FetcherConfigurer, FetchExchange } from '@ahoo-wang/fetcher';
2
+ import { DeviceIdStorage } from './deviceIdStorage';
3
+ import { JwtTokenManager } from './jwtTokenManager';
4
+ import { TokenRefresher } from './tokenRefresher';
5
+ import { TokenStorage } from './tokenStorage';
6
+ /**
7
+ * Simplified configuration interface for CoSec setup.
8
+ * Provides flexible configuration with sensible defaults for optional components.
9
+ */
10
+ export interface CoSecConfig {
11
+ /**
12
+ * Application ID to be sent in the CoSec-App-Id header.
13
+ * This is required for identifying your application in the CoSec system.
14
+ */
15
+ appId: string;
16
+ /**
17
+ * Custom token storage implementation.
18
+ * If not provided, a default TokenStorage instance will be created.
19
+ * Useful for custom storage backends or testing scenarios.
20
+ */
21
+ tokenStorage?: TokenStorage;
22
+ /**
23
+ * Custom device ID storage implementation.
24
+ * If not provided, a default DeviceIdStorage instance will be created.
25
+ * Useful for custom device identification strategies or testing scenarios.
26
+ */
27
+ deviceIdStorage?: DeviceIdStorage;
28
+ /**
29
+ * Token refresher implementation for handling expired tokens.
30
+ * If not provided, authentication interceptors will not be added.
31
+ * This enables CoSec configuration without full JWT authentication.
32
+ */
33
+ tokenRefresher?: TokenRefresher;
34
+ /**
35
+ * Callback function invoked when an unauthorized (401) response is detected.
36
+ * If not provided, 401 errors will not be intercepted.
37
+ */
38
+ onUnauthorized?: (exchange: FetchExchange) => Promise<void> | void;
39
+ /**
40
+ * Callback function invoked when a forbidden (403) response is detected.
41
+ * If not provided, 403 errors will not be intercepted.
42
+ */
43
+ onForbidden?: (exchange: FetchExchange) => Promise<void>;
44
+ }
45
+ /**
46
+ * CoSecConfigurer provides a flexible way to configure CoSec interceptors
47
+ * and dependencies with a single configuration object.
48
+ *
49
+ * This class implements FetcherConfigurer and supports both full authentication
50
+ * setups and minimal CoSec header injection. It conditionally creates dependencies
51
+ * based on the provided configuration, allowing for different levels of integration.
52
+ *
53
+ * @implements {FetcherConfigurer}
54
+ *
55
+ * @example
56
+ * Full authentication setup with custom storage:
57
+ * ```typescript
58
+ * const configurer = new CoSecConfigurer({
59
+ * appId: 'my-app-001',
60
+ * tokenStorage: new CustomTokenStorage(),
61
+ * deviceIdStorage: new CustomDeviceStorage(),
62
+ * tokenRefresher: {
63
+ * refresh: async (token: CompositeToken) => {
64
+ * const response = await fetch('/api/auth/refresh', {
65
+ * method: 'POST',
66
+ * body: JSON.stringify({ refreshToken: token.refreshToken }),
67
+ * });
68
+ * const newTokens = await response.json();
69
+ * return {
70
+ * accessToken: newTokens.accessToken,
71
+ * refreshToken: newTokens.refreshToken,
72
+ * };
73
+ * },
74
+ * },
75
+ * onUnauthorized: (exchange) => redirectToLogin(),
76
+ * onForbidden: (exchange) => showPermissionError(),
77
+ * });
78
+ *
79
+ * configurer.applyTo(fetcher);
80
+ * ```
81
+ *
82
+ * @example
83
+ * Minimal setup with only CoSec headers (no authentication):
84
+ * ```typescript
85
+ * const configurer = new CoSecConfigurer({
86
+ * appId: 'my-app-001',
87
+ * // No tokenRefresher provided - authentication interceptors won't be added
88
+ * });
89
+ *
90
+ * configurer.applyTo(fetcher);
91
+ * ```
92
+ */
93
+ export declare class CoSecConfigurer implements FetcherConfigurer {
94
+ readonly config: CoSecConfig;
95
+ /**
96
+ * Token storage instance, either provided in config or auto-created.
97
+ */
98
+ readonly tokenStorage: TokenStorage;
99
+ /**
100
+ * Device ID storage instance, either provided in config or auto-created.
101
+ */
102
+ readonly deviceIdStorage: DeviceIdStorage;
103
+ /**
104
+ * JWT token manager instance, only created if tokenRefresher is provided.
105
+ * When undefined, authentication interceptors will not be added.
106
+ */
107
+ readonly tokenManager?: JwtTokenManager;
108
+ /**
109
+ * Creates a new CoSecConfigurer instance with the provided configuration.
110
+ *
111
+ * This constructor conditionally creates dependencies based on the configuration:
112
+ * - TokenStorage and DeviceIdStorage are always created (using defaults if not provided)
113
+ * - JwtTokenManager is only created if tokenRefresher is provided
114
+ *
115
+ * @param config - CoSec configuration object
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * // Full setup with all dependencies
120
+ * const configurer = new CoSecConfigurer({
121
+ * appId: 'my-app',
122
+ * tokenRefresher: myTokenRefresher,
123
+ * });
124
+ *
125
+ * // Minimal setup with custom storage
126
+ * const configurer = new CoSecConfigurer({
127
+ * appId: 'my-app',
128
+ * tokenStorage: customStorage,
129
+ * deviceIdStorage: customDeviceStorage,
130
+ * });
131
+ * ```
132
+ */
133
+ constructor(config: CoSecConfig);
134
+ /**
135
+ * Applies CoSec interceptors to the provided Fetcher instance.
136
+ *
137
+ * This method conditionally configures interceptors based on the provided configuration:
138
+ *
139
+ * Always added:
140
+ * 1. CoSecRequestInterceptor - Adds CoSec headers (appId, deviceId, requestId)
141
+ * 2. ResourceAttributionRequestInterceptor - Adds tenant/owner path parameters
142
+ *
143
+ * Only when `tokenRefresher` is provided:
144
+ * 3. AuthorizationRequestInterceptor - Adds Bearer token authentication
145
+ * 4. AuthorizationResponseInterceptor - Handles token refresh on 401 responses
146
+ *
147
+ * Only when corresponding handlers are provided:
148
+ * 5. UnauthorizedErrorInterceptor - Handles 401 unauthorized errors
149
+ * 6. ForbiddenErrorInterceptor - Handles 403 forbidden errors
150
+ *
151
+ * @param fetcher - The Fetcher instance to configure
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * const fetcher = new Fetcher({ baseURL: '/api' });
156
+ * const configurer = new CoSecConfigurer({
157
+ * appId: 'my-app',
158
+ * tokenRefresher: myTokenRefresher,
159
+ * onUnauthorized: handle401,
160
+ * onForbidden: handle403,
161
+ * });
162
+ *
163
+ * configurer.applyTo(fetcher);
164
+ * // Now fetcher has all CoSec interceptors configured
165
+ * ```
166
+ */
167
+ applyTo(fetcher: Fetcher): void;
168
+ }
169
+ //# sourceMappingURL=cosecConfigurer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cosecConfigurer.d.ts","sourceRoot":"","sources":["../src/cosecConfigurer.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAI/E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;OAIG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAE5B;;;;OAIG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC;;;;OAIG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAEnE;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,qBAAa,eAAgB,YAAW,iBAAiB;aA0C3B,MAAM,EAAE,WAAW;IAzC/C;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAE1C;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,eAAe,CAAC;IAExC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;gBACyB,MAAM,EAAE,WAAW;IAc/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;CA0ChC"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './authorizationRequestInterceptor';
2
2
  export * from './authorizationResponseInterceptor';
3
+ export * from './cosecConfigurer';
3
4
  export * from './cosecRequestInterceptor';
4
5
  export * from './deviceIdStorage';
5
6
  export * from './idGenerator';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,yCAAyC,CAAC;AACxD,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,yCAAyC,CAAC;AACxD,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC"}