create-request 0.0.1-beta.2 → 0.0.1-beta.4

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.
@@ -10,11 +10,11 @@
10
10
  exports.HttpMethod = void 0;
11
11
  (function (HttpMethod) {
12
12
  HttpMethod["GET"] = "GET";
13
- HttpMethod["POST"] = "POST";
14
13
  HttpMethod["PUT"] = "PUT";
15
- HttpMethod["DELETE"] = "DELETE";
16
- HttpMethod["PATCH"] = "PATCH";
14
+ HttpMethod["POST"] = "POST";
17
15
  HttpMethod["HEAD"] = "HEAD";
16
+ HttpMethod["PATCH"] = "PATCH";
17
+ HttpMethod["DELETE"] = "DELETE";
18
18
  HttpMethod["OPTIONS"] = "OPTIONS";
19
19
  })(exports.HttpMethod || (exports.HttpMethod = {}));
20
20
  /**
@@ -22,8 +22,8 @@
22
22
  */
23
23
  exports.RequestPriority = void 0;
24
24
  (function (RequestPriority) {
25
- RequestPriority["HIGH"] = "high";
26
25
  RequestPriority["LOW"] = "low";
26
+ RequestPriority["HIGH"] = "high";
27
27
  RequestPriority["AUTO"] = "auto";
28
28
  })(exports.RequestPriority || (exports.RequestPriority = {}));
29
29
  /**
@@ -31,9 +31,9 @@
31
31
  */
32
32
  exports.CredentialsPolicy = void 0;
33
33
  (function (CredentialsPolicy) {
34
+ CredentialsPolicy["OMIT"] = "omit";
34
35
  CredentialsPolicy["INCLUDE"] = "include";
35
36
  CredentialsPolicy["SAME_ORIGIN"] = "same-origin";
36
- CredentialsPolicy["OMIT"] = "omit";
37
37
  })(exports.CredentialsPolicy || (exports.CredentialsPolicy = {}));
38
38
  /**
39
39
  * Enum for request modes
@@ -50,8 +50,8 @@
50
50
  */
51
51
  exports.RedirectMode = void 0;
52
52
  (function (RedirectMode) {
53
- RedirectMode["FOLLOW"] = "follow";
54
53
  RedirectMode["ERROR"] = "error";
54
+ RedirectMode["FOLLOW"] = "follow";
55
55
  RedirectMode["MANUAL"] = "manual";
56
56
  })(exports.RedirectMode || (exports.RedirectMode = {}));
57
57
  /**
@@ -60,12 +60,30 @@
60
60
  exports.CacheMode = void 0;
61
61
  (function (CacheMode) {
62
62
  CacheMode["DEFAULT"] = "default";
63
- CacheMode["NO_STORE"] = "no-store";
64
63
  CacheMode["RELOAD"] = "reload";
64
+ CacheMode["NO_STORE"] = "no-store";
65
65
  CacheMode["NO_CACHE"] = "no-cache";
66
66
  CacheMode["FORCE_CACHE"] = "force-cache";
67
67
  CacheMode["ONLY_IF_CACHED"] = "only-if-cached";
68
68
  })(exports.CacheMode || (exports.CacheMode = {}));
69
+ /**
70
+ * Enum for cookie SameSite policies
71
+ */
72
+ exports.SameSitePolicy = void 0;
73
+ (function (SameSitePolicy) {
74
+ SameSitePolicy["LAX"] = "Lax";
75
+ SameSitePolicy["NONE"] = "None";
76
+ SameSitePolicy["STRICT"] = "Strict";
77
+ })(exports.SameSitePolicy || (exports.SameSitePolicy = {}));
78
+ /**
79
+ * Enum for body types
80
+ */
81
+ var BodyType;
82
+ (function (BodyType) {
83
+ BodyType["JSON"] = "json";
84
+ BodyType["STRING"] = "string";
85
+ BodyType["BINARY"] = "binary";
86
+ })(BodyType || (BodyType = {}));
69
87
 
70
88
  class RequestError extends Error {
71
89
  constructor(message, url, method, options = {}) {
@@ -139,44 +157,241 @@
139
157
  /**
140
158
  * Parse response as JSON
141
159
  */
142
- async json() {
160
+ async getJson() {
143
161
  return this.response.json();
144
162
  }
145
163
  /**
146
164
  * Get response as text
147
165
  */
148
- async text() {
166
+ async getText() {
149
167
  return this.response.text();
150
168
  }
151
169
  /**
152
170
  * Get response as Blob
153
171
  */
154
- async blob() {
172
+ async getBlob() {
155
173
  return this.response.blob();
156
174
  }
157
175
  /**
158
176
  * Get response as ArrayBuffer
159
177
  */
160
- async arrayBuffer() {
178
+ async getArrayBuffer() {
161
179
  return this.response.arrayBuffer();
162
180
  }
163
181
  /**
164
- * Get response as ReadableStream
182
+ * Get response as ReadableStream for true streaming consumption.
183
+ * This allows you to process data incrementally as it arrives.
184
+ *
185
+ * @example
186
+ * const stream = await request.sendTo('https://example.com/large-file').getBody();
187
+ * const reader = stream.getReader();
188
+ *
189
+ * while (true) {
190
+ * const { done, value } = await reader.read();
191
+ * if (done) break;
192
+ * // Process chunk of data in 'value'
193
+ * }
165
194
  */
166
- body() {
195
+ getBody() {
167
196
  return this.response.body;
168
197
  }
169
198
  }
170
199
 
200
+ /**
201
+ * Global configuration for create-request
202
+ */
203
+ class Config {
204
+ constructor() {
205
+ // CSRF configuration
206
+ this.csrfHeaderName = "X-CSRF-Token";
207
+ this.xsrfCookieName = "XSRF-TOKEN";
208
+ this.xsrfHeaderName = "X-XSRF-TOKEN";
209
+ this.csrfToken = null;
210
+ this.enableAutoXsrf = true;
211
+ this.enableAntiCsrf = true; // X-Requested-With header
212
+ }
213
+ /**
214
+ * Get the singleton instance
215
+ */
216
+ static getInstance() {
217
+ if (!Config.instance) {
218
+ Config.instance = new Config();
219
+ }
220
+ return Config.instance;
221
+ }
222
+ /**
223
+ * Set a global CSRF token to be used for all requests
224
+ */
225
+ setCsrfToken(token) {
226
+ this.csrfToken = token;
227
+ return this;
228
+ }
229
+ /**
230
+ * Get the global CSRF token
231
+ */
232
+ getCsrfToken() {
233
+ return this.csrfToken;
234
+ }
235
+ /**
236
+ * Set the CSRF header name (default is X-CSRF-Token)
237
+ */
238
+ setCsrfHeaderName(name) {
239
+ this.csrfHeaderName = name;
240
+ return this;
241
+ }
242
+ /**
243
+ * Get the CSRF header name
244
+ */
245
+ getCsrfHeaderName() {
246
+ return this.csrfHeaderName;
247
+ }
248
+ /**
249
+ * Set the XSRF cookie name to look for (default is XSRF-TOKEN)
250
+ */
251
+ setXsrfCookieName(name) {
252
+ this.xsrfCookieName = name;
253
+ return this;
254
+ }
255
+ /**
256
+ * Get the XSRF cookie name
257
+ */
258
+ getXsrfCookieName() {
259
+ return this.xsrfCookieName;
260
+ }
261
+ /**
262
+ * Set the XSRF header name to send the token in (default is X-XSRF-TOKEN)
263
+ */
264
+ setXsrfHeaderName(name) {
265
+ this.xsrfHeaderName = name;
266
+ return this;
267
+ }
268
+ /**
269
+ * Get the XSRF header name
270
+ */
271
+ getXsrfHeaderName() {
272
+ return this.xsrfHeaderName;
273
+ }
274
+ /**
275
+ * Enable or disable automatic XSRF token extraction from cookies
276
+ */
277
+ setEnableAutoXsrf(enable) {
278
+ this.enableAutoXsrf = enable;
279
+ return this;
280
+ }
281
+ /**
282
+ * Check if automatic XSRF is enabled
283
+ */
284
+ isAutoXsrfEnabled() {
285
+ return this.enableAutoXsrf;
286
+ }
287
+ /**
288
+ * Enable or disable automatic addition of anti-CSRF headers
289
+ */
290
+ setEnableAntiCsrf(enable) {
291
+ this.enableAntiCsrf = enable;
292
+ return this;
293
+ }
294
+ /**
295
+ * Check if anti-CSRF is enabled
296
+ */
297
+ isAntiCsrfEnabled() {
298
+ return this.enableAntiCsrf;
299
+ }
300
+ /**
301
+ * Reset configuration to defaults
302
+ */
303
+ reset() {
304
+ this.csrfToken = null;
305
+ this.csrfHeaderName = "X-CSRF-Token";
306
+ this.xsrfCookieName = "XSRF-TOKEN";
307
+ this.xsrfHeaderName = "X-XSRF-TOKEN";
308
+ this.enableAutoXsrf = true;
309
+ this.enableAntiCsrf = true;
310
+ return this;
311
+ }
312
+ }
313
+
314
+ class CookieUtils {
315
+ /**
316
+ * Formats cookies for a request
317
+ * @param cookies Object containing cookie name-value pairs or cookie options
318
+ * @returns Formatted cookie string for the Cookie header
319
+ */
320
+ static formatRequestCookies(cookies) {
321
+ const cookiePairs = [];
322
+ Object.entries(cookies).forEach(([name, valueOrOptions]) => {
323
+ let value;
324
+ if (typeof valueOrOptions === "string") {
325
+ value = valueOrOptions;
326
+ }
327
+ else {
328
+ // Extract value from options object without validation
329
+ value = valueOrOptions.value;
330
+ }
331
+ // Add the cookie to the request
332
+ cookiePairs.push(`${encodeURIComponent(name)}=${encodeURIComponent(value)}`);
333
+ });
334
+ return cookiePairs.join("; ");
335
+ }
336
+ }
337
+
338
+ /**
339
+ * Utility class for CSRF token management
340
+ */
341
+ class CsrfUtils {
342
+ /**
343
+ * Extracts CSRF token from a meta tag in the document head
344
+ * @param metaName The name attribute of the meta tag (default: "csrf-token")
345
+ * @returns The CSRF token or null if not found
346
+ */
347
+ static getTokenFromMeta(metaName = "csrf-token") {
348
+ if (typeof document === "undefined") {
349
+ return null;
350
+ }
351
+ const meta = document.querySelector(`meta[name="${metaName}"]`);
352
+ return (meta === null || meta === void 0 ? void 0 : meta.getAttribute("content")) || null;
353
+ }
354
+ /**
355
+ * Extracts CSRF token from a cookie
356
+ * @param cookieName The name of the cookie containing the CSRF token
357
+ * @returns The CSRF token or null if not found
358
+ */
359
+ static getTokenFromCookie(cookieName = "csrf-token") {
360
+ if (typeof document === "undefined") {
361
+ return null;
362
+ }
363
+ const cookies = document.cookie.split(";");
364
+ for (const cookie of cookies) {
365
+ const [name, value] = cookie.trim().split("=");
366
+ if (name === cookieName) {
367
+ return decodeURIComponent(value);
368
+ }
369
+ }
370
+ return null;
371
+ }
372
+ /**
373
+ * Validates if the provided string is a potential CSRF token
374
+ * Checks if the token meets minimum security requirements (non-empty, not too short)
375
+ * @param token The token to validate
376
+ * @returns Whether the token is potentially valid
377
+ */
378
+ static isValidToken(token) {
379
+ return typeof token === "string" && token.length >= 8;
380
+ }
381
+ }
382
+
171
383
  // Base class with common functionality for all request types
172
384
  class BaseRequest {
173
385
  constructor() {
174
- this.requestOptions = {};
386
+ this.requestOptions = {
387
+ headers: {},
388
+ };
175
389
  this.queryParams = new URLSearchParams();
390
+ this.autoApplyCsrfProtection = true;
176
391
  }
177
392
  withHeaders(headers) {
178
393
  this.requestOptions.headers = {
179
- ...(this.requestOptions.headers || {}),
394
+ ...this.requestOptions.headers,
180
395
  ...headers,
181
396
  };
182
397
  return this;
@@ -328,7 +543,7 @@
328
543
  }
329
544
  /**
330
545
  * Sets cookies for the request
331
- * @param cookies - An object containing cookie name-value pairs
546
+ * @param cookies Object containing cookie name-value pairs or cookie options
332
547
  * @returns The instance for chaining
333
548
  */
334
549
  withCookies(cookies) {
@@ -336,18 +551,58 @@
336
551
  if (cookieEntries.length === 0) {
337
552
  return this;
338
553
  }
339
- // Format cookies as name=value pairs
340
- const cookieString = cookieEntries
341
- .map(([name, value]) => `${encodeURIComponent(name)}=${encodeURIComponent(value)}`)
342
- .join("; ");
343
554
  // Get current headers or initialize empty object
344
555
  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"] || "";
556
+ // Get the existing cookie header in a case-insensitive way
557
+ let existingCookies = "";
558
+ const cookieHeaderName = Object.keys(currentHeaders).find(header => header.toLowerCase() === "cookie");
559
+ if (cookieHeaderName)
560
+ existingCookies = currentHeaders[cookieHeaderName];
561
+ const cookieString = CookieUtils.formatRequestCookies(cookies);
562
+ // Combine with existing cookies if present
347
563
  const newCookieValue = existingCookies ? `${existingCookies}; ${cookieString}` : cookieString;
348
- // Set the Cookie header
564
+ // Set the Cookie header, preserving original case if it exists
565
+ const headerName = cookieHeaderName || "Cookie";
349
566
  return this.withHeaders({
350
- Cookie: newCookieValue,
567
+ [headerName]: newCookieValue,
568
+ });
569
+ }
570
+ /**
571
+ * Set a single cookie
572
+ * @param name Cookie name
573
+ * @param value Cookie value or options object
574
+ * @returns The instance for chaining
575
+ */
576
+ withCookie(name, value) {
577
+ return this.withCookies({ [name]: value });
578
+ }
579
+ /**
580
+ * Sets a CSRF token in the request headers
581
+ * @param token The CSRF token
582
+ * @param headerName The name of the header to use (default: X-CSRF-Token)
583
+ * @returns The instance for chaining
584
+ */
585
+ withCsrfToken(token, headerName = "X-CSRF-Token") {
586
+ return this.withHeaders({
587
+ [headerName]: token,
588
+ });
589
+ }
590
+ /**
591
+ * Disables automatic anti-CSRF protection.
592
+ * By default, X-Requested-With: XMLHttpRequest header is sent with all requests.
593
+ * @returns The instance for chaining
594
+ */
595
+ withoutCsrfProtection() {
596
+ this.autoApplyCsrfProtection = false;
597
+ return this;
598
+ }
599
+ /**
600
+ * Sets common security headers to help prevent CSRF attacks
601
+ * @returns The instance for chaining
602
+ */
603
+ withAntiCsrfHeaders() {
604
+ return this.withHeaders({
605
+ "X-Requested-With": "XMLHttpRequest",
351
606
  });
352
607
  }
353
608
  /**
@@ -357,6 +612,41 @@
357
612
  sendTo(url) {
358
613
  // Format the URL with query parameters
359
614
  url = this.formatUrlWithQueryParams(url);
615
+ // Apply automatic CSRF protection if enabled
616
+ if (this.autoApplyCsrfProtection) {
617
+ const config = Config.getInstance();
618
+ // Apply anti-CSRF headers if enabled
619
+ if (config.isAntiCsrfEnabled()) {
620
+ this.withHeaders({
621
+ "X-Requested-With": "XMLHttpRequest",
622
+ });
623
+ }
624
+ // Apply global CSRF token if set
625
+ const globalToken = config.getCsrfToken();
626
+ if (globalToken) {
627
+ // Check if local token exists
628
+ const headers = this.requestOptions.headers;
629
+ const hasLocalToken = Object.keys(headers).some(key => key === "X-CSRF-Token" || key === config.getCsrfHeaderName());
630
+ if (!hasLocalToken) {
631
+ this.withHeaders({
632
+ [config.getCsrfHeaderName()]: globalToken,
633
+ });
634
+ }
635
+ }
636
+ // check for XSRF token in cookies and send it as a header
637
+ if (config.isAutoXsrfEnabled() && typeof document !== "undefined") {
638
+ const xsrfToken = CsrfUtils.getTokenFromCookie(config.getXsrfCookieName());
639
+ if (xsrfToken && CsrfUtils.isValidToken(xsrfToken)) {
640
+ const headers = this.requestOptions.headers;
641
+ const hasLocalToken = Object.keys(headers).some(key => key === "X-XSRF-TOKEN" || key === config.getXsrfHeaderName());
642
+ if (!hasLocalToken) {
643
+ this.withHeaders({
644
+ [config.getXsrfHeaderName()]: xsrfToken,
645
+ });
646
+ }
647
+ }
648
+ }
649
+ }
360
650
  // Cast the request options to RequestInit to ensure compatibility
361
651
  const fetchOptions = {
362
652
  ...this.requestOptions,
@@ -366,28 +656,22 @@
366
656
  const basePromise = !this.requestOptions.retries
367
657
  ? this.executeRequest(url, fetchOptions)
368
658
  : 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();
659
+ const responsePromise = basePromise;
660
+ // Attach convenience methods that begin processing immediately
661
+ responsePromise.getJson = async () => {
662
+ return basePromise.then(response => response.getJson());
375
663
  };
376
- responsePromise.text = async () => {
377
- const response = await basePromise;
378
- return response.text();
664
+ responsePromise.getText = async () => {
665
+ return basePromise.then(response => response.getText());
379
666
  };
380
- responsePromise.blob = async () => {
381
- const response = await basePromise;
382
- return response.blob();
667
+ responsePromise.getBlob = async () => {
668
+ return basePromise.then(response => response.getBlob());
383
669
  };
384
- responsePromise.arrayBuffer = async () => {
385
- const response = await basePromise;
386
- return response.arrayBuffer();
670
+ responsePromise.getArrayBuffer = async () => {
671
+ return basePromise.then(response => response.getArrayBuffer());
387
672
  };
388
- responsePromise.body = async () => {
389
- const response = await basePromise;
390
- return response.body();
673
+ responsePromise.getBody = async () => {
674
+ return basePromise.then(response => response.getBody());
391
675
  };
392
676
  return responsePromise;
393
677
  }
@@ -414,7 +698,7 @@
414
698
  * @returns A wrapped response object
415
699
  */
416
700
  async executeWithRetries(url, fetchOptions) {
417
- let retryCount = 0;
701
+ let attempt = 0;
418
702
  const maxRetries = this.requestOptions.retries || 0;
419
703
  // eslint-disable-next-line no-constant-condition
420
704
  while (true) {
@@ -425,12 +709,12 @@
425
709
  const requestError = error instanceof RequestError
426
710
  ? error
427
711
  : RequestError.networkError(url, fetchOptions.method, error);
428
- if (retryCount >= maxRetries || requestError.timeoutError) {
712
+ if (attempt >= maxRetries || requestError.timeoutError) {
429
713
  throw requestError;
430
714
  }
431
- retryCount++;
715
+ attempt++;
432
716
  if (this.requestOptions.onRetry) {
433
- await this.requestOptions.onRetry({ retryCount, error: requestError });
717
+ await this.requestOptions.onRetry({ attempt, error: requestError });
434
718
  }
435
719
  }
436
720
  }
@@ -476,47 +760,72 @@
476
760
  }
477
761
  }
478
762
 
479
- // An extension of BaseRequest for methods that support request bodies
763
+ /**
764
+ * Base class for requests that can have a body (POST, PUT, PATCH)
765
+ */
480
766
  class BodyRequest extends BaseRequest {
767
+ constructor() {
768
+ super(...arguments);
769
+ this.bodyProcessed = false;
770
+ }
481
771
  /**
482
- * Sets the request body with appropriate content type handling
772
+ * Sets the body of the request
773
+ * @param body - The request body
483
774
  */
484
775
  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
776
+ this.body = body;
777
+ this.bodyProcessed = false;
778
+ // Set body type and validate
502
779
  if (typeof body === "string") {
503
- this.requestOptions.body = body;
504
- return this;
780
+ this.bodyType = BodyType.STRING;
781
+ this.setContentTypeIfNeeded("text/plain");
505
782
  }
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
- };
783
+ else if (body !== null &&
784
+ typeof body === "object" &&
785
+ !(body instanceof FormData ||
786
+ body instanceof Blob ||
787
+ body instanceof ArrayBuffer ||
788
+ body instanceof URLSearchParams ||
789
+ body instanceof ReadableStream)) {
790
+ this.bodyType = BodyType.JSON;
791
+ this.setContentTypeIfNeeded("application/json");
792
+ // Validate JSON is stringifiable early
793
+ try {
794
+ JSON.stringify(body);
795
+ }
796
+ catch (error) {
797
+ throw new Error(`Failed to stringify request body: ${String(error)}`);
798
+ }
513
799
  }
514
- catch (error) {
515
- const errorMessage = error instanceof Error ? error.message : String(error);
516
- throw new Error(`Failed to stringify request body: ${errorMessage}`);
800
+ else {
801
+ this.bodyType = BodyType.BINARY;
517
802
  }
518
803
  return this;
519
804
  }
805
+ setContentTypeIfNeeded(contentType) {
806
+ // Only set if not already set
807
+ const headers = this.requestOptions.headers;
808
+ if (!Object.keys(headers).some(header => header.toLowerCase() === "content-type")) {
809
+ this.withContentType(contentType);
810
+ }
811
+ }
812
+ /**
813
+ * Send the request to the specified URL
814
+ * Overrides the base implementation to add body handling
815
+ */
816
+ sendTo(url) {
817
+ // Process body only once
818
+ if (!this.bodyProcessed && this.body !== undefined && !this.requestOptions.body) {
819
+ if (this.bodyType === BodyType.JSON) {
820
+ this.requestOptions.body = JSON.stringify(this.body);
821
+ }
822
+ else {
823
+ this.requestOptions.body = this.body;
824
+ }
825
+ this.bodyProcessed = true;
826
+ }
827
+ return super.sendTo(url);
828
+ }
520
829
  }
521
830
 
522
831
  // Methods without body
@@ -608,7 +917,7 @@
608
917
  return new OptionsRequest();
609
918
  }
610
919
 
611
- // Create the main API object
920
+ // Create the main API object with configuration
612
921
  const create = {
613
922
  get,
614
923
  post,
@@ -617,8 +926,11 @@
617
926
  patch,
618
927
  head,
619
928
  options,
929
+ // Add configuration access
930
+ config: Config.getInstance(),
620
931
  };
621
932
 
933
+ exports.CookieUtils = CookieUtils;
622
934
  exports.DeleteRequest = DeleteRequest;
623
935
  exports.GetRequest = GetRequest;
624
936
  exports.HeadRequest = HeadRequest;
@@ -1,11 +1,22 @@
1
- import { HttpMethod, RequestPriority, CredentialsPolicy, RequestMode, RedirectMode, CacheMode } from "./enums";
1
+ import { HttpMethod, RequestPriority, CredentialsPolicy, RequestMode, RedirectMode, CacheMode, SameSitePolicy } from "./enums";
2
2
  import type { RequestError } from "./RequestError";
3
3
  export type Body = null | Blob | string | object | FormData | ArrayBuffer | URLSearchParams | ReadableStream;
4
4
  export type RetryCallback = (options: {
5
- retryCount: number;
5
+ attempt: number;
6
6
  error: RequestError;
7
7
  }) => void | Promise<void>;
8
- export { HttpMethod, RequestPriority, CredentialsPolicy, RequestMode, RedirectMode, CacheMode };
8
+ export interface CookieOptions {
9
+ value: string;
10
+ secure?: boolean;
11
+ httpOnly?: boolean;
12
+ sameSite?: SameSitePolicy;
13
+ expires?: Date;
14
+ path?: string;
15
+ domain?: string;
16
+ maxAge?: number;
17
+ }
18
+ export type CookiesRecord = Record<string, string | CookieOptions>;
19
+ export { CacheMode, HttpMethod, RequestMode, RedirectMode, SameSitePolicy, RequestPriority, CredentialsPolicy, };
9
20
  export interface RequestOptions extends Omit<RequestInit, "signal" | "body" | "method" | "credentials" | "mode" | "redirect" | "cache" | "priority"> {
10
21
  timeout?: number;
11
22
  retries?: number;