xn-fe-tools 1.5.0 → 1.6.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.
Files changed (50) hide show
  1. package/README.md +75 -4
  2. package/dist/hooks/toSentrySetup/core.d.ts +155 -0
  3. package/dist/hooks/toSentrySetup/core.d.ts.map +1 -0
  4. package/dist/hooks/toSentrySetup/index.d.ts +17 -0
  5. package/dist/hooks/toSentrySetup/index.d.ts.map +1 -0
  6. package/dist/hooks/toSentrySetup/toReactSentrySetup.d.ts +21 -0
  7. package/dist/hooks/toSentrySetup/toReactSentrySetup.d.ts.map +1 -0
  8. package/dist/hooks/toSentrySetup/toSentrySetup.d.ts +21 -0
  9. package/dist/hooks/toSentrySetup/toSentrySetup.d.ts.map +1 -0
  10. package/dist/hooks/toSentrySetup/toVue2SentrySetup.d.ts +23 -0
  11. package/dist/hooks/toSentrySetup/toVue2SentrySetup.d.ts.map +1 -0
  12. package/dist/hooks/toSentrySetup/toVue3SentrySetup.d.ts +24 -0
  13. package/dist/hooks/toSentrySetup/toVue3SentrySetup.d.ts.map +1 -0
  14. package/dist/index.cjs.js +1 -1
  15. package/dist/index.es.js +1 -1
  16. package/dist/mcp/hook-metadata.json +26 -18
  17. package/dist/sentry/browser.cjs.js +1 -0
  18. package/dist/sentry/browser.es.js +1 -0
  19. package/dist/sentry/react.cjs.js +1 -0
  20. package/dist/sentry/react.es.js +1 -0
  21. package/dist/sentry/vue2.cjs.js +1 -0
  22. package/dist/sentry/vue2.es.js +1 -0
  23. package/dist/sentry/vue3.cjs.js +1 -0
  24. package/dist/sentry/vue3.es.js +1 -0
  25. package/dist/shared/core.cjs.js +1 -0
  26. package/dist/shared/core.es.js +1 -0
  27. package/dist/shared/sentry/shared-base.cjs.js +1 -0
  28. package/dist/shared/sentry/shared-base.es.js +1 -0
  29. package/dist/shared/sentry/shared-react.cjs.js +1 -0
  30. package/dist/shared/sentry/shared-react.es.js +1 -0
  31. package/dist/shared/sentry/shared-vue.cjs.js +1 -0
  32. package/dist/shared/sentry/shared-vue.es.js +1 -0
  33. package/package.json +48 -3
  34. package/dist/toAwaitFetch/toAwaitFetch.cjs.js +0 -1
  35. package/dist/toAwaitFetch/toAwaitFetch.es.js +0 -1
  36. package/dist/useInputNumber/index.cjs.js +0 -1
  37. package/dist/useInputNumber/index.es.js +0 -1
  38. package/dist/useRequestCache/index.cjs.js +0 -1
  39. package/dist/useRequestCache/index.es.js +0 -1
  40. package/dist/useTableRequest/index.cjs.js +0 -1
  41. package/dist/useTableRequest/index.es.js +0 -1
  42. package/dist/utils/utils.cjs.js +0 -1
  43. package/dist/utils/utils.es.js +0 -1
  44. package/dist/version.cjs.js +0 -1
  45. package/dist/version.es.js +0 -1
  46. package/docs/hooks/index.md +0 -33
  47. package/docs/hooks/toAwaitFetch.md +0 -430
  48. package/docs/hooks/useInputNumber.md +0 -355
  49. package/docs/hooks/useRequestCache.md +0 -232
  50. package/docs/hooks/useTableRequest.md +0 -532
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # xn-fe-tools
2
2
 
3
- 基于 Vue 3 Composition API 的工具库,当前主力能力是 `toAwaitFetch`:一个支持链式和解构两种模式的 HTTP 请求工具,内置错误处理、重试、全局配置与取消能力。
3
+ 基于 Vue 3 Composition API 的工具库,提供 HTTP 请求工具 `toAwaitFetch` Sentry 统一初始化工具集等能力。
4
4
 
5
5
  ## ✨ 特性
6
6
 
@@ -10,6 +10,7 @@
10
10
  - 多种请求/响应类型:JSON、FormData、Blob
11
11
  - 全局配置:baseURL、headers、validateStatus、validateResponse、transformResponse 等
12
12
  - TypeScript 全量类型定义,零外部依赖(基于原生 Fetch)
13
+ - **Sentry 统一初始化**:支持 Vue 3 / Vue 2 / React / 纯浏览器,零安装成本,主包体积不受影响
13
14
 
14
15
  ## 📦 安装
15
16
 
@@ -89,6 +90,61 @@ const [, error, success] = await request // 被取消时 error.type === 'timeout
89
90
  ```
90
91
 
91
92
 
93
+ ## 🛡️ Sentry 集成
94
+
95
+ 通过独立子路径引入,主包体积不受影响,Sentry SDK 已内置打包无需额外安装:
96
+
97
+ ```ts
98
+ // Vue 3(支持 Vue Router 路由追踪)
99
+ import { toVue3SentrySetup } from 'xn-fe-tools/sentry/vue3'
100
+
101
+ toVue3SentrySetup({
102
+ dsn: 'https://xxx@sentry.io/xxx',
103
+ app, // Vue 3 应用实例,必填
104
+ router, // Vue Router,可选
105
+ })
106
+
107
+ // Vue 2 / React / 纯浏览器
108
+ import { toVue2SentrySetup } from 'xn-fe-tools/sentry/vue2'
109
+ import { toReactSentrySetup } from 'xn-fe-tools/sentry/react'
110
+ import { toSentrySetup } from 'xn-fe-tools/sentry/browser'
111
+ ```
112
+
113
+ 返回值提供运行时控制能力:
114
+
115
+ ```ts
116
+ const { isInitialized, captureException, captureMessage, setUser } = toVue3SentrySetup({ ... })
117
+ ```
118
+
119
+ 简化配置参数(无需了解 Sentry 集成 API):
120
+
121
+ ```ts
122
+ toVue3SentrySetup({
123
+ dsn: '...',
124
+ app,
125
+ enableTracing: true, // 控制 browserTracingIntegration,默认 true
126
+ enableReplay: false, // 控制 replayIntegration,默认 true
127
+ breadcrumbs: { console: false }, // 控制面包屑行为
128
+ })
129
+ ```
130
+
131
+ Vite Source Map 上传配置辅助:
132
+
133
+ ```ts
134
+ // vite.config.ts
135
+ import { sentryVitePlugin } from '@sentry/vite-plugin' // 需单独安装为 devDependency
136
+ import { getSentryViteConfig } from 'xn-fe-tools/sentry/browser'
137
+
138
+ export default defineConfig({
139
+ plugins: [sentryVitePlugin(getSentryViteConfig({
140
+ org: 'my-org',
141
+ project: 'my-project',
142
+ authToken: process.env.SENTRY_AUTH_TOKEN,
143
+ }))],
144
+ build: { sourcemap: true },
145
+ })
146
+ ```
147
+
92
148
  ## 📦 版本信息
93
149
 
94
150
  ```ts
@@ -106,6 +162,8 @@ xn-fe-tools 内置了 [MCP(Model Context Protocol)](https://modelcontextprot
106
162
 
107
163
  在项目中创建 MCP 配置文件:
108
164
 
165
+ > **注意:** `xn-fe-tools-mcp` 是 `xn-fe-tools` 包内注册的 bin 命令,不是独立的 npm 包。必须通过 `-p` 参数指定包名。
166
+
109
167
  **Kiro** — `.kiro/settings/mcp.json`:
110
168
 
111
169
  ```json
@@ -113,7 +171,7 @@ xn-fe-tools 内置了 [MCP(Model Context Protocol)](https://modelcontextprot
113
171
  "mcpServers": {
114
172
  "xn-fe-tools": {
115
173
  "command": "npx",
116
- "args": ["xn-fe-tools-mcp"]
174
+ "args": ["-p", "xn-fe-tools", "xn-fe-tools-mcp"]
117
175
  }
118
176
  }
119
177
  }
@@ -126,7 +184,7 @@ xn-fe-tools 内置了 [MCP(Model Context Protocol)](https://modelcontextprot
126
184
  "mcpServers": {
127
185
  "xn-fe-tools": {
128
186
  "command": "npx",
129
- "args": ["xn-fe-tools-mcp"]
187
+ "args": ["-p", "xn-fe-tools", "xn-fe-tools-mcp"]
130
188
  }
131
189
  }
132
190
  }
@@ -139,7 +197,20 @@ xn-fe-tools 内置了 [MCP(Model Context Protocol)](https://modelcontextprot
139
197
  "mcpServers": {
140
198
  "xn-fe-tools": {
141
199
  "command": "npx",
142
- "args": ["xn-fe-tools-mcp"]
200
+ "args": ["-p", "xn-fe-tools", "xn-fe-tools-mcp"]
201
+ }
202
+ }
203
+ }
204
+ ```
205
+
206
+ 如果项目已安装 xn-fe-tools,也可以直接指向本地文件:
207
+
208
+ ```json
209
+ {
210
+ "mcpServers": {
211
+ "xn-fe-tools": {
212
+ "command": "node",
213
+ "args": ["node_modules/xn-fe-tools/dist/mcp/server.mjs"]
143
214
  }
144
215
  }
145
216
  }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * 面包屑配置,控制 breadcrumbsIntegration 的行为
3
+ */
4
+ export interface BreadcrumbsConfig {
5
+ /** 是否记录 console 输出,默认 true */
6
+ console?: boolean;
7
+ /** 是否记录 DOM 交互事件,默认 true */
8
+ dom?: boolean;
9
+ /** 是否记录 fetch 请求,默认 true */
10
+ fetch?: boolean;
11
+ /** 是否记录 XMLHttpRequest 请求,默认 true */
12
+ xhr?: boolean;
13
+ /** 是否记录浏览器导航历史,默认 true */
14
+ history?: boolean;
15
+ }
16
+ /**
17
+ * 所有框架通用的基础配置
18
+ */
19
+ export interface SentryBaseOptions {
20
+ /** Sentry DSN,必填 */
21
+ dsn: string;
22
+ /** 运行环境,默认 'production' */
23
+ environment?: string;
24
+ /** 是否启用 Sentry,默认 true */
25
+ enabled?: boolean;
26
+ /** 性能追踪采样率,默认 0.1(10%) */
27
+ tracesSampleRate?: number;
28
+ /** 会话回放采样率,默认 0.1(10%) */
29
+ replaysSessionSampleRate?: number;
30
+ /** 错误回放采样率,默认 1.0(100%) */
31
+ replaysOnErrorSampleRate?: number;
32
+ /**
33
+ * 是否启用 browserTracingIntegration,默认 true
34
+ * 简化配置参数,优先级高于 integrations 数组
35
+ */
36
+ enableTracing?: boolean;
37
+ /**
38
+ * 是否启用 replayIntegration,默认 true
39
+ * 简化配置参数,优先级高于 integrations 数组
40
+ */
41
+ enableReplay?: boolean;
42
+ /**
43
+ * 面包屑配置,传入时会使用该配置创建 breadcrumbsIntegration 并覆盖默认面包屑行为
44
+ * 简化配置参数,优先级高于 integrations 数组
45
+ */
46
+ breadcrumbs?: BreadcrumbsConfig;
47
+ /** 事件上报前的回调,可用于过滤或修改事件 */
48
+ beforeSend?: (event: unknown) => unknown | null;
49
+ /** 自定义 integrations 数组,与默认 integrations 合并 */
50
+ integrations?: unknown[];
51
+ /** 其他 Sentry 原生 init 配置项(透传) */
52
+ [key: string]: unknown;
53
+ }
54
+ /** Vue 3 专用配置 */
55
+ export interface Vue3SentryOptions extends SentryBaseOptions {
56
+ /** Vue 3 应用实例,必填 */
57
+ app: unknown;
58
+ /** Vue Router 实例,可选;提供时配置路由级别性能追踪 */
59
+ router?: unknown;
60
+ }
61
+ /** Vue 2 专用配置 */
62
+ export interface Vue2SentryOptions extends SentryBaseOptions {
63
+ /** Vue 2 构造函数,必填 */
64
+ Vue: unknown;
65
+ /** Vue Router 实例,可选;提供时配置路由级别性能追踪 */
66
+ router?: unknown;
67
+ }
68
+ /** React 专用配置 */
69
+ export interface ReactSentryOptions extends SentryBaseOptions {
70
+ /** React Router 相关配置,可选;提供时配置路由级别性能追踪 */
71
+ reactRouter?: unknown;
72
+ }
73
+ /** 纯浏览器配置(使用 @sentry/browser,无框架依赖) */
74
+ export interface BrowserSentryOptions extends SentryBaseOptions {
75
+ }
76
+ /**
77
+ * Sentry 初始化返回值
78
+ * 当 DSN 无效或 enabled=false 时,所有方法均为安全的空操作
79
+ */
80
+ export interface SentrySetupReturn {
81
+ /** Sentry 是否已成功初始化 */
82
+ isInitialized: boolean;
83
+ /** 手动上报异常,返回 event ID */
84
+ captureException: (error: unknown) => string | undefined;
85
+ /** 手动上报消息,返回 event ID */
86
+ captureMessage: (message: string) => string | undefined;
87
+ /** 设置/清除当前用户信息 */
88
+ setUser: (user: {
89
+ id?: string;
90
+ email?: string;
91
+ username?: string;
92
+ } | null) => void;
93
+ }
94
+ /** Source Map Vite 插件配置(用于 @sentry/vite-plugin) */
95
+ export interface SentryViteConfig {
96
+ /** Sentry 组织 slug */
97
+ org: string;
98
+ /** Sentry 项目 slug */
99
+ project: string;
100
+ /** Sentry Auth Token */
101
+ authToken: string;
102
+ /** Source Map 配置 */
103
+ sourcemaps?: {
104
+ /** 构建后自动删除的文件 glob,默认 ['./dist/\*\*\/*.map'] */
105
+ filesToDeleteAfterUpload?: string[];
106
+ };
107
+ /** 其他自定义配置 */
108
+ [key: string]: unknown;
109
+ }
110
+ export declare const SENTRY_DEFAULTS: {
111
+ readonly environment: "production";
112
+ readonly tracesSampleRate: 0.1;
113
+ readonly replaysSessionSampleRate: 0.1;
114
+ readonly replaysOnErrorSampleRate: 1;
115
+ readonly enableTracing: true;
116
+ readonly enableReplay: true;
117
+ };
118
+ /**
119
+ * 验证 DSN 是否有效(非空字符串且非 undefined)
120
+ */
121
+ export declare function isValidDsn(dsn: string | undefined): dsn is string;
122
+ /**
123
+ * 创建未初始化状态的返回值
124
+ * 用于 DSN 无效或 enabled=false 时返回
125
+ */
126
+ export declare function createUninitializedReturn(): SentrySetupReturn;
127
+ /**
128
+ * 根据 Simplified_Config 和用户 integrations 构建最终的 integrations 列表
129
+ *
130
+ * 优先级:Simplified_Config 参数 > integrations 数组 > 默认配置
131
+ *
132
+ * @param options - 用户配置
133
+ * @param frameworkIntegrations - 框架特定的集成(如 Vue Router 路由追踪),已根据 options 构建
134
+ * @param sentry - Sentry SDK 对象(包含 browserTracingIntegration、replayIntegration、breadcrumbsIntegration)
135
+ */
136
+ export declare function buildIntegrations(options: SentryBaseOptions, frameworkIntegrations: unknown[], sentry: {
137
+ browserTracingIntegration: (opts?: unknown) => unknown;
138
+ replayIntegration: (opts?: unknown) => unknown;
139
+ breadcrumbsIntegration: (opts?: unknown) => unknown;
140
+ }): unknown[];
141
+ /**
142
+ * 合并用户配置与默认配置
143
+ * 提取 Simplified_Config 参数(enableTracing、enableReplay、breadcrumbs),
144
+ * 返回干净的 Sentry init 配置对象
145
+ */
146
+ export declare function mergeConfig<T extends SentryBaseOptions>(userConfig: T): Omit<T, 'enableTracing' | 'enableReplay' | 'breadcrumbs'>;
147
+ /**
148
+ * 生成 @sentry/vite-plugin 的配置对象
149
+ * 注意:该函数仅生成配置对象,不依赖 @sentry/vite-plugin(由用户自行安装为 devDependency)
150
+ *
151
+ * @param config - 包含 org、project、authToken 和可选 sourcemaps 配置
152
+ * @returns 完整的 Vite 插件配置对象
153
+ */
154
+ export declare function getSentryViteConfig(config: SentryViteConfig): SentryViteConfig;
155
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/hooks/toSentrySetup/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * toSentrySetup 统一导出
3
+ *
4
+ * 注意:此文件不被主入口 src/index.ts 引用,保持主入口与 Sentry 代码完全隔离。
5
+ * 用户应通过 sub-path exports 使用:
6
+ * - xn-fe-tools/sentry/vue3
7
+ * - xn-fe-tools/sentry/vue2
8
+ * - xn-fe-tools/sentry/react
9
+ * - xn-fe-tools/sentry/browser
10
+ */
11
+ export { toVue3SentrySetup } from './toVue3SentrySetup';
12
+ export { toVue2SentrySetup } from './toVue2SentrySetup';
13
+ export { toReactSentrySetup } from './toReactSentrySetup';
14
+ export { toSentrySetup } from './toSentrySetup';
15
+ export { getSentryViteConfig } from './core';
16
+ export type { BreadcrumbsConfig, SentryBaseOptions, Vue3SentryOptions, Vue2SentryOptions, ReactSentryOptions, BrowserSentryOptions, SentrySetupReturn, SentryViteConfig, } from './core';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/toSentrySetup/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAA;AAE5C,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,QAAQ,CAAA"}
@@ -0,0 +1,21 @@
1
+ import { type ReactSentryOptions, type SentrySetupReturn } from './core';
2
+ /**
3
+ * React Sentry 初始化
4
+ *
5
+ * @param options - 包含 dsn 必填参数的配置对象
6
+ * @returns SentrySetupReturn
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { toReactSentrySetup } from 'xn-fe-tools/sentry/react'
11
+ *
12
+ * toReactSentrySetup({
13
+ * dsn: 'https://xxx@sentry.io/xxx',
14
+ * })
15
+ * ```
16
+ */
17
+ export declare function toReactSentrySetup(options: ReactSentryOptions): SentrySetupReturn;
18
+ export { breadcrumbsIntegration, browserTracingIntegration, replayIntegration, feedbackIntegration, httpClientIntegration, captureConsoleIntegration, contextLinesIntegration, extraErrorDataIntegration, reportingObserverIntegration, } from '@sentry/react';
19
+ export type { ReactSentryOptions, SentrySetupReturn, SentryBaseOptions, BreadcrumbsConfig, SentryViteConfig } from './core';
20
+ export { getSentryViteConfig } from './core';
21
+ //# sourceMappingURL=toReactSentrySetup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toReactSentrySetup.d.ts","sourceRoot":"","sources":["../../../src/hooks/toSentrySetup/toReactSentrySetup.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EAKvB,MAAM,QAAQ,CAAA;AAEf;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CAoCjF;AAGD,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,4BAA4B,GAC7B,MAAM,eAAe,CAAA;AAEtB,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAA;AAC3H,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAA"}
@@ -0,0 +1,21 @@
1
+ import { type BrowserSentryOptions, type SentrySetupReturn } from './core';
2
+ /**
3
+ * 纯浏览器 Sentry 初始化(适用于非框架项目或原生 JS)
4
+ *
5
+ * @param options - 包含 dsn 必填参数的配置对象
6
+ * @returns SentrySetupReturn
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { toSentrySetup } from 'xn-fe-tools/sentry/browser'
11
+ *
12
+ * const { isInitialized, captureException } = toSentrySetup({
13
+ * dsn: 'https://xxx@sentry.io/xxx',
14
+ * })
15
+ * ```
16
+ */
17
+ export declare function toSentrySetup(options: BrowserSentryOptions): SentrySetupReturn;
18
+ export { breadcrumbsIntegration, browserTracingIntegration, replayIntegration, feedbackIntegration, httpClientIntegration, captureConsoleIntegration, contextLinesIntegration, extraErrorDataIntegration, reportingObserverIntegration, } from '@sentry/browser';
19
+ export type { BrowserSentryOptions, SentrySetupReturn, SentryBaseOptions, BreadcrumbsConfig, SentryViteConfig } from './core';
20
+ export { getSentryViteConfig } from './core';
21
+ //# sourceMappingURL=toSentrySetup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toSentrySetup.d.ts","sourceRoot":"","sources":["../../../src/hooks/toSentrySetup/toSentrySetup.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EAKvB,MAAM,QAAQ,CAAA;AAEf;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,iBAAiB,CA6B9E;AAGD,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,4BAA4B,GAC7B,MAAM,iBAAiB,CAAA;AAExB,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAA;AAC7H,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAA"}
@@ -0,0 +1,23 @@
1
+ import { type Vue2SentryOptions, type SentrySetupReturn } from './core';
2
+ /**
3
+ * Vue 2 Sentry 初始化
4
+ *
5
+ * @param options - 包含 dsn 和 Vue(Vue 2 构造函数)必填参数的配置对象
6
+ * @returns SentrySetupReturn
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import Vue from 'vue'
11
+ * import Router from 'vue-router'
12
+ * import { toVue2SentrySetup } from 'xn-fe-tools/sentry/vue2'
13
+ *
14
+ * const router = new Router({ ... })
15
+ *
16
+ * toVue2SentrySetup({ dsn: 'https://xxx@sentry.io/xxx', Vue, router })
17
+ * ```
18
+ */
19
+ export declare function toVue2SentrySetup(options: Vue2SentryOptions): SentrySetupReturn;
20
+ export { breadcrumbsIntegration, browserTracingIntegration, replayIntegration, feedbackIntegration, httpClientIntegration, captureConsoleIntegration, contextLinesIntegration, extraErrorDataIntegration, reportingObserverIntegration, } from '@sentry/vue';
21
+ export type { Vue2SentryOptions, SentrySetupReturn, SentryBaseOptions, BreadcrumbsConfig, SentryViteConfig } from './core';
22
+ export { getSentryViteConfig } from './core';
23
+ //# sourceMappingURL=toVue2SentrySetup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toVue2SentrySetup.d.ts","sourceRoot":"","sources":["../../../src/hooks/toSentrySetup/toVue2SentrySetup.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EAKvB,MAAM,QAAQ,CAAA;AAEf;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,iBAAiB,CAkC/E;AAGD,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,4BAA4B,GAC7B,MAAM,aAAa,CAAA;AAEpB,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAA;AAC1H,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAA"}
@@ -0,0 +1,24 @@
1
+ import { type Vue3SentryOptions, type SentrySetupReturn } from './core';
2
+ /**
3
+ * Vue 3 Sentry 初始化
4
+ *
5
+ * @param options - 包含 dsn 和 app(Vue 3 应用实例)必填参数的配置对象
6
+ * @returns SentrySetupReturn
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { createApp } from 'vue'
11
+ * import { useRouter } from 'vue-router'
12
+ * import { toVue3SentrySetup } from 'xn-fe-tools/sentry/vue3'
13
+ *
14
+ * const app = createApp(App)
15
+ * const router = createRouter({ ... })
16
+ *
17
+ * toVue3SentrySetup({ dsn: 'https://xxx@sentry.io/xxx', app, router })
18
+ * ```
19
+ */
20
+ export declare function toVue3SentrySetup(options: Vue3SentryOptions): SentrySetupReturn;
21
+ export { breadcrumbsIntegration, browserTracingIntegration, replayIntegration, feedbackIntegration, httpClientIntegration, captureConsoleIntegration, contextLinesIntegration, extraErrorDataIntegration, reportingObserverIntegration, } from '@sentry/vue';
22
+ export type { Vue3SentryOptions, SentrySetupReturn, SentryBaseOptions, BreadcrumbsConfig, SentryViteConfig } from './core';
23
+ export { getSentryViteConfig } from './core';
24
+ //# sourceMappingURL=toVue3SentrySetup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toVue3SentrySetup.d.ts","sourceRoot":"","sources":["../../../src/hooks/toSentrySetup/toVue3SentrySetup.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EAKvB,MAAM,QAAQ,CAAA;AAEf;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,iBAAiB,CAkC/E;AAGD,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,4BAA4B,GAC7B,MAAM,aAAa,CAAA;AAEpB,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAA;AAC1H,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAA"}
package/dist/index.cjs.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./toAwaitFetch/toAwaitFetch.cjs.js"),s=require("./useTableRequest/index.cjs.js"),t=require("./useInputNumber/index.cjs.js"),o=require("./useRequestCache/index.cjs.js"),r=require("./version.cjs.js");exports.cancel=e.cancel,exports.createInstance=e.createInstance,exports.sendGet=e.sendGet,exports.sendGetBlob=e.sendGetBlob,exports.sendPost=e.sendPost,exports.sendPostBlob=e.sendPostBlob,exports.sendPostForm=e.sendPostForm,exports.setGlobalConfig=e.setGlobalConfig,exports.toAwaitFetch=e.default,exports.getTableRequestGlobalConfig=s.getTableRequestGlobalConfig,exports.setTableRequestGlobalConfig=s.setTableRequestGlobalConfig,exports.useTableRequest=s.useTableRequest,exports.useInputNumber=t.useInputNumber,exports.useRequestCache=o.useRequestCache,exports.VERSION=r.VERSION,exports.getVersion=r.getVersion;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),t=e=>!("object"!=typeof e||null===e||Array.isArray(e)||e instanceof Date||e instanceof RegExp||e instanceof File||e instanceof Blob||"undefined"!=typeof FormData&&e instanceof FormData),r=(e,n)=>{const o={...e};for(const s in n){if(!Object.prototype.hasOwnProperty.call(n,s))continue;const e=n[s];if(void 0===e)continue;const a=o[s];t(e)&&t(a)?o[s]=r(a,e):o[s]=e}return o},n=e=>e>=200&&e<300,o=()=>!0,s=e=>new Promise(t=>setTimeout(t,e)),a=async e=>{if(!(e=>{if(!e)return!0;if(204===e.status||205===e.status||304===e.status)return!0;const t=e.headers.get("content-length");return!(!t||0!==Number(t))})(e))try{return await e.json()}catch(t){let n;try{n=await e.text()}catch{return}if(!n.trim())return;try{return JSON.parse(n)}catch(r){return}}},i=(e,t,r,n,o)=>({message:e,type:t,status:r,response:n,error:o}),u=e=>{if(e instanceof Error){const t=new Error(e.message);return e.name&&(t.name=e.name),e.stack&&(t.stack=e.stack),t}return new Error(String(e))},c=async(e,t,r)=>!!e?.enabled&&(!(t>(e.maxRetryCount??3))&&(e.shouldRetry?await e.shouldRetry(t,r):"network"===r.type||"timeout"===r.type)),l=(e,t)=>{const r=Object.create(e);let n=!1,o=!1,s=!1;const a=e.then.bind(e),i=e.catch.bind(e),u=a(e=>{s=!0===e.__errorSuppressed,delete e.__errorSuppressed;const t=new Proxy(e,{get(e,t){if(("1"===t||"number"==typeof t&&1===t)&&(o=!0),t===Symbol.iterator){const t=e[Symbol.iterator]();return function*(){let e=0;for(const r of t)1===e&&(o=!0),yield r,e++}}return e[t]}}),r=e[1];return e[2]||!r||s||n||queueMicrotask(()=>{queueMicrotask(()=>{if(!(o||o||n||s)){const e=new Error(`Unhandled fetch error: ${r.message} (type: ${r.type})`);throw e.fetchError=r,e}})}),t});r.cancel=()=>{t&&t()};const c=u.then.bind(u);return r.then=function(e,r){return e&&"function"==typeof e&&!r&&e.length<=2?l(c(t=>{const r=t[2],n=t[0],o=t[3];return r&&void 0!==n&&e(n,o),t}),t):c(e,r)},r.catchHttp=function(e){n=!0;const r=c(t=>{const r=t[2],n=t[1];return!r&&n&&"http"===n.type&&e(n),!r&&n&&(t.__errorSuppressed=!0),t});return l(r,t)},r.catchBusiness=function(e){n=!0;const r=c(t=>{const r=t[1],n=t[2];return!n&&r&&"business"===r.type&&e(r),!n&&r&&(t.__errorSuppressed=!0),t});return l(r,t)},r.catchNetwork=function(e){if(n=!0,e&&"function"==typeof e){const r=c(t=>{const r=t[1],n=t[2];return!n&&r&&e(r),!n&&r&&(t.__errorSuppressed=!0),t});return l(r,t)}return i(e)},r};class d{globalConfig={};constructor(e){e&&(this.globalConfig={...e}),this.request=this.request.bind(this),this.sendGet=this.sendGet.bind(this),this.sendPost=this.sendPost.bind(this),this.sendPostForm=this.sendPostForm.bind(this),this.sendPostBlob=this.sendPostBlob.bind(this),this.sendGetBlob=this.sendGetBlob.bind(this),this.setGlobalConfig=this.setGlobalConfig.bind(this)}async executeRequest(e,r,l=1){try{const y=e,w=y.signal;w&&(w.aborted?r.abort():w.addEventListener("abort",()=>r.abort(),{once:!0}));const b=(d=y.headers,f=y.url,p=y.method,d?"function"==typeof d?d({url:f,method:p}):d:{}),{body:v,urlParams:S}=((e,r,n)=>{if(!e)return{};if("GET"===r||"HEAD"===r||"OPTIONS"===r){if(t(e)){const t=new URLSearchParams;for(const r in e)if(Object.prototype.hasOwnProperty.call(e,r)){const n=e[r];null!=n&&t.append(r,String(n))}return{urlParams:t.toString()}}return{}}if("form"===n&&e instanceof FormData)return{body:e};if("form"===n&&t(e)){const t=new FormData;for(const r in e)if(Object.prototype.hasOwnProperty.call(e,r)){const n=e[r];null!=n&&(n instanceof File||n instanceof Blob?t.append(r,n):t.append(r,String(n)))}return{body:t}}return"json"===n?{body:JSON.stringify(e)}:"text"===n?{body:String(e)}:"blob"===n&&e instanceof Blob||"arraybuffer"===n&&e instanceof ArrayBuffer?{body:e}:{body:String(e)}})(y.data,y.method||"GET",y.requestType||"json"),x=((e,t,r)=>{if(t.startsWith("http://")||t.startsWith("https://")){if(r){const e=t.includes("?")?"&":"?";return`${t}${e}${r}`}return t}let n=t;e&&(n=`${e.endsWith("/")?e.slice(0,-1):e}${t.startsWith("/")?t:`/${t}`}`);if(r){const e=n.includes("?")?"&":"?";n=`${n}${e}${r}`}return n})(y.baseURL,y.url,S),E=y.timeout;let q,P=!1,T=b;v&&"string"==typeof v&&"json"===y.requestType?T={"Content-Type":"application/json",...b}:v instanceof FormData&&(T=b);const R=new AbortController,B=()=>R.abort();r.signal.addEventListener("abort",B);const $={method:y.method||"GET",headers:T,body:v,mode:"cors",credentials:!1===y.withCredentials?"same-origin":"include",signal:R.signal},C=fetch(x,$);let G;try{if(E){const e=new Promise((e,t)=>{q=setTimeout(()=>{P=!0,R.abort(),t(i("Request timeout","timeout"))},E)});G=await Promise.race([C,e])}else G=await C}catch(g){if(q&&clearTimeout(q),P){const e=i("Request timeout","timeout");if(await c(y.retry,l,e))return r.signal.removeEventListener("abort",B),await s(y.retry?.delay||1e3),this.executeRequest(y,r,l+1);let t=!1;if(y.onNetworkError){const r=()=>{t=!0};await y.onNetworkError(u(new Error(e.message)),r)}const n=[void 0,e,!1,void 0];return n.__errorSuppressed=t,r.signal.removeEventListener("abort",B),n}throw g}finally{q&&clearTimeout(q),r.signal.removeEventListener("abort",B)}const _=y.responseType||"json";let D;try{D=await(async(e,t)=>{if(!e)throw new Error("No response received");switch(t){case"json":default:return await a(e);case"text":return await e.text();case"blob":return await e.blob();case"arraybuffer":return await e.arrayBuffer();case"formData":return await e.formData()}})(G,_)}catch(h){const e=i("Failed to parse response","network",G.status,void 0,h instanceof Error?h:new Error(String(h)));if(await c(y.retry,l,e))return await s(y.retry?.delay||1e3),this.executeRequest(y,r,l+1);let t=!1;if(y.onNetworkError){const r=()=>{t=!0};await y.onNetworkError(u(e.error||new Error(e.message)),r)}const n=[void 0,e,!1,void 0];return n.__errorSuppressed=t,n}if(!(y.validateStatus||n)(G.status)){const e=i(`HTTP Error: ${G.status} ${G.statusText}`,"http",G.status,D);if(await c(y.retry,l,e))return await s(y.retry?.delay||1e3),this.executeRequest(y,r,l+1);let t=!1;if(y.onHttpError){const r=()=>{t=!0},n=new Error(e.message);await y.onHttpError(n,G.status,D,r)}const n=[void 0,e,!1,{data:D,status:G.status,statusText:G.statusText,headers:G.headers,response:G}];return n.__errorSuppressed=t,n}if(!(y.validateResponse||o)(D)){const e=i("Business validation failed","business",G.status,D);if(await c(y.retry,l,e))return await s(y.retry?.delay||1e3),this.executeRequest(y,r,l+1);let t=!1;if(y.onBusinessError){const r=()=>{t=!0},n=new Error(e.message);await y.onBusinessError(n,D,r)}const n=[void 0,e,!1,{data:D,status:G.status,statusText:G.statusText,headers:G.headers,response:G}];return n.__errorSuppressed=t,n}let F=D;if(y.transformResponse)try{F=y.transformResponse(D)}catch(m){console.warn("[toAwaitFetch] transformResponse error:",m)}return[F,void 0,!0,{data:D,status:G.status,statusText:G.statusText,headers:G.headers,response:G}]}catch(g){const t=(e=>e instanceof DOMException&&"AbortError"===e.name)(g),n=i(t?"Request aborted":g instanceof Error?g.message:"Network error","network",void 0,void 0,g instanceof Error?g:new Error(String(g)));if(!t&&await c(e.retry,l,n))return await s(e.retry?.delay||1e3),this.executeRequest(e,r,l+1);let o=!1;if(e.onNetworkError){const t=()=>{o=!0};await e.onNetworkError(u(n.error||new Error(n.message)),t)}const a=[void 0,n,!1,void 0];return a.__errorSuppressed=o,a}var d,f,p}request(e){const t=r({...this.globalConfig},e),n=new AbortController,o=this.executeRequest(t,n);return l(o,()=>n.abort())}setGlobalConfig(e){this.globalConfig={...e}}getGlobalConfig(){return{...this.globalConfig}}mergeGlobalConfig(e){this.globalConfig=r(this.globalConfig,e)}sendGet(e,t,r){return this.request({...r,url:e,method:"GET",data:t})}sendPost(e,t,r){return this.request({...r,url:e,method:"POST",data:t,requestType:"json"})}sendPostForm(e,t,r){return this.request({...r,url:e,method:"POST",data:t,requestType:"form"})}sendPostBlob(e,t,r){return this.request({...r,url:e,method:"POST",data:t,requestType:"json",responseType:"blob"})}sendGetBlob(e,t,r){return this.request({...r,url:e,method:"GET",data:t,responseType:"blob"})}}const f=e=>new d(e),p=new d,g=e=>{e?.cancel?.()},h=Object.assign(e=>e&&"object"==typeof e&&"url"in e?p.request(e):f(e),{create:f,sendGet:p.sendGet.bind(p),sendPost:p.sendPost.bind(p),sendPostForm:p.sendPostForm.bind(p),sendPostBlob:p.sendPostBlob.bind(p),sendGetBlob:p.sendGetBlob.bind(p),setGlobalConfig:p.setGlobalConfig.bind(p),cancel:g});function m(e,t){if(!e||!t)return;const r=t.replace(/\[(\d+)\]/g,".$1").split(".").filter(Boolean);let n=e;for(const o of r){if(null==n)return;n=n[o]}return n}function y(t){return"function"==typeof t?t():e.unref(t)}function w(t,r){"undefined"!=typeof __DEV__&&__DEV__&&void 0!==t&&!function(t){return"function"==typeof t||e.isRef(t)}(t)&&console.warn(`[${r}] 检测到 params 是普通对象,参数变化将不会触发请求更新。\n请使用 computed() 或 getter 函数包装:`)}const b={};const v=new Map,S=new Map,x=new Map,E=new Set;let q=null;const P=(e,t)=>new Promise((r,n)=>{if(q)return r(q);const o=indexedDB.open(e,1);o.onupgradeneeded=e=>{const r=e.target.result;r.objectStoreNames.contains(t)||r.createObjectStore(t)},o.onsuccess=e=>{q=e.target.result,r(q)},o.onerror=e=>{n(e.target.error)}});const T="1.6.0";exports.VERSION=T,exports.cancel=g,exports.createInstance=f,exports.getTableRequestGlobalConfig=function(){return{...b,pagination:{...b.pagination}}},exports.getVersion=function(){return T},exports.sendGet=(e,t,r)=>p.request({...r,url:e,method:"GET",data:t}),exports.sendGetBlob=(e,t,r)=>p.sendGetBlob(e,t,r),exports.sendPost=(e,t,r)=>p.sendPost(e,t,r),exports.sendPostBlob=(e,t,r)=>p.sendPostBlob(e,t,r),exports.sendPostForm=(e,t,r)=>p.sendPostForm(e,t,r),exports.setGlobalConfig=e=>{p.setGlobalConfig(e)},exports.setTableRequestGlobalConfig=function(e){Object.assign(b,e),e.pagination&&(b.pagination={...b.pagination,...e.pagination})},exports.toAwaitFetch=h,exports.useInputNumber=function(t,r){let n,o;null===t||"object"!=typeof t||e.isRef(t)?(n=t,o=r||{}):(o=t,n="");const s=()=>e.toValue(o.precision)??0,a=()=>e.toValue(o.showThousands)??!1,i=e.ref(e.toValue(n)?.toString()??""),u=e.computed(()=>{let e=i.value;if(a()){const[t,r]=e.split(".");let n=t.replace(/\B(?=(\d{3})+(?!\d))/g,",");return r?n+=`.${r}`:e.includes(".")&&(n+="."),n}return e}),c=t=>{let r=null==t?"":t.toString().trim();const n=e.toValue(o.allowNegative)?/[^\d.-]/g:/[^\d.]/g;r=r.replace(n,""),r=r.replace(/^-/,"$#$").replace(/-/g,"").replace("$#$","-"),r.length>1&&r.startsWith("0")&&"."!==r[1]&&(r=r.replace(/^0+/,""),""===r&&(r="0")),r.startsWith("-0")&&r.length>2&&"."!==r[2]&&(r="-"+r.slice(2).replace(/^0+/,""),"-"===r&&(r="-0"));const a=s();if(a>0){r=r.replace(/^\./g,"").replace(/\./g,"$#$").replace(/\./g,"").replace("$#$",".");const t=r.indexOf(".");if(-1!==t){if(r.slice(t+1).length>a){const n=e.toValue(o.decimalLimitMode)??"discard";if("discard"===n)r=r.slice(0,t+a+1);else{const e=Math.pow(10,a);let o=Number(r);isNaN(o)?r=r.slice(0,t+a+1):("round"===n?o=Math.round(o*e)/e:"ceil"===n&&(o=Math.ceil(o*e)/e),r=o.toString())}}}}else r=r.replace(/\./g,"");return r};return e.watch(()=>e.toValue(n),e=>{const t=null==e?"":e.toString();t!==i.value&&(i.value=t)}),{value:i,displayValue:u,handleInput:e=>{const t=c(e);i.value=t},handleBlur:()=>{if(!i.value)return;let t=Number(i.value);const r=o.max??1/0,n=o.min??-1/0;t>r&&(t=r,i.value=r.toString()),t<n&&(t=n,i.value=n.toString());const a=e.toValue(o.autoFixed)??!1;i.value=!0===a||"pad"===a?t.toFixed(s()):"trim"===a?Number(t.toFixed(s())).toString():t.toString()},formatter:e=>u.value,parser:e=>a()?e.replace(/,/g,""):e,clean:c}},exports.useRequestCache=function(t){const{requestFn:r,cacheKey:n,cacheTime:o=3e5,storage:s="memory",params:a,transformResult:i,immediate:u=!0,storageKeyPrefix:c="req_cache_",forceRefreshOnFirst:l=!1,dbName:d="RequestCacheDB",storeName:f="request_cache",onSuccess:p,onError:g}=t,h=(e=>{if("undefined"==typeof window)return"memory";try{if("localStorage"===e&&!window.localStorage)throw new Error;if("sessionStorage"===e&&!window.sessionStorage)throw new Error;if("indexedDB"===e&&!window.indexedDB)throw new Error;return e}catch(t){return console.warn(`[useRequestCache] ${e} is not supported in this environment, falling back to 'memory' mode.`),"memory"}})(y(s)),m=e.ref(),w=e.ref(!1),b=e.ref(null),q=()=>{const e=a?y(a):{};if("function"==typeof n)try{return n(e)}catch(t){return console.warn("[useRequestCache] Generate key failed",t),""}return n},T=async e=>{if("indexedDB"===h){try{const t=await P(d,f);return new Promise((r,n)=>{const o=t.transaction([f],"readwrite").objectStore(f).delete(`${c}${e}`);o.onsuccess=()=>r(),o.onerror=()=>n(o.error)})}catch(r){console.warn("[useRequestCache] IndexedDB delete failed",r)}return}const t="localStorage"===h?localStorage:"sessionStorage"===h?sessionStorage:null;t&&t.removeItem(`${c}${e}`)},R=async(e=!1)=>{const t=q();if(!t)return void console.warn("[useRequestCache] Cache key is empty, skipping request");const n=y(l)&&!E.has(t),s=e||n,u=a?y(a):{};if(!s&&"indexedDB"!==h){const e=v.get(t);if(e){if(Date.now()-e.timestamp<o)return m.value=i?i(e.data):e.data,p&&p(m.value),m.value;v.delete(t)}}w.value=!0,b.value=null;try{if(S.has(t)){if(p||g){const e=x.get(t);e&&(p&&e.onSuccess.push(p),g&&e.onError.push(g))}const e=await S.get(t);return m.value=i?i(e):e,m.value}if(!s&&"memory"!==h){const e=await(async e=>{if("indexedDB"===h)try{const t=await P(d,f);return new Promise(r=>{const n=t.transaction([f],"readonly").objectStore(f).get(`${c}${e}`);n.onsuccess=()=>r(n.result||null),n.onerror=()=>r(null)})}catch(r){return console.warn("[useRequestCache] IndexedDB read failed",r),null}const t="localStorage"===h?localStorage:"sessionStorage"===h?sessionStorage:null;if(!t)return null;try{const r=t.getItem(`${c}${e}`);if(r)return JSON.parse(r)}catch(r){console.warn("[useRequestCache] Read storage failed",r)}return null})(t);if(e){if(Date.now()-e.timestamp<o)return"indexedDB"!==h&&v.set(t,e),m.value=i?i(e.data):e.data,p&&p(m.value),m.value;await T(t)}}const e=r(u);S.set(t,e),x.set(t,{onSuccess:p?[p]:[],onError:g?[g]:[]});try{const r=await e,o={data:r,timestamp:Date.now()};"indexedDB"!==h&&v.set(t,o),"memory"!==h&&await(async(e,t)=>{if("indexedDB"===h){try{const r=await P(d,f);return new Promise((n,o)=>{const s=r.transaction([f],"readwrite").objectStore(f).put(t,`${c}${e}`);s.onsuccess=()=>n(),s.onerror=()=>o(s.error)})}catch(n){console.warn("[useRequestCache] IndexedDB write failed",n)}return}const r="localStorage"===h?localStorage:"sessionStorage"===h?sessionStorage:null;if(r)try{r.setItem(`${c}${e}`,JSON.stringify(t))}catch(n){console.warn("[useRequestCache] Write storage failed",n)}})(t,o),n&&E.add(t),m.value=i?i(r):r;const s=x.get(t);if(s&&s.onSuccess){[...s.onSuccess].forEach(e=>e(m.value))}return S.delete(t),x.delete(t),m.value}catch(R){b.value=R;const e=x.get(t);if(e&&e.onError){[...e.onError].forEach(e=>e(R))}throw S.delete(t),x.delete(t),R}}catch(R){throw b.value=R,R}finally{w.value=!1}},B=()=>R(!1);return a?e.watch(()=>y(a),()=>{B()},{deep:!0,immediate:u}):u&&B(),{data:m,loading:w,error:b,run:B,refresh:()=>R(!0),clearCache:async e=>{const t=e||q();t&&(v.delete(t),"memory"!==h&&await T(t))}}},exports.useTableRequest=function(t,r={}){const n={...b.pagination,...r.pagination},{params:o,immediate:s=b.immediate??!0,debounceDelay:a=b.debounceDelay??0,dataField:i=b.dataField??"",totalField:u=b.totalField??"",currentPageField:c=b.currentPageField??"",transformParams:l,transformResult:d,onSuccess:f,onError:p,incremental:g=b.incremental??!1}=r,{defaultPage:h=1,defaultPageSize:v=10,pageKey:S="page",pageSizeKey:x="pageSize"}=n,E=e.ref([]),q=e.ref(!1),P=e.ref(null),T=e.reactive({page:h,pageSize:v,total:0});let R=0;async function B(){const e=++R;q.value=!0,P.value=null;try{const r=o?y(o):{},n={[S]:T.page,[x]:T.pageSize};let s;s=l?l(r,{page:T.page,pageSize:T.pageSize}):{...r,...n};const a=await t(s);if(e!==R)return;if(d){const e=d(a);if(e&&"object"==typeof e&&Array.isArray(e.list)){const t=e.list;g&&T.page>h?E.value=[...E.value,...t]:E.value=t,T.total="number"==typeof e.total?e.total:e.list.length}else E.value=[],T.total=0,console.warn("[useTableRequest] transformResult 返回格式无法识别,请返回 { list: T[], total: number } 格式。")}else{const e=a;if(Array.isArray(e))g&&T.page>h?E.value=[...E.value,...e]:E.value=e,T.total=e.length;else if(e&&"object"==typeof e){if(i&&""!==i.trim()){const t=m(e,i)||[];g&&T.page>h?E.value=[...E.value,...t]:E.value=t}else E.value=[];u&&""!==u.trim()?T.total=m(e,u)??0:T.total=0}else E.value=[],T.total=0}if(c&&""!==c.trim()){const e=m(a,c);"number"==typeof e&&e!==T.page&&(console.warn(`[useTableRequest] 后端返回页码(${e})与客户端页码(${T.page})不一致,已自动修正`),T.page=e)}f?.(E.value,a)}catch(r){if(e!==R)return;P.value=r instanceof Error?r:new Error(String(r)),p?.(P.value)}finally{e===R&&(q.value=!1)}}const $=a>0?function(e,t){let r=null;return(...n)=>{r&&clearTimeout(r),r=setTimeout(()=>{e(...n),r=null},t)}}(B,a):B;let C=!1;async function G(){await B()}return e.watch(()=>[T.page,T.pageSize],()=>{C||$()}),o&&(w(o,"useTableRequest"),e.watch(()=>y(o),()=>{C=!0,T.page=h,C=!1,$()},{deep:!0})),s&&B(),{data:E,loading:q,error:P,pagination:T,run:G,onPageChange:async function(e){const t=T.page!==e;T.page=e,t||await B()},onSizeChange:async function(e){const t=T.pageSize!==e,r=T.page!==h;T.pageSize=e,T.page=h,t||r||await B()},refresh:async function(){g?(C=!0,T.page=h,E.value=[],await e.nextTick(),C=!1,await B()):await G()}}};
package/dist/index.es.js CHANGED
@@ -1 +1 @@
1
- import{cancel as e,createInstance as t,sendGet as s,sendGetBlob as o,sendPost as r,sendPostBlob as i,sendPostForm as m,setGlobalConfig as a,default as u}from"./toAwaitFetch/toAwaitFetch.es.js";import{getTableRequestGlobalConfig as p,setTableRequestGlobalConfig as f,useTableRequest as j}from"./useTableRequest/index.es.js";import{useInputNumber as n}from"./useInputNumber/index.es.js";import{useRequestCache as c}from"./useRequestCache/index.es.js";import{VERSION as d,getVersion as h}from"./version.es.js";export{d as VERSION,e as cancel,t as createInstance,p as getTableRequestGlobalConfig,h as getVersion,s as sendGet,o as sendGetBlob,r as sendPost,i as sendPostBlob,m as sendPostForm,a as setGlobalConfig,f as setTableRequestGlobalConfig,u as toAwaitFetch,n as useInputNumber,c as useRequestCache,j as useTableRequest};
1
+ import{unref as e,isRef as t,ref as r,reactive as n,watch as o,nextTick as s,toValue as a,computed as i}from"vue";const u=e=>!("object"!=typeof e||null===e||Array.isArray(e)||e instanceof Date||e instanceof RegExp||e instanceof File||e instanceof Blob||"undefined"!=typeof FormData&&e instanceof FormData),c=(e,t)=>{const r={...e};for(const n in t){if(!Object.prototype.hasOwnProperty.call(t,n))continue;const e=t[n];if(void 0===e)continue;const o=r[n];u(e)&&u(o)?r[n]=c(o,e):r[n]=e}return r},l=e=>e>=200&&e<300,d=()=>!0,f=e=>new Promise(t=>setTimeout(t,e)),p=async e=>{if(!(e=>{if(!e)return!0;if(204===e.status||205===e.status||304===e.status)return!0;const t=e.headers.get("content-length");return!(!t||0!==Number(t))})(e))try{return await e.json()}catch(t){let n;try{n=await e.text()}catch{return}if(!n.trim())return;try{return JSON.parse(n)}catch(r){return}}},g=(e,t,r,n,o)=>({message:e,type:t,status:r,response:n,error:o}),h=e=>{if(e instanceof Error){const t=new Error(e.message);return e.name&&(t.name=e.name),e.stack&&(t.stack=e.stack),t}return new Error(String(e))},m=async(e,t,r)=>!!e?.enabled&&(!(t>(e.maxRetryCount??3))&&(e.shouldRetry?await e.shouldRetry(t,r):"network"===r.type||"timeout"===r.type)),y=(e,t)=>{const r=Object.create(e);let n=!1,o=!1,s=!1;const a=e.then.bind(e),i=e.catch.bind(e),u=a(e=>{s=!0===e.__errorSuppressed,delete e.__errorSuppressed;const t=new Proxy(e,{get(e,t){if(("1"===t||"number"==typeof t&&1===t)&&(o=!0),t===Symbol.iterator){const t=e[Symbol.iterator]();return function*(){let e=0;for(const r of t)1===e&&(o=!0),yield r,e++}}return e[t]}}),r=e[1];return e[2]||!r||s||n||queueMicrotask(()=>{queueMicrotask(()=>{if(!(o||o||n||s)){const e=new Error(`Unhandled fetch error: ${r.message} (type: ${r.type})`);throw e.fetchError=r,e}})}),t});r.cancel=()=>{t&&t()};const c=u.then.bind(u);return r.then=function(e,r){return e&&"function"==typeof e&&!r&&e.length<=2?y(c(t=>{const r=t[2],n=t[0],o=t[3];return r&&void 0!==n&&e(n,o),t}),t):c(e,r)},r.catchHttp=function(e){n=!0;const r=c(t=>{const r=t[2],n=t[1];return!r&&n&&"http"===n.type&&e(n),!r&&n&&(t.__errorSuppressed=!0),t});return y(r,t)},r.catchBusiness=function(e){n=!0;const r=c(t=>{const r=t[1],n=t[2];return!n&&r&&"business"===r.type&&e(r),!n&&r&&(t.__errorSuppressed=!0),t});return y(r,t)},r.catchNetwork=function(e){if(n=!0,e&&"function"==typeof e){const r=c(t=>{const r=t[1],n=t[2];return!n&&r&&e(r),!n&&r&&(t.__errorSuppressed=!0),t});return y(r,t)}return i(e)},r};class w{globalConfig={};constructor(e){e&&(this.globalConfig={...e}),this.request=this.request.bind(this),this.sendGet=this.sendGet.bind(this),this.sendPost=this.sendPost.bind(this),this.sendPostForm=this.sendPostForm.bind(this),this.sendPostBlob=this.sendPostBlob.bind(this),this.sendGetBlob=this.sendGetBlob.bind(this),this.setGlobalConfig=this.setGlobalConfig.bind(this)}async executeRequest(e,t,r=1){try{const y=e,w=y.signal;w&&(w.aborted?t.abort():w.addEventListener("abort",()=>t.abort(),{once:!0}));const b=(n=y.headers,o=y.url,s=y.method,n?"function"==typeof n?n({url:o,method:s}):n:{}),{body:v,urlParams:S}=((e,t,r)=>{if(!e)return{};if("GET"===t||"HEAD"===t||"OPTIONS"===t){if(u(e)){const t=new URLSearchParams;for(const r in e)if(Object.prototype.hasOwnProperty.call(e,r)){const n=e[r];null!=n&&t.append(r,String(n))}return{urlParams:t.toString()}}return{}}if("form"===r&&e instanceof FormData)return{body:e};if("form"===r&&u(e)){const t=new FormData;for(const r in e)if(Object.prototype.hasOwnProperty.call(e,r)){const n=e[r];null!=n&&(n instanceof File||n instanceof Blob?t.append(r,n):t.append(r,String(n)))}return{body:t}}return"json"===r?{body:JSON.stringify(e)}:"text"===r?{body:String(e)}:"blob"===r&&e instanceof Blob||"arraybuffer"===r&&e instanceof ArrayBuffer?{body:e}:{body:String(e)}})(y.data,y.method||"GET",y.requestType||"json"),E=((e,t,r)=>{if(t.startsWith("http://")||t.startsWith("https://")){if(r){const e=t.includes("?")?"&":"?";return`${t}${e}${r}`}return t}let n=t;e&&(n=`${e.endsWith("/")?e.slice(0,-1):e}${t.startsWith("/")?t:`/${t}`}`);if(r){const e=n.includes("?")?"&":"?";n=`${n}${e}${r}`}return n})(y.baseURL,y.url,S),P=y.timeout;let q,x=!1,T=b;v&&"string"==typeof v&&"json"===y.requestType?T={"Content-Type":"application/json",...b}:v instanceof FormData&&(T=b);const $=new AbortController,B=()=>$.abort();t.signal.addEventListener("abort",B);const R={method:y.method||"GET",headers:T,body:v,mode:"cors",credentials:!1===y.withCredentials?"same-origin":"include",signal:$.signal},C=fetch(E,R);let _;try{if(P){const e=new Promise((e,t)=>{q=setTimeout(()=>{x=!0,$.abort(),t(g("Request timeout","timeout"))},P)});_=await Promise.race([C,e])}else _=await C}catch(a){if(q&&clearTimeout(q),x){const e=g("Request timeout","timeout");if(await m(y.retry,r,e))return t.signal.removeEventListener("abort",B),await f(y.retry?.delay||1e3),this.executeRequest(y,t,r+1);let n=!1;if(y.onNetworkError){const t=()=>{n=!0};await y.onNetworkError(h(new Error(e.message)),t)}const o=[void 0,e,!1,void 0];return o.__errorSuppressed=n,t.signal.removeEventListener("abort",B),o}throw a}finally{q&&clearTimeout(q),t.signal.removeEventListener("abort",B)}const D=y.responseType||"json";let F;try{F=await(async(e,t)=>{if(!e)throw new Error("No response received");switch(t){case"json":default:return await p(e);case"text":return await e.text();case"blob":return await e.blob();case"arraybuffer":return await e.arrayBuffer();case"formData":return await e.formData()}})(_,D)}catch(i){const e=g("Failed to parse response","network",_.status,void 0,i instanceof Error?i:new Error(String(i)));if(await m(y.retry,r,e))return await f(y.retry?.delay||1e3),this.executeRequest(y,t,r+1);let n=!1;if(y.onNetworkError){const t=()=>{n=!0};await y.onNetworkError(h(e.error||new Error(e.message)),t)}const o=[void 0,e,!1,void 0];return o.__errorSuppressed=n,o}if(!(y.validateStatus||l)(_.status)){const e=g(`HTTP Error: ${_.status} ${_.statusText}`,"http",_.status,F);if(await m(y.retry,r,e))return await f(y.retry?.delay||1e3),this.executeRequest(y,t,r+1);let n=!1;if(y.onHttpError){const t=()=>{n=!0},r=new Error(e.message);await y.onHttpError(r,_.status,F,t)}const o=[void 0,e,!1,{data:F,status:_.status,statusText:_.statusText,headers:_.headers,response:_}];return o.__errorSuppressed=n,o}if(!(y.validateResponse||d)(F)){const e=g("Business validation failed","business",_.status,F);if(await m(y.retry,r,e))return await f(y.retry?.delay||1e3),this.executeRequest(y,t,r+1);let n=!1;if(y.onBusinessError){const t=()=>{n=!0},r=new Error(e.message);await y.onBusinessError(r,F,t)}const o=[void 0,e,!1,{data:F,status:_.status,statusText:_.statusText,headers:_.headers,response:_}];return o.__errorSuppressed=n,o}let G=F;if(y.transformResponse)try{G=y.transformResponse(F)}catch(c){console.warn("[toAwaitFetch] transformResponse error:",c)}return[G,void 0,!0,{data:F,status:_.status,statusText:_.statusText,headers:_.headers,response:_}]}catch(a){const n=(e=>e instanceof DOMException&&"AbortError"===e.name)(a),o=g(n?"Request aborted":a instanceof Error?a.message:"Network error","network",void 0,void 0,a instanceof Error?a:new Error(String(a)));if(!n&&await m(e.retry,r,o))return await f(e.retry?.delay||1e3),this.executeRequest(e,t,r+1);let s=!1;if(e.onNetworkError){const t=()=>{s=!0};await e.onNetworkError(h(o.error||new Error(o.message)),t)}const i=[void 0,o,!1,void 0];return i.__errorSuppressed=s,i}var n,o,s}request(e){const t=c({...this.globalConfig},e),r=new AbortController,n=this.executeRequest(t,r);return y(n,()=>r.abort())}setGlobalConfig(e){this.globalConfig={...e}}getGlobalConfig(){return{...this.globalConfig}}mergeGlobalConfig(e){this.globalConfig=c(this.globalConfig,e)}sendGet(e,t,r){return this.request({...r,url:e,method:"GET",data:t})}sendPost(e,t,r){return this.request({...r,url:e,method:"POST",data:t,requestType:"json"})}sendPostForm(e,t,r){return this.request({...r,url:e,method:"POST",data:t,requestType:"form"})}sendPostBlob(e,t,r){return this.request({...r,url:e,method:"POST",data:t,requestType:"json",responseType:"blob"})}sendGetBlob(e,t,r){return this.request({...r,url:e,method:"GET",data:t,responseType:"blob"})}}const b=e=>new w(e),v=new w,S=(e,t,r)=>v.request({...r,url:e,method:"GET",data:t}),E=(e,t,r)=>v.sendPost(e,t,r),P=(e,t,r)=>v.sendPostForm(e,t,r),q=(e,t,r)=>v.sendPostBlob(e,t,r),x=(e,t,r)=>v.sendGetBlob(e,t,r),T=e=>{v.setGlobalConfig(e)},$=e=>{e?.cancel?.()},B=Object.assign(e=>e&&"object"==typeof e&&"url"in e?v.request(e):b(e),{create:b,sendGet:v.sendGet.bind(v),sendPost:v.sendPost.bind(v),sendPostForm:v.sendPostForm.bind(v),sendPostBlob:v.sendPostBlob.bind(v),sendGetBlob:v.sendGetBlob.bind(v),setGlobalConfig:v.setGlobalConfig.bind(v),cancel:$});function R(e,t){if(!e||!t)return;const r=t.replace(/\[(\d+)\]/g,".$1").split(".").filter(Boolean);let n=e;for(const o of r){if(null==n)return;n=n[o]}return n}function C(t){return"function"==typeof t?t():e(t)}function _(e,r){"undefined"!=typeof __DEV__&&__DEV__&&void 0!==e&&!function(e){return"function"==typeof e||t(e)}(e)&&console.warn(`[${r}] 检测到 params 是普通对象,参数变化将不会触发请求更新。\n请使用 computed() 或 getter 函数包装:`)}const D={};function F(e){Object.assign(D,e),e.pagination&&(D.pagination={...D.pagination,...e.pagination})}function G(){return{...D,pagination:{...D.pagination}}}function j(e,t={}){const a={...D.pagination,...t.pagination},{params:i,immediate:u=D.immediate??!0,debounceDelay:c=D.debounceDelay??0,dataField:l=D.dataField??"",totalField:d=D.totalField??"",currentPageField:f=D.currentPageField??"",transformParams:p,transformResult:g,onSuccess:h,onError:m,incremental:y=D.incremental??!1}=t,{defaultPage:w=1,defaultPageSize:b=10,pageKey:v="page",pageSizeKey:S="pageSize"}=a,E=r([]),P=r(!1),q=r(null),x=n({page:w,pageSize:b,total:0});let T=0;async function $(){const t=++T;P.value=!0,q.value=null;try{const r=i?C(i):{},n={[v]:x.page,[S]:x.pageSize};let o;o=p?p(r,{page:x.page,pageSize:x.pageSize}):{...r,...n};const s=await e(o);if(t!==T)return;if(g){const e=g(s);if(e&&"object"==typeof e&&Array.isArray(e.list)){const t=e.list;y&&x.page>w?E.value=[...E.value,...t]:E.value=t,x.total="number"==typeof e.total?e.total:e.list.length}else E.value=[],x.total=0,console.warn("[useTableRequest] transformResult 返回格式无法识别,请返回 { list: T[], total: number } 格式。")}else{const e=s;if(Array.isArray(e))y&&x.page>w?E.value=[...E.value,...e]:E.value=e,x.total=e.length;else if(e&&"object"==typeof e){if(l&&""!==l.trim()){const t=R(e,l)||[];y&&x.page>w?E.value=[...E.value,...t]:E.value=t}else E.value=[];d&&""!==d.trim()?x.total=R(e,d)??0:x.total=0}else E.value=[],x.total=0}if(f&&""!==f.trim()){const e=R(s,f);"number"==typeof e&&e!==x.page&&(console.warn(`[useTableRequest] 后端返回页码(${e})与客户端页码(${x.page})不一致,已自动修正`),x.page=e)}h?.(E.value,s)}catch(r){if(t!==T)return;q.value=r instanceof Error?r:new Error(String(r)),m?.(q.value)}finally{t===T&&(P.value=!1)}}const B=c>0?function(e,t){let r=null;return(...n)=>{r&&clearTimeout(r),r=setTimeout(()=>{e(...n),r=null},t)}}($,c):$;let F=!1;async function G(){await $()}return o(()=>[x.page,x.pageSize],()=>{F||B()}),i&&(_(i,"useTableRequest"),o(()=>C(i),()=>{F=!0,x.page=w,F=!1,B()},{deep:!0})),u&&$(),{data:E,loading:P,error:q,pagination:x,run:G,onPageChange:async function(e){const t=x.page!==e;x.page=e,t||await $()},onSizeChange:async function(e){const t=x.pageSize!==e,r=x.page!==w;x.pageSize=e,x.page=w,t||r||await $()},refresh:async function(){y?(F=!0,x.page=w,E.value=[],await s(),F=!1,await $()):await G()}}}function N(e,n){let s,u;null===e||"object"!=typeof e||t(e)?(s=e,u=n||{}):(u=e,s="");const c=()=>a(u.precision)??0,l=()=>a(u.showThousands)??!1,d=r(a(s)?.toString()??""),f=i(()=>{let e=d.value;if(l()){const[t,r]=e.split(".");let n=t.replace(/\B(?=(\d{3})+(?!\d))/g,",");return r?n+=`.${r}`:e.includes(".")&&(n+="."),n}return e}),p=e=>{let t=null==e?"":e.toString().trim();const r=a(u.allowNegative)?/[^\d.-]/g:/[^\d.]/g;t=t.replace(r,""),t=t.replace(/^-/,"$#$").replace(/-/g,"").replace("$#$","-"),t.length>1&&t.startsWith("0")&&"."!==t[1]&&(t=t.replace(/^0+/,""),""===t&&(t="0")),t.startsWith("-0")&&t.length>2&&"."!==t[2]&&(t="-"+t.slice(2).replace(/^0+/,""),"-"===t&&(t="-0"));const n=c();if(n>0){t=t.replace(/^\./g,"").replace(/\./g,"$#$").replace(/\./g,"").replace("$#$",".");const e=t.indexOf(".");if(-1!==e){if(t.slice(e+1).length>n){const r=a(u.decimalLimitMode)??"discard";if("discard"===r)t=t.slice(0,e+n+1);else{const o=Math.pow(10,n);let s=Number(t);isNaN(s)?t=t.slice(0,e+n+1):("round"===r?s=Math.round(s*o)/o:"ceil"===r&&(s=Math.ceil(s*o)/o),t=s.toString())}}}}else t=t.replace(/\./g,"");return t};return o(()=>a(s),e=>{const t=null==e?"":e.toString();t!==d.value&&(d.value=t)}),{value:d,displayValue:f,handleInput:e=>{const t=p(e);d.value=t},handleBlur:()=>{if(!d.value)return;let e=Number(d.value);const t=u.max??1/0,r=u.min??-1/0;e>t&&(e=t,d.value=t.toString()),e<r&&(e=r,d.value=r.toString());const n=a(u.autoFixed)??!1;d.value=!0===n||"pad"===n?e.toFixed(c()):"trim"===n?Number(e.toFixed(c())).toString():e.toString()},formatter:e=>f.value,parser:e=>l()?e.replace(/,/g,""):e,clean:p}}const O=/* @__PURE__ */new Map,k=/* @__PURE__ */new Map,A=/* @__PURE__ */new Map,z=/* @__PURE__ */new Set;let M=null;const I=(e,t)=>new Promise((r,n)=>{if(M)return r(M);const o=indexedDB.open(e,1);o.onupgradeneeded=e=>{const r=e.target.result;r.objectStoreNames.contains(t)||r.createObjectStore(t)},o.onsuccess=e=>{M=e.target.result,r(M)},o.onerror=e=>{n(e.target.error)}});function L(e){const{requestFn:t,cacheKey:n,cacheTime:s=3e5,storage:a="memory",params:i,transformResult:u,immediate:c=!0,storageKeyPrefix:l="req_cache_",forceRefreshOnFirst:d=!1,dbName:f="RequestCacheDB",storeName:p="request_cache",onSuccess:g,onError:h}=e,m=(e=>{if("undefined"==typeof window)return"memory";try{if("localStorage"===e&&!window.localStorage)throw new Error;if("sessionStorage"===e&&!window.sessionStorage)throw new Error;if("indexedDB"===e&&!window.indexedDB)throw new Error;return e}catch(t){return console.warn(`[useRequestCache] ${e} is not supported in this environment, falling back to 'memory' mode.`),"memory"}})(C(a)),y=r(),w=r(!1),b=r(null),v=()=>{const e=i?C(i):{};if("function"==typeof n)try{return n(e)}catch(t){return console.warn("[useRequestCache] Generate key failed",t),""}return n},S=async e=>{if("indexedDB"===m){try{const t=await I(f,p);return new Promise((r,n)=>{const o=t.transaction([p],"readwrite").objectStore(p).delete(`${l}${e}`);o.onsuccess=()=>r(),o.onerror=()=>n(o.error)})}catch(r){console.warn("[useRequestCache] IndexedDB delete failed",r)}return}const t="localStorage"===m?localStorage:"sessionStorage"===m?sessionStorage:null;t&&t.removeItem(`${l}${e}`)},E=async(e=!1)=>{const r=v();if(!r)return void console.warn("[useRequestCache] Cache key is empty, skipping request");const n=C(d)&&!z.has(r),o=e||n,a=i?C(i):{};if(!o&&"indexedDB"!==m){const e=O.get(r);if(e){if(Date.now()-e.timestamp<s)return y.value=u?u(e.data):e.data,g&&g(y.value),y.value;O.delete(r)}}w.value=!0,b.value=null;try{if(k.has(r)){if(g||h){const e=A.get(r);e&&(g&&e.onSuccess.push(g),h&&e.onError.push(h))}const e=await k.get(r);return y.value=u?u(e):e,y.value}if(!o&&"memory"!==m){const e=await(async e=>{if("indexedDB"===m)try{const t=await I(f,p);return new Promise(r=>{const n=t.transaction([p],"readonly").objectStore(p).get(`${l}${e}`);n.onsuccess=()=>r(n.result||null),n.onerror=()=>r(null)})}catch(r){return console.warn("[useRequestCache] IndexedDB read failed",r),null}const t="localStorage"===m?localStorage:"sessionStorage"===m?sessionStorage:null;if(!t)return null;try{const r=t.getItem(`${l}${e}`);if(r)return JSON.parse(r)}catch(r){console.warn("[useRequestCache] Read storage failed",r)}return null})(r);if(e){if(Date.now()-e.timestamp<s)return"indexedDB"!==m&&O.set(r,e),y.value=u?u(e.data):e.data,g&&g(y.value),y.value;await S(r)}}const e=t(a);k.set(r,e),A.set(r,{onSuccess:g?[g]:[],onError:h?[h]:[]});try{const t=await e,o={data:t,timestamp:Date.now()};"indexedDB"!==m&&O.set(r,o),"memory"!==m&&await(async(e,t)=>{if("indexedDB"===m){try{const r=await I(f,p);return new Promise((n,o)=>{const s=r.transaction([p],"readwrite").objectStore(p).put(t,`${l}${e}`);s.onsuccess=()=>n(),s.onerror=()=>o(s.error)})}catch(n){console.warn("[useRequestCache] IndexedDB write failed",n)}return}const r="localStorage"===m?localStorage:"sessionStorage"===m?sessionStorage:null;if(r)try{r.setItem(`${l}${e}`,JSON.stringify(t))}catch(n){console.warn("[useRequestCache] Write storage failed",n)}})(r,o),n&&z.add(r),y.value=u?u(t):t;const s=A.get(r);if(s&&s.onSuccess){[...s.onSuccess].forEach(e=>e(y.value))}return k.delete(r),A.delete(r),y.value}catch(c){b.value=c;const e=A.get(r);if(e&&e.onError){[...e.onError].forEach(e=>e(c))}throw k.delete(r),A.delete(r),c}}catch(c){throw b.value=c,c}finally{w.value=!1}},P=()=>E(!1);return i?o(()=>C(i),()=>{P()},{deep:!0,immediate:c}):c&&P(),{data:y,loading:w,error:b,run:P,refresh:()=>E(!0),clearCache:async e=>{const t=e||v();t&&(O.delete(t),"memory"!==m&&await S(t))}}}const W="1.6.0";function H(){return W}export{W as VERSION,$ as cancel,b as createInstance,G as getTableRequestGlobalConfig,H as getVersion,S as sendGet,x as sendGetBlob,E as sendPost,q as sendPostBlob,P as sendPostForm,T as setGlobalConfig,F as setTableRequestGlobalConfig,B as toAwaitFetch,N as useInputNumber,L as useRequestCache,j as useTableRequest};