@i.un/api-client 1.1.6 → 1.1.8
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 +10 -10
- package/README.zh-CN.md +10 -10
- package/dist/chain.d.mts +0 -11
- package/dist/chain.d.ts +0 -11
- package/dist/chain.js +7 -17
- package/dist/chain.js.map +1 -1
- package/dist/chain.mjs +1 -1
- package/dist/{chunk-5CXSMOKF.mjs → chunk-2OSF7OWV.mjs} +8 -18
- package/dist/chunk-2OSF7OWV.mjs.map +1 -0
- package/dist/{chunk-E4AUGZBD.mjs → chunk-QJ34L7YD.mjs} +1 -1
- package/dist/chunk-QJ34L7YD.mjs.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +7 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/protobuf.d.mts +9 -21
- package/dist/protobuf.d.ts +9 -21
- package/dist/protobuf.js.map +1 -1
- package/dist/protobuf.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-5CXSMOKF.mjs.map +0 -1
- package/dist/chunk-E4AUGZBD.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -279,14 +279,12 @@ The Request Chain engine (`executeRequestChain`) allows you to coordinate multip
|
|
|
279
279
|
|
|
280
280
|
### Rule Configuration (`ChainRequestRule`)
|
|
281
281
|
|
|
282
|
-
| Property
|
|
283
|
-
|
|
|
284
|
-
| `key`
|
|
285
|
-
| `request`
|
|
286
|
-
| `selector`
|
|
287
|
-
| `
|
|
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. |
|
|
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
|
+
| `optional` | `boolean` | If true, the chain continues even if this request fails. |
|
|
290
288
|
|
|
291
289
|
### Variable Substitution
|
|
292
290
|
|
|
@@ -319,9 +317,11 @@ const rules = [
|
|
|
319
317
|
request: {
|
|
320
318
|
method: "PUT",
|
|
321
319
|
url: "/sync",
|
|
322
|
-
body: {
|
|
320
|
+
body: {
|
|
321
|
+
source: "web-client",
|
|
322
|
+
profile: "{{profile}}", // Automatically injects the 'profile' object/array from context
|
|
323
|
+
},
|
|
323
324
|
},
|
|
324
|
-
pickContext: ["profile"], // contextData will be merged into body
|
|
325
325
|
},
|
|
326
326
|
];
|
|
327
327
|
|
package/README.zh-CN.md
CHANGED
|
@@ -271,14 +271,12 @@ const client = createApiClient({
|
|
|
271
271
|
|
|
272
272
|
### 规则配置 (`ChainRequestRule`)
|
|
273
273
|
|
|
274
|
-
| 属性
|
|
275
|
-
|
|
|
276
|
-
| `key`
|
|
277
|
-
| `request`
|
|
278
|
-
| `selector`
|
|
279
|
-
| `
|
|
280
|
-
| `pickContext` | `string[]` | 指定要合并到请求 `body` 中的上下文键列表。 |
|
|
281
|
-
| `optional` | `boolean` | 如果为 true,即使该请求失败,链式执行也会继续。 |
|
|
274
|
+
| 属性 | 类型 | 描述 |
|
|
275
|
+
| :--------- | :---------------- | :----------------------------------------------------------- |
|
|
276
|
+
| `key` | `string` | 结果在上下文中的存储键名。 |
|
|
277
|
+
| `request` | `HttpRequestSpec` | 包含方法、URL、Header 和初始 Body。 |
|
|
278
|
+
| `selector` | `string` | 可选。使用点分隔的路径(如 `user.id`)从响应中提取特定数据。 |
|
|
279
|
+
| `optional` | `boolean` | 如果为 true,即使该请求失败,链式执行也会继续。 |
|
|
282
280
|
|
|
283
281
|
### 变量替换
|
|
284
282
|
|
|
@@ -311,9 +309,11 @@ const rules = [
|
|
|
311
309
|
request: {
|
|
312
310
|
method: "PUT",
|
|
313
311
|
url: "/sync",
|
|
314
|
-
body: {
|
|
312
|
+
body: {
|
|
313
|
+
source: "web-client",
|
|
314
|
+
profile: "{{profile}}", // 自动从上下文中注入 'profile' 对象/数组
|
|
315
|
+
},
|
|
315
316
|
},
|
|
316
|
-
pickContext: ["profile"], // contextData 将合并到 body
|
|
317
317
|
},
|
|
318
318
|
];
|
|
319
319
|
|
package/dist/chain.d.mts
CHANGED
|
@@ -59,17 +59,6 @@ interface ChainRequestRule {
|
|
|
59
59
|
selector?: string;
|
|
60
60
|
/** 是否允许请求失败 (默认 false) */
|
|
61
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
62
|
}
|
|
74
63
|
/**
|
|
75
64
|
* 请求链执行器 (Request Chain Engine)
|
package/dist/chain.d.ts
CHANGED
|
@@ -59,17 +59,6 @@ interface ChainRequestRule {
|
|
|
59
59
|
selector?: string;
|
|
60
60
|
/** 是否允许请求失败 (默认 false) */
|
|
61
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
62
|
}
|
|
74
63
|
/**
|
|
75
64
|
* 请求链执行器 (Request Chain Engine)
|
package/dist/chain.js
CHANGED
|
@@ -89,6 +89,12 @@ function getByPath(obj, path) {
|
|
|
89
89
|
}
|
|
90
90
|
function substituteVariables(target, context) {
|
|
91
91
|
if (typeof target === "string") {
|
|
92
|
+
const directMatch = target.match(/^\{\{([\w\.]+)\}\}$/);
|
|
93
|
+
if (directMatch) {
|
|
94
|
+
const path = directMatch[1];
|
|
95
|
+
const val = getByPath(context, path);
|
|
96
|
+
return val !== void 0 ? val : "";
|
|
97
|
+
}
|
|
92
98
|
return target.replace(/\{\{([\w\.]+)\}\}/g, (_, path) => {
|
|
93
99
|
const val = getByPath(context, path);
|
|
94
100
|
return val !== void 0 ? String(val) : "";
|
|
@@ -111,23 +117,7 @@ async function executeRequestChain(requests, handlers = [], getChainRequests, in
|
|
|
111
117
|
let lastResult = null;
|
|
112
118
|
for (const rule of requests) {
|
|
113
119
|
try {
|
|
114
|
-
|
|
115
|
-
if (rule.pickContext) {
|
|
116
|
-
rule.pickContext.forEach((key) => {
|
|
117
|
-
if (key in context) contextData[key] = context[key];
|
|
118
|
-
});
|
|
119
|
-
} else if (rule.includeContext) {
|
|
120
|
-
contextData = context;
|
|
121
|
-
}
|
|
122
|
-
const hasContextData = Object.keys(contextData).length > 0;
|
|
123
|
-
let requestSpec = { ...rule.request };
|
|
124
|
-
if (hasContextData) {
|
|
125
|
-
requestSpec.body = {
|
|
126
|
-
...contextData,
|
|
127
|
-
...requestSpec.body || {}
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
requestSpec = substituteVariables(requestSpec, context);
|
|
120
|
+
const requestSpec = substituteVariables(rule.request, context);
|
|
131
121
|
let rawData = await executeChainRequest(requestSpec, handlers);
|
|
132
122
|
if (getChainRequests) {
|
|
133
123
|
const chainRequests = getChainRequests(rawData);
|
package/dist/chain.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/chain.ts"],"sourcesContent":["/**\n * Request Chain Runner\n * 负责解析和执行通用的 HTTP 请求链 (Chain Execution)\n * 适用于任何需要链式 HTTP 请求编排的场景\n */\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\n/** Supported HTTP Methods */\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/** HTTP 请求参数 */\nexport interface HttpRequestSpec {\n method: HttpMethod;\n url: string;\n headers?: Record<string, string>;\n body?: any;\n}\n\n/**\n * 网络适配器接口\n * 定义实际发送请求的能力\n */\n/**\n * 网络适配器接口\n * 定义实际发送请求的能力\n */\nexport interface NetworkAdapter {\n get<T>(\n url: string,\n params?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n post<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n put?<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n delete?<T>(\n url: string,\n params?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n patch?<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n}\n\n/**\n * 网络处理器接口 (Strategy Pattern)\n * 组合了\"匹配规则\"和\"执行能力\"\n */\nexport interface NetworkHandler {\n /** 处理器名称 (用于调试) */\n name?: string;\n\n /** 判断该 URL 是否由此适配器处理 */\n shouldHandle(url: string, method: HttpMethod): boolean;\n\n /** 具体的网络适配器 */\n adapter: NetworkAdapter;\n}\n\n/**\n * 请求链规则 (Chain Step)\n */\nexport interface ChainRequestRule {\n /**\n * 结果存储的键名 (Context Key)\n * Fetch 结果存储: context[key] = response\n */\n key?: string;\n\n /**\n * HTTP 请求详情\n */\n request: HttpRequestSpec;\n\n /**\n * 数据提取选择器\n * 用于从响应中提取特定数据, e.g., \"elements.0\"\n */\n selector?: string;\n\n /** 是否允许请求失败 (默认 false) */\n optional?: boolean;\n\n /**\n * 是否包含上下文\n * 如果为 true,请求 Body 将自动合并当前 Context 和 Payload\n */\n includeContext?: boolean;\n\n /**\n * 上下文筛选列表 (优先级高于 includeContext)\n * 指定需要合并到 Body 中的 Context Key 列表\n * e.g., [\"rawProfile\", \"rawCompany\"]\n */\n pickContext?: string[];\n}\n\n// ============================================================================\n// Internal Utilities\n// ============================================================================\n\n/**\n * 执行 HTTP 请求\n * 遍历 handlers 数组,找到第一个能处理该 URL 的适配器执行\n *\n * @param spec 请求详情\n * @param handlers 网络处理器链\n */\nasync function executeChainRequest<T>(\n spec: HttpRequestSpec,\n handlers: NetworkHandler[] = [],\n): Promise<T | null> {\n // Normalize method to upper case for robustness\n const method = spec.method.toUpperCase() as HttpMethod;\n\n // 1. 遍历处理器数组 (责任链)\n for (const handler of handlers) {\n if (handler.shouldHandle(spec.url, method)) {\n try {\n const { adapter } = handler;\n const headers = spec.headers;\n\n switch (method) {\n case \"GET\":\n return await adapter.get<T>(spec.url, spec.body, headers);\n case \"POST\":\n return await adapter.post<T>(spec.url, spec.body, headers);\n case \"PUT\":\n if (!adapter.put)\n throw new Error(`Adapter ${handler.name} missing PUT method`);\n return await adapter.put<T>(spec.url, spec.body, headers);\n case \"DELETE\":\n if (!adapter.delete)\n throw new Error(`Adapter ${handler.name} missing DELETE method`);\n return await adapter.delete<T>(spec.url, spec.body, headers);\n case \"PATCH\":\n if (!adapter.patch)\n throw new Error(`Adapter ${handler.name} missing PATCH method`);\n return await adapter.patch<T>(spec.url, spec.body, headers);\n default:\n throw new Error(`Unsupported method: ${method}`);\n }\n } catch (err) {\n console.warn(\n `Handler [${handler.name || \"Anonymous\"}] failed for ${spec.url}`,\n err,\n );\n // 如果需要继续尝试下一个 handler,可以在这里 continue,但通常由第一个匹配者全权负责\n return null;\n }\n }\n }\n\n // 2. 默认行为 (Fallback): 绝对路径自动走标准 fetch\n if (spec.url.startsWith(\"http://\") || spec.url.startsWith(\"https://\")) {\n return await executeFallbackFetch<T>(spec);\n }\n\n console.warn(`No handler found for url: ${spec.url}`);\n return null;\n}\n\n/**\n * 标准 Fetch 回退实现\n */\nasync function executeFallbackFetch<T>(\n spec: HttpRequestSpec,\n): Promise<T | null> {\n try {\n const response = await fetch(spec.url, {\n method: spec.method,\n headers: spec.headers,\n body: spec.body ? JSON.stringify(spec.body) : undefined,\n credentials: \"include\",\n });\n\n if (!response.ok) {\n console.log(`External Request failed: ${response.status} ${spec.url}`);\n return null;\n }\n\n return await response.json();\n } catch (err) {\n console.log(\"External Request error:\", err);\n return null;\n }\n}\n\n/**\n * 根据路径获取对象值\n */\nfunction getByPath(obj: any, path: string): any {\n if (!path) return obj;\n return path.split(\".\").reduce((acc, part) => acc && acc[part], obj);\n}\n\n/**\n * 变量替换 (Internal)\n * 支持字符串 {{key}} 和 {{key.prop}}\n */\nfunction substituteVariables(target: any, context: any): any {\n if (typeof target === \"string\") {\n return target.replace(/\\{\\{([\\w\\.]+)\\}\\}/g, (_, path) => {\n const val = getByPath(context, path);\n return val !== undefined ? String(val) : \"\";\n });\n }\n\n if (Array.isArray(target)) {\n return target.map((item) => substituteVariables(item, context));\n }\n\n if (target && typeof target === \"object\") {\n const result: any = {};\n for (const key in target) {\n result[key] = substituteVariables(target[key], context);\n }\n return result;\n }\n\n return target;\n}\n\n// ============================================================================\n// Main Runner\n// ============================================================================\n\n/**\n * 请求链执行器 (Request Chain Engine)\n * 支持链式请求、上下文累积、智能路由、变量替换\n *\n * @param requests 链式执行规则列表\n * @param handlers 网络适配器处理器列表 (按顺序匹配)\n */\nexport async function executeRequestChain<T>(\n requests: ChainRequestRule[],\n handlers: NetworkHandler[] = [],\n getChainRequests?: (\n context: Record<string, any>,\n ) => ChainRequestRule[] | null | undefined,\n initContext?: Record<string, any>,\n): Promise<T> {\n const context: Record<string, any> = initContext || {};\n let lastResult: any = null;\n\n for (const rule of requests) {\n try {\n // 1. 准备 Context Data (用于 Submit)\n let contextData: Record<string, any> = {};\n if (rule.pickContext) {\n rule.pickContext.forEach((key) => {\n if (key in context) contextData[key] = context[key];\n });\n } else if (rule.includeContext) {\n contextData = context;\n }\n const hasContextData = Object.keys(contextData).length > 0;\n\n // 2. 准备 Request Spec (合并 Context 到 Body)\n let requestSpec = { ...rule.request };\n if (hasContextData) {\n requestSpec.body = {\n ...contextData,\n ...(requestSpec.body || {}),\n };\n }\n\n // 3. 变量替换\n requestSpec = substituteVariables(requestSpec, context);\n\n // 4. 执行请求 (传入 handlers)\n let rawData = await executeChainRequest<any>(requestSpec, handlers);\n\n if (getChainRequests) {\n const chainRequests = getChainRequests(rawData);\n if (chainRequests && chainRequests.length > 0) {\n rawData = await executeRequestChain(\n chainRequests,\n handlers,\n getChainRequests,\n JSON.parse(JSON.stringify(context)),\n );\n }\n }\n\n lastResult = rawData;\n\n if (rawData) {\n // 5. 存储结果\n if (rule.key) {\n const data = rule.selector\n ? getByPath(rawData, rule.selector)\n : rawData;\n context[rule.key] = data;\n }\n } else if (!rule.optional) {\n throw new Error(\n `Failed to fetch required data for key: ${rule.key || \"unknown\"}`,\n );\n }\n } catch (err) {\n if (!rule.optional) {\n throw err;\n }\n console.warn(`Optional request failed for rule:`, rule, err);\n }\n }\n\n return lastResult as T;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/chain.ts"],"sourcesContent":["/**\n * Request Chain Runner\n * 负责解析和执行通用的 HTTP 请求链 (Chain Execution)\n * 适用于任何需要链式 HTTP 请求编排的场景\n */\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\n/** Supported HTTP Methods */\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/** HTTP 请求参数 */\nexport interface HttpRequestSpec {\n method: HttpMethod;\n url: string;\n headers?: Record<string, string>;\n body?: any;\n}\n\n/**\n * 网络适配器接口\n * 定义实际发送请求的能力\n */\n/**\n * 网络适配器接口\n * 定义实际发送请求的能力\n */\nexport interface NetworkAdapter {\n get<T>(\n url: string,\n params?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n post<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n put?<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n delete?<T>(\n url: string,\n params?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n patch?<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n}\n\n/**\n * 网络处理器接口 (Strategy Pattern)\n * 组合了\"匹配规则\"和\"执行能力\"\n */\nexport interface NetworkHandler {\n /** 处理器名称 (用于调试) */\n name?: string;\n\n /** 判断该 URL 是否由此适配器处理 */\n shouldHandle(url: string, method: HttpMethod): boolean;\n\n /** 具体的网络适配器 */\n adapter: NetworkAdapter;\n}\n\n/**\n * 请求链规则 (Chain Step)\n */\nexport interface ChainRequestRule {\n /**\n * 结果存储的键名 (Context Key)\n * Fetch 结果存储: context[key] = response\n */\n key?: string;\n\n /**\n * HTTP 请求详情\n */\n request: HttpRequestSpec;\n\n /**\n * 数据提取选择器\n * 用于从响应中提取特定数据, e.g., \"elements.0\"\n */\n selector?: string;\n\n /** 是否允许请求失败 (默认 false) */\n optional?: boolean;\n}\n\n// ============================================================================\n// Internal Utilities\n// ============================================================================\n\n/**\n * 执行 HTTP 请求\n * 遍历 handlers 数组,找到第一个能处理该 URL 的适配器执行\n *\n * @param spec 请求详情\n * @param handlers 网络处理器链\n */\nasync function executeChainRequest<T>(\n spec: HttpRequestSpec,\n handlers: NetworkHandler[] = [],\n): Promise<T | null> {\n // Normalize method to upper case for robustness\n const method = spec.method.toUpperCase() as HttpMethod;\n\n // 1. 遍历处理器数组 (责任链)\n for (const handler of handlers) {\n if (handler.shouldHandle(spec.url, method)) {\n try {\n const { adapter } = handler;\n const headers = spec.headers;\n\n switch (method) {\n case \"GET\":\n return await adapter.get<T>(spec.url, spec.body, headers);\n case \"POST\":\n return await adapter.post<T>(spec.url, spec.body, headers);\n case \"PUT\":\n if (!adapter.put)\n throw new Error(`Adapter ${handler.name} missing PUT method`);\n return await adapter.put<T>(spec.url, spec.body, headers);\n case \"DELETE\":\n if (!adapter.delete)\n throw new Error(`Adapter ${handler.name} missing DELETE method`);\n return await adapter.delete<T>(spec.url, spec.body, headers);\n case \"PATCH\":\n if (!adapter.patch)\n throw new Error(`Adapter ${handler.name} missing PATCH method`);\n return await adapter.patch<T>(spec.url, spec.body, headers);\n default:\n throw new Error(`Unsupported method: ${method}`);\n }\n } catch (err) {\n console.warn(\n `Handler [${handler.name || \"Anonymous\"}] failed for ${spec.url}`,\n err,\n );\n // 如果需要继续尝试下一个 handler,可以在这里 continue,但通常由第一个匹配者全权负责\n return null;\n }\n }\n }\n\n // 2. 默认行为 (Fallback): 绝对路径自动走标准 fetch\n if (spec.url.startsWith(\"http://\") || spec.url.startsWith(\"https://\")) {\n return await executeFallbackFetch<T>(spec);\n }\n\n console.warn(`No handler found for url: ${spec.url}`);\n return null;\n}\n\n/**\n * 标准 Fetch 回退实现\n */\nasync function executeFallbackFetch<T>(\n spec: HttpRequestSpec,\n): Promise<T | null> {\n try {\n const response = await fetch(spec.url, {\n method: spec.method,\n headers: spec.headers,\n body: spec.body ? JSON.stringify(spec.body) : undefined,\n credentials: \"include\",\n });\n\n if (!response.ok) {\n console.log(`External Request failed: ${response.status} ${spec.url}`);\n return null;\n }\n\n return await response.json();\n } catch (err) {\n console.log(\"External Request error:\", err);\n return null;\n }\n}\n\n/**\n * 根据路径获取对象值\n */\nfunction getByPath(obj: any, path: string): any {\n if (!path) return obj;\n return path.split(\".\").reduce((acc, part) => acc && acc[part], obj);\n}\n\n/**\n * 变量替换 (Internal)\n * 支持字符串 {{key}} 和 {{key.prop}}\n */\nfunction substituteVariables(target: any, context: any): any {\n if (typeof target === \"string\") {\n // 1. 如果整个字符串就是一个变量占位符,例如 \"{{user}}\",则返回原始对象/值\n const directMatch = target.match(/^\\{\\{([\\w\\.]+)\\}\\}$/);\n if (directMatch) {\n const path = directMatch[1];\n const val = getByPath(context, path);\n return val !== undefined ? val : \"\";\n }\n\n // 2. 如果是混合字符串,例如 \"Hello {{user.name}}\",则执行字符串替换\n return target.replace(/\\{\\{([\\w\\.]+)\\}\\}/g, (_, path) => {\n const val = getByPath(context, path);\n return val !== undefined ? String(val) : \"\";\n });\n }\n\n if (Array.isArray(target)) {\n return target.map((item) => substituteVariables(item, context));\n }\n\n if (target && typeof target === \"object\") {\n const result: any = {};\n for (const key in target) {\n result[key] = substituteVariables(target[key], context);\n }\n return result;\n }\n\n return target;\n}\n\n// ============================================================================\n// Main Runner\n// ============================================================================\n\n/**\n * 请求链执行器 (Request Chain Engine)\n * 支持链式请求、上下文累积、智能路由、变量替换\n *\n * @param requests 链式执行规则列表\n * @param handlers 网络适配器处理器列表 (按顺序匹配)\n */\nexport async function executeRequestChain<T>(\n requests: ChainRequestRule[],\n handlers: NetworkHandler[] = [],\n getChainRequests?: (\n context: Record<string, any>,\n ) => ChainRequestRule[] | null | undefined,\n initContext?: Record<string, any>,\n): Promise<T> {\n const context: Record<string, any> = initContext || {};\n let lastResult: any = null;\n\n for (const rule of requests) {\n try {\n // 1. 变量替换 (支持从 Context 注入对象到 Request Body/URL/Headers)\n const requestSpec = substituteVariables(rule.request, context);\n\n // 2. 执行请求 (传入 handlers)\n let rawData = await executeChainRequest<any>(requestSpec, handlers);\n\n if (getChainRequests) {\n const chainRequests = getChainRequests(rawData);\n if (chainRequests && chainRequests.length > 0) {\n rawData = await executeRequestChain(\n chainRequests,\n handlers,\n getChainRequests,\n JSON.parse(JSON.stringify(context)),\n );\n }\n }\n\n lastResult = rawData;\n\n if (rawData) {\n // 5. 存储结果\n if (rule.key) {\n const data = rule.selector\n ? getByPath(rawData, rule.selector)\n : rawData;\n context[rule.key] = data;\n }\n } else if (!rule.optional) {\n throw new Error(\n `Failed to fetch required data for key: ${rule.key || \"unknown\"}`,\n );\n }\n } catch (err) {\n if (!rule.optional) {\n throw err;\n }\n console.warn(`Optional request failed for rule:`, rule, err);\n }\n }\n\n return lastResult as T;\n}\n"],"mappings":"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","names":[]}
|
package/dist/chain.mjs
CHANGED
|
@@ -65,6 +65,12 @@ function getByPath(obj, path) {
|
|
|
65
65
|
}
|
|
66
66
|
function substituteVariables(target, context) {
|
|
67
67
|
if (typeof target === "string") {
|
|
68
|
+
const directMatch = target.match(/^\{\{([\w\.]+)\}\}$/);
|
|
69
|
+
if (directMatch) {
|
|
70
|
+
const path = directMatch[1];
|
|
71
|
+
const val = getByPath(context, path);
|
|
72
|
+
return val !== void 0 ? val : "";
|
|
73
|
+
}
|
|
68
74
|
return target.replace(/\{\{([\w\.]+)\}\}/g, (_, path) => {
|
|
69
75
|
const val = getByPath(context, path);
|
|
70
76
|
return val !== void 0 ? String(val) : "";
|
|
@@ -87,23 +93,7 @@ async function executeRequestChain(requests, handlers = [], getChainRequests, in
|
|
|
87
93
|
let lastResult = null;
|
|
88
94
|
for (const rule of requests) {
|
|
89
95
|
try {
|
|
90
|
-
|
|
91
|
-
if (rule.pickContext) {
|
|
92
|
-
rule.pickContext.forEach((key) => {
|
|
93
|
-
if (key in context) contextData[key] = context[key];
|
|
94
|
-
});
|
|
95
|
-
} else if (rule.includeContext) {
|
|
96
|
-
contextData = context;
|
|
97
|
-
}
|
|
98
|
-
const hasContextData = Object.keys(contextData).length > 0;
|
|
99
|
-
let requestSpec = { ...rule.request };
|
|
100
|
-
if (hasContextData) {
|
|
101
|
-
requestSpec.body = {
|
|
102
|
-
...contextData,
|
|
103
|
-
...requestSpec.body || {}
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
requestSpec = substituteVariables(requestSpec, context);
|
|
96
|
+
const requestSpec = substituteVariables(rule.request, context);
|
|
107
97
|
let rawData = await executeChainRequest(requestSpec, handlers);
|
|
108
98
|
if (getChainRequests) {
|
|
109
99
|
const chainRequests = getChainRequests(rawData);
|
|
@@ -140,4 +130,4 @@ async function executeRequestChain(requests, handlers = [], getChainRequests, in
|
|
|
140
130
|
export {
|
|
141
131
|
executeRequestChain
|
|
142
132
|
};
|
|
143
|
-
//# sourceMappingURL=chunk-
|
|
133
|
+
//# sourceMappingURL=chunk-2OSF7OWV.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/chain.ts"],"sourcesContent":["/**\n * Request Chain Runner\n * 负责解析和执行通用的 HTTP 请求链 (Chain Execution)\n * 适用于任何需要链式 HTTP 请求编排的场景\n */\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\n/** Supported HTTP Methods */\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/** HTTP 请求参数 */\nexport interface HttpRequestSpec {\n method: HttpMethod;\n url: string;\n headers?: Record<string, string>;\n body?: any;\n}\n\n/**\n * 网络适配器接口\n * 定义实际发送请求的能力\n */\n/**\n * 网络适配器接口\n * 定义实际发送请求的能力\n */\nexport interface NetworkAdapter {\n get<T>(\n url: string,\n params?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n post<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n put?<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n delete?<T>(\n url: string,\n params?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n patch?<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n}\n\n/**\n * 网络处理器接口 (Strategy Pattern)\n * 组合了\"匹配规则\"和\"执行能力\"\n */\nexport interface NetworkHandler {\n /** 处理器名称 (用于调试) */\n name?: string;\n\n /** 判断该 URL 是否由此适配器处理 */\n shouldHandle(url: string, method: HttpMethod): boolean;\n\n /** 具体的网络适配器 */\n adapter: NetworkAdapter;\n}\n\n/**\n * 请求链规则 (Chain Step)\n */\nexport interface ChainRequestRule {\n /**\n * 结果存储的键名 (Context Key)\n * Fetch 结果存储: context[key] = response\n */\n key?: string;\n\n /**\n * HTTP 请求详情\n */\n request: HttpRequestSpec;\n\n /**\n * 数据提取选择器\n * 用于从响应中提取特定数据, e.g., \"elements.0\"\n */\n selector?: string;\n\n /** 是否允许请求失败 (默认 false) */\n optional?: boolean;\n}\n\n// ============================================================================\n// Internal Utilities\n// ============================================================================\n\n/**\n * 执行 HTTP 请求\n * 遍历 handlers 数组,找到第一个能处理该 URL 的适配器执行\n *\n * @param spec 请求详情\n * @param handlers 网络处理器链\n */\nasync function executeChainRequest<T>(\n spec: HttpRequestSpec,\n handlers: NetworkHandler[] = [],\n): Promise<T | null> {\n // Normalize method to upper case for robustness\n const method = spec.method.toUpperCase() as HttpMethod;\n\n // 1. 遍历处理器数组 (责任链)\n for (const handler of handlers) {\n if (handler.shouldHandle(spec.url, method)) {\n try {\n const { adapter } = handler;\n const headers = spec.headers;\n\n switch (method) {\n case \"GET\":\n return await adapter.get<T>(spec.url, spec.body, headers);\n case \"POST\":\n return await adapter.post<T>(spec.url, spec.body, headers);\n case \"PUT\":\n if (!adapter.put)\n throw new Error(`Adapter ${handler.name} missing PUT method`);\n return await adapter.put<T>(spec.url, spec.body, headers);\n case \"DELETE\":\n if (!adapter.delete)\n throw new Error(`Adapter ${handler.name} missing DELETE method`);\n return await adapter.delete<T>(spec.url, spec.body, headers);\n case \"PATCH\":\n if (!adapter.patch)\n throw new Error(`Adapter ${handler.name} missing PATCH method`);\n return await adapter.patch<T>(spec.url, spec.body, headers);\n default:\n throw new Error(`Unsupported method: ${method}`);\n }\n } catch (err) {\n console.warn(\n `Handler [${handler.name || \"Anonymous\"}] failed for ${spec.url}`,\n err,\n );\n // 如果需要继续尝试下一个 handler,可以在这里 continue,但通常由第一个匹配者全权负责\n return null;\n }\n }\n }\n\n // 2. 默认行为 (Fallback): 绝对路径自动走标准 fetch\n if (spec.url.startsWith(\"http://\") || spec.url.startsWith(\"https://\")) {\n return await executeFallbackFetch<T>(spec);\n }\n\n console.warn(`No handler found for url: ${spec.url}`);\n return null;\n}\n\n/**\n * 标准 Fetch 回退实现\n */\nasync function executeFallbackFetch<T>(\n spec: HttpRequestSpec,\n): Promise<T | null> {\n try {\n const response = await fetch(spec.url, {\n method: spec.method,\n headers: spec.headers,\n body: spec.body ? JSON.stringify(spec.body) : undefined,\n credentials: \"include\",\n });\n\n if (!response.ok) {\n console.log(`External Request failed: ${response.status} ${spec.url}`);\n return null;\n }\n\n return await response.json();\n } catch (err) {\n console.log(\"External Request error:\", err);\n return null;\n }\n}\n\n/**\n * 根据路径获取对象值\n */\nfunction getByPath(obj: any, path: string): any {\n if (!path) return obj;\n return path.split(\".\").reduce((acc, part) => acc && acc[part], obj);\n}\n\n/**\n * 变量替换 (Internal)\n * 支持字符串 {{key}} 和 {{key.prop}}\n */\nfunction substituteVariables(target: any, context: any): any {\n if (typeof target === \"string\") {\n // 1. 如果整个字符串就是一个变量占位符,例如 \"{{user}}\",则返回原始对象/值\n const directMatch = target.match(/^\\{\\{([\\w\\.]+)\\}\\}$/);\n if (directMatch) {\n const path = directMatch[1];\n const val = getByPath(context, path);\n return val !== undefined ? val : \"\";\n }\n\n // 2. 如果是混合字符串,例如 \"Hello {{user.name}}\",则执行字符串替换\n return target.replace(/\\{\\{([\\w\\.]+)\\}\\}/g, (_, path) => {\n const val = getByPath(context, path);\n return val !== undefined ? String(val) : \"\";\n });\n }\n\n if (Array.isArray(target)) {\n return target.map((item) => substituteVariables(item, context));\n }\n\n if (target && typeof target === \"object\") {\n const result: any = {};\n for (const key in target) {\n result[key] = substituteVariables(target[key], context);\n }\n return result;\n }\n\n return target;\n}\n\n// ============================================================================\n// Main Runner\n// ============================================================================\n\n/**\n * 请求链执行器 (Request Chain Engine)\n * 支持链式请求、上下文累积、智能路由、变量替换\n *\n * @param requests 链式执行规则列表\n * @param handlers 网络适配器处理器列表 (按顺序匹配)\n */\nexport async function executeRequestChain<T>(\n requests: ChainRequestRule[],\n handlers: NetworkHandler[] = [],\n getChainRequests?: (\n context: Record<string, any>,\n ) => ChainRequestRule[] | null | undefined,\n initContext?: Record<string, any>,\n): Promise<T> {\n const context: Record<string, any> = initContext || {};\n let lastResult: any = null;\n\n for (const rule of requests) {\n try {\n // 1. 变量替换 (支持从 Context 注入对象到 Request Body/URL/Headers)\n const requestSpec = substituteVariables(rule.request, context);\n\n // 2. 执行请求 (传入 handlers)\n let rawData = await executeChainRequest<any>(requestSpec, handlers);\n\n if (getChainRequests) {\n const chainRequests = getChainRequests(rawData);\n if (chainRequests && chainRequests.length > 0) {\n rawData = await executeRequestChain(\n chainRequests,\n handlers,\n getChainRequests,\n JSON.parse(JSON.stringify(context)),\n );\n }\n }\n\n lastResult = rawData;\n\n if (rawData) {\n // 5. 存储结果\n if (rule.key) {\n const data = rule.selector\n ? getByPath(rawData, rule.selector)\n : rawData;\n context[rule.key] = data;\n }\n } else if (!rule.optional) {\n throw new Error(\n `Failed to fetch required data for key: ${rule.key || \"unknown\"}`,\n );\n }\n } catch (err) {\n if (!rule.optional) {\n throw err;\n }\n console.warn(`Optional request failed for rule:`, rule, err);\n }\n }\n\n return lastResult as T;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/secure.js","../src/protobuf.ts"],"sourcesContent":["/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/\nimport * as $protobuf from \"protobufjs/minimal\";\n\n// Common aliases\nconst $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;\n\n// Exported root namespace\nconst $root = $protobuf.roots[\"default\"] || ($protobuf.roots[\"default\"] = {});\n\nexport const secure = $root.secure = (() => {\n\n /**\n * Namespace secure.\n * @exports secure\n * @namespace\n */\n const secure = {};\n\n secure.SecurePayload = (function() {\n\n /**\n * Properties of a SecurePayload.\n * @memberof secure\n * @interface ISecurePayload\n * @property {number|Long|null} [ts] SecurePayload ts\n * @property {Uint8Array|null} [data] SecurePayload data\n */\n\n /**\n * Constructs a new SecurePayload.\n * @memberof secure\n * @classdesc Represents a SecurePayload.\n * @implements ISecurePayload\n * @constructor\n * @param {secure.ISecurePayload=} [properties] Properties to set\n */\n function SecurePayload(properties) {\n if (properties)\n for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)\n if (properties[keys[i]] != null)\n this[keys[i]] = properties[keys[i]];\n }\n\n /**\n * SecurePayload ts.\n * @member {number|Long} ts\n * @memberof secure.SecurePayload\n * @instance\n */\n SecurePayload.prototype.ts = $util.Long ? $util.Long.fromBits(0,0,false) : 0;\n\n /**\n * SecurePayload data.\n * @member {Uint8Array} data\n * @memberof secure.SecurePayload\n * @instance\n */\n SecurePayload.prototype.data = $util.newBuffer([]);\n\n /**\n * Creates a new SecurePayload instance using the specified properties.\n * @function create\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload=} [properties] Properties to set\n * @returns {secure.SecurePayload} SecurePayload instance\n */\n SecurePayload.create = function create(properties) {\n return new SecurePayload(properties);\n };\n\n /**\n * Encodes the specified SecurePayload message. Does not implicitly {@link secure.SecurePayload.verify|verify} messages.\n * @function encode\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload} message SecurePayload message or plain object to encode\n * @param {$protobuf.Writer} [writer] Writer to encode to\n * @returns {$protobuf.Writer} Writer\n */\n SecurePayload.encode = function encode(message, writer) {\n if (!writer)\n writer = $Writer.create();\n if (message.ts != null && Object.hasOwnProperty.call(message, \"ts\"))\n writer.uint32(/* id 1, wireType 0 =*/8).int64(message.ts);\n if (message.data != null && Object.hasOwnProperty.call(message, \"data\"))\n writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.data);\n return writer;\n };\n\n /**\n * Encodes the specified SecurePayload message, length delimited. Does not implicitly {@link secure.SecurePayload.verify|verify} messages.\n * @function encodeDelimited\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload} message SecurePayload message or plain object to encode\n * @param {$protobuf.Writer} [writer] Writer to encode to\n * @returns {$protobuf.Writer} Writer\n */\n SecurePayload.encodeDelimited = function encodeDelimited(message, writer) {\n return this.encode(message, writer).ldelim();\n };\n\n /**\n * Decodes a SecurePayload message from the specified reader or buffer.\n * @function decode\n * @memberof secure.SecurePayload\n * @static\n * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from\n * @param {number} [length] Message length if known beforehand\n * @returns {secure.SecurePayload} SecurePayload\n * @throws {Error} If the payload is not a reader or valid buffer\n * @throws {$protobuf.util.ProtocolError} If required fields are missing\n */\n SecurePayload.decode = function decode(reader, length, error) {\n if (!(reader instanceof $Reader))\n reader = $Reader.create(reader);\n let end = length === undefined ? reader.len : reader.pos + length, message = new $root.secure.SecurePayload();\n while (reader.pos < end) {\n let tag = reader.uint32();\n if (tag === error)\n break;\n switch (tag >>> 3) {\n case 1: {\n message.ts = reader.int64();\n break;\n }\n case 2: {\n message.data = reader.bytes();\n break;\n }\n default:\n reader.skipType(tag & 7);\n break;\n }\n }\n return message;\n };\n\n /**\n * Decodes a SecurePayload message from the specified reader or buffer, length delimited.\n * @function decodeDelimited\n * @memberof secure.SecurePayload\n * @static\n * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from\n * @returns {secure.SecurePayload} SecurePayload\n * @throws {Error} If the payload is not a reader or valid buffer\n * @throws {$protobuf.util.ProtocolError} If required fields are missing\n */\n SecurePayload.decodeDelimited = function decodeDelimited(reader) {\n if (!(reader instanceof $Reader))\n reader = new $Reader(reader);\n return this.decode(reader, reader.uint32());\n };\n\n /**\n * Verifies a SecurePayload message.\n * @function verify\n * @memberof secure.SecurePayload\n * @static\n * @param {Object.<string,*>} message Plain object to verify\n * @returns {string|null} `null` if valid, otherwise the reason why it is not\n */\n SecurePayload.verify = function verify(message) {\n if (typeof message !== \"object\" || message === null)\n return \"object expected\";\n if (message.ts != null && message.hasOwnProperty(\"ts\"))\n if (!$util.isInteger(message.ts) && !(message.ts && $util.isInteger(message.ts.low) && $util.isInteger(message.ts.high)))\n return \"ts: integer|Long expected\";\n if (message.data != null && message.hasOwnProperty(\"data\"))\n if (!(message.data && typeof message.data.length === \"number\" || $util.isString(message.data)))\n return \"data: buffer expected\";\n return null;\n };\n\n /**\n * Creates a SecurePayload message from a plain object. Also converts values to their respective internal types.\n * @function fromObject\n * @memberof secure.SecurePayload\n * @static\n * @param {Object.<string,*>} object Plain object\n * @returns {secure.SecurePayload} SecurePayload\n */\n SecurePayload.fromObject = function fromObject(object) {\n if (object instanceof $root.secure.SecurePayload)\n return object;\n let message = new $root.secure.SecurePayload();\n if (object.ts != null)\n if ($util.Long)\n (message.ts = $util.Long.fromValue(object.ts)).unsigned = false;\n else if (typeof object.ts === \"string\")\n message.ts = parseInt(object.ts, 10);\n else if (typeof object.ts === \"number\")\n message.ts = object.ts;\n else if (typeof object.ts === \"object\")\n message.ts = new $util.LongBits(object.ts.low >>> 0, object.ts.high >>> 0).toNumber();\n if (object.data != null)\n if (typeof object.data === \"string\")\n $util.base64.decode(object.data, message.data = $util.newBuffer($util.base64.length(object.data)), 0);\n else if (object.data.length >= 0)\n message.data = object.data;\n return message;\n };\n\n /**\n * Creates a plain object from a SecurePayload message. Also converts values to other types if specified.\n * @function toObject\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.SecurePayload} message SecurePayload\n * @param {$protobuf.IConversionOptions} [options] Conversion options\n * @returns {Object.<string,*>} Plain object\n */\n SecurePayload.toObject = function toObject(message, options) {\n if (!options)\n options = {};\n let object = {};\n if (options.defaults) {\n if ($util.Long) {\n let long = new $util.Long(0, 0, false);\n object.ts = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;\n } else\n object.ts = options.longs === String ? \"0\" : 0;\n if (options.bytes === String)\n object.data = \"\";\n else {\n object.data = [];\n if (options.bytes !== Array)\n object.data = $util.newBuffer(object.data);\n }\n }\n if (message.ts != null && message.hasOwnProperty(\"ts\"))\n if (typeof message.ts === \"number\")\n object.ts = options.longs === String ? String(message.ts) : message.ts;\n else\n object.ts = options.longs === String ? $util.Long.prototype.toString.call(message.ts) : options.longs === Number ? new $util.LongBits(message.ts.low >>> 0, message.ts.high >>> 0).toNumber() : message.ts;\n if (message.data != null && message.hasOwnProperty(\"data\"))\n object.data = options.bytes === String ? $util.base64.encode(message.data, 0, message.data.length) : options.bytes === Array ? Array.prototype.slice.call(message.data) : message.data;\n return object;\n };\n\n /**\n * Converts this SecurePayload to JSON.\n * @function toJSON\n * @memberof secure.SecurePayload\n * @instance\n * @returns {Object.<string,*>} JSON object\n */\n SecurePayload.prototype.toJSON = function toJSON() {\n return this.constructor.toObject(this, $protobuf.util.toJSONOptions);\n };\n\n /**\n * Gets the default type url for SecurePayload\n * @function getTypeUrl\n * @memberof secure.SecurePayload\n * @static\n * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default \"type.googleapis.com\")\n * @returns {string} The default type url\n */\n SecurePayload.getTypeUrl = function getTypeUrl(typeUrlPrefix) {\n if (typeUrlPrefix === undefined) {\n typeUrlPrefix = \"type.googleapis.com\";\n }\n return typeUrlPrefix + \"/secure.SecurePayload\";\n };\n\n return SecurePayload;\n })();\n\n return secure;\n})();\n\nexport { $root as default };\n","/**\n * Protobuf 安全通信模块\n *\n * 提供基于 Protobuf 的二进制序列化、XOR 混淆加密以及与 API Client 的无缝集成。\n */\n\nimport protobuf from \"protobufjs/light\";\nimport { secure } from \"./secure.js\";\nimport type { FetchContext } from \"ofetch\";\n\n// ============================================================================\n// 1. 类型定义 (Types)\n// ============================================================================\n// export type ProtobufTypeLike = Pick<protobuf.Type, \"create\" | \"encode\" | \"decode\" | \"toObject\">;\nexport interface ProtobufTypeLike {\n // 1. 允许 properties 为任何对象,返回结果不再强制要求 $type\n create(properties?: Record<string, any>): any;\n // 2. 借用原生的参数类型约束,但手动简化返回类型\n encode(message: any): { finish(): Uint8Array };\n // 3. 借用原生的 decode 签名(支持 Uint8Array 和 Reader)\n decode(reader: Uint8Array | protobuf.Reader): any;\n // 4. 借用原生的 toObject 签名,保留 IConversionOptions 的类型检查\n toObject(message: any, options?: protobuf.IConversionOptions): any;\n}\n/**\n * 二进制混淆接口\n * 允许外部定义混淆逻辑,以便与不同语言实现的后端兼容\n */\nexport interface ProtobufObfuscator {\n encrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;\n decrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;\n}\n\n/**\n * Protobuf 编解码集成配置项\n * 用于控制序列化、混淆、钩子集成等全流程\n */\nexport interface ProtobufOptions {\n /**\n * 混淆器实现\n * 提供该选项时才会启用混淆\n */\n obfuscator?: ProtobufObfuscator;\n /** 预编译的 Protobuf 类型对象 (推荐,性能最高) */\n protoType?: ProtobufTypeLike;\n /** 数据转换钩子:处理业务模型与 Proto 结构不一致的情况 */\n transform?: {\n beforeEncode?: (data: any) => any;\n afterDecode?: (payload: any) => any;\n };\n /** 外部定义的编码逻辑 (返回原始二进制) */\n encode?: (data: any) => Uint8Array | Promise<Uint8Array>;\n /** 外部定义的解码逻辑 (返回原始对象) */\n decode?: <T>(buffer: Uint8Array) => T | Promise<T>;\n}\n\nexport const PROTOBUF_CONTENT_TYPE = \"application/x-protobuf\";\n\n/** 检查是否为 Protobuf 响应头 */\nexport function isProtobufContentType(contentType: string | null): boolean {\n return !!contentType?.toLowerCase().includes(PROTOBUF_CONTENT_TYPE);\n}\n\n/**\n * 获取 Protobuf 相关的 Header 配置对象\n */\nexport function getProtobufHeaders({\n send = true,\n receive = true,\n}: {\n send?: boolean;\n receive?: boolean;\n} = {}): Record<string, string> {\n const headers: Record<string, string> = {};\n\n if (send) {\n headers[\"Content-Type\"] = PROTOBUF_CONTENT_TYPE;\n }\n\n if (receive) {\n headers[\"Accept\"] = PROTOBUF_CONTENT_TYPE;\n }\n\n return headers;\n}\n\n/**\n * API Client 内部使用的标准化配置\n */\n// export interface ProtobufConfig {\n// encode: (data: any) => Uint8Array | Promise<Uint8Array>;\n// decode: <T>(buffer: Uint8Array) => T | Promise<T>;\n// options?: ProtobufCodecOptions;\n// }\n\n// ============================================================================\n// 2. 内部工具函数 (Internal Utilities)\n// ============================================================================\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/** 简单的二进制异或混淆转换 */\nexport function xorTransform(\n data: Uint8Array,\n key: string | Uint8Array,\n): Uint8Array {\n const keyBytes = typeof key === \"string\" ? encoder.encode(key) : key;\n if (keyBytes.length === 0) return data;\n\n for (let i = 0; i < data.length; i++) {\n data[i] ^= keyBytes[i % keyBytes.length];\n }\n return data;\n}\n\n/** 创建一个简单的 XOR 混淆器 */\nexport function createXorObfuscator(\n key: string | Uint8Array,\n): ProtobufObfuscator {\n return {\n encrypt: (data) => xorTransform(data, key),\n decrypt: (data) => xorTransform(data, key),\n };\n}\n\n/** 获取内置的 SecurePayload 类型(使用预编译代码) */\nfunction getInternalSecureType(): protobuf.Type {\n return secure.SecurePayload as unknown as protobuf.Type;\n}\n\n// ============================================================================\n// 3. 核心编解码逻辑 (Core Codecs)\n// ============================================================================\n\n/**\n * 编码安全载荷\n *\n * 流程:业务数据 -> (自定义编码 / Proto 序列化) -> 二进制混淆\n */\nexport async function encodeSecure<T>(\n data: T,\n options: ProtobufOptions = {},\n): Promise<Uint8Array> {\n const { obfuscator, protoType, transform, encode: customEncode } = options;\n\n let buffer: Uint8Array;\n\n // 1. 预处理阶段:无论后续走哪条路径,只要定义了 beforeEncode 就先执行\n const processedData = transform?.beforeEncode\n ? transform.beforeEncode(data)\n : data;\n\n // 1. 序列化阶段\n if (customEncode) {\n buffer = await customEncode(processedData);\n } else {\n const type = protoType || getInternalSecureType();\n\n // 构造最终要交给 Protobuf 序列化的对象\n const payload = protoType\n ? processedData // 自定义模式:直接使用预处理后的数据\n : {\n // 默认容器模式:将预处理后的数据封装进信封\n ts: Date.now(),\n data:\n processedData instanceof Uint8Array\n ? processedData\n : encoder.encode(JSON.stringify(processedData)),\n };\n\n const message = type.create(payload);\n buffer = type.encode(message).finish();\n }\n\n // 2. 混淆阶段\n if (obfuscator) {\n return await obfuscator.encrypt(buffer);\n }\n return buffer;\n}\n\n/**\n * 解码安全载荷\n *\n * 流程:二进制流 -> 二进制反混淆 -> (自定义解码 / Proto 反序列化) -> 业务数据\n */\nexport async function decodeSecure<T>(\n buffer: Uint8Array | ArrayBuffer,\n options: ProtobufOptions = {},\n): Promise<T> {\n const { obfuscator, protoType, transform, decode: customDecode } = options;\n\n // let uint8 = buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : buffer;\n // let uint8 =\n // buffer instanceof ArrayBuffer\n // ? new Uint8Array(buffer)\n // : new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n\n // 1. 标准化为 Uint8Array 视图 (跨环境最稳写法)\n let uint8 = ArrayBuffer.isView(buffer)\n ? new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength)\n : new Uint8Array(buffer);\n\n if (uint8.length === 0) {\n return null as T; // 或者返回 {},根据业务定\n }\n\n // 1. 混淆阶段\n if (uint8.length > 0 && obfuscator) {\n uint8 = await obfuscator.decrypt(uint8);\n }\n\n // 2. 反序列化阶段\n if (customDecode) {\n return await customDecode<T>(uint8);\n }\n\n const type = protoType || getInternalSecureType();\n const decoded = type.decode(uint8);\n const plainObj = type.toObject(decoded, {\n longs: String,\n enums: String,\n bytes: Uint8Array as any,\n defaults: true,\n });\n\n // 3. 转换阶段\n if (transform?.afterDecode) {\n return transform.afterDecode(plainObj);\n }\n\n // 内置容器模式的额外还原逻辑\n if (!protoType && plainObj.data) {\n const jsonString = decoder.decode(plainObj.data as Uint8Array);\n try {\n return JSON.parse(jsonString) as T;\n } catch {\n return jsonString as unknown as T;\n }\n }\n\n return plainObj as T;\n}\n\n// ============================================================================\n// 4. HTTP/环境适配工具 (HTTP Tools)\n// ============================================================================\n\n/** 创建安全响应 (Worker/Server 端使用) */\nexport async function secureResponse<T>(\n data: T,\n options?: ProtobufOptions & { corsHeaders?: Record<string, string> },\n): Promise<Response> {\n const buffer = await encodeSecure(data, options);\n // const arrayBuffer = buffer.buffer.slice(\n // buffer.byteOffset,\n // buffer.byteOffset + buffer.byteLength,\n // ) as ArrayBuffer;\n const cleanBuffer = buffer.slice();\n\n return new Response(cleanBuffer, {\n headers: {\n ...getProtobufHeaders({ send: true }),\n ...options?.corsHeaders,\n },\n });\n}\n\n/** * 解析安全请求体 (Worker/Server 端使用)\n * @param request 原生 Request 对象\n * @param options 编解码配置(可包含当前接口对应的 protoType 和自定义 obfuscator)\n */\nexport async function parseSecureRequest<T>(\n request: Request,\n options: ProtobufOptions = {}, // 统一使用这个配置对象\n): Promise<T> {\n const buffer = await request.arrayBuffer();\n return decodeSecure<T>(buffer, options);\n}\n\n/** 标准化配置对象 */\n// export function normalizeProtobufConfig(\n// config: boolean | ProtobufConfig | undefined,\n// options?: ProtobufHooksOptions, // 接收全局配置\n// ): ProtobufConfig | null {\n// if (!config) return null;\n// if (config === true) {\n// return {\n// encode: (data) => encodeSecure(data, options),\n// decode: <T>(buffer: Uint8Array) => decodeSecure<T>(buffer, options),\n// options,\n// };\n// }\n// return config;\n// }\n\n// ============================================================================\n// 5. API Client 钩子逻辑 (Integration Hooks)\n// ============================================================================\n\n/** 创建 Protobuf 编解码钩子 (用于与 createApiClient 配合使用) */\nexport function createProtobufHooks(globalOptions: ProtobufOptions = {}) {\n // const encode = (data: any) => encodeSecure(data, globalOptions);\n // const decode = <T>(buffer: Uint8Array) => decodeSecure<T>(buffer, globalOptions);\n\n return {\n async onRequest(context: FetchContext) {\n const { options: reqOptions } = context;\n\n // 1. 动态合并配置:将全局 globalOptions 和单次请求传的 reqOptions 合并\n // 这确保了 encodeSecure 能拿到当前请求特有的 protoType 或 transform\n const mergedOptions: ProtobufOptions = {\n ...globalOptions,\n ...reqOptions,\n };\n\n const headers =\n reqOptions.headers instanceof Headers\n ? reqOptions.headers\n : new Headers(reqOptions.headers as HeadersInit | undefined);\n\n // 自动编码请求体\n if (\n isProtobufContentType(headers.get(\"Content-Type\")) &&\n reqOptions.body &&\n !(reqOptions.body instanceof Uint8Array)\n ) {\n reqOptions.body = await encodeSecure(reqOptions.body, mergedOptions);\n }\n\n // 自动设置期望响应类型\n if (\n isProtobufContentType(headers.get(\"Accept\")) &&\n !reqOptions.responseType\n ) {\n reqOptions.responseType = \"arrayBuffer\";\n }\n\n reqOptions.headers = headers;\n },\n\n async onResponse(context: FetchContext) {\n const { response, options: reqOptions } = context;\n if (!response?._data || response.status === 204) return;\n\n // 同样在响应阶段合并 options,以获取单次请求指定的 protoType 来解码\n const mergedOptions: ProtobufOptions = {\n ...globalOptions,\n ...reqOptions,\n };\n\n if (isProtobufContentType(response.headers.get(\"Content-Type\"))) {\n try {\n // 这里的 _data 可能是 ArrayBuffer (浏览器) 或 Buffer (Node)\n // decodeSecure 内部已处理好兼容性\n response._data = await decodeSecure(response._data, mergedOptions);\n // const buffer = response._data as ArrayBuffer;\n // if (buffer && buffer.byteLength > 0) {\n // response._data = await decode(new Uint8Array(buffer));\n // }\n } catch (e) {\n console.log(\"Error [Protobuf Decode Error]\", e);\n response._data = null;\n }\n } else if (response._data instanceof ArrayBuffer) {\n const text = decoder.decode(response._data);\n try {\n response._data = JSON.parse(text);\n } catch {\n response._data = text;\n }\n }\n },\n };\n}\n"],"mappings":"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","names":["secure"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { ApiError, ApiResult, CreateApiClientOptions, TokenStorage, createApiClient, isApiError } from './client.mjs';
|
|
2
2
|
export { ChainRequestRule, HttpRequestSpec, NetworkAdapter, NetworkHandler, executeRequestChain } from './chain.mjs';
|
|
3
|
-
export { PROTOBUF_CONTENT_TYPE,
|
|
3
|
+
export { PROTOBUF_CONTENT_TYPE, ProtobufObfuscator, ProtobufOptions, ProtobufTypeLike, createProtobufHooks, createXorObfuscator, decodeSecure, encodeSecure, getProtobufHeaders, isProtobufContentType, parseSecureRequest, secureResponse, xorTransform } from './protobuf.mjs';
|
|
4
4
|
import 'ofetch';
|
|
5
5
|
import 'protobufjs/light';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { ApiError, ApiResult, CreateApiClientOptions, TokenStorage, createApiClient, isApiError } from './client.js';
|
|
2
2
|
export { ChainRequestRule, HttpRequestSpec, NetworkAdapter, NetworkHandler, executeRequestChain } from './chain.js';
|
|
3
|
-
export { PROTOBUF_CONTENT_TYPE,
|
|
3
|
+
export { PROTOBUF_CONTENT_TYPE, ProtobufObfuscator, ProtobufOptions, ProtobufTypeLike, createProtobufHooks, createXorObfuscator, decodeSecure, encodeSecure, getProtobufHeaders, isProtobufContentType, parseSecureRequest, secureResponse, xorTransform } from './protobuf.js';
|
|
4
4
|
import 'ofetch';
|
|
5
5
|
import 'protobufjs/light';
|
package/dist/index.js
CHANGED
|
@@ -288,6 +288,12 @@ function getByPath(obj, path) {
|
|
|
288
288
|
}
|
|
289
289
|
function substituteVariables(target, context) {
|
|
290
290
|
if (typeof target === "string") {
|
|
291
|
+
const directMatch = target.match(/^\{\{([\w\.]+)\}\}$/);
|
|
292
|
+
if (directMatch) {
|
|
293
|
+
const path = directMatch[1];
|
|
294
|
+
const val = getByPath(context, path);
|
|
295
|
+
return val !== void 0 ? val : "";
|
|
296
|
+
}
|
|
291
297
|
return target.replace(/\{\{([\w\.]+)\}\}/g, (_, path) => {
|
|
292
298
|
const val = getByPath(context, path);
|
|
293
299
|
return val !== void 0 ? String(val) : "";
|
|
@@ -310,23 +316,7 @@ async function executeRequestChain(requests, handlers = [], getChainRequests, in
|
|
|
310
316
|
let lastResult = null;
|
|
311
317
|
for (const rule of requests) {
|
|
312
318
|
try {
|
|
313
|
-
|
|
314
|
-
if (rule.pickContext) {
|
|
315
|
-
rule.pickContext.forEach((key) => {
|
|
316
|
-
if (key in context) contextData[key] = context[key];
|
|
317
|
-
});
|
|
318
|
-
} else if (rule.includeContext) {
|
|
319
|
-
contextData = context;
|
|
320
|
-
}
|
|
321
|
-
const hasContextData = Object.keys(contextData).length > 0;
|
|
322
|
-
let requestSpec = { ...rule.request };
|
|
323
|
-
if (hasContextData) {
|
|
324
|
-
requestSpec.body = {
|
|
325
|
-
...contextData,
|
|
326
|
-
...requestSpec.body || {}
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
requestSpec = substituteVariables(requestSpec, context);
|
|
319
|
+
const requestSpec = substituteVariables(rule.request, context);
|
|
330
320
|
let rawData = await executeChainRequest(requestSpec, handlers);
|
|
331
321
|
if (getChainRequests) {
|
|
332
322
|
const chainRequests = getChainRequests(rawData);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/chain.ts","../src/secure.js","../src/protobuf.ts"],"sourcesContent":["export * from \"./client\";\nexport * from \"./chain\";\nexport * from \"./protobuf\";\n","import {\n ofetch,\n type FetchOptions,\n type FetchContext,\n type $Fetch,\n} from \"ofetch\";\n\nexport interface ApiResult<T> {\n code: number;\n data: T;\n message: string;\n}\n\nexport interface ApiError extends Error {\n code: number; // 业务错误码\n data?: unknown; // 后端返回的 data 字段(如果有)\n status?: number; // HTTP 状态码(网络错误时)\n}\n\n// 类型守卫:判断是否是 API 业务错误\nexport const isApiError = (error: unknown): error is ApiError => {\n return error instanceof Error && \"code\" in error;\n};\n\nexport interface TokenStorage {\n getAccessToken: () => Promise<string> | string;\n setAccessToken: (token: string) => Promise<void> | void;\n}\n\nexport interface CreateApiClientOptions {\n baseURL: string;\n tokenStorage: TokenStorage;\n refreshToken?: (() => Promise<string>) | string | false;\n retry?: number; // 重试次数,默认 1\n retryDelay?: number; // 重试间隔,默认 1s\n isAuthError?: (code: number) => boolean;\n unwrapResponse?<T>(result: unknown, returnFullResponse: boolean): T;\n createErrorFromResult?(res: unknown): Error;\n /**\n * 自定义请求钩子\n * 在请求发送前执行,可用于编码请求体等\n */\n onRequest?: (context: FetchContext) => void | Promise<void>;\n /**\n * 自定义响应钩子\n * 在响应返回后执行,可用于解码响应体等\n */\n onResponse?: (context: FetchContext) => void | Promise<void>;\n}\n\ntype RequestOptions = Omit<FetchOptions<\"json\">, \"responseType\"> & {\n returnFullResponse?: boolean;\n responseType?: \"json\" | \"arrayBuffer\" | \"text\" | \"blob\";\n};\n\n// 解包后端统一响应格式(默认实现)\nconst defaultUnwrapResponse = <T>(\n result: unknown,\n returnFullResponse = false,\n): T => {\n if (result && typeof result === \"object\" && \"code\" in result) {\n const body = result as Record<string, unknown>;\n if (body.code === 0) {\n return returnFullResponse ? (body as T) : (body.data as T);\n }\n }\n return result as T;\n};\n\nconst defaultCreateErrorFromResult = (res: ApiResult<unknown>): ApiError => {\n const error = new Error(res.message || \"Request failed\") as ApiError;\n error.code = res.code;\n error.data = res.data;\n return error;\n};\n\nconst extractAccessToken = (data: unknown): string => {\n if (typeof data === \"string\" && data) {\n return data;\n }\n\n if (!data || typeof data !== \"object\") {\n throw new Error(\n \"Invalid refresh token response: data is not an object or string\",\n );\n }\n\n const anyData = data as Record<string, unknown>;\n\n const accessToken =\n anyData.access_token ?? anyData.accessToken ?? anyData.token;\n\n if (typeof accessToken === \"string\" && accessToken) {\n return accessToken;\n }\n\n throw new Error(\n \"Invalid refresh token response: no access_token or token field found\",\n );\n};\n\n// 全局共享的刷新状态,以 tokenStorage 为 Key\n// 这样即使有多个 ApiClient 实例,只要它们共用同一个 tokenStorage,刷新逻辑就是单例的\nconst refreshingPromises = new WeakMap<TokenStorage, Promise<string>>();\n\nexport function createApiClient(options: CreateApiClientOptions) {\n const {\n baseURL,\n tokenStorage,\n refreshToken = false,\n retry = 1,\n retryDelay = 1000,\n isAuthError = (code: number) => code === 401,\n unwrapResponse = defaultUnwrapResponse,\n createErrorFromResult = defaultCreateErrorFromResult,\n } = options;\n\n const refreshTokenFn: (() => Promise<string>) | null = !refreshToken\n ? null\n : typeof refreshToken === \"string\"\n ? async () => {\n const res = await ofetch<ApiResult<unknown>>(refreshToken, {\n baseURL,\n method: \"POST\",\n retry,\n retryDelay,\n });\n\n if (res.code !== 0) {\n throw createErrorFromResult(res as ApiResult<unknown>);\n }\n\n return extractAccessToken(res.data);\n }\n : refreshToken;\n\n const rawRequest = ofetch.create({\n baseURL,\n retry,\n retryDelay,\n\n async onRequest(context: FetchContext) {\n const { options: reqOptions } = context;\n const token = await tokenStorage.getAccessToken();\n\n const headers = new Headers(\n reqOptions.headers as HeadersInit | undefined,\n );\n\n if (token) {\n headers.set(\"Authorization\", `Bearer ${token}`);\n }\n\n reqOptions.headers = headers;\n\n // 执行用户自定义钩子\n if (options.onRequest) {\n await options.onRequest(context);\n }\n },\n async onResponse(context) {\n const { response } = context;\n // 不在这里处理 code,统一交给 fetchApi 层处理\n if (response.status === 204) {\n response._data = null;\n return;\n }\n\n // 执行用户自定义钩子\n if (options.onResponse) {\n await options.onResponse(context);\n }\n },\n\n async onResponseError(context: FetchContext) {\n // 后端统一返回 HTTP 200,此处只处理网络层错误(如超时、断网)\n const { response } = context;\n const message =\n (response?._data as Record<string, unknown>)?.message ||\n `HTTP ${response?.status || \"Network Error\"}`;\n\n const error = new Error(message as string) as ApiError;\n error.status = response?.status;\n error.data = response?._data;\n throw error;\n },\n }) as $Fetch;\n\n async function request<T = unknown>(\n url: string,\n options: RequestOptions & { _retry?: boolean } = {},\n ): Promise<T> {\n // 提取自定义选项,避免传递给 $fetch\n const { returnFullResponse, _retry, ...fetchOptions } = options;\n\n // const res = await rawRequest<ApiResult<T>>(url, fetchOptions);\n const res = (await rawRequest(url, fetchOptions as FetchOptions)) as ApiResult<T>;\n\n if (res.code === 0) {\n return unwrapResponse<T>(res, !!returnFullResponse);\n // if (returnFullResponse) {\n // return res as unknown as T;\n // }\n\n // return res.data;\n }\n\n if (isAuthError(res.code) && !_retry && refreshTokenFn) {\n try {\n let refreshingPromise = refreshingPromises.get(tokenStorage);\n\n if (!refreshingPromise) {\n refreshingPromise = refreshTokenFn().finally(() => {\n refreshingPromises.delete(tokenStorage);\n });\n refreshingPromises.set(tokenStorage, refreshingPromise);\n }\n\n const newToken = await refreshingPromise;\n\n if (newToken) {\n await tokenStorage.setAccessToken(newToken);\n }\n\n return await request<T>(url, {\n ...(options || {}),\n _retry: true,\n } as any);\n } catch (e) {\n await tokenStorage.setAccessToken(\"\");\n throw createErrorFromResult(res as ApiResult<unknown>);\n }\n }\n\n throw createErrorFromResult(res as ApiResult<unknown>);\n }\n\n async function get<T = unknown>(\n url: string,\n params: FetchOptions[\"query\"] = {},\n options?: RequestOptions,\n ) {\n return request<T>(url, {\n ...options,\n method: \"GET\",\n query: params,\n } as any);\n }\n\n async function post<T = unknown>(\n url: string,\n body: FetchOptions[\"body\"] = {},\n options?: RequestOptions,\n ) {\n return request<T>(url, {\n ...options,\n method: \"POST\",\n body,\n } as any);\n }\n\n async function put<T = unknown>(\n url: string,\n body: FetchOptions[\"body\"] = {},\n options?: RequestOptions,\n ) {\n return request<T>(url, {\n ...options,\n method: \"PUT\",\n body,\n } as any);\n }\n\n async function patch<T = unknown>(\n url: string,\n body: FetchOptions[\"body\"] = {},\n options?: RequestOptions,\n ) {\n return request<T>(url, {\n ...options,\n method: \"PATCH\",\n body,\n } as any);\n }\n\n async function del<T = unknown>(\n url: string,\n params: FetchOptions[\"query\"] = {},\n options?: RequestOptions,\n ) {\n return request<T>(url, {\n ...options,\n method: \"DELETE\",\n query: params,\n } as any);\n }\n\n return {\n rawRequest,\n request,\n get,\n post,\n put,\n patch,\n del,\n };\n}\n","/**\n * Request Chain Runner\n * 负责解析和执行通用的 HTTP 请求链 (Chain Execution)\n * 适用于任何需要链式 HTTP 请求编排的场景\n */\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\n/** Supported HTTP Methods */\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/** HTTP 请求参数 */\nexport interface HttpRequestSpec {\n method: HttpMethod;\n url: string;\n headers?: Record<string, string>;\n body?: any;\n}\n\n/**\n * 网络适配器接口\n * 定义实际发送请求的能力\n */\n/**\n * 网络适配器接口\n * 定义实际发送请求的能力\n */\nexport interface NetworkAdapter {\n get<T>(\n url: string,\n params?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n post<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n put?<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n delete?<T>(\n url: string,\n params?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n patch?<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n}\n\n/**\n * 网络处理器接口 (Strategy Pattern)\n * 组合了\"匹配规则\"和\"执行能力\"\n */\nexport interface NetworkHandler {\n /** 处理器名称 (用于调试) */\n name?: string;\n\n /** 判断该 URL 是否由此适配器处理 */\n shouldHandle(url: string, method: HttpMethod): boolean;\n\n /** 具体的网络适配器 */\n adapter: NetworkAdapter;\n}\n\n/**\n * 请求链规则 (Chain Step)\n */\nexport interface ChainRequestRule {\n /**\n * 结果存储的键名 (Context Key)\n * Fetch 结果存储: context[key] = response\n */\n key?: string;\n\n /**\n * HTTP 请求详情\n */\n request: HttpRequestSpec;\n\n /**\n * 数据提取选择器\n * 用于从响应中提取特定数据, e.g., \"elements.0\"\n */\n selector?: string;\n\n /** 是否允许请求失败 (默认 false) */\n optional?: boolean;\n\n /**\n * 是否包含上下文\n * 如果为 true,请求 Body 将自动合并当前 Context 和 Payload\n */\n includeContext?: boolean;\n\n /**\n * 上下文筛选列表 (优先级高于 includeContext)\n * 指定需要合并到 Body 中的 Context Key 列表\n * e.g., [\"rawProfile\", \"rawCompany\"]\n */\n pickContext?: string[];\n}\n\n// ============================================================================\n// Internal Utilities\n// ============================================================================\n\n/**\n * 执行 HTTP 请求\n * 遍历 handlers 数组,找到第一个能处理该 URL 的适配器执行\n *\n * @param spec 请求详情\n * @param handlers 网络处理器链\n */\nasync function executeChainRequest<T>(\n spec: HttpRequestSpec,\n handlers: NetworkHandler[] = [],\n): Promise<T | null> {\n // Normalize method to upper case for robustness\n const method = spec.method.toUpperCase() as HttpMethod;\n\n // 1. 遍历处理器数组 (责任链)\n for (const handler of handlers) {\n if (handler.shouldHandle(spec.url, method)) {\n try {\n const { adapter } = handler;\n const headers = spec.headers;\n\n switch (method) {\n case \"GET\":\n return await adapter.get<T>(spec.url, spec.body, headers);\n case \"POST\":\n return await adapter.post<T>(spec.url, spec.body, headers);\n case \"PUT\":\n if (!adapter.put)\n throw new Error(`Adapter ${handler.name} missing PUT method`);\n return await adapter.put<T>(spec.url, spec.body, headers);\n case \"DELETE\":\n if (!adapter.delete)\n throw new Error(`Adapter ${handler.name} missing DELETE method`);\n return await adapter.delete<T>(spec.url, spec.body, headers);\n case \"PATCH\":\n if (!adapter.patch)\n throw new Error(`Adapter ${handler.name} missing PATCH method`);\n return await adapter.patch<T>(spec.url, spec.body, headers);\n default:\n throw new Error(`Unsupported method: ${method}`);\n }\n } catch (err) {\n console.warn(\n `Handler [${handler.name || \"Anonymous\"}] failed for ${spec.url}`,\n err,\n );\n // 如果需要继续尝试下一个 handler,可以在这里 continue,但通常由第一个匹配者全权负责\n return null;\n }\n }\n }\n\n // 2. 默认行为 (Fallback): 绝对路径自动走标准 fetch\n if (spec.url.startsWith(\"http://\") || spec.url.startsWith(\"https://\")) {\n return await executeFallbackFetch<T>(spec);\n }\n\n console.warn(`No handler found for url: ${spec.url}`);\n return null;\n}\n\n/**\n * 标准 Fetch 回退实现\n */\nasync function executeFallbackFetch<T>(\n spec: HttpRequestSpec,\n): Promise<T | null> {\n try {\n const response = await fetch(spec.url, {\n method: spec.method,\n headers: spec.headers,\n body: spec.body ? JSON.stringify(spec.body) : undefined,\n credentials: \"include\",\n });\n\n if (!response.ok) {\n console.log(`External Request failed: ${response.status} ${spec.url}`);\n return null;\n }\n\n return await response.json();\n } catch (err) {\n console.log(\"External Request error:\", err);\n return null;\n }\n}\n\n/**\n * 根据路径获取对象值\n */\nfunction getByPath(obj: any, path: string): any {\n if (!path) return obj;\n return path.split(\".\").reduce((acc, part) => acc && acc[part], obj);\n}\n\n/**\n * 变量替换 (Internal)\n * 支持字符串 {{key}} 和 {{key.prop}}\n */\nfunction substituteVariables(target: any, context: any): any {\n if (typeof target === \"string\") {\n return target.replace(/\\{\\{([\\w\\.]+)\\}\\}/g, (_, path) => {\n const val = getByPath(context, path);\n return val !== undefined ? String(val) : \"\";\n });\n }\n\n if (Array.isArray(target)) {\n return target.map((item) => substituteVariables(item, context));\n }\n\n if (target && typeof target === \"object\") {\n const result: any = {};\n for (const key in target) {\n result[key] = substituteVariables(target[key], context);\n }\n return result;\n }\n\n return target;\n}\n\n// ============================================================================\n// Main Runner\n// ============================================================================\n\n/**\n * 请求链执行器 (Request Chain Engine)\n * 支持链式请求、上下文累积、智能路由、变量替换\n *\n * @param requests 链式执行规则列表\n * @param handlers 网络适配器处理器列表 (按顺序匹配)\n */\nexport async function executeRequestChain<T>(\n requests: ChainRequestRule[],\n handlers: NetworkHandler[] = [],\n getChainRequests?: (\n context: Record<string, any>,\n ) => ChainRequestRule[] | null | undefined,\n initContext?: Record<string, any>,\n): Promise<T> {\n const context: Record<string, any> = initContext || {};\n let lastResult: any = null;\n\n for (const rule of requests) {\n try {\n // 1. 准备 Context Data (用于 Submit)\n let contextData: Record<string, any> = {};\n if (rule.pickContext) {\n rule.pickContext.forEach((key) => {\n if (key in context) contextData[key] = context[key];\n });\n } else if (rule.includeContext) {\n contextData = context;\n }\n const hasContextData = Object.keys(contextData).length > 0;\n\n // 2. 准备 Request Spec (合并 Context 到 Body)\n let requestSpec = { ...rule.request };\n if (hasContextData) {\n requestSpec.body = {\n ...contextData,\n ...(requestSpec.body || {}),\n };\n }\n\n // 3. 变量替换\n requestSpec = substituteVariables(requestSpec, context);\n\n // 4. 执行请求 (传入 handlers)\n let rawData = await executeChainRequest<any>(requestSpec, handlers);\n\n if (getChainRequests) {\n const chainRequests = getChainRequests(rawData);\n if (chainRequests && chainRequests.length > 0) {\n rawData = await executeRequestChain(\n chainRequests,\n handlers,\n getChainRequests,\n JSON.parse(JSON.stringify(context)),\n );\n }\n }\n\n lastResult = rawData;\n\n if (rawData) {\n // 5. 存储结果\n if (rule.key) {\n const data = rule.selector\n ? getByPath(rawData, rule.selector)\n : rawData;\n context[rule.key] = data;\n }\n } else if (!rule.optional) {\n throw new Error(\n `Failed to fetch required data for key: ${rule.key || \"unknown\"}`,\n );\n }\n } catch (err) {\n if (!rule.optional) {\n throw err;\n }\n console.warn(`Optional request failed for rule:`, rule, err);\n }\n }\n\n return lastResult as T;\n}\n","/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/\nimport * as $protobuf from \"protobufjs/minimal\";\n\n// Common aliases\nconst $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;\n\n// Exported root namespace\nconst $root = $protobuf.roots[\"default\"] || ($protobuf.roots[\"default\"] = {});\n\nexport const secure = $root.secure = (() => {\n\n /**\n * Namespace secure.\n * @exports secure\n * @namespace\n */\n const secure = {};\n\n secure.SecurePayload = (function() {\n\n /**\n * Properties of a SecurePayload.\n * @memberof secure\n * @interface ISecurePayload\n * @property {number|Long|null} [ts] SecurePayload ts\n * @property {Uint8Array|null} [data] SecurePayload data\n */\n\n /**\n * Constructs a new SecurePayload.\n * @memberof secure\n * @classdesc Represents a SecurePayload.\n * @implements ISecurePayload\n * @constructor\n * @param {secure.ISecurePayload=} [properties] Properties to set\n */\n function SecurePayload(properties) {\n if (properties)\n for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)\n if (properties[keys[i]] != null)\n this[keys[i]] = properties[keys[i]];\n }\n\n /**\n * SecurePayload ts.\n * @member {number|Long} ts\n * @memberof secure.SecurePayload\n * @instance\n */\n SecurePayload.prototype.ts = $util.Long ? $util.Long.fromBits(0,0,false) : 0;\n\n /**\n * SecurePayload data.\n * @member {Uint8Array} data\n * @memberof secure.SecurePayload\n * @instance\n */\n SecurePayload.prototype.data = $util.newBuffer([]);\n\n /**\n * Creates a new SecurePayload instance using the specified properties.\n * @function create\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload=} [properties] Properties to set\n * @returns {secure.SecurePayload} SecurePayload instance\n */\n SecurePayload.create = function create(properties) {\n return new SecurePayload(properties);\n };\n\n /**\n * Encodes the specified SecurePayload message. Does not implicitly {@link secure.SecurePayload.verify|verify} messages.\n * @function encode\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload} message SecurePayload message or plain object to encode\n * @param {$protobuf.Writer} [writer] Writer to encode to\n * @returns {$protobuf.Writer} Writer\n */\n SecurePayload.encode = function encode(message, writer) {\n if (!writer)\n writer = $Writer.create();\n if (message.ts != null && Object.hasOwnProperty.call(message, \"ts\"))\n writer.uint32(/* id 1, wireType 0 =*/8).int64(message.ts);\n if (message.data != null && Object.hasOwnProperty.call(message, \"data\"))\n writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.data);\n return writer;\n };\n\n /**\n * Encodes the specified SecurePayload message, length delimited. Does not implicitly {@link secure.SecurePayload.verify|verify} messages.\n * @function encodeDelimited\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload} message SecurePayload message or plain object to encode\n * @param {$protobuf.Writer} [writer] Writer to encode to\n * @returns {$protobuf.Writer} Writer\n */\n SecurePayload.encodeDelimited = function encodeDelimited(message, writer) {\n return this.encode(message, writer).ldelim();\n };\n\n /**\n * Decodes a SecurePayload message from the specified reader or buffer.\n * @function decode\n * @memberof secure.SecurePayload\n * @static\n * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from\n * @param {number} [length] Message length if known beforehand\n * @returns {secure.SecurePayload} SecurePayload\n * @throws {Error} If the payload is not a reader or valid buffer\n * @throws {$protobuf.util.ProtocolError} If required fields are missing\n */\n SecurePayload.decode = function decode(reader, length, error) {\n if (!(reader instanceof $Reader))\n reader = $Reader.create(reader);\n let end = length === undefined ? reader.len : reader.pos + length, message = new $root.secure.SecurePayload();\n while (reader.pos < end) {\n let tag = reader.uint32();\n if (tag === error)\n break;\n switch (tag >>> 3) {\n case 1: {\n message.ts = reader.int64();\n break;\n }\n case 2: {\n message.data = reader.bytes();\n break;\n }\n default:\n reader.skipType(tag & 7);\n break;\n }\n }\n return message;\n };\n\n /**\n * Decodes a SecurePayload message from the specified reader or buffer, length delimited.\n * @function decodeDelimited\n * @memberof secure.SecurePayload\n * @static\n * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from\n * @returns {secure.SecurePayload} SecurePayload\n * @throws {Error} If the payload is not a reader or valid buffer\n * @throws {$protobuf.util.ProtocolError} If required fields are missing\n */\n SecurePayload.decodeDelimited = function decodeDelimited(reader) {\n if (!(reader instanceof $Reader))\n reader = new $Reader(reader);\n return this.decode(reader, reader.uint32());\n };\n\n /**\n * Verifies a SecurePayload message.\n * @function verify\n * @memberof secure.SecurePayload\n * @static\n * @param {Object.<string,*>} message Plain object to verify\n * @returns {string|null} `null` if valid, otherwise the reason why it is not\n */\n SecurePayload.verify = function verify(message) {\n if (typeof message !== \"object\" || message === null)\n return \"object expected\";\n if (message.ts != null && message.hasOwnProperty(\"ts\"))\n if (!$util.isInteger(message.ts) && !(message.ts && $util.isInteger(message.ts.low) && $util.isInteger(message.ts.high)))\n return \"ts: integer|Long expected\";\n if (message.data != null && message.hasOwnProperty(\"data\"))\n if (!(message.data && typeof message.data.length === \"number\" || $util.isString(message.data)))\n return \"data: buffer expected\";\n return null;\n };\n\n /**\n * Creates a SecurePayload message from a plain object. Also converts values to their respective internal types.\n * @function fromObject\n * @memberof secure.SecurePayload\n * @static\n * @param {Object.<string,*>} object Plain object\n * @returns {secure.SecurePayload} SecurePayload\n */\n SecurePayload.fromObject = function fromObject(object) {\n if (object instanceof $root.secure.SecurePayload)\n return object;\n let message = new $root.secure.SecurePayload();\n if (object.ts != null)\n if ($util.Long)\n (message.ts = $util.Long.fromValue(object.ts)).unsigned = false;\n else if (typeof object.ts === \"string\")\n message.ts = parseInt(object.ts, 10);\n else if (typeof object.ts === \"number\")\n message.ts = object.ts;\n else if (typeof object.ts === \"object\")\n message.ts = new $util.LongBits(object.ts.low >>> 0, object.ts.high >>> 0).toNumber();\n if (object.data != null)\n if (typeof object.data === \"string\")\n $util.base64.decode(object.data, message.data = $util.newBuffer($util.base64.length(object.data)), 0);\n else if (object.data.length >= 0)\n message.data = object.data;\n return message;\n };\n\n /**\n * Creates a plain object from a SecurePayload message. Also converts values to other types if specified.\n * @function toObject\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.SecurePayload} message SecurePayload\n * @param {$protobuf.IConversionOptions} [options] Conversion options\n * @returns {Object.<string,*>} Plain object\n */\n SecurePayload.toObject = function toObject(message, options) {\n if (!options)\n options = {};\n let object = {};\n if (options.defaults) {\n if ($util.Long) {\n let long = new $util.Long(0, 0, false);\n object.ts = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;\n } else\n object.ts = options.longs === String ? \"0\" : 0;\n if (options.bytes === String)\n object.data = \"\";\n else {\n object.data = [];\n if (options.bytes !== Array)\n object.data = $util.newBuffer(object.data);\n }\n }\n if (message.ts != null && message.hasOwnProperty(\"ts\"))\n if (typeof message.ts === \"number\")\n object.ts = options.longs === String ? String(message.ts) : message.ts;\n else\n object.ts = options.longs === String ? $util.Long.prototype.toString.call(message.ts) : options.longs === Number ? new $util.LongBits(message.ts.low >>> 0, message.ts.high >>> 0).toNumber() : message.ts;\n if (message.data != null && message.hasOwnProperty(\"data\"))\n object.data = options.bytes === String ? $util.base64.encode(message.data, 0, message.data.length) : options.bytes === Array ? Array.prototype.slice.call(message.data) : message.data;\n return object;\n };\n\n /**\n * Converts this SecurePayload to JSON.\n * @function toJSON\n * @memberof secure.SecurePayload\n * @instance\n * @returns {Object.<string,*>} JSON object\n */\n SecurePayload.prototype.toJSON = function toJSON() {\n return this.constructor.toObject(this, $protobuf.util.toJSONOptions);\n };\n\n /**\n * Gets the default type url for SecurePayload\n * @function getTypeUrl\n * @memberof secure.SecurePayload\n * @static\n * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default \"type.googleapis.com\")\n * @returns {string} The default type url\n */\n SecurePayload.getTypeUrl = function getTypeUrl(typeUrlPrefix) {\n if (typeUrlPrefix === undefined) {\n typeUrlPrefix = \"type.googleapis.com\";\n }\n return typeUrlPrefix + \"/secure.SecurePayload\";\n };\n\n return SecurePayload;\n })();\n\n return secure;\n})();\n\nexport { $root as default };\n","/**\n * Protobuf 安全通信模块\n *\n * 提供基于 Protobuf 的二进制序列化、XOR 混淆加密以及与 API Client 的无缝集成。\n */\n\nimport protobuf from \"protobufjs/light\";\nimport { secure } from \"./secure.js\";\nimport type { FetchContext } from \"ofetch\";\n\n// ============================================================================\n// 1. 类型定义 (Types)\n// ============================================================================\n// export type ProtobufTypeLike = Pick<protobuf.Type, \"create\" | \"encode\" | \"decode\" | \"toObject\">;\nexport interface ProtobufTypeLike {\n // 1. 允许 properties 为任何对象,返回结果不再强制要求 $type\n create(properties?: Record<string, any>): any;\n // 2. 借用原生的参数类型约束,但手动简化返回类型\n encode(message: any): { finish(): Uint8Array };\n // 3. 借用原生的 decode 签名(支持 Uint8Array 和 Reader)\n decode(reader: Uint8Array | protobuf.Reader): any;\n // 4. 借用原生的 toObject 签名,保留 IConversionOptions 的类型检查\n toObject(message: any, options?: protobuf.IConversionOptions): any;\n}\n/**\n * 二进制混淆接口\n * 允许外部定义混淆逻辑,以便与不同语言实现的后端兼容\n */\nexport interface ProtobufObfuscator {\n encrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;\n decrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;\n}\n\n/**\n * 基础编解码配置\n * 控制如何将数据转换为二进制,以及是否混淆\n */\nexport interface ProtobufCodecOptions {\n /**\n * 混淆器实现\n * 提供该选项时才会启用混淆\n */\n obfuscator?: ProtobufObfuscator;\n /** 预编译的 Protobuf 类型对象 (推荐,性能最高) */\n protoType?: ProtobufTypeLike;\n /** 数据转换钩子:处理业务模型与 Proto 结构不一致的情况 */\n transform?: {\n beforeEncode?: (data: any) => any;\n afterDecode?: (payload: any) => any;\n };\n}\n\n/**\n * 完全自定义编解码接口\n * 用于外部项目完全接管序列化过程,同时复用基础库的混淆外壳\n */\nexport interface ProtobufCustomCodec {\n /** 外部定义的编码逻辑 (返回原始二进制) */\n encode?: (data: any) => Uint8Array | Promise<Uint8Array>;\n /** 外部定义的解码逻辑 (返回原始对象) */\n decode?: <T>(buffer: Uint8Array) => T | Promise<T>;\n}\n\n/**\n * 集成配置项\n * 用于 createProtobufHooks 或 API Client 全局配置\n */\nexport interface ProtobufHooksOptions\n extends ProtobufCodecOptions, ProtobufCustomCodec {}\n\nexport const PROTOBUF_CONTENT_TYPE = \"application/x-protobuf\";\n\n/** 检查是否为 Protobuf 响应头 */\nexport function isProtobufContentType(contentType: string | null): boolean {\n return !!contentType?.toLowerCase().includes(PROTOBUF_CONTENT_TYPE);\n}\n\n/**\n * 获取 Protobuf 相关的 Header 配置对象\n */\nexport function getProtobufHeaders({\n send = true,\n receive = true,\n}: {\n send?: boolean;\n receive?: boolean;\n} = {}): Record<string, string> {\n const headers: Record<string, string> = {};\n\n if (send) {\n headers[\"Content-Type\"] = PROTOBUF_CONTENT_TYPE;\n }\n\n if (receive) {\n headers[\"Accept\"] = PROTOBUF_CONTENT_TYPE;\n }\n\n return headers;\n}\n\n/**\n * API Client 内部使用的标准化配置\n */\n// export interface ProtobufConfig {\n// encode: (data: any) => Uint8Array | Promise<Uint8Array>;\n// decode: <T>(buffer: Uint8Array) => T | Promise<T>;\n// options?: ProtobufCodecOptions;\n// }\n\n// ============================================================================\n// 2. 内部工具函数 (Internal Utilities)\n// ============================================================================\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/** 简单的二进制异或混淆转换 */\nexport function xorTransform(\n data: Uint8Array,\n key: string | Uint8Array,\n): Uint8Array {\n const keyBytes = typeof key === \"string\" ? encoder.encode(key) : key;\n if (keyBytes.length === 0) return data;\n\n for (let i = 0; i < data.length; i++) {\n data[i] ^= keyBytes[i % keyBytes.length];\n }\n return data;\n}\n\n/** 创建一个简单的 XOR 混淆器 */\nexport function createXorObfuscator(\n key: string | Uint8Array,\n): ProtobufObfuscator {\n return {\n encrypt: (data) => xorTransform(data, key),\n decrypt: (data) => xorTransform(data, key),\n };\n}\n\n/** 获取内置的 SecurePayload 类型(使用预编译代码) */\nfunction getInternalSecureType(): protobuf.Type {\n return secure.SecurePayload as unknown as protobuf.Type;\n}\n\n// ============================================================================\n// 3. 核心编解码逻辑 (Core Codecs)\n// ============================================================================\n\n/**\n * 编码安全载荷\n *\n * 流程:业务数据 -> (自定义编码 / Proto 序列化) -> 二进制混淆\n */\nexport async function encodeSecure<T>(\n data: T,\n options: ProtobufHooksOptions = {},\n): Promise<Uint8Array> {\n const { obfuscator, protoType, transform, encode: customEncode } = options;\n\n let buffer: Uint8Array;\n\n // 1. 预处理阶段:无论后续走哪条路径,只要定义了 beforeEncode 就先执行\n const processedData = transform?.beforeEncode\n ? transform.beforeEncode(data)\n : data;\n\n // 1. 序列化阶段\n if (customEncode) {\n buffer = await customEncode(processedData);\n } else {\n const type = protoType || getInternalSecureType();\n\n // 构造最终要交给 Protobuf 序列化的对象\n const payload = protoType\n ? processedData // 自定义模式:直接使用预处理后的数据\n : {\n // 默认容器模式:将预处理后的数据封装进信封\n ts: Date.now(),\n data:\n processedData instanceof Uint8Array\n ? processedData\n : encoder.encode(JSON.stringify(processedData)),\n };\n\n const message = type.create(payload);\n buffer = type.encode(message).finish();\n }\n\n // 2. 混淆阶段\n if (obfuscator) {\n return await obfuscator.encrypt(buffer);\n }\n return buffer;\n}\n\n/**\n * 解码安全载荷\n *\n * 流程:二进制流 -> 二进制反混淆 -> (自定义解码 / Proto 反序列化) -> 业务数据\n */\nexport async function decodeSecure<T>(\n buffer: Uint8Array | ArrayBuffer,\n options: ProtobufHooksOptions = {},\n): Promise<T> {\n const { obfuscator, protoType, transform, decode: customDecode } = options;\n\n // let uint8 = buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : buffer;\n // let uint8 =\n // buffer instanceof ArrayBuffer\n // ? new Uint8Array(buffer)\n // : new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n\n // 1. 标准化为 Uint8Array 视图 (跨环境最稳写法)\n let uint8 = ArrayBuffer.isView(buffer)\n ? new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength)\n : new Uint8Array(buffer);\n\n if (uint8.length === 0) {\n return null as T; // 或者返回 {},根据业务定\n }\n\n // 1. 混淆阶段\n if (uint8.length > 0 && obfuscator) {\n uint8 = await obfuscator.decrypt(uint8);\n }\n\n // 2. 反序列化阶段\n if (customDecode) {\n return await customDecode<T>(uint8);\n }\n\n const type = protoType || getInternalSecureType();\n const decoded = type.decode(uint8);\n const plainObj = type.toObject(decoded, {\n longs: String,\n enums: String,\n bytes: Uint8Array as any,\n defaults: true,\n });\n\n // 3. 转换阶段\n if (transform?.afterDecode) {\n return transform.afterDecode(plainObj);\n }\n\n // 内置容器模式的额外还原逻辑\n if (!protoType && plainObj.data) {\n const jsonString = decoder.decode(plainObj.data as Uint8Array);\n try {\n return JSON.parse(jsonString) as T;\n } catch {\n return jsonString as unknown as T;\n }\n }\n\n return plainObj as T;\n}\n\n// ============================================================================\n// 4. HTTP/环境适配工具 (HTTP Tools)\n// ============================================================================\n\n/** 创建安全响应 (Worker/Server 端使用) */\nexport async function secureResponse<T>(\n data: T,\n options?: ProtobufCodecOptions & { corsHeaders?: Record<string, string> },\n): Promise<Response> {\n const buffer = await encodeSecure(data, options);\n // const arrayBuffer = buffer.buffer.slice(\n // buffer.byteOffset,\n // buffer.byteOffset + buffer.byteLength,\n // ) as ArrayBuffer;\n const cleanBuffer = buffer.slice();\n\n return new Response(cleanBuffer, {\n headers: {\n ...getProtobufHeaders({ send: true }),\n ...options?.corsHeaders,\n },\n });\n}\n\n/** * 解析安全请求体 (Worker/Server 端使用)\n * @param request 原生 Request 对象\n * @param options 编解码配置(可包含当前接口对应的 protoType 和自定义 obfuscator)\n */\nexport async function parseSecureRequest<T>(\n request: Request,\n options: ProtobufHooksOptions = {}, // 统一使用这个配置对象\n): Promise<T> {\n const buffer = await request.arrayBuffer();\n return decodeSecure<T>(buffer, options);\n}\n\n/** 标准化配置对象 */\n// export function normalizeProtobufConfig(\n// config: boolean | ProtobufConfig | undefined,\n// options?: ProtobufHooksOptions, // 接收全局配置\n// ): ProtobufConfig | null {\n// if (!config) return null;\n// if (config === true) {\n// return {\n// encode: (data) => encodeSecure(data, options),\n// decode: <T>(buffer: Uint8Array) => decodeSecure<T>(buffer, options),\n// options,\n// };\n// }\n// return config;\n// }\n\n// ============================================================================\n// 5. API Client 钩子逻辑 (Integration Hooks)\n// ============================================================================\n\n/** 创建 Protobuf 编解码钩子 (用于与 createApiClient 配合使用) */\nexport function createProtobufHooks(globalOptions: ProtobufHooksOptions = {}) {\n // const encode = (data: any) => encodeSecure(data, globalOptions);\n // const decode = <T>(buffer: Uint8Array) => decodeSecure<T>(buffer, globalOptions);\n\n return {\n async onRequest(context: FetchContext) {\n const { options: reqOptions } = context;\n\n // 1. 动态合并配置:将全局 globalOptions 和单次请求传的 reqOptions 合并\n // 这确保了 encodeSecure 能拿到当前请求特有的 protoType 或 transform\n const mergedOptions: ProtobufHooksOptions = {\n ...globalOptions,\n ...reqOptions,\n };\n\n const headers =\n reqOptions.headers instanceof Headers\n ? reqOptions.headers\n : new Headers(reqOptions.headers as HeadersInit | undefined);\n\n // 自动编码请求体\n if (\n isProtobufContentType(headers.get(\"Content-Type\")) &&\n reqOptions.body &&\n !(reqOptions.body instanceof Uint8Array)\n ) {\n reqOptions.body = await encodeSecure(reqOptions.body, mergedOptions);\n }\n\n // 自动设置期望响应类型\n if (\n isProtobufContentType(headers.get(\"Accept\")) &&\n !reqOptions.responseType\n ) {\n reqOptions.responseType = \"arrayBuffer\";\n }\n\n reqOptions.headers = headers;\n },\n\n async onResponse(context: FetchContext) {\n const { response, options: reqOptions } = context;\n if (!response?._data || response.status === 204) return;\n\n // 同样在响应阶段合并 options,以获取单次请求指定的 protoType 来解码\n const mergedOptions: ProtobufHooksOptions = {\n ...globalOptions,\n ...reqOptions,\n };\n\n if (isProtobufContentType(response.headers.get(\"Content-Type\"))) {\n try {\n // 这里的 _data 可能是 ArrayBuffer (浏览器) 或 Buffer (Node)\n // decodeSecure 内部已处理好兼容性\n response._data = await decodeSecure(response._data, mergedOptions);\n // const buffer = response._data as ArrayBuffer;\n // if (buffer && buffer.byteLength > 0) {\n // response._data = await decode(new Uint8Array(buffer));\n // }\n } catch (e) {\n console.log(\"Error [Protobuf Decode Error]\", e);\n response._data = null;\n }\n } else if (response._data instanceof ArrayBuffer) {\n const text = decoder.decode(response._data);\n try {\n response._data = JSON.parse(text);\n } catch {\n response._data = text;\n }\n }\n },\n };\n}\n"],"mappings":"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","names":["options","secure"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/chain.ts","../src/secure.js","../src/protobuf.ts"],"sourcesContent":["export * from \"./client\";\nexport * from \"./chain\";\nexport * from \"./protobuf\";\n","import {\n ofetch,\n type FetchOptions,\n type FetchContext,\n type $Fetch,\n} from \"ofetch\";\n\nexport interface ApiResult<T> {\n code: number;\n data: T;\n message: string;\n}\n\nexport interface ApiError extends Error {\n code: number; // 业务错误码\n data?: unknown; // 后端返回的 data 字段(如果有)\n status?: number; // HTTP 状态码(网络错误时)\n}\n\n// 类型守卫:判断是否是 API 业务错误\nexport const isApiError = (error: unknown): error is ApiError => {\n return error instanceof Error && \"code\" in error;\n};\n\nexport interface TokenStorage {\n getAccessToken: () => Promise<string> | string;\n setAccessToken: (token: string) => Promise<void> | void;\n}\n\nexport interface CreateApiClientOptions {\n baseURL: string;\n tokenStorage: TokenStorage;\n refreshToken?: (() => Promise<string>) | string | false;\n retry?: number; // 重试次数,默认 1\n retryDelay?: number; // 重试间隔,默认 1s\n isAuthError?: (code: number) => boolean;\n unwrapResponse?<T>(result: unknown, returnFullResponse: boolean): T;\n createErrorFromResult?(res: unknown): Error;\n /**\n * 自定义请求钩子\n * 在请求发送前执行,可用于编码请求体等\n */\n onRequest?: (context: FetchContext) => void | Promise<void>;\n /**\n * 自定义响应钩子\n * 在响应返回后执行,可用于解码响应体等\n */\n onResponse?: (context: FetchContext) => void | Promise<void>;\n}\n\ntype RequestOptions = Omit<FetchOptions<\"json\">, \"responseType\"> & {\n returnFullResponse?: boolean;\n responseType?: \"json\" | \"arrayBuffer\" | \"text\" | \"blob\";\n};\n\n// 解包后端统一响应格式(默认实现)\nconst defaultUnwrapResponse = <T>(\n result: unknown,\n returnFullResponse = false,\n): T => {\n if (result && typeof result === \"object\" && \"code\" in result) {\n const body = result as Record<string, unknown>;\n if (body.code === 0) {\n return returnFullResponse ? (body as T) : (body.data as T);\n }\n }\n return result as T;\n};\n\nconst defaultCreateErrorFromResult = (res: ApiResult<unknown>): ApiError => {\n const error = new Error(res.message || \"Request failed\") as ApiError;\n error.code = res.code;\n error.data = res.data;\n return error;\n};\n\nconst extractAccessToken = (data: unknown): string => {\n if (typeof data === \"string\" && data) {\n return data;\n }\n\n if (!data || typeof data !== \"object\") {\n throw new Error(\n \"Invalid refresh token response: data is not an object or string\",\n );\n }\n\n const anyData = data as Record<string, unknown>;\n\n const accessToken =\n anyData.access_token ?? anyData.accessToken ?? anyData.token;\n\n if (typeof accessToken === \"string\" && accessToken) {\n return accessToken;\n }\n\n throw new Error(\n \"Invalid refresh token response: no access_token or token field found\",\n );\n};\n\n// 全局共享的刷新状态,以 tokenStorage 为 Key\n// 这样即使有多个 ApiClient 实例,只要它们共用同一个 tokenStorage,刷新逻辑就是单例的\nconst refreshingPromises = new WeakMap<TokenStorage, Promise<string>>();\n\nexport function createApiClient(options: CreateApiClientOptions) {\n const {\n baseURL,\n tokenStorage,\n refreshToken = false,\n retry = 1,\n retryDelay = 1000,\n isAuthError = (code: number) => code === 401,\n unwrapResponse = defaultUnwrapResponse,\n createErrorFromResult = defaultCreateErrorFromResult,\n } = options;\n\n const refreshTokenFn: (() => Promise<string>) | null = !refreshToken\n ? null\n : typeof refreshToken === \"string\"\n ? async () => {\n const res = await ofetch<ApiResult<unknown>>(refreshToken, {\n baseURL,\n method: \"POST\",\n retry,\n retryDelay,\n });\n\n if (res.code !== 0) {\n throw createErrorFromResult(res as ApiResult<unknown>);\n }\n\n return extractAccessToken(res.data);\n }\n : refreshToken;\n\n const rawRequest = ofetch.create({\n baseURL,\n retry,\n retryDelay,\n\n async onRequest(context: FetchContext) {\n const { options: reqOptions } = context;\n const token = await tokenStorage.getAccessToken();\n\n const headers = new Headers(\n reqOptions.headers as HeadersInit | undefined,\n );\n\n if (token) {\n headers.set(\"Authorization\", `Bearer ${token}`);\n }\n\n reqOptions.headers = headers;\n\n // 执行用户自定义钩子\n if (options.onRequest) {\n await options.onRequest(context);\n }\n },\n async onResponse(context) {\n const { response } = context;\n // 不在这里处理 code,统一交给 fetchApi 层处理\n if (response.status === 204) {\n response._data = null;\n return;\n }\n\n // 执行用户自定义钩子\n if (options.onResponse) {\n await options.onResponse(context);\n }\n },\n\n async onResponseError(context: FetchContext) {\n // 后端统一返回 HTTP 200,此处只处理网络层错误(如超时、断网)\n const { response } = context;\n const message =\n (response?._data as Record<string, unknown>)?.message ||\n `HTTP ${response?.status || \"Network Error\"}`;\n\n const error = new Error(message as string) as ApiError;\n error.status = response?.status;\n error.data = response?._data;\n throw error;\n },\n }) as $Fetch;\n\n async function request<T = unknown>(\n url: string,\n options: RequestOptions & { _retry?: boolean } = {},\n ): Promise<T> {\n // 提取自定义选项,避免传递给 $fetch\n const { returnFullResponse, _retry, ...fetchOptions } = options;\n\n // const res = await rawRequest<ApiResult<T>>(url, fetchOptions);\n const res = (await rawRequest(url, fetchOptions as FetchOptions)) as ApiResult<T>;\n\n if (res.code === 0) {\n return unwrapResponse<T>(res, !!returnFullResponse);\n // if (returnFullResponse) {\n // return res as unknown as T;\n // }\n\n // return res.data;\n }\n\n if (isAuthError(res.code) && !_retry && refreshTokenFn) {\n try {\n let refreshingPromise = refreshingPromises.get(tokenStorage);\n\n if (!refreshingPromise) {\n refreshingPromise = refreshTokenFn().finally(() => {\n refreshingPromises.delete(tokenStorage);\n });\n refreshingPromises.set(tokenStorage, refreshingPromise);\n }\n\n const newToken = await refreshingPromise;\n\n if (newToken) {\n await tokenStorage.setAccessToken(newToken);\n }\n\n return await request<T>(url, {\n ...(options || {}),\n _retry: true,\n } as any);\n } catch (e) {\n await tokenStorage.setAccessToken(\"\");\n throw createErrorFromResult(res as ApiResult<unknown>);\n }\n }\n\n throw createErrorFromResult(res as ApiResult<unknown>);\n }\n\n async function get<T = unknown>(\n url: string,\n params: FetchOptions[\"query\"] = {},\n options?: RequestOptions,\n ) {\n return request<T>(url, {\n ...options,\n method: \"GET\",\n query: params,\n } as any);\n }\n\n async function post<T = unknown>(\n url: string,\n body: FetchOptions[\"body\"] = {},\n options?: RequestOptions,\n ) {\n return request<T>(url, {\n ...options,\n method: \"POST\",\n body,\n } as any);\n }\n\n async function put<T = unknown>(\n url: string,\n body: FetchOptions[\"body\"] = {},\n options?: RequestOptions,\n ) {\n return request<T>(url, {\n ...options,\n method: \"PUT\",\n body,\n } as any);\n }\n\n async function patch<T = unknown>(\n url: string,\n body: FetchOptions[\"body\"] = {},\n options?: RequestOptions,\n ) {\n return request<T>(url, {\n ...options,\n method: \"PATCH\",\n body,\n } as any);\n }\n\n async function del<T = unknown>(\n url: string,\n params: FetchOptions[\"query\"] = {},\n options?: RequestOptions,\n ) {\n return request<T>(url, {\n ...options,\n method: \"DELETE\",\n query: params,\n } as any);\n }\n\n return {\n rawRequest,\n request,\n get,\n post,\n put,\n patch,\n del,\n };\n}\n","/**\n * Request Chain Runner\n * 负责解析和执行通用的 HTTP 请求链 (Chain Execution)\n * 适用于任何需要链式 HTTP 请求编排的场景\n */\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\n/** Supported HTTP Methods */\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/** HTTP 请求参数 */\nexport interface HttpRequestSpec {\n method: HttpMethod;\n url: string;\n headers?: Record<string, string>;\n body?: any;\n}\n\n/**\n * 网络适配器接口\n * 定义实际发送请求的能力\n */\n/**\n * 网络适配器接口\n * 定义实际发送请求的能力\n */\nexport interface NetworkAdapter {\n get<T>(\n url: string,\n params?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n post<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n put?<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n delete?<T>(\n url: string,\n params?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n patch?<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n}\n\n/**\n * 网络处理器接口 (Strategy Pattern)\n * 组合了\"匹配规则\"和\"执行能力\"\n */\nexport interface NetworkHandler {\n /** 处理器名称 (用于调试) */\n name?: string;\n\n /** 判断该 URL 是否由此适配器处理 */\n shouldHandle(url: string, method: HttpMethod): boolean;\n\n /** 具体的网络适配器 */\n adapter: NetworkAdapter;\n}\n\n/**\n * 请求链规则 (Chain Step)\n */\nexport interface ChainRequestRule {\n /**\n * 结果存储的键名 (Context Key)\n * Fetch 结果存储: context[key] = response\n */\n key?: string;\n\n /**\n * HTTP 请求详情\n */\n request: HttpRequestSpec;\n\n /**\n * 数据提取选择器\n * 用于从响应中提取特定数据, e.g., \"elements.0\"\n */\n selector?: string;\n\n /** 是否允许请求失败 (默认 false) */\n optional?: boolean;\n}\n\n// ============================================================================\n// Internal Utilities\n// ============================================================================\n\n/**\n * 执行 HTTP 请求\n * 遍历 handlers 数组,找到第一个能处理该 URL 的适配器执行\n *\n * @param spec 请求详情\n * @param handlers 网络处理器链\n */\nasync function executeChainRequest<T>(\n spec: HttpRequestSpec,\n handlers: NetworkHandler[] = [],\n): Promise<T | null> {\n // Normalize method to upper case for robustness\n const method = spec.method.toUpperCase() as HttpMethod;\n\n // 1. 遍历处理器数组 (责任链)\n for (const handler of handlers) {\n if (handler.shouldHandle(spec.url, method)) {\n try {\n const { adapter } = handler;\n const headers = spec.headers;\n\n switch (method) {\n case \"GET\":\n return await adapter.get<T>(spec.url, spec.body, headers);\n case \"POST\":\n return await adapter.post<T>(spec.url, spec.body, headers);\n case \"PUT\":\n if (!adapter.put)\n throw new Error(`Adapter ${handler.name} missing PUT method`);\n return await adapter.put<T>(spec.url, spec.body, headers);\n case \"DELETE\":\n if (!adapter.delete)\n throw new Error(`Adapter ${handler.name} missing DELETE method`);\n return await adapter.delete<T>(spec.url, spec.body, headers);\n case \"PATCH\":\n if (!adapter.patch)\n throw new Error(`Adapter ${handler.name} missing PATCH method`);\n return await adapter.patch<T>(spec.url, spec.body, headers);\n default:\n throw new Error(`Unsupported method: ${method}`);\n }\n } catch (err) {\n console.warn(\n `Handler [${handler.name || \"Anonymous\"}] failed for ${spec.url}`,\n err,\n );\n // 如果需要继续尝试下一个 handler,可以在这里 continue,但通常由第一个匹配者全权负责\n return null;\n }\n }\n }\n\n // 2. 默认行为 (Fallback): 绝对路径自动走标准 fetch\n if (spec.url.startsWith(\"http://\") || spec.url.startsWith(\"https://\")) {\n return await executeFallbackFetch<T>(spec);\n }\n\n console.warn(`No handler found for url: ${spec.url}`);\n return null;\n}\n\n/**\n * 标准 Fetch 回退实现\n */\nasync function executeFallbackFetch<T>(\n spec: HttpRequestSpec,\n): Promise<T | null> {\n try {\n const response = await fetch(spec.url, {\n method: spec.method,\n headers: spec.headers,\n body: spec.body ? JSON.stringify(spec.body) : undefined,\n credentials: \"include\",\n });\n\n if (!response.ok) {\n console.log(`External Request failed: ${response.status} ${spec.url}`);\n return null;\n }\n\n return await response.json();\n } catch (err) {\n console.log(\"External Request error:\", err);\n return null;\n }\n}\n\n/**\n * 根据路径获取对象值\n */\nfunction getByPath(obj: any, path: string): any {\n if (!path) return obj;\n return path.split(\".\").reduce((acc, part) => acc && acc[part], obj);\n}\n\n/**\n * 变量替换 (Internal)\n * 支持字符串 {{key}} 和 {{key.prop}}\n */\nfunction substituteVariables(target: any, context: any): any {\n if (typeof target === \"string\") {\n // 1. 如果整个字符串就是一个变量占位符,例如 \"{{user}}\",则返回原始对象/值\n const directMatch = target.match(/^\\{\\{([\\w\\.]+)\\}\\}$/);\n if (directMatch) {\n const path = directMatch[1];\n const val = getByPath(context, path);\n return val !== undefined ? val : \"\";\n }\n\n // 2. 如果是混合字符串,例如 \"Hello {{user.name}}\",则执行字符串替换\n return target.replace(/\\{\\{([\\w\\.]+)\\}\\}/g, (_, path) => {\n const val = getByPath(context, path);\n return val !== undefined ? String(val) : \"\";\n });\n }\n\n if (Array.isArray(target)) {\n return target.map((item) => substituteVariables(item, context));\n }\n\n if (target && typeof target === \"object\") {\n const result: any = {};\n for (const key in target) {\n result[key] = substituteVariables(target[key], context);\n }\n return result;\n }\n\n return target;\n}\n\n// ============================================================================\n// Main Runner\n// ============================================================================\n\n/**\n * 请求链执行器 (Request Chain Engine)\n * 支持链式请求、上下文累积、智能路由、变量替换\n *\n * @param requests 链式执行规则列表\n * @param handlers 网络适配器处理器列表 (按顺序匹配)\n */\nexport async function executeRequestChain<T>(\n requests: ChainRequestRule[],\n handlers: NetworkHandler[] = [],\n getChainRequests?: (\n context: Record<string, any>,\n ) => ChainRequestRule[] | null | undefined,\n initContext?: Record<string, any>,\n): Promise<T> {\n const context: Record<string, any> = initContext || {};\n let lastResult: any = null;\n\n for (const rule of requests) {\n try {\n // 1. 变量替换 (支持从 Context 注入对象到 Request Body/URL/Headers)\n const requestSpec = substituteVariables(rule.request, context);\n\n // 2. 执行请求 (传入 handlers)\n let rawData = await executeChainRequest<any>(requestSpec, handlers);\n\n if (getChainRequests) {\n const chainRequests = getChainRequests(rawData);\n if (chainRequests && chainRequests.length > 0) {\n rawData = await executeRequestChain(\n chainRequests,\n handlers,\n getChainRequests,\n JSON.parse(JSON.stringify(context)),\n );\n }\n }\n\n lastResult = rawData;\n\n if (rawData) {\n // 5. 存储结果\n if (rule.key) {\n const data = rule.selector\n ? getByPath(rawData, rule.selector)\n : rawData;\n context[rule.key] = data;\n }\n } else if (!rule.optional) {\n throw new Error(\n `Failed to fetch required data for key: ${rule.key || \"unknown\"}`,\n );\n }\n } catch (err) {\n if (!rule.optional) {\n throw err;\n }\n console.warn(`Optional request failed for rule:`, rule, err);\n }\n }\n\n return lastResult as T;\n}\n","/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/\nimport * as $protobuf from \"protobufjs/minimal\";\n\n// Common aliases\nconst $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;\n\n// Exported root namespace\nconst $root = $protobuf.roots[\"default\"] || ($protobuf.roots[\"default\"] = {});\n\nexport const secure = $root.secure = (() => {\n\n /**\n * Namespace secure.\n * @exports secure\n * @namespace\n */\n const secure = {};\n\n secure.SecurePayload = (function() {\n\n /**\n * Properties of a SecurePayload.\n * @memberof secure\n * @interface ISecurePayload\n * @property {number|Long|null} [ts] SecurePayload ts\n * @property {Uint8Array|null} [data] SecurePayload data\n */\n\n /**\n * Constructs a new SecurePayload.\n * @memberof secure\n * @classdesc Represents a SecurePayload.\n * @implements ISecurePayload\n * @constructor\n * @param {secure.ISecurePayload=} [properties] Properties to set\n */\n function SecurePayload(properties) {\n if (properties)\n for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)\n if (properties[keys[i]] != null)\n this[keys[i]] = properties[keys[i]];\n }\n\n /**\n * SecurePayload ts.\n * @member {number|Long} ts\n * @memberof secure.SecurePayload\n * @instance\n */\n SecurePayload.prototype.ts = $util.Long ? $util.Long.fromBits(0,0,false) : 0;\n\n /**\n * SecurePayload data.\n * @member {Uint8Array} data\n * @memberof secure.SecurePayload\n * @instance\n */\n SecurePayload.prototype.data = $util.newBuffer([]);\n\n /**\n * Creates a new SecurePayload instance using the specified properties.\n * @function create\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload=} [properties] Properties to set\n * @returns {secure.SecurePayload} SecurePayload instance\n */\n SecurePayload.create = function create(properties) {\n return new SecurePayload(properties);\n };\n\n /**\n * Encodes the specified SecurePayload message. Does not implicitly {@link secure.SecurePayload.verify|verify} messages.\n * @function encode\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload} message SecurePayload message or plain object to encode\n * @param {$protobuf.Writer} [writer] Writer to encode to\n * @returns {$protobuf.Writer} Writer\n */\n SecurePayload.encode = function encode(message, writer) {\n if (!writer)\n writer = $Writer.create();\n if (message.ts != null && Object.hasOwnProperty.call(message, \"ts\"))\n writer.uint32(/* id 1, wireType 0 =*/8).int64(message.ts);\n if (message.data != null && Object.hasOwnProperty.call(message, \"data\"))\n writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.data);\n return writer;\n };\n\n /**\n * Encodes the specified SecurePayload message, length delimited. Does not implicitly {@link secure.SecurePayload.verify|verify} messages.\n * @function encodeDelimited\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload} message SecurePayload message or plain object to encode\n * @param {$protobuf.Writer} [writer] Writer to encode to\n * @returns {$protobuf.Writer} Writer\n */\n SecurePayload.encodeDelimited = function encodeDelimited(message, writer) {\n return this.encode(message, writer).ldelim();\n };\n\n /**\n * Decodes a SecurePayload message from the specified reader or buffer.\n * @function decode\n * @memberof secure.SecurePayload\n * @static\n * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from\n * @param {number} [length] Message length if known beforehand\n * @returns {secure.SecurePayload} SecurePayload\n * @throws {Error} If the payload is not a reader or valid buffer\n * @throws {$protobuf.util.ProtocolError} If required fields are missing\n */\n SecurePayload.decode = function decode(reader, length, error) {\n if (!(reader instanceof $Reader))\n reader = $Reader.create(reader);\n let end = length === undefined ? reader.len : reader.pos + length, message = new $root.secure.SecurePayload();\n while (reader.pos < end) {\n let tag = reader.uint32();\n if (tag === error)\n break;\n switch (tag >>> 3) {\n case 1: {\n message.ts = reader.int64();\n break;\n }\n case 2: {\n message.data = reader.bytes();\n break;\n }\n default:\n reader.skipType(tag & 7);\n break;\n }\n }\n return message;\n };\n\n /**\n * Decodes a SecurePayload message from the specified reader or buffer, length delimited.\n * @function decodeDelimited\n * @memberof secure.SecurePayload\n * @static\n * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from\n * @returns {secure.SecurePayload} SecurePayload\n * @throws {Error} If the payload is not a reader or valid buffer\n * @throws {$protobuf.util.ProtocolError} If required fields are missing\n */\n SecurePayload.decodeDelimited = function decodeDelimited(reader) {\n if (!(reader instanceof $Reader))\n reader = new $Reader(reader);\n return this.decode(reader, reader.uint32());\n };\n\n /**\n * Verifies a SecurePayload message.\n * @function verify\n * @memberof secure.SecurePayload\n * @static\n * @param {Object.<string,*>} message Plain object to verify\n * @returns {string|null} `null` if valid, otherwise the reason why it is not\n */\n SecurePayload.verify = function verify(message) {\n if (typeof message !== \"object\" || message === null)\n return \"object expected\";\n if (message.ts != null && message.hasOwnProperty(\"ts\"))\n if (!$util.isInteger(message.ts) && !(message.ts && $util.isInteger(message.ts.low) && $util.isInteger(message.ts.high)))\n return \"ts: integer|Long expected\";\n if (message.data != null && message.hasOwnProperty(\"data\"))\n if (!(message.data && typeof message.data.length === \"number\" || $util.isString(message.data)))\n return \"data: buffer expected\";\n return null;\n };\n\n /**\n * Creates a SecurePayload message from a plain object. Also converts values to their respective internal types.\n * @function fromObject\n * @memberof secure.SecurePayload\n * @static\n * @param {Object.<string,*>} object Plain object\n * @returns {secure.SecurePayload} SecurePayload\n */\n SecurePayload.fromObject = function fromObject(object) {\n if (object instanceof $root.secure.SecurePayload)\n return object;\n let message = new $root.secure.SecurePayload();\n if (object.ts != null)\n if ($util.Long)\n (message.ts = $util.Long.fromValue(object.ts)).unsigned = false;\n else if (typeof object.ts === \"string\")\n message.ts = parseInt(object.ts, 10);\n else if (typeof object.ts === \"number\")\n message.ts = object.ts;\n else if (typeof object.ts === \"object\")\n message.ts = new $util.LongBits(object.ts.low >>> 0, object.ts.high >>> 0).toNumber();\n if (object.data != null)\n if (typeof object.data === \"string\")\n $util.base64.decode(object.data, message.data = $util.newBuffer($util.base64.length(object.data)), 0);\n else if (object.data.length >= 0)\n message.data = object.data;\n return message;\n };\n\n /**\n * Creates a plain object from a SecurePayload message. Also converts values to other types if specified.\n * @function toObject\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.SecurePayload} message SecurePayload\n * @param {$protobuf.IConversionOptions} [options] Conversion options\n * @returns {Object.<string,*>} Plain object\n */\n SecurePayload.toObject = function toObject(message, options) {\n if (!options)\n options = {};\n let object = {};\n if (options.defaults) {\n if ($util.Long) {\n let long = new $util.Long(0, 0, false);\n object.ts = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;\n } else\n object.ts = options.longs === String ? \"0\" : 0;\n if (options.bytes === String)\n object.data = \"\";\n else {\n object.data = [];\n if (options.bytes !== Array)\n object.data = $util.newBuffer(object.data);\n }\n }\n if (message.ts != null && message.hasOwnProperty(\"ts\"))\n if (typeof message.ts === \"number\")\n object.ts = options.longs === String ? String(message.ts) : message.ts;\n else\n object.ts = options.longs === String ? $util.Long.prototype.toString.call(message.ts) : options.longs === Number ? new $util.LongBits(message.ts.low >>> 0, message.ts.high >>> 0).toNumber() : message.ts;\n if (message.data != null && message.hasOwnProperty(\"data\"))\n object.data = options.bytes === String ? $util.base64.encode(message.data, 0, message.data.length) : options.bytes === Array ? Array.prototype.slice.call(message.data) : message.data;\n return object;\n };\n\n /**\n * Converts this SecurePayload to JSON.\n * @function toJSON\n * @memberof secure.SecurePayload\n * @instance\n * @returns {Object.<string,*>} JSON object\n */\n SecurePayload.prototype.toJSON = function toJSON() {\n return this.constructor.toObject(this, $protobuf.util.toJSONOptions);\n };\n\n /**\n * Gets the default type url for SecurePayload\n * @function getTypeUrl\n * @memberof secure.SecurePayload\n * @static\n * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default \"type.googleapis.com\")\n * @returns {string} The default type url\n */\n SecurePayload.getTypeUrl = function getTypeUrl(typeUrlPrefix) {\n if (typeUrlPrefix === undefined) {\n typeUrlPrefix = \"type.googleapis.com\";\n }\n return typeUrlPrefix + \"/secure.SecurePayload\";\n };\n\n return SecurePayload;\n })();\n\n return secure;\n})();\n\nexport { $root as default };\n","/**\n * Protobuf 安全通信模块\n *\n * 提供基于 Protobuf 的二进制序列化、XOR 混淆加密以及与 API Client 的无缝集成。\n */\n\nimport protobuf from \"protobufjs/light\";\nimport { secure } from \"./secure.js\";\nimport type { FetchContext } from \"ofetch\";\n\n// ============================================================================\n// 1. 类型定义 (Types)\n// ============================================================================\n// export type ProtobufTypeLike = Pick<protobuf.Type, \"create\" | \"encode\" | \"decode\" | \"toObject\">;\nexport interface ProtobufTypeLike {\n // 1. 允许 properties 为任何对象,返回结果不再强制要求 $type\n create(properties?: Record<string, any>): any;\n // 2. 借用原生的参数类型约束,但手动简化返回类型\n encode(message: any): { finish(): Uint8Array };\n // 3. 借用原生的 decode 签名(支持 Uint8Array 和 Reader)\n decode(reader: Uint8Array | protobuf.Reader): any;\n // 4. 借用原生的 toObject 签名,保留 IConversionOptions 的类型检查\n toObject(message: any, options?: protobuf.IConversionOptions): any;\n}\n/**\n * 二进制混淆接口\n * 允许外部定义混淆逻辑,以便与不同语言实现的后端兼容\n */\nexport interface ProtobufObfuscator {\n encrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;\n decrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;\n}\n\n/**\n * Protobuf 编解码集成配置项\n * 用于控制序列化、混淆、钩子集成等全流程\n */\nexport interface ProtobufOptions {\n /**\n * 混淆器实现\n * 提供该选项时才会启用混淆\n */\n obfuscator?: ProtobufObfuscator;\n /** 预编译的 Protobuf 类型对象 (推荐,性能最高) */\n protoType?: ProtobufTypeLike;\n /** 数据转换钩子:处理业务模型与 Proto 结构不一致的情况 */\n transform?: {\n beforeEncode?: (data: any) => any;\n afterDecode?: (payload: any) => any;\n };\n /** 外部定义的编码逻辑 (返回原始二进制) */\n encode?: (data: any) => Uint8Array | Promise<Uint8Array>;\n /** 外部定义的解码逻辑 (返回原始对象) */\n decode?: <T>(buffer: Uint8Array) => T | Promise<T>;\n}\n\nexport const PROTOBUF_CONTENT_TYPE = \"application/x-protobuf\";\n\n/** 检查是否为 Protobuf 响应头 */\nexport function isProtobufContentType(contentType: string | null): boolean {\n return !!contentType?.toLowerCase().includes(PROTOBUF_CONTENT_TYPE);\n}\n\n/**\n * 获取 Protobuf 相关的 Header 配置对象\n */\nexport function getProtobufHeaders({\n send = true,\n receive = true,\n}: {\n send?: boolean;\n receive?: boolean;\n} = {}): Record<string, string> {\n const headers: Record<string, string> = {};\n\n if (send) {\n headers[\"Content-Type\"] = PROTOBUF_CONTENT_TYPE;\n }\n\n if (receive) {\n headers[\"Accept\"] = PROTOBUF_CONTENT_TYPE;\n }\n\n return headers;\n}\n\n/**\n * API Client 内部使用的标准化配置\n */\n// export interface ProtobufConfig {\n// encode: (data: any) => Uint8Array | Promise<Uint8Array>;\n// decode: <T>(buffer: Uint8Array) => T | Promise<T>;\n// options?: ProtobufCodecOptions;\n// }\n\n// ============================================================================\n// 2. 内部工具函数 (Internal Utilities)\n// ============================================================================\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/** 简单的二进制异或混淆转换 */\nexport function xorTransform(\n data: Uint8Array,\n key: string | Uint8Array,\n): Uint8Array {\n const keyBytes = typeof key === \"string\" ? encoder.encode(key) : key;\n if (keyBytes.length === 0) return data;\n\n for (let i = 0; i < data.length; i++) {\n data[i] ^= keyBytes[i % keyBytes.length];\n }\n return data;\n}\n\n/** 创建一个简单的 XOR 混淆器 */\nexport function createXorObfuscator(\n key: string | Uint8Array,\n): ProtobufObfuscator {\n return {\n encrypt: (data) => xorTransform(data, key),\n decrypt: (data) => xorTransform(data, key),\n };\n}\n\n/** 获取内置的 SecurePayload 类型(使用预编译代码) */\nfunction getInternalSecureType(): protobuf.Type {\n return secure.SecurePayload as unknown as protobuf.Type;\n}\n\n// ============================================================================\n// 3. 核心编解码逻辑 (Core Codecs)\n// ============================================================================\n\n/**\n * 编码安全载荷\n *\n * 流程:业务数据 -> (自定义编码 / Proto 序列化) -> 二进制混淆\n */\nexport async function encodeSecure<T>(\n data: T,\n options: ProtobufOptions = {},\n): Promise<Uint8Array> {\n const { obfuscator, protoType, transform, encode: customEncode } = options;\n\n let buffer: Uint8Array;\n\n // 1. 预处理阶段:无论后续走哪条路径,只要定义了 beforeEncode 就先执行\n const processedData = transform?.beforeEncode\n ? transform.beforeEncode(data)\n : data;\n\n // 1. 序列化阶段\n if (customEncode) {\n buffer = await customEncode(processedData);\n } else {\n const type = protoType || getInternalSecureType();\n\n // 构造最终要交给 Protobuf 序列化的对象\n const payload = protoType\n ? processedData // 自定义模式:直接使用预处理后的数据\n : {\n // 默认容器模式:将预处理后的数据封装进信封\n ts: Date.now(),\n data:\n processedData instanceof Uint8Array\n ? processedData\n : encoder.encode(JSON.stringify(processedData)),\n };\n\n const message = type.create(payload);\n buffer = type.encode(message).finish();\n }\n\n // 2. 混淆阶段\n if (obfuscator) {\n return await obfuscator.encrypt(buffer);\n }\n return buffer;\n}\n\n/**\n * 解码安全载荷\n *\n * 流程:二进制流 -> 二进制反混淆 -> (自定义解码 / Proto 反序列化) -> 业务数据\n */\nexport async function decodeSecure<T>(\n buffer: Uint8Array | ArrayBuffer,\n options: ProtobufOptions = {},\n): Promise<T> {\n const { obfuscator, protoType, transform, decode: customDecode } = options;\n\n // let uint8 = buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : buffer;\n // let uint8 =\n // buffer instanceof ArrayBuffer\n // ? new Uint8Array(buffer)\n // : new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n\n // 1. 标准化为 Uint8Array 视图 (跨环境最稳写法)\n let uint8 = ArrayBuffer.isView(buffer)\n ? new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength)\n : new Uint8Array(buffer);\n\n if (uint8.length === 0) {\n return null as T; // 或者返回 {},根据业务定\n }\n\n // 1. 混淆阶段\n if (uint8.length > 0 && obfuscator) {\n uint8 = await obfuscator.decrypt(uint8);\n }\n\n // 2. 反序列化阶段\n if (customDecode) {\n return await customDecode<T>(uint8);\n }\n\n const type = protoType || getInternalSecureType();\n const decoded = type.decode(uint8);\n const plainObj = type.toObject(decoded, {\n longs: String,\n enums: String,\n bytes: Uint8Array as any,\n defaults: true,\n });\n\n // 3. 转换阶段\n if (transform?.afterDecode) {\n return transform.afterDecode(plainObj);\n }\n\n // 内置容器模式的额外还原逻辑\n if (!protoType && plainObj.data) {\n const jsonString = decoder.decode(plainObj.data as Uint8Array);\n try {\n return JSON.parse(jsonString) as T;\n } catch {\n return jsonString as unknown as T;\n }\n }\n\n return plainObj as T;\n}\n\n// ============================================================================\n// 4. HTTP/环境适配工具 (HTTP Tools)\n// ============================================================================\n\n/** 创建安全响应 (Worker/Server 端使用) */\nexport async function secureResponse<T>(\n data: T,\n options?: ProtobufOptions & { corsHeaders?: Record<string, string> },\n): Promise<Response> {\n const buffer = await encodeSecure(data, options);\n // const arrayBuffer = buffer.buffer.slice(\n // buffer.byteOffset,\n // buffer.byteOffset + buffer.byteLength,\n // ) as ArrayBuffer;\n const cleanBuffer = buffer.slice();\n\n return new Response(cleanBuffer, {\n headers: {\n ...getProtobufHeaders({ send: true }),\n ...options?.corsHeaders,\n },\n });\n}\n\n/** * 解析安全请求体 (Worker/Server 端使用)\n * @param request 原生 Request 对象\n * @param options 编解码配置(可包含当前接口对应的 protoType 和自定义 obfuscator)\n */\nexport async function parseSecureRequest<T>(\n request: Request,\n options: ProtobufOptions = {}, // 统一使用这个配置对象\n): Promise<T> {\n const buffer = await request.arrayBuffer();\n return decodeSecure<T>(buffer, options);\n}\n\n/** 标准化配置对象 */\n// export function normalizeProtobufConfig(\n// config: boolean | ProtobufConfig | undefined,\n// options?: ProtobufHooksOptions, // 接收全局配置\n// ): ProtobufConfig | null {\n// if (!config) return null;\n// if (config === true) {\n// return {\n// encode: (data) => encodeSecure(data, options),\n// decode: <T>(buffer: Uint8Array) => decodeSecure<T>(buffer, options),\n// options,\n// };\n// }\n// return config;\n// }\n\n// ============================================================================\n// 5. API Client 钩子逻辑 (Integration Hooks)\n// ============================================================================\n\n/** 创建 Protobuf 编解码钩子 (用于与 createApiClient 配合使用) */\nexport function createProtobufHooks(globalOptions: ProtobufOptions = {}) {\n // const encode = (data: any) => encodeSecure(data, globalOptions);\n // const decode = <T>(buffer: Uint8Array) => decodeSecure<T>(buffer, globalOptions);\n\n return {\n async onRequest(context: FetchContext) {\n const { options: reqOptions } = context;\n\n // 1. 动态合并配置:将全局 globalOptions 和单次请求传的 reqOptions 合并\n // 这确保了 encodeSecure 能拿到当前请求特有的 protoType 或 transform\n const mergedOptions: ProtobufOptions = {\n ...globalOptions,\n ...reqOptions,\n };\n\n const headers =\n reqOptions.headers instanceof Headers\n ? reqOptions.headers\n : new Headers(reqOptions.headers as HeadersInit | undefined);\n\n // 自动编码请求体\n if (\n isProtobufContentType(headers.get(\"Content-Type\")) &&\n reqOptions.body &&\n !(reqOptions.body instanceof Uint8Array)\n ) {\n reqOptions.body = await encodeSecure(reqOptions.body, mergedOptions);\n }\n\n // 自动设置期望响应类型\n if (\n isProtobufContentType(headers.get(\"Accept\")) &&\n !reqOptions.responseType\n ) {\n reqOptions.responseType = \"arrayBuffer\";\n }\n\n reqOptions.headers = headers;\n },\n\n async onResponse(context: FetchContext) {\n const { response, options: reqOptions } = context;\n if (!response?._data || response.status === 204) return;\n\n // 同样在响应阶段合并 options,以获取单次请求指定的 protoType 来解码\n const mergedOptions: ProtobufOptions = {\n ...globalOptions,\n ...reqOptions,\n };\n\n if (isProtobufContentType(response.headers.get(\"Content-Type\"))) {\n try {\n // 这里的 _data 可能是 ArrayBuffer (浏览器) 或 Buffer (Node)\n // decodeSecure 内部已处理好兼容性\n response._data = await decodeSecure(response._data, mergedOptions);\n // const buffer = response._data as ArrayBuffer;\n // if (buffer && buffer.byteLength > 0) {\n // response._data = await decode(new Uint8Array(buffer));\n // }\n } catch (e) {\n console.log(\"Error [Protobuf Decode Error]\", e);\n response._data = null;\n }\n } else if (response._data instanceof ArrayBuffer) {\n const text = decoder.decode(response._data);\n try {\n response._data = JSON.parse(text);\n } catch {\n response._data = text;\n }\n }\n },\n };\n}\n"],"mappings":"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","names":["options","secure"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
executeRequestChain
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2OSF7OWV.mjs";
|
|
4
4
|
import {
|
|
5
5
|
createApiClient,
|
|
6
6
|
isApiError
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
parseSecureRequest,
|
|
17
17
|
secureResponse,
|
|
18
18
|
xorTransform
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-QJ34L7YD.mjs";
|
|
20
20
|
export {
|
|
21
21
|
PROTOBUF_CONTENT_TYPE,
|
|
22
22
|
createApiClient,
|
package/dist/protobuf.d.mts
CHANGED
|
@@ -24,10 +24,10 @@ interface ProtobufObfuscator {
|
|
|
24
24
|
decrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
27
|
+
* Protobuf 编解码集成配置项
|
|
28
|
+
* 用于控制序列化、混淆、钩子集成等全流程
|
|
29
29
|
*/
|
|
30
|
-
interface
|
|
30
|
+
interface ProtobufOptions {
|
|
31
31
|
/**
|
|
32
32
|
* 混淆器实现
|
|
33
33
|
* 提供该选项时才会启用混淆
|
|
@@ -40,23 +40,11 @@ interface ProtobufCodecOptions {
|
|
|
40
40
|
beforeEncode?: (data: any) => any;
|
|
41
41
|
afterDecode?: (payload: any) => any;
|
|
42
42
|
};
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* 完全自定义编解码接口
|
|
46
|
-
* 用于外部项目完全接管序列化过程,同时复用基础库的混淆外壳
|
|
47
|
-
*/
|
|
48
|
-
interface ProtobufCustomCodec {
|
|
49
43
|
/** 外部定义的编码逻辑 (返回原始二进制) */
|
|
50
44
|
encode?: (data: any) => Uint8Array | Promise<Uint8Array>;
|
|
51
45
|
/** 外部定义的解码逻辑 (返回原始对象) */
|
|
52
46
|
decode?: <T>(buffer: Uint8Array) => T | Promise<T>;
|
|
53
47
|
}
|
|
54
|
-
/**
|
|
55
|
-
* 集成配置项
|
|
56
|
-
* 用于 createProtobufHooks 或 API Client 全局配置
|
|
57
|
-
*/
|
|
58
|
-
interface ProtobufHooksOptions extends ProtobufCodecOptions, ProtobufCustomCodec {
|
|
59
|
-
}
|
|
60
48
|
declare const PROTOBUF_CONTENT_TYPE = "application/x-protobuf";
|
|
61
49
|
/** 检查是否为 Protobuf 响应头 */
|
|
62
50
|
declare function isProtobufContentType(contentType: string | null): boolean;
|
|
@@ -76,27 +64,27 @@ declare function createXorObfuscator(key: string | Uint8Array): ProtobufObfuscat
|
|
|
76
64
|
*
|
|
77
65
|
* 流程:业务数据 -> (自定义编码 / Proto 序列化) -> 二进制混淆
|
|
78
66
|
*/
|
|
79
|
-
declare function encodeSecure<T>(data: T, options?:
|
|
67
|
+
declare function encodeSecure<T>(data: T, options?: ProtobufOptions): Promise<Uint8Array>;
|
|
80
68
|
/**
|
|
81
69
|
* 解码安全载荷
|
|
82
70
|
*
|
|
83
71
|
* 流程:二进制流 -> 二进制反混淆 -> (自定义解码 / Proto 反序列化) -> 业务数据
|
|
84
72
|
*/
|
|
85
|
-
declare function decodeSecure<T>(buffer: Uint8Array | ArrayBuffer, options?:
|
|
73
|
+
declare function decodeSecure<T>(buffer: Uint8Array | ArrayBuffer, options?: ProtobufOptions): Promise<T>;
|
|
86
74
|
/** 创建安全响应 (Worker/Server 端使用) */
|
|
87
|
-
declare function secureResponse<T>(data: T, options?:
|
|
75
|
+
declare function secureResponse<T>(data: T, options?: ProtobufOptions & {
|
|
88
76
|
corsHeaders?: Record<string, string>;
|
|
89
77
|
}): Promise<Response>;
|
|
90
78
|
/** * 解析安全请求体 (Worker/Server 端使用)
|
|
91
79
|
* @param request 原生 Request 对象
|
|
92
80
|
* @param options 编解码配置(可包含当前接口对应的 protoType 和自定义 obfuscator)
|
|
93
81
|
*/
|
|
94
|
-
declare function parseSecureRequest<T>(request: Request, options?:
|
|
82
|
+
declare function parseSecureRequest<T>(request: Request, options?: ProtobufOptions): Promise<T>;
|
|
95
83
|
/** 标准化配置对象 */
|
|
96
84
|
/** 创建 Protobuf 编解码钩子 (用于与 createApiClient 配合使用) */
|
|
97
|
-
declare function createProtobufHooks(globalOptions?:
|
|
85
|
+
declare function createProtobufHooks(globalOptions?: ProtobufOptions): {
|
|
98
86
|
onRequest(context: FetchContext): Promise<void>;
|
|
99
87
|
onResponse(context: FetchContext): Promise<void>;
|
|
100
88
|
};
|
|
101
89
|
|
|
102
|
-
export { PROTOBUF_CONTENT_TYPE, type
|
|
90
|
+
export { PROTOBUF_CONTENT_TYPE, type ProtobufObfuscator, type ProtobufOptions, type ProtobufTypeLike, createProtobufHooks, createXorObfuscator, decodeSecure, encodeSecure, getProtobufHeaders, isProtobufContentType, parseSecureRequest, secureResponse, xorTransform };
|
package/dist/protobuf.d.ts
CHANGED
|
@@ -24,10 +24,10 @@ interface ProtobufObfuscator {
|
|
|
24
24
|
decrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
27
|
+
* Protobuf 编解码集成配置项
|
|
28
|
+
* 用于控制序列化、混淆、钩子集成等全流程
|
|
29
29
|
*/
|
|
30
|
-
interface
|
|
30
|
+
interface ProtobufOptions {
|
|
31
31
|
/**
|
|
32
32
|
* 混淆器实现
|
|
33
33
|
* 提供该选项时才会启用混淆
|
|
@@ -40,23 +40,11 @@ interface ProtobufCodecOptions {
|
|
|
40
40
|
beforeEncode?: (data: any) => any;
|
|
41
41
|
afterDecode?: (payload: any) => any;
|
|
42
42
|
};
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* 完全自定义编解码接口
|
|
46
|
-
* 用于外部项目完全接管序列化过程,同时复用基础库的混淆外壳
|
|
47
|
-
*/
|
|
48
|
-
interface ProtobufCustomCodec {
|
|
49
43
|
/** 外部定义的编码逻辑 (返回原始二进制) */
|
|
50
44
|
encode?: (data: any) => Uint8Array | Promise<Uint8Array>;
|
|
51
45
|
/** 外部定义的解码逻辑 (返回原始对象) */
|
|
52
46
|
decode?: <T>(buffer: Uint8Array) => T | Promise<T>;
|
|
53
47
|
}
|
|
54
|
-
/**
|
|
55
|
-
* 集成配置项
|
|
56
|
-
* 用于 createProtobufHooks 或 API Client 全局配置
|
|
57
|
-
*/
|
|
58
|
-
interface ProtobufHooksOptions extends ProtobufCodecOptions, ProtobufCustomCodec {
|
|
59
|
-
}
|
|
60
48
|
declare const PROTOBUF_CONTENT_TYPE = "application/x-protobuf";
|
|
61
49
|
/** 检查是否为 Protobuf 响应头 */
|
|
62
50
|
declare function isProtobufContentType(contentType: string | null): boolean;
|
|
@@ -76,27 +64,27 @@ declare function createXorObfuscator(key: string | Uint8Array): ProtobufObfuscat
|
|
|
76
64
|
*
|
|
77
65
|
* 流程:业务数据 -> (自定义编码 / Proto 序列化) -> 二进制混淆
|
|
78
66
|
*/
|
|
79
|
-
declare function encodeSecure<T>(data: T, options?:
|
|
67
|
+
declare function encodeSecure<T>(data: T, options?: ProtobufOptions): Promise<Uint8Array>;
|
|
80
68
|
/**
|
|
81
69
|
* 解码安全载荷
|
|
82
70
|
*
|
|
83
71
|
* 流程:二进制流 -> 二进制反混淆 -> (自定义解码 / Proto 反序列化) -> 业务数据
|
|
84
72
|
*/
|
|
85
|
-
declare function decodeSecure<T>(buffer: Uint8Array | ArrayBuffer, options?:
|
|
73
|
+
declare function decodeSecure<T>(buffer: Uint8Array | ArrayBuffer, options?: ProtobufOptions): Promise<T>;
|
|
86
74
|
/** 创建安全响应 (Worker/Server 端使用) */
|
|
87
|
-
declare function secureResponse<T>(data: T, options?:
|
|
75
|
+
declare function secureResponse<T>(data: T, options?: ProtobufOptions & {
|
|
88
76
|
corsHeaders?: Record<string, string>;
|
|
89
77
|
}): Promise<Response>;
|
|
90
78
|
/** * 解析安全请求体 (Worker/Server 端使用)
|
|
91
79
|
* @param request 原生 Request 对象
|
|
92
80
|
* @param options 编解码配置(可包含当前接口对应的 protoType 和自定义 obfuscator)
|
|
93
81
|
*/
|
|
94
|
-
declare function parseSecureRequest<T>(request: Request, options?:
|
|
82
|
+
declare function parseSecureRequest<T>(request: Request, options?: ProtobufOptions): Promise<T>;
|
|
95
83
|
/** 标准化配置对象 */
|
|
96
84
|
/** 创建 Protobuf 编解码钩子 (用于与 createApiClient 配合使用) */
|
|
97
|
-
declare function createProtobufHooks(globalOptions?:
|
|
85
|
+
declare function createProtobufHooks(globalOptions?: ProtobufOptions): {
|
|
98
86
|
onRequest(context: FetchContext): Promise<void>;
|
|
99
87
|
onResponse(context: FetchContext): Promise<void>;
|
|
100
88
|
};
|
|
101
89
|
|
|
102
|
-
export { PROTOBUF_CONTENT_TYPE, type
|
|
90
|
+
export { PROTOBUF_CONTENT_TYPE, type ProtobufObfuscator, type ProtobufOptions, type ProtobufTypeLike, createProtobufHooks, createXorObfuscator, decodeSecure, encodeSecure, getProtobufHeaders, isProtobufContentType, parseSecureRequest, secureResponse, xorTransform };
|
package/dist/protobuf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/protobuf.ts","../src/secure.js"],"sourcesContent":["/**\n * Protobuf 安全通信模块\n *\n * 提供基于 Protobuf 的二进制序列化、XOR 混淆加密以及与 API Client 的无缝集成。\n */\n\nimport protobuf from \"protobufjs/light\";\nimport { secure } from \"./secure.js\";\nimport type { FetchContext } from \"ofetch\";\n\n// ============================================================================\n// 1. 类型定义 (Types)\n// ============================================================================\n// export type ProtobufTypeLike = Pick<protobuf.Type, \"create\" | \"encode\" | \"decode\" | \"toObject\">;\nexport interface ProtobufTypeLike {\n // 1. 允许 properties 为任何对象,返回结果不再强制要求 $type\n create(properties?: Record<string, any>): any;\n // 2. 借用原生的参数类型约束,但手动简化返回类型\n encode(message: any): { finish(): Uint8Array };\n // 3. 借用原生的 decode 签名(支持 Uint8Array 和 Reader)\n decode(reader: Uint8Array | protobuf.Reader): any;\n // 4. 借用原生的 toObject 签名,保留 IConversionOptions 的类型检查\n toObject(message: any, options?: protobuf.IConversionOptions): any;\n}\n/**\n * 二进制混淆接口\n * 允许外部定义混淆逻辑,以便与不同语言实现的后端兼容\n */\nexport interface ProtobufObfuscator {\n encrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;\n decrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;\n}\n\n/**\n * 基础编解码配置\n * 控制如何将数据转换为二进制,以及是否混淆\n */\nexport interface ProtobufCodecOptions {\n /**\n * 混淆器实现\n * 提供该选项时才会启用混淆\n */\n obfuscator?: ProtobufObfuscator;\n /** 预编译的 Protobuf 类型对象 (推荐,性能最高) */\n protoType?: ProtobufTypeLike;\n /** 数据转换钩子:处理业务模型与 Proto 结构不一致的情况 */\n transform?: {\n beforeEncode?: (data: any) => any;\n afterDecode?: (payload: any) => any;\n };\n}\n\n/**\n * 完全自定义编解码接口\n * 用于外部项目完全接管序列化过程,同时复用基础库的混淆外壳\n */\nexport interface ProtobufCustomCodec {\n /** 外部定义的编码逻辑 (返回原始二进制) */\n encode?: (data: any) => Uint8Array | Promise<Uint8Array>;\n /** 外部定义的解码逻辑 (返回原始对象) */\n decode?: <T>(buffer: Uint8Array) => T | Promise<T>;\n}\n\n/**\n * 集成配置项\n * 用于 createProtobufHooks 或 API Client 全局配置\n */\nexport interface ProtobufHooksOptions\n extends ProtobufCodecOptions, ProtobufCustomCodec {}\n\nexport const PROTOBUF_CONTENT_TYPE = \"application/x-protobuf\";\n\n/** 检查是否为 Protobuf 响应头 */\nexport function isProtobufContentType(contentType: string | null): boolean {\n return !!contentType?.toLowerCase().includes(PROTOBUF_CONTENT_TYPE);\n}\n\n/**\n * 获取 Protobuf 相关的 Header 配置对象\n */\nexport function getProtobufHeaders({\n send = true,\n receive = true,\n}: {\n send?: boolean;\n receive?: boolean;\n} = {}): Record<string, string> {\n const headers: Record<string, string> = {};\n\n if (send) {\n headers[\"Content-Type\"] = PROTOBUF_CONTENT_TYPE;\n }\n\n if (receive) {\n headers[\"Accept\"] = PROTOBUF_CONTENT_TYPE;\n }\n\n return headers;\n}\n\n/**\n * API Client 内部使用的标准化配置\n */\n// export interface ProtobufConfig {\n// encode: (data: any) => Uint8Array | Promise<Uint8Array>;\n// decode: <T>(buffer: Uint8Array) => T | Promise<T>;\n// options?: ProtobufCodecOptions;\n// }\n\n// ============================================================================\n// 2. 内部工具函数 (Internal Utilities)\n// ============================================================================\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/** 简单的二进制异或混淆转换 */\nexport function xorTransform(\n data: Uint8Array,\n key: string | Uint8Array,\n): Uint8Array {\n const keyBytes = typeof key === \"string\" ? encoder.encode(key) : key;\n if (keyBytes.length === 0) return data;\n\n for (let i = 0; i < data.length; i++) {\n data[i] ^= keyBytes[i % keyBytes.length];\n }\n return data;\n}\n\n/** 创建一个简单的 XOR 混淆器 */\nexport function createXorObfuscator(\n key: string | Uint8Array,\n): ProtobufObfuscator {\n return {\n encrypt: (data) => xorTransform(data, key),\n decrypt: (data) => xorTransform(data, key),\n };\n}\n\n/** 获取内置的 SecurePayload 类型(使用预编译代码) */\nfunction getInternalSecureType(): protobuf.Type {\n return secure.SecurePayload as unknown as protobuf.Type;\n}\n\n// ============================================================================\n// 3. 核心编解码逻辑 (Core Codecs)\n// ============================================================================\n\n/**\n * 编码安全载荷\n *\n * 流程:业务数据 -> (自定义编码 / Proto 序列化) -> 二进制混淆\n */\nexport async function encodeSecure<T>(\n data: T,\n options: ProtobufHooksOptions = {},\n): Promise<Uint8Array> {\n const { obfuscator, protoType, transform, encode: customEncode } = options;\n\n let buffer: Uint8Array;\n\n // 1. 预处理阶段:无论后续走哪条路径,只要定义了 beforeEncode 就先执行\n const processedData = transform?.beforeEncode\n ? transform.beforeEncode(data)\n : data;\n\n // 1. 序列化阶段\n if (customEncode) {\n buffer = await customEncode(processedData);\n } else {\n const type = protoType || getInternalSecureType();\n\n // 构造最终要交给 Protobuf 序列化的对象\n const payload = protoType\n ? processedData // 自定义模式:直接使用预处理后的数据\n : {\n // 默认容器模式:将预处理后的数据封装进信封\n ts: Date.now(),\n data:\n processedData instanceof Uint8Array\n ? processedData\n : encoder.encode(JSON.stringify(processedData)),\n };\n\n const message = type.create(payload);\n buffer = type.encode(message).finish();\n }\n\n // 2. 混淆阶段\n if (obfuscator) {\n return await obfuscator.encrypt(buffer);\n }\n return buffer;\n}\n\n/**\n * 解码安全载荷\n *\n * 流程:二进制流 -> 二进制反混淆 -> (自定义解码 / Proto 反序列化) -> 业务数据\n */\nexport async function decodeSecure<T>(\n buffer: Uint8Array | ArrayBuffer,\n options: ProtobufHooksOptions = {},\n): Promise<T> {\n const { obfuscator, protoType, transform, decode: customDecode } = options;\n\n // let uint8 = buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : buffer;\n // let uint8 =\n // buffer instanceof ArrayBuffer\n // ? new Uint8Array(buffer)\n // : new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n\n // 1. 标准化为 Uint8Array 视图 (跨环境最稳写法)\n let uint8 = ArrayBuffer.isView(buffer)\n ? new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength)\n : new Uint8Array(buffer);\n\n if (uint8.length === 0) {\n return null as T; // 或者返回 {},根据业务定\n }\n\n // 1. 混淆阶段\n if (uint8.length > 0 && obfuscator) {\n uint8 = await obfuscator.decrypt(uint8);\n }\n\n // 2. 反序列化阶段\n if (customDecode) {\n return await customDecode<T>(uint8);\n }\n\n const type = protoType || getInternalSecureType();\n const decoded = type.decode(uint8);\n const plainObj = type.toObject(decoded, {\n longs: String,\n enums: String,\n bytes: Uint8Array as any,\n defaults: true,\n });\n\n // 3. 转换阶段\n if (transform?.afterDecode) {\n return transform.afterDecode(plainObj);\n }\n\n // 内置容器模式的额外还原逻辑\n if (!protoType && plainObj.data) {\n const jsonString = decoder.decode(plainObj.data as Uint8Array);\n try {\n return JSON.parse(jsonString) as T;\n } catch {\n return jsonString as unknown as T;\n }\n }\n\n return plainObj as T;\n}\n\n// ============================================================================\n// 4. HTTP/环境适配工具 (HTTP Tools)\n// ============================================================================\n\n/** 创建安全响应 (Worker/Server 端使用) */\nexport async function secureResponse<T>(\n data: T,\n options?: ProtobufCodecOptions & { corsHeaders?: Record<string, string> },\n): Promise<Response> {\n const buffer = await encodeSecure(data, options);\n // const arrayBuffer = buffer.buffer.slice(\n // buffer.byteOffset,\n // buffer.byteOffset + buffer.byteLength,\n // ) as ArrayBuffer;\n const cleanBuffer = buffer.slice();\n\n return new Response(cleanBuffer, {\n headers: {\n ...getProtobufHeaders({ send: true }),\n ...options?.corsHeaders,\n },\n });\n}\n\n/** * 解析安全请求体 (Worker/Server 端使用)\n * @param request 原生 Request 对象\n * @param options 编解码配置(可包含当前接口对应的 protoType 和自定义 obfuscator)\n */\nexport async function parseSecureRequest<T>(\n request: Request,\n options: ProtobufHooksOptions = {}, // 统一使用这个配置对象\n): Promise<T> {\n const buffer = await request.arrayBuffer();\n return decodeSecure<T>(buffer, options);\n}\n\n/** 标准化配置对象 */\n// export function normalizeProtobufConfig(\n// config: boolean | ProtobufConfig | undefined,\n// options?: ProtobufHooksOptions, // 接收全局配置\n// ): ProtobufConfig | null {\n// if (!config) return null;\n// if (config === true) {\n// return {\n// encode: (data) => encodeSecure(data, options),\n// decode: <T>(buffer: Uint8Array) => decodeSecure<T>(buffer, options),\n// options,\n// };\n// }\n// return config;\n// }\n\n// ============================================================================\n// 5. API Client 钩子逻辑 (Integration Hooks)\n// ============================================================================\n\n/** 创建 Protobuf 编解码钩子 (用于与 createApiClient 配合使用) */\nexport function createProtobufHooks(globalOptions: ProtobufHooksOptions = {}) {\n // const encode = (data: any) => encodeSecure(data, globalOptions);\n // const decode = <T>(buffer: Uint8Array) => decodeSecure<T>(buffer, globalOptions);\n\n return {\n async onRequest(context: FetchContext) {\n const { options: reqOptions } = context;\n\n // 1. 动态合并配置:将全局 globalOptions 和单次请求传的 reqOptions 合并\n // 这确保了 encodeSecure 能拿到当前请求特有的 protoType 或 transform\n const mergedOptions: ProtobufHooksOptions = {\n ...globalOptions,\n ...reqOptions,\n };\n\n const headers =\n reqOptions.headers instanceof Headers\n ? reqOptions.headers\n : new Headers(reqOptions.headers as HeadersInit | undefined);\n\n // 自动编码请求体\n if (\n isProtobufContentType(headers.get(\"Content-Type\")) &&\n reqOptions.body &&\n !(reqOptions.body instanceof Uint8Array)\n ) {\n reqOptions.body = await encodeSecure(reqOptions.body, mergedOptions);\n }\n\n // 自动设置期望响应类型\n if (\n isProtobufContentType(headers.get(\"Accept\")) &&\n !reqOptions.responseType\n ) {\n reqOptions.responseType = \"arrayBuffer\";\n }\n\n reqOptions.headers = headers;\n },\n\n async onResponse(context: FetchContext) {\n const { response, options: reqOptions } = context;\n if (!response?._data || response.status === 204) return;\n\n // 同样在响应阶段合并 options,以获取单次请求指定的 protoType 来解码\n const mergedOptions: ProtobufHooksOptions = {\n ...globalOptions,\n ...reqOptions,\n };\n\n if (isProtobufContentType(response.headers.get(\"Content-Type\"))) {\n try {\n // 这里的 _data 可能是 ArrayBuffer (浏览器) 或 Buffer (Node)\n // decodeSecure 内部已处理好兼容性\n response._data = await decodeSecure(response._data, mergedOptions);\n // const buffer = response._data as ArrayBuffer;\n // if (buffer && buffer.byteLength > 0) {\n // response._data = await decode(new Uint8Array(buffer));\n // }\n } catch (e) {\n console.log(\"Error [Protobuf Decode Error]\", e);\n response._data = null;\n }\n } else if (response._data instanceof ArrayBuffer) {\n const text = decoder.decode(response._data);\n try {\n response._data = JSON.parse(text);\n } catch {\n response._data = text;\n }\n }\n },\n };\n}\n","/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/\nimport * as $protobuf from \"protobufjs/minimal\";\n\n// Common aliases\nconst $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;\n\n// Exported root namespace\nconst $root = $protobuf.roots[\"default\"] || ($protobuf.roots[\"default\"] = {});\n\nexport const secure = $root.secure = (() => {\n\n /**\n * Namespace secure.\n * @exports secure\n * @namespace\n */\n const secure = {};\n\n secure.SecurePayload = (function() {\n\n /**\n * Properties of a SecurePayload.\n * @memberof secure\n * @interface ISecurePayload\n * @property {number|Long|null} [ts] SecurePayload ts\n * @property {Uint8Array|null} [data] SecurePayload data\n */\n\n /**\n * Constructs a new SecurePayload.\n * @memberof secure\n * @classdesc Represents a SecurePayload.\n * @implements ISecurePayload\n * @constructor\n * @param {secure.ISecurePayload=} [properties] Properties to set\n */\n function SecurePayload(properties) {\n if (properties)\n for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)\n if (properties[keys[i]] != null)\n this[keys[i]] = properties[keys[i]];\n }\n\n /**\n * SecurePayload ts.\n * @member {number|Long} ts\n * @memberof secure.SecurePayload\n * @instance\n */\n SecurePayload.prototype.ts = $util.Long ? $util.Long.fromBits(0,0,false) : 0;\n\n /**\n * SecurePayload data.\n * @member {Uint8Array} data\n * @memberof secure.SecurePayload\n * @instance\n */\n SecurePayload.prototype.data = $util.newBuffer([]);\n\n /**\n * Creates a new SecurePayload instance using the specified properties.\n * @function create\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload=} [properties] Properties to set\n * @returns {secure.SecurePayload} SecurePayload instance\n */\n SecurePayload.create = function create(properties) {\n return new SecurePayload(properties);\n };\n\n /**\n * Encodes the specified SecurePayload message. Does not implicitly {@link secure.SecurePayload.verify|verify} messages.\n * @function encode\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload} message SecurePayload message or plain object to encode\n * @param {$protobuf.Writer} [writer] Writer to encode to\n * @returns {$protobuf.Writer} Writer\n */\n SecurePayload.encode = function encode(message, writer) {\n if (!writer)\n writer = $Writer.create();\n if (message.ts != null && Object.hasOwnProperty.call(message, \"ts\"))\n writer.uint32(/* id 1, wireType 0 =*/8).int64(message.ts);\n if (message.data != null && Object.hasOwnProperty.call(message, \"data\"))\n writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.data);\n return writer;\n };\n\n /**\n * Encodes the specified SecurePayload message, length delimited. Does not implicitly {@link secure.SecurePayload.verify|verify} messages.\n * @function encodeDelimited\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload} message SecurePayload message or plain object to encode\n * @param {$protobuf.Writer} [writer] Writer to encode to\n * @returns {$protobuf.Writer} Writer\n */\n SecurePayload.encodeDelimited = function encodeDelimited(message, writer) {\n return this.encode(message, writer).ldelim();\n };\n\n /**\n * Decodes a SecurePayload message from the specified reader or buffer.\n * @function decode\n * @memberof secure.SecurePayload\n * @static\n * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from\n * @param {number} [length] Message length if known beforehand\n * @returns {secure.SecurePayload} SecurePayload\n * @throws {Error} If the payload is not a reader or valid buffer\n * @throws {$protobuf.util.ProtocolError} If required fields are missing\n */\n SecurePayload.decode = function decode(reader, length, error) {\n if (!(reader instanceof $Reader))\n reader = $Reader.create(reader);\n let end = length === undefined ? reader.len : reader.pos + length, message = new $root.secure.SecurePayload();\n while (reader.pos < end) {\n let tag = reader.uint32();\n if (tag === error)\n break;\n switch (tag >>> 3) {\n case 1: {\n message.ts = reader.int64();\n break;\n }\n case 2: {\n message.data = reader.bytes();\n break;\n }\n default:\n reader.skipType(tag & 7);\n break;\n }\n }\n return message;\n };\n\n /**\n * Decodes a SecurePayload message from the specified reader or buffer, length delimited.\n * @function decodeDelimited\n * @memberof secure.SecurePayload\n * @static\n * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from\n * @returns {secure.SecurePayload} SecurePayload\n * @throws {Error} If the payload is not a reader or valid buffer\n * @throws {$protobuf.util.ProtocolError} If required fields are missing\n */\n SecurePayload.decodeDelimited = function decodeDelimited(reader) {\n if (!(reader instanceof $Reader))\n reader = new $Reader(reader);\n return this.decode(reader, reader.uint32());\n };\n\n /**\n * Verifies a SecurePayload message.\n * @function verify\n * @memberof secure.SecurePayload\n * @static\n * @param {Object.<string,*>} message Plain object to verify\n * @returns {string|null} `null` if valid, otherwise the reason why it is not\n */\n SecurePayload.verify = function verify(message) {\n if (typeof message !== \"object\" || message === null)\n return \"object expected\";\n if (message.ts != null && message.hasOwnProperty(\"ts\"))\n if (!$util.isInteger(message.ts) && !(message.ts && $util.isInteger(message.ts.low) && $util.isInteger(message.ts.high)))\n return \"ts: integer|Long expected\";\n if (message.data != null && message.hasOwnProperty(\"data\"))\n if (!(message.data && typeof message.data.length === \"number\" || $util.isString(message.data)))\n return \"data: buffer expected\";\n return null;\n };\n\n /**\n * Creates a SecurePayload message from a plain object. Also converts values to their respective internal types.\n * @function fromObject\n * @memberof secure.SecurePayload\n * @static\n * @param {Object.<string,*>} object Plain object\n * @returns {secure.SecurePayload} SecurePayload\n */\n SecurePayload.fromObject = function fromObject(object) {\n if (object instanceof $root.secure.SecurePayload)\n return object;\n let message = new $root.secure.SecurePayload();\n if (object.ts != null)\n if ($util.Long)\n (message.ts = $util.Long.fromValue(object.ts)).unsigned = false;\n else if (typeof object.ts === \"string\")\n message.ts = parseInt(object.ts, 10);\n else if (typeof object.ts === \"number\")\n message.ts = object.ts;\n else if (typeof object.ts === \"object\")\n message.ts = new $util.LongBits(object.ts.low >>> 0, object.ts.high >>> 0).toNumber();\n if (object.data != null)\n if (typeof object.data === \"string\")\n $util.base64.decode(object.data, message.data = $util.newBuffer($util.base64.length(object.data)), 0);\n else if (object.data.length >= 0)\n message.data = object.data;\n return message;\n };\n\n /**\n * Creates a plain object from a SecurePayload message. Also converts values to other types if specified.\n * @function toObject\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.SecurePayload} message SecurePayload\n * @param {$protobuf.IConversionOptions} [options] Conversion options\n * @returns {Object.<string,*>} Plain object\n */\n SecurePayload.toObject = function toObject(message, options) {\n if (!options)\n options = {};\n let object = {};\n if (options.defaults) {\n if ($util.Long) {\n let long = new $util.Long(0, 0, false);\n object.ts = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;\n } else\n object.ts = options.longs === String ? \"0\" : 0;\n if (options.bytes === String)\n object.data = \"\";\n else {\n object.data = [];\n if (options.bytes !== Array)\n object.data = $util.newBuffer(object.data);\n }\n }\n if (message.ts != null && message.hasOwnProperty(\"ts\"))\n if (typeof message.ts === \"number\")\n object.ts = options.longs === String ? String(message.ts) : message.ts;\n else\n object.ts = options.longs === String ? $util.Long.prototype.toString.call(message.ts) : options.longs === Number ? new $util.LongBits(message.ts.low >>> 0, message.ts.high >>> 0).toNumber() : message.ts;\n if (message.data != null && message.hasOwnProperty(\"data\"))\n object.data = options.bytes === String ? $util.base64.encode(message.data, 0, message.data.length) : options.bytes === Array ? Array.prototype.slice.call(message.data) : message.data;\n return object;\n };\n\n /**\n * Converts this SecurePayload to JSON.\n * @function toJSON\n * @memberof secure.SecurePayload\n * @instance\n * @returns {Object.<string,*>} JSON object\n */\n SecurePayload.prototype.toJSON = function toJSON() {\n return this.constructor.toObject(this, $protobuf.util.toJSONOptions);\n };\n\n /**\n * Gets the default type url for SecurePayload\n * @function getTypeUrl\n * @memberof secure.SecurePayload\n * @static\n * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default \"type.googleapis.com\")\n * @returns {string} The default type url\n */\n SecurePayload.getTypeUrl = function getTypeUrl(typeUrlPrefix) {\n if (typeUrlPrefix === undefined) {\n typeUrlPrefix = \"type.googleapis.com\";\n }\n return typeUrlPrefix + \"/secure.SecurePayload\";\n };\n\n return SecurePayload;\n })();\n\n return secure;\n})();\n\nexport { $root as default };\n"],"mappings":"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","names":["secure"]}
|
|
1
|
+
{"version":3,"sources":["../src/protobuf.ts","../src/secure.js"],"sourcesContent":["/**\n * Protobuf 安全通信模块\n *\n * 提供基于 Protobuf 的二进制序列化、XOR 混淆加密以及与 API Client 的无缝集成。\n */\n\nimport protobuf from \"protobufjs/light\";\nimport { secure } from \"./secure.js\";\nimport type { FetchContext } from \"ofetch\";\n\n// ============================================================================\n// 1. 类型定义 (Types)\n// ============================================================================\n// export type ProtobufTypeLike = Pick<protobuf.Type, \"create\" | \"encode\" | \"decode\" | \"toObject\">;\nexport interface ProtobufTypeLike {\n // 1. 允许 properties 为任何对象,返回结果不再强制要求 $type\n create(properties?: Record<string, any>): any;\n // 2. 借用原生的参数类型约束,但手动简化返回类型\n encode(message: any): { finish(): Uint8Array };\n // 3. 借用原生的 decode 签名(支持 Uint8Array 和 Reader)\n decode(reader: Uint8Array | protobuf.Reader): any;\n // 4. 借用原生的 toObject 签名,保留 IConversionOptions 的类型检查\n toObject(message: any, options?: protobuf.IConversionOptions): any;\n}\n/**\n * 二进制混淆接口\n * 允许外部定义混淆逻辑,以便与不同语言实现的后端兼容\n */\nexport interface ProtobufObfuscator {\n encrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;\n decrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;\n}\n\n/**\n * Protobuf 编解码集成配置项\n * 用于控制序列化、混淆、钩子集成等全流程\n */\nexport interface ProtobufOptions {\n /**\n * 混淆器实现\n * 提供该选项时才会启用混淆\n */\n obfuscator?: ProtobufObfuscator;\n /** 预编译的 Protobuf 类型对象 (推荐,性能最高) */\n protoType?: ProtobufTypeLike;\n /** 数据转换钩子:处理业务模型与 Proto 结构不一致的情况 */\n transform?: {\n beforeEncode?: (data: any) => any;\n afterDecode?: (payload: any) => any;\n };\n /** 外部定义的编码逻辑 (返回原始二进制) */\n encode?: (data: any) => Uint8Array | Promise<Uint8Array>;\n /** 外部定义的解码逻辑 (返回原始对象) */\n decode?: <T>(buffer: Uint8Array) => T | Promise<T>;\n}\n\nexport const PROTOBUF_CONTENT_TYPE = \"application/x-protobuf\";\n\n/** 检查是否为 Protobuf 响应头 */\nexport function isProtobufContentType(contentType: string | null): boolean {\n return !!contentType?.toLowerCase().includes(PROTOBUF_CONTENT_TYPE);\n}\n\n/**\n * 获取 Protobuf 相关的 Header 配置对象\n */\nexport function getProtobufHeaders({\n send = true,\n receive = true,\n}: {\n send?: boolean;\n receive?: boolean;\n} = {}): Record<string, string> {\n const headers: Record<string, string> = {};\n\n if (send) {\n headers[\"Content-Type\"] = PROTOBUF_CONTENT_TYPE;\n }\n\n if (receive) {\n headers[\"Accept\"] = PROTOBUF_CONTENT_TYPE;\n }\n\n return headers;\n}\n\n/**\n * API Client 内部使用的标准化配置\n */\n// export interface ProtobufConfig {\n// encode: (data: any) => Uint8Array | Promise<Uint8Array>;\n// decode: <T>(buffer: Uint8Array) => T | Promise<T>;\n// options?: ProtobufCodecOptions;\n// }\n\n// ============================================================================\n// 2. 内部工具函数 (Internal Utilities)\n// ============================================================================\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/** 简单的二进制异或混淆转换 */\nexport function xorTransform(\n data: Uint8Array,\n key: string | Uint8Array,\n): Uint8Array {\n const keyBytes = typeof key === \"string\" ? encoder.encode(key) : key;\n if (keyBytes.length === 0) return data;\n\n for (let i = 0; i < data.length; i++) {\n data[i] ^= keyBytes[i % keyBytes.length];\n }\n return data;\n}\n\n/** 创建一个简单的 XOR 混淆器 */\nexport function createXorObfuscator(\n key: string | Uint8Array,\n): ProtobufObfuscator {\n return {\n encrypt: (data) => xorTransform(data, key),\n decrypt: (data) => xorTransform(data, key),\n };\n}\n\n/** 获取内置的 SecurePayload 类型(使用预编译代码) */\nfunction getInternalSecureType(): protobuf.Type {\n return secure.SecurePayload as unknown as protobuf.Type;\n}\n\n// ============================================================================\n// 3. 核心编解码逻辑 (Core Codecs)\n// ============================================================================\n\n/**\n * 编码安全载荷\n *\n * 流程:业务数据 -> (自定义编码 / Proto 序列化) -> 二进制混淆\n */\nexport async function encodeSecure<T>(\n data: T,\n options: ProtobufOptions = {},\n): Promise<Uint8Array> {\n const { obfuscator, protoType, transform, encode: customEncode } = options;\n\n let buffer: Uint8Array;\n\n // 1. 预处理阶段:无论后续走哪条路径,只要定义了 beforeEncode 就先执行\n const processedData = transform?.beforeEncode\n ? transform.beforeEncode(data)\n : data;\n\n // 1. 序列化阶段\n if (customEncode) {\n buffer = await customEncode(processedData);\n } else {\n const type = protoType || getInternalSecureType();\n\n // 构造最终要交给 Protobuf 序列化的对象\n const payload = protoType\n ? processedData // 自定义模式:直接使用预处理后的数据\n : {\n // 默认容器模式:将预处理后的数据封装进信封\n ts: Date.now(),\n data:\n processedData instanceof Uint8Array\n ? processedData\n : encoder.encode(JSON.stringify(processedData)),\n };\n\n const message = type.create(payload);\n buffer = type.encode(message).finish();\n }\n\n // 2. 混淆阶段\n if (obfuscator) {\n return await obfuscator.encrypt(buffer);\n }\n return buffer;\n}\n\n/**\n * 解码安全载荷\n *\n * 流程:二进制流 -> 二进制反混淆 -> (自定义解码 / Proto 反序列化) -> 业务数据\n */\nexport async function decodeSecure<T>(\n buffer: Uint8Array | ArrayBuffer,\n options: ProtobufOptions = {},\n): Promise<T> {\n const { obfuscator, protoType, transform, decode: customDecode } = options;\n\n // let uint8 = buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : buffer;\n // let uint8 =\n // buffer instanceof ArrayBuffer\n // ? new Uint8Array(buffer)\n // : new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n\n // 1. 标准化为 Uint8Array 视图 (跨环境最稳写法)\n let uint8 = ArrayBuffer.isView(buffer)\n ? new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength)\n : new Uint8Array(buffer);\n\n if (uint8.length === 0) {\n return null as T; // 或者返回 {},根据业务定\n }\n\n // 1. 混淆阶段\n if (uint8.length > 0 && obfuscator) {\n uint8 = await obfuscator.decrypt(uint8);\n }\n\n // 2. 反序列化阶段\n if (customDecode) {\n return await customDecode<T>(uint8);\n }\n\n const type = protoType || getInternalSecureType();\n const decoded = type.decode(uint8);\n const plainObj = type.toObject(decoded, {\n longs: String,\n enums: String,\n bytes: Uint8Array as any,\n defaults: true,\n });\n\n // 3. 转换阶段\n if (transform?.afterDecode) {\n return transform.afterDecode(plainObj);\n }\n\n // 内置容器模式的额外还原逻辑\n if (!protoType && plainObj.data) {\n const jsonString = decoder.decode(plainObj.data as Uint8Array);\n try {\n return JSON.parse(jsonString) as T;\n } catch {\n return jsonString as unknown as T;\n }\n }\n\n return plainObj as T;\n}\n\n// ============================================================================\n// 4. HTTP/环境适配工具 (HTTP Tools)\n// ============================================================================\n\n/** 创建安全响应 (Worker/Server 端使用) */\nexport async function secureResponse<T>(\n data: T,\n options?: ProtobufOptions & { corsHeaders?: Record<string, string> },\n): Promise<Response> {\n const buffer = await encodeSecure(data, options);\n // const arrayBuffer = buffer.buffer.slice(\n // buffer.byteOffset,\n // buffer.byteOffset + buffer.byteLength,\n // ) as ArrayBuffer;\n const cleanBuffer = buffer.slice();\n\n return new Response(cleanBuffer, {\n headers: {\n ...getProtobufHeaders({ send: true }),\n ...options?.corsHeaders,\n },\n });\n}\n\n/** * 解析安全请求体 (Worker/Server 端使用)\n * @param request 原生 Request 对象\n * @param options 编解码配置(可包含当前接口对应的 protoType 和自定义 obfuscator)\n */\nexport async function parseSecureRequest<T>(\n request: Request,\n options: ProtobufOptions = {}, // 统一使用这个配置对象\n): Promise<T> {\n const buffer = await request.arrayBuffer();\n return decodeSecure<T>(buffer, options);\n}\n\n/** 标准化配置对象 */\n// export function normalizeProtobufConfig(\n// config: boolean | ProtobufConfig | undefined,\n// options?: ProtobufHooksOptions, // 接收全局配置\n// ): ProtobufConfig | null {\n// if (!config) return null;\n// if (config === true) {\n// return {\n// encode: (data) => encodeSecure(data, options),\n// decode: <T>(buffer: Uint8Array) => decodeSecure<T>(buffer, options),\n// options,\n// };\n// }\n// return config;\n// }\n\n// ============================================================================\n// 5. API Client 钩子逻辑 (Integration Hooks)\n// ============================================================================\n\n/** 创建 Protobuf 编解码钩子 (用于与 createApiClient 配合使用) */\nexport function createProtobufHooks(globalOptions: ProtobufOptions = {}) {\n // const encode = (data: any) => encodeSecure(data, globalOptions);\n // const decode = <T>(buffer: Uint8Array) => decodeSecure<T>(buffer, globalOptions);\n\n return {\n async onRequest(context: FetchContext) {\n const { options: reqOptions } = context;\n\n // 1. 动态合并配置:将全局 globalOptions 和单次请求传的 reqOptions 合并\n // 这确保了 encodeSecure 能拿到当前请求特有的 protoType 或 transform\n const mergedOptions: ProtobufOptions = {\n ...globalOptions,\n ...reqOptions,\n };\n\n const headers =\n reqOptions.headers instanceof Headers\n ? reqOptions.headers\n : new Headers(reqOptions.headers as HeadersInit | undefined);\n\n // 自动编码请求体\n if (\n isProtobufContentType(headers.get(\"Content-Type\")) &&\n reqOptions.body &&\n !(reqOptions.body instanceof Uint8Array)\n ) {\n reqOptions.body = await encodeSecure(reqOptions.body, mergedOptions);\n }\n\n // 自动设置期望响应类型\n if (\n isProtobufContentType(headers.get(\"Accept\")) &&\n !reqOptions.responseType\n ) {\n reqOptions.responseType = \"arrayBuffer\";\n }\n\n reqOptions.headers = headers;\n },\n\n async onResponse(context: FetchContext) {\n const { response, options: reqOptions } = context;\n if (!response?._data || response.status === 204) return;\n\n // 同样在响应阶段合并 options,以获取单次请求指定的 protoType 来解码\n const mergedOptions: ProtobufOptions = {\n ...globalOptions,\n ...reqOptions,\n };\n\n if (isProtobufContentType(response.headers.get(\"Content-Type\"))) {\n try {\n // 这里的 _data 可能是 ArrayBuffer (浏览器) 或 Buffer (Node)\n // decodeSecure 内部已处理好兼容性\n response._data = await decodeSecure(response._data, mergedOptions);\n // const buffer = response._data as ArrayBuffer;\n // if (buffer && buffer.byteLength > 0) {\n // response._data = await decode(new Uint8Array(buffer));\n // }\n } catch (e) {\n console.log(\"Error [Protobuf Decode Error]\", e);\n response._data = null;\n }\n } else if (response._data instanceof ArrayBuffer) {\n const text = decoder.decode(response._data);\n try {\n response._data = JSON.parse(text);\n } catch {\n response._data = text;\n }\n }\n },\n };\n}\n","/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/\nimport * as $protobuf from \"protobufjs/minimal\";\n\n// Common aliases\nconst $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;\n\n// Exported root namespace\nconst $root = $protobuf.roots[\"default\"] || ($protobuf.roots[\"default\"] = {});\n\nexport const secure = $root.secure = (() => {\n\n /**\n * Namespace secure.\n * @exports secure\n * @namespace\n */\n const secure = {};\n\n secure.SecurePayload = (function() {\n\n /**\n * Properties of a SecurePayload.\n * @memberof secure\n * @interface ISecurePayload\n * @property {number|Long|null} [ts] SecurePayload ts\n * @property {Uint8Array|null} [data] SecurePayload data\n */\n\n /**\n * Constructs a new SecurePayload.\n * @memberof secure\n * @classdesc Represents a SecurePayload.\n * @implements ISecurePayload\n * @constructor\n * @param {secure.ISecurePayload=} [properties] Properties to set\n */\n function SecurePayload(properties) {\n if (properties)\n for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)\n if (properties[keys[i]] != null)\n this[keys[i]] = properties[keys[i]];\n }\n\n /**\n * SecurePayload ts.\n * @member {number|Long} ts\n * @memberof secure.SecurePayload\n * @instance\n */\n SecurePayload.prototype.ts = $util.Long ? $util.Long.fromBits(0,0,false) : 0;\n\n /**\n * SecurePayload data.\n * @member {Uint8Array} data\n * @memberof secure.SecurePayload\n * @instance\n */\n SecurePayload.prototype.data = $util.newBuffer([]);\n\n /**\n * Creates a new SecurePayload instance using the specified properties.\n * @function create\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload=} [properties] Properties to set\n * @returns {secure.SecurePayload} SecurePayload instance\n */\n SecurePayload.create = function create(properties) {\n return new SecurePayload(properties);\n };\n\n /**\n * Encodes the specified SecurePayload message. Does not implicitly {@link secure.SecurePayload.verify|verify} messages.\n * @function encode\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload} message SecurePayload message or plain object to encode\n * @param {$protobuf.Writer} [writer] Writer to encode to\n * @returns {$protobuf.Writer} Writer\n */\n SecurePayload.encode = function encode(message, writer) {\n if (!writer)\n writer = $Writer.create();\n if (message.ts != null && Object.hasOwnProperty.call(message, \"ts\"))\n writer.uint32(/* id 1, wireType 0 =*/8).int64(message.ts);\n if (message.data != null && Object.hasOwnProperty.call(message, \"data\"))\n writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.data);\n return writer;\n };\n\n /**\n * Encodes the specified SecurePayload message, length delimited. Does not implicitly {@link secure.SecurePayload.verify|verify} messages.\n * @function encodeDelimited\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload} message SecurePayload message or plain object to encode\n * @param {$protobuf.Writer} [writer] Writer to encode to\n * @returns {$protobuf.Writer} Writer\n */\n SecurePayload.encodeDelimited = function encodeDelimited(message, writer) {\n return this.encode(message, writer).ldelim();\n };\n\n /**\n * Decodes a SecurePayload message from the specified reader or buffer.\n * @function decode\n * @memberof secure.SecurePayload\n * @static\n * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from\n * @param {number} [length] Message length if known beforehand\n * @returns {secure.SecurePayload} SecurePayload\n * @throws {Error} If the payload is not a reader or valid buffer\n * @throws {$protobuf.util.ProtocolError} If required fields are missing\n */\n SecurePayload.decode = function decode(reader, length, error) {\n if (!(reader instanceof $Reader))\n reader = $Reader.create(reader);\n let end = length === undefined ? reader.len : reader.pos + length, message = new $root.secure.SecurePayload();\n while (reader.pos < end) {\n let tag = reader.uint32();\n if (tag === error)\n break;\n switch (tag >>> 3) {\n case 1: {\n message.ts = reader.int64();\n break;\n }\n case 2: {\n message.data = reader.bytes();\n break;\n }\n default:\n reader.skipType(tag & 7);\n break;\n }\n }\n return message;\n };\n\n /**\n * Decodes a SecurePayload message from the specified reader or buffer, length delimited.\n * @function decodeDelimited\n * @memberof secure.SecurePayload\n * @static\n * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from\n * @returns {secure.SecurePayload} SecurePayload\n * @throws {Error} If the payload is not a reader or valid buffer\n * @throws {$protobuf.util.ProtocolError} If required fields are missing\n */\n SecurePayload.decodeDelimited = function decodeDelimited(reader) {\n if (!(reader instanceof $Reader))\n reader = new $Reader(reader);\n return this.decode(reader, reader.uint32());\n };\n\n /**\n * Verifies a SecurePayload message.\n * @function verify\n * @memberof secure.SecurePayload\n * @static\n * @param {Object.<string,*>} message Plain object to verify\n * @returns {string|null} `null` if valid, otherwise the reason why it is not\n */\n SecurePayload.verify = function verify(message) {\n if (typeof message !== \"object\" || message === null)\n return \"object expected\";\n if (message.ts != null && message.hasOwnProperty(\"ts\"))\n if (!$util.isInteger(message.ts) && !(message.ts && $util.isInteger(message.ts.low) && $util.isInteger(message.ts.high)))\n return \"ts: integer|Long expected\";\n if (message.data != null && message.hasOwnProperty(\"data\"))\n if (!(message.data && typeof message.data.length === \"number\" || $util.isString(message.data)))\n return \"data: buffer expected\";\n return null;\n };\n\n /**\n * Creates a SecurePayload message from a plain object. Also converts values to their respective internal types.\n * @function fromObject\n * @memberof secure.SecurePayload\n * @static\n * @param {Object.<string,*>} object Plain object\n * @returns {secure.SecurePayload} SecurePayload\n */\n SecurePayload.fromObject = function fromObject(object) {\n if (object instanceof $root.secure.SecurePayload)\n return object;\n let message = new $root.secure.SecurePayload();\n if (object.ts != null)\n if ($util.Long)\n (message.ts = $util.Long.fromValue(object.ts)).unsigned = false;\n else if (typeof object.ts === \"string\")\n message.ts = parseInt(object.ts, 10);\n else if (typeof object.ts === \"number\")\n message.ts = object.ts;\n else if (typeof object.ts === \"object\")\n message.ts = new $util.LongBits(object.ts.low >>> 0, object.ts.high >>> 0).toNumber();\n if (object.data != null)\n if (typeof object.data === \"string\")\n $util.base64.decode(object.data, message.data = $util.newBuffer($util.base64.length(object.data)), 0);\n else if (object.data.length >= 0)\n message.data = object.data;\n return message;\n };\n\n /**\n * Creates a plain object from a SecurePayload message. Also converts values to other types if specified.\n * @function toObject\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.SecurePayload} message SecurePayload\n * @param {$protobuf.IConversionOptions} [options] Conversion options\n * @returns {Object.<string,*>} Plain object\n */\n SecurePayload.toObject = function toObject(message, options) {\n if (!options)\n options = {};\n let object = {};\n if (options.defaults) {\n if ($util.Long) {\n let long = new $util.Long(0, 0, false);\n object.ts = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;\n } else\n object.ts = options.longs === String ? \"0\" : 0;\n if (options.bytes === String)\n object.data = \"\";\n else {\n object.data = [];\n if (options.bytes !== Array)\n object.data = $util.newBuffer(object.data);\n }\n }\n if (message.ts != null && message.hasOwnProperty(\"ts\"))\n if (typeof message.ts === \"number\")\n object.ts = options.longs === String ? String(message.ts) : message.ts;\n else\n object.ts = options.longs === String ? $util.Long.prototype.toString.call(message.ts) : options.longs === Number ? new $util.LongBits(message.ts.low >>> 0, message.ts.high >>> 0).toNumber() : message.ts;\n if (message.data != null && message.hasOwnProperty(\"data\"))\n object.data = options.bytes === String ? $util.base64.encode(message.data, 0, message.data.length) : options.bytes === Array ? Array.prototype.slice.call(message.data) : message.data;\n return object;\n };\n\n /**\n * Converts this SecurePayload to JSON.\n * @function toJSON\n * @memberof secure.SecurePayload\n * @instance\n * @returns {Object.<string,*>} JSON object\n */\n SecurePayload.prototype.toJSON = function toJSON() {\n return this.constructor.toObject(this, $protobuf.util.toJSONOptions);\n };\n\n /**\n * Gets the default type url for SecurePayload\n * @function getTypeUrl\n * @memberof secure.SecurePayload\n * @static\n * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default \"type.googleapis.com\")\n * @returns {string} The default type url\n */\n SecurePayload.getTypeUrl = function getTypeUrl(typeUrlPrefix) {\n if (typeUrlPrefix === undefined) {\n typeUrlPrefix = \"type.googleapis.com\";\n }\n return typeUrlPrefix + \"/secure.SecurePayload\";\n };\n\n return SecurePayload;\n })();\n\n return secure;\n})();\n\nexport { $root as default };\n"],"mappings":"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","names":["secure"]}
|
package/dist/protobuf.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/chain.ts"],"sourcesContent":["/**\n * Request Chain Runner\n * 负责解析和执行通用的 HTTP 请求链 (Chain Execution)\n * 适用于任何需要链式 HTTP 请求编排的场景\n */\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\n/** Supported HTTP Methods */\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/** HTTP 请求参数 */\nexport interface HttpRequestSpec {\n method: HttpMethod;\n url: string;\n headers?: Record<string, string>;\n body?: any;\n}\n\n/**\n * 网络适配器接口\n * 定义实际发送请求的能力\n */\n/**\n * 网络适配器接口\n * 定义实际发送请求的能力\n */\nexport interface NetworkAdapter {\n get<T>(\n url: string,\n params?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n post<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n put?<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n delete?<T>(\n url: string,\n params?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n patch?<T>(\n url: string,\n body?: any,\n headers?: Record<string, string>,\n ): Promise<T>;\n}\n\n/**\n * 网络处理器接口 (Strategy Pattern)\n * 组合了\"匹配规则\"和\"执行能力\"\n */\nexport interface NetworkHandler {\n /** 处理器名称 (用于调试) */\n name?: string;\n\n /** 判断该 URL 是否由此适配器处理 */\n shouldHandle(url: string, method: HttpMethod): boolean;\n\n /** 具体的网络适配器 */\n adapter: NetworkAdapter;\n}\n\n/**\n * 请求链规则 (Chain Step)\n */\nexport interface ChainRequestRule {\n /**\n * 结果存储的键名 (Context Key)\n * Fetch 结果存储: context[key] = response\n */\n key?: string;\n\n /**\n * HTTP 请求详情\n */\n request: HttpRequestSpec;\n\n /**\n * 数据提取选择器\n * 用于从响应中提取特定数据, e.g., \"elements.0\"\n */\n selector?: string;\n\n /** 是否允许请求失败 (默认 false) */\n optional?: boolean;\n\n /**\n * 是否包含上下文\n * 如果为 true,请求 Body 将自动合并当前 Context 和 Payload\n */\n includeContext?: boolean;\n\n /**\n * 上下文筛选列表 (优先级高于 includeContext)\n * 指定需要合并到 Body 中的 Context Key 列表\n * e.g., [\"rawProfile\", \"rawCompany\"]\n */\n pickContext?: string[];\n}\n\n// ============================================================================\n// Internal Utilities\n// ============================================================================\n\n/**\n * 执行 HTTP 请求\n * 遍历 handlers 数组,找到第一个能处理该 URL 的适配器执行\n *\n * @param spec 请求详情\n * @param handlers 网络处理器链\n */\nasync function executeChainRequest<T>(\n spec: HttpRequestSpec,\n handlers: NetworkHandler[] = [],\n): Promise<T | null> {\n // Normalize method to upper case for robustness\n const method = spec.method.toUpperCase() as HttpMethod;\n\n // 1. 遍历处理器数组 (责任链)\n for (const handler of handlers) {\n if (handler.shouldHandle(spec.url, method)) {\n try {\n const { adapter } = handler;\n const headers = spec.headers;\n\n switch (method) {\n case \"GET\":\n return await adapter.get<T>(spec.url, spec.body, headers);\n case \"POST\":\n return await adapter.post<T>(spec.url, spec.body, headers);\n case \"PUT\":\n if (!adapter.put)\n throw new Error(`Adapter ${handler.name} missing PUT method`);\n return await adapter.put<T>(spec.url, spec.body, headers);\n case \"DELETE\":\n if (!adapter.delete)\n throw new Error(`Adapter ${handler.name} missing DELETE method`);\n return await adapter.delete<T>(spec.url, spec.body, headers);\n case \"PATCH\":\n if (!adapter.patch)\n throw new Error(`Adapter ${handler.name} missing PATCH method`);\n return await adapter.patch<T>(spec.url, spec.body, headers);\n default:\n throw new Error(`Unsupported method: ${method}`);\n }\n } catch (err) {\n console.warn(\n `Handler [${handler.name || \"Anonymous\"}] failed for ${spec.url}`,\n err,\n );\n // 如果需要继续尝试下一个 handler,可以在这里 continue,但通常由第一个匹配者全权负责\n return null;\n }\n }\n }\n\n // 2. 默认行为 (Fallback): 绝对路径自动走标准 fetch\n if (spec.url.startsWith(\"http://\") || spec.url.startsWith(\"https://\")) {\n return await executeFallbackFetch<T>(spec);\n }\n\n console.warn(`No handler found for url: ${spec.url}`);\n return null;\n}\n\n/**\n * 标准 Fetch 回退实现\n */\nasync function executeFallbackFetch<T>(\n spec: HttpRequestSpec,\n): Promise<T | null> {\n try {\n const response = await fetch(spec.url, {\n method: spec.method,\n headers: spec.headers,\n body: spec.body ? JSON.stringify(spec.body) : undefined,\n credentials: \"include\",\n });\n\n if (!response.ok) {\n console.log(`External Request failed: ${response.status} ${spec.url}`);\n return null;\n }\n\n return await response.json();\n } catch (err) {\n console.log(\"External Request error:\", err);\n return null;\n }\n}\n\n/**\n * 根据路径获取对象值\n */\nfunction getByPath(obj: any, path: string): any {\n if (!path) return obj;\n return path.split(\".\").reduce((acc, part) => acc && acc[part], obj);\n}\n\n/**\n * 变量替换 (Internal)\n * 支持字符串 {{key}} 和 {{key.prop}}\n */\nfunction substituteVariables(target: any, context: any): any {\n if (typeof target === \"string\") {\n return target.replace(/\\{\\{([\\w\\.]+)\\}\\}/g, (_, path) => {\n const val = getByPath(context, path);\n return val !== undefined ? String(val) : \"\";\n });\n }\n\n if (Array.isArray(target)) {\n return target.map((item) => substituteVariables(item, context));\n }\n\n if (target && typeof target === \"object\") {\n const result: any = {};\n for (const key in target) {\n result[key] = substituteVariables(target[key], context);\n }\n return result;\n }\n\n return target;\n}\n\n// ============================================================================\n// Main Runner\n// ============================================================================\n\n/**\n * 请求链执行器 (Request Chain Engine)\n * 支持链式请求、上下文累积、智能路由、变量替换\n *\n * @param requests 链式执行规则列表\n * @param handlers 网络适配器处理器列表 (按顺序匹配)\n */\nexport async function executeRequestChain<T>(\n requests: ChainRequestRule[],\n handlers: NetworkHandler[] = [],\n getChainRequests?: (\n context: Record<string, any>,\n ) => ChainRequestRule[] | null | undefined,\n initContext?: Record<string, any>,\n): Promise<T> {\n const context: Record<string, any> = initContext || {};\n let lastResult: any = null;\n\n for (const rule of requests) {\n try {\n // 1. 准备 Context Data (用于 Submit)\n let contextData: Record<string, any> = {};\n if (rule.pickContext) {\n rule.pickContext.forEach((key) => {\n if (key in context) contextData[key] = context[key];\n });\n } else if (rule.includeContext) {\n contextData = context;\n }\n const hasContextData = Object.keys(contextData).length > 0;\n\n // 2. 准备 Request Spec (合并 Context 到 Body)\n let requestSpec = { ...rule.request };\n if (hasContextData) {\n requestSpec.body = {\n ...contextData,\n ...(requestSpec.body || {}),\n };\n }\n\n // 3. 变量替换\n requestSpec = substituteVariables(requestSpec, context);\n\n // 4. 执行请求 (传入 handlers)\n let rawData = await executeChainRequest<any>(requestSpec, handlers);\n\n if (getChainRequests) {\n const chainRequests = getChainRequests(rawData);\n if (chainRequests && chainRequests.length > 0) {\n rawData = await executeRequestChain(\n chainRequests,\n handlers,\n getChainRequests,\n JSON.parse(JSON.stringify(context)),\n );\n }\n }\n\n lastResult = rawData;\n\n if (rawData) {\n // 5. 存储结果\n if (rule.key) {\n const data = rule.selector\n ? getByPath(rawData, rule.selector)\n : rawData;\n context[rule.key] = data;\n }\n } else if (!rule.optional) {\n throw new Error(\n `Failed to fetch required data for key: ${rule.key || \"unknown\"}`,\n );\n }\n } catch (err) {\n if (!rule.optional) {\n throw err;\n }\n console.warn(`Optional request failed for rule:`, rule, err);\n }\n }\n\n return lastResult as T;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/secure.js","../src/protobuf.ts"],"sourcesContent":["/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/\nimport * as $protobuf from \"protobufjs/minimal\";\n\n// Common aliases\nconst $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;\n\n// Exported root namespace\nconst $root = $protobuf.roots[\"default\"] || ($protobuf.roots[\"default\"] = {});\n\nexport const secure = $root.secure = (() => {\n\n /**\n * Namespace secure.\n * @exports secure\n * @namespace\n */\n const secure = {};\n\n secure.SecurePayload = (function() {\n\n /**\n * Properties of a SecurePayload.\n * @memberof secure\n * @interface ISecurePayload\n * @property {number|Long|null} [ts] SecurePayload ts\n * @property {Uint8Array|null} [data] SecurePayload data\n */\n\n /**\n * Constructs a new SecurePayload.\n * @memberof secure\n * @classdesc Represents a SecurePayload.\n * @implements ISecurePayload\n * @constructor\n * @param {secure.ISecurePayload=} [properties] Properties to set\n */\n function SecurePayload(properties) {\n if (properties)\n for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)\n if (properties[keys[i]] != null)\n this[keys[i]] = properties[keys[i]];\n }\n\n /**\n * SecurePayload ts.\n * @member {number|Long} ts\n * @memberof secure.SecurePayload\n * @instance\n */\n SecurePayload.prototype.ts = $util.Long ? $util.Long.fromBits(0,0,false) : 0;\n\n /**\n * SecurePayload data.\n * @member {Uint8Array} data\n * @memberof secure.SecurePayload\n * @instance\n */\n SecurePayload.prototype.data = $util.newBuffer([]);\n\n /**\n * Creates a new SecurePayload instance using the specified properties.\n * @function create\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload=} [properties] Properties to set\n * @returns {secure.SecurePayload} SecurePayload instance\n */\n SecurePayload.create = function create(properties) {\n return new SecurePayload(properties);\n };\n\n /**\n * Encodes the specified SecurePayload message. Does not implicitly {@link secure.SecurePayload.verify|verify} messages.\n * @function encode\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload} message SecurePayload message or plain object to encode\n * @param {$protobuf.Writer} [writer] Writer to encode to\n * @returns {$protobuf.Writer} Writer\n */\n SecurePayload.encode = function encode(message, writer) {\n if (!writer)\n writer = $Writer.create();\n if (message.ts != null && Object.hasOwnProperty.call(message, \"ts\"))\n writer.uint32(/* id 1, wireType 0 =*/8).int64(message.ts);\n if (message.data != null && Object.hasOwnProperty.call(message, \"data\"))\n writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.data);\n return writer;\n };\n\n /**\n * Encodes the specified SecurePayload message, length delimited. Does not implicitly {@link secure.SecurePayload.verify|verify} messages.\n * @function encodeDelimited\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.ISecurePayload} message SecurePayload message or plain object to encode\n * @param {$protobuf.Writer} [writer] Writer to encode to\n * @returns {$protobuf.Writer} Writer\n */\n SecurePayload.encodeDelimited = function encodeDelimited(message, writer) {\n return this.encode(message, writer).ldelim();\n };\n\n /**\n * Decodes a SecurePayload message from the specified reader or buffer.\n * @function decode\n * @memberof secure.SecurePayload\n * @static\n * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from\n * @param {number} [length] Message length if known beforehand\n * @returns {secure.SecurePayload} SecurePayload\n * @throws {Error} If the payload is not a reader or valid buffer\n * @throws {$protobuf.util.ProtocolError} If required fields are missing\n */\n SecurePayload.decode = function decode(reader, length, error) {\n if (!(reader instanceof $Reader))\n reader = $Reader.create(reader);\n let end = length === undefined ? reader.len : reader.pos + length, message = new $root.secure.SecurePayload();\n while (reader.pos < end) {\n let tag = reader.uint32();\n if (tag === error)\n break;\n switch (tag >>> 3) {\n case 1: {\n message.ts = reader.int64();\n break;\n }\n case 2: {\n message.data = reader.bytes();\n break;\n }\n default:\n reader.skipType(tag & 7);\n break;\n }\n }\n return message;\n };\n\n /**\n * Decodes a SecurePayload message from the specified reader or buffer, length delimited.\n * @function decodeDelimited\n * @memberof secure.SecurePayload\n * @static\n * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from\n * @returns {secure.SecurePayload} SecurePayload\n * @throws {Error} If the payload is not a reader or valid buffer\n * @throws {$protobuf.util.ProtocolError} If required fields are missing\n */\n SecurePayload.decodeDelimited = function decodeDelimited(reader) {\n if (!(reader instanceof $Reader))\n reader = new $Reader(reader);\n return this.decode(reader, reader.uint32());\n };\n\n /**\n * Verifies a SecurePayload message.\n * @function verify\n * @memberof secure.SecurePayload\n * @static\n * @param {Object.<string,*>} message Plain object to verify\n * @returns {string|null} `null` if valid, otherwise the reason why it is not\n */\n SecurePayload.verify = function verify(message) {\n if (typeof message !== \"object\" || message === null)\n return \"object expected\";\n if (message.ts != null && message.hasOwnProperty(\"ts\"))\n if (!$util.isInteger(message.ts) && !(message.ts && $util.isInteger(message.ts.low) && $util.isInteger(message.ts.high)))\n return \"ts: integer|Long expected\";\n if (message.data != null && message.hasOwnProperty(\"data\"))\n if (!(message.data && typeof message.data.length === \"number\" || $util.isString(message.data)))\n return \"data: buffer expected\";\n return null;\n };\n\n /**\n * Creates a SecurePayload message from a plain object. Also converts values to their respective internal types.\n * @function fromObject\n * @memberof secure.SecurePayload\n * @static\n * @param {Object.<string,*>} object Plain object\n * @returns {secure.SecurePayload} SecurePayload\n */\n SecurePayload.fromObject = function fromObject(object) {\n if (object instanceof $root.secure.SecurePayload)\n return object;\n let message = new $root.secure.SecurePayload();\n if (object.ts != null)\n if ($util.Long)\n (message.ts = $util.Long.fromValue(object.ts)).unsigned = false;\n else if (typeof object.ts === \"string\")\n message.ts = parseInt(object.ts, 10);\n else if (typeof object.ts === \"number\")\n message.ts = object.ts;\n else if (typeof object.ts === \"object\")\n message.ts = new $util.LongBits(object.ts.low >>> 0, object.ts.high >>> 0).toNumber();\n if (object.data != null)\n if (typeof object.data === \"string\")\n $util.base64.decode(object.data, message.data = $util.newBuffer($util.base64.length(object.data)), 0);\n else if (object.data.length >= 0)\n message.data = object.data;\n return message;\n };\n\n /**\n * Creates a plain object from a SecurePayload message. Also converts values to other types if specified.\n * @function toObject\n * @memberof secure.SecurePayload\n * @static\n * @param {secure.SecurePayload} message SecurePayload\n * @param {$protobuf.IConversionOptions} [options] Conversion options\n * @returns {Object.<string,*>} Plain object\n */\n SecurePayload.toObject = function toObject(message, options) {\n if (!options)\n options = {};\n let object = {};\n if (options.defaults) {\n if ($util.Long) {\n let long = new $util.Long(0, 0, false);\n object.ts = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;\n } else\n object.ts = options.longs === String ? \"0\" : 0;\n if (options.bytes === String)\n object.data = \"\";\n else {\n object.data = [];\n if (options.bytes !== Array)\n object.data = $util.newBuffer(object.data);\n }\n }\n if (message.ts != null && message.hasOwnProperty(\"ts\"))\n if (typeof message.ts === \"number\")\n object.ts = options.longs === String ? String(message.ts) : message.ts;\n else\n object.ts = options.longs === String ? $util.Long.prototype.toString.call(message.ts) : options.longs === Number ? new $util.LongBits(message.ts.low >>> 0, message.ts.high >>> 0).toNumber() : message.ts;\n if (message.data != null && message.hasOwnProperty(\"data\"))\n object.data = options.bytes === String ? $util.base64.encode(message.data, 0, message.data.length) : options.bytes === Array ? Array.prototype.slice.call(message.data) : message.data;\n return object;\n };\n\n /**\n * Converts this SecurePayload to JSON.\n * @function toJSON\n * @memberof secure.SecurePayload\n * @instance\n * @returns {Object.<string,*>} JSON object\n */\n SecurePayload.prototype.toJSON = function toJSON() {\n return this.constructor.toObject(this, $protobuf.util.toJSONOptions);\n };\n\n /**\n * Gets the default type url for SecurePayload\n * @function getTypeUrl\n * @memberof secure.SecurePayload\n * @static\n * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default \"type.googleapis.com\")\n * @returns {string} The default type url\n */\n SecurePayload.getTypeUrl = function getTypeUrl(typeUrlPrefix) {\n if (typeUrlPrefix === undefined) {\n typeUrlPrefix = \"type.googleapis.com\";\n }\n return typeUrlPrefix + \"/secure.SecurePayload\";\n };\n\n return SecurePayload;\n })();\n\n return secure;\n})();\n\nexport { $root as default };\n","/**\n * Protobuf 安全通信模块\n *\n * 提供基于 Protobuf 的二进制序列化、XOR 混淆加密以及与 API Client 的无缝集成。\n */\n\nimport protobuf from \"protobufjs/light\";\nimport { secure } from \"./secure.js\";\nimport type { FetchContext } from \"ofetch\";\n\n// ============================================================================\n// 1. 类型定义 (Types)\n// ============================================================================\n// export type ProtobufTypeLike = Pick<protobuf.Type, \"create\" | \"encode\" | \"decode\" | \"toObject\">;\nexport interface ProtobufTypeLike {\n // 1. 允许 properties 为任何对象,返回结果不再强制要求 $type\n create(properties?: Record<string, any>): any;\n // 2. 借用原生的参数类型约束,但手动简化返回类型\n encode(message: any): { finish(): Uint8Array };\n // 3. 借用原生的 decode 签名(支持 Uint8Array 和 Reader)\n decode(reader: Uint8Array | protobuf.Reader): any;\n // 4. 借用原生的 toObject 签名,保留 IConversionOptions 的类型检查\n toObject(message: any, options?: protobuf.IConversionOptions): any;\n}\n/**\n * 二进制混淆接口\n * 允许外部定义混淆逻辑,以便与不同语言实现的后端兼容\n */\nexport interface ProtobufObfuscator {\n encrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;\n decrypt(data: Uint8Array): Uint8Array | Promise<Uint8Array>;\n}\n\n/**\n * 基础编解码配置\n * 控制如何将数据转换为二进制,以及是否混淆\n */\nexport interface ProtobufCodecOptions {\n /**\n * 混淆器实现\n * 提供该选项时才会启用混淆\n */\n obfuscator?: ProtobufObfuscator;\n /** 预编译的 Protobuf 类型对象 (推荐,性能最高) */\n protoType?: ProtobufTypeLike;\n /** 数据转换钩子:处理业务模型与 Proto 结构不一致的情况 */\n transform?: {\n beforeEncode?: (data: any) => any;\n afterDecode?: (payload: any) => any;\n };\n}\n\n/**\n * 完全自定义编解码接口\n * 用于外部项目完全接管序列化过程,同时复用基础库的混淆外壳\n */\nexport interface ProtobufCustomCodec {\n /** 外部定义的编码逻辑 (返回原始二进制) */\n encode?: (data: any) => Uint8Array | Promise<Uint8Array>;\n /** 外部定义的解码逻辑 (返回原始对象) */\n decode?: <T>(buffer: Uint8Array) => T | Promise<T>;\n}\n\n/**\n * 集成配置项\n * 用于 createProtobufHooks 或 API Client 全局配置\n */\nexport interface ProtobufHooksOptions\n extends ProtobufCodecOptions, ProtobufCustomCodec {}\n\nexport const PROTOBUF_CONTENT_TYPE = \"application/x-protobuf\";\n\n/** 检查是否为 Protobuf 响应头 */\nexport function isProtobufContentType(contentType: string | null): boolean {\n return !!contentType?.toLowerCase().includes(PROTOBUF_CONTENT_TYPE);\n}\n\n/**\n * 获取 Protobuf 相关的 Header 配置对象\n */\nexport function getProtobufHeaders({\n send = true,\n receive = true,\n}: {\n send?: boolean;\n receive?: boolean;\n} = {}): Record<string, string> {\n const headers: Record<string, string> = {};\n\n if (send) {\n headers[\"Content-Type\"] = PROTOBUF_CONTENT_TYPE;\n }\n\n if (receive) {\n headers[\"Accept\"] = PROTOBUF_CONTENT_TYPE;\n }\n\n return headers;\n}\n\n/**\n * API Client 内部使用的标准化配置\n */\n// export interface ProtobufConfig {\n// encode: (data: any) => Uint8Array | Promise<Uint8Array>;\n// decode: <T>(buffer: Uint8Array) => T | Promise<T>;\n// options?: ProtobufCodecOptions;\n// }\n\n// ============================================================================\n// 2. 内部工具函数 (Internal Utilities)\n// ============================================================================\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/** 简单的二进制异或混淆转换 */\nexport function xorTransform(\n data: Uint8Array,\n key: string | Uint8Array,\n): Uint8Array {\n const keyBytes = typeof key === \"string\" ? encoder.encode(key) : key;\n if (keyBytes.length === 0) return data;\n\n for (let i = 0; i < data.length; i++) {\n data[i] ^= keyBytes[i % keyBytes.length];\n }\n return data;\n}\n\n/** 创建一个简单的 XOR 混淆器 */\nexport function createXorObfuscator(\n key: string | Uint8Array,\n): ProtobufObfuscator {\n return {\n encrypt: (data) => xorTransform(data, key),\n decrypt: (data) => xorTransform(data, key),\n };\n}\n\n/** 获取内置的 SecurePayload 类型(使用预编译代码) */\nfunction getInternalSecureType(): protobuf.Type {\n return secure.SecurePayload as unknown as protobuf.Type;\n}\n\n// ============================================================================\n// 3. 核心编解码逻辑 (Core Codecs)\n// ============================================================================\n\n/**\n * 编码安全载荷\n *\n * 流程:业务数据 -> (自定义编码 / Proto 序列化) -> 二进制混淆\n */\nexport async function encodeSecure<T>(\n data: T,\n options: ProtobufHooksOptions = {},\n): Promise<Uint8Array> {\n const { obfuscator, protoType, transform, encode: customEncode } = options;\n\n let buffer: Uint8Array;\n\n // 1. 预处理阶段:无论后续走哪条路径,只要定义了 beforeEncode 就先执行\n const processedData = transform?.beforeEncode\n ? transform.beforeEncode(data)\n : data;\n\n // 1. 序列化阶段\n if (customEncode) {\n buffer = await customEncode(processedData);\n } else {\n const type = protoType || getInternalSecureType();\n\n // 构造最终要交给 Protobuf 序列化的对象\n const payload = protoType\n ? processedData // 自定义模式:直接使用预处理后的数据\n : {\n // 默认容器模式:将预处理后的数据封装进信封\n ts: Date.now(),\n data:\n processedData instanceof Uint8Array\n ? processedData\n : encoder.encode(JSON.stringify(processedData)),\n };\n\n const message = type.create(payload);\n buffer = type.encode(message).finish();\n }\n\n // 2. 混淆阶段\n if (obfuscator) {\n return await obfuscator.encrypt(buffer);\n }\n return buffer;\n}\n\n/**\n * 解码安全载荷\n *\n * 流程:二进制流 -> 二进制反混淆 -> (自定义解码 / Proto 反序列化) -> 业务数据\n */\nexport async function decodeSecure<T>(\n buffer: Uint8Array | ArrayBuffer,\n options: ProtobufHooksOptions = {},\n): Promise<T> {\n const { obfuscator, protoType, transform, decode: customDecode } = options;\n\n // let uint8 = buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : buffer;\n // let uint8 =\n // buffer instanceof ArrayBuffer\n // ? new Uint8Array(buffer)\n // : new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n\n // 1. 标准化为 Uint8Array 视图 (跨环境最稳写法)\n let uint8 = ArrayBuffer.isView(buffer)\n ? new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength)\n : new Uint8Array(buffer);\n\n if (uint8.length === 0) {\n return null as T; // 或者返回 {},根据业务定\n }\n\n // 1. 混淆阶段\n if (uint8.length > 0 && obfuscator) {\n uint8 = await obfuscator.decrypt(uint8);\n }\n\n // 2. 反序列化阶段\n if (customDecode) {\n return await customDecode<T>(uint8);\n }\n\n const type = protoType || getInternalSecureType();\n const decoded = type.decode(uint8);\n const plainObj = type.toObject(decoded, {\n longs: String,\n enums: String,\n bytes: Uint8Array as any,\n defaults: true,\n });\n\n // 3. 转换阶段\n if (transform?.afterDecode) {\n return transform.afterDecode(plainObj);\n }\n\n // 内置容器模式的额外还原逻辑\n if (!protoType && plainObj.data) {\n const jsonString = decoder.decode(plainObj.data as Uint8Array);\n try {\n return JSON.parse(jsonString) as T;\n } catch {\n return jsonString as unknown as T;\n }\n }\n\n return plainObj as T;\n}\n\n// ============================================================================\n// 4. HTTP/环境适配工具 (HTTP Tools)\n// ============================================================================\n\n/** 创建安全响应 (Worker/Server 端使用) */\nexport async function secureResponse<T>(\n data: T,\n options?: ProtobufCodecOptions & { corsHeaders?: Record<string, string> },\n): Promise<Response> {\n const buffer = await encodeSecure(data, options);\n // const arrayBuffer = buffer.buffer.slice(\n // buffer.byteOffset,\n // buffer.byteOffset + buffer.byteLength,\n // ) as ArrayBuffer;\n const cleanBuffer = buffer.slice();\n\n return new Response(cleanBuffer, {\n headers: {\n ...getProtobufHeaders({ send: true }),\n ...options?.corsHeaders,\n },\n });\n}\n\n/** * 解析安全请求体 (Worker/Server 端使用)\n * @param request 原生 Request 对象\n * @param options 编解码配置(可包含当前接口对应的 protoType 和自定义 obfuscator)\n */\nexport async function parseSecureRequest<T>(\n request: Request,\n options: ProtobufHooksOptions = {}, // 统一使用这个配置对象\n): Promise<T> {\n const buffer = await request.arrayBuffer();\n return decodeSecure<T>(buffer, options);\n}\n\n/** 标准化配置对象 */\n// export function normalizeProtobufConfig(\n// config: boolean | ProtobufConfig | undefined,\n// options?: ProtobufHooksOptions, // 接收全局配置\n// ): ProtobufConfig | null {\n// if (!config) return null;\n// if (config === true) {\n// return {\n// encode: (data) => encodeSecure(data, options),\n// decode: <T>(buffer: Uint8Array) => decodeSecure<T>(buffer, options),\n// options,\n// };\n// }\n// return config;\n// }\n\n// ============================================================================\n// 5. API Client 钩子逻辑 (Integration Hooks)\n// ============================================================================\n\n/** 创建 Protobuf 编解码钩子 (用于与 createApiClient 配合使用) */\nexport function createProtobufHooks(globalOptions: ProtobufHooksOptions = {}) {\n // const encode = (data: any) => encodeSecure(data, globalOptions);\n // const decode = <T>(buffer: Uint8Array) => decodeSecure<T>(buffer, globalOptions);\n\n return {\n async onRequest(context: FetchContext) {\n const { options: reqOptions } = context;\n\n // 1. 动态合并配置:将全局 globalOptions 和单次请求传的 reqOptions 合并\n // 这确保了 encodeSecure 能拿到当前请求特有的 protoType 或 transform\n const mergedOptions: ProtobufHooksOptions = {\n ...globalOptions,\n ...reqOptions,\n };\n\n const headers =\n reqOptions.headers instanceof Headers\n ? reqOptions.headers\n : new Headers(reqOptions.headers as HeadersInit | undefined);\n\n // 自动编码请求体\n if (\n isProtobufContentType(headers.get(\"Content-Type\")) &&\n reqOptions.body &&\n !(reqOptions.body instanceof Uint8Array)\n ) {\n reqOptions.body = await encodeSecure(reqOptions.body, mergedOptions);\n }\n\n // 自动设置期望响应类型\n if (\n isProtobufContentType(headers.get(\"Accept\")) &&\n !reqOptions.responseType\n ) {\n reqOptions.responseType = \"arrayBuffer\";\n }\n\n reqOptions.headers = headers;\n },\n\n async onResponse(context: FetchContext) {\n const { response, options: reqOptions } = context;\n if (!response?._data || response.status === 204) return;\n\n // 同样在响应阶段合并 options,以获取单次请求指定的 protoType 来解码\n const mergedOptions: ProtobufHooksOptions = {\n ...globalOptions,\n ...reqOptions,\n };\n\n if (isProtobufContentType(response.headers.get(\"Content-Type\"))) {\n try {\n // 这里的 _data 可能是 ArrayBuffer (浏览器) 或 Buffer (Node)\n // decodeSecure 内部已处理好兼容性\n response._data = await decodeSecure(response._data, mergedOptions);\n // const buffer = response._data as ArrayBuffer;\n // if (buffer && buffer.byteLength > 0) {\n // response._data = await decode(new Uint8Array(buffer));\n // }\n } catch (e) {\n console.log(\"Error [Protobuf Decode Error]\", e);\n response._data = null;\n }\n } else if (response._data instanceof ArrayBuffer) {\n const text = decoder.decode(response._data);\n try {\n response._data = JSON.parse(text);\n } catch {\n response._data = text;\n }\n }\n },\n };\n}\n"],"mappings":"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","names":["secure"]}
|