@snack-kit/lib 0.3.0 → 0.5.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 +261 -17
- package/dist/cjs/chunk-IMHC6CTK.cjs +13 -0
- package/dist/{es/chunk-BEL6AFK4.js.map → cjs/chunk-IMHC6CTK.cjs.map} +1 -1
- package/dist/cjs/{chunk-N7BJS6LI.cjs → chunk-XEQEQWDB.cjs} +48 -14
- package/dist/cjs/chunk-XEQEQWDB.cjs.map +1 -0
- package/dist/cjs/{chunk-YOWLTZM5.cjs → chunk-ZJMTV2GJ.cjs} +7 -6
- package/dist/cjs/chunk-ZJMTV2GJ.cjs.map +1 -0
- package/dist/cjs/debugger.cjs +7 -3
- package/dist/cjs/http.cjs +22 -14
- package/dist/cjs/index.cjs +29 -17
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/es/{chunk-4DLFIN3C.js → chunk-4SGFAIRT.js} +4 -3
- package/dist/es/chunk-4SGFAIRT.js.map +1 -0
- package/dist/es/chunk-MHCY2PIP.js +3 -0
- package/dist/{cjs/chunk-YY5WQN7B.cjs.map → es/chunk-MHCY2PIP.js.map} +1 -1
- package/dist/es/{chunk-JQYH5FWE.js → chunk-YV6SGXUJ.js} +48 -15
- package/dist/es/chunk-YV6SGXUJ.js.map +1 -0
- package/dist/es/debugger.js +2 -2
- package/dist/es/http.js +2 -2
- package/dist/es/index.js +4 -4
- package/dist/es/index.js.map +1 -1
- package/dist/types/context-C4dFUDbw.d.ts +237 -0
- package/dist/types/debugger.d.ts +3 -0
- package/dist/types/http.d.ts +61 -236
- package/dist/types/index.d.ts +4 -3
- package/dist/umd/debugger.global.js +28 -5
- package/dist/umd/debugger.global.js.map +1 -1
- package/dist/umd/http.global.js +46 -12
- package/dist/umd/http.global.js.map +1 -1
- package/dist/umd/index.global.js +49 -13
- package/dist/umd/index.global.js.map +1 -1
- package/package.json +1 -1
- package/dist/cjs/chunk-N7BJS6LI.cjs.map +0 -1
- package/dist/cjs/chunk-YOWLTZM5.cjs.map +0 -1
- package/dist/cjs/chunk-YY5WQN7B.cjs +0 -4
- package/dist/es/chunk-4DLFIN3C.js.map +0 -1
- package/dist/es/chunk-BEL6AFK4.js +0 -3
- package/dist/es/chunk-JQYH5FWE.js.map +0 -1
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
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"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/debugger/debugger.ts"],"names":["Get","Context"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAwXpB,IAAM,eAAN,MAAmB;AAAA,EAWjB,YAAY,QAAA,EAAmC;AAJ/C,IAAA,IAAA,CAAQ,UAAmD,EAAC;AAC5D,IAAA,IAAA,CAAQ,QAAA,GAAW,EAAA;AAIjB,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,EAAA,GAAK,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACtC,IAAA,IAAA,CAAK,GAAG,SAAA,GAAY,YAAA;AAGpB,IAAA,IAAA,CAAK,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC3C,IAAA,IAAA,CAAK,QAAQ,SAAA,GAAY,oBAAA;AACzB,IAAA,IAAA,CAAK,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AAC1C,IAAA,IAAA,CAAK,MAAM,SAAA,GAAY,4BAAA;AACvB,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AAC3C,IAAA,KAAA,CAAM,SAAA,GAAY,kBAAA;AAClB,IAAA,KAAA,CAAM,WAAA,GAAc,QAAA;AACpB,IAAA,IAAA,CAAK,OAAA,CAAQ,WAAA,CAAY,IAAA,CAAK,KAAK,CAAA;AACnC,IAAA,IAAA,CAAK,OAAA,CAAQ,YAAY,KAAK,CAAA;AAG9B,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC5C,IAAA,IAAA,CAAK,SAAS,SAAA,GAAY,qBAAA;AAG1B,IAAA,MAAM,UAAA,GAAa,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC/C,IAAA,UAAA,CAAW,SAAA,GAAY,mBAAA;AACvB,IAAA,MAAM,UAAA,GAAa,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AAChD,IAAA,UAAA,CAAW,SAAA,GAAY,wBAAA;AACvB,IAAA,UAAA,CAAW,WAAA,GAAc,QAAA;AACzB,IAAA,IAAA,CAAK,WAAA,GAAc,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AACjD,IAAA,IAAA,CAAK,YAAY,IAAA,GAAO,MAAA;AACxB,IAAA,IAAA,CAAK,WAAA,CAAY,WAAA,GAAc,CAAA,CAAE,MAAA,EAAO;AACxC,IAAA,UAAA,CAAW,YAAY,UAAU,CAAA;AACjC,IAAA,UAAA,CAAW,WAAA,CAAY,KAAK,WAAW,CAAA;AAEvC,IAAA,IAAA,CAAK,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC1C,IAAA,IAAA,CAAK,OAAO,SAAA,GAAY,iBAAA;AAExB,IAAA,IAAA,CAAK,QAAA,CAAS,YAAY,UAAU,CAAA;AACpC,IAAA,IAAA,CAAK,QAAA,CAAS,WAAA,CAAY,IAAA,CAAK,MAAM,CAAA;AACrC,IAAA,IAAA,CAAK,EAAA,CAAG,WAAA,CAAY,IAAA,CAAK,OAAO,CAAA;AAChC,IAAA,IAAA,CAAK,EAAA,CAAG,WAAA,CAAY,IAAA,CAAK,QAAQ,CAAA;AAEjC,IAAA,IAAA,CAAK,UAAA,EAAW;AAAA,EAClB;AAAA,EAEQ,UAAA,GAAmB;AACzB,IAAA,IAAA,CAAK,OAAA,CAAQ,gBAAA,CAAiB,OAAA,EAAS,CAAC,CAAA,KAAM;AAC5C,MAAA,CAAA,CAAE,eAAA,EAAgB;AAClB,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,EAAA,CAAG,SAAA,CAAU,SAAS,MAAM,CAAA;AAChD,MAAA,QAAA,CAAS,gBAAA,CAAiB,yCAAyC,CAAA,CAAE,OAAA,CAAQ,CAAC,EAAA,KAAO;AACnF,QAAA,IAAI,OAAO,IAAA,CAAK,EAAA,EAAI,EAAA,CAAG,SAAA,CAAU,OAAO,MAAM,CAAA;AAAA,MAChD,CAAC,CAAA;AACD,MAAA,IAAA,CAAK,EAAA,CAAG,SAAA,CAAU,MAAA,CAAO,MAAA,EAAQ,CAAC,MAAM,CAAA;AACxC,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,IAAA,CAAK,YAAY,KAAA,GAAQ,EAAA;AACzB,QAAA,IAAA,CAAK,cAAc,EAAE,CAAA;AACrB,QAAA,UAAA,CAAW,MAAM,IAAA,CAAK,WAAA,CAAY,KAAA,IAAS,EAAE,CAAA;AAAA,MAC/C;AAAA,IACF,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,WAAA,CAAY,gBAAA,CAAiB,OAAA,EAAS,MAAM;AAC/C,MAAA,IAAA,CAAK,aAAA,CAAc,IAAA,CAAK,WAAA,CAAY,KAAK,CAAA;AAAA,IAC3C,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,YAAY,gBAAA,CAAiB,OAAA,EAAS,CAAC,CAAA,KAAM,CAAA,CAAE,iBAAiB,CAAA;AAErE,IAAA,QAAA,CAAS,gBAAA,CAAiB,SAAS,MAAM;AACvC,MAAA,IAAA,CAAK,EAAA,CAAG,SAAA,CAAU,MAAA,CAAO,MAAM,CAAA;AAAA,IACjC,CAAC,CAAA;AAAA,EACH;AAAA,EAEQ,cAAc,KAAA,EAAqB;AACzC,IAAA,MAAM,CAAA,GAAI,MAAM,WAAA,EAAY;AAC5B,IAAA,IAAI,YAAA,GAAe,CAAA;AACnB,IAAA,IAAA,CAAK,OAAO,gBAAA,CAA8B,oBAAoB,CAAA,CAAE,OAAA,CAAQ,CAAC,GAAA,KAAQ;AAC/E,MAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,IAAK,GAAA,CAAI,YAAa,WAAA,EAAY,CAAE,SAAS,CAAC,CAAA;AAC7D,MAAA,GAAA,CAAI,SAAA,CAAU,MAAA,CAAO,QAAA,EAAU,CAAC,KAAK,CAAA;AACrC,MAAA,IAAI,KAAA,EAAO,YAAA,EAAA;AAAA,IACb,CAAC,CAAA;AACD,IAAA,IAAI,OAAA,GAAU,IAAA,CAAK,MAAA,CAAO,aAAA,CAA2B,mBAAmB,CAAA;AACxE,IAAA,IAAI,iBAAiB,CAAA,EAAG;AACtB,MAAA,IAAI,CAAC,OAAA,EAAS;AACZ,QAAA,OAAA,GAAU,QAAA,CAAS,cAAc,KAAK,CAAA;AACtC,QAAA,OAAA,CAAQ,SAAA,GAAY,kBAAA;AACpB,QAAA,OAAA,CAAQ,WAAA,GAAc,EAAE,OAAA,EAAQ;AAChC,QAAA,IAAA,CAAK,MAAA,CAAO,YAAY,OAAO,CAAA;AAAA,MACjC;AAAA,IACF,CAAA,MAAO;AACL,MAAA,OAAA,EAAS,MAAA,EAAO;AAAA,IAClB;AAAA,EACF;AAAA;AAAA,EAGA,UAAA,CAAW,SAAkD,WAAA,EAA2B;AACtF,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,OAAO,SAAA,GAAY,EAAA;AACxB,IAAA,IAAA,CAAK,MAAM,WAAA,GAAc,WAAA;AACzB,IAAA,IAAA,CAAK,MAAM,SAAA,GAAY,4BAAA;AACvB,IAAA,IAAA,CAAK,QAAA,GAAW,EAAA;AAEhB,IAAA,OAAA,CAAQ,OAAA,CAAQ,CAAC,EAAE,KAAA,EAAO,OAAM,KAAM;AACpC,MAAA,MAAM,GAAA,GAAM,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACxC,MAAA,GAAA,CAAI,SAAA,GAAY,mBAAA;AAChB,MAAA,GAAA,CAAI,OAAA,CAAQ,OAAO,CAAA,GAAI,KAAA;AACvB,MAAA,GAAA,CAAI,WAAA,GAAc,KAAA;AAClB,MAAA,GAAA,CAAI,YAAA,CAAa,SAAS,KAAK,CAAA;AAC/B,MAAA,GAAA,CAAI,gBAAA,CAAiB,OAAA,EAAS,CAAC,CAAA,KAAM;AACnC,QAAA,CAAA,CAAE,eAAA,EAAgB;AAClB,QAAA,IAAA,CAAK,MAAA,CAAO,OAAO,KAAK,CAAA;AACxB,QAAA,IAAA,CAAK,EAAA,CAAG,SAAA,CAAU,MAAA,CAAO,MAAM,CAAA;AAAA,MACjC,CAAC,CAAA;AACD,MAAA,IAAA,CAAK,MAAA,CAAO,YAAY,GAAG,CAAA;AAAA,IAC7B,CAAC,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,SAAS,KAAA,EAAqB;AAC5B,IAAA,MAAM,GAAA,GAAM,KAAK,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,KAAK,CAAA;AACtD,IAAA,IAAI,KAAK,IAAA,CAAK,MAAA,CAAO,IAAI,KAAA,EAAO,GAAA,CAAI,OAAO,KAAK,CAAA;AAAA,EAClD;AAAA,EAEQ,MAAA,CAAO,KAAA,EAAe,KAAA,EAAe,IAAA,GAAO,IAAA,EAAY;AAC9D,IAAA,IAAA,CAAK,QAAA,GAAW,KAAA;AAChB,IAAA,IAAA,CAAK,MAAM,WAAA,GAAc,KAAA;AACzB,IAAA,IAAA,CAAK,MAAM,SAAA,GAAY,gBAAA;AACvB,IAAA,IAAA,CAAK,OAAO,gBAAA,CAAiB,oBAAoB,CAAA,CAAE,OAAA,CAAQ,CAAC,EAAA,KAAO;AACjE,MAAA,EAAA,CAAG,UAAU,MAAA,CAAO,QAAA,EAAW,GAAmB,OAAA,CAAQ,OAAO,MAAM,KAAK,CAAA;AAAA,IAC9E,CAAC,CAAA;AACD,IAAA,IAAI,IAAA,EAAM,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA;AAAA,EAC/B;AAAA,EAEA,QAAA,GAAmB;AAAE,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EAAS;AAAA,EAC1C,UAAA,GAA0B;AAAE,IAAA,OAAO,IAAA,CAAK,EAAA;AAAA,EAAG;AAC7C,CAAA;AAqBO,IAAM,QAAA,GAAN,MAAM,SAAA,CAAS;AAAA,EAgBZ,YAAY,OAAA,EAAoC;AAbxD,IAAA,IAAA,CAAQ,UAAwB,EAAC;AACjC,IAAA,IAAA,CAAQ,gBAAwC,EAAC;AAa/C,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,QAAA,GAAW,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,QAAQ,IAAI,OAAA,CAAQ,QAAA,GAAW,CAAC,OAAA,CAAQ,QAAQ,CAAA;AAAA,EACxF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuCA,aAAa,KAAK,OAAA,EAA6C;AAC7D,IAAA,MAAM,QAAA,GAAW,IAAI,SAAA,CAAS,EAAE,SAAS,GAAA,EAAO,GAAG,SAAS,CAAA;AAC5D,IAAA,QAAA,CAAS,WAAA,EAAY;AACrB,IAAA,QAAA,CAAS,QAAA,EAAS;AAClB,IAAA,MAAM,SAAS,YAAA,EAAa;AAC5B,IAAA,OAAO,QAAA;AAAA,EACT;AAAA;AAAA,EAGQ,WAAA,GAAoB;AAC1B,IAAA,IAAI,QAAA,CAAS,cAAA,CAAe,6BAA6B,CAAA,EAAG;AAC5D,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AAC5C,IAAA,KAAA,CAAM,EAAA,GAAK,6BAAA;AACX,IAAA,KAAA,CAAM,WAAA,GAAc,WAAA;AACpB,IAAA,QAAA,CAAS,IAAA,CAAK,YAAY,KAAK,CAAA;AAAA,EACjC;AAAA;AAAA,EAGQ,QAAA,GAAiB;AACvB,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACzC,IAAA,IAAA,CAAK,EAAA,GAAK,uBAAA;AAGV,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC1C,IAAA,KAAA,CAAM,SAAA,GAAY,WAAA;AAClB,IAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AAGf,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC3C,IAAA,MAAA,CAAO,SAAA,GAAY,YAAA;AACnB,IAAA,MAAM,UAAA,GAAa,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC/C,IAAA,UAAA,CAAW,SAAA,GAAY,iBAAA;AACvB,IAAA,IAAA,CAAK,SAAA,GAAY,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AAC9C,IAAA,IAAA,CAAK,UAAU,SAAA,GAAY,wBAAA;AAC3B,IAAA,MAAM,WAAA,GAAc,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AACjD,IAAA,WAAA,CAAY,SAAA,GAAY,kBAAA;AACxB,IAAA,WAAA,CAAY,WAAA,GAAc,oBAAA;AAC1B,IAAA,UAAA,CAAW,WAAA,CAAY,KAAK,SAAS,CAAA;AACrC,IAAA,UAAA,CAAW,YAAY,WAAW,CAAA;AAClC,IAAA,MAAA,CAAO,YAAY,UAAU,CAAA;AAC7B,IAAA,KAAA,CAAM,YAAY,MAAM,CAAA;AAGxB,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACzC,IAAA,IAAA,CAAK,SAAA,GAAY,UAAA;AAGjB,IAAA,IAAA,CAAK,SAAA,GAAY,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AAC9C,IAAA,IAAA,CAAK,UAAU,SAAA,GAAY,iBAAA;AAC3B,IAAA,IAAA,CAAK,QAAA,GAAW,IAAI,YAAA,CAAa,CAAC,QAAQ,IAAA,CAAK,eAAA,CAAgB,GAAG,CAAC,CAAA;AACnE,IAAA,IAAA,CAAK,SAAS,UAAA,CAAW,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,KAAA,EAAO,CAAA,EAAG,OAAO,CAAA,EAAE,CAAE,CAAA,EAAG,CAAA,CAAE,eAAe,CAAA;AAC9F,IAAA,IAAA,CAAK,WAAA,CAAY,IAAA,CAAK,qBAAA,CAAsB,CAAA,CAAE,OAAA,EAAQ,EAAG,IAAA,CAAK,SAAA,EAAW,IAAA,CAAK,QAAA,CAAS,UAAA,EAAY,CAAC,CAAA;AAGpG,IAAA,IAAA,CAAK,UAAA,GAAa,IAAI,YAAA,CAAa,CAAC,QAAQ,IAAA,CAAK,YAAA,CAAa,GAAG,CAAC,CAAA;AAClE,IAAA,IAAA,CAAK,WAAA,CAAY,IAAA,CAAK,WAAA,CAAY,CAAA,CAAE,GAAA,IAAO,IAAA,CAAK,UAAA,CAAW,UAAA,EAAY,CAAC,CAAA;AAGxE,IAAA,IAAA,CAAK,YAAA,GAAe,IAAI,YAAA,CAAa,CAAC,QAAQ,IAAA,CAAK,cAAA,CAAe,GAAG,CAAC,CAAA;AACtE,IAAA,IAAA,CAAK,WAAA,CAAY,IAAA,CAAK,WAAA,CAAY,CAAA,CAAE,MAAA,IAAU,IAAA,CAAK,YAAA,CAAa,UAAA,EAAY,CAAC,CAAA;AAG7E,IAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC5C,IAAA,OAAA,CAAQ,SAAA,GAAY,cAAA;AAEpB,IAAA,MAAM,SAAA,GAAY,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC9C,IAAA,SAAA,CAAU,SAAA,GAAY,gBAAA;AACtB,IAAA,MAAM,aAAA,GAAgB,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AACnD,IAAA,aAAA,CAAc,SAAA,GAAY,wBAAA;AAC1B,IAAA,aAAA,CAAc,WAAA,GAAc,QAAA;AAC5B,IAAA,IAAA,CAAK,cAAA,GAAiB,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AACpD,IAAA,IAAA,CAAK,eAAe,IAAA,GAAO,MAAA;AAC3B,IAAA,IAAA,CAAK,cAAA,CAAe,WAAA,GAAc,CAAA,CAAE,SAAA,EAAU;AAC9C,IAAA,IAAA,CAAK,cAAA,CAAe,iBAAiB,OAAA,EAAS,MAAM,KAAK,SAAA,CAAU,IAAA,CAAK,cAAA,CAAe,KAAK,CAAC,CAAA;AAC7F,IAAA,SAAA,CAAU,YAAY,aAAa,CAAA;AACnC,IAAA,SAAA,CAAU,WAAA,CAAY,KAAK,cAAc,CAAA;AAEzC,IAAA,IAAA,CAAK,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC3C,IAAA,IAAA,CAAK,QAAQ,SAAA,GAAY,cAAA;AAEzB,IAAA,OAAA,CAAQ,YAAY,SAAS,CAAA;AAC7B,IAAA,OAAA,CAAQ,WAAA,CAAY,KAAK,OAAO,CAAA;AAGhC,IAAA,IAAA,CAAK,UAAA,GAAa,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AACjD,IAAA,IAAA,CAAK,WAAW,SAAA,GAAY,cAAA;AAC5B,IAAA,IAAA,CAAK,UAAA,CAAW,WAAA,GAAc,CAAA,CAAE,OAAA,EAAQ;AACxC,IAAA,IAAA,CAAK,WAAW,YAAA,CAAa,OAAA,EAAS,SAAA,EAAU,GAC5C,+HACA,sDAAsD,CAAA;AAC1D,IAAA,IAAA,CAAK,UAAA,CAAW,gBAAA,CAAiB,OAAA,EAAS,CAAC,CAAA,KAAM;AAC/C,MAAA,CAAA,CAAE,eAAA,EAAgB;AAClB,MAAA,IAAA,CAAK,UAAA,EAAW;AAAA,IAClB,CAAC,CAAA;AAED,IAAA,MAAM,QAAA,GAAW,KAAK,qBAAA,CAAsB,CAAA,CAAE,UAAS,EAAG,IAAA,CAAK,YAAY,OAAO,CAAA;AAClF,IAAA,QAAA,CAAS,SAAA,CAAU,IAAI,eAAe,CAAA;AACtC,IAAA,IAAA,CAAK,YAAY,QAAQ,CAAA;AAEzB,IAAA,KAAA,CAAM,YAAY,IAAI,CAAA;AAGtB,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC3C,IAAA,MAAA,CAAO,SAAA,GAAY,YAAA;AACnB,IAAA,IAAA,CAAK,QAAA,GAAW,MAAA;AAChB,IAAA,KAAA,CAAM,YAAY,MAAM,CAAA;AAGxB,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC9C,IAAA,MAAA,CAAO,SAAA,GAAY,YAAA;AACnB,IAAA,MAAA,CAAO,WAAA,GAAc,WAAA;AACrB,IAAA,MAAA,CAAO,YAAA,CAAa,SAAS,gBAAgB,CAAA;AAC7C,IAAA,MAAA,CAAO,gBAAA,CAAiB,OAAA,EAAS,CAAC,CAAA,KAAM;AACtC,MAAA,CAAA,CAAE,eAAA,EAAgB;AAClB,MAAA,KAAA,CAAM,SAAA,CAAU,OAAO,MAAM,CAAA;AAAA,IAC/B,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,YAAY,KAAK,CAAA;AACtB,IAAA,IAAA,CAAK,YAAY,MAAM,CAAA;AACvB,IAAA,QAAA,CAAS,IAAA,CAAK,YAAY,IAAI,CAAA;AAAA,EAChC;AAAA;AAAA,EAGQ,WAAA,CAAY,OAAe,OAAA,EAAmC;AACpE,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC1C,IAAA,KAAA,CAAM,SAAA,GAAY,WAAA;AAClB,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACxC,IAAA,GAAA,CAAI,SAAA,GAAY,WAAA;AAChB,IAAA,GAAA,CAAI,WAAA,GAAc,KAAA;AAClB,IAAA,KAAA,CAAM,YAAY,GAAG,CAAA;AACrB,IAAA,KAAA,CAAM,YAAY,OAAO,CAAA;AACzB,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA,EAGQ,qBAAA,CAAsB,KAAA,EAAe,MAAA,EAAqB,OAAA,EAAmC;AACnG,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC1C,IAAA,KAAA,CAAM,SAAA,GAAY,WAAA;AAClB,IAAA,MAAM,WAAA,GAAc,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAChD,IAAA,WAAA,CAAY,SAAA,GAAY,kBAAA;AACxB,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACxC,IAAA,GAAA,CAAI,SAAA,GAAY,WAAA;AAChB,IAAA,GAAA,CAAI,WAAA,GAAc,KAAA;AAClB,IAAA,WAAA,CAAY,YAAY,GAAG,CAAA;AAC3B,IAAA,WAAA,CAAY,YAAY,MAAM,CAAA;AAC9B,IAAA,KAAA,CAAM,YAAY,WAAW,CAAA;AAC7B,IAAA,KAAA,CAAM,YAAY,OAAO,CAAA;AACzB,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA,EAGA,MAAc,YAAA,GAA8B;AAC1C,IAAA,MAAM,OAAA,GAAU,YAAA,CAAa,OAAA,CAAQ,WAAW,CAAA;AAChD,IAAA,MAAM,EAAA,GAAM,OAAA,IAAW,IAAA,CAAK,QAAA,CAAS,QAAA,CAAS,OAAO,CAAA,GAAK,OAAA,GAAU,IAAA,CAAK,QAAA,CAAS,CAAC,CAAA;AACnF,IAAA,IAAA,CAAK,QAAA,CAAS,SAAS,EAAE,CAAA;AACzB,IAAA,MAAM,IAAA,CAAK,YAAY,EAAE,CAAA;AAEzB,IAAA,MAAM,SAAA,GAAY,YAAA,CAAa,OAAA,CAAQ,QAAQ,CAAA;AAC/C,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,IAAA,CAAK,UAAA,CAAW,SAAS,SAAS,CAAA;AAClC,MAAA,IAAA,CAAK,oBAAoB,SAAS,CAAA;AAAA,IACpC;AAEA,IAAA,MAAM,WAAA,GAAc,YAAA,CAAa,OAAA,CAAQ,UAAU,CAAA;AACnD,IAAA,IAAI,WAAA,IAAe,KAAK,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,GAAA,KAAQ,WAAW,CAAA,EAAG;AAClE,MAAA,IAAA,CAAK,YAAA,CAAa,SAAS,WAAW,CAAA;AACtC,MAAA,MAAM,IAAA,CAAK,YAAY,WAAW,CAAA;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,MAAc,gBAAgB,EAAA,EAA2B;AACvD,IAAA,YAAA,CAAa,OAAA,CAAQ,aAAa,EAAE,CAAA;AACpC,IAAA,IAAA,CAAK,UAAU,WAAA,GAAc,EAAA;AAC7B,IAAA,MAAM,IAAA,CAAK,YAAY,EAAE,CAAA;AAAA,EAC3B;AAAA,EAEQ,aAAa,IAAA,EAAoB;AACvC,IAAA,YAAA,CAAa,OAAA,CAAQ,UAAU,IAAI,CAAA;AACnC,IAAA,IAAA,CAAK,oBAAoB,IAAI,CAAA;AAAA,EAC/B;AAAA,EAEA,MAAc,eAAe,GAAA,EAA4B;AACvD,IAAA,YAAA,CAAa,OAAA,CAAQ,YAAY,GAAG,CAAA;AACpC,IAAA,MAAM,IAAA,CAAK,YAAY,GAAG,CAAA;AAAA,EAC5B;AAAA;AAAA,EAGA,MAAc,YAAY,KAAA,EAA8B;AACtD,IAAA,IAAA,CAAK,UAAU,SAAS,CAAA;AACxB,IAAA,IAAA,CAAK,SAAA,CAAU,CAAA,CAAE,OAAA,EAAQ,EAAG,EAAE,CAAA;AAC9B,IAAA,MAAM,MAAA,GAAS,MAAMA,qBAAA,CAAkB,CAAA,EAAG,KAAK,CAAA,oBAAA,CAAA,EAAwB;AAAA,MACrE,KAAA,EAAO,IAAA;AAAA,MACP,OAAA,EAAS,KAAK,OAAA,CAAQ;AAAA,KACvB,CAAA;AAED,IAAA,IAAI,OAAO,KAAA,EAAO;AAChB,MAAA,IAAA,CAAK,UAAU,KAAK,CAAA;AACpB,MAAA,IAAA,CAAK,UAAU,CAAA,CAAE,UAAA,CAAW,OAAO,KAAA,CAAM,OAAO,GAAG,KAAK,CAAA;AACxD,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA,CAAO,IAAA,IAAQ,EAAC;AAC/B,IAAA,IAAA,CAAK,iBAAA,EAAkB;AACvB,IAAA,IAAA,CAAK,UAAU,IAAI,CAAA;AACnB,IAAA,IAAA,CAAK,UAAU,CAAA,CAAE,MAAA,CAAO,KAAK,OAAA,CAAQ,MAAM,GAAG,IAAI,CAAA;AAAA,EACpD;AAAA;AAAA,EAGQ,iBAAA,GAA0B;AAChC,IAAA,MAAM,QAAQ,CAAC,GAAG,IAAI,GAAA,CAAI,KAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,IAAI,CAAA,CAAE,MAAA,CAAO,OAAO,CAAC,CAAC,CAAA;AAC1E,IAAA,MAAM,IAAA,GAAO,CAAC,EAAE,KAAA,EAAO,IAAI,KAAA,EAAO,CAAA,CAAE,SAAQ,EAAE,EAAG,GAAG,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,OAAO,CAAA,EAAG,KAAA,EAAO,CAAA,EAAE,CAAE,CAAC,CAAA;AAC9F,IAAA,IAAA,CAAK,UAAA,CAAW,UAAA,CAAW,IAAA,EAAM,CAAA,CAAE,SAAS,CAAA;AAC5C,IAAA,IAAA,CAAK,UAAA,CAAW,SAAS,EAAE,CAAA;AAC3B,IAAA,IAAA,CAAK,oBAAoB,EAAE,CAAA;AAAA,EAC7B;AAAA;AAAA,EAGQ,oBAAoB,IAAA,EAAoB;AAC9C,IAAA,MAAM,QAAA,GAAW,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,IAAI,CAAA,GAAI,IAAA,CAAK,OAAA;AAC3E,IAAA,IAAA,CAAK,YAAA,CAAa,UAAA;AAAA,MAChB,SAAS,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,OAAO,CAAA,CAAE,GAAA,EAAK,KAAA,EAAO,CAAA,EAAG,EAAE,IAAI,CAAA,GAAA,EAAM,CAAA,CAAE,GAAG,KAAI,CAAE,CAAA;AAAA,MACtE,EAAE,YAAA;AAAa,KACjB;AACA,IAAA,IAAA,CAAK,aAAA,CAAc,EAAE,CAAA;AAAA,EACvB;AAAA;AAAA,EAGA,MAAc,YAAY,GAAA,EAA4B;AACpD,IAAA,IAAI,CAAC,GAAA,EAAK;AAAE,MAAA,IAAA,CAAK,aAAA,CAAc,EAAE,CAAA;AAAG,MAAA;AAAA,IAAO;AAC3C,IAAA,MAAM,MAAA,GAAS,KAAK,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,QAAQ,GAAG,CAAA;AACrD,IAAA,IAAI,CAAC,MAAA,EAAQ;AAEb,IAAA,IAAA,CAAK,SAAA,CAAU,CAAA,CAAE,SAAA,EAAU,EAAG,EAAE,CAAA;AAChC,IAAA,IAAI;AACF,MAAA,MAAMC,0BAAQ,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,IAAA,CAAK,QAAQ,OAAO,CAAA;AACtD,MAAA,MAAM,MAAM,MAAM,KAAA,CAAM,CAAA,EAAG,MAAA,CAAO,MAAM,CAAA,YAAA,CAAc,CAAA;AACtD,MAAA,MAAM,MAA+B,GAAA,CAAI,EAAA,GAAK,MAAM,GAAA,CAAI,IAAA,KAAS,EAAC;AAClE,MAAA,MAAM,SAAiC,EAAC;AACxC,MAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AACxC,QAAA,IAAI,MAAM,OAAA,IAAW,OAAO,MAAM,QAAA,EAAU,MAAA,CAAO,CAAC,CAAA,GAAI,CAAA;AAAA,MAC1D;AACA,MAAA,MAAM,OAAOA,yBAAA,CAAQ,IAAA;AACrB,MAAA,IAAI,MAAM,IAAA,CAAK,SAAA,CAAU,WAAA,GAAc,CAAA,CAAA,EAAI,KAAK,OAAO,CAAA,CAAA;AACvD,MAAA,IAAA,CAAK,cAAc,MAAM,CAAA;AACzB,MAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,MAAA;AAClC,MAAA,IAAA,CAAK,UAAU,CAAA,CAAE,MAAA,CAAO,OAAO,IAAA,EAAM,KAAK,GAAG,IAAI,CAAA;AAAA,IACnD,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,MAAM,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAC3D,MAAA,IAAA,CAAK,SAAA,CAAU,CAAA,CAAE,YAAA,CAAa,GAAG,GAAG,KAAK,CAAA;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA,EAGQ,cAAc,MAAA,EAAsC;AAC1D,IAAA,IAAA,CAAK,aAAA,GAAgB,MAAA;AACrB,IAAA,IAAA,CAAK,QAAQ,SAAA,GAAY,EAAA;AACzB,IAAA,IAAA,CAAK,eAAe,KAAA,GAAQ,EAAA;AAC5B,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA;AACrC,IAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,MAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC1C,MAAA,KAAA,CAAM,SAAA,GAAY,eAAA;AAClB,MAAA,KAAA,CAAM,WAAA,GAAc,EAAE,WAAA,EAAY;AAClC,MAAA,IAAA,CAAK,OAAA,CAAQ,YAAY,KAAK,CAAA;AAC9B,MAAA;AAAA,IACF;AACA,IAAA,OAAA,CAAQ,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM;AAC1B,MAAA,MAAM,IAAA,GAAO,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACzC,MAAA,IAAA,CAAK,SAAA,GAAY,cAAA;AACjB,MAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAA,GAAI,CAAA;AAEtB,MAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AAC7C,MAAA,OAAA,CAAQ,SAAA,GAAY,aAAA;AACpB,MAAA,OAAA,CAAQ,WAAA,GAAc,CAAA;AACtB,MAAA,OAAA,CAAQ,YAAA,CAAa,SAAS,CAAC,CAAA;AAE/B,MAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AAC7C,MAAA,OAAA,CAAQ,SAAA,GAAY,aAAA;AACpB,MAAA,OAAA,CAAQ,WAAA,GAAc,CAAA;AACtB,MAAA,OAAA,CAAQ,aAAa,OAAA,EAAS,CAAA,EAAG,CAAC,CAAA,UAAA,EAAQ,CAAC,CAAA,CAAE,CAAA;AAE7C,MAAA,MAAM,QAAA,GAAW,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AAC9C,MAAA,QAAA,CAAS,SAAA,GAAY,cAAA;AACrB,MAAA,QAAA,CAAS,WAAA,GAAc,QAAA;AAEvB,MAAA,IAAA,CAAK,YAAY,OAAO,CAAA;AACxB,MAAA,IAAA,CAAK,YAAY,OAAO,CAAA;AACxB,MAAA,IAAA,CAAK,YAAY,QAAQ,CAAA;AACzB,MAAA,IAAA,CAAK,iBAAiB,OAAA,EAAS,MAAM,KAAK,WAAA,CAAY,IAAA,EAAM,CAAC,CAAC,CAAA;AAC9D,MAAA,IAAA,CAAK,OAAA,CAAQ,YAAY,IAAI,CAAA;AAAA,IAC/B,CAAC,CAAA;AAAA,EACH;AAAA;AAAA,EAGQ,UAAU,KAAA,EAAqB;AACrC,IAAA,MAAM,CAAA,GAAI,MAAM,WAAA,EAAY;AAC5B,IAAA,IAAA,CAAK,QAAQ,gBAAA,CAA8B,eAAe,CAAA,CAAE,OAAA,CAAQ,CAAC,IAAA,KAAS;AAC5E,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAA,IAAK,EAAA;AACnC,MAAA,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,QAAA,EAAU,CAAC,CAAC,CAAA,IAAK,CAAC,GAAA,CAAI,WAAA,EAAY,CAAE,QAAA,CAAS,CAAC,CAAC,CAAA;AAAA,IACvE,CAAC,CAAA;AAAA,EACH;AAAA;AAAA,EAGQ,WAAA,CAAY,MAAmB,IAAA,EAAoB;AACzD,IAAA,SAAA,CAAU,SAAA,CAAU,SAAA,CAAU,IAAI,CAAA,CAAE,KAAK,MAAM;AAC7C,MAAA,IAAA,CAAK,SAAA,CAAU,IAAI,QAAQ,CAAA;AAC3B,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,aAAA,CAAc,eAAe,CAAA;AAC/C,MAAA,IAAI,IAAA,OAAW,WAAA,GAAc,QAAA;AAC7B,MAAA,UAAA,CAAW,MAAM;AACf,QAAA,IAAA,CAAK,SAAA,CAAU,OAAO,QAAQ,CAAA;AAC9B,QAAA,MAAM,EAAA,GAAK,IAAA,CAAK,aAAA,CAAc,eAAe,CAAA;AAC7C,QAAA,IAAI,EAAA,KAAO,WAAA,GAAc,QAAA;AAAA,MAC3B,GAAG,IAAI,CAAA;AACP,MAAA,IAAA,CAAK,SAAA,CAAU,CAAA,CAAE,MAAA,CAAO,IAAI,GAAG,IAAI,CAAA;AACnC,MAAA,UAAA,CAAW,MAAM,IAAA,CAAK,SAAA,CAAU,EAAA,EAAI,EAAE,GAAG,GAAI,CAAA;AAAA,IAC/C,CAAC,CAAA;AAAA,EACH;AAAA;AAAA,EAGQ,UAAA,GAAmB;AACzB,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,aAAa,CAAA;AAC9C,IAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AAC1B,IAAA,MAAM,OAAO,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,aAAA,EAAe,MAAM,CAAC,CAAA;AACvD,IAAA,SAAA,CAAU,SAAA,CAAU,SAAA,CAAU,IAAI,CAAA,CAAE,KAAK,MAAM;AAC7C,MAAA,IAAA,CAAK,UAAA,CAAW,WAAA,GAAc,SAAA,GAAO,CAAA,CAAE,WAAA,EAAY;AACnD,MAAA,IAAA,CAAK,UAAA,CAAW,SAAA,CAAU,GAAA,CAAI,MAAM,CAAA;AACpC,MAAA,UAAA,CAAW,MAAM;AACf,QAAA,IAAA,CAAK,UAAA,CAAW,WAAA,GAAc,CAAA,CAAE,OAAA,EAAQ;AACxC,QAAA,IAAA,CAAK,UAAA,CAAW,SAAA,CAAU,MAAA,CAAO,MAAM,CAAA;AAAA,MACzC,GAAG,GAAI,CAAA;AACP,MAAA,IAAA,CAAK,SAAA,CAAU,CAAA,CAAE,WAAA,EAAY,EAAG,IAAI,CAAA;AACpC,MAAA,UAAA,CAAW,MAAM,IAAA,CAAK,SAAA,CAAU,EAAA,EAAI,EAAE,GAAG,IAAI,CAAA;AAAA,IAC/C,CAAC,CAAA;AAAA,EACH;AAAA,EAEQ,UAAU,KAAA,EAAuC;AACvD,IAAA,IAAA,CAAK,SAAA,CAAU,YAAY,CAAA,cAAA,EAAiB,KAAA,KAAU,OAAO,CAAA,CAAA,EAAI,KAAK,KAAK,EAAE,CAAA,CAAA;AAAA,EAC/E;AAAA,EAEQ,SAAA,CAAU,KAAa,GAAA,EAA8B;AAC3D,IAAA,IAAA,CAAK,QAAA,CAAS,SAAA,GAAY,GAAA,GACtB,CAAA,oCAAA,EAAuC,GAAG,CAAA,CAAA,GAC1C,EAAA;AACJ,IAAA,IAAA,CAAK,SAAS,SAAA,GAAY,CAAA,UAAA,EAAa,MAAM,CAAA,CAAA,EAAI,GAAG,KAAK,EAAE,CAAA,CAAA;AAAA,EAC7D;AACF","file":"chunk-YOWLTZM5.cjs","sourcesContent":["import { Get } from '../http/client'\nimport { Context } from '../http/context'\nimport type { ServerItem } from '../http/types'\nimport type { DebuggerOptions } from './types'\n\n/** localStorage key 前缀 */\nconst STORAGE_PREFIX = '__snackkit_debugger__'\nconst KEY_GATEWAY = `${STORAGE_PREFIX}gateway`\nconst KEY_TYPE = `${STORAGE_PREFIX}type`\nconst KEY_SERVER = `${STORAGE_PREFIX}server`\n\n/** 是否为中文环境 */\nfunction isChinese(): boolean {\n return /^zh/i.test(navigator.language ?? '')\n}\n\n/** i18n 文案 */\nconst T = {\n gateway: () => isChinese() ? '网关' : 'Gateway',\n tag: () => isChinese() ? '标签' : 'Tag',\n server: () => isChinese() ? '服务' : 'Server',\n ctx: () => isChinese() ? '上下文' : 'Ctx',\n ctxLabel: () => isChinese() ? '上下文 — 点击行复制 key' : 'Ctx — click row to copy key',\n search: () => isChinese() ? '搜索...' : 'Search...',\n noMatch: () => isChinese() ? '无匹配项' : 'No results',\n allTags: () => isChinese() ? '全部标签' : 'All tags',\n selectGateway: () => isChinese() ? '选择网关' : 'Select gateway',\n selectServer: () => isChinese() ? '选择服务' : 'Select server',\n filterCtx: () => isChinese() ? '过滤路由...' : 'Filter routes...',\n selectFirst: () => isChinese() ? '← 请先选择服务' : '← Select a server first',\n loading: () => isChinese() ? '加载服务列表...' : 'Loading...',\n loadFailed: (m: string) => isChinese() ? `加载失败: ${m}` : `Failed: ${m}`,\n loaded: (n: number) => isChinese() ? `已加载 ${n} 个服务` : `${n} servers loaded`,\n switching: () => isChinese() ? '切换服务中...' : 'Switching...',\n switchFailed: (m: string) => isChinese() ? `切换失败: ${m}` : `Failed: ${m}`,\n routes: (name: string, n: number) => isChinese() ? `${name} · ${n} 条路由` : `${name} · ${n} routes`,\n copied: (k: string) => isChinese() ? `已复制: ${k}` : `Copied: ${k}`,\n copyAll: () => isChinese() ? '复制全部 JSON' : 'Copy all JSON',\n copyAllDone: () => isChinese() ? '已复制为 JSON' : 'Copied as JSON',\n}\n\n/** 面板内联样式 */\nconst PANEL_STYLE = `\n #__snackkit_debugger__ {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 99999;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif;\n font-size: 13px;\n color: #b8ccec;\n user-select: none;\n }\n\n /* ── 浮动按钮 ── */\n #__snackkit_debugger__ .dbg-toggle {\n width: 42px;\n height: 42px;\n border-radius: 50%;\n background: linear-gradient(135deg, #4f8ef7, #6d6ff5);\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 14px rgba(79,142,247,0.45);\n margin-left: auto;\n font-size: 20px;\n transition: transform 0.15s, box-shadow 0.15s;\n }\n #__snackkit_debugger__ .dbg-toggle:hover {\n transform: scale(1.08);\n box-shadow: 0 6px 20px rgba(79,142,247,0.55);\n }\n #__snackkit_debugger__ .dbg-toggle:active { transform: scale(0.94); }\n\n /* ── 面板主体 ── */\n #__snackkit_debugger__ .dbg-panel {\n background: #1e2638;\n border: 1px solid #2d3a55;\n border-radius: 12px;\n width: 440px;\n margin-bottom: 10px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.45), 0 0 0 1px rgba(255,255,255,0.05);\n overflow: visible;\n opacity: 0;\n transform: translateY(8px) scale(0.98);\n pointer-events: none;\n transition: opacity 0.18s ease, transform 0.18s ease;\n }\n #__snackkit_debugger__ .dbg-panel.open {\n opacity: 1;\n transform: translateY(0) scale(1);\n pointer-events: auto;\n }\n\n /* ── 面板 Header ── */\n #__snackkit_debugger__ .dbg-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 14px;\n background: #171e2e;\n border-bottom: 1px solid #2d3a55;\n border-radius: 12px 12px 0 0;\n }\n #__snackkit_debugger__ .dbg-header-left {\n display: flex;\n align-items: center;\n gap: 7px;\n }\n #__snackkit_debugger__ .dbg-header-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: #34d399;\n box-shadow: 0 0 6px rgba(52,211,153,0.6);\n }\n #__snackkit_debugger__ .dbg-header-dot.loading {\n background: #fbbf24;\n box-shadow: 0 0 6px rgba(251,191,36,0.6);\n animation: dbg-pulse 1s ease-in-out infinite;\n }\n #__snackkit_debugger__ .dbg-header-dot.err {\n background: #f87171;\n box-shadow: 0 0 6px rgba(248,113,113,0.6);\n }\n #__snackkit_debugger__ .dbg-header-title {\n font-size: 12px;\n font-weight: 600;\n color: #dce8fa;\n letter-spacing: 0.03em;\n }\n #__snackkit_debugger__ .dbg-header-meta {\n font-size: 11px;\n color: #4d6080;\n }\n\n /* ── 面板内容区 ── */\n #__snackkit_debugger__ .dbg-body {\n padding: 12px 14px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n height: 420px;\n overflow: visible;\n }\n\n /* ── 字段行 ── */\n #__snackkit_debugger__ .dbg-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n }\n #__snackkit_debugger__ .dbg-field-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n #__snackkit_debugger__ .dbg-label {\n font-size: 10px;\n font-weight: 600;\n color: #5e72a0;\n text-transform: uppercase;\n letter-spacing: 0.07em;\n }\n\n /* ── 一键复制全部 JSON 按钮 ── */\n #__snackkit_debugger__ .dbg-copy-all {\n display: flex;\n align-items: center;\n gap: 4px;\n background: transparent;\n border: 1px solid #2d3a55;\n border-radius: 4px;\n padding: 2px 7px;\n color: #5e72a0;\n font-size: 10px;\n font-family: inherit;\n cursor: pointer;\n transition: border-color 0.15s, color 0.15s, background 0.15s;\n }\n #__snackkit_debugger__ .dbg-copy-all:hover {\n border-color: #4f8ef7;\n color: #7aacfa;\n background: rgba(79,142,247,0.08);\n }\n #__snackkit_debugger__ .dbg-copy-all.done {\n border-color: #34d399;\n color: #34d399;\n }\n\n /* ── 自定义下拉 ── */\n #__snackkit_debugger__ .dbg-select {\n position: relative;\n }\n #__snackkit_debugger__ .dbg-select-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n background: #252f45;\n border: 1px solid #2d3a55;\n border-radius: 6px;\n padding: 6px 10px;\n cursor: pointer;\n transition: border-color 0.15s, background 0.15s;\n min-height: 32px;\n }\n #__snackkit_debugger__ .dbg-select-trigger:hover { border-color: #3d5070; background: #2d3a55; }\n #__snackkit_debugger__ .dbg-select.open .dbg-select-trigger {\n border-color: #4f8ef7;\n background: #2d3a55;\n }\n #__snackkit_debugger__ .dbg-select-val {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n color: #b8ccec;\n }\n #__snackkit_debugger__ .dbg-select-val.placeholder { color: #3d5070; }\n #__snackkit_debugger__ .dbg-select-arrow {\n color: #3d5070;\n font-size: 10px;\n flex-shrink: 0;\n transition: transform 0.15s, color 0.15s;\n }\n #__snackkit_debugger__ .dbg-select.open .dbg-select-arrow {\n transform: rotate(180deg);\n color: #4f8ef7;\n }\n #__snackkit_debugger__ .dbg-select-dropdown {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 0;\n right: 0;\n background: #1e2638;\n border: 1px solid #2d3a55;\n border-radius: 8px;\n box-shadow: 0 -8px 24px rgba(0,0,0,0.35);\n overflow: hidden;\n opacity: 0;\n transform: translateY(4px);\n pointer-events: none;\n transition: opacity 0.14s, transform 0.14s;\n z-index: 100000;\n }\n #__snackkit_debugger__ .dbg-select.open .dbg-select-dropdown {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n }\n #__snackkit_debugger__ .dbg-select-search {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 7px 10px;\n border-bottom: 1px solid #2d3a55;\n }\n #__snackkit_debugger__ .dbg-select-search-icon { color: #3d5070; font-size: 11px; flex-shrink: 0; }\n #__snackkit_debugger__ .dbg-select-search input {\n flex: 1;\n background: transparent;\n border: none;\n outline: none;\n color: #b8ccec;\n font-size: 12px;\n font-family: inherit;\n }\n #__snackkit_debugger__ .dbg-select-search input::placeholder { color: #3d5070; }\n #__snackkit_debugger__ .dbg-select-list {\n max-height: 160px;\n overflow-y: auto;\n }\n #__snackkit_debugger__ .dbg-select-list::-webkit-scrollbar { width: 3px; }\n #__snackkit_debugger__ .dbg-select-list::-webkit-scrollbar-track { background: transparent; }\n #__snackkit_debugger__ .dbg-select-list::-webkit-scrollbar-thumb { background: #2d3a55; border-radius: 2px; }\n #__snackkit_debugger__ .dbg-select-option {\n padding: 7px 10px;\n cursor: pointer;\n font-size: 12px;\n color: #8aa4c8;\n transition: background 0.1s, color 0.1s;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n #__snackkit_debugger__ .dbg-select-option:hover { background: #2d3a55; color: #dce8fa; }\n #__snackkit_debugger__ .dbg-select-option.active { color: #7aacfa; background: #1e3060; }\n #__snackkit_debugger__ .dbg-select-option.hidden { display: none; }\n #__snackkit_debugger__ .dbg-select-empty {\n padding: 12px 10px;\n font-size: 12px;\n color: #3d5070;\n text-align: center;\n }\n\n /* ── 路由列表 ── */\n #__snackkit_debugger__ .dbg-ctx-field {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n gap: 5px;\n }\n #__snackkit_debugger__ .dbg-ctx-wrap {\n flex: 1;\n min-height: 0;\n border: 1px solid #2d3a55;\n border-radius: 6px;\n overflow: hidden;\n background: #252f45;\n display: flex;\n flex-direction: column;\n }\n #__snackkit_debugger__ .dbg-ctx-search {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 10px;\n border-bottom: 1px solid #2d3a55;\n background: #1e2638;\n }\n #__snackkit_debugger__ .dbg-ctx-search input {\n flex: 1;\n background: transparent;\n border: none;\n outline: none;\n color: #b8ccec;\n font-size: 12px;\n font-family: inherit;\n }\n #__snackkit_debugger__ .dbg-ctx-search input::placeholder { color: #3d5070; }\n #__snackkit_debugger__ .dbg-ctx-list {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n }\n #__snackkit_debugger__ .dbg-ctx-list::-webkit-scrollbar { width: 3px; }\n #__snackkit_debugger__ .dbg-ctx-list::-webkit-scrollbar-track { background: transparent; }\n #__snackkit_debugger__ .dbg-ctx-list::-webkit-scrollbar-thumb { background: #2d3a55; border-radius: 2px; }\n #__snackkit_debugger__ .dbg-ctx-item {\n padding: 5px 10px;\n cursor: pointer;\n display: grid;\n grid-template-columns: minmax(80px, 148px) 1fr auto;\n gap: 8px;\n align-items: center;\n border-bottom: 1px solid #1e2638;\n transition: background 0.1s;\n }\n #__snackkit_debugger__ .dbg-ctx-item:last-child { border-bottom: none; }\n #__snackkit_debugger__ .dbg-ctx-item:hover { background: #2d3a55; }\n #__snackkit_debugger__ .dbg-ctx-item.hidden { display: none; }\n #__snackkit_debugger__ .dbg-ctx-key {\n font-size: 12px;\n color: #7aacfa;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n #__snackkit_debugger__ .dbg-ctx-val {\n font-size: 11px;\n color: #4d6080;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n transition: color 0.1s;\n }\n #__snackkit_debugger__ .dbg-ctx-item:hover .dbg-ctx-val { color: #7a90b0; }\n #__snackkit_debugger__ .dbg-ctx-copy {\n font-size: 11px;\n color: #3d5070;\n opacity: 0;\n flex-shrink: 0;\n transition: opacity 0.1s, color 0.1s;\n }\n #__snackkit_debugger__ .dbg-ctx-item:hover .dbg-ctx-copy { opacity: 1; color: #5e72a0; }\n #__snackkit_debugger__ .dbg-ctx-item.copied .dbg-ctx-copy { color: #34d399; opacity: 1; }\n #__snackkit_debugger__ .dbg-ctx-empty {\n padding: 16px 10px;\n font-size: 12px;\n color: #3d5070;\n text-align: center;\n }\n\n /* ── 底部状态栏 ── */\n #__snackkit_debugger__ .dbg-footer {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 7px 14px;\n background: #171e2e;\n border-top: 1px solid #2d3a55;\n border-radius: 0 0 12px 12px;\n font-size: 11px;\n color: #4d6080;\n min-height: 30px;\n }\n #__snackkit_debugger__ .dbg-footer.ok { color: #34d399; }\n #__snackkit_debugger__ .dbg-footer.err { color: #f87171; }\n #__snackkit_debugger__ .dbg-footer-dot {\n width: 4px;\n height: 4px;\n border-radius: 50%;\n background: currentColor;\n flex-shrink: 0;\n }\n\n @keyframes dbg-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.35; }\n }\n`\n\n/** 可搜索的自定义下拉组件 */\nclass SearchSelect {\n private el: HTMLElement\n private trigger: HTMLElement\n private valEl: HTMLElement\n private dropdown: HTMLElement\n private searchInput: HTMLInputElement\n private listEl: HTMLElement\n private options: Array<{ value: string; label: string }> = []\n private selected = ''\n private onChange: (value: string) => void\n\n constructor(onChange: (value: string) => void) {\n this.onChange = onChange\n this.el = document.createElement('div')\n this.el.className = 'dbg-select'\n\n // 触发器\n this.trigger = document.createElement('div')\n this.trigger.className = 'dbg-select-trigger'\n this.valEl = document.createElement('span')\n this.valEl.className = 'dbg-select-val placeholder'\n const arrow = document.createElement('span')\n arrow.className = 'dbg-select-arrow'\n arrow.textContent = '▾'\n this.trigger.appendChild(this.valEl)\n this.trigger.appendChild(arrow)\n\n // 下拉面板\n this.dropdown = document.createElement('div')\n this.dropdown.className = 'dbg-select-dropdown'\n\n // 搜索框\n const searchWrap = document.createElement('div')\n searchWrap.className = 'dbg-select-search'\n const searchIcon = document.createElement('span')\n searchIcon.className = 'dbg-select-search-icon'\n searchIcon.textContent = '⌕'\n this.searchInput = document.createElement('input')\n this.searchInput.type = 'text'\n this.searchInput.placeholder = T.search()\n searchWrap.appendChild(searchIcon)\n searchWrap.appendChild(this.searchInput)\n\n this.listEl = document.createElement('div')\n this.listEl.className = 'dbg-select-list'\n\n this.dropdown.appendChild(searchWrap)\n this.dropdown.appendChild(this.listEl)\n this.el.appendChild(this.trigger)\n this.el.appendChild(this.dropdown)\n\n this.bindEvents()\n }\n\n private bindEvents(): void {\n this.trigger.addEventListener('click', (e) => {\n e.stopPropagation()\n const isOpen = this.el.classList.contains('open')\n document.querySelectorAll('#__snackkit_debugger__ .dbg-select.open').forEach((el) => {\n if (el !== this.el) el.classList.remove('open')\n })\n this.el.classList.toggle('open', !isOpen)\n if (!isOpen) {\n this.searchInput.value = ''\n this.filterOptions('')\n setTimeout(() => this.searchInput.focus(), 50)\n }\n })\n\n this.searchInput.addEventListener('input', () => {\n this.filterOptions(this.searchInput.value)\n })\n\n this.searchInput.addEventListener('click', (e) => e.stopPropagation())\n\n document.addEventListener('click', () => {\n this.el.classList.remove('open')\n })\n }\n\n private filterOptions(query: string): void {\n const q = query.toLowerCase()\n let visibleCount = 0\n this.listEl.querySelectorAll<HTMLElement>('.dbg-select-option').forEach((opt) => {\n const match = !q || opt.textContent!.toLowerCase().includes(q)\n opt.classList.toggle('hidden', !match)\n if (match) visibleCount++\n })\n let emptyEl = this.listEl.querySelector<HTMLElement>('.dbg-select-empty')\n if (visibleCount === 0) {\n if (!emptyEl) {\n emptyEl = document.createElement('div')\n emptyEl.className = 'dbg-select-empty'\n emptyEl.textContent = T.noMatch()\n this.listEl.appendChild(emptyEl)\n }\n } else {\n emptyEl?.remove()\n }\n }\n\n /** 更新选项列表 */\n setOptions(options: Array<{ value: string; label: string }>, placeholder: string): void {\n this.options = options\n this.listEl.innerHTML = ''\n this.valEl.textContent = placeholder\n this.valEl.className = 'dbg-select-val placeholder'\n this.selected = ''\n\n options.forEach(({ value, label }) => {\n const opt = document.createElement('div')\n opt.className = 'dbg-select-option'\n opt.dataset['value'] = value\n opt.textContent = label\n opt.setAttribute('title', label)\n opt.addEventListener('click', (e) => {\n e.stopPropagation()\n this.select(value, label)\n this.el.classList.remove('open')\n })\n this.listEl.appendChild(opt)\n })\n }\n\n /** 选中某个值(不触发 onChange) */\n setValue(value: string): void {\n const opt = this.options.find((o) => o.value === value)\n if (opt) this.select(opt.value, opt.label, false)\n }\n\n private select(value: string, label: string, emit = true): void {\n this.selected = value\n this.valEl.textContent = label\n this.valEl.className = 'dbg-select-val'\n this.listEl.querySelectorAll('.dbg-select-option').forEach((el) => {\n el.classList.toggle('active', (el as HTMLElement).dataset['value'] === value)\n })\n if (emit) this.onChange(value)\n }\n\n getValue(): string { return this.selected }\n getElement(): HTMLElement { return this.el }\n}\n\n/**\n * 浏览器端浮动调试面板\n *\n * 允许开发者在运行时:\n * - 选择调试网关 → 拉取服务清单\n * - 切换目标服务 → 重新加载 Context 路由映射\n * - 查看并复制可用的路由 ctx 列表\n *\n * 与 http 模块集成:使用 `Get()` 拉取服务清单,使用 `context.load()` 切换请求目标。\n *\n * @see [交互式 Demo](../demo/debugger.html)\n *\n * @example\n * ```ts\n * import { Debugger } from '@snack-kit/lib/debugger'\n *\n * await Debugger.init({ gateways: 'http://dev-gateway.example.com' })\n * ```\n */\nexport class Debugger {\n private options: Required<DebuggerOptions>\n private gateways: string[]\n private servers: ServerItem[] = []\n private currentCtxMap: Record<string, string> = {}\n private panelEl!: HTMLElement\n private headerDot!: HTMLElement\n private gwVersion!: HTMLElement\n private footerEl!: HTMLElement\n private copyAllBtn!: HTMLButtonElement\n private gwSelect!: SearchSelect\n private typeSelect!: SearchSelect\n private serverSelect!: SearchSelect\n private ctxList!: HTMLElement\n private ctxSearchInput!: HTMLInputElement\n\n private constructor(options: Required<DebuggerOptions>) {\n this.options = options\n this.gateways = Array.isArray(options.gateways) ? options.gateways : [options.gateways]\n }\n\n /**\n * 初始化并渲染调试面板\n *\n * 调用后在页面右下角插入浮动按钮,点击展开调试面板。\n * 面板支持:选择调试网关、切换目标服务、查看并复制路由 ctx。\n * 网关/服务选择通过 `localStorage` 持久化,刷新后自动恢复。\n *\n * @param options 配置项\n *\n * @example 单网关\n * ```ts\n * import { Debugger } from '@snack-kit/lib/debugger'\n *\n * await Debugger.init({\n * gateways: 'http://dev-gateway.example.com',\n * })\n * ```\n *\n * @example 多网关(开发/测试环境切换)\n * ```ts\n * await Debugger.init({\n * gateways: [\n * 'http://dev-gateway.example.com',\n * 'http://test-gateway.example.com',\n * ],\n * timeout: 5000,\n * })\n * ```\n *\n * @example 仅在非生产环境加载\n * ```ts\n * if (import.meta.env.DEV) {\n * const { Debugger } = await import('@snack-kit/lib/debugger')\n * await Debugger.init({ gateways: 'http://dev-gateway.example.com' })\n * }\n * ```\n */\n static async init(options: DebuggerOptions): Promise<Debugger> {\n const instance = new Debugger({ timeout: 10000, ...options })\n instance.injectStyle()\n instance.buildDOM()\n await instance.restoreState()\n return instance\n }\n\n /** 注入内联样式 */\n private injectStyle(): void {\n if (document.getElementById('__snackkit_debugger_style__')) return\n const style = document.createElement('style')\n style.id = '__snackkit_debugger_style__'\n style.textContent = PANEL_STYLE\n document.head.appendChild(style)\n }\n\n /** 构建 DOM 结构 */\n private buildDOM(): void {\n const root = document.createElement('div')\n root.id = '__snackkit_debugger__'\n\n // ── 面板 ──\n const panel = document.createElement('div')\n panel.className = 'dbg-panel'\n this.panelEl = panel\n\n // Header\n const header = document.createElement('div')\n header.className = 'dbg-header'\n const headerLeft = document.createElement('div')\n headerLeft.className = 'dbg-header-left'\n this.headerDot = document.createElement('span')\n this.headerDot.className = 'dbg-header-dot loading'\n const headerTitle = document.createElement('span')\n headerTitle.className = 'dbg-header-title'\n headerTitle.textContent = 'Snack Kit Debugger'\n headerLeft.appendChild(this.headerDot)\n headerLeft.appendChild(headerTitle)\n header.appendChild(headerLeft)\n panel.appendChild(header)\n\n // Body\n const body = document.createElement('div')\n body.className = 'dbg-body'\n\n // 网关选择(标签行右侧显示版本号)\n this.gwVersion = document.createElement('span')\n this.gwVersion.className = 'dbg-header-meta'\n this.gwSelect = new SearchSelect((val) => this.onGatewayChange(val))\n this.gwSelect.setOptions(this.gateways.map((g) => ({ value: g, label: g })), T.selectGateway())\n body.appendChild(this.createFieldWithAction(T.gateway(), this.gwVersion, this.gwSelect.getElement()))\n\n // 标签(类型)选择\n this.typeSelect = new SearchSelect((val) => this.onTypeChange(val))\n body.appendChild(this.createField(T.tag(), this.typeSelect.getElement()))\n\n // 服务选择\n this.serverSelect = new SearchSelect((val) => this.onServerChange(val))\n body.appendChild(this.createField(T.server(), this.serverSelect.getElement()))\n\n // 路由列表(含一键复制全部 JSON 按钮)\n const ctxWrap = document.createElement('div')\n ctxWrap.className = 'dbg-ctx-wrap'\n\n const ctxSearch = document.createElement('div')\n ctxSearch.className = 'dbg-ctx-search'\n const ctxSearchIcon = document.createElement('span')\n ctxSearchIcon.className = 'dbg-select-search-icon'\n ctxSearchIcon.textContent = '⌕'\n this.ctxSearchInput = document.createElement('input')\n this.ctxSearchInput.type = 'text'\n this.ctxSearchInput.placeholder = T.filterCtx()\n this.ctxSearchInput.addEventListener('input', () => this.filterCtx(this.ctxSearchInput.value))\n ctxSearch.appendChild(ctxSearchIcon)\n ctxSearch.appendChild(this.ctxSearchInput)\n\n this.ctxList = document.createElement('div')\n this.ctxList.className = 'dbg-ctx-list'\n\n ctxWrap.appendChild(ctxSearch)\n ctxWrap.appendChild(this.ctxList)\n\n // 一键复制全部 JSON 按钮\n this.copyAllBtn = document.createElement('button')\n this.copyAllBtn.className = 'dbg-copy-all'\n this.copyAllBtn.textContent = T.copyAll()\n this.copyAllBtn.setAttribute('title', isChinese()\n ? '将全部上下文复制为 JSON,可作为 Context.load({...}) 的参数'\n : 'Copy all ctx entries as JSON for Context.load({...})')\n this.copyAllBtn.addEventListener('click', (e) => {\n e.stopPropagation()\n this.copyAllCtx()\n })\n\n const ctxField = this.createFieldWithAction(T.ctxLabel(), this.copyAllBtn, ctxWrap)\n ctxField.classList.add('dbg-ctx-field')\n body.appendChild(ctxField)\n\n panel.appendChild(body)\n\n // Footer 状态栏\n const footer = document.createElement('div')\n footer.className = 'dbg-footer'\n this.footerEl = footer\n panel.appendChild(footer)\n\n // ── 浮动按钮 ──\n const toggle = document.createElement('button')\n toggle.className = 'dbg-toggle'\n toggle.textContent = '🐛'\n toggle.setAttribute('title', 'Snack Debugger')\n toggle.addEventListener('click', (e) => {\n e.stopPropagation()\n panel.classList.toggle('open')\n })\n\n root.appendChild(panel)\n root.appendChild(toggle)\n document.body.appendChild(root)\n }\n\n /** 创建普通字段行(label + content) */\n private createField(label: string, content: HTMLElement): HTMLElement {\n const field = document.createElement('div')\n field.className = 'dbg-field'\n const lbl = document.createElement('div')\n lbl.className = 'dbg-label'\n lbl.textContent = label\n field.appendChild(lbl)\n field.appendChild(content)\n return field\n }\n\n /** 创建带操作按钮的字段行(label + action button + content) */\n private createFieldWithAction(label: string, action: HTMLElement, content: HTMLElement): HTMLElement {\n const field = document.createElement('div')\n field.className = 'dbg-field'\n const fieldHeader = document.createElement('div')\n fieldHeader.className = 'dbg-field-header'\n const lbl = document.createElement('div')\n lbl.className = 'dbg-label'\n lbl.textContent = label\n fieldHeader.appendChild(lbl)\n fieldHeader.appendChild(action)\n field.appendChild(fieldHeader)\n field.appendChild(content)\n return field\n }\n\n /** 恢复上次持久化的状态 */\n private async restoreState(): Promise<void> {\n const savedGw = localStorage.getItem(KEY_GATEWAY)\n const gw = (savedGw && this.gateways.includes(savedGw)) ? savedGw : this.gateways[0]\n this.gwSelect.setValue(gw)\n await this.loadServers(gw)\n\n const savedType = localStorage.getItem(KEY_TYPE)\n if (savedType) {\n this.typeSelect.setValue(savedType)\n this.renderServerOptions(savedType)\n }\n\n const savedServer = localStorage.getItem(KEY_SERVER)\n if (savedServer && this.servers.find((s) => s.key === savedServer)) {\n this.serverSelect.setValue(savedServer)\n await this.applyServer(savedServer)\n }\n }\n\n private async onGatewayChange(gw: string): Promise<void> {\n localStorage.setItem(KEY_GATEWAY, gw)\n this.gwVersion.textContent = ''\n await this.loadServers(gw)\n }\n\n private onTypeChange(type: string): void {\n localStorage.setItem(KEY_TYPE, type)\n this.renderServerOptions(type)\n }\n\n private async onServerChange(key: string): Promise<void> {\n localStorage.setItem(KEY_SERVER, key)\n await this.applyServer(key)\n }\n\n /** 从网关加载服务列表 */\n private async loadServers(gwUrl: string): Promise<void> {\n this.setHeader('loading')\n this.setFooter(T.loading(), '')\n const result = await Get<ServerItem[]>(`${gwUrl}/web-debug/host/list`, {\n cache: true,\n timeout: this.options.timeout,\n })\n\n if (result.error) {\n this.setHeader('err')\n this.setFooter(T.loadFailed(result.error.message), 'err')\n return\n }\n\n this.servers = result.data ?? []\n this.renderTypeOptions()\n this.setHeader('ok')\n this.setFooter(T.loaded(this.servers.length), 'ok')\n }\n\n /** 渲染标签选项 */\n private renderTypeOptions(): void {\n const types = [...new Set(this.servers.map((s) => s.type).filter(Boolean))]\n const opts = [{ value: '', label: T.allTags() }, ...types.map((t) => ({ value: t, label: t }))]\n this.typeSelect.setOptions(opts, T.allTags())\n this.typeSelect.setValue('')\n this.renderServerOptions('')\n }\n\n /** 根据标签渲染服务选项 */\n private renderServerOptions(type: string): void {\n const filtered = type ? this.servers.filter((s) => s.type === type) : this.servers\n this.serverSelect.setOptions(\n filtered.map((s) => ({ value: s.key, label: `${s.name} (${s.key})` })),\n T.selectServer(),\n )\n this.renderCtxList({})\n }\n\n /** 切换目标服务,重新加载 Context 路由映射 */\n private async applyServer(key: string): Promise<void> {\n if (!key) { this.renderCtxList({}); return }\n const server = this.servers.find((s) => s.key === key)\n if (!server) return\n\n this.setFooter(T.switching(), '')\n try {\n await Context.load(server.origin, this.options.timeout)\n const res = await fetch(`${server.origin}/ngw/context`)\n const raw: Record<string, unknown> = res.ok ? await res.json() : {}\n const ctxMap: Record<string, string> = {}\n for (const [k, v] of Object.entries(raw)) {\n if (k !== '$info' && typeof v === 'string') ctxMap[k] = v\n }\n const info = Context.info\n if (info) this.gwVersion.textContent = `v${info.version}`\n this.renderCtxList(ctxMap)\n const count = Object.keys(ctxMap).length\n this.setFooter(T.routes(server.name, count), 'ok')\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n this.setFooter(T.switchFailed(msg), 'err')\n }\n }\n\n /** 渲染路由列表 */\n private renderCtxList(ctxMap: Record<string, string>): void {\n this.currentCtxMap = ctxMap\n this.ctxList.innerHTML = ''\n this.ctxSearchInput.value = ''\n const entries = Object.entries(ctxMap)\n if (entries.length === 0) {\n const empty = document.createElement('div')\n empty.className = 'dbg-ctx-empty'\n empty.textContent = T.selectFirst()\n this.ctxList.appendChild(empty)\n return\n }\n entries.forEach(([k, v]) => {\n const item = document.createElement('div')\n item.className = 'dbg-ctx-item'\n item.dataset['key'] = k\n\n const keySpan = document.createElement('span')\n keySpan.className = 'dbg-ctx-key'\n keySpan.textContent = k\n keySpan.setAttribute('title', k)\n\n const valSpan = document.createElement('span')\n valSpan.className = 'dbg-ctx-val'\n valSpan.textContent = v\n valSpan.setAttribute('title', `${k} → ${v}`)\n\n const copyIcon = document.createElement('span')\n copyIcon.className = 'dbg-ctx-copy'\n copyIcon.textContent = '⎘'\n\n item.appendChild(keySpan)\n item.appendChild(valSpan)\n item.appendChild(copyIcon)\n item.addEventListener('click', () => this.copyCtxItem(item, k))\n this.ctxList.appendChild(item)\n })\n }\n\n /** 过滤路由列表 */\n private filterCtx(query: string): void {\n const q = query.toLowerCase()\n this.ctxList.querySelectorAll<HTMLElement>('.dbg-ctx-item').forEach((item) => {\n const key = item.dataset['key'] ?? ''\n item.classList.toggle('hidden', !!q && !key.toLowerCase().includes(q))\n })\n }\n\n /** 复制单个 ctx key */\n private copyCtxItem(item: HTMLElement, text: string): void {\n navigator.clipboard.writeText(text).then(() => {\n item.classList.add('copied')\n const icon = item.querySelector('.dbg-ctx-copy')\n if (icon) icon.textContent = '✓'\n setTimeout(() => {\n item.classList.remove('copied')\n const ic = item.querySelector('.dbg-ctx-copy')\n if (ic) ic.textContent = '⎘'\n }, 1500)\n this.setFooter(T.copied(text), 'ok')\n setTimeout(() => this.setFooter('', ''), 2000)\n })\n }\n\n /** 一键复制全部上下文为 JSON */\n private copyAllCtx(): void {\n const entries = Object.keys(this.currentCtxMap)\n if (entries.length === 0) return\n const json = JSON.stringify(this.currentCtxMap, null, 2)\n navigator.clipboard.writeText(json).then(() => {\n this.copyAllBtn.textContent = '✓ ' + T.copyAllDone()\n this.copyAllBtn.classList.add('done')\n setTimeout(() => {\n this.copyAllBtn.textContent = T.copyAll()\n this.copyAllBtn.classList.remove('done')\n }, 2000)\n this.setFooter(T.copyAllDone(), 'ok')\n setTimeout(() => this.setFooter('', ''), 2500)\n })\n }\n\n private setHeader(state: 'ok' | 'err' | 'loading'): void {\n this.headerDot.className = `dbg-header-dot${state !== 'ok' ? ` ${state}` : ''}`\n }\n\n private setFooter(msg: string, cls: '' | 'ok' | 'err'): void {\n this.footerEl.innerHTML = msg\n ? `<span class=\"dbg-footer-dot\"></span>${msg}`\n : ''\n this.footerEl.className = `dbg-footer${cls ? ` ${cls}` : ''}`\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/debugger/debugger.ts"],"names":[],"mappings":"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;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","file":"chunk-4DLFIN3C.js","sourcesContent":["import { Get } from '../http/client'\nimport { Context } from '../http/context'\nimport type { ServerItem } from '../http/types'\nimport type { DebuggerOptions } from './types'\n\n/** localStorage key 前缀 */\nconst STORAGE_PREFIX = '__snackkit_debugger__'\nconst KEY_GATEWAY = `${STORAGE_PREFIX}gateway`\nconst KEY_TYPE = `${STORAGE_PREFIX}type`\nconst KEY_SERVER = `${STORAGE_PREFIX}server`\n\n/** 是否为中文环境 */\nfunction isChinese(): boolean {\n return /^zh/i.test(navigator.language ?? '')\n}\n\n/** i18n 文案 */\nconst T = {\n gateway: () => isChinese() ? '网关' : 'Gateway',\n tag: () => isChinese() ? '标签' : 'Tag',\n server: () => isChinese() ? '服务' : 'Server',\n ctx: () => isChinese() ? '上下文' : 'Ctx',\n ctxLabel: () => isChinese() ? '上下文 — 点击行复制 key' : 'Ctx — click row to copy key',\n search: () => isChinese() ? '搜索...' : 'Search...',\n noMatch: () => isChinese() ? '无匹配项' : 'No results',\n allTags: () => isChinese() ? '全部标签' : 'All tags',\n selectGateway: () => isChinese() ? '选择网关' : 'Select gateway',\n selectServer: () => isChinese() ? '选择服务' : 'Select server',\n filterCtx: () => isChinese() ? '过滤路由...' : 'Filter routes...',\n selectFirst: () => isChinese() ? '← 请先选择服务' : '← Select a server first',\n loading: () => isChinese() ? '加载服务列表...' : 'Loading...',\n loadFailed: (m: string) => isChinese() ? `加载失败: ${m}` : `Failed: ${m}`,\n loaded: (n: number) => isChinese() ? `已加载 ${n} 个服务` : `${n} servers loaded`,\n switching: () => isChinese() ? '切换服务中...' : 'Switching...',\n switchFailed: (m: string) => isChinese() ? `切换失败: ${m}` : `Failed: ${m}`,\n routes: (name: string, n: number) => isChinese() ? `${name} · ${n} 条路由` : `${name} · ${n} routes`,\n copied: (k: string) => isChinese() ? `已复制: ${k}` : `Copied: ${k}`,\n copyAll: () => isChinese() ? '复制全部 JSON' : 'Copy all JSON',\n copyAllDone: () => isChinese() ? '已复制为 JSON' : 'Copied as JSON',\n}\n\n/** 面板内联样式 */\nconst PANEL_STYLE = `\n #__snackkit_debugger__ {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 99999;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif;\n font-size: 13px;\n color: #b8ccec;\n user-select: none;\n }\n\n /* ── 浮动按钮 ── */\n #__snackkit_debugger__ .dbg-toggle {\n width: 42px;\n height: 42px;\n border-radius: 50%;\n background: linear-gradient(135deg, #4f8ef7, #6d6ff5);\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 14px rgba(79,142,247,0.45);\n margin-left: auto;\n font-size: 20px;\n transition: transform 0.15s, box-shadow 0.15s;\n }\n #__snackkit_debugger__ .dbg-toggle:hover {\n transform: scale(1.08);\n box-shadow: 0 6px 20px rgba(79,142,247,0.55);\n }\n #__snackkit_debugger__ .dbg-toggle:active { transform: scale(0.94); }\n\n /* ── 面板主体 ── */\n #__snackkit_debugger__ .dbg-panel {\n background: #1e2638;\n border: 1px solid #2d3a55;\n border-radius: 12px;\n width: 440px;\n margin-bottom: 10px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.45), 0 0 0 1px rgba(255,255,255,0.05);\n overflow: visible;\n opacity: 0;\n transform: translateY(8px) scale(0.98);\n pointer-events: none;\n transition: opacity 0.18s ease, transform 0.18s ease;\n }\n #__snackkit_debugger__ .dbg-panel.open {\n opacity: 1;\n transform: translateY(0) scale(1);\n pointer-events: auto;\n }\n\n /* ── 面板 Header ── */\n #__snackkit_debugger__ .dbg-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 14px;\n background: #171e2e;\n border-bottom: 1px solid #2d3a55;\n border-radius: 12px 12px 0 0;\n }\n #__snackkit_debugger__ .dbg-header-left {\n display: flex;\n align-items: center;\n gap: 7px;\n }\n #__snackkit_debugger__ .dbg-header-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: #34d399;\n box-shadow: 0 0 6px rgba(52,211,153,0.6);\n }\n #__snackkit_debugger__ .dbg-header-dot.loading {\n background: #fbbf24;\n box-shadow: 0 0 6px rgba(251,191,36,0.6);\n animation: dbg-pulse 1s ease-in-out infinite;\n }\n #__snackkit_debugger__ .dbg-header-dot.err {\n background: #f87171;\n box-shadow: 0 0 6px rgba(248,113,113,0.6);\n }\n #__snackkit_debugger__ .dbg-header-title {\n font-size: 12px;\n font-weight: 600;\n color: #dce8fa;\n letter-spacing: 0.03em;\n }\n #__snackkit_debugger__ .dbg-header-meta {\n font-size: 11px;\n color: #4d6080;\n }\n\n /* ── 面板内容区 ── */\n #__snackkit_debugger__ .dbg-body {\n padding: 12px 14px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n height: 420px;\n overflow: visible;\n }\n\n /* ── 字段行 ── */\n #__snackkit_debugger__ .dbg-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n }\n #__snackkit_debugger__ .dbg-field-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n #__snackkit_debugger__ .dbg-label {\n font-size: 10px;\n font-weight: 600;\n color: #5e72a0;\n text-transform: uppercase;\n letter-spacing: 0.07em;\n }\n\n /* ── 一键复制全部 JSON 按钮 ── */\n #__snackkit_debugger__ .dbg-copy-all {\n display: flex;\n align-items: center;\n gap: 4px;\n background: transparent;\n border: 1px solid #2d3a55;\n border-radius: 4px;\n padding: 2px 7px;\n color: #5e72a0;\n font-size: 10px;\n font-family: inherit;\n cursor: pointer;\n transition: border-color 0.15s, color 0.15s, background 0.15s;\n }\n #__snackkit_debugger__ .dbg-copy-all:hover {\n border-color: #4f8ef7;\n color: #7aacfa;\n background: rgba(79,142,247,0.08);\n }\n #__snackkit_debugger__ .dbg-copy-all.done {\n border-color: #34d399;\n color: #34d399;\n }\n\n /* ── 自定义下拉 ── */\n #__snackkit_debugger__ .dbg-select {\n position: relative;\n }\n #__snackkit_debugger__ .dbg-select-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n background: #252f45;\n border: 1px solid #2d3a55;\n border-radius: 6px;\n padding: 6px 10px;\n cursor: pointer;\n transition: border-color 0.15s, background 0.15s;\n min-height: 32px;\n }\n #__snackkit_debugger__ .dbg-select-trigger:hover { border-color: #3d5070; background: #2d3a55; }\n #__snackkit_debugger__ .dbg-select.open .dbg-select-trigger {\n border-color: #4f8ef7;\n background: #2d3a55;\n }\n #__snackkit_debugger__ .dbg-select-val {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n color: #b8ccec;\n }\n #__snackkit_debugger__ .dbg-select-val.placeholder { color: #3d5070; }\n #__snackkit_debugger__ .dbg-select-arrow {\n color: #3d5070;\n font-size: 10px;\n flex-shrink: 0;\n transition: transform 0.15s, color 0.15s;\n }\n #__snackkit_debugger__ .dbg-select.open .dbg-select-arrow {\n transform: rotate(180deg);\n color: #4f8ef7;\n }\n #__snackkit_debugger__ .dbg-select-dropdown {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 0;\n right: 0;\n background: #1e2638;\n border: 1px solid #2d3a55;\n border-radius: 8px;\n box-shadow: 0 -8px 24px rgba(0,0,0,0.35);\n overflow: hidden;\n opacity: 0;\n transform: translateY(4px);\n pointer-events: none;\n transition: opacity 0.14s, transform 0.14s;\n z-index: 100000;\n }\n #__snackkit_debugger__ .dbg-select.open .dbg-select-dropdown {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n }\n #__snackkit_debugger__ .dbg-select-search {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 7px 10px;\n border-bottom: 1px solid #2d3a55;\n }\n #__snackkit_debugger__ .dbg-select-search-icon { color: #3d5070; font-size: 11px; flex-shrink: 0; }\n #__snackkit_debugger__ .dbg-select-search input {\n flex: 1;\n background: transparent;\n border: none;\n outline: none;\n color: #b8ccec;\n font-size: 12px;\n font-family: inherit;\n }\n #__snackkit_debugger__ .dbg-select-search input::placeholder { color: #3d5070; }\n #__snackkit_debugger__ .dbg-select-list {\n max-height: 160px;\n overflow-y: auto;\n }\n #__snackkit_debugger__ .dbg-select-list::-webkit-scrollbar { width: 3px; }\n #__snackkit_debugger__ .dbg-select-list::-webkit-scrollbar-track { background: transparent; }\n #__snackkit_debugger__ .dbg-select-list::-webkit-scrollbar-thumb { background: #2d3a55; border-radius: 2px; }\n #__snackkit_debugger__ .dbg-select-option {\n padding: 7px 10px;\n cursor: pointer;\n font-size: 12px;\n color: #8aa4c8;\n transition: background 0.1s, color 0.1s;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n #__snackkit_debugger__ .dbg-select-option:hover { background: #2d3a55; color: #dce8fa; }\n #__snackkit_debugger__ .dbg-select-option.active { color: #7aacfa; background: #1e3060; }\n #__snackkit_debugger__ .dbg-select-option.hidden { display: none; }\n #__snackkit_debugger__ .dbg-select-empty {\n padding: 12px 10px;\n font-size: 12px;\n color: #3d5070;\n text-align: center;\n }\n\n /* ── 路由列表 ── */\n #__snackkit_debugger__ .dbg-ctx-field {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n gap: 5px;\n }\n #__snackkit_debugger__ .dbg-ctx-wrap {\n flex: 1;\n min-height: 0;\n border: 1px solid #2d3a55;\n border-radius: 6px;\n overflow: hidden;\n background: #252f45;\n display: flex;\n flex-direction: column;\n }\n #__snackkit_debugger__ .dbg-ctx-search {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 10px;\n border-bottom: 1px solid #2d3a55;\n background: #1e2638;\n }\n #__snackkit_debugger__ .dbg-ctx-search input {\n flex: 1;\n background: transparent;\n border: none;\n outline: none;\n color: #b8ccec;\n font-size: 12px;\n font-family: inherit;\n }\n #__snackkit_debugger__ .dbg-ctx-search input::placeholder { color: #3d5070; }\n #__snackkit_debugger__ .dbg-ctx-list {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n }\n #__snackkit_debugger__ .dbg-ctx-list::-webkit-scrollbar { width: 3px; }\n #__snackkit_debugger__ .dbg-ctx-list::-webkit-scrollbar-track { background: transparent; }\n #__snackkit_debugger__ .dbg-ctx-list::-webkit-scrollbar-thumb { background: #2d3a55; border-radius: 2px; }\n #__snackkit_debugger__ .dbg-ctx-item {\n padding: 5px 10px;\n cursor: pointer;\n display: grid;\n grid-template-columns: minmax(80px, 148px) 1fr auto;\n gap: 8px;\n align-items: center;\n border-bottom: 1px solid #1e2638;\n transition: background 0.1s;\n }\n #__snackkit_debugger__ .dbg-ctx-item:last-child { border-bottom: none; }\n #__snackkit_debugger__ .dbg-ctx-item:hover { background: #2d3a55; }\n #__snackkit_debugger__ .dbg-ctx-item.hidden { display: none; }\n #__snackkit_debugger__ .dbg-ctx-key {\n font-size: 12px;\n color: #7aacfa;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n #__snackkit_debugger__ .dbg-ctx-val {\n font-size: 11px;\n color: #4d6080;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n transition: color 0.1s;\n }\n #__snackkit_debugger__ .dbg-ctx-item:hover .dbg-ctx-val { color: #7a90b0; }\n #__snackkit_debugger__ .dbg-ctx-copy {\n font-size: 11px;\n color: #3d5070;\n opacity: 0;\n flex-shrink: 0;\n transition: opacity 0.1s, color 0.1s;\n }\n #__snackkit_debugger__ .dbg-ctx-item:hover .dbg-ctx-copy { opacity: 1; color: #5e72a0; }\n #__snackkit_debugger__ .dbg-ctx-item.copied .dbg-ctx-copy { color: #34d399; opacity: 1; }\n #__snackkit_debugger__ .dbg-ctx-empty {\n padding: 16px 10px;\n font-size: 12px;\n color: #3d5070;\n text-align: center;\n }\n\n /* ── 底部状态栏 ── */\n #__snackkit_debugger__ .dbg-footer {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 7px 14px;\n background: #171e2e;\n border-top: 1px solid #2d3a55;\n border-radius: 0 0 12px 12px;\n font-size: 11px;\n color: #4d6080;\n min-height: 30px;\n }\n #__snackkit_debugger__ .dbg-footer.ok { color: #34d399; }\n #__snackkit_debugger__ .dbg-footer.err { color: #f87171; }\n #__snackkit_debugger__ .dbg-footer-dot {\n width: 4px;\n height: 4px;\n border-radius: 50%;\n background: currentColor;\n flex-shrink: 0;\n }\n\n @keyframes dbg-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.35; }\n }\n`\n\n/** 可搜索的自定义下拉组件 */\nclass SearchSelect {\n private el: HTMLElement\n private trigger: HTMLElement\n private valEl: HTMLElement\n private dropdown: HTMLElement\n private searchInput: HTMLInputElement\n private listEl: HTMLElement\n private options: Array<{ value: string; label: string }> = []\n private selected = ''\n private onChange: (value: string) => void\n\n constructor(onChange: (value: string) => void) {\n this.onChange = onChange\n this.el = document.createElement('div')\n this.el.className = 'dbg-select'\n\n // 触发器\n this.trigger = document.createElement('div')\n this.trigger.className = 'dbg-select-trigger'\n this.valEl = document.createElement('span')\n this.valEl.className = 'dbg-select-val placeholder'\n const arrow = document.createElement('span')\n arrow.className = 'dbg-select-arrow'\n arrow.textContent = '▾'\n this.trigger.appendChild(this.valEl)\n this.trigger.appendChild(arrow)\n\n // 下拉面板\n this.dropdown = document.createElement('div')\n this.dropdown.className = 'dbg-select-dropdown'\n\n // 搜索框\n const searchWrap = document.createElement('div')\n searchWrap.className = 'dbg-select-search'\n const searchIcon = document.createElement('span')\n searchIcon.className = 'dbg-select-search-icon'\n searchIcon.textContent = '⌕'\n this.searchInput = document.createElement('input')\n this.searchInput.type = 'text'\n this.searchInput.placeholder = T.search()\n searchWrap.appendChild(searchIcon)\n searchWrap.appendChild(this.searchInput)\n\n this.listEl = document.createElement('div')\n this.listEl.className = 'dbg-select-list'\n\n this.dropdown.appendChild(searchWrap)\n this.dropdown.appendChild(this.listEl)\n this.el.appendChild(this.trigger)\n this.el.appendChild(this.dropdown)\n\n this.bindEvents()\n }\n\n private bindEvents(): void {\n this.trigger.addEventListener('click', (e) => {\n e.stopPropagation()\n const isOpen = this.el.classList.contains('open')\n document.querySelectorAll('#__snackkit_debugger__ .dbg-select.open').forEach((el) => {\n if (el !== this.el) el.classList.remove('open')\n })\n this.el.classList.toggle('open', !isOpen)\n if (!isOpen) {\n this.searchInput.value = ''\n this.filterOptions('')\n setTimeout(() => this.searchInput.focus(), 50)\n }\n })\n\n this.searchInput.addEventListener('input', () => {\n this.filterOptions(this.searchInput.value)\n })\n\n this.searchInput.addEventListener('click', (e) => e.stopPropagation())\n\n document.addEventListener('click', () => {\n this.el.classList.remove('open')\n })\n }\n\n private filterOptions(query: string): void {\n const q = query.toLowerCase()\n let visibleCount = 0\n this.listEl.querySelectorAll<HTMLElement>('.dbg-select-option').forEach((opt) => {\n const match = !q || opt.textContent!.toLowerCase().includes(q)\n opt.classList.toggle('hidden', !match)\n if (match) visibleCount++\n })\n let emptyEl = this.listEl.querySelector<HTMLElement>('.dbg-select-empty')\n if (visibleCount === 0) {\n if (!emptyEl) {\n emptyEl = document.createElement('div')\n emptyEl.className = 'dbg-select-empty'\n emptyEl.textContent = T.noMatch()\n this.listEl.appendChild(emptyEl)\n }\n } else {\n emptyEl?.remove()\n }\n }\n\n /** 更新选项列表 */\n setOptions(options: Array<{ value: string; label: string }>, placeholder: string): void {\n this.options = options\n this.listEl.innerHTML = ''\n this.valEl.textContent = placeholder\n this.valEl.className = 'dbg-select-val placeholder'\n this.selected = ''\n\n options.forEach(({ value, label }) => {\n const opt = document.createElement('div')\n opt.className = 'dbg-select-option'\n opt.dataset['value'] = value\n opt.textContent = label\n opt.setAttribute('title', label)\n opt.addEventListener('click', (e) => {\n e.stopPropagation()\n this.select(value, label)\n this.el.classList.remove('open')\n })\n this.listEl.appendChild(opt)\n })\n }\n\n /** 选中某个值(不触发 onChange) */\n setValue(value: string): void {\n const opt = this.options.find((o) => o.value === value)\n if (opt) this.select(opt.value, opt.label, false)\n }\n\n private select(value: string, label: string, emit = true): void {\n this.selected = value\n this.valEl.textContent = label\n this.valEl.className = 'dbg-select-val'\n this.listEl.querySelectorAll('.dbg-select-option').forEach((el) => {\n el.classList.toggle('active', (el as HTMLElement).dataset['value'] === value)\n })\n if (emit) this.onChange(value)\n }\n\n getValue(): string { return this.selected }\n getElement(): HTMLElement { return this.el }\n}\n\n/**\n * 浏览器端浮动调试面板\n *\n * 允许开发者在运行时:\n * - 选择调试网关 → 拉取服务清单\n * - 切换目标服务 → 重新加载 Context 路由映射\n * - 查看并复制可用的路由 ctx 列表\n *\n * 与 http 模块集成:使用 `Get()` 拉取服务清单,使用 `context.load()` 切换请求目标。\n *\n * @see [交互式 Demo](../demo/debugger.html)\n *\n * @example\n * ```ts\n * import { Debugger } from '@snack-kit/lib/debugger'\n *\n * await Debugger.init({ gateways: 'http://dev-gateway.example.com' })\n * ```\n */\nexport class Debugger {\n private options: Required<DebuggerOptions>\n private gateways: string[]\n private servers: ServerItem[] = []\n private currentCtxMap: Record<string, string> = {}\n private panelEl!: HTMLElement\n private headerDot!: HTMLElement\n private gwVersion!: HTMLElement\n private footerEl!: HTMLElement\n private copyAllBtn!: HTMLButtonElement\n private gwSelect!: SearchSelect\n private typeSelect!: SearchSelect\n private serverSelect!: SearchSelect\n private ctxList!: HTMLElement\n private ctxSearchInput!: HTMLInputElement\n\n private constructor(options: Required<DebuggerOptions>) {\n this.options = options\n this.gateways = Array.isArray(options.gateways) ? options.gateways : [options.gateways]\n }\n\n /**\n * 初始化并渲染调试面板\n *\n * 调用后在页面右下角插入浮动按钮,点击展开调试面板。\n * 面板支持:选择调试网关、切换目标服务、查看并复制路由 ctx。\n * 网关/服务选择通过 `localStorage` 持久化,刷新后自动恢复。\n *\n * @param options 配置项\n *\n * @example 单网关\n * ```ts\n * import { Debugger } from '@snack-kit/lib/debugger'\n *\n * await Debugger.init({\n * gateways: 'http://dev-gateway.example.com',\n * })\n * ```\n *\n * @example 多网关(开发/测试环境切换)\n * ```ts\n * await Debugger.init({\n * gateways: [\n * 'http://dev-gateway.example.com',\n * 'http://test-gateway.example.com',\n * ],\n * timeout: 5000,\n * })\n * ```\n *\n * @example 仅在非生产环境加载\n * ```ts\n * if (import.meta.env.DEV) {\n * const { Debugger } = await import('@snack-kit/lib/debugger')\n * await Debugger.init({ gateways: 'http://dev-gateway.example.com' })\n * }\n * ```\n */\n static async init(options: DebuggerOptions): Promise<Debugger> {\n const instance = new Debugger({ timeout: 10000, ...options })\n instance.injectStyle()\n instance.buildDOM()\n await instance.restoreState()\n return instance\n }\n\n /** 注入内联样式 */\n private injectStyle(): void {\n if (document.getElementById('__snackkit_debugger_style__')) return\n const style = document.createElement('style')\n style.id = '__snackkit_debugger_style__'\n style.textContent = PANEL_STYLE\n document.head.appendChild(style)\n }\n\n /** 构建 DOM 结构 */\n private buildDOM(): void {\n const root = document.createElement('div')\n root.id = '__snackkit_debugger__'\n\n // ── 面板 ──\n const panel = document.createElement('div')\n panel.className = 'dbg-panel'\n this.panelEl = panel\n\n // Header\n const header = document.createElement('div')\n header.className = 'dbg-header'\n const headerLeft = document.createElement('div')\n headerLeft.className = 'dbg-header-left'\n this.headerDot = document.createElement('span')\n this.headerDot.className = 'dbg-header-dot loading'\n const headerTitle = document.createElement('span')\n headerTitle.className = 'dbg-header-title'\n headerTitle.textContent = 'Snack Kit Debugger'\n headerLeft.appendChild(this.headerDot)\n headerLeft.appendChild(headerTitle)\n header.appendChild(headerLeft)\n panel.appendChild(header)\n\n // Body\n const body = document.createElement('div')\n body.className = 'dbg-body'\n\n // 网关选择(标签行右侧显示版本号)\n this.gwVersion = document.createElement('span')\n this.gwVersion.className = 'dbg-header-meta'\n this.gwSelect = new SearchSelect((val) => this.onGatewayChange(val))\n this.gwSelect.setOptions(this.gateways.map((g) => ({ value: g, label: g })), T.selectGateway())\n body.appendChild(this.createFieldWithAction(T.gateway(), this.gwVersion, this.gwSelect.getElement()))\n\n // 标签(类型)选择\n this.typeSelect = new SearchSelect((val) => this.onTypeChange(val))\n body.appendChild(this.createField(T.tag(), this.typeSelect.getElement()))\n\n // 服务选择\n this.serverSelect = new SearchSelect((val) => this.onServerChange(val))\n body.appendChild(this.createField(T.server(), this.serverSelect.getElement()))\n\n // 路由列表(含一键复制全部 JSON 按钮)\n const ctxWrap = document.createElement('div')\n ctxWrap.className = 'dbg-ctx-wrap'\n\n const ctxSearch = document.createElement('div')\n ctxSearch.className = 'dbg-ctx-search'\n const ctxSearchIcon = document.createElement('span')\n ctxSearchIcon.className = 'dbg-select-search-icon'\n ctxSearchIcon.textContent = '⌕'\n this.ctxSearchInput = document.createElement('input')\n this.ctxSearchInput.type = 'text'\n this.ctxSearchInput.placeholder = T.filterCtx()\n this.ctxSearchInput.addEventListener('input', () => this.filterCtx(this.ctxSearchInput.value))\n ctxSearch.appendChild(ctxSearchIcon)\n ctxSearch.appendChild(this.ctxSearchInput)\n\n this.ctxList = document.createElement('div')\n this.ctxList.className = 'dbg-ctx-list'\n\n ctxWrap.appendChild(ctxSearch)\n ctxWrap.appendChild(this.ctxList)\n\n // 一键复制全部 JSON 按钮\n this.copyAllBtn = document.createElement('button')\n this.copyAllBtn.className = 'dbg-copy-all'\n this.copyAllBtn.textContent = T.copyAll()\n this.copyAllBtn.setAttribute('title', isChinese()\n ? '将全部上下文复制为 JSON,可作为 Context.load({...}) 的参数'\n : 'Copy all ctx entries as JSON for Context.load({...})')\n this.copyAllBtn.addEventListener('click', (e) => {\n e.stopPropagation()\n this.copyAllCtx()\n })\n\n const ctxField = this.createFieldWithAction(T.ctxLabel(), this.copyAllBtn, ctxWrap)\n ctxField.classList.add('dbg-ctx-field')\n body.appendChild(ctxField)\n\n panel.appendChild(body)\n\n // Footer 状态栏\n const footer = document.createElement('div')\n footer.className = 'dbg-footer'\n this.footerEl = footer\n panel.appendChild(footer)\n\n // ── 浮动按钮 ──\n const toggle = document.createElement('button')\n toggle.className = 'dbg-toggle'\n toggle.textContent = '🐛'\n toggle.setAttribute('title', 'Snack Debugger')\n toggle.addEventListener('click', (e) => {\n e.stopPropagation()\n panel.classList.toggle('open')\n })\n\n root.appendChild(panel)\n root.appendChild(toggle)\n document.body.appendChild(root)\n }\n\n /** 创建普通字段行(label + content) */\n private createField(label: string, content: HTMLElement): HTMLElement {\n const field = document.createElement('div')\n field.className = 'dbg-field'\n const lbl = document.createElement('div')\n lbl.className = 'dbg-label'\n lbl.textContent = label\n field.appendChild(lbl)\n field.appendChild(content)\n return field\n }\n\n /** 创建带操作按钮的字段行(label + action button + content) */\n private createFieldWithAction(label: string, action: HTMLElement, content: HTMLElement): HTMLElement {\n const field = document.createElement('div')\n field.className = 'dbg-field'\n const fieldHeader = document.createElement('div')\n fieldHeader.className = 'dbg-field-header'\n const lbl = document.createElement('div')\n lbl.className = 'dbg-label'\n lbl.textContent = label\n fieldHeader.appendChild(lbl)\n fieldHeader.appendChild(action)\n field.appendChild(fieldHeader)\n field.appendChild(content)\n return field\n }\n\n /** 恢复上次持久化的状态 */\n private async restoreState(): Promise<void> {\n const savedGw = localStorage.getItem(KEY_GATEWAY)\n const gw = (savedGw && this.gateways.includes(savedGw)) ? savedGw : this.gateways[0]\n this.gwSelect.setValue(gw)\n await this.loadServers(gw)\n\n const savedType = localStorage.getItem(KEY_TYPE)\n if (savedType) {\n this.typeSelect.setValue(savedType)\n this.renderServerOptions(savedType)\n }\n\n const savedServer = localStorage.getItem(KEY_SERVER)\n if (savedServer && this.servers.find((s) => s.key === savedServer)) {\n this.serverSelect.setValue(savedServer)\n await this.applyServer(savedServer)\n }\n }\n\n private async onGatewayChange(gw: string): Promise<void> {\n localStorage.setItem(KEY_GATEWAY, gw)\n this.gwVersion.textContent = ''\n await this.loadServers(gw)\n }\n\n private onTypeChange(type: string): void {\n localStorage.setItem(KEY_TYPE, type)\n this.renderServerOptions(type)\n }\n\n private async onServerChange(key: string): Promise<void> {\n localStorage.setItem(KEY_SERVER, key)\n await this.applyServer(key)\n }\n\n /** 从网关加载服务列表 */\n private async loadServers(gwUrl: string): Promise<void> {\n this.setHeader('loading')\n this.setFooter(T.loading(), '')\n const result = await Get<ServerItem[]>(`${gwUrl}/web-debug/host/list`, {\n cache: true,\n timeout: this.options.timeout,\n })\n\n if (result.error) {\n this.setHeader('err')\n this.setFooter(T.loadFailed(result.error.message), 'err')\n return\n }\n\n this.servers = result.data ?? []\n this.renderTypeOptions()\n this.setHeader('ok')\n this.setFooter(T.loaded(this.servers.length), 'ok')\n }\n\n /** 渲染标签选项 */\n private renderTypeOptions(): void {\n const types = [...new Set(this.servers.map((s) => s.type).filter(Boolean))]\n const opts = [{ value: '', label: T.allTags() }, ...types.map((t) => ({ value: t, label: t }))]\n this.typeSelect.setOptions(opts, T.allTags())\n this.typeSelect.setValue('')\n this.renderServerOptions('')\n }\n\n /** 根据标签渲染服务选项 */\n private renderServerOptions(type: string): void {\n const filtered = type ? this.servers.filter((s) => s.type === type) : this.servers\n this.serverSelect.setOptions(\n filtered.map((s) => ({ value: s.key, label: `${s.name} (${s.key})` })),\n T.selectServer(),\n )\n this.renderCtxList({})\n }\n\n /** 切换目标服务,重新加载 Context 路由映射 */\n private async applyServer(key: string): Promise<void> {\n if (!key) { this.renderCtxList({}); return }\n const server = this.servers.find((s) => s.key === key)\n if (!server) return\n\n this.setFooter(T.switching(), '')\n try {\n await Context.load(server.origin, this.options.timeout)\n const res = await fetch(`${server.origin}/ngw/context`)\n const raw: Record<string, unknown> = res.ok ? await res.json() : {}\n const ctxMap: Record<string, string> = {}\n for (const [k, v] of Object.entries(raw)) {\n if (k !== '$info' && typeof v === 'string') ctxMap[k] = v\n }\n const info = Context.info\n if (info) this.gwVersion.textContent = `v${info.version}`\n this.renderCtxList(ctxMap)\n const count = Object.keys(ctxMap).length\n this.setFooter(T.routes(server.name, count), 'ok')\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n this.setFooter(T.switchFailed(msg), 'err')\n }\n }\n\n /** 渲染路由列表 */\n private renderCtxList(ctxMap: Record<string, string>): void {\n this.currentCtxMap = ctxMap\n this.ctxList.innerHTML = ''\n this.ctxSearchInput.value = ''\n const entries = Object.entries(ctxMap)\n if (entries.length === 0) {\n const empty = document.createElement('div')\n empty.className = 'dbg-ctx-empty'\n empty.textContent = T.selectFirst()\n this.ctxList.appendChild(empty)\n return\n }\n entries.forEach(([k, v]) => {\n const item = document.createElement('div')\n item.className = 'dbg-ctx-item'\n item.dataset['key'] = k\n\n const keySpan = document.createElement('span')\n keySpan.className = 'dbg-ctx-key'\n keySpan.textContent = k\n keySpan.setAttribute('title', k)\n\n const valSpan = document.createElement('span')\n valSpan.className = 'dbg-ctx-val'\n valSpan.textContent = v\n valSpan.setAttribute('title', `${k} → ${v}`)\n\n const copyIcon = document.createElement('span')\n copyIcon.className = 'dbg-ctx-copy'\n copyIcon.textContent = '⎘'\n\n item.appendChild(keySpan)\n item.appendChild(valSpan)\n item.appendChild(copyIcon)\n item.addEventListener('click', () => this.copyCtxItem(item, k))\n this.ctxList.appendChild(item)\n })\n }\n\n /** 过滤路由列表 */\n private filterCtx(query: string): void {\n const q = query.toLowerCase()\n this.ctxList.querySelectorAll<HTMLElement>('.dbg-ctx-item').forEach((item) => {\n const key = item.dataset['key'] ?? ''\n item.classList.toggle('hidden', !!q && !key.toLowerCase().includes(q))\n })\n }\n\n /** 复制单个 ctx key */\n private copyCtxItem(item: HTMLElement, text: string): void {\n navigator.clipboard.writeText(text).then(() => {\n item.classList.add('copied')\n const icon = item.querySelector('.dbg-ctx-copy')\n if (icon) icon.textContent = '✓'\n setTimeout(() => {\n item.classList.remove('copied')\n const ic = item.querySelector('.dbg-ctx-copy')\n if (ic) ic.textContent = '⎘'\n }, 1500)\n this.setFooter(T.copied(text), 'ok')\n setTimeout(() => this.setFooter('', ''), 2000)\n })\n }\n\n /** 一键复制全部上下文为 JSON */\n private copyAllCtx(): void {\n const entries = Object.keys(this.currentCtxMap)\n if (entries.length === 0) return\n const json = JSON.stringify(this.currentCtxMap, null, 2)\n navigator.clipboard.writeText(json).then(() => {\n this.copyAllBtn.textContent = '✓ ' + T.copyAllDone()\n this.copyAllBtn.classList.add('done')\n setTimeout(() => {\n this.copyAllBtn.textContent = T.copyAll()\n this.copyAllBtn.classList.remove('done')\n }, 2000)\n this.setFooter(T.copyAllDone(), 'ok')\n setTimeout(() => this.setFooter('', ''), 2500)\n })\n }\n\n private setHeader(state: 'ok' | 'err' | 'loading'): void {\n this.headerDot.className = `dbg-header-dot${state !== 'ok' ? ` ${state}` : ''}`\n }\n\n private setFooter(msg: string, cls: '' | 'ok' | 'err'): void {\n this.footerEl.innerHTML = msg\n ? `<span class=\"dbg-footer-dot\"></span>${msg}`\n : ''\n this.footerEl.className = `dbg-footer${cls ? ` ${cls}` : ''}`\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
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"]}
|