vigor-fetch 1.0.4 → 1.0.6

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) [2024] [Uav1010 / Your Full Name]
3
+ Copyright (c) [2024] [Uav1010]
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -12,7 +12,7 @@
12
12
  - 🎯 **Immutable Chaining**: Every configuration method returns a new instance, making it perfect for base templates and functional patterns.
13
13
 
14
14
  ## 📦 Installation
15
- ```terminal
15
+ ```powershell
16
16
 
17
17
  npm install vigor-fetch
18
18
 
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- interface VigorErrorOptions {
1
+ export interface VigorErrorOptions {
2
2
  url?: string | null;
3
3
  status?: number;
4
4
  message?: string;
5
5
  data?: any;
6
6
  }
7
- interface VigorFetchConfig {
7
+ export interface VigorFetchConfig {
8
8
  path: string;
9
9
  method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | null;
10
10
  offset: RequestInit;
@@ -53,7 +53,7 @@ declare class VigorFetch<T = any> {
53
53
  onError(...arg: VigorFetchConfig['onError']): VigorFetch<T>;
54
54
  request(): Promise<T>;
55
55
  }
56
- interface VigorAllConfig {
56
+ export interface VigorAllConfig {
57
57
  limit: number;
58
58
  jitter: number;
59
59
  promises: Array<() => Promise<any>>;
@@ -71,5 +71,4 @@ declare class Vigor {
71
71
  fetch<T = any>(origin: string, config?: VigorFetchConfig): VigorFetch<T>;
72
72
  all(config?: VigorAllConfig): VigorAll;
73
73
  }
74
-
75
- export { type VigorAllConfig, type VigorErrorOptions, type VigorFetchConfig, Vigor as default };
74
+ export default Vigor;
package/dist/index.js CHANGED
@@ -1,282 +1,194 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ 'use strict';
19
2
 
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- default: () => index_default
24
- });
25
- module.exports = __toCommonJS(index_exports);
26
- var VigorError = class extends Error {
27
- constructor(text, { url = null, status = 0, message, data = null }) {
28
- super(text);
29
- this.name = "VigorError";
30
- this.url = url;
31
- this.status = status;
32
- this.message = message || text;
33
- this.data = data;
34
- }
35
- };
36
- var VigorFetch = class _VigorFetch {
37
- constructor(origin, config) {
38
- this._origin = origin;
39
- this._config = config || {
40
- path: "",
41
- method: null,
42
- offset: {},
43
- headers: {},
44
- body: null,
45
- count: 5,
46
- max: 5e3,
47
- wait: 1e4,
48
- backoff: 1.3,
49
- unretry: /* @__PURE__ */ new Set([400, 401, 403, 404, 405, 413, 422]),
50
- retryHeader: ["retry-after", "ratelimit-reset", "x-ratelimit-reset", "x-retry-after", "x-amz-retry-after", "chrome-proxy-next-link"],
51
- original: false,
52
- parse: null,
53
- query: {},
54
- jitter: 500,
55
- beforeRequest: [],
56
- afterRequest: [],
57
- beforeResponse: [],
58
- afterResponse: [],
59
- onError: []
60
- };
61
- }
62
- _next(changes) {
63
- return new _VigorFetch(this._origin, { ...this._config, ...changes });
64
- }
65
- path(arg) {
66
- return this._next({ path: arg });
67
- }
68
- method(arg) {
69
- return this._next({ method: arg });
70
- }
71
- offset(arg) {
72
- return this._next({ offset: arg });
73
- }
74
- headers(arg) {
75
- return this._next({ headers: arg });
76
- }
77
- body(arg) {
78
- return this._next({ body: arg });
79
- }
80
- count(arg) {
81
- return this._next({ count: arg });
82
- }
83
- max(arg) {
84
- return this._next({ max: arg });
85
- }
86
- wait(arg) {
87
- return this._next({ wait: arg });
88
- }
89
- backoff(arg) {
90
- return this._next({ backoff: arg });
91
- }
92
- unretry(arg) {
93
- return this._next({ unretry: new Set(arg) });
94
- }
95
- retryHeader(...arg) {
96
- return this._next({ retryHeader: [...this._config.retryHeader, ...arg] });
97
- }
98
- original(arg) {
99
- return this._next({ original: arg });
100
- }
101
- parse(arg) {
102
- return this._next({ parse: arg });
103
- }
104
- query(arg) {
105
- return this._next({ query: { ...this._config.query, ...arg } });
106
- }
107
- jitter(arg) {
108
- return this._next({ jitter: arg });
109
- }
110
- beforeRequest(...arg) {
111
- return this._next({ beforeRequest: [...this._config.beforeRequest, ...arg] });
112
- }
113
- afterRequest(...arg) {
114
- return this._next({ afterRequest: [...this._config.afterRequest, ...arg] });
115
- }
116
- beforeResponse(...arg) {
117
- return this._next({ beforeResponse: [...this._config.beforeResponse, ...arg] });
118
- }
119
- afterResponse(...arg) {
120
- return this._next({ afterResponse: [...this._config.afterResponse, ...arg] });
121
- }
122
- onError(...arg) {
123
- return this._next({ onError: [...this._config.onError, ...arg] });
124
- }
125
- async request() {
126
- const {
127
- path,
128
- method,
129
- offset,
130
- headers,
131
- body,
132
- query,
133
- count,
134
- max,
135
- wait,
136
- backoff,
137
- unretry,
138
- jitter,
139
- original,
140
- parse,
141
- retryHeader,
142
- beforeRequest,
143
- afterRequest,
144
- beforeResponse,
145
- afterResponse,
146
- onError
147
- } = this._config;
148
- try {
149
- if (!/^(https?|data|blob|file|about):\/\//.test(this._origin)) {
150
- throw new VigorError(`[vigor] ${this._origin} >> Invalid Protocol`, {
151
- url: this._origin,
152
- status: 0,
153
- message: "Invalid Protocol"
154
- });
155
- }
156
- const urlObj = new URL(path.replace(/^\//, ""), this._origin + "/");
157
- Object.entries(query).forEach(([key, value]) => {
158
- if (value !== null && value !== void 0) urlObj.searchParams.append(key, String(value));
159
- });
160
- const url = urlObj.href;
161
- const isJson = Array.isArray(body) || !!body && Object.getPrototypeOf(body) === Object.prototype;
162
- const waitTimeout = (time) => new Promise((resolve) => setTimeout(resolve, time));
163
- let option = {
164
- ...offset,
165
- method: method || (body ? "POST" : "GET"),
166
- headers: { ...isJson && { "Content-Type": "application/json" }, ...headers },
167
- ...body && { body: isJson ? JSON.stringify(body) : body }
168
- };
169
- for (const hook of beforeRequest) {
170
- const modified = await hook(option);
171
- if (modified) option = { ...option, ...modified };
172
- }
173
- let req;
174
- for (let i = 0; i < count; i++) {
175
- const controller = new AbortController();
176
- const abort = setTimeout(() => controller.abort(), max);
177
- option.signal = controller.signal;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ class VigorError extends Error {
5
+ constructor(text, { url = null, status = 0, message, data = null }) {
6
+ super(text);
7
+ this.name = "VigorError";
8
+ this.url = url;
9
+ this.status = status;
10
+ this.message = message || text;
11
+ this.data = data;
12
+ }
13
+ }
14
+ class VigorFetch {
15
+ constructor(origin, config) {
16
+ this._origin = origin;
17
+ this._config = config || {
18
+ path: "", method: null, offset: {}, headers: {}, body: null,
19
+ count: 5, max: 5000, wait: 10000, backoff: 1.3,
20
+ unretry: new Set([400, 401, 403, 404, 405, 413, 422]),
21
+ retryHeader: ["retry-after", "ratelimit-reset", "x-ratelimit-reset", "x-retry-after", "x-amz-retry-after", "chrome-proxy-next-link"],
22
+ original: false, parse: null, query: {}, jitter: 500,
23
+ beforeRequest: [], afterRequest: [], beforeResponse: [], afterResponse: [], onError: []
24
+ };
25
+ }
26
+ _next(changes) {
27
+ return new VigorFetch(this._origin, { ...this._config, ...changes });
28
+ }
29
+ path(arg) { return this._next({ path: arg }); }
30
+ method(arg) { return this._next({ method: arg }); }
31
+ offset(arg) { return this._next({ offset: arg }); }
32
+ headers(arg) { return this._next({ headers: arg }); }
33
+ body(arg) { return this._next({ body: arg }); }
34
+ count(arg) { return this._next({ count: arg }); }
35
+ max(arg) { return this._next({ max: arg }); }
36
+ wait(arg) { return this._next({ wait: arg }); }
37
+ backoff(arg) { return this._next({ backoff: arg }); }
38
+ unretry(arg) { return this._next({ unretry: new Set(arg) }); }
39
+ retryHeader(...arg) { return this._next({ retryHeader: [...this._config.retryHeader, ...arg] }); }
40
+ original(arg) { return this._next({ original: arg }); }
41
+ parse(arg) { return this._next({ parse: arg }); }
42
+ query(arg) { return this._next({ query: { ...this._config.query, ...arg } }); }
43
+ jitter(arg) { return this._next({ jitter: arg }); }
44
+ beforeRequest(...arg) { return this._next({ beforeRequest: [...this._config.beforeRequest, ...arg] }); }
45
+ afterRequest(...arg) { return this._next({ afterRequest: [...this._config.afterRequest, ...arg] }); }
46
+ beforeResponse(...arg) { return this._next({ beforeResponse: [...this._config.beforeResponse, ...arg] }); }
47
+ afterResponse(...arg) { return this._next({ afterResponse: [...this._config.afterResponse, ...arg] }); }
48
+ onError(...arg) { return this._next({ onError: [...this._config.onError, ...arg] }); }
49
+ async request() {
50
+ const { path, method, offset, headers, body, query, count, max, wait, backoff, unretry, jitter, original, parse, retryHeader, beforeRequest, afterRequest, beforeResponse, afterResponse, onError, } = this._config;
178
51
  try {
179
- req = await fetch(url, option);
180
- for (const hook of afterRequest) {
181
- req = await hook(req) || req;
182
- }
183
- if (req.ok) {
184
- clearTimeout(abort);
185
- break;
186
- }
187
- } catch (error) {
188
- clearTimeout(abort);
189
- if (i === count - 1) throw new VigorError(`[vigor] ${url} >> Network Error`, { url, status: 0, message: "Network Error" });
190
- } finally {
191
- clearTimeout(abort);
52
+ if (!/^(https?|data|blob|file|about):\/\//.test(this._origin)) {
53
+ throw new VigorError(`[vigor] ${this._origin} >> Invalid Protocol`, {
54
+ url: this._origin, status: 0, message: "Invalid Protocol"
55
+ });
56
+ }
57
+ const urlObj = new URL(path.replace(/^\//, ""), this._origin + "/");
58
+ Object.entries(query).forEach(([key, value]) => {
59
+ if (value !== null && value !== undefined)
60
+ urlObj.searchParams.append(key, String(value));
61
+ });
62
+ const url = urlObj.href;
63
+ const isJson = Array.isArray(body) || (!!body && Object.getPrototypeOf(body) === Object.prototype);
64
+ const waitTimeout = (time) => new Promise(resolve => setTimeout(resolve, time));
65
+ let option = {
66
+ ...offset,
67
+ method: method || (body ? "POST" : "GET"),
68
+ headers: { ...(isJson && { "Content-Type": "application/json" }), ...headers },
69
+ ...(body && { body: isJson ? JSON.stringify(body) : body }),
70
+ };
71
+ for (const hook of beforeRequest) {
72
+ const modified = await hook(option);
73
+ if (modified)
74
+ option = { ...option, ...modified };
75
+ }
76
+ let req;
77
+ for (let i = 0; i < count; i++) {
78
+ const controller = new AbortController();
79
+ const abort = setTimeout(() => controller.abort(), max);
80
+ option.signal = controller.signal;
81
+ try {
82
+ req = await fetch(url, option);
83
+ for (const hook of afterRequest) {
84
+ req = (await hook(req)) || req;
85
+ }
86
+ if (req.ok) {
87
+ clearTimeout(abort);
88
+ break;
89
+ }
90
+ }
91
+ catch (error) {
92
+ clearTimeout(abort);
93
+ if (i === count - 1)
94
+ throw new VigorError(`[vigor] ${url} >> Network Error`, { url, status: 0, message: "Network Error" });
95
+ }
96
+ finally {
97
+ clearTimeout(abort);
98
+ }
99
+ if (req) {
100
+ const status = req.status;
101
+ if (unretry.has(status))
102
+ throw new VigorError(`[vigor] ${url} >> Unretry ${status}`, { url, status, message: "Unretry", data: status });
103
+ const basic = Math.min(Math.pow(backoff, i) * 1000, wait) + Math.random() * jitter;
104
+ if (status === 429) {
105
+ const rHeader = retryHeader.map(h => req?.headers.get(h)).find(Boolean);
106
+ const delay = rHeader ? (isNaN(Number(rHeader)) ? new Date(rHeader).getTime() - Date.now() : Number(rHeader) * 1000) : 0;
107
+ const parsedDelay = Math.max(0, delay) + Math.random() * jitter;
108
+ if (parsedDelay > wait)
109
+ throw new VigorError(`[vigor] ${url} >> Timeouted ${parsedDelay}ms`, { url, status, message: "Timeouted", data: parsedDelay });
110
+ await waitTimeout(parsedDelay || basic);
111
+ }
112
+ else {
113
+ await waitTimeout(basic);
114
+ }
115
+ }
116
+ }
117
+ if (!req)
118
+ throw new Error("No response");
119
+ let currentReq = req;
120
+ for (const hook of beforeResponse) {
121
+ currentReq = await hook(currentReq);
122
+ }
123
+ if (!currentReq.ok)
124
+ throw new VigorError(`[vigor] ${url} >> Failed`, { url, status: currentReq.status, message: "Failed" });
125
+ let res = await (async () => {
126
+ if (original)
127
+ return currentReq;
128
+ if (parse) {
129
+ const target = currentReq[parse];
130
+ return typeof target === 'function' ? await target.call(currentReq) : target;
131
+ }
132
+ const contentType = currentReq.headers.get("Content-Type") || "";
133
+ if (/json/.test(contentType))
134
+ return await currentReq.json();
135
+ if (/(image|video|audio|pdf)/.test(contentType))
136
+ return await currentReq.blob();
137
+ return await currentReq.text();
138
+ })();
139
+ for (const hook of afterResponse) {
140
+ res = await hook(res);
141
+ }
142
+ return res;
192
143
  }
193
- if (req) {
194
- const status = req.status;
195
- if (unretry.has(status)) throw new VigorError(`[vigor] ${url} >> Unretry ${status}`, { url, status, message: "Unretry", data: status });
196
- const basic = Math.min(Math.pow(backoff, i) * 1e3, wait) + Math.random() * jitter;
197
- if (status === 429) {
198
- const rHeader = retryHeader.map((h) => req?.headers.get(h)).find(Boolean);
199
- const delay = rHeader ? isNaN(Number(rHeader)) ? new Date(rHeader).getTime() - Date.now() : Number(rHeader) * 1e3 : 0;
200
- const parsedDelay = Math.max(0, delay) + Math.random() * jitter;
201
- if (parsedDelay > wait) throw new VigorError(`[vigor] ${url} >> Timeouted ${parsedDelay}ms`, { url, status, message: "Timeouted", data: parsedDelay });
202
- await waitTimeout(parsedDelay || basic);
203
- } else {
204
- await waitTimeout(basic);
205
- }
144
+ catch (error) {
145
+ let currentError = error;
146
+ for (const hook of onError) {
147
+ const result = await hook(currentError);
148
+ if (result !== undefined && !(result instanceof Error))
149
+ return result;
150
+ currentError = result || currentError;
151
+ }
152
+ throw currentError;
206
153
  }
207
- }
208
- if (!req) throw new Error("No response");
209
- let currentReq = req;
210
- for (const hook of beforeResponse) {
211
- currentReq = await hook(currentReq);
212
- }
213
- if (!currentReq.ok) throw new VigorError(`[vigor] ${url} >> Failed`, { url, status: currentReq.status, message: "Failed" });
214
- let res = await (async () => {
215
- if (original) return currentReq;
216
- if (parse) {
217
- const target = currentReq[parse];
218
- return typeof target === "function" ? await target.call(currentReq) : target;
154
+ }
155
+ }
156
+ class VigorAll {
157
+ constructor(config) {
158
+ this._config = config || { limit: 10, jitter: 1000, promises: [] };
159
+ }
160
+ _next(changes) { return new VigorAll({ ...this._config, ...changes }); }
161
+ limit(arg) { return this._next({ limit: arg }); }
162
+ jitter(arg) { return this._next({ jitter: arg }); }
163
+ promises(...args) { return this._next({ promises: [...this._config.promises, ...args] }); }
164
+ async request() {
165
+ const { limit, jitter, promises } = this._config;
166
+ const results = [];
167
+ const executing = new Set();
168
+ for (const task of promises) {
169
+ const p = Promise.resolve()
170
+ .then(() => new Promise(res => setTimeout(res, Math.random() * jitter)))
171
+ .then(() => task());
172
+ results.push(p);
173
+ executing.add(p);
174
+ p.finally(() => executing.delete(p));
175
+ if (executing.size >= limit)
176
+ await Promise.race(executing);
219
177
  }
220
- const contentType = currentReq.headers.get("Content-Type") || "";
221
- if (/json/.test(contentType)) return await currentReq.json();
222
- if (/(image|video|audio|pdf)/.test(contentType)) return await currentReq.blob();
223
- return await currentReq.text();
224
- })();
225
- for (const hook of afterResponse) {
226
- res = await hook(res);
227
- }
228
- return res;
229
- } catch (error) {
230
- let currentError = error;
231
- for (const hook of onError) {
232
- const result = await hook(currentError);
233
- if (result !== void 0 && !(result instanceof Error)) return result;
234
- currentError = result || currentError;
235
- }
236
- throw currentError;
178
+ const ready = await Promise.allSettled(results);
179
+ return ready.map(i => {
180
+ if (i.status === "fulfilled")
181
+ return i.value;
182
+ return i.reason instanceof VigorError ? i.reason : new VigorError(i.reason?.message || "Unknown", { message: i.reason?.message || "Unknown" });
183
+ });
184
+ }
185
+ }
186
+ class Vigor {
187
+ fetch(origin, config) {
188
+ return new VigorFetch(origin, config);
237
189
  }
238
- }
239
- };
240
- var VigorAll = class _VigorAll {
241
- constructor(config) {
242
- this._config = config || { limit: 10, jitter: 1e3, promises: [] };
243
- }
244
- _next(changes) {
245
- return new _VigorAll({ ...this._config, ...changes });
246
- }
247
- limit(arg) {
248
- return this._next({ limit: arg });
249
- }
250
- jitter(arg) {
251
- return this._next({ jitter: arg });
252
- }
253
- promises(...args) {
254
- return this._next({ promises: [...this._config.promises, ...args] });
255
- }
256
- async request() {
257
- const { limit, jitter, promises } = this._config;
258
- const results = [];
259
- const executing = /* @__PURE__ */ new Set();
260
- for (const task of promises) {
261
- const p = Promise.resolve().then(() => new Promise((res) => setTimeout(res, Math.random() * jitter))).then(() => task());
262
- results.push(p);
263
- executing.add(p);
264
- p.finally(() => executing.delete(p));
265
- if (executing.size >= limit) await Promise.race(executing);
190
+ all(config) {
191
+ return new VigorAll(config);
266
192
  }
267
- const ready = await Promise.allSettled(results);
268
- return ready.map((i) => {
269
- if (i.status === "fulfilled") return i.value;
270
- return i.reason instanceof VigorError ? i.reason : new VigorError(i.reason?.message || "Unknown", { message: i.reason?.message || "Unknown" });
271
- });
272
- }
273
- };
274
- var Vigor = class {
275
- fetch(origin, config) {
276
- return new VigorFetch(origin, config);
277
- }
278
- all(config) {
279
- return new VigorAll(config);
280
- }
281
- };
282
- var index_default = Vigor;
193
+ }
194
+ exports.default = Vigor;
package/dist/index.mjs CHANGED
@@ -1,261 +1,192 @@
1
- // src/index.ts
2
- var VigorError = class extends Error {
3
- constructor(text, { url = null, status = 0, message, data = null }) {
4
- super(text);
5
- this.name = "VigorError";
6
- this.url = url;
7
- this.status = status;
8
- this.message = message || text;
9
- this.data = data;
10
- }
11
- };
12
- var VigorFetch = class _VigorFetch {
13
- constructor(origin, config) {
14
- this._origin = origin;
15
- this._config = config || {
16
- path: "",
17
- method: null,
18
- offset: {},
19
- headers: {},
20
- body: null,
21
- count: 5,
22
- max: 5e3,
23
- wait: 1e4,
24
- backoff: 1.3,
25
- unretry: /* @__PURE__ */ new Set([400, 401, 403, 404, 405, 413, 422]),
26
- retryHeader: ["retry-after", "ratelimit-reset", "x-ratelimit-reset", "x-retry-after", "x-amz-retry-after", "chrome-proxy-next-link"],
27
- original: false,
28
- parse: null,
29
- query: {},
30
- jitter: 500,
31
- beforeRequest: [],
32
- afterRequest: [],
33
- beforeResponse: [],
34
- afterResponse: [],
35
- onError: []
36
- };
37
- }
38
- _next(changes) {
39
- return new _VigorFetch(this._origin, { ...this._config, ...changes });
40
- }
41
- path(arg) {
42
- return this._next({ path: arg });
43
- }
44
- method(arg) {
45
- return this._next({ method: arg });
46
- }
47
- offset(arg) {
48
- return this._next({ offset: arg });
49
- }
50
- headers(arg) {
51
- return this._next({ headers: arg });
52
- }
53
- body(arg) {
54
- return this._next({ body: arg });
55
- }
56
- count(arg) {
57
- return this._next({ count: arg });
58
- }
59
- max(arg) {
60
- return this._next({ max: arg });
61
- }
62
- wait(arg) {
63
- return this._next({ wait: arg });
64
- }
65
- backoff(arg) {
66
- return this._next({ backoff: arg });
67
- }
68
- unretry(arg) {
69
- return this._next({ unretry: new Set(arg) });
70
- }
71
- retryHeader(...arg) {
72
- return this._next({ retryHeader: [...this._config.retryHeader, ...arg] });
73
- }
74
- original(arg) {
75
- return this._next({ original: arg });
76
- }
77
- parse(arg) {
78
- return this._next({ parse: arg });
79
- }
80
- query(arg) {
81
- return this._next({ query: { ...this._config.query, ...arg } });
82
- }
83
- jitter(arg) {
84
- return this._next({ jitter: arg });
85
- }
86
- beforeRequest(...arg) {
87
- return this._next({ beforeRequest: [...this._config.beforeRequest, ...arg] });
88
- }
89
- afterRequest(...arg) {
90
- return this._next({ afterRequest: [...this._config.afterRequest, ...arg] });
91
- }
92
- beforeResponse(...arg) {
93
- return this._next({ beforeResponse: [...this._config.beforeResponse, ...arg] });
94
- }
95
- afterResponse(...arg) {
96
- return this._next({ afterResponse: [...this._config.afterResponse, ...arg] });
97
- }
98
- onError(...arg) {
99
- return this._next({ onError: [...this._config.onError, ...arg] });
100
- }
101
- async request() {
102
- const {
103
- path,
104
- method,
105
- offset,
106
- headers,
107
- body,
108
- query,
109
- count,
110
- max,
111
- wait,
112
- backoff,
113
- unretry,
114
- jitter,
115
- original,
116
- parse,
117
- retryHeader,
118
- beforeRequest,
119
- afterRequest,
120
- beforeResponse,
121
- afterResponse,
122
- onError
123
- } = this._config;
124
- try {
125
- if (!/^(https?|data|blob|file|about):\/\//.test(this._origin)) {
126
- throw new VigorError(`[vigor] ${this._origin} >> Invalid Protocol`, {
127
- url: this._origin,
128
- status: 0,
129
- message: "Invalid Protocol"
130
- });
131
- }
132
- const urlObj = new URL(path.replace(/^\//, ""), this._origin + "/");
133
- Object.entries(query).forEach(([key, value]) => {
134
- if (value !== null && value !== void 0) urlObj.searchParams.append(key, String(value));
135
- });
136
- const url = urlObj.href;
137
- const isJson = Array.isArray(body) || !!body && Object.getPrototypeOf(body) === Object.prototype;
138
- const waitTimeout = (time) => new Promise((resolve) => setTimeout(resolve, time));
139
- let option = {
140
- ...offset,
141
- method: method || (body ? "POST" : "GET"),
142
- headers: { ...isJson && { "Content-Type": "application/json" }, ...headers },
143
- ...body && { body: isJson ? JSON.stringify(body) : body }
144
- };
145
- for (const hook of beforeRequest) {
146
- const modified = await hook(option);
147
- if (modified) option = { ...option, ...modified };
148
- }
149
- let req;
150
- for (let i = 0; i < count; i++) {
151
- const controller = new AbortController();
152
- const abort = setTimeout(() => controller.abort(), max);
153
- option.signal = controller.signal;
1
+ Object.defineProperty(exports, "__esModule", { value: true });
2
+ class VigorError extends Error {
3
+ constructor(text, { url = null, status = 0, message, data = null }) {
4
+ super(text);
5
+ this.name = "VigorError";
6
+ this.url = url;
7
+ this.status = status;
8
+ this.message = message || text;
9
+ this.data = data;
10
+ }
11
+ }
12
+ class VigorFetch {
13
+ constructor(origin, config) {
14
+ this._origin = origin;
15
+ this._config = config || {
16
+ path: "", method: null, offset: {}, headers: {}, body: null,
17
+ count: 5, max: 5000, wait: 10000, backoff: 1.3,
18
+ unretry: new Set([400, 401, 403, 404, 405, 413, 422]),
19
+ retryHeader: ["retry-after", "ratelimit-reset", "x-ratelimit-reset", "x-retry-after", "x-amz-retry-after", "chrome-proxy-next-link"],
20
+ original: false, parse: null, query: {}, jitter: 500,
21
+ beforeRequest: [], afterRequest: [], beforeResponse: [], afterResponse: [], onError: []
22
+ };
23
+ }
24
+ _next(changes) {
25
+ return new VigorFetch(this._origin, { ...this._config, ...changes });
26
+ }
27
+ path(arg) { return this._next({ path: arg }); }
28
+ method(arg) { return this._next({ method: arg }); }
29
+ offset(arg) { return this._next({ offset: arg }); }
30
+ headers(arg) { return this._next({ headers: arg }); }
31
+ body(arg) { return this._next({ body: arg }); }
32
+ count(arg) { return this._next({ count: arg }); }
33
+ max(arg) { return this._next({ max: arg }); }
34
+ wait(arg) { return this._next({ wait: arg }); }
35
+ backoff(arg) { return this._next({ backoff: arg }); }
36
+ unretry(arg) { return this._next({ unretry: new Set(arg) }); }
37
+ retryHeader(...arg) { return this._next({ retryHeader: [...this._config.retryHeader, ...arg] }); }
38
+ original(arg) { return this._next({ original: arg }); }
39
+ parse(arg) { return this._next({ parse: arg }); }
40
+ query(arg) { return this._next({ query: { ...this._config.query, ...arg } }); }
41
+ jitter(arg) { return this._next({ jitter: arg }); }
42
+ beforeRequest(...arg) { return this._next({ beforeRequest: [...this._config.beforeRequest, ...arg] }); }
43
+ afterRequest(...arg) { return this._next({ afterRequest: [...this._config.afterRequest, ...arg] }); }
44
+ beforeResponse(...arg) { return this._next({ beforeResponse: [...this._config.beforeResponse, ...arg] }); }
45
+ afterResponse(...arg) { return this._next({ afterResponse: [...this._config.afterResponse, ...arg] }); }
46
+ onError(...arg) { return this._next({ onError: [...this._config.onError, ...arg] }); }
47
+ async request() {
48
+ const { path, method, offset, headers, body, query, count, max, wait, backoff, unretry, jitter, original, parse, retryHeader, beforeRequest, afterRequest, beforeResponse, afterResponse, onError, } = this._config;
154
49
  try {
155
- req = await fetch(url, option);
156
- for (const hook of afterRequest) {
157
- req = await hook(req) || req;
158
- }
159
- if (req.ok) {
160
- clearTimeout(abort);
161
- break;
162
- }
163
- } catch (error) {
164
- clearTimeout(abort);
165
- if (i === count - 1) throw new VigorError(`[vigor] ${url} >> Network Error`, { url, status: 0, message: "Network Error" });
166
- } finally {
167
- clearTimeout(abort);
50
+ if (!/^(https?|data|blob|file|about):\/\//.test(this._origin)) {
51
+ throw new VigorError(`[vigor] ${this._origin} >> Invalid Protocol`, {
52
+ url: this._origin, status: 0, message: "Invalid Protocol"
53
+ });
54
+ }
55
+ const urlObj = new URL(path.replace(/^\//, ""), this._origin + "/");
56
+ Object.entries(query).forEach(([key, value]) => {
57
+ if (value !== null && value !== undefined)
58
+ urlObj.searchParams.append(key, String(value));
59
+ });
60
+ const url = urlObj.href;
61
+ const isJson = Array.isArray(body) || (!!body && Object.getPrototypeOf(body) === Object.prototype);
62
+ const waitTimeout = (time) => new Promise(resolve => setTimeout(resolve, time));
63
+ let option = {
64
+ ...offset,
65
+ method: method || (body ? "POST" : "GET"),
66
+ headers: { ...(isJson && { "Content-Type": "application/json" }), ...headers },
67
+ ...(body && { body: isJson ? JSON.stringify(body) : body }),
68
+ };
69
+ for (const hook of beforeRequest) {
70
+ const modified = await hook(option);
71
+ if (modified)
72
+ option = { ...option, ...modified };
73
+ }
74
+ let req;
75
+ for (let i = 0; i < count; i++) {
76
+ const controller = new AbortController();
77
+ const abort = setTimeout(() => controller.abort(), max);
78
+ option.signal = controller.signal;
79
+ try {
80
+ req = await fetch(url, option);
81
+ for (const hook of afterRequest) {
82
+ req = (await hook(req)) || req;
83
+ }
84
+ if (req.ok) {
85
+ clearTimeout(abort);
86
+ break;
87
+ }
88
+ }
89
+ catch (error) {
90
+ clearTimeout(abort);
91
+ if (i === count - 1)
92
+ throw new VigorError(`[vigor] ${url} >> Network Error`, { url, status: 0, message: "Network Error" });
93
+ }
94
+ finally {
95
+ clearTimeout(abort);
96
+ }
97
+ if (req) {
98
+ const status = req.status;
99
+ if (unretry.has(status))
100
+ throw new VigorError(`[vigor] ${url} >> Unretry ${status}`, { url, status, message: "Unretry", data: status });
101
+ const basic = Math.min(Math.pow(backoff, i) * 1000, wait) + Math.random() * jitter;
102
+ if (status === 429) {
103
+ const rHeader = retryHeader.map(h => req?.headers.get(h)).find(Boolean);
104
+ const delay = rHeader ? (isNaN(Number(rHeader)) ? new Date(rHeader).getTime() - Date.now() : Number(rHeader) * 1000) : 0;
105
+ const parsedDelay = Math.max(0, delay) + Math.random() * jitter;
106
+ if (parsedDelay > wait)
107
+ throw new VigorError(`[vigor] ${url} >> Timeouted ${parsedDelay}ms`, { url, status, message: "Timeouted", data: parsedDelay });
108
+ await waitTimeout(parsedDelay || basic);
109
+ }
110
+ else {
111
+ await waitTimeout(basic);
112
+ }
113
+ }
114
+ }
115
+ if (!req)
116
+ throw new Error("No response");
117
+ let currentReq = req;
118
+ for (const hook of beforeResponse) {
119
+ currentReq = await hook(currentReq);
120
+ }
121
+ if (!currentReq.ok)
122
+ throw new VigorError(`[vigor] ${url} >> Failed`, { url, status: currentReq.status, message: "Failed" });
123
+ let res = await (async () => {
124
+ if (original)
125
+ return currentReq;
126
+ if (parse) {
127
+ const target = currentReq[parse];
128
+ return typeof target === 'function' ? await target.call(currentReq) : target;
129
+ }
130
+ const contentType = currentReq.headers.get("Content-Type") || "";
131
+ if (/json/.test(contentType))
132
+ return await currentReq.json();
133
+ if (/(image|video|audio|pdf)/.test(contentType))
134
+ return await currentReq.blob();
135
+ return await currentReq.text();
136
+ })();
137
+ for (const hook of afterResponse) {
138
+ res = await hook(res);
139
+ }
140
+ return res;
168
141
  }
169
- if (req) {
170
- const status = req.status;
171
- if (unretry.has(status)) throw new VigorError(`[vigor] ${url} >> Unretry ${status}`, { url, status, message: "Unretry", data: status });
172
- const basic = Math.min(Math.pow(backoff, i) * 1e3, wait) + Math.random() * jitter;
173
- if (status === 429) {
174
- const rHeader = retryHeader.map((h) => req?.headers.get(h)).find(Boolean);
175
- const delay = rHeader ? isNaN(Number(rHeader)) ? new Date(rHeader).getTime() - Date.now() : Number(rHeader) * 1e3 : 0;
176
- const parsedDelay = Math.max(0, delay) + Math.random() * jitter;
177
- if (parsedDelay > wait) throw new VigorError(`[vigor] ${url} >> Timeouted ${parsedDelay}ms`, { url, status, message: "Timeouted", data: parsedDelay });
178
- await waitTimeout(parsedDelay || basic);
179
- } else {
180
- await waitTimeout(basic);
181
- }
142
+ catch (error) {
143
+ let currentError = error;
144
+ for (const hook of onError) {
145
+ const result = await hook(currentError);
146
+ if (result !== undefined && !(result instanceof Error))
147
+ return result;
148
+ currentError = result || currentError;
149
+ }
150
+ throw currentError;
182
151
  }
183
- }
184
- if (!req) throw new Error("No response");
185
- let currentReq = req;
186
- for (const hook of beforeResponse) {
187
- currentReq = await hook(currentReq);
188
- }
189
- if (!currentReq.ok) throw new VigorError(`[vigor] ${url} >> Failed`, { url, status: currentReq.status, message: "Failed" });
190
- let res = await (async () => {
191
- if (original) return currentReq;
192
- if (parse) {
193
- const target = currentReq[parse];
194
- return typeof target === "function" ? await target.call(currentReq) : target;
152
+ }
153
+ }
154
+ class VigorAll {
155
+ constructor(config) {
156
+ this._config = config || { limit: 10, jitter: 1000, promises: [] };
157
+ }
158
+ _next(changes) { return new VigorAll({ ...this._config, ...changes }); }
159
+ limit(arg) { return this._next({ limit: arg }); }
160
+ jitter(arg) { return this._next({ jitter: arg }); }
161
+ promises(...args) { return this._next({ promises: [...this._config.promises, ...args] }); }
162
+ async request() {
163
+ const { limit, jitter, promises } = this._config;
164
+ const results = [];
165
+ const executing = new Set();
166
+ for (const task of promises) {
167
+ const p = Promise.resolve()
168
+ .then(() => new Promise(res => setTimeout(res, Math.random() * jitter)))
169
+ .then(() => task());
170
+ results.push(p);
171
+ executing.add(p);
172
+ p.finally(() => executing.delete(p));
173
+ if (executing.size >= limit)
174
+ await Promise.race(executing);
195
175
  }
196
- const contentType = currentReq.headers.get("Content-Type") || "";
197
- if (/json/.test(contentType)) return await currentReq.json();
198
- if (/(image|video|audio|pdf)/.test(contentType)) return await currentReq.blob();
199
- return await currentReq.text();
200
- })();
201
- for (const hook of afterResponse) {
202
- res = await hook(res);
203
- }
204
- return res;
205
- } catch (error) {
206
- let currentError = error;
207
- for (const hook of onError) {
208
- const result = await hook(currentError);
209
- if (result !== void 0 && !(result instanceof Error)) return result;
210
- currentError = result || currentError;
211
- }
212
- throw currentError;
176
+ const ready = await Promise.allSettled(results);
177
+ return ready.map(i => {
178
+ if (i.status === "fulfilled")
179
+ return i.value;
180
+ return i.reason instanceof VigorError ? i.reason : new VigorError(i.reason?.message || "Unknown", { message: i.reason?.message || "Unknown" });
181
+ });
182
+ }
183
+ }
184
+ class Vigor {
185
+ fetch(origin, config) {
186
+ return new VigorFetch(origin, config);
213
187
  }
214
- }
215
- };
216
- var VigorAll = class _VigorAll {
217
- constructor(config) {
218
- this._config = config || { limit: 10, jitter: 1e3, promises: [] };
219
- }
220
- _next(changes) {
221
- return new _VigorAll({ ...this._config, ...changes });
222
- }
223
- limit(arg) {
224
- return this._next({ limit: arg });
225
- }
226
- jitter(arg) {
227
- return this._next({ jitter: arg });
228
- }
229
- promises(...args) {
230
- return this._next({ promises: [...this._config.promises, ...args] });
231
- }
232
- async request() {
233
- const { limit, jitter, promises } = this._config;
234
- const results = [];
235
- const executing = /* @__PURE__ */ new Set();
236
- for (const task of promises) {
237
- const p = Promise.resolve().then(() => new Promise((res) => setTimeout(res, Math.random() * jitter))).then(() => task());
238
- results.push(p);
239
- executing.add(p);
240
- p.finally(() => executing.delete(p));
241
- if (executing.size >= limit) await Promise.race(executing);
188
+ all(config) {
189
+ return new VigorAll(config);
242
190
  }
243
- const ready = await Promise.allSettled(results);
244
- return ready.map((i) => {
245
- if (i.status === "fulfilled") return i.value;
246
- return i.reason instanceof VigorError ? i.reason : new VigorError(i.reason?.message || "Unknown", { message: i.reason?.message || "Unknown" });
247
- });
248
- }
249
- };
250
- var Vigor = class {
251
- fetch(origin, config) {
252
- return new VigorFetch(origin, config);
253
- }
254
- all(config) {
255
- return new VigorAll(config);
256
- }
257
- };
258
- var index_default = Vigor;
259
- export {
260
- index_default as default
261
- };
191
+ }
192
+ exports.default = Vigor;
package/package.json CHANGED
@@ -1,16 +1,23 @@
1
1
  {
2
2
  "name": "vigor-fetch",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Smart, zero-dependency HTTP client with self-healing retries for rate-limited servers.",
5
- "main": "dist/index.js",
6
- "module": "dist/index.mjs",
7
- "types": "dist/index.d.ts",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "require": "./dist/index.js",
11
+ "import": "./dist/index.mjs",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
8
15
  "files": [
9
16
  "dist"
10
17
  ],
11
18
  "scripts": {
12
- "build": "tsup src/index.ts --format cjs,esm --dts --clean",
13
- "dev": "tsup src/index.ts --format cjs,esm --watch --dts"
19
+ "build": "rollup -c",
20
+ "dev": "rollup -c -w"
14
21
  },
15
22
  "keywords": [
16
23
  "fetch",
@@ -24,7 +31,9 @@
24
31
  "author": "Uav1010",
25
32
  "license": "MIT",
26
33
  "devDependencies": {
27
- "tsup": "^8.5.1",
34
+ "@rollup/plugin-typescript": "^11.1.6",
35
+ "rollup": "^4.59.0",
36
+ "tslib": "^2.8.1",
28
37
  "typescript": "^5.9.3"
29
38
  },
30
39
  "engines": {
package/dist/index.d.mts DELETED
@@ -1,75 +0,0 @@
1
- interface VigorErrorOptions {
2
- url?: string | null;
3
- status?: number;
4
- message?: string;
5
- data?: any;
6
- }
7
- interface VigorFetchConfig {
8
- path: string;
9
- method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | null;
10
- offset: RequestInit;
11
- headers: Record<string, string>;
12
- body: any;
13
- count: number;
14
- max: number;
15
- wait: number;
16
- backoff: number;
17
- unretry: Set<number>;
18
- retryHeader: string[];
19
- original: boolean;
20
- parse: keyof Response | null;
21
- beforeRequest: Array<(opt: RequestInit) => Promise<Partial<RequestInit> | void> | Partial<RequestInit> | void>;
22
- afterRequest: Array<(res: Response) => Promise<Response | void> | Response | void>;
23
- beforeResponse: Array<(res: Response) => Promise<Response> | Response>;
24
- afterResponse: Array<(data: any) => Promise<any> | any>;
25
- onError: Array<(err: any) => Promise<any> | any>;
26
- query: Record<string, any>;
27
- jitter: number;
28
- }
29
- declare class VigorFetch<T = any> {
30
- private _origin;
31
- private _config;
32
- constructor(origin: string, config?: VigorFetchConfig);
33
- private _next;
34
- path(arg: string): VigorFetch<T>;
35
- method(arg: VigorFetchConfig['method']): VigorFetch<T>;
36
- offset(arg: RequestInit): VigorFetch<T>;
37
- headers(arg: Record<string, string>): VigorFetch<T>;
38
- body(arg: any): VigorFetch<T>;
39
- count(arg: number): VigorFetch<T>;
40
- max(arg: number): VigorFetch<T>;
41
- wait(arg: number): VigorFetch<T>;
42
- backoff(arg: number): VigorFetch<T>;
43
- unretry(arg: number[]): VigorFetch<T>;
44
- retryHeader(...arg: string[]): VigorFetch<T>;
45
- original(arg: boolean): VigorFetch<T>;
46
- parse(arg: keyof Response): VigorFetch<T>;
47
- query(arg: Record<string, any>): VigorFetch<T>;
48
- jitter(arg: number): VigorFetch<T>;
49
- beforeRequest(...arg: VigorFetchConfig['beforeRequest']): VigorFetch<T>;
50
- afterRequest(...arg: VigorFetchConfig['afterRequest']): VigorFetch<T>;
51
- beforeResponse(...arg: VigorFetchConfig['beforeResponse']): VigorFetch<T>;
52
- afterResponse(...arg: VigorFetchConfig['afterResponse']): VigorFetch<T>;
53
- onError(...arg: VigorFetchConfig['onError']): VigorFetch<T>;
54
- request(): Promise<T>;
55
- }
56
- interface VigorAllConfig {
57
- limit: number;
58
- jitter: number;
59
- promises: Array<() => Promise<any>>;
60
- }
61
- declare class VigorAll {
62
- private _config;
63
- constructor(config?: VigorAllConfig);
64
- private _next;
65
- limit(arg: number): VigorAll;
66
- jitter(arg: number): VigorAll;
67
- promises(...args: Array<() => Promise<any>>): VigorAll;
68
- request(): Promise<any[]>;
69
- }
70
- declare class Vigor {
71
- fetch<T = any>(origin: string, config?: VigorFetchConfig): VigorFetch<T>;
72
- all(config?: VigorAllConfig): VigorAll;
73
- }
74
-
75
- export { type VigorAllConfig, type VigorErrorOptions, type VigorFetchConfig, Vigor as default };