create-request 0.0.1-beta.2

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.
@@ -0,0 +1,635 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.createRequest = {}));
5
+ })(this, (function (exports) { 'use strict';
6
+
7
+ /**
8
+ * Enum for HTTP methods
9
+ */
10
+ exports.HttpMethod = void 0;
11
+ (function (HttpMethod) {
12
+ HttpMethod["GET"] = "GET";
13
+ HttpMethod["POST"] = "POST";
14
+ HttpMethod["PUT"] = "PUT";
15
+ HttpMethod["DELETE"] = "DELETE";
16
+ HttpMethod["PATCH"] = "PATCH";
17
+ HttpMethod["HEAD"] = "HEAD";
18
+ HttpMethod["OPTIONS"] = "OPTIONS";
19
+ })(exports.HttpMethod || (exports.HttpMethod = {}));
20
+ /**
21
+ * Enum for request priorities
22
+ */
23
+ exports.RequestPriority = void 0;
24
+ (function (RequestPriority) {
25
+ RequestPriority["HIGH"] = "high";
26
+ RequestPriority["LOW"] = "low";
27
+ RequestPriority["AUTO"] = "auto";
28
+ })(exports.RequestPriority || (exports.RequestPriority = {}));
29
+ /**
30
+ * Enum for credentials policies
31
+ */
32
+ exports.CredentialsPolicy = void 0;
33
+ (function (CredentialsPolicy) {
34
+ CredentialsPolicy["INCLUDE"] = "include";
35
+ CredentialsPolicy["SAME_ORIGIN"] = "same-origin";
36
+ CredentialsPolicy["OMIT"] = "omit";
37
+ })(exports.CredentialsPolicy || (exports.CredentialsPolicy = {}));
38
+ /**
39
+ * Enum for request modes
40
+ */
41
+ exports.RequestMode = void 0;
42
+ (function (RequestMode) {
43
+ RequestMode["CORS"] = "cors";
44
+ RequestMode["NO_CORS"] = "no-cors";
45
+ RequestMode["SAME_ORIGIN"] = "same-origin";
46
+ RequestMode["NAVIGATE"] = "navigate";
47
+ })(exports.RequestMode || (exports.RequestMode = {}));
48
+ /**
49
+ * Enum for redirect modes
50
+ */
51
+ exports.RedirectMode = void 0;
52
+ (function (RedirectMode) {
53
+ RedirectMode["FOLLOW"] = "follow";
54
+ RedirectMode["ERROR"] = "error";
55
+ RedirectMode["MANUAL"] = "manual";
56
+ })(exports.RedirectMode || (exports.RedirectMode = {}));
57
+ /**
58
+ * Enum for cache modes
59
+ */
60
+ exports.CacheMode = void 0;
61
+ (function (CacheMode) {
62
+ CacheMode["DEFAULT"] = "default";
63
+ CacheMode["NO_STORE"] = "no-store";
64
+ CacheMode["RELOAD"] = "reload";
65
+ CacheMode["NO_CACHE"] = "no-cache";
66
+ CacheMode["FORCE_CACHE"] = "force-cache";
67
+ CacheMode["ONLY_IF_CACHED"] = "only-if-cached";
68
+ })(exports.CacheMode || (exports.CacheMode = {}));
69
+
70
+ class RequestError extends Error {
71
+ constructor(message, url, method, options = {}) {
72
+ super(message);
73
+ this.name = "RequestError";
74
+ this.url = url;
75
+ this.method = method;
76
+ this.status = options.status;
77
+ this.response = options.response;
78
+ this.timeoutError = options.timeoutError;
79
+ // For better stack traces in modern environments
80
+ if (Error.captureStackTrace) {
81
+ Error.captureStackTrace(this, RequestError);
82
+ }
83
+ // Maintains proper prototype chain for instanceof checks
84
+ Object.setPrototypeOf(this, RequestError.prototype);
85
+ }
86
+ /**
87
+ * Static methods for creating specific types of RequestError
88
+ */
89
+ static timeout(url, method, timeoutMs) {
90
+ return new RequestError(`Request timed out after ${timeoutMs}ms`, url, method, {
91
+ timeoutError: true,
92
+ });
93
+ }
94
+ static fromResponse(response, url, method) {
95
+ return new RequestError(`Request failed with status ${response.status}`, url, method, {
96
+ status: response.status,
97
+ response,
98
+ });
99
+ }
100
+ static networkError(url, method, originalError) {
101
+ const error = new RequestError(`Network error: ${originalError.message}`, url, method);
102
+ error.stack = originalError.stack;
103
+ return error;
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Wrapper for HTTP responses with methods to transform the response data
109
+ */
110
+ class ResponseWrapper {
111
+ constructor(response) {
112
+ this.response = response;
113
+ this.ok = response.status >= 200 && response.status < 300; // Standard Fetch API behavior
114
+ }
115
+ /**
116
+ * Get the raw Response object
117
+ */
118
+ get raw() {
119
+ return this.response;
120
+ }
121
+ /**
122
+ * Get the HTTP status code
123
+ */
124
+ get status() {
125
+ return this.response.status;
126
+ }
127
+ /**
128
+ * Get the HTTP status text
129
+ */
130
+ get statusText() {
131
+ return this.response.statusText;
132
+ }
133
+ /**
134
+ * Get response headers
135
+ */
136
+ get headers() {
137
+ return this.response.headers;
138
+ }
139
+ /**
140
+ * Parse response as JSON
141
+ */
142
+ async json() {
143
+ return this.response.json();
144
+ }
145
+ /**
146
+ * Get response as text
147
+ */
148
+ async text() {
149
+ return this.response.text();
150
+ }
151
+ /**
152
+ * Get response as Blob
153
+ */
154
+ async blob() {
155
+ return this.response.blob();
156
+ }
157
+ /**
158
+ * Get response as ArrayBuffer
159
+ */
160
+ async arrayBuffer() {
161
+ return this.response.arrayBuffer();
162
+ }
163
+ /**
164
+ * Get response as ReadableStream
165
+ */
166
+ body() {
167
+ return this.response.body;
168
+ }
169
+ }
170
+
171
+ // Base class with common functionality for all request types
172
+ class BaseRequest {
173
+ constructor() {
174
+ this.requestOptions = {};
175
+ this.queryParams = new URLSearchParams();
176
+ }
177
+ withHeaders(headers) {
178
+ this.requestOptions.headers = {
179
+ ...(this.requestOptions.headers || {}),
180
+ ...headers,
181
+ };
182
+ return this;
183
+ }
184
+ withTimeout(timeout) {
185
+ this.requestOptions.timeout = timeout;
186
+ return this;
187
+ }
188
+ withRetries(retries) {
189
+ this.requestOptions.retries = retries;
190
+ return this;
191
+ }
192
+ onRetry(callback) {
193
+ this.requestOptions.onRetry = callback;
194
+ return this;
195
+ }
196
+ /**
197
+ * Sets the credentials policy for the request
198
+ * @param credentialsPolicy - Can be 'omit', 'same-origin', or 'include'
199
+ * @returns The instance for chaining
200
+ */
201
+ withCredentials(credentialsPolicy = exports.CredentialsPolicy.SAME_ORIGIN) {
202
+ this.requestOptions.credentials = credentialsPolicy;
203
+ return this;
204
+ }
205
+ /**
206
+ * Allows providing an external AbortController to cancel the request
207
+ * @param controller - The AbortController to use for this request
208
+ * @returns The instance for chaining
209
+ */
210
+ withAbortController(controller) {
211
+ this.abortController = controller;
212
+ return this;
213
+ }
214
+ /**
215
+ * Sets the referrer for the request
216
+ * @param referrer - The referrer URL or policy
217
+ * @returns The instance for chaining
218
+ */
219
+ withReferrer(referrer) {
220
+ this.requestOptions.referrer = referrer;
221
+ return this;
222
+ }
223
+ /**
224
+ * Sets the redirect policy for the request
225
+ * @param redirect - Can be 'follow', 'error', or 'manual'
226
+ * @returns The instance for chaining
227
+ */
228
+ withRedirect(redirect) {
229
+ this.requestOptions.redirect = redirect;
230
+ return this;
231
+ }
232
+ /**
233
+ * Sets the keepalive flag for the request
234
+ * @param keepalive - Whether to allow the request to outlive the page
235
+ * @returns The instance for chaining
236
+ */
237
+ withKeepAlive(keepalive) {
238
+ this.requestOptions.keepalive = keepalive;
239
+ return this;
240
+ }
241
+ /**
242
+ * Sets the priority of the request
243
+ * @param priority - Can be 'high', 'low', or 'auto'
244
+ * @returns The instance for chaining
245
+ */
246
+ withPriority(priority) {
247
+ this.requestOptions.priority = priority;
248
+ return this;
249
+ }
250
+ /**
251
+ * Adds query parameters to the request URL
252
+ * @param params - An object containing the query parameters
253
+ * @returns The instance for chaining
254
+ */
255
+ withQueryParams(params) {
256
+ Object.entries(params).forEach(([key, value]) => {
257
+ if (value === null || value === undefined) {
258
+ return;
259
+ }
260
+ if (Array.isArray(value)) {
261
+ // Handle array values - add multiple entries with the same key
262
+ value.forEach(v => this.queryParams.append(key, String(v)));
263
+ }
264
+ else {
265
+ this.queryParams.append(key, String(value));
266
+ }
267
+ });
268
+ return this;
269
+ }
270
+ /**
271
+ * Adds a single query parameter
272
+ * @param key - The parameter name
273
+ * @param value - The parameter value
274
+ * @returns The instance for chaining
275
+ */
276
+ withQueryParam(key, value) {
277
+ if (value !== null && value !== undefined) {
278
+ this.queryParams.append(key, String(value));
279
+ }
280
+ return this;
281
+ }
282
+ /**
283
+ * Sets the mode of the request
284
+ * @param mode - The mode for the request (cors, no-cors, same-origin, navigate)
285
+ * @returns The instance for chaining
286
+ */
287
+ withMode(mode) {
288
+ this.requestOptions.mode = mode;
289
+ return this;
290
+ }
291
+ /**
292
+ * Shorthand for setting the Content-Type header
293
+ * @param contentType - The content type
294
+ * @returns The instance for chaining
295
+ */
296
+ withContentType(contentType) {
297
+ return this.withHeaders({
298
+ "Content-Type": contentType,
299
+ });
300
+ }
301
+ /**
302
+ * Shorthand for setting the Authorization header
303
+ * @param authValue - The authorization value
304
+ * @returns The instance for chaining
305
+ */
306
+ withAuthorization(authValue) {
307
+ return this.withHeaders({
308
+ Authorization: authValue,
309
+ });
310
+ }
311
+ /**
312
+ * Shorthand for setting up Basic authentication
313
+ * @param username - The username
314
+ * @param password - The password
315
+ * @returns The instance for chaining
316
+ */
317
+ withBasicAuth(username, password) {
318
+ const credentials = btoa(`${username}:${password}`);
319
+ return this.withAuthorization(`Basic ${credentials}`);
320
+ }
321
+ /**
322
+ * Sets the bearer token for authentication
323
+ * @param token - The bearer token
324
+ * @returns The instance for chaining
325
+ */
326
+ withBearerToken(token) {
327
+ return this.withAuthorization(`Bearer ${token}`);
328
+ }
329
+ /**
330
+ * Sets cookies for the request
331
+ * @param cookies - An object containing cookie name-value pairs
332
+ * @returns The instance for chaining
333
+ */
334
+ withCookies(cookies) {
335
+ const cookieEntries = Object.entries(cookies);
336
+ if (cookieEntries.length === 0) {
337
+ return this;
338
+ }
339
+ // Format cookies as name=value pairs
340
+ const cookieString = cookieEntries
341
+ .map(([name, value]) => `${encodeURIComponent(name)}=${encodeURIComponent(value)}`)
342
+ .join("; ");
343
+ // Get current headers or initialize empty object
344
+ const currentHeaders = this.requestOptions.headers || {};
345
+ // If there's already a Cookie header, append to it; otherwise create a new one
346
+ const existingCookies = currentHeaders["Cookie"] || "";
347
+ const newCookieValue = existingCookies ? `${existingCookies}; ${cookieString}` : cookieString;
348
+ // Set the Cookie header
349
+ return this.withHeaders({
350
+ Cookie: newCookieValue,
351
+ });
352
+ }
353
+ /**
354
+ * Send the request to the specified URL
355
+ * @param url The URL to send the request to
356
+ */
357
+ sendTo(url) {
358
+ // Format the URL with query parameters
359
+ url = this.formatUrlWithQueryParams(url);
360
+ // Cast the request options to RequestInit to ensure compatibility
361
+ const fetchOptions = {
362
+ ...this.requestOptions,
363
+ method: this.method,
364
+ };
365
+ // Create the base promise
366
+ const basePromise = !this.requestOptions.retries
367
+ ? this.executeRequest(url, fetchOptions)
368
+ : this.executeWithRetries(url, fetchOptions);
369
+ // Enhance the promise with response methods
370
+ const responsePromise = basePromise.then(response => response);
371
+ // Attach convenience methods to the promise
372
+ responsePromise.json = async () => {
373
+ const response = await basePromise;
374
+ return response.json();
375
+ };
376
+ responsePromise.text = async () => {
377
+ const response = await basePromise;
378
+ return response.text();
379
+ };
380
+ responsePromise.blob = async () => {
381
+ const response = await basePromise;
382
+ return response.blob();
383
+ };
384
+ responsePromise.arrayBuffer = async () => {
385
+ const response = await basePromise;
386
+ return response.arrayBuffer();
387
+ };
388
+ responsePromise.body = async () => {
389
+ const response = await basePromise;
390
+ return response.body();
391
+ };
392
+ return responsePromise;
393
+ }
394
+ /**
395
+ * Formats the URL with any query parameters
396
+ * @param url The base URL
397
+ * @returns The URL with query parameters appended
398
+ */
399
+ formatUrlWithQueryParams(url) {
400
+ if (!this.queryParams.toString()) {
401
+ return url;
402
+ }
403
+ const urlObj = new URL(url);
404
+ // Merge our query params with any that might be in the URL already
405
+ this.queryParams.forEach((value, key) => {
406
+ urlObj.searchParams.append(key, value);
407
+ });
408
+ return urlObj.toString();
409
+ }
410
+ /**
411
+ * Executes a request with configured retry logic
412
+ * @param url The formatted URL to send the request to
413
+ * @param fetchOptions The fetch options to use
414
+ * @returns A wrapped response object
415
+ */
416
+ async executeWithRetries(url, fetchOptions) {
417
+ let retryCount = 0;
418
+ const maxRetries = this.requestOptions.retries || 0;
419
+ // eslint-disable-next-line no-constant-condition
420
+ while (true) {
421
+ try {
422
+ return await this.executeRequest(url, fetchOptions);
423
+ }
424
+ catch (error) {
425
+ const requestError = error instanceof RequestError
426
+ ? error
427
+ : RequestError.networkError(url, fetchOptions.method, error);
428
+ if (retryCount >= maxRetries || requestError.timeoutError) {
429
+ throw requestError;
430
+ }
431
+ retryCount++;
432
+ if (this.requestOptions.onRetry) {
433
+ await this.requestOptions.onRetry({ retryCount, error: requestError });
434
+ }
435
+ }
436
+ }
437
+ }
438
+ async executeRequest(url, fetchOptions) {
439
+ // Create a request controller for timeout if needed, or use the provided one
440
+ const controller = this.abortController || new AbortController();
441
+ const { signal } = controller;
442
+ // Use the controller signal for the fetch request, but don't overwrite an existing signal
443
+ // that might have been set in requestOptions if it exists
444
+ fetchOptions.signal = fetchOptions.signal || signal;
445
+ let timeoutId;
446
+ // If we have a timeout and we're using our own controller (not provided externally)
447
+ if (this.requestOptions.timeout && !this.abortController) {
448
+ timeoutId = setTimeout(() => {
449
+ controller.abort();
450
+ }, this.requestOptions.timeout);
451
+ }
452
+ try {
453
+ let response;
454
+ try {
455
+ response = await fetch(url, fetchOptions);
456
+ }
457
+ catch (error) {
458
+ // Check if this is an abort error from our timeout
459
+ if (error instanceof DOMException && error.name === "AbortError" && timeoutId) {
460
+ throw RequestError.timeout(url, fetchOptions.method, this.requestOptions.timeout);
461
+ }
462
+ // Otherwise it's a network error
463
+ throw RequestError.networkError(url, fetchOptions.method, error);
464
+ }
465
+ if (!response.ok) {
466
+ throw RequestError.fromResponse(response, url, fetchOptions.method);
467
+ }
468
+ // Return a wrapped response instead of parsing it
469
+ return new ResponseWrapper(response);
470
+ }
471
+ finally {
472
+ if (timeoutId) {
473
+ clearTimeout(timeoutId);
474
+ }
475
+ }
476
+ }
477
+ }
478
+
479
+ // An extension of BaseRequest for methods that support request bodies
480
+ class BodyRequest extends BaseRequest {
481
+ /**
482
+ * Sets the request body with appropriate content type handling
483
+ */
484
+ withBody(body) {
485
+ if (body === undefined || body === null) {
486
+ this.requestOptions.body = null;
487
+ return this;
488
+ }
489
+ // Handle special body types that don't need transformation
490
+ if (body instanceof Blob ||
491
+ body instanceof FormData ||
492
+ body instanceof URLSearchParams ||
493
+ body instanceof ArrayBuffer ||
494
+ body instanceof ReadableStream) {
495
+ this.requestOptions.body = body;
496
+ // For FormData, make sure to NOT explicitly set Content-Type
497
+ // The browser will set it automatically with the correct boundary
498
+ // If we set it manually, it would be missing the boundary parameter
499
+ return this;
500
+ }
501
+ // Handle strings
502
+ if (typeof body === "string") {
503
+ this.requestOptions.body = body;
504
+ return this;
505
+ }
506
+ // For objects and other types, stringify and set JSON content-type
507
+ try {
508
+ this.requestOptions.body = JSON.stringify(body);
509
+ this.requestOptions.headers = {
510
+ "Content-Type": "application/json",
511
+ ...(this.requestOptions.headers || {}),
512
+ };
513
+ }
514
+ catch (error) {
515
+ const errorMessage = error instanceof Error ? error.message : String(error);
516
+ throw new Error(`Failed to stringify request body: ${errorMessage}`);
517
+ }
518
+ return this;
519
+ }
520
+ }
521
+
522
+ // Methods without body
523
+ class GetRequest extends BaseRequest {
524
+ constructor() {
525
+ super(...arguments);
526
+ this.method = exports.HttpMethod.GET;
527
+ }
528
+ }
529
+ class HeadRequest extends BaseRequest {
530
+ constructor() {
531
+ super(...arguments);
532
+ this.method = exports.HttpMethod.HEAD;
533
+ }
534
+ }
535
+ class OptionsRequest extends BaseRequest {
536
+ constructor() {
537
+ super(...arguments);
538
+ this.method = exports.HttpMethod.OPTIONS;
539
+ }
540
+ }
541
+ class DeleteRequest extends BaseRequest {
542
+ constructor() {
543
+ super(...arguments);
544
+ this.method = exports.HttpMethod.DELETE;
545
+ }
546
+ }
547
+ // Methods with body
548
+ class PostRequest extends BodyRequest {
549
+ constructor() {
550
+ super(...arguments);
551
+ this.method = exports.HttpMethod.POST;
552
+ }
553
+ }
554
+ class PutRequest extends BodyRequest {
555
+ constructor() {
556
+ super(...arguments);
557
+ this.method = exports.HttpMethod.PUT;
558
+ }
559
+ }
560
+ class PatchRequest extends BodyRequest {
561
+ constructor() {
562
+ super(...arguments);
563
+ this.method = exports.HttpMethod.PATCH;
564
+ }
565
+ }
566
+
567
+ /**
568
+ * Create a GET request
569
+ */
570
+ function get() {
571
+ return new GetRequest();
572
+ }
573
+ /**
574
+ * Create a POST request
575
+ */
576
+ function post() {
577
+ return new PostRequest();
578
+ }
579
+ /**
580
+ * Create a PUT request
581
+ */
582
+ function put() {
583
+ return new PutRequest();
584
+ }
585
+ /**
586
+ * Create a DELETE request
587
+ * Note: We use 'del' to avoid JS keyword conflict
588
+ */
589
+ function del() {
590
+ return new DeleteRequest();
591
+ }
592
+ /**
593
+ * Create a PATCH request
594
+ */
595
+ function patch() {
596
+ return new PatchRequest();
597
+ }
598
+ /**
599
+ * Create a HEAD request
600
+ */
601
+ function head() {
602
+ return new HeadRequest();
603
+ }
604
+ /**
605
+ * Create an OPTIONS request
606
+ */
607
+ function options() {
608
+ return new OptionsRequest();
609
+ }
610
+
611
+ // Create the main API object
612
+ const create = {
613
+ get,
614
+ post,
615
+ put,
616
+ del,
617
+ patch,
618
+ head,
619
+ options,
620
+ };
621
+
622
+ exports.DeleteRequest = DeleteRequest;
623
+ exports.GetRequest = GetRequest;
624
+ exports.HeadRequest = HeadRequest;
625
+ exports.OptionsRequest = OptionsRequest;
626
+ exports.PatchRequest = PatchRequest;
627
+ exports.PostRequest = PostRequest;
628
+ exports.PutRequest = PutRequest;
629
+ exports.RequestError = RequestError;
630
+ exports.ResponseWrapper = ResponseWrapper;
631
+ exports["default"] = create;
632
+
633
+ Object.defineProperty(exports, '__esModule', { value: true });
634
+
635
+ }));
@@ -0,0 +1,30 @@
1
+ import { GetRequest, PostRequest, PutRequest, DeleteRequest, PatchRequest, HeadRequest, OptionsRequest } from "./requestMethods";
2
+ /**
3
+ * Create a GET request
4
+ */
5
+ export declare function get(): GetRequest;
6
+ /**
7
+ * Create a POST request
8
+ */
9
+ export declare function post(): PostRequest;
10
+ /**
11
+ * Create a PUT request
12
+ */
13
+ export declare function put(): PutRequest;
14
+ /**
15
+ * Create a DELETE request
16
+ * Note: We use 'del' to avoid JS keyword conflict
17
+ */
18
+ export declare function del(): DeleteRequest;
19
+ /**
20
+ * Create a PATCH request
21
+ */
22
+ export declare function patch(): PatchRequest;
23
+ /**
24
+ * Create a HEAD request
25
+ */
26
+ export declare function head(): HeadRequest;
27
+ /**
28
+ * Create an OPTIONS request
29
+ */
30
+ export declare function options(): OptionsRequest;
@@ -0,0 +1,24 @@
1
+ import { BaseRequest } from "./BaseRequest";
2
+ import { BodyRequest } from "./BodyRequest";
3
+ import { HttpMethod } from "./enums";
4
+ export declare class GetRequest extends BaseRequest {
5
+ protected method: HttpMethod;
6
+ }
7
+ export declare class HeadRequest extends BaseRequest {
8
+ protected method: HttpMethod;
9
+ }
10
+ export declare class OptionsRequest extends BaseRequest {
11
+ protected method: HttpMethod;
12
+ }
13
+ export declare class DeleteRequest extends BaseRequest {
14
+ protected method: HttpMethod;
15
+ }
16
+ export declare class PostRequest extends BodyRequest {
17
+ protected method: HttpMethod;
18
+ }
19
+ export declare class PutRequest extends BodyRequest {
20
+ protected method: HttpMethod;
21
+ }
22
+ export declare class PatchRequest extends BodyRequest {
23
+ protected method: HttpMethod;
24
+ }