@snack-kit/lib 0.1.0
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 +36 -0
- package/dist/cjs/chunk-JBJEXFQC.cjs +363 -0
- package/dist/cjs/chunk-JBJEXFQC.cjs.map +1 -0
- package/dist/cjs/chunk-N7BJS6LI.cjs +214 -0
- package/dist/cjs/chunk-N7BJS6LI.cjs.map +1 -0
- package/dist/cjs/chunk-YY5WQN7B.cjs +4 -0
- package/dist/cjs/chunk-YY5WQN7B.cjs.map +1 -0
- package/dist/cjs/debugger.cjs +13 -0
- package/dist/cjs/debugger.cjs.map +1 -0
- package/dist/cjs/http.cjs +57 -0
- package/dist/cjs/http.cjs.map +1 -0
- package/dist/cjs/index.cjs +64 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/es/chunk-BEL6AFK4.js +3 -0
- package/dist/es/chunk-BEL6AFK4.js.map +1 -0
- package/dist/es/chunk-JQYH5FWE.js +197 -0
- package/dist/es/chunk-JQYH5FWE.js.map +1 -0
- package/dist/es/chunk-QBBEQHXG.js +361 -0
- package/dist/es/chunk-QBBEQHXG.js.map +1 -0
- package/dist/es/debugger.js +4 -0
- package/dist/es/debugger.js.map +1 -0
- package/dist/es/http.js +4 -0
- package/dist/es/http.js.map +1 -0
- package/dist/es/index.js +10 -0
- package/dist/es/index.js.map +1 -0
- package/dist/types/debugger.d.ts +113 -0
- package/dist/types/http.d.ts +355 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/umd/debugger.global.js +15924 -0
- package/dist/umd/debugger.global.js.map +1 -0
- package/dist/umd/http.global.js +15604 -0
- package/dist/umd/http.global.js.map +1 -0
- package/dist/umd/index.global.js +15965 -0
- package/dist/umd/index.global.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/http/context.ts","../../src/http/cancel.ts","../../src/http/client.ts"],"names":["axios","isAxiosError"],"mappings":"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","file":"chunk-N7BJS6LI.cjs","sourcesContent":["import axios from 'axios'\nimport type { ContextInfo } from './types'\n\n/** 网关 `/ngw/context` 原始响应格式(包含路由映射和 `$info` 元数据) */\ninterface ContextResponse {\n $info?: ContextInfo\n [key: string]: string | ContextInfo | undefined\n}\n\n/**\n * 管理服务地址映射的上下文单例\n *\n * 支持两种加载方式:\n * - **远程加载**:传入网关 URL,自动请求 `GET /ngw/context` 获取映射表\n * - **本地注入**:直接传入键值对象\n *\n * @example 远程加载\n * ```ts\n * import { Context } from '@snack-kit/lib/http'\n *\n * await Context.load('http://172.16.32.155:20000')\n * Context.get('ngw') // 'http://172.16.32.155:20000/ngw'\n * Context.info // { version: '4.6.2-r10', domain: '...', ... }\n * ```\n *\n * @example 本地注入\n * ```ts\n * await Context.load({\n * 'user-svc': 'http://user.api.com',\n * 'order-svc': 'http://order.api.com',\n * })\n * ```\n */\nexport class HttpContext {\n private _store = new Map<string, string>()\n private _loaded = false\n private _info: ContextInfo | undefined\n\n /**\n * 加载服务地址映射\n *\n * 远程加载时,响应中的 `$info` 元数据字段会被单独存储,不计入路由映射表。\n *\n * @param source 远程加载传入网关 URL;本地注入传入键值对象\n * @param timeout 远程加载超时(ms),默认 5000\n *\n * @example 远程加载\n * ```ts\n * await Context.load('http://172.16.32.155:20000', 3000)\n * ```\n *\n * @example 本地注入\n * ```ts\n * await Context.load({ 'user-svc': 'http://user.api.com' })\n * ```\n */\n async load(source: string | Record<string, string>, timeout = 5000): Promise<void> {\n if (typeof source === 'string') {\n const url = `${source}/ngw/context`\n const res = await axios.get<ContextResponse>(url, { timeout })\n const data = res.data\n if (data && typeof data === 'object') {\n this._store.clear()\n for (const [k, v] of Object.entries(data)) {\n if (k === '$info') {\n // 保存元数据,不计入路由映射\n this._info = v as ContextInfo\n } else if (typeof v === 'string') {\n this._store.set(k, v)\n }\n }\n }\n } else {\n this._store.clear()\n for (const [k, v] of Object.entries(source)) {\n this._store.set(k, v)\n }\n }\n this._loaded = true\n }\n\n /**\n * 获取指定 ctx key 对应的服务地址\n * @param key ctx key,例如 `'ngw'`、`'osc'`\n * @returns 服务地址,未找到时返回空字符串\n *\n * @example\n * ```ts\n * await Context.load('http://172.16.32.155:20000')\n * Context.get('osc') // 'http://172.16.32.155:20000/osc'\n * Context.get('none') // ''\n * ```\n */\n get(key: string): string {\n return this._store.get(key) ?? ''\n }\n\n /**\n * 网关元数据(仅远程加载后可用)\n *\n * @example\n * ```ts\n * await Context.load('http://172.16.32.155:20000')\n * Context.info?.version // '4.6.2-r10'\n * Context.info?.domain // 'http://172.16.32.155:20000'\n * ```\n */\n get info(): ContextInfo | undefined {\n return this._info\n }\n\n /**\n * Context 是否已加载\n *\n * @example\n * ```ts\n * Context.loaded // false\n * await Context.load({ 'user-svc': 'http://user.api.com' })\n * Context.loaded // true\n * ```\n */\n get loaded(): boolean {\n return this._loaded\n }\n\n /**\n * 清空所有映射并重置加载状态\n *\n * @example\n * ```ts\n * Context.clear()\n * Context.loaded // false\n * ```\n */\n clear(): void {\n this._store.clear()\n this._loaded = false\n this._info = undefined\n }\n}\n\n/** 模块级单例,避免全局 window 污染 */\nconst _instance = new HttpContext()\n\n/**\n * HttpContext 全局单例\n *\n * @example\n * ```ts\n * import { Context } from '@snack-kit/lib/http'\n *\n * await Context.load('http://172.16.32.155:20000')\n * Context.get('osc') // 'http://172.16.32.155:20000/osc'\n * ```\n */\nexport const Context: HttpContext = _instance\n\n/** 浏览器 location 对象(兼容 Node/SSR 环境) */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst _loc: { protocol?: string; host?: string; pathname?: string } | undefined =\n typeof globalThis !== 'undefined'\n ? ((globalThis as Record<string, unknown>)['location'] as typeof _loc)\n : undefined\n\n/**\n * 当前页面的 origin(`protocol + host`)\n *\n * 在非浏览器环境(如 SSR/Node)返回空字符串。\n *\n * @example\n * ```ts\n * import { Origin } from '@snack-kit/lib/http'\n * // 浏览器中:'https://app.example.com'\n * // Node 环境:''\n * ```\n */\nexport const Origin: string =\n _loc?.protocol && _loc?.host ? `${_loc.protocol}//${_loc.host}` : ''\n\n/**\n * 当前页面路径的首段,可直接用作 `ctx` 参数\n *\n * 例如 `/osc/employee` → `'osc'`,在非浏览器环境返回空字符串。\n *\n * @example\n * ```ts\n * import { Ctx, Get } from '@snack-kit/lib/http'\n *\n * // 当前路径为 /osc/... 时,Ctx === 'osc'\n * const result = await Get('/employee', { ctx: Ctx })\n * ```\n */\nexport const Ctx: string = _loc?.pathname ? (_loc.pathname.split('/')[1] ?? '') : ''\n","/** 模块私有注册表,避免全局 window 污染 */\nconst registry = new Map<string, AbortController>()\n\n/**\n * 注册一个请求取消控制器\n *\n * 若已存在相同 id 的控制器,先取消旧请求再注册新的。\n *\n * @param id 请求唯一标识\n * @returns 新创建的 AbortController\n *\n * @example\n * ```ts\n * import { Register, Cancel } from '@snack-kit/lib/http'\n *\n * const ctrl = Register('my-req')\n * // 请求进行中时手动取消\n * Cancel('my-req')\n * ```\n */\nexport function Register(id: string): AbortController {\n if (registry.has(id)) {\n registry.get(id)!.abort()\n }\n const controller = new AbortController()\n registry.set(id, controller)\n return controller\n}\n\n/**\n * 取消指定 id 的请求并从注册表移除\n *\n * @param id 请求唯一标识\n * @returns 是否找到并取消了请求\n *\n * @example\n * ```ts\n * import { Get, Cancel } from '@snack-kit/lib/http'\n *\n * let cancelId = ''\n * Get('/api/data', { onCancelId: (id) => { cancelId = id } })\n *\n * // 需要时取消\n * Cancel(cancelId)\n * ```\n */\nexport function Cancel(id: string): boolean {\n const controller = registry.get(id)\n if (!controller) return false\n controller.abort()\n registry.delete(id)\n return true\n}\n\n/**\n * 取消所有已注册的请求并清空注册表\n *\n * @example\n * ```ts\n * import { CancelAll } from '@snack-kit/lib/http'\n *\n * // 页面卸载时取消所有进行中的请求\n * window.addEventListener('beforeunload', () => CancelAll())\n * ```\n */\nexport function CancelAll(): void {\n for (const controller of registry.values()) {\n controller.abort()\n }\n registry.clear()\n}\n\n/**\n * 从注册表中移除指定 id(不触发取消,用于请求完成后内部清理)\n *\n * @param id 请求唯一标识\n */\nexport function Unregister(id: string): void {\n registry.delete(id)\n}\n","import axios, { isAxiosError } from 'axios'\nimport { Context } from './context'\nimport { Register, Unregister } from './cancel'\nimport type { HttpRequestConfig, HttpResult } from './types'\n\n/** 生成请求唯一 ID */\nfunction generateId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID()\n }\n return `${Date.now()}-${Math.random().toString(36).slice(2)}`\n}\n\n/**\n * 核心请求函数,所有快捷方法基于此实现\n *\n * 自动处理:\n * - `ctx` → 从 HttpContext 查询 baseURL 并注入\n * - `cache: false`(默认)→ URL 附加 `?_=timestamp` 防缓存\n * - 请求取消 → 自动注册 AbortController,完成后自动清理\n * - 错误捕获 → 统一返回 `{ error }` 而非 throw\n *\n * @param config 请求配置\n * @returns 请求结果\n *\n * @example 基础用法\n * ```ts\n * import { Request } from '@snack-kit/lib/http'\n *\n * const result = await Request<{ id: number }>({ url: '/api/user', method: 'GET' })\n * if (result.error) {\n * console.error(result.error.message)\n * } else {\n * console.log(result.data)\n * }\n * ```\n *\n * @example 使用 ctx 自动注入 baseURL\n * ```ts\n * import { context, Request } from '@snack-kit/lib/http'\n *\n * await context.load({ 'user-svc': 'http://user.api.com' })\n * const result = await Request({ url: '/profile', method: 'GET', ctx: 'user-svc' })\n * // 实际请求:GET http://user.api.com/profile\n * ```\n */\nexport async function Request<T>(config: HttpRequestConfig): Promise<HttpResult<T>> {\n const { ctx, cancelId: customCancelId, onCancelId, cache = false, ...axiosConfig } = config\n\n // ctx 自动注入 baseURL\n if (ctx && Context.loaded) {\n const base = Context.get(ctx)\n if (base) {\n axiosConfig.baseURL = base\n }\n }\n\n // 防缓存:默认添加时间戳参数\n if (!cache) {\n const sep = (axiosConfig.url ?? '').includes('?') ? '&' : '?'\n axiosConfig.url = `${axiosConfig.url ?? ''}${sep}_=${Date.now()}`\n }\n\n // 注册取消控制器\n const cancelId = customCancelId ?? generateId()\n const controller = Register(cancelId)\n axiosConfig.signal = controller.signal\n onCancelId?.(cancelId)\n\n try {\n const response = await axios.request<T>({ ...axiosConfig })\n return response\n } catch (err) {\n if (isAxiosError(err)) {\n return {\n error: {\n status: err.response?.status,\n message: err.message,\n data: err.response?.data,\n },\n }\n }\n // AbortError 或其他非 axios 错误\n const message = err instanceof Error ? err.message : String(err)\n return { error: { message } }\n } finally {\n Unregister(cancelId)\n }\n}\n\n/**\n * 发起 GET 请求\n *\n * @param url 请求地址\n * @param config 请求配置\n *\n * @example\n * ```ts\n * import { Get } from '@snack-kit/lib/http'\n *\n * const { data, error } = await Get<{ name: string }>('/api/user/1')\n * if (!error) console.log(data?.name)\n * ```\n *\n * @example 使用 ctx 自动路由\n * ```ts\n * const { data } = await Get('/profile', { ctx: 'user-svc' })\n * ```\n *\n * @example 获取 cancelId 以便主动取消\n * ```ts\n * let cancelId = ''\n * Get('/api/list', { onCancelId: (id) => { cancelId = id } })\n * Cancel(cancelId) // 取消请求\n * ```\n */\nexport function Get<T>(url: string, config?: HttpRequestConfig): Promise<HttpResult<T>> {\n return Request<T>({ ...config, method: 'GET', url })\n}\n\n/**\n * 发起 POST 请求\n *\n * @param url 请求地址\n * @param data 请求体数据\n * @param config 请求配置\n *\n * @example\n * ```ts\n * import { Post } from '@snack-kit/lib/http'\n *\n * const { data, error } = await Post<{ token: string }>('/api/login', {\n * username: 'admin',\n * password: '123456',\n * })\n * if (!error) console.log(data?.token)\n * ```\n */\nexport function Post<T>(\n url: string,\n data?: unknown,\n config?: HttpRequestConfig,\n): Promise<HttpResult<T>> {\n return Request<T>({ ...config, method: 'POST', url, data })\n}\n\n/**\n * 发起 PUT 请求\n *\n * @param url 请求地址\n * @param data 请求体数据\n * @param config 请求配置\n *\n * @example\n * ```ts\n * import { Put } from '@snack-kit/lib/http'\n *\n * await Put('/api/user/1', { name: 'Alice' })\n * ```\n */\nexport function Put<T>(\n url: string,\n data?: unknown,\n config?: HttpRequestConfig,\n): Promise<HttpResult<T>> {\n return Request<T>({ ...config, method: 'PUT', url, data })\n}\n\n/**\n * 发起 PATCH 请求\n *\n * @param url 请求地址\n * @param data 请求体数据\n * @param config 请求配置\n *\n * @example\n * ```ts\n * import { Patch } from '@snack-kit/lib/http'\n *\n * await Patch('/api/user/1', { avatar: 'https://...' })\n * ```\n */\nexport function Patch<T>(\n url: string,\n data?: unknown,\n config?: HttpRequestConfig,\n): Promise<HttpResult<T>> {\n return Request<T>({ ...config, method: 'PATCH', url, data })\n}\n\n/**\n * 发起 DELETE 请求\n *\n * @param url 请求地址\n * @param config 请求配置\n *\n * @example\n * ```ts\n * import { Del } from '@snack-kit/lib/http'\n *\n * await Del('/api/user/1')\n * ```\n */\nexport function Del<T>(url: string, config?: HttpRequestConfig): Promise<HttpResult<T>> {\n return Request<T>({ ...config, method: 'DELETE', url })\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-YY5WQN7B.cjs"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkJBJEXFQC_cjs = require('./chunk-JBJEXFQC.cjs');
|
|
4
|
+
require('./chunk-N7BJS6LI.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Object.defineProperty(exports, "Debugger", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
get: function () { return chunkJBJEXFQC_cjs.Debugger; }
|
|
11
|
+
});
|
|
12
|
+
//# sourceMappingURL=debugger.cjs.map
|
|
13
|
+
//# sourceMappingURL=debugger.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"debugger.cjs"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
require('./chunk-YY5WQN7B.cjs');
|
|
4
|
+
var chunkN7BJS6LI_cjs = require('./chunk-N7BJS6LI.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Object.defineProperty(exports, "Cancel", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
get: function () { return chunkN7BJS6LI_cjs.Cancel; }
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "CancelAll", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () { return chunkN7BJS6LI_cjs.CancelAll; }
|
|
15
|
+
});
|
|
16
|
+
Object.defineProperty(exports, "Context", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return chunkN7BJS6LI_cjs.Context; }
|
|
19
|
+
});
|
|
20
|
+
Object.defineProperty(exports, "Ctx", {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: function () { return chunkN7BJS6LI_cjs.Ctx; }
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "Del", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () { return chunkN7BJS6LI_cjs.Del; }
|
|
27
|
+
});
|
|
28
|
+
Object.defineProperty(exports, "Get", {
|
|
29
|
+
enumerable: true,
|
|
30
|
+
get: function () { return chunkN7BJS6LI_cjs.Get; }
|
|
31
|
+
});
|
|
32
|
+
Object.defineProperty(exports, "HttpContext", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
get: function () { return chunkN7BJS6LI_cjs.HttpContext; }
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(exports, "Origin", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () { return chunkN7BJS6LI_cjs.Origin; }
|
|
39
|
+
});
|
|
40
|
+
Object.defineProperty(exports, "Patch", {
|
|
41
|
+
enumerable: true,
|
|
42
|
+
get: function () { return chunkN7BJS6LI_cjs.Patch; }
|
|
43
|
+
});
|
|
44
|
+
Object.defineProperty(exports, "Post", {
|
|
45
|
+
enumerable: true,
|
|
46
|
+
get: function () { return chunkN7BJS6LI_cjs.Post; }
|
|
47
|
+
});
|
|
48
|
+
Object.defineProperty(exports, "Put", {
|
|
49
|
+
enumerable: true,
|
|
50
|
+
get: function () { return chunkN7BJS6LI_cjs.Put; }
|
|
51
|
+
});
|
|
52
|
+
Object.defineProperty(exports, "Request", {
|
|
53
|
+
enumerable: true,
|
|
54
|
+
get: function () { return chunkN7BJS6LI_cjs.Request; }
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=http.cjs.map
|
|
57
|
+
//# sourceMappingURL=http.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"http.cjs"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
require('./chunk-YY5WQN7B.cjs');
|
|
4
|
+
var chunkJBJEXFQC_cjs = require('./chunk-JBJEXFQC.cjs');
|
|
5
|
+
var chunkN7BJS6LI_cjs = require('./chunk-N7BJS6LI.cjs');
|
|
6
|
+
|
|
7
|
+
// package.json
|
|
8
|
+
var version = "0.1.0";
|
|
9
|
+
|
|
10
|
+
Object.defineProperty(exports, "Debugger", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () { return chunkJBJEXFQC_cjs.Debugger; }
|
|
13
|
+
});
|
|
14
|
+
Object.defineProperty(exports, "Cancel", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () { return chunkN7BJS6LI_cjs.Cancel; }
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "CancelAll", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () { return chunkN7BJS6LI_cjs.CancelAll; }
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(exports, "Context", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
get: function () { return chunkN7BJS6LI_cjs.Context; }
|
|
25
|
+
});
|
|
26
|
+
Object.defineProperty(exports, "Ctx", {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
get: function () { return chunkN7BJS6LI_cjs.Ctx; }
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(exports, "Del", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () { return chunkN7BJS6LI_cjs.Del; }
|
|
33
|
+
});
|
|
34
|
+
Object.defineProperty(exports, "Get", {
|
|
35
|
+
enumerable: true,
|
|
36
|
+
get: function () { return chunkN7BJS6LI_cjs.Get; }
|
|
37
|
+
});
|
|
38
|
+
Object.defineProperty(exports, "HttpContext", {
|
|
39
|
+
enumerable: true,
|
|
40
|
+
get: function () { return chunkN7BJS6LI_cjs.HttpContext; }
|
|
41
|
+
});
|
|
42
|
+
Object.defineProperty(exports, "Origin", {
|
|
43
|
+
enumerable: true,
|
|
44
|
+
get: function () { return chunkN7BJS6LI_cjs.Origin; }
|
|
45
|
+
});
|
|
46
|
+
Object.defineProperty(exports, "Patch", {
|
|
47
|
+
enumerable: true,
|
|
48
|
+
get: function () { return chunkN7BJS6LI_cjs.Patch; }
|
|
49
|
+
});
|
|
50
|
+
Object.defineProperty(exports, "Post", {
|
|
51
|
+
enumerable: true,
|
|
52
|
+
get: function () { return chunkN7BJS6LI_cjs.Post; }
|
|
53
|
+
});
|
|
54
|
+
Object.defineProperty(exports, "Put", {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function () { return chunkN7BJS6LI_cjs.Put; }
|
|
57
|
+
});
|
|
58
|
+
Object.defineProperty(exports, "Request", {
|
|
59
|
+
enumerable: true,
|
|
60
|
+
get: function () { return chunkN7BJS6LI_cjs.Request; }
|
|
61
|
+
});
|
|
62
|
+
exports.VERSION = version;
|
|
63
|
+
//# sourceMappingURL=index.cjs.map
|
|
64
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../package.json"],"names":[],"mappings":";;;;;;;AAEE,IAAA,OAAA,GAAW","file":"index.cjs","sourcesContent":["{\n \"name\": \"@snack-kit/lib\",\n \"version\": \"0.1.0\",\n \"description\": \"Enterprise-grade utility library\",\n \"keywords\": [],\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/types/index.d.ts\",\n \"import\": \"./dist/es/index.js\",\n \"require\": \"./dist/cjs/index.cjs\"\n },\n \"./http\": {\n \"types\": \"./dist/types/http.d.ts\",\n \"import\": \"./dist/es/http.js\",\n \"require\": \"./dist/cjs/http.cjs\"\n },\n \"./debugger\": {\n \"types\": \"./dist/types/debugger.d.ts\",\n \"import\": \"./dist/es/debugger.js\",\n \"require\": \"./dist/cjs/debugger.cjs\"\n }\n },\n \"main\": \"./dist/cjs/index.cjs\",\n \"module\": \"./dist/es/index.js\",\n \"types\": \"./dist/types/index.d.ts\",\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"build:watch\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\",\n \"docs\": \"typedoc && cp -r docs/demo docs/api/demo\",\n \"docs:watch\": \"typedoc --watch\",\n \"lint\": \"tsc --noEmit\",\n \"prepublishOnly\": \"npm run build\",\n \"release\": \"npm run build && npm publish --access public\"\n },\n \"devDependencies\": {\n \"@vitest/coverage-v8\": \"^2.0.0\",\n \"tsup\": \"^8.0.0\",\n \"typedoc\": \"^0.26.0\",\n \"typescript\": \"^5.5.3\",\n \"vitest\": \"^2.0.0\"\n },\n \"dependencies\": {\n \"axios\": \"^1.13.6\"\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-BEL6AFK4.js"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import axios, { isAxiosError } from 'axios';
|
|
2
|
+
|
|
3
|
+
// src/http/context.ts
|
|
4
|
+
var HttpContext = class {
|
|
5
|
+
constructor() {
|
|
6
|
+
this._store = /* @__PURE__ */ new Map();
|
|
7
|
+
this._loaded = false;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 加载服务地址映射
|
|
11
|
+
*
|
|
12
|
+
* 远程加载时,响应中的 `$info` 元数据字段会被单独存储,不计入路由映射表。
|
|
13
|
+
*
|
|
14
|
+
* @param source 远程加载传入网关 URL;本地注入传入键值对象
|
|
15
|
+
* @param timeout 远程加载超时(ms),默认 5000
|
|
16
|
+
*
|
|
17
|
+
* @example 远程加载
|
|
18
|
+
* ```ts
|
|
19
|
+
* await Context.load('http://172.16.32.155:20000', 3000)
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example 本地注入
|
|
23
|
+
* ```ts
|
|
24
|
+
* await Context.load({ 'user-svc': 'http://user.api.com' })
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
async load(source, timeout = 5e3) {
|
|
28
|
+
if (typeof source === "string") {
|
|
29
|
+
const url = `${source}/ngw/context`;
|
|
30
|
+
const res = await axios.get(url, { timeout });
|
|
31
|
+
const data = res.data;
|
|
32
|
+
if (data && typeof data === "object") {
|
|
33
|
+
this._store.clear();
|
|
34
|
+
for (const [k, v] of Object.entries(data)) {
|
|
35
|
+
if (k === "$info") {
|
|
36
|
+
this._info = v;
|
|
37
|
+
} else if (typeof v === "string") {
|
|
38
|
+
this._store.set(k, v);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
this._store.clear();
|
|
44
|
+
for (const [k, v] of Object.entries(source)) {
|
|
45
|
+
this._store.set(k, v);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
this._loaded = true;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 获取指定 ctx key 对应的服务地址
|
|
52
|
+
* @param key ctx key,例如 `'ngw'`、`'osc'`
|
|
53
|
+
* @returns 服务地址,未找到时返回空字符串
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* await Context.load('http://172.16.32.155:20000')
|
|
58
|
+
* Context.get('osc') // 'http://172.16.32.155:20000/osc'
|
|
59
|
+
* Context.get('none') // ''
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
get(key) {
|
|
63
|
+
return this._store.get(key) ?? "";
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 网关元数据(仅远程加载后可用)
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* await Context.load('http://172.16.32.155:20000')
|
|
71
|
+
* Context.info?.version // '4.6.2-r10'
|
|
72
|
+
* Context.info?.domain // 'http://172.16.32.155:20000'
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
get info() {
|
|
76
|
+
return this._info;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Context 是否已加载
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* Context.loaded // false
|
|
84
|
+
* await Context.load({ 'user-svc': 'http://user.api.com' })
|
|
85
|
+
* Context.loaded // true
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
get loaded() {
|
|
89
|
+
return this._loaded;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 清空所有映射并重置加载状态
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* Context.clear()
|
|
97
|
+
* Context.loaded // false
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
clear() {
|
|
101
|
+
this._store.clear();
|
|
102
|
+
this._loaded = false;
|
|
103
|
+
this._info = void 0;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var _instance = new HttpContext();
|
|
107
|
+
var Context = _instance;
|
|
108
|
+
var _loc = typeof globalThis !== "undefined" ? globalThis["location"] : void 0;
|
|
109
|
+
var Origin = _loc?.protocol && _loc?.host ? `${_loc.protocol}//${_loc.host}` : "";
|
|
110
|
+
var Ctx = _loc?.pathname ? _loc.pathname.split("/")[1] ?? "" : "";
|
|
111
|
+
|
|
112
|
+
// src/http/cancel.ts
|
|
113
|
+
var registry = /* @__PURE__ */ new Map();
|
|
114
|
+
function Register(id) {
|
|
115
|
+
if (registry.has(id)) {
|
|
116
|
+
registry.get(id).abort();
|
|
117
|
+
}
|
|
118
|
+
const controller = new AbortController();
|
|
119
|
+
registry.set(id, controller);
|
|
120
|
+
return controller;
|
|
121
|
+
}
|
|
122
|
+
function Cancel(id) {
|
|
123
|
+
const controller = registry.get(id);
|
|
124
|
+
if (!controller) return false;
|
|
125
|
+
controller.abort();
|
|
126
|
+
registry.delete(id);
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
function CancelAll() {
|
|
130
|
+
for (const controller of registry.values()) {
|
|
131
|
+
controller.abort();
|
|
132
|
+
}
|
|
133
|
+
registry.clear();
|
|
134
|
+
}
|
|
135
|
+
function Unregister(id) {
|
|
136
|
+
registry.delete(id);
|
|
137
|
+
}
|
|
138
|
+
function generateId() {
|
|
139
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
140
|
+
return crypto.randomUUID();
|
|
141
|
+
}
|
|
142
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
143
|
+
}
|
|
144
|
+
async function Request(config) {
|
|
145
|
+
const { ctx, cancelId: customCancelId, onCancelId, cache = false, ...axiosConfig } = config;
|
|
146
|
+
if (ctx && Context.loaded) {
|
|
147
|
+
const base = Context.get(ctx);
|
|
148
|
+
if (base) {
|
|
149
|
+
axiosConfig.baseURL = base;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (!cache) {
|
|
153
|
+
const sep = (axiosConfig.url ?? "").includes("?") ? "&" : "?";
|
|
154
|
+
axiosConfig.url = `${axiosConfig.url ?? ""}${sep}_=${Date.now()}`;
|
|
155
|
+
}
|
|
156
|
+
const cancelId = customCancelId ?? generateId();
|
|
157
|
+
const controller = Register(cancelId);
|
|
158
|
+
axiosConfig.signal = controller.signal;
|
|
159
|
+
onCancelId?.(cancelId);
|
|
160
|
+
try {
|
|
161
|
+
const response = await axios.request({ ...axiosConfig });
|
|
162
|
+
return response;
|
|
163
|
+
} catch (err) {
|
|
164
|
+
if (isAxiosError(err)) {
|
|
165
|
+
return {
|
|
166
|
+
error: {
|
|
167
|
+
status: err.response?.status,
|
|
168
|
+
message: err.message,
|
|
169
|
+
data: err.response?.data
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
174
|
+
return { error: { message } };
|
|
175
|
+
} finally {
|
|
176
|
+
Unregister(cancelId);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function Get(url, config) {
|
|
180
|
+
return Request({ ...config, method: "GET", url });
|
|
181
|
+
}
|
|
182
|
+
function Post(url, data, config) {
|
|
183
|
+
return Request({ ...config, method: "POST", url, data });
|
|
184
|
+
}
|
|
185
|
+
function Put(url, data, config) {
|
|
186
|
+
return Request({ ...config, method: "PUT", url, data });
|
|
187
|
+
}
|
|
188
|
+
function Patch(url, data, config) {
|
|
189
|
+
return Request({ ...config, method: "PATCH", url, data });
|
|
190
|
+
}
|
|
191
|
+
function Del(url, config) {
|
|
192
|
+
return Request({ ...config, method: "DELETE", url });
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export { Cancel, CancelAll, Context, Ctx, Del, Get, HttpContext, Origin, Patch, Post, Put, Request };
|
|
196
|
+
//# sourceMappingURL=chunk-JQYH5FWE.js.map
|
|
197
|
+
//# sourceMappingURL=chunk-JQYH5FWE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/http/context.ts","../../src/http/cancel.ts","../../src/http/client.ts"],"names":["axios"],"mappings":"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","file":"chunk-JQYH5FWE.js","sourcesContent":["import axios from 'axios'\nimport type { ContextInfo } from './types'\n\n/** 网关 `/ngw/context` 原始响应格式(包含路由映射和 `$info` 元数据) */\ninterface ContextResponse {\n $info?: ContextInfo\n [key: string]: string | ContextInfo | undefined\n}\n\n/**\n * 管理服务地址映射的上下文单例\n *\n * 支持两种加载方式:\n * - **远程加载**:传入网关 URL,自动请求 `GET /ngw/context` 获取映射表\n * - **本地注入**:直接传入键值对象\n *\n * @example 远程加载\n * ```ts\n * import { Context } from '@snack-kit/lib/http'\n *\n * await Context.load('http://172.16.32.155:20000')\n * Context.get('ngw') // 'http://172.16.32.155:20000/ngw'\n * Context.info // { version: '4.6.2-r10', domain: '...', ... }\n * ```\n *\n * @example 本地注入\n * ```ts\n * await Context.load({\n * 'user-svc': 'http://user.api.com',\n * 'order-svc': 'http://order.api.com',\n * })\n * ```\n */\nexport class HttpContext {\n private _store = new Map<string, string>()\n private _loaded = false\n private _info: ContextInfo | undefined\n\n /**\n * 加载服务地址映射\n *\n * 远程加载时,响应中的 `$info` 元数据字段会被单独存储,不计入路由映射表。\n *\n * @param source 远程加载传入网关 URL;本地注入传入键值对象\n * @param timeout 远程加载超时(ms),默认 5000\n *\n * @example 远程加载\n * ```ts\n * await Context.load('http://172.16.32.155:20000', 3000)\n * ```\n *\n * @example 本地注入\n * ```ts\n * await Context.load({ 'user-svc': 'http://user.api.com' })\n * ```\n */\n async load(source: string | Record<string, string>, timeout = 5000): Promise<void> {\n if (typeof source === 'string') {\n const url = `${source}/ngw/context`\n const res = await axios.get<ContextResponse>(url, { timeout })\n const data = res.data\n if (data && typeof data === 'object') {\n this._store.clear()\n for (const [k, v] of Object.entries(data)) {\n if (k === '$info') {\n // 保存元数据,不计入路由映射\n this._info = v as ContextInfo\n } else if (typeof v === 'string') {\n this._store.set(k, v)\n }\n }\n }\n } else {\n this._store.clear()\n for (const [k, v] of Object.entries(source)) {\n this._store.set(k, v)\n }\n }\n this._loaded = true\n }\n\n /**\n * 获取指定 ctx key 对应的服务地址\n * @param key ctx key,例如 `'ngw'`、`'osc'`\n * @returns 服务地址,未找到时返回空字符串\n *\n * @example\n * ```ts\n * await Context.load('http://172.16.32.155:20000')\n * Context.get('osc') // 'http://172.16.32.155:20000/osc'\n * Context.get('none') // ''\n * ```\n */\n get(key: string): string {\n return this._store.get(key) ?? ''\n }\n\n /**\n * 网关元数据(仅远程加载后可用)\n *\n * @example\n * ```ts\n * await Context.load('http://172.16.32.155:20000')\n * Context.info?.version // '4.6.2-r10'\n * Context.info?.domain // 'http://172.16.32.155:20000'\n * ```\n */\n get info(): ContextInfo | undefined {\n return this._info\n }\n\n /**\n * Context 是否已加载\n *\n * @example\n * ```ts\n * Context.loaded // false\n * await Context.load({ 'user-svc': 'http://user.api.com' })\n * Context.loaded // true\n * ```\n */\n get loaded(): boolean {\n return this._loaded\n }\n\n /**\n * 清空所有映射并重置加载状态\n *\n * @example\n * ```ts\n * Context.clear()\n * Context.loaded // false\n * ```\n */\n clear(): void {\n this._store.clear()\n this._loaded = false\n this._info = undefined\n }\n}\n\n/** 模块级单例,避免全局 window 污染 */\nconst _instance = new HttpContext()\n\n/**\n * HttpContext 全局单例\n *\n * @example\n * ```ts\n * import { Context } from '@snack-kit/lib/http'\n *\n * await Context.load('http://172.16.32.155:20000')\n * Context.get('osc') // 'http://172.16.32.155:20000/osc'\n * ```\n */\nexport const Context: HttpContext = _instance\n\n/** 浏览器 location 对象(兼容 Node/SSR 环境) */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst _loc: { protocol?: string; host?: string; pathname?: string } | undefined =\n typeof globalThis !== 'undefined'\n ? ((globalThis as Record<string, unknown>)['location'] as typeof _loc)\n : undefined\n\n/**\n * 当前页面的 origin(`protocol + host`)\n *\n * 在非浏览器环境(如 SSR/Node)返回空字符串。\n *\n * @example\n * ```ts\n * import { Origin } from '@snack-kit/lib/http'\n * // 浏览器中:'https://app.example.com'\n * // Node 环境:''\n * ```\n */\nexport const Origin: string =\n _loc?.protocol && _loc?.host ? `${_loc.protocol}//${_loc.host}` : ''\n\n/**\n * 当前页面路径的首段,可直接用作 `ctx` 参数\n *\n * 例如 `/osc/employee` → `'osc'`,在非浏览器环境返回空字符串。\n *\n * @example\n * ```ts\n * import { Ctx, Get } from '@snack-kit/lib/http'\n *\n * // 当前路径为 /osc/... 时,Ctx === 'osc'\n * const result = await Get('/employee', { ctx: Ctx })\n * ```\n */\nexport const Ctx: string = _loc?.pathname ? (_loc.pathname.split('/')[1] ?? '') : ''\n","/** 模块私有注册表,避免全局 window 污染 */\nconst registry = new Map<string, AbortController>()\n\n/**\n * 注册一个请求取消控制器\n *\n * 若已存在相同 id 的控制器,先取消旧请求再注册新的。\n *\n * @param id 请求唯一标识\n * @returns 新创建的 AbortController\n *\n * @example\n * ```ts\n * import { Register, Cancel } from '@snack-kit/lib/http'\n *\n * const ctrl = Register('my-req')\n * // 请求进行中时手动取消\n * Cancel('my-req')\n * ```\n */\nexport function Register(id: string): AbortController {\n if (registry.has(id)) {\n registry.get(id)!.abort()\n }\n const controller = new AbortController()\n registry.set(id, controller)\n return controller\n}\n\n/**\n * 取消指定 id 的请求并从注册表移除\n *\n * @param id 请求唯一标识\n * @returns 是否找到并取消了请求\n *\n * @example\n * ```ts\n * import { Get, Cancel } from '@snack-kit/lib/http'\n *\n * let cancelId = ''\n * Get('/api/data', { onCancelId: (id) => { cancelId = id } })\n *\n * // 需要时取消\n * Cancel(cancelId)\n * ```\n */\nexport function Cancel(id: string): boolean {\n const controller = registry.get(id)\n if (!controller) return false\n controller.abort()\n registry.delete(id)\n return true\n}\n\n/**\n * 取消所有已注册的请求并清空注册表\n *\n * @example\n * ```ts\n * import { CancelAll } from '@snack-kit/lib/http'\n *\n * // 页面卸载时取消所有进行中的请求\n * window.addEventListener('beforeunload', () => CancelAll())\n * ```\n */\nexport function CancelAll(): void {\n for (const controller of registry.values()) {\n controller.abort()\n }\n registry.clear()\n}\n\n/**\n * 从注册表中移除指定 id(不触发取消,用于请求完成后内部清理)\n *\n * @param id 请求唯一标识\n */\nexport function Unregister(id: string): void {\n registry.delete(id)\n}\n","import axios, { isAxiosError } from 'axios'\nimport { Context } from './context'\nimport { Register, Unregister } from './cancel'\nimport type { HttpRequestConfig, HttpResult } from './types'\n\n/** 生成请求唯一 ID */\nfunction generateId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID()\n }\n return `${Date.now()}-${Math.random().toString(36).slice(2)}`\n}\n\n/**\n * 核心请求函数,所有快捷方法基于此实现\n *\n * 自动处理:\n * - `ctx` → 从 HttpContext 查询 baseURL 并注入\n * - `cache: false`(默认)→ URL 附加 `?_=timestamp` 防缓存\n * - 请求取消 → 自动注册 AbortController,完成后自动清理\n * - 错误捕获 → 统一返回 `{ error }` 而非 throw\n *\n * @param config 请求配置\n * @returns 请求结果\n *\n * @example 基础用法\n * ```ts\n * import { Request } from '@snack-kit/lib/http'\n *\n * const result = await Request<{ id: number }>({ url: '/api/user', method: 'GET' })\n * if (result.error) {\n * console.error(result.error.message)\n * } else {\n * console.log(result.data)\n * }\n * ```\n *\n * @example 使用 ctx 自动注入 baseURL\n * ```ts\n * import { context, Request } from '@snack-kit/lib/http'\n *\n * await context.load({ 'user-svc': 'http://user.api.com' })\n * const result = await Request({ url: '/profile', method: 'GET', ctx: 'user-svc' })\n * // 实际请求:GET http://user.api.com/profile\n * ```\n */\nexport async function Request<T>(config: HttpRequestConfig): Promise<HttpResult<T>> {\n const { ctx, cancelId: customCancelId, onCancelId, cache = false, ...axiosConfig } = config\n\n // ctx 自动注入 baseURL\n if (ctx && Context.loaded) {\n const base = Context.get(ctx)\n if (base) {\n axiosConfig.baseURL = base\n }\n }\n\n // 防缓存:默认添加时间戳参数\n if (!cache) {\n const sep = (axiosConfig.url ?? '').includes('?') ? '&' : '?'\n axiosConfig.url = `${axiosConfig.url ?? ''}${sep}_=${Date.now()}`\n }\n\n // 注册取消控制器\n const cancelId = customCancelId ?? generateId()\n const controller = Register(cancelId)\n axiosConfig.signal = controller.signal\n onCancelId?.(cancelId)\n\n try {\n const response = await axios.request<T>({ ...axiosConfig })\n return response\n } catch (err) {\n if (isAxiosError(err)) {\n return {\n error: {\n status: err.response?.status,\n message: err.message,\n data: err.response?.data,\n },\n }\n }\n // AbortError 或其他非 axios 错误\n const message = err instanceof Error ? err.message : String(err)\n return { error: { message } }\n } finally {\n Unregister(cancelId)\n }\n}\n\n/**\n * 发起 GET 请求\n *\n * @param url 请求地址\n * @param config 请求配置\n *\n * @example\n * ```ts\n * import { Get } from '@snack-kit/lib/http'\n *\n * const { data, error } = await Get<{ name: string }>('/api/user/1')\n * if (!error) console.log(data?.name)\n * ```\n *\n * @example 使用 ctx 自动路由\n * ```ts\n * const { data } = await Get('/profile', { ctx: 'user-svc' })\n * ```\n *\n * @example 获取 cancelId 以便主动取消\n * ```ts\n * let cancelId = ''\n * Get('/api/list', { onCancelId: (id) => { cancelId = id } })\n * Cancel(cancelId) // 取消请求\n * ```\n */\nexport function Get<T>(url: string, config?: HttpRequestConfig): Promise<HttpResult<T>> {\n return Request<T>({ ...config, method: 'GET', url })\n}\n\n/**\n * 发起 POST 请求\n *\n * @param url 请求地址\n * @param data 请求体数据\n * @param config 请求配置\n *\n * @example\n * ```ts\n * import { Post } from '@snack-kit/lib/http'\n *\n * const { data, error } = await Post<{ token: string }>('/api/login', {\n * username: 'admin',\n * password: '123456',\n * })\n * if (!error) console.log(data?.token)\n * ```\n */\nexport function Post<T>(\n url: string,\n data?: unknown,\n config?: HttpRequestConfig,\n): Promise<HttpResult<T>> {\n return Request<T>({ ...config, method: 'POST', url, data })\n}\n\n/**\n * 发起 PUT 请求\n *\n * @param url 请求地址\n * @param data 请求体数据\n * @param config 请求配置\n *\n * @example\n * ```ts\n * import { Put } from '@snack-kit/lib/http'\n *\n * await Put('/api/user/1', { name: 'Alice' })\n * ```\n */\nexport function Put<T>(\n url: string,\n data?: unknown,\n config?: HttpRequestConfig,\n): Promise<HttpResult<T>> {\n return Request<T>({ ...config, method: 'PUT', url, data })\n}\n\n/**\n * 发起 PATCH 请求\n *\n * @param url 请求地址\n * @param data 请求体数据\n * @param config 请求配置\n *\n * @example\n * ```ts\n * import { Patch } from '@snack-kit/lib/http'\n *\n * await Patch('/api/user/1', { avatar: 'https://...' })\n * ```\n */\nexport function Patch<T>(\n url: string,\n data?: unknown,\n config?: HttpRequestConfig,\n): Promise<HttpResult<T>> {\n return Request<T>({ ...config, method: 'PATCH', url, data })\n}\n\n/**\n * 发起 DELETE 请求\n *\n * @param url 请求地址\n * @param config 请求配置\n *\n * @example\n * ```ts\n * import { Del } from '@snack-kit/lib/http'\n *\n * await Del('/api/user/1')\n * ```\n */\nexport function Del<T>(url: string, config?: HttpRequestConfig): Promise<HttpResult<T>> {\n return Request<T>({ ...config, method: 'DELETE', url })\n}\n"]}
|