@vobs/http 1.1.0 → 1.2.1

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/dist/index.cjs ADDED
@@ -0,0 +1,944 @@
1
+ 'use strict';
2
+
3
+ var axios = require('axios');
4
+
5
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
6
+
7
+ var axios__default = /*#__PURE__*/_interopDefault(axios);
8
+
9
+ var __defProp = Object.defineProperty;
10
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
11
+
12
+ // packages/reactivity/src/debug.ts
13
+ var activeDebugHooks = null;
14
+ function hasDebugHooks() {
15
+ return activeDebugHooks !== null;
16
+ }
17
+ __name(hasDebugHooks, "hasDebugHooks");
18
+ function invokeDebug(name, ...args) {
19
+ return;
20
+ }
21
+ __name(invokeDebug, "invokeDebug");
22
+
23
+ // packages/reactivity/src/scheduler.ts
24
+ var _Scheduler = class _Scheduler {
25
+ constructor() {
26
+ this.dirtyEffects = /* @__PURE__ */ new Set();
27
+ this.lowPriorityEffects = /* @__PURE__ */ new Set();
28
+ // flush 不可重入(flushing 标志保证),缓冲数组可在轮次间安全复用,避免每轮分配。
29
+ this.normalBuffer = [];
30
+ this.lowBuffer = [];
31
+ this.flushing = false;
32
+ this.scheduled = false;
33
+ this.batchDepth = 0;
34
+ }
35
+ schedule(effect2) {
36
+ if (effect2.disposed) return;
37
+ this.dirtyEffects.add(effect2);
38
+ this.lowPriorityEffects.delete(effect2);
39
+ this.ensureScheduled();
40
+ }
41
+ /** Queue an effect behind normal updates while preserving deterministic order. */
42
+ scheduleLow(effect2) {
43
+ if (effect2.disposed) return;
44
+ if (!this.dirtyEffects.has(effect2)) this.lowPriorityEffects.add(effect2);
45
+ this.ensureScheduled();
46
+ }
47
+ ensureScheduled() {
48
+ if (this.batchDepth === 0 && !this.flushing && !this.scheduled) {
49
+ this.scheduled = true;
50
+ queueMicrotask(() => {
51
+ this.scheduled = false;
52
+ this.flush();
53
+ });
54
+ }
55
+ }
56
+ remove(effect2) {
57
+ this.dirtyEffects.delete(effect2);
58
+ this.lowPriorityEffects.delete(effect2);
59
+ }
60
+ batch(fn) {
61
+ this.batchDepth++;
62
+ try {
63
+ return fn();
64
+ } finally {
65
+ this.batchDepth--;
66
+ if (this.batchDepth === 0) this.flush();
67
+ }
68
+ }
69
+ flush() {
70
+ if (this.flushing || this.batchDepth > 0) return;
71
+ this.flushing = true;
72
+ let rounds = 0;
73
+ let firstError;
74
+ let hasError = false;
75
+ try {
76
+ while (this.dirtyEffects.size > 0 || this.lowPriorityEffects.size > 0) {
77
+ if (++rounds > 100) {
78
+ this.dirtyEffects.clear();
79
+ this.lowPriorityEffects.clear();
80
+ throw new Error("Vobs: \u54CD\u5E94\u5F0F\u66F4\u65B0\u8D85\u8FC7 100 \u8F6E\uFF0C\u53EF\u80FD\u5B58\u5728\u5FAA\u73AF\u4F9D\u8D56");
81
+ }
82
+ this.collectRunnable(this.dirtyEffects, this.normalBuffer);
83
+ this.collectRunnable(this.lowPriorityEffects, this.lowBuffer);
84
+ sortEffects(this.normalBuffer);
85
+ sortEffects(this.lowBuffer);
86
+ for (const effect2 of this.normalBuffer) {
87
+ try {
88
+ effect2.run();
89
+ } catch (error) {
90
+ if (!hasError) {
91
+ firstError = error;
92
+ hasError = true;
93
+ }
94
+ }
95
+ }
96
+ for (const effect2 of this.lowBuffer) {
97
+ try {
98
+ effect2.run();
99
+ } catch (error) {
100
+ if (!hasError) {
101
+ firstError = error;
102
+ hasError = true;
103
+ }
104
+ }
105
+ }
106
+ this.normalBuffer.length = 0;
107
+ this.lowBuffer.length = 0;
108
+ }
109
+ } finally {
110
+ this.normalBuffer.length = 0;
111
+ this.lowBuffer.length = 0;
112
+ this.flushing = false;
113
+ }
114
+ if (hasError) throw firstError;
115
+ }
116
+ /** 收集未 disposed 的 effect 并清空源集合;run() 期间新调度的 effect 留给下一轮。 */
117
+ collectRunnable(source, target) {
118
+ for (const effect2 of source) {
119
+ if (!effect2.disposed) target.push(effect2);
120
+ }
121
+ source.clear();
122
+ }
123
+ };
124
+ __name(_Scheduler, "Scheduler");
125
+ function sortEffects(effects) {
126
+ if (effects.length > 1) {
127
+ effects.sort((a, b) => b.depth - a.depth || a.order - b.order);
128
+ }
129
+ }
130
+ __name(sortEffects, "sortEffects");
131
+
132
+ // packages/runtime/src/debug.ts
133
+ var activeRuntimeDebugContext = null;
134
+ function getRuntimeDebugContext() {
135
+ return activeRuntimeDebugContext;
136
+ }
137
+ __name(getRuntimeDebugContext, "getRuntimeDebugContext");
138
+
139
+ // packages/runtime/src/hmr.ts
140
+ var globalTarget = globalThis;
141
+ var hmrGlobal = globalTarget.__VOBS_HMR__ ?? { modules: /* @__PURE__ */ new Map() };
142
+ globalTarget.__VOBS_HMR__ = hmrGlobal;
143
+
144
+ // packages/vobs/src/app.ts
145
+ function createInjectionKey(description) {
146
+ return Symbol(description);
147
+ }
148
+ __name(createInjectionKey, "createInjectionKey");
149
+
150
+ // packages/http/src/stream.ts
151
+ function createSSE(url, options = {}) {
152
+ const EventSourceImpl = options.eventSource ?? globalThis.EventSource;
153
+ if (!EventSourceImpl) throw new Error("HTTP: \u5F53\u524D\u73AF\u5883\u6CA1\u6709\u53EF\u7528\u7684 EventSource");
154
+ const source = new EventSourceImpl(url, { withCredentials: options.withCredentials ?? false });
155
+ if (options.onOpen) source.addEventListener("open", options.onOpen);
156
+ if (options.onMessage) source.addEventListener("message", options.onMessage);
157
+ if (options.onError) source.addEventListener("error", options.onError);
158
+ return {
159
+ source,
160
+ close: /* @__PURE__ */ __name(() => source.close(), "close")
161
+ };
162
+ }
163
+ __name(createSSE, "createSSE");
164
+ function createWebSocket(url, options = {}) {
165
+ const WebSocketImpl = options.webSocket ?? globalThis.WebSocket;
166
+ if (!WebSocketImpl) throw new Error("HTTP: \u5F53\u524D\u73AF\u5883\u6CA1\u6709\u53EF\u7528\u7684 WebSocket");
167
+ const reconnectDelay = options.reconnectDelay ?? 1e3;
168
+ if (!Number.isFinite(reconnectDelay) || reconnectDelay < 0) {
169
+ throw new Error("HTTP: reconnectDelay \u5FC5\u987B\u662F\u5927\u4E8E\u7B49\u4E8E 0 \u7684\u6709\u9650\u6570\u5B57");
170
+ }
171
+ const listeners = /* @__PURE__ */ new Map();
172
+ let socket = null;
173
+ let state2 = "idle";
174
+ let manuallyClosed = false;
175
+ let reconnectTimer;
176
+ const client = {
177
+ get socket() {
178
+ return socket;
179
+ },
180
+ get state() {
181
+ return state2;
182
+ },
183
+ connect,
184
+ send(data) {
185
+ if (!socket || state2 !== "open") throw new Error("HTTP: WebSocket \u5C1A\u672A\u8FDE\u63A5");
186
+ socket.send(data);
187
+ },
188
+ close(code, reason) {
189
+ manuallyClosed = true;
190
+ if (reconnectTimer !== void 0) clearTimeout(reconnectTimer);
191
+ socket?.close(code, reason);
192
+ if (!socket) state2 = "closed";
193
+ },
194
+ on(event, listener) {
195
+ let eventListeners = listeners.get(event);
196
+ if (!eventListeners) {
197
+ eventListeners = /* @__PURE__ */ new Set();
198
+ listeners.set(event, eventListeners);
199
+ }
200
+ eventListeners.add(listener);
201
+ return () => eventListeners?.delete(listener);
202
+ }
203
+ };
204
+ connect();
205
+ return client;
206
+ function connect() {
207
+ if (state2 === "connecting" || state2 === "open") return;
208
+ manuallyClosed = false;
209
+ state2 = "connecting";
210
+ const protocols = options.protocols === void 0 ? void 0 : typeof options.protocols === "string" ? options.protocols : [...options.protocols];
211
+ socket = new WebSocketImpl(url, protocols);
212
+ socket.addEventListener("open", (event) => {
213
+ state2 = "open";
214
+ notify("open", event);
215
+ });
216
+ socket.addEventListener("message", (event) => notify("message", event));
217
+ socket.addEventListener("error", (event) => notify("error", event));
218
+ socket.addEventListener("close", (event) => {
219
+ state2 = "closed";
220
+ socket = null;
221
+ notify("close", event);
222
+ if (options.autoReconnect && !manuallyClosed) {
223
+ reconnectTimer = setTimeout(() => {
224
+ reconnectTimer = void 0;
225
+ connect();
226
+ }, reconnectDelay);
227
+ }
228
+ });
229
+ }
230
+ function notify(event, value) {
231
+ for (const listener of [...listeners.get(event) ?? []]) listener(value);
232
+ }
233
+ }
234
+ __name(createWebSocket, "createWebSocket");
235
+
236
+ // packages/http/src/debug.ts
237
+ var activeHTTPDebugHooks = null;
238
+ var httpDebugListeners = /* @__PURE__ */ new Set();
239
+ function setHTTPDebugHooks(hooks) {
240
+ const previous = activeHTTPDebugHooks;
241
+ activeHTTPDebugHooks = hooks;
242
+ return previous;
243
+ }
244
+ __name(setHTTPDebugHooks, "setHTTPDebugHooks");
245
+ function getHTTPDebugHooks() {
246
+ return activeHTTPDebugHooks;
247
+ }
248
+ __name(getHTTPDebugHooks, "getHTTPDebugHooks");
249
+ function subscribeHTTPDebug(listener) {
250
+ httpDebugListeners.add(listener);
251
+ return () => httpDebugListeners.delete(listener);
252
+ }
253
+ __name(subscribeHTTPDebug, "subscribeHTTPDebug");
254
+ function emitHTTPDebug(event) {
255
+ try {
256
+ activeHTTPDebugHooks?.request?.(event);
257
+ } catch {
258
+ }
259
+ for (const listener of [...httpDebugListeners]) {
260
+ try {
261
+ listener(event);
262
+ } catch {
263
+ }
264
+ }
265
+ }
266
+ __name(emitHTTPDebug, "emitHTTPDebug");
267
+
268
+ // packages/http/src/index.ts
269
+ var PROGRESS_HANDLED = Symbol("vobs.http.progress-handled");
270
+ var nextHTTPDebugId = 1;
271
+ function toResourceFetcher(request) {
272
+ return (signal) => Promise.resolve().then(() => request(signal)).then((response) => response.data);
273
+ }
274
+ __name(toResourceFetcher, "toResourceFetcher");
275
+ function createAxiosAdapter(request = builtInAxiosRequest) {
276
+ return async (config) => {
277
+ const { params: _params, ...requestConfig } = config;
278
+ const response = await request({ ...requestConfig, data: config.body });
279
+ return {
280
+ data: response.data,
281
+ status: response.status,
282
+ statusText: response.statusText ?? "",
283
+ headers: new Headers(response.headers),
284
+ config,
285
+ raw: response.raw ?? null
286
+ };
287
+ };
288
+ }
289
+ __name(createAxiosAdapter, "createAxiosAdapter");
290
+ function createMockAdapter(handler) {
291
+ return async (config) => {
292
+ const result = await handler(config);
293
+ if (isResponse(result) || isHTTPResponse(result)) return result;
294
+ return {
295
+ data: result,
296
+ status: 200,
297
+ statusText: "OK",
298
+ headers: new Headers(),
299
+ config,
300
+ raw: null
301
+ };
302
+ };
303
+ }
304
+ __name(createMockAdapter, "createMockAdapter");
305
+ function createXHRAdapter() {
306
+ return (config) => new Promise((resolve, reject) => {
307
+ if (typeof XMLHttpRequest === "undefined") {
308
+ reject(new Error("HTTP: \u5F53\u524D\u73AF\u5883\u6CA1\u6709\u53EF\u7528\u7684 XMLHttpRequest"));
309
+ return;
310
+ }
311
+ const xhr = new XMLHttpRequest();
312
+ xhr.open(config.method, config.url, true);
313
+ if (config.responseType === "arrayBuffer") xhr.responseType = "arraybuffer";
314
+ else if (config.responseType === "blob") xhr.responseType = "blob";
315
+ const signal = config.signal ?? config.state;
316
+ const abort = /* @__PURE__ */ __name(() => xhr.abort(), "abort");
317
+ if (signal?.aborted) {
318
+ reject(Object.assign(new Error("The operation was aborted"), { name: "AbortError" }));
319
+ return;
320
+ }
321
+ const cleanup = /* @__PURE__ */ __name(() => signal?.removeEventListener("abort", abort), "cleanup");
322
+ signal?.addEventListener("abort", abort, { once: true });
323
+ xhr.upload.onprogress = (event) => config.onUploadProgress?.(toProgress(event.loaded, event.lengthComputable ? event.total : void 0));
324
+ xhr.onprogress = (event) => config.onDownloadProgress?.(toProgress(event.loaded, event.lengthComputable ? event.total : void 0));
325
+ xhr.onload = () => {
326
+ cleanup();
327
+ const headers = new Headers();
328
+ xhr.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach((line) => {
329
+ const separator = line.indexOf(":");
330
+ if (separator > 0) headers.set(line.slice(0, separator).trim(), line.slice(separator + 1).trim());
331
+ });
332
+ const body = config.responseType === "arrayBuffer" || config.responseType === "blob" ? xhr.response : xhr.responseText;
333
+ const response = new Response(body, {
334
+ status: xhr.status,
335
+ statusText: xhr.statusText,
336
+ headers
337
+ });
338
+ Object.defineProperty(response, PROGRESS_HANDLED, { value: true });
339
+ resolve(response);
340
+ };
341
+ xhr.onerror = () => {
342
+ cleanup();
343
+ reject(new Error("HTTP: XMLHttpRequest \u7F51\u7EDC\u9519\u8BEF"));
344
+ };
345
+ xhr.onabort = () => {
346
+ cleanup();
347
+ reject(Object.assign(new Error("The operation was aborted"), { name: "AbortError" }));
348
+ };
349
+ try {
350
+ const headers = new Headers(config.headers);
351
+ const body = encodeBody(config.body, headers, config.method);
352
+ headers.forEach((value, key) => xhr.setRequestHeader(key, value));
353
+ xhr.send(body ?? null);
354
+ } catch (error) {
355
+ cleanup();
356
+ reject(error);
357
+ }
358
+ });
359
+ }
360
+ __name(createXHRAdapter, "createXHRAdapter");
361
+ function createFetchAdapter() {
362
+ return fetchAdapter;
363
+ }
364
+ __name(createFetchAdapter, "createFetchAdapter");
365
+ var _HTTPError = class _HTTPError extends Error {
366
+ constructor(response) {
367
+ super(`HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`);
368
+ this.name = "HTTPError";
369
+ this.status = response.status;
370
+ this.statusText = response.statusText;
371
+ this.data = response.data;
372
+ this.config = response.config;
373
+ this.response = response;
374
+ }
375
+ };
376
+ __name(_HTTPError, "HTTPError");
377
+ var HTTPError = _HTTPError;
378
+ var _TimeoutError = class _TimeoutError extends Error {
379
+ constructor(timeout) {
380
+ super(`HTTP \u8BF7\u6C42\u8D85\u8FC7 ${timeout}ms \u672A\u5B8C\u6210`);
381
+ this.code = "ETIMEDOUT";
382
+ this.name = "TimeoutError";
383
+ }
384
+ };
385
+ __name(_TimeoutError, "TimeoutError");
386
+ var TimeoutError = _TimeoutError;
387
+ var HTTP_KEY = createInjectionKey("vobs.http");
388
+ function createHTTPClient(options = {}) {
389
+ const defaults = normalizeClientOptions(options);
390
+ const requestInterceptors = createInterceptors();
391
+ const responseInterceptors = createInterceptors();
392
+ const adapter = options.adapter ?? createAxiosAdapter();
393
+ const limiter = createConcurrencyLimiter(options.concurrency ?? Infinity);
394
+ const pending = /* @__PURE__ */ new Map();
395
+ async function request(input) {
396
+ const initial = normalizeRequest(input, defaults);
397
+ const dedupeKey = getDedupeKey(initial, options.dedupe ?? false);
398
+ if (dedupeKey) {
399
+ const existing = pending.get(dedupeKey);
400
+ if (existing) return existing;
401
+ const shared = executeDebugRequest(initial);
402
+ pending.set(dedupeKey, shared);
403
+ void shared.finally(() => pending.delete(dedupeKey)).catch(() => void 0);
404
+ return shared;
405
+ }
406
+ return executeDebugRequest(initial);
407
+ }
408
+ __name(request, "request");
409
+ function executeDebugRequest(initial) {
410
+ const id = nextHTTPDebugId++;
411
+ const startedAt = Date.now();
412
+ const context = {
413
+ ...getRuntimeDebugContext(),
414
+ ...initial.debugContext
415
+ };
416
+ emitHTTPDebug({
417
+ id,
418
+ phase: "start",
419
+ status: "loading",
420
+ url: initial.url,
421
+ method: initial.method,
422
+ headers: debugHeaders(initial.headers),
423
+ requestBody: debugValue(initial.body),
424
+ startedAt,
425
+ attempt: 0,
426
+ retries: 0,
427
+ context: Object.keys(context).length > 0 ? context : void 0
428
+ });
429
+ return executeRequest(initial, id).then((response) => {
430
+ const endedAt = Date.now();
431
+ emitHTTPDebug({
432
+ id,
433
+ phase: "end",
434
+ status: "success",
435
+ url: response.config.url,
436
+ method: response.config.method,
437
+ headers: debugHeaders(response.config.headers),
438
+ requestBody: debugValue(response.config.body),
439
+ startedAt,
440
+ endedAt,
441
+ duration: endedAt - startedAt,
442
+ attempt: 0,
443
+ retries: 0,
444
+ responseStatus: response.status,
445
+ responseBody: debugValue(response.data),
446
+ context: Object.keys(context).length > 0 ? context : void 0
447
+ });
448
+ return response;
449
+ }, (error) => {
450
+ const endedAt = Date.now();
451
+ const cancelled = isAbortError(error);
452
+ emitHTTPDebug({
453
+ id,
454
+ phase: "end",
455
+ status: cancelled ? "cancelled" : "error",
456
+ url: initial.url,
457
+ method: initial.method,
458
+ headers: debugHeaders(initial.headers),
459
+ requestBody: debugValue(initial.body),
460
+ startedAt,
461
+ endedAt,
462
+ duration: endedAt - startedAt,
463
+ attempt: 0,
464
+ retries: 0,
465
+ responseStatus: error instanceof HTTPError ? error.status : void 0,
466
+ responseBody: error instanceof HTTPError ? debugValue(error.data) : void 0,
467
+ error: { name: error instanceof Error ? error.name : "Error", message: error instanceof Error ? error.message : String(error) },
468
+ context: Object.keys(context).length > 0 ? context : void 0
469
+ });
470
+ throw error;
471
+ });
472
+ }
473
+ __name(executeDebugRequest, "executeDebugRequest");
474
+ async function executeRequest(initial, debugId) {
475
+ const requestChain = requestInterceptors.handlers();
476
+ const responseChain = responseInterceptors.handlers().reverse();
477
+ let chain = Promise.resolve(initial);
478
+ for (const handler of requestChain) {
479
+ chain = chain.then(handler.onFulfilled, handler.onRejected);
480
+ }
481
+ chain = chain.then((config) => limiter(() => executeWithRetry(config, adapter, debugId)));
482
+ for (const handler of responseChain) {
483
+ chain = chain.then(handler.onFulfilled, handler.onRejected);
484
+ }
485
+ return chain;
486
+ }
487
+ __name(executeRequest, "executeRequest");
488
+ function method(methodName, url, input = {}) {
489
+ return request({ ...input, url, method: methodName });
490
+ }
491
+ __name(method, "method");
492
+ function methodWithBody(methodName, url, body, input = {}) {
493
+ return request({ ...input, url, method: methodName, body });
494
+ }
495
+ __name(methodWithBody, "methodWithBody");
496
+ const client = {
497
+ interceptors: {
498
+ request: requestInterceptors,
499
+ response: responseInterceptors
500
+ },
501
+ request,
502
+ get: /* @__PURE__ */ __name((url, input) => method("GET", url, input), "get"),
503
+ delete: /* @__PURE__ */ __name((url, input) => method("DELETE", url, input), "delete"),
504
+ head: /* @__PURE__ */ __name((url, input) => method("HEAD", url, input), "head"),
505
+ post: /* @__PURE__ */ __name((url, body, input) => methodWithBody("POST", url, body, input), "post"),
506
+ put: /* @__PURE__ */ __name((url, body, input) => methodWithBody("PUT", url, body, input), "put"),
507
+ patch: /* @__PURE__ */ __name((url, body, input) => methodWithBody("PATCH", url, body, input), "patch")
508
+ };
509
+ return client;
510
+ async function executeWithRetry(config, requestAdapter, debugId) {
511
+ const controller = new AbortController();
512
+ const inputSignal = config.signal ?? config.state;
513
+ let timedOut = false;
514
+ let timeoutId;
515
+ const abortFromInput = /* @__PURE__ */ __name(() => controller.abort(inputSignal?.reason), "abortFromInput");
516
+ if (inputSignal) {
517
+ if (inputSignal.aborted) controller.abort(inputSignal.reason);
518
+ else inputSignal.addEventListener("abort", abortFromInput, { once: true });
519
+ }
520
+ if (config.timeout !== void 0 && config.timeout > 0) {
521
+ timeoutId = setTimeout(() => {
522
+ timedOut = true;
523
+ controller.abort();
524
+ }, config.timeout);
525
+ }
526
+ const adapterConfig = { ...config, signal: controller.signal };
527
+ let attempt = 0;
528
+ try {
529
+ while (true) {
530
+ try {
531
+ const result = await requestAdapter(adapterConfig);
532
+ const response = isHTTPResponse(result) ? result : await parseResponse(result, adapterConfig);
533
+ if (response.status < 200 || response.status >= 300) throw new HTTPError(response);
534
+ return response;
535
+ } catch (error) {
536
+ if (timedOut) throw new TimeoutError(config.timeout);
537
+ if (inputSignal?.aborted || isAbortError(error)) throw error;
538
+ const nextAttempt = attempt + 1;
539
+ if (nextAttempt > (config.retry ?? 0)) throw toError(error);
540
+ const shouldRetry = config.shouldRetry ? await config.shouldRetry(toError(error), nextAttempt) : isRetryable(error);
541
+ if (!shouldRetry) throw toError(error);
542
+ attempt = nextAttempt;
543
+ const retryContext = {
544
+ ...getRuntimeDebugContext(),
545
+ ...config.debugContext
546
+ };
547
+ emitHTTPDebug({
548
+ id: debugId ?? 0,
549
+ phase: "retry",
550
+ status: "retrying",
551
+ url: config.url,
552
+ method: config.method,
553
+ headers: debugHeaders(config.headers),
554
+ requestBody: debugValue(config.body),
555
+ startedAt: Date.now(),
556
+ attempt,
557
+ retries: attempt,
558
+ error: { name: toError(error).name, message: toError(error).message },
559
+ context: Object.keys(retryContext).length > 0 ? retryContext : void 0
560
+ });
561
+ const delay = resolveRetryDelay(config.retryDelay ?? 0, attempt, toError(error));
562
+ if (delay > 0) await wait(delay);
563
+ }
564
+ }
565
+ } finally {
566
+ if (timeoutId !== void 0) clearTimeout(timeoutId);
567
+ inputSignal?.removeEventListener("abort", abortFromInput);
568
+ }
569
+ }
570
+ }
571
+ __name(createHTTPClient, "createHTTPClient");
572
+ function debugHeaders(headers) {
573
+ const safe = {};
574
+ for (const [key, value] of Object.entries(headers)) {
575
+ if (/authorization|cookie|token|password|secret|api[-_]?key/i.test(key)) continue;
576
+ safe[key] = value;
577
+ }
578
+ return safe;
579
+ }
580
+ __name(debugHeaders, "debugHeaders");
581
+ function debugValue(value, depth = 0) {
582
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
583
+ if (value === void 0) return void 0;
584
+ if (depth >= 2) return "[MaxDepth]";
585
+ if (typeof value === "bigint") return `${value}n`;
586
+ if (typeof value === "function") return `[Function ${value.name || "anonymous"}]`;
587
+ if (typeof value !== "object") return String(value);
588
+ if (Array.isArray(value)) return value.slice(0, 20).map((item) => debugValue(item, depth + 1));
589
+ try {
590
+ return Object.fromEntries(Object.entries(value).slice(0, 30).map(([key, item]) => [key, debugValue(item, depth + 1)]));
591
+ } catch {
592
+ return "[Uninspectable]";
593
+ }
594
+ }
595
+ __name(debugValue, "debugValue");
596
+ function httpPlugin(options = {}) {
597
+ return {
598
+ name: "@vobs/http",
599
+ version: "0.1.0",
600
+ install(context) {
601
+ const client = options.client ?? createHTTPClient(options);
602
+ context.provide(HTTP_KEY, client);
603
+ }
604
+ };
605
+ }
606
+ __name(httpPlugin, "httpPlugin");
607
+ function createInterceptors() {
608
+ const entries = [];
609
+ return {
610
+ use(onFulfilled, onRejected) {
611
+ entries.push({
612
+ onFulfilled: /* @__PURE__ */ __name((value) => onFulfilled ? onFulfilled(value) : value, "onFulfilled"),
613
+ onRejected: /* @__PURE__ */ __name((error) => onRejected ? onRejected(error) : Promise.reject(error), "onRejected")
614
+ });
615
+ return entries.length - 1;
616
+ },
617
+ eject(id) {
618
+ if (id >= 0 && id < entries.length) entries[id] = null;
619
+ },
620
+ clear() {
621
+ entries.fill(null);
622
+ },
623
+ handlers() {
624
+ return entries.filter((entry) => entry !== null);
625
+ }
626
+ };
627
+ }
628
+ __name(createInterceptors, "createInterceptors");
629
+ function normalizeClientOptions(options) {
630
+ return {
631
+ baseURL: options.baseURL ?? "",
632
+ headers: options.headers ?? {},
633
+ timeout: validateTimeout(options.timeout ?? 0),
634
+ retry: validateRetry(options.retry ?? 0),
635
+ retryDelay: options.retryDelay ?? 0,
636
+ shouldRetry: options.shouldRetry
637
+ };
638
+ }
639
+ __name(normalizeClientOptions, "normalizeClientOptions");
640
+ function createConcurrencyLimiter(limit) {
641
+ if (limit !== Infinity && (!Number.isFinite(limit) || limit < 1 || !Number.isInteger(limit))) {
642
+ throw new Error("HTTP: concurrency \u5FC5\u987B\u662F\u5927\u4E8E\u7B49\u4E8E 1 \u7684\u6574\u6570");
643
+ }
644
+ let active = 0;
645
+ const queue = [];
646
+ return (task) => new Promise((resolve, reject) => {
647
+ const run = /* @__PURE__ */ __name(() => {
648
+ active++;
649
+ Promise.resolve().then(task).then(resolve, reject).finally(() => {
650
+ active--;
651
+ queue.shift()?.();
652
+ });
653
+ }, "run");
654
+ if (active < limit) run();
655
+ else queue.push(run);
656
+ });
657
+ }
658
+ __name(createConcurrencyLimiter, "createConcurrencyLimiter");
659
+ function getDedupeKey(config, defaultEnabled) {
660
+ if (config.dedupe === false) return void 0;
661
+ if (config.dedupeKey) return config.dedupeKey;
662
+ if (!(config.dedupe ?? defaultEnabled)) return void 0;
663
+ if (config.method !== "GET" && config.method !== "HEAD") return void 0;
664
+ return `${config.method} ${config.url}`;
665
+ }
666
+ __name(getDedupeKey, "getDedupeKey");
667
+ function normalizeRequest(input, defaults) {
668
+ if (!input.url) throw new Error("HTTP: url \u4E0D\u80FD\u4E3A\u7A7A");
669
+ const method = (input.method ?? "GET").toUpperCase();
670
+ const timeout = validateTimeout(input.timeout ?? defaults.timeout);
671
+ const retry = validateRetry(input.retry ?? defaults.retry);
672
+ const retryDelay = input.retryDelay ?? defaults.retryDelay;
673
+ const signal = input.signal ?? input.state;
674
+ if (input.signal && input.state && input.signal !== input.state) {
675
+ throw new Error("HTTP: signal \u548C state \u4E0D\u80FD\u540C\u65F6\u6307\u5411\u4E0D\u540C\u7684 AbortSignal");
676
+ }
677
+ return {
678
+ ...input,
679
+ url: appendParams(resolveURL(input.url, input.baseURL ?? defaults.baseURL), input.params),
680
+ method,
681
+ headers: toHeaders(defaults.headers, input.headers),
682
+ timeout,
683
+ retry,
684
+ retryDelay,
685
+ shouldRetry: input.shouldRetry ?? defaults.shouldRetry,
686
+ signal
687
+ };
688
+ }
689
+ __name(normalizeRequest, "normalizeRequest");
690
+ async function fetchAdapter(config) {
691
+ if (typeof fetch !== "function") throw new Error("HTTP: \u5F53\u524D\u73AF\u5883\u6CA1\u6709\u53EF\u7528\u7684 fetch");
692
+ const headers = new Headers(config.headers);
693
+ const body = encodeBody(config.body, headers, config.method);
694
+ return fetch(config.url, {
695
+ method: config.method,
696
+ headers,
697
+ body,
698
+ signal: config.signal,
699
+ cache: config.cache,
700
+ credentials: config.credentials,
701
+ mode: config.mode
702
+ });
703
+ }
704
+ __name(fetchAdapter, "fetchAdapter");
705
+ async function parseResponse(response, config) {
706
+ const data = config.responseType === "response" ? response : await parseBody(response, config.responseType, hasHandledProgress(response) ? void 0 : config.onDownloadProgress);
707
+ return {
708
+ data,
709
+ status: response.status,
710
+ statusText: response.statusText,
711
+ headers: response.headers,
712
+ config,
713
+ raw: response
714
+ };
715
+ }
716
+ __name(parseResponse, "parseResponse");
717
+ var builtInAxiosRequest = /* @__PURE__ */ __name(async (config) => {
718
+ const responseType = config.responseType === "response" ? "arraybuffer" : toAxiosResponseType(config.responseType);
719
+ const response = await axios__default.default.request({
720
+ url: config.url,
721
+ method: config.method,
722
+ headers: config.headers,
723
+ data: config.method === "GET" || config.method === "HEAD" ? void 0 : config.body,
724
+ signal: config.signal,
725
+ timeout: config.timeout,
726
+ responseType,
727
+ withCredentials: toAxiosCredentials(config.credentials),
728
+ validateStatus: /* @__PURE__ */ __name(() => true, "validateStatus"),
729
+ adapter: "fetch",
730
+ fetchOptions: compactFetchOptions(config),
731
+ onUploadProgress: /* @__PURE__ */ __name((event) => config.onUploadProgress?.(toAxiosProgress(event.loaded, event.total)), "onUploadProgress"),
732
+ onDownloadProgress: /* @__PURE__ */ __name((event) => config.onDownloadProgress?.(toAxiosProgress(event.loaded, event.total)), "onDownloadProgress")
733
+ });
734
+ const raw = config.responseType === "response" ? toRawResponse(response.data, response.status, response.statusText, response.headers) : null;
735
+ return {
736
+ data: raw ?? response.data,
737
+ status: response.status,
738
+ statusText: response.statusText,
739
+ headers: typeof response.headers?.toJSON === "function" ? response.headers.toJSON() : response.headers,
740
+ raw
741
+ };
742
+ }, "builtInAxiosRequest");
743
+ function toAxiosCredentials(credentials) {
744
+ if (credentials === "include") return true;
745
+ if (credentials === "omit") return false;
746
+ return void 0;
747
+ }
748
+ __name(toAxiosCredentials, "toAxiosCredentials");
749
+ function toRawResponse(data, status, statusText, headers) {
750
+ if (typeof Response === "undefined") throw new Error("HTTP: \u5F53\u524D\u73AF\u5883\u6CA1\u6709\u53EF\u7528\u7684 Response");
751
+ const body = status === 204 || status === 205 ? null : data;
752
+ return new Response(body, {
753
+ status,
754
+ statusText: statusText ?? "",
755
+ headers: new Headers(headers)
756
+ });
757
+ }
758
+ __name(toRawResponse, "toRawResponse");
759
+ function toAxiosResponseType(responseType) {
760
+ if (responseType === "arrayBuffer") return "arraybuffer";
761
+ if (responseType === "response") return void 0;
762
+ return responseType;
763
+ }
764
+ __name(toAxiosResponseType, "toAxiosResponseType");
765
+ function compactFetchOptions(config) {
766
+ const options = {
767
+ cache: config.cache,
768
+ credentials: config.credentials,
769
+ mode: config.mode
770
+ };
771
+ const entries = Object.entries(options).filter(([, value]) => value !== void 0);
772
+ return entries.length === 0 ? void 0 : Object.fromEntries(entries);
773
+ }
774
+ __name(compactFetchOptions, "compactFetchOptions");
775
+ function toAxiosProgress(loaded, total) {
776
+ return {
777
+ loaded,
778
+ total,
779
+ percent: total && total > 0 ? loaded / total * 100 : void 0
780
+ };
781
+ }
782
+ __name(toAxiosProgress, "toAxiosProgress");
783
+ async function parseBody(response, responseType, onDownloadProgress) {
784
+ if (response.status === 204 || response.status === 205) return null;
785
+ const bytes = onDownloadProgress && response.body ? await readResponseBytes(response, onDownloadProgress) : void 0;
786
+ if (responseType === "blob") return bytes ? new Blob([bytes]) : response.blob();
787
+ if (responseType === "arrayBuffer") return bytes ? bytes.buffer : response.arrayBuffer();
788
+ const text = bytes ? new TextDecoder().decode(bytes) : await response.text();
789
+ if (responseType === "text") return text;
790
+ if (!text) return null;
791
+ if (responseType === "json" || response.headers.get("content-type")?.includes("json")) {
792
+ try {
793
+ return JSON.parse(text);
794
+ } catch {
795
+ throw new Error("HTTP: \u54CD\u5E94\u4E0D\u662F\u6709\u6548 JSON");
796
+ }
797
+ }
798
+ return text;
799
+ }
800
+ __name(parseBody, "parseBody");
801
+ async function readResponseBytes(response, onProgress) {
802
+ const reader = response.body.getReader();
803
+ const chunks = [];
804
+ const totalHeader = response.headers.get("content-length");
805
+ const parsedTotal = totalHeader ? Number(totalHeader) : NaN;
806
+ const total = Number.isFinite(parsedTotal) && parsedTotal >= 0 ? parsedTotal : void 0;
807
+ let loaded = 0;
808
+ while (true) {
809
+ const next = await reader.read();
810
+ if (next.done) break;
811
+ chunks.push(next.value);
812
+ loaded += next.value.byteLength;
813
+ onProgress(toProgress(loaded, total));
814
+ }
815
+ const result = new Uint8Array(loaded);
816
+ let offset = 0;
817
+ for (const chunk of chunks) {
818
+ result.set(chunk, offset);
819
+ offset += chunk.byteLength;
820
+ }
821
+ return result;
822
+ }
823
+ __name(readResponseBytes, "readResponseBytes");
824
+ function isHTTPResponse(value) {
825
+ return typeof value === "object" && value !== null && "data" in value && "status" in value && "config" in value;
826
+ }
827
+ __name(isHTTPResponse, "isHTTPResponse");
828
+ function isResponse(value) {
829
+ return typeof Response !== "undefined" && value instanceof Response;
830
+ }
831
+ __name(isResponse, "isResponse");
832
+ function hasHandledProgress(response) {
833
+ return Boolean(response[PROGRESS_HANDLED]);
834
+ }
835
+ __name(hasHandledProgress, "hasHandledProgress");
836
+ function encodeBody(body, headers, method) {
837
+ if (body === void 0 || body === null || method === "GET" || method === "HEAD") return void 0;
838
+ if (typeof body === "string" || body instanceof Blob || body instanceof FormData || body instanceof ArrayBuffer || body instanceof URLSearchParams) return body;
839
+ if (!headers.has("content-type")) headers.set("content-type", "application/json");
840
+ return JSON.stringify(body);
841
+ }
842
+ __name(encodeBody, "encodeBody");
843
+ function toHeaders(...inputs) {
844
+ const headers = new Headers();
845
+ for (const input of inputs) {
846
+ if (!input) continue;
847
+ new Headers(input).forEach((value, key) => headers.set(key, value));
848
+ }
849
+ const result = {};
850
+ headers.forEach((value, key) => {
851
+ result[key] = value;
852
+ });
853
+ return result;
854
+ }
855
+ __name(toHeaders, "toHeaders");
856
+ function resolveURL(url, baseURL) {
857
+ if (!baseURL || /^[a-z][a-z\d+.-]*:/i.test(url) || url.startsWith("//")) return url;
858
+ if (!baseURL) return url;
859
+ return `${baseURL.replace(/\/$/, "")}/${url.replace(/^\//, "")}`;
860
+ }
861
+ __name(resolveURL, "resolveURL");
862
+ function appendParams(url, params) {
863
+ if (!params) return url;
864
+ const query = params instanceof URLSearchParams ? params : toSearchParams(params);
865
+ const serialized = query.toString();
866
+ if (!serialized) return url;
867
+ return `${url}${url.includes("?") ? "&" : "?"}${serialized}`;
868
+ }
869
+ __name(appendParams, "appendParams");
870
+ function toSearchParams(params) {
871
+ const search = new URLSearchParams();
872
+ for (const [key, value] of Object.entries(params)) {
873
+ if (value === void 0 || value === null) continue;
874
+ if (Array.isArray(value)) {
875
+ for (const item of value) search.append(key, String(item));
876
+ } else if (typeof value === "object") {
877
+ search.set(key, JSON.stringify(value));
878
+ } else {
879
+ search.set(key, String(value));
880
+ }
881
+ }
882
+ return search;
883
+ }
884
+ __name(toSearchParams, "toSearchParams");
885
+ function isRetryable(error) {
886
+ return error instanceof HTTPError ? error.status === 429 || error.status >= 500 : !isAbortError(error);
887
+ }
888
+ __name(isRetryable, "isRetryable");
889
+ function isAbortError(error) {
890
+ return Boolean(error) && typeof error === "object" && (error.name === "AbortError" || error.code === "ERR_CANCELED");
891
+ }
892
+ __name(isAbortError, "isAbortError");
893
+ function resolveRetryDelay(retryDelay, attempt, error) {
894
+ const delay = typeof retryDelay === "function" ? retryDelay(attempt, error) : retryDelay;
895
+ if (!Number.isFinite(delay) || delay < 0) throw new Error("HTTP: retryDelay \u5FC5\u987B\u662F\u5927\u4E8E\u7B49\u4E8E 0 \u7684\u6709\u9650\u6570\u5B57");
896
+ return delay;
897
+ }
898
+ __name(resolveRetryDelay, "resolveRetryDelay");
899
+ function validateRetry(retry) {
900
+ if (!Number.isInteger(retry) || retry < 0) throw new Error("HTTP: retry \u5FC5\u987B\u662F\u5927\u4E8E\u7B49\u4E8E 0 \u7684\u6574\u6570");
901
+ return retry;
902
+ }
903
+ __name(validateRetry, "validateRetry");
904
+ function validateTimeout(timeout) {
905
+ if (!Number.isFinite(timeout) || timeout < 0) throw new Error("HTTP: timeout \u5FC5\u987B\u662F\u5927\u4E8E\u7B49\u4E8E 0 \u7684\u6709\u9650\u6570\u5B57");
906
+ return timeout;
907
+ }
908
+ __name(validateTimeout, "validateTimeout");
909
+ function toError(error) {
910
+ return error instanceof Error ? error : new Error(String(error));
911
+ }
912
+ __name(toError, "toError");
913
+ function wait(delay) {
914
+ return new Promise((resolve) => setTimeout(resolve, delay));
915
+ }
916
+ __name(wait, "wait");
917
+ function toProgress(loaded, total) {
918
+ return {
919
+ loaded,
920
+ total,
921
+ percent: total && total > 0 ? loaded / total * 100 : void 0
922
+ };
923
+ }
924
+ __name(toProgress, "toProgress");
925
+
926
+ exports.HTTPError = HTTPError;
927
+ exports.HTTP_KEY = HTTP_KEY;
928
+ exports.TimeoutError = TimeoutError;
929
+ exports.createAxiosAdapter = createAxiosAdapter;
930
+ exports.createConcurrencyLimiter = createConcurrencyLimiter;
931
+ exports.createFetchAdapter = createFetchAdapter;
932
+ exports.createHTTPClient = createHTTPClient;
933
+ exports.createMockAdapter = createMockAdapter;
934
+ exports.createSSE = createSSE;
935
+ exports.createWebSocket = createWebSocket;
936
+ exports.createXHRAdapter = createXHRAdapter;
937
+ exports.emitHTTPDebug = emitHTTPDebug;
938
+ exports.getHTTPDebugHooks = getHTTPDebugHooks;
939
+ exports.httpPlugin = httpPlugin;
940
+ exports.setHTTPDebugHooks = setHTTPDebugHooks;
941
+ exports.subscribeHTTPDebug = subscribeHTTPDebug;
942
+ exports.toResourceFetcher = toResourceFetcher;
943
+ //# sourceMappingURL=index.cjs.map
944
+ //# sourceMappingURL=index.cjs.map