@i.un/api-client 1.1.2 → 1.1.4

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
@@ -90,9 +90,9 @@ You can override this protocol via configuration (see "Advanced: custom unwrappi
90
90
 
91
91
  ```ts
92
92
  export interface ApiError extends Error {
93
- code: number; // business error code
94
- data?: unknown; // backend data field
95
- status?: number; // HTTP status code (for network-level errors)
93
+ code: number; // business error code
94
+ data?: unknown; // backend data field
95
+ status?: number; // HTTP status code (for network-level errors)
96
96
  }
97
97
 
98
98
  export const isApiError = (error: unknown): error is ApiError => {
@@ -267,8 +267,229 @@ The protocol details are entirely up to you.
267
267
 
268
268
  ---
269
269
 
270
+ ## Request Chain Execution
271
+
272
+ The Request Chain engine (`executeRequestChain`) allows you to coordinate multiple dependent HTTP requests. It manages a shared **Context**, handles **Variable Substitution**, and supports **Smart Routing** via a strategy pattern.
273
+
274
+ ### Core Concepts
275
+
276
+ - **Rule (`ChainRequestRule`)**: Defines a single step in the chain.
277
+ - **Context**: A shared object that accumulates results. Every step can read from and write to the context.
278
+ - **Handler (`NetworkHandler`)**: Decides which **Adapter** should execute a particular request based on the URL or Method.
279
+
280
+ ### Rule Configuration (`ChainRequestRule`)
281
+
282
+ | Property | Type | Description |
283
+ | :--------------- | :---------------- | :------------------------------------------------------------------------------------------ |
284
+ | `key` | `string` | The key to store the result in the Context. |
285
+ | `request` | `HttpRequestSpec` | Method, URL, Headers, and initial Body. |
286
+ | `selector` | `string` | Optional. A dot-notation path (e.g., `user.id`) to extract specific data from the response. |
287
+ | `includeContext` | `boolean` | If true, the entire Context is merged into the request `body`. |
288
+ | `pickContext` | `string[]` | Specific keys from the Context to merge into the request `body`. |
289
+ | `optional` | `boolean` | If true, the chain continues even if this request fails. |
290
+
291
+ ### Variable Substitution
292
+
293
+ You can use `{{key.path}}` in `url`, `headers`, and `body`. The engine will replace these placeholders with values from the current Context.
294
+
295
+ ### Detailed Example: 3-Step Orchestration
296
+
297
+ ```ts
298
+ import { executeRequestChain } from "@i.un/api-client";
299
+
300
+ const rules = [
301
+ // Step 1: Get session
302
+ {
303
+ key: "auth",
304
+ request: { method: "POST", url: "/login", body: { user: "admin" } },
305
+ },
306
+ // Step 2: Use session token in URL and Headers
307
+ {
308
+ key: "profile",
309
+ request: {
310
+ method: "GET",
311
+ url: "/users/{{auth.userId}}",
312
+ headers: { "X-Session": "{{auth.token}}" },
313
+ },
314
+ selector: "data", // context.profile will only contain the 'data' field
315
+ },
316
+ // Step 3: Combine previous data into a new request
317
+ {
318
+ key: "update",
319
+ request: {
320
+ method: "PUT",
321
+ url: "/sync",
322
+ body: { source: "web-client" }, // static data directly in body
323
+ },
324
+ pickContext: ["profile"], // contextData will be merged into body
325
+ },
326
+ ];
327
+
328
+ const result = await executeRequestChain(rules);
329
+ ```
330
+
331
+ ### Custom Routing (Strategy Pattern)
332
+
333
+ You can provide a list of `NetworkHandler`s to route requests to different environments (e.g., redirecting `/ext/*` to a browser extension API while `/api/*` goes to standard fetch).
334
+
335
+ ```ts
336
+ const handlers = [
337
+ {
338
+ name: "extension-router",
339
+ shouldHandle: (url) => url.startsWith("chrome-extension://"),
340
+ adapter: {
341
+ post: (url, body) => chrome.runtime.sendMessage({ url, body }),
342
+ get: (url) => ...
343
+ }
344
+ }
345
+ ];
346
+
347
+ await executeRequestChain(rules, handlers);
348
+ ```
349
+
350
+ ---
351
+
352
+ ## Protobuf & Security
353
+
354
+ The Protobuf module provides a security layer over `ofetch`. It supports binary serialization, XOR obfuscation, and automatic integration via hooks.
355
+
356
+ ### The Pipeline
357
+
358
+ 1. **Object** -> **Transform** (Optional) -> **Protobuf Encode** -> **XOR Obfuscation** -> **Binary Payload**
359
+
360
+ ### Integration Hooks
361
+
362
+ Use `createProtobufHooks` to add Protobuf support to your `api-client` instance.
363
+
364
+ ```ts
365
+ import {
366
+ createApiClient,
367
+ createProtobufHooks,
368
+ createXorObfuscator,
369
+ } from "@i.un/api-client";
370
+
371
+ const hooks = createProtobufHooks({
372
+ // 1. Custom Obfuscator (Optional)
373
+ // obfuscator: createXorObfuscator("my-secret-key"),
374
+
375
+ // 2. Custom transformations
376
+ transform: {
377
+ beforeEncode: (data) => ({ ...data, ts: Date.now() }),
378
+ afterDecode: (res) => res.data,
379
+ },
380
+ });
381
+
382
+ const client = createApiClient({
383
+ baseURL: "/api",
384
+ ...hooks,
385
+ });
386
+
387
+ // usage: just set Content-Type or Accept to 'application/x-protobuf'
388
+ const data = await client.post(
389
+ "/secure-endpoint",
390
+ { foo: "bar" },
391
+ {
392
+ headers: { "Content-Type": "application/x-protobuf" },
393
+ },
394
+ );
395
+ ```
396
+
397
+ ### Manual Header Configuration
398
+
399
+ If you are not using the automatic hooks or need to manually configure headers for a specific request, you can use the `setProtobufRequestHeaders` helper:
400
+
401
+ ```ts
402
+ import { setProtobufRequestHeaders } from "@i.un/api-client";
403
+
404
+ // 1. Send and receive Protobuf (default)
405
+ const headers = setProtobufRequestHeaders({ "X-Custom": "val" });
406
+ // { "X-Custom": "val", "Content-Type": "application/x-protobuf", "Accept": "application/x-protobuf" }
407
+
408
+ // 2. Only receive Protobuf
409
+ const receiveOnly = setProtobufRequestHeaders({}, "receive");
410
+ // { "Accept": "application/x-protobuf" }
411
+
412
+ // Use with client
413
+ await client.get("/data", { headers: receiveOnly });
414
+ ```
415
+
416
+ ### Envelope Mode vs Custom Type Mode
417
+
418
+ - **Envelope Mode (Default)**: If no `protoType` is provided, the library uses a built-in `SecurePayload` (Timestamp + JSON-stringified data). This is the easiest way to hide data from DevTools without defining schemas for every API.
419
+ - **Custom Type Mode**: Provide a `protoType` (compiled from `.proto`) for full binary performance and type safety.
420
+
421
+ ```ts
422
+ const hooks = createProtobufHooks({
423
+ protoType: MyCompiledMessage, // From protobufjs
424
+ });
425
+ ```
426
+
427
+ ### Custom Obfuscator
428
+
429
+ No obfuscation is enabled by default. If you need to obfuscate the binary data (e.g., to bypass certain network filters), you can provide an `obfuscator` implementation.
430
+
431
+ To use the built-in XOR obfuscator:
432
+
433
+ ```ts
434
+ import { createProtobufHooks, createXorObfuscator } from "@i.un/api-client";
435
+
436
+ const hooks = createProtobufHooks({
437
+ obfuscator: createXorObfuscator("your-secret-key"),
438
+ });
439
+ ```
440
+
441
+ Or provide a completely custom implementation:
442
+
443
+ ```ts
444
+ import { createProtobufHooks, type ProtobufObfuscator } from "@i.un/api-client";
445
+
446
+ const myObfuscator: ProtobufObfuscator = {
447
+ encrypt: (data: Uint8Array) => {
448
+ // your encryption logic
449
+ return data;
450
+ },
451
+ decrypt: (data: Uint8Array) => {
452
+ // your decryption logic
453
+ return data;
454
+ },
455
+ };
456
+
457
+ const hooks = createProtobufHooks({
458
+ obfuscator: myObfuscator,
459
+ });
460
+ ```
461
+
462
+ ### Server-Side Usage (Node/Workers)
463
+
464
+ The library provides utilities for the server/worker side to handle these secure requests.
465
+
466
+ ```ts
467
+ import {
468
+ parseSecureRequest,
469
+ secureResponse,
470
+ createXorObfuscator,
471
+ } from "@i.un/api-client";
472
+
473
+ // 1. Parse incoming request
474
+ const body = await parseSecureRequest(request, {
475
+ obfuscator: createXorObfuscator("key"),
476
+ });
477
+
478
+ // 2. Send secure response
479
+ return await secureResponse(
480
+ { success: true },
481
+ {
482
+ obfuscator: createXorObfuscator("key"),
483
+ },
484
+ );
485
+ ```
486
+
487
+ ---
488
+
270
489
  ## Environment & Notes
271
490
 
491
+ ---
492
+
272
493
  - Built on `ofetch`, works in browsers, Node 18+, Nuxt, etc.
273
494
  - Requires `fetch` / `Headers`:
274
495
  - Browsers: built-in.
package/README.zh-CN.md CHANGED
@@ -90,9 +90,9 @@ export interface ApiResult<T> {
90
90
 
91
91
  ```ts
92
92
  export interface ApiError extends Error {
93
- code: number; // 业务错误码
94
- data?: unknown; // 后端 data 字段
95
- status?: number; // HTTP 状态码(仅网络层错误时可能存在)
93
+ code: number; // 业务错误码
94
+ data?: unknown; // 后端 data 字段
95
+ status?: number; // HTTP 状态码(仅网络层错误时可能存在)
96
96
  }
97
97
 
98
98
  export const isApiError = (error: unknown): error is ApiError => {
@@ -259,8 +259,229 @@ const client = createApiClient({
259
259
 
260
260
  ---
261
261
 
262
+ ## 请求链执行 (Request Chain)
263
+
264
+ 请求链引擎 (`executeRequestChain`) 允许你编排多个相互依赖的 HTTP 请求。它管理一个共享的 **上下文 (Context)**,处理 **变量替换 (Variable Substitution)**,并支持通过策略模式实现的 **智能路由 (Smart Routing)**。
265
+
266
+ ### 核心概念
267
+
268
+ - **规则 (`ChainRequestRule`)**: 定义链中的单个步骤。
269
+ - **上下文 (Context)**: 一个共享对象,用于累积结果。每个步骤都可以从上下文中读取数据或向其中写入结果。
270
+ - **处理器 (`NetworkHandler`)**: 根据 URL 或方法决定哪个 **适配器 (Adapter)** 应该执行特定的请求。
271
+
272
+ ### 规则配置 (`ChainRequestRule`)
273
+
274
+ | 属性 | 类型 | 描述 |
275
+ | :--------------- | :---------------- | :----------------------------------------------------------- |
276
+ | `key` | `string` | 结果在上下文中的存储键名。 |
277
+ | `request` | `HttpRequestSpec` | 包含方法、URL、Header 和初始 Body。 |
278
+ | `selector` | `string` | 可选。使用点分隔的路径(如 `user.id`)从响应中提取特定数据。 |
279
+ | `includeContext` | `boolean` | 如果为 true,则将整个上下文合并到请求的 `body` 中。 |
280
+ | `pickContext` | `string[]` | 指定要合并到请求 `body` 中的上下文键列表。 |
281
+ | `optional` | `boolean` | 如果为 true,即使该请求失败,链式执行也会继续。 |
282
+
283
+ ### 变量替换
284
+
285
+ 你可以在 `url`、`headers` 和 `body` 中使用 `{{key.path}}`。引擎会自动将这些占位符替换为当前上下文中的值。
286
+
287
+ ### 详细示例:三步请求编排
288
+
289
+ ```ts
290
+ import { executeRequestChain } from "@i.un/api-client";
291
+
292
+ const rules = [
293
+ // 步骤 1: 获取登录会话
294
+ {
295
+ key: "auth",
296
+ request: { method: "POST", url: "/login", body: { user: "admin" } },
297
+ },
298
+ // 步骤 2: 在 URL 和 Header 中使用会话 Token
299
+ {
300
+ key: "profile",
301
+ request: {
302
+ method: "GET",
303
+ url: "/users/{{auth.userId}}",
304
+ headers: { "X-Session": "{{auth.token}}" },
305
+ },
306
+ selector: "data", // context.profile 将仅包含响应中的 'data' 字段
307
+ },
308
+ // 步骤 3: 结合之前的步骤数据发起新请求
309
+ {
310
+ key: "update",
311
+ request: {
312
+ method: "PUT",
313
+ url: "/sync",
314
+ body: { source: "web-client" }, // 静态数据直接写在 body
315
+ },
316
+ pickContext: ["profile"], // contextData 将合并到 body
317
+ },
318
+ ];
319
+
320
+ const result = await executeRequestChain(rules);
321
+ ```
322
+
323
+ ### 自定义路由 (策略模式)
324
+
325
+ 你可以提供 `NetworkHandler` 列表,将请求路由到不同的环境(例如:将 `/ext/*` 重定向到浏览器扩展 API,而 `/api/*` 走标准 fetch)。
326
+
327
+ ```ts
328
+ const handlers = [
329
+ {
330
+ name: "extension-router",
331
+ shouldHandle: (url) => url.startsWith("chrome-extension://"),
332
+ adapter: {
333
+ post: (url, body) => chrome.runtime.sendMessage({ url, body }),
334
+ get: (url) => ...
335
+ }
336
+ }
337
+ ];
338
+
339
+ await executeRequestChain(rules, handlers);
340
+ ```
341
+
342
+ ---
343
+
344
+ ## Protobuf 与安全通信
345
+
346
+ Protobuf 模块为 `ofetch` 提供了一层安全保障。它支持二进制序列化、XOR 混淆以及通过 Hook 实现的自动集成。
347
+
348
+ ### 处理流程
349
+
350
+ 1. **对象** -> **转换 (Transform, 可选)** -> **Protobuf 编码** -> **XOR 混淆** -> **二进制负载 (Binary Payload)**
351
+
352
+ ### 集成 Hook
353
+
354
+ 由于使用了 `createProtobufHooks`,你可以轻松地为 `api-client` 实例添加 Protobuf 支持。
355
+
356
+ ```ts
357
+ import {
358
+ createApiClient,
359
+ createProtobufHooks,
360
+ createXorObfuscator,
361
+ } from "@i.un/api-client";
362
+
363
+ const hooks = createProtobufHooks({
364
+ // 1. 自定义混淆器 (可选)
365
+ // obfuscator: createXorObfuscator("my-secret-key"),
366
+
367
+ // 2. 自定义数据转换
368
+ transform: {
369
+ beforeEncode: (data) => ({ ...data, ts: Date.now() }),
370
+ afterDecode: (res) => res.data,
371
+ },
372
+ });
373
+
374
+ const client = createApiClient({
375
+ baseURL: "/api",
376
+ ...hooks,
377
+ });
378
+
379
+ // 使用方法:只需将 Content-Type 或 Accept 设置为 'application/x-protobuf'
380
+ const data = await client.post(
381
+ "/secure-endpoint",
382
+ { foo: "bar" },
383
+ {
384
+ headers: { "Content-Type": "application/x-protobuf" },
385
+ },
386
+ );
387
+ ```
388
+
389
+ ### 手动配置请求头
390
+
391
+ 如果你没有使用自动 Hook,或者需要为特定请求手动配置 Header,可以使用 `setProtobufRequestHeaders` 辅助函数:
392
+
393
+ ```ts
394
+ import { setProtobufRequestHeaders } from "@i.un/api-client";
395
+
396
+ // 1. 同时发送和接收 Protobuf (默认)
397
+ const headers = setProtobufRequestHeaders({ "X-Custom": "val" });
398
+ // { "X-Custom": "val", "Content-Type": "application/x-protobuf", "Accept": "application/x-protobuf" }
399
+
400
+ // 2. 仅接收 Protobuf
401
+ const receiveOnly = setProtobufRequestHeaders({}, "receive");
402
+ // { "Accept": "application/x-protobuf" }
403
+
404
+ // 在 client 中使用
405
+ await client.get("/data", { headers: receiveOnly });
406
+ ```
407
+
408
+ ### 信封模式 vs 自定义类型模式
409
+
410
+ - **信封模式 (默认)**:如果不提供 `protoType`,库将使用内置的 `SecurePayload`(包含时间戳和经过 JSON 序列化的数据)。这是在不为每个接口定义 Schema 的情况下,向开发者工具隐藏数据的最简单方法。
411
+ - **自定义类型模式**:提供一个 `protoType`(从 `.proto` 文件编译出的对象),以获得极致的二进制性能和类型安全。
412
+
413
+ ```ts
414
+ const hooks = createProtobufHooks({
415
+ protoType: MyCompiledMessage, // 来自 protobufjs
416
+ });
417
+ ```
418
+
419
+ ### 自定义混淆逻辑 (Obfuscator)
420
+
421
+ 默认不启用任何混淆。如果需要对二进制数据进行混淆(例如为了绕过某些网络审查或简单的防篡改),你可以提供 `obfuscator` 实现。
422
+
423
+ 如果你想使用库内置的 XOR 混淆,可以使用 `createXorObfuscator`:
424
+
425
+ ```ts
426
+ import { createProtobufHooks, createXorObfuscator } from "@i.un/api-client";
427
+
428
+ const hooks = createProtobufHooks({
429
+ obfuscator: createXorObfuscator("your-secret-key"),
430
+ });
431
+ ```
432
+
433
+ 或者完全自定义混淆算法:
434
+
435
+ ```ts
436
+ import { createProtobufHooks, type ProtobufObfuscator } from "@i.un/api-client";
437
+
438
+ const myObfuscator: ProtobufObfuscator = {
439
+ encrypt: (data: Uint8Array) => {
440
+ // 自定义加密逻辑,返回 Uint8Array
441
+ return data;
442
+ },
443
+ decrypt: (data: Uint8Array) => {
444
+ // 自定义解密逻辑
445
+ return data;
446
+ },
447
+ };
448
+
449
+ const hooks = createProtobufHooks({
450
+ obfuscator: myObfuscator,
451
+ });
452
+ ```
453
+
454
+ ### 服务端/边缘计算使用 (Node/Workers)
455
+
456
+ 本库提供了服务端工具,用于处理这些安全请求。
457
+
458
+ ```ts
459
+ import {
460
+ parseSecureRequest,
461
+ secureResponse,
462
+ createXorObfuscator,
463
+ } from "@i.un/api-client";
464
+
465
+ // 1. 解析进入的加密请求
466
+ const body = await parseSecureRequest(request, {
467
+ obfuscator: createXorObfuscator("key"),
468
+ });
469
+
470
+ // 2. 发送加密响应
471
+ return await secureResponse(
472
+ { success: true },
473
+ {
474
+ obfuscator: createXorObfuscator("key"),
475
+ },
476
+ );
477
+ ```
478
+
479
+ ---
480
+
262
481
  ## 环境支持与注意事项
263
482
 
483
+ ---
484
+
264
485
  - 依赖 `ofetch`,可在浏览器、Node 18+、Nuxt 等环境使用。
265
486
  - 需要环境有 `fetch` / `Headers`:
266
487
  - 浏览器:原生支持。
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Request Chain Runner
3
+ * 负责解析和执行通用的 HTTP 请求链 (Chain Execution)
4
+ * 适用于任何需要链式 HTTP 请求编排的场景
5
+ */
6
+ /** Supported HTTP Methods */
7
+ type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
8
+ /** HTTP 请求参数 */
9
+ interface HttpRequestSpec {
10
+ method: HttpMethod;
11
+ url: string;
12
+ headers?: Record<string, string>;
13
+ body?: any;
14
+ }
15
+ /**
16
+ * 网络适配器接口
17
+ * 定义实际发送请求的能力
18
+ */
19
+ /**
20
+ * 网络适配器接口
21
+ * 定义实际发送请求的能力
22
+ */
23
+ interface NetworkAdapter {
24
+ get<T>(url: string, params?: any, headers?: Record<string, string>): Promise<T>;
25
+ post<T>(url: string, body?: any, headers?: Record<string, string>): Promise<T>;
26
+ put?<T>(url: string, body?: any, headers?: Record<string, string>): Promise<T>;
27
+ delete?<T>(url: string, params?: any, headers?: Record<string, string>): Promise<T>;
28
+ patch?<T>(url: string, body?: any, headers?: Record<string, string>): Promise<T>;
29
+ }
30
+ /**
31
+ * 网络处理器接口 (Strategy Pattern)
32
+ * 组合了"匹配规则"和"执行能力"
33
+ */
34
+ interface NetworkHandler {
35
+ /** 处理器名称 (用于调试) */
36
+ name?: string;
37
+ /** 判断该 URL 是否由此适配器处理 */
38
+ shouldHandle(url: string, method: HttpMethod): boolean;
39
+ /** 具体的网络适配器 */
40
+ adapter: NetworkAdapter;
41
+ }
42
+ /**
43
+ * 请求链规则 (Chain Step)
44
+ */
45
+ interface ChainRequestRule {
46
+ /**
47
+ * 结果存储的键名 (Context Key)
48
+ * Fetch 结果存储: context[key] = response
49
+ */
50
+ key?: string;
51
+ /**
52
+ * HTTP 请求详情
53
+ */
54
+ request: HttpRequestSpec;
55
+ /**
56
+ * 数据提取选择器
57
+ * 用于从响应中提取特定数据, e.g., "elements.0"
58
+ */
59
+ selector?: string;
60
+ /** 是否允许请求失败 (默认 false) */
61
+ optional?: boolean;
62
+ /**
63
+ * 是否包含上下文
64
+ * 如果为 true,请求 Body 将自动合并当前 Context 和 Payload
65
+ */
66
+ includeContext?: boolean;
67
+ /**
68
+ * 上下文筛选列表 (优先级高于 includeContext)
69
+ * 指定需要合并到 Body 中的 Context Key 列表
70
+ * e.g., ["rawProfile", "rawCompany"]
71
+ */
72
+ pickContext?: string[];
73
+ }
74
+ /**
75
+ * 请求链执行器 (Request Chain Engine)
76
+ * 支持链式请求、上下文累积、智能路由、变量替换
77
+ *
78
+ * @param requests 链式执行规则列表
79
+ * @param handlers 网络适配器处理器列表 (按顺序匹配)
80
+ */
81
+ declare function executeRequestChain<T>(requests: ChainRequestRule[], handlers?: NetworkHandler[], getChainRequests?: (context: Record<string, any>) => ChainRequestRule[] | null | undefined, initContext?: Record<string, any>): Promise<T>;
82
+
83
+ export { type ChainRequestRule, type HttpRequestSpec, type NetworkAdapter, type NetworkHandler, executeRequestChain };
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Request Chain Runner
3
+ * 负责解析和执行通用的 HTTP 请求链 (Chain Execution)
4
+ * 适用于任何需要链式 HTTP 请求编排的场景
5
+ */
6
+ /** Supported HTTP Methods */
7
+ type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
8
+ /** HTTP 请求参数 */
9
+ interface HttpRequestSpec {
10
+ method: HttpMethod;
11
+ url: string;
12
+ headers?: Record<string, string>;
13
+ body?: any;
14
+ }
15
+ /**
16
+ * 网络适配器接口
17
+ * 定义实际发送请求的能力
18
+ */
19
+ /**
20
+ * 网络适配器接口
21
+ * 定义实际发送请求的能力
22
+ */
23
+ interface NetworkAdapter {
24
+ get<T>(url: string, params?: any, headers?: Record<string, string>): Promise<T>;
25
+ post<T>(url: string, body?: any, headers?: Record<string, string>): Promise<T>;
26
+ put?<T>(url: string, body?: any, headers?: Record<string, string>): Promise<T>;
27
+ delete?<T>(url: string, params?: any, headers?: Record<string, string>): Promise<T>;
28
+ patch?<T>(url: string, body?: any, headers?: Record<string, string>): Promise<T>;
29
+ }
30
+ /**
31
+ * 网络处理器接口 (Strategy Pattern)
32
+ * 组合了"匹配规则"和"执行能力"
33
+ */
34
+ interface NetworkHandler {
35
+ /** 处理器名称 (用于调试) */
36
+ name?: string;
37
+ /** 判断该 URL 是否由此适配器处理 */
38
+ shouldHandle(url: string, method: HttpMethod): boolean;
39
+ /** 具体的网络适配器 */
40
+ adapter: NetworkAdapter;
41
+ }
42
+ /**
43
+ * 请求链规则 (Chain Step)
44
+ */
45
+ interface ChainRequestRule {
46
+ /**
47
+ * 结果存储的键名 (Context Key)
48
+ * Fetch 结果存储: context[key] = response
49
+ */
50
+ key?: string;
51
+ /**
52
+ * HTTP 请求详情
53
+ */
54
+ request: HttpRequestSpec;
55
+ /**
56
+ * 数据提取选择器
57
+ * 用于从响应中提取特定数据, e.g., "elements.0"
58
+ */
59
+ selector?: string;
60
+ /** 是否允许请求失败 (默认 false) */
61
+ optional?: boolean;
62
+ /**
63
+ * 是否包含上下文
64
+ * 如果为 true,请求 Body 将自动合并当前 Context 和 Payload
65
+ */
66
+ includeContext?: boolean;
67
+ /**
68
+ * 上下文筛选列表 (优先级高于 includeContext)
69
+ * 指定需要合并到 Body 中的 Context Key 列表
70
+ * e.g., ["rawProfile", "rawCompany"]
71
+ */
72
+ pickContext?: string[];
73
+ }
74
+ /**
75
+ * 请求链执行器 (Request Chain Engine)
76
+ * 支持链式请求、上下文累积、智能路由、变量替换
77
+ *
78
+ * @param requests 链式执行规则列表
79
+ * @param handlers 网络适配器处理器列表 (按顺序匹配)
80
+ */
81
+ declare function executeRequestChain<T>(requests: ChainRequestRule[], handlers?: NetworkHandler[], getChainRequests?: (context: Record<string, any>) => ChainRequestRule[] | null | undefined, initContext?: Record<string, any>): Promise<T>;
82
+
83
+ export { type ChainRequestRule, type HttpRequestSpec, type NetworkAdapter, type NetworkHandler, executeRequestChain };