@yh-ui/request 0.1.21

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 (78) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -0
  3. package/dist/adapters/fetch.cjs +157 -0
  4. package/dist/adapters/fetch.d.ts +25 -0
  5. package/dist/adapters/fetch.mjs +148 -0
  6. package/dist/adapters/index.cjs +27 -0
  7. package/dist/adapters/index.d.ts +5 -0
  8. package/dist/adapters/index.mjs +2 -0
  9. package/dist/adapters/platform.cjs +394 -0
  10. package/dist/adapters/platform.d.ts +72 -0
  11. package/dist/adapters/platform.mjs +369 -0
  12. package/dist/cache/index.cjs +56 -0
  13. package/dist/cache/index.d.ts +21 -0
  14. package/dist/cache/index.mjs +14 -0
  15. package/dist/cache/indexedDB.cjs +188 -0
  16. package/dist/cache/indexedDB.d.ts +58 -0
  17. package/dist/cache/indexedDB.mjs +176 -0
  18. package/dist/cache/localStorage.cjs +158 -0
  19. package/dist/cache/localStorage.d.ts +58 -0
  20. package/dist/cache/localStorage.mjs +153 -0
  21. package/dist/cache/memory.cjs +112 -0
  22. package/dist/cache/memory.d.ts +71 -0
  23. package/dist/cache/memory.mjs +103 -0
  24. package/dist/graphql.cjs +255 -0
  25. package/dist/graphql.d.ts +192 -0
  26. package/dist/graphql.mjs +235 -0
  27. package/dist/http-cache.cjs +248 -0
  28. package/dist/http-cache.d.ts +156 -0
  29. package/dist/http-cache.mjs +233 -0
  30. package/dist/index.cjs +181 -0
  31. package/dist/index.d.ts +23 -0
  32. package/dist/index.mjs +16 -0
  33. package/dist/interceptors/debug.cjs +139 -0
  34. package/dist/interceptors/debug.d.ts +92 -0
  35. package/dist/interceptors/debug.mjs +130 -0
  36. package/dist/interceptors/index.cjs +38 -0
  37. package/dist/interceptors/index.d.ts +6 -0
  38. package/dist/interceptors/index.mjs +3 -0
  39. package/dist/interceptors/progress.cjs +185 -0
  40. package/dist/interceptors/progress.d.ts +97 -0
  41. package/dist/interceptors/progress.mjs +177 -0
  42. package/dist/interceptors/security.cjs +154 -0
  43. package/dist/interceptors/security.d.ts +83 -0
  44. package/dist/interceptors/security.mjs +134 -0
  45. package/dist/plugin.cjs +166 -0
  46. package/dist/plugin.d.ts +106 -0
  47. package/dist/plugin.mjs +163 -0
  48. package/dist/request.cjs +396 -0
  49. package/dist/request.d.ts +111 -0
  50. package/dist/request.mjs +339 -0
  51. package/dist/types.cjs +13 -0
  52. package/dist/types.d.ts +157 -0
  53. package/dist/types.mjs +7 -0
  54. package/dist/useAIStream.cjs +125 -0
  55. package/dist/useAIStream.d.ts +89 -0
  56. package/dist/useAIStream.mjs +108 -0
  57. package/dist/useLoadMore.cjs +136 -0
  58. package/dist/useLoadMore.d.ts +84 -0
  59. package/dist/useLoadMore.mjs +134 -0
  60. package/dist/usePagination.cjs +141 -0
  61. package/dist/usePagination.d.ts +89 -0
  62. package/dist/usePagination.mjs +132 -0
  63. package/dist/useQueue.cjs +243 -0
  64. package/dist/useQueue.d.ts +118 -0
  65. package/dist/useQueue.mjs +239 -0
  66. package/dist/useRequest.cjs +325 -0
  67. package/dist/useRequest.d.ts +126 -0
  68. package/dist/useRequest.mjs +329 -0
  69. package/dist/useRequestQueue.cjs +36 -0
  70. package/dist/useRequestQueue.d.ts +52 -0
  71. package/dist/useRequestQueue.mjs +27 -0
  72. package/dist/useSSE.cjs +241 -0
  73. package/dist/useSSE.d.ts +74 -0
  74. package/dist/useSSE.mjs +226 -0
  75. package/dist/websocket.cjs +325 -0
  76. package/dist/websocket.d.ts +163 -0
  77. package/dist/websocket.mjs +316 -0
  78. package/package.json +61 -0
@@ -0,0 +1,329 @@
1
+ import {
2
+ ref,
3
+ shallowRef,
4
+ computed,
5
+ watch,
6
+ onMounted,
7
+ onUnmounted
8
+ } from "vue";
9
+ import { debounce, throttle } from "@yh-ui/utils";
10
+ const globalCache = /* @__PURE__ */ new Map();
11
+ function setCache(key, value, cacheTime) {
12
+ const expireTime = Date.now() + (cacheTime || 5 * 60 * 1e3);
13
+ globalCache.set(key, { data: value, expireTime });
14
+ }
15
+ export function useRequest(service, options = {}) {
16
+ const {
17
+ manual = false,
18
+ defaultParams = [],
19
+ debounceWait,
20
+ throttleWait,
21
+ formatResult,
22
+ onSuccess,
23
+ onError,
24
+ onFinally
25
+ } = options;
26
+ const loading = ref(false);
27
+ const loadingMore = ref(false);
28
+ const data = shallowRef(void 0);
29
+ const error = shallowRef(void 0);
30
+ const params = ref(defaultParams);
31
+ const noMore = ref(false);
32
+ const runCount = ref(0);
33
+ let abortController = null;
34
+ const format = (response) => {
35
+ if (formatResult) {
36
+ return formatResult(response);
37
+ }
38
+ if (response && typeof response === "object" && !("config" in response && "requestId" in response)) {
39
+ return response;
40
+ }
41
+ const res = response;
42
+ return res?.data ?? res;
43
+ };
44
+ const run = async (...runParams) => {
45
+ const currentRunCount = ++runCount.value;
46
+ if (abortController) {
47
+ abortController.abort();
48
+ }
49
+ abortController = new AbortController();
50
+ params.value = runParams;
51
+ loading.value = true;
52
+ error.value = void 0;
53
+ try {
54
+ const response = await service(...runParams);
55
+ if (currentRunCount !== runCount.value) {
56
+ const cancelError = new Error("Request canceled");
57
+ cancelError.isCanceled = true;
58
+ throw cancelError;
59
+ }
60
+ const formattedData = format(response);
61
+ data.value = formattedData;
62
+ if (onSuccess) {
63
+ onSuccess(formattedData, runParams);
64
+ }
65
+ return response;
66
+ } catch (err) {
67
+ const cancelableErr = err;
68
+ if (cancelableErr?.isCanceled || cancelableErr?.name === "AbortError") {
69
+ throw err;
70
+ }
71
+ error.value = err;
72
+ if (onError) {
73
+ onError(err, runParams);
74
+ }
75
+ throw err;
76
+ } finally {
77
+ if (currentRunCount === runCount.value) {
78
+ loading.value = false;
79
+ if (onFinally) {
80
+ onFinally(runParams);
81
+ }
82
+ }
83
+ }
84
+ };
85
+ const mutate = (newData) => {
86
+ if (typeof newData === "function") {
87
+ const oldData = data.value;
88
+ data.value = newData(oldData);
89
+ } else if (newData !== void 0) {
90
+ data.value = newData;
91
+ }
92
+ };
93
+ const cancel = () => {
94
+ if (abortController) {
95
+ abortController.abort();
96
+ abortController = null;
97
+ }
98
+ loading.value = false;
99
+ };
100
+ const refresh = async () => {
101
+ await run(...params.value).catch(() => {
102
+ });
103
+ };
104
+ const loadMore = async () => {
105
+ if (loadingMore.value || noMore.value) return;
106
+ loadingMore.value = true;
107
+ try {
108
+ await run(...params.value).catch(() => {
109
+ });
110
+ } finally {
111
+ loadingMore.value = false;
112
+ }
113
+ };
114
+ let wrappedRun = run;
115
+ let cancelFn;
116
+ if (debounceWait) {
117
+ const debounced = debounce(
118
+ ((...args) => {
119
+ run(...args).catch(() => {
120
+ });
121
+ }),
122
+ debounceWait
123
+ );
124
+ wrappedRun = ((...args) => {
125
+ debounced(...args);
126
+ return Promise.resolve();
127
+ });
128
+ wrappedRun.cancel = () => debounced.cancel();
129
+ cancelFn = () => debounced.cancel();
130
+ } else if (throttleWait) {
131
+ const throttled = throttle(
132
+ ((...args) => {
133
+ run(...args).catch(() => {
134
+ });
135
+ }),
136
+ throttleWait
137
+ );
138
+ wrappedRun = ((...args) => {
139
+ throttled(...args);
140
+ return Promise.resolve();
141
+ });
142
+ wrappedRun.cancel = () => throttled.cancel();
143
+ cancelFn = () => throttled.cancel();
144
+ }
145
+ onUnmounted(() => {
146
+ cancelFn?.();
147
+ });
148
+ if (!manual && defaultParams.length > 0) {
149
+ onMounted(() => {
150
+ if (!debounceWait && !throttleWait) {
151
+ run(...defaultParams).catch(() => {
152
+ });
153
+ }
154
+ });
155
+ }
156
+ const disabled = computed(() => loading.value);
157
+ return {
158
+ loading,
159
+ loadingMore,
160
+ data,
161
+ error,
162
+ params,
163
+ noMore,
164
+ run: wrappedRun,
165
+ mutate,
166
+ cancel,
167
+ refresh,
168
+ loadMore,
169
+ disabled
170
+ };
171
+ }
172
+ export function useRequestSWR(cacheKey, service, options = {}) {
173
+ const {
174
+ cacheTime = 10 * 60 * 1e3,
175
+ setCache: customSetCache,
176
+ refreshOnWindowFocus = false,
177
+ refreshDepsWait = 1e3,
178
+ refreshDeps = [],
179
+ manual = false,
180
+ ...requestOptions
181
+ } = options;
182
+ const setCacheFn = customSetCache || ((key, value) => setCache(key, value, cacheTime));
183
+ const getKey = () => {
184
+ const key = typeof cacheKey === "function" ? cacheKey() : cacheKey;
185
+ return key;
186
+ };
187
+ const { loading, data, error, params, run, mutate, cancel, refresh, disabled } = useRequest((key) => service(key), {
188
+ manual,
189
+ defaultParams: manual ? [] : [getKey()],
190
+ ...requestOptions
191
+ });
192
+ const updateCache = (newData) => {
193
+ const key = getKey();
194
+ if (key) {
195
+ setCacheFn(key, newData);
196
+ }
197
+ };
198
+ watch(
199
+ () => data.value,
200
+ (newData) => {
201
+ if (newData !== void 0) {
202
+ updateCache(newData);
203
+ }
204
+ },
205
+ { immediate: true }
206
+ );
207
+ if (refreshOnWindowFocus && !manual) {
208
+ onMounted(() => {
209
+ const handleFocus = () => {
210
+ const key = getKey();
211
+ if (key && !loading.value) {
212
+ refresh();
213
+ }
214
+ };
215
+ window.addEventListener("visibilitychange", handleFocus);
216
+ window.addEventListener("focus", handleFocus);
217
+ onUnmounted(() => {
218
+ window.removeEventListener("visibilitychange", handleFocus);
219
+ window.removeEventListener("focus", handleFocus);
220
+ });
221
+ });
222
+ }
223
+ if (refreshDeps && refreshDeps.length > 0 && !manual) {
224
+ watch(
225
+ () => refreshDeps.map((dep) => dep.value),
226
+ () => {
227
+ const key = getKey();
228
+ if (key) {
229
+ setTimeout(() => run(key).catch(() => {
230
+ }), refreshDepsWait);
231
+ }
232
+ },
233
+ { deep: true }
234
+ );
235
+ }
236
+ return {
237
+ loading,
238
+ data,
239
+ error,
240
+ params,
241
+ loadingMore: ref(false),
242
+ noMore: ref(false),
243
+ run,
244
+ mutate,
245
+ cancel,
246
+ refresh,
247
+ loadMore: async () => {
248
+ return Promise.resolve();
249
+ },
250
+ disabled
251
+ };
252
+ }
253
+ export function useRequestPolling(service, options = {}) {
254
+ const {
255
+ polling = false,
256
+ pollingInterval = 3e3,
257
+ pollingWhenHidden = false,
258
+ ...requestOptions
259
+ } = options;
260
+ const {
261
+ loading,
262
+ data,
263
+ error,
264
+ params,
265
+ loadingMore,
266
+ noMore,
267
+ run,
268
+ mutate,
269
+ cancel,
270
+ refresh,
271
+ loadMore,
272
+ disabled
273
+ } = useRequest(service, {
274
+ manual: true,
275
+ ...requestOptions
276
+ });
277
+ const isPolling = ref(false);
278
+ const pollingTimer = ref(null);
279
+ const startPolling = () => {
280
+ if (pollingTimer.value) return;
281
+ isPolling.value = true;
282
+ run(...params.value).catch(() => {
283
+ });
284
+ pollingTimer.value = setInterval(() => {
285
+ if (!pollingWhenHidden && document.hidden) {
286
+ return;
287
+ }
288
+ run(...params.value).catch(() => {
289
+ });
290
+ }, pollingInterval);
291
+ };
292
+ const pause = () => {
293
+ if (pollingTimer.value) {
294
+ clearInterval(pollingTimer.value);
295
+ pollingTimer.value = null;
296
+ }
297
+ isPolling.value = false;
298
+ };
299
+ const resume = () => {
300
+ if (polling && !pollingTimer.value) {
301
+ startPolling();
302
+ }
303
+ };
304
+ onUnmounted(() => {
305
+ pause();
306
+ cancel();
307
+ });
308
+ if (polling) {
309
+ onMounted(() => {
310
+ startPolling();
311
+ });
312
+ }
313
+ return {
314
+ loading,
315
+ data,
316
+ error,
317
+ params,
318
+ loadingMore,
319
+ noMore,
320
+ run,
321
+ mutate,
322
+ cancel,
323
+ refresh,
324
+ loadMore,
325
+ disabled,
326
+ pause,
327
+ resume
328
+ };
329
+ }
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useRequestQueue = useRequestQueue;
7
+ var _useQueue = require("./useQueue.cjs");
8
+ function useRequestQueue(options = {}) {
9
+ const {
10
+ request: _customRequest,
11
+ ...queueOptions
12
+ } = options;
13
+ const queue = (0, _useQueue.useQueue)(queueOptions);
14
+ const addRequest = (requestFn, addOptions = {}) => {
15
+ return queue.add(requestFn, {
16
+ ...addOptions,
17
+ metadata: {
18
+ ...addOptions.metadata,
19
+ type: "request"
20
+ }
21
+ });
22
+ };
23
+ const cancelByKey = key => {
24
+ const pending = queue.pendingTasks.value ?? [];
25
+ const running = queue.runningTasks.value ?? [];
26
+ const task = [...pending, ...running].find(t => t.key === key);
27
+ if (task) {
28
+ queue.cancel(task.id);
29
+ }
30
+ };
31
+ return {
32
+ ...queue,
33
+ addRequest,
34
+ cancelByKey
35
+ };
36
+ }
@@ -0,0 +1,52 @@
1
+ import { useQueue, type UseQueueOptions, type QueueTask } from './useQueue';
2
+ /**
3
+ * useRequestQueue - 请求队列 Hook
4
+ *
5
+ * 专用于 HTTP 请求的队列管理,支持并发限制、优先级
6
+ *
7
+ * @example
8
+ * const { addRequest, cancelByKey } = useRequestQueue({
9
+ * concurrency: 2,
10
+ * })
11
+ *
12
+ * addRequest(() => request.get('/api/item/1'), { key: 'item-1' })
13
+ */
14
+ /** 请求队列配置 */
15
+ export interface UseRequestQueueOptions extends UseQueueOptions {
16
+ /** 请求实例 */
17
+ request?: unknown;
18
+ }
19
+ /** 请求队列返回 */
20
+ export interface UseRequestQueueReturn {
21
+ tasks: ReturnType<typeof useQueue>['tasks'];
22
+ pendingTasks: ReturnType<typeof useQueue>['pendingTasks'];
23
+ runningTasks: ReturnType<typeof useQueue>['runningTasks'];
24
+ completedTasks: ReturnType<typeof useQueue>['completedTasks'];
25
+ failedTasks: ReturnType<typeof useQueue>['failedTasks'];
26
+ isRunning: ReturnType<typeof useQueue>['isRunning'];
27
+ isEmpty: ReturnType<typeof useQueue>['isEmpty'];
28
+ isAllComplete: ReturnType<typeof useQueue>['isAllComplete'];
29
+ completedCount: ReturnType<typeof useQueue>['completedCount'];
30
+ totalCount: ReturnType<typeof useQueue>['totalCount'];
31
+ addRequest: <T = unknown>(requestFn: () => Promise<T>, options?: {
32
+ key?: string;
33
+ priority?: number;
34
+ delay?: number;
35
+ metadata?: Record<string, unknown>;
36
+ }) => string;
37
+ cancelByKey: (key: string) => void;
38
+ remove: (taskId: string) => void;
39
+ clear: () => void;
40
+ start: () => void;
41
+ pause: () => void;
42
+ resume: () => void;
43
+ cancel: (taskId: string) => void;
44
+ cancelAll: () => void;
45
+ retry: (taskId: string) => void;
46
+ retryAll: () => void;
47
+ getTask: (taskId: string) => QueueTask | undefined;
48
+ }
49
+ /**
50
+ * useRequestQueue - HTTP 请求队列 Hook
51
+ */
52
+ export declare function useRequestQueue(options?: UseRequestQueueOptions): UseRequestQueueReturn;
@@ -0,0 +1,27 @@
1
+ import { useQueue } from "./useQueue.mjs";
2
+ export function useRequestQueue(options = {}) {
3
+ const { request: _customRequest, ...queueOptions } = options;
4
+ const queue = useQueue(queueOptions);
5
+ const addRequest = (requestFn, addOptions = {}) => {
6
+ return queue.add(requestFn, {
7
+ ...addOptions,
8
+ metadata: {
9
+ ...addOptions.metadata,
10
+ type: "request"
11
+ }
12
+ });
13
+ };
14
+ const cancelByKey = (key) => {
15
+ const pending = queue.pendingTasks.value ?? [];
16
+ const running = queue.runningTasks.value ?? [];
17
+ const task = [...pending, ...running].find((t) => t.key === key);
18
+ if (task) {
19
+ queue.cancel(task.id);
20
+ }
21
+ };
22
+ return {
23
+ ...queue,
24
+ addRequest,
25
+ cancelByKey
26
+ };
27
+ }
@@ -0,0 +1,241 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useSSE = useSSE;
7
+ var _vue = require("vue");
8
+ function useSSE(options = {}) {
9
+ const {
10
+ parseJSON = true,
11
+ separator = "\n\n",
12
+ eventPrefix = "event:",
13
+ onStart,
14
+ onMessage,
15
+ onDone,
16
+ onError,
17
+ onCustomEvent,
18
+ ...fetchOptions
19
+ } = options;
20
+ const loading = (0, _vue.ref)(false);
21
+ const content = (0, _vue.ref)("");
22
+ const messages = (0, _vue.ref)([]);
23
+ const error = (0, _vue.shallowRef)(void 0);
24
+ let abortController = null;
25
+ let reader = null;
26
+ let decoder;
27
+ const getDecoder = () => {
28
+ if (!decoder) {
29
+ decoder = new TextDecoder();
30
+ }
31
+ return decoder;
32
+ };
33
+ const parseLine = line => {
34
+ const result = {
35
+ data: ""
36
+ };
37
+ if (!line || line.startsWith("#")) return result;
38
+ if (line.startsWith(eventPrefix)) {
39
+ result.event = line.slice(eventPrefix.length).trim();
40
+ return result;
41
+ }
42
+ if (line.startsWith("data:")) {
43
+ const data = line.slice(5);
44
+ result.data = data.startsWith(" ") ? data.slice(1) : data;
45
+ }
46
+ return result;
47
+ };
48
+ const parseSSE = rawData => {
49
+ const lines = rawData.split("\n");
50
+ let originalEventType = "message";
51
+ let eventData = "";
52
+ let done = false;
53
+ for (const line of lines) {
54
+ const {
55
+ event,
56
+ data
57
+ } = parseLine(line);
58
+ if (event) originalEventType = event;
59
+ if (data) eventData += data;
60
+ }
61
+ let eventType = "message";
62
+ switch (originalEventType.toLowerCase()) {
63
+ case "start":
64
+ eventType = "start";
65
+ break;
66
+ case "message":
67
+ case "chunk":
68
+ case "content":
69
+ eventType = "chunk";
70
+ break;
71
+ case "done":
72
+ case "stop":
73
+ eventType = "done";
74
+ done = true;
75
+ break;
76
+ case "error":
77
+ eventType = "error";
78
+ break;
79
+ case "tool":
80
+ case "function":
81
+ eventType = "tool";
82
+ break;
83
+ case "thinking":
84
+ case "thinking_start":
85
+ case "thinking_end":
86
+ eventType = "thinking";
87
+ break;
88
+ default:
89
+ eventType = "custom";
90
+ break;
91
+ }
92
+ if (!eventData && eventType !== "done" && eventType !== "start") return null;
93
+ let finalData = eventData;
94
+ if (parseJSON && eventData) {
95
+ try {
96
+ finalData = JSON.parse(eventData);
97
+ } catch {}
98
+ }
99
+ if (eventType === "custom" && onCustomEvent) {
100
+ onCustomEvent(originalEventType, finalData);
101
+ }
102
+ return {
103
+ event: eventType,
104
+ data: finalData,
105
+ raw: rawData,
106
+ done
107
+ };
108
+ };
109
+ const start = async requestOptions => {
110
+ stop();
111
+ reset();
112
+ const config = {
113
+ ...fetchOptions,
114
+ ...requestOptions
115
+ };
116
+ loading.value = true;
117
+ error.value = void 0;
118
+ onStart?.();
119
+ try {
120
+ let url = config.url || "";
121
+ if (config.baseURL) {
122
+ url = url.startsWith("http") ? url : config.baseURL + url;
123
+ }
124
+ if (config.params) {
125
+ const params = new URLSearchParams();
126
+ Object.entries(config.params).forEach(([key, value]) => {
127
+ if (Array.isArray(value)) {
128
+ value.forEach(v => params.append(key, String(v)));
129
+ } else {
130
+ params.append(key, String(value));
131
+ }
132
+ });
133
+ const sep = url.includes("?") ? "&" : "?";
134
+ url += sep + params.toString();
135
+ }
136
+ const headers = config.headers || {};
137
+ const fetchInit = {
138
+ method: config.method || "POST",
139
+ headers,
140
+ credentials: config.credentials || "same-origin"
141
+ };
142
+ if (config.data && config.method !== "GET") {
143
+ fetchInit.body = JSON.stringify(config.data);
144
+ if (!headers["Content-Type"]) {
145
+ headers["Content-Type"] = "application/json";
146
+ }
147
+ }
148
+ abortController = new AbortController();
149
+ fetchInit.signal = abortController.signal;
150
+ const response = await fetch(url, fetchInit);
151
+ if (!response.ok) {
152
+ throw new Error(`SSE request failed: ${response.status} ${response.statusText}`);
153
+ }
154
+ const body = response.body;
155
+ if (!body) {
156
+ throw new Error("Response body is null");
157
+ }
158
+ reader = body.getReader();
159
+ const textDecoder = getDecoder();
160
+ let buffer = "";
161
+ while (true) {
162
+ const {
163
+ done: readDone,
164
+ value
165
+ } = await reader.read();
166
+ if (readDone) {
167
+ if (buffer) {
168
+ const msg = parseSSE(buffer);
169
+ if (msg) {
170
+ handleMessage(msg);
171
+ }
172
+ }
173
+ break;
174
+ }
175
+ const chunk = textDecoder.decode(value, {
176
+ stream: true
177
+ });
178
+ buffer += chunk;
179
+ const parts = buffer.split(separator);
180
+ buffer = parts.pop() || "";
181
+ for (const part of parts) {
182
+ const msg = parseSSE(part);
183
+ if (msg) {
184
+ handleMessage(msg);
185
+ if (msg.done) {
186
+ onDone?.(content.value);
187
+ loading.value = false;
188
+ return;
189
+ }
190
+ }
191
+ }
192
+ }
193
+ onDone?.(content.value);
194
+ } catch (err) {
195
+ const errWithName = err;
196
+ if (errWithName?.name === "AbortError") {
197
+ return;
198
+ }
199
+ const errObj = err instanceof Error ? err : new Error(String(err));
200
+ error.value = errObj;
201
+ onError?.(errObj);
202
+ } finally {
203
+ loading.value = false;
204
+ }
205
+ };
206
+ const handleMessage = message => {
207
+ if (typeof message.data === "string") {
208
+ content.value += message.data;
209
+ }
210
+ messages.value.push(message);
211
+ onMessage?.(message);
212
+ };
213
+ const stop = () => {
214
+ if (reader) {
215
+ reader.cancel();
216
+ reader = null;
217
+ }
218
+ if (abortController) {
219
+ abortController.abort();
220
+ abortController = null;
221
+ }
222
+ loading.value = false;
223
+ };
224
+ const reset = () => {
225
+ content.value = "";
226
+ messages.value = [];
227
+ error.value = void 0;
228
+ };
229
+ (0, _vue.onUnmounted)(() => {
230
+ stop();
231
+ });
232
+ return {
233
+ loading,
234
+ content,
235
+ messages,
236
+ error,
237
+ start,
238
+ stop,
239
+ reset
240
+ };
241
+ }