@fgrzl/fetch 1.0.0-ci.11 → 1.1.0-alpha.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.
package/dist/client.d.ts CHANGED
@@ -1,18 +1,111 @@
1
+ /**
2
+ * Middleware function that processes requests before they are sent.
3
+ * Can modify request options and URL.
4
+ * @param req - The request configuration object
5
+ * @param url - The request URL
6
+ * @returns A promise that resolves to a tuple of [modified request, modified URL]
7
+ */
1
8
  export type RequestMiddleware = (req: RequestInit, url: string) => Promise<[RequestInit, string]>;
9
+ /**
10
+ * Middleware function that processes responses after they are received.
11
+ * Can modify or replace the response.
12
+ * @param res - The response object
13
+ * @returns A promise that resolves to the modified response
14
+ */
2
15
  export type ResponseMiddleware = (res: Response) => Promise<Response>;
16
+ /**
17
+ * Configuration options for FetchClient.
18
+ */
3
19
  export interface FetchClientConfig {
20
+ /** Controls whether credentials are sent with requests. Defaults to 'same-origin'. */
4
21
  credentials?: RequestCredentials;
5
22
  }
23
+ /**
24
+ * A configurable HTTP client with middleware support.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const client = new FetchClient({
29
+ * credentials: 'same-origin'
30
+ * });
31
+ *
32
+ * // Add middleware
33
+ * client.useRequestMiddleware(async (req, url) => {
34
+ * return [{ ...req, headers: { ...req.headers, 'Auth': 'token' } }, url];
35
+ * });
36
+ *
37
+ * // Make requests
38
+ * const data = await client.get('/api/users');
39
+ * ```
40
+ */
6
41
  export declare class FetchClient {
7
42
  private requestMiddlewares;
8
43
  private responseMiddlewares;
9
44
  private credentials;
45
+ /**
46
+ * Creates a new FetchClient instance.
47
+ * @param config - Configuration options for the client
48
+ */
10
49
  constructor(config?: FetchClientConfig);
50
+ /**
51
+ * Adds a request middleware to the client.
52
+ * Request middlewares are executed in the order they are added.
53
+ * @param middleware - The middleware function to add
54
+ */
11
55
  useRequestMiddleware(middleware: RequestMiddleware): void;
56
+ /**
57
+ * Adds a response middleware to the client.
58
+ * Response middlewares are executed in the order they are added.
59
+ * @param middleware - The middleware function to add
60
+ */
12
61
  useResponseMiddleware(middleware: ResponseMiddleware): void;
62
+ /**
63
+ * Makes an HTTP request with middleware processing.
64
+ *
65
+ * @template T - The expected response type
66
+ * @param url - The URL to request
67
+ * @param init - Request configuration options
68
+ * @returns Promise that resolves to the parsed JSON response
69
+ * @throws The error object from the response if the request fails
70
+ */
13
71
  request<T = any>(url: string, init?: RequestInit): Promise<T>;
72
+ /**
73
+ * Makes a GET request.
74
+ * @template T - The expected response type
75
+ * @param url - The URL to request
76
+ * @returns Promise that resolves to the parsed JSON response
77
+ */
14
78
  get<T>(url: string): Promise<T>;
15
- post<T>(url: string, body: any): Promise<T>;
16
- put<T>(url: string, body: any): Promise<T>;
79
+ /**
80
+ * Helper method for requests with JSON body.
81
+ * @template T - The expected response type
82
+ * @param url - The URL to request
83
+ * @param method - The HTTP method
84
+ * @param body - The request body data (will be JSON stringified)
85
+ * @returns Promise that resolves to the parsed JSON response
86
+ */
87
+ private requestWithJsonBody;
88
+ /**
89
+ * Makes a POST request with JSON body.
90
+ * @template T - The expected response type
91
+ * @param url - The URL to request
92
+ * @param body - The request body data (will be JSON stringified)
93
+ * @returns Promise that resolves to the parsed JSON response
94
+ */
95
+ post<T>(url: string, body?: any): Promise<T>;
96
+ /**
97
+ * Makes a PUT request with JSON body.
98
+ * @template T - The expected response type
99
+ * @param url - The URL to request
100
+ * @param body - The request body data (will be JSON stringified)
101
+ * @returns Promise that resolves to the parsed JSON response
102
+ */
103
+ put<T>(url: string, body?: any): Promise<T>;
104
+ /**
105
+ * Makes a DELETE request.
106
+ * @template T - The expected response type
107
+ * @param url - The URL to request
108
+ * @returns Promise that resolves to the parsed JSON response
109
+ */
17
110
  del<T>(url: string): Promise<T>;
18
111
  }
package/dist/client.js CHANGED
@@ -1,50 +1,137 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FetchClient = void 0;
4
+ const errors_1 = require("./errors");
5
+ /**
6
+ * A configurable HTTP client with middleware support.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const client = new FetchClient({
11
+ * credentials: 'same-origin'
12
+ * });
13
+ *
14
+ * // Add middleware
15
+ * client.useRequestMiddleware(async (req, url) => {
16
+ * return [{ ...req, headers: { ...req.headers, 'Auth': 'token' } }, url];
17
+ * });
18
+ *
19
+ * // Make requests
20
+ * const data = await client.get('/api/users');
21
+ * ```
22
+ */
4
23
  class FetchClient {
24
+ /**
25
+ * Creates a new FetchClient instance.
26
+ * @param config - Configuration options for the client
27
+ */
5
28
  constructor(config = {}) {
6
29
  this.requestMiddlewares = [];
7
30
  this.responseMiddlewares = [];
8
31
  this.credentials = config.credentials ?? 'same-origin';
9
32
  }
33
+ /**
34
+ * Adds a request middleware to the client.
35
+ * Request middlewares are executed in the order they are added.
36
+ * @param middleware - The middleware function to add
37
+ */
10
38
  useRequestMiddleware(middleware) {
11
39
  this.requestMiddlewares.push(middleware);
12
40
  }
41
+ /**
42
+ * Adds a response middleware to the client.
43
+ * Response middlewares are executed in the order they are added.
44
+ * @param middleware - The middleware function to add
45
+ */
13
46
  useResponseMiddleware(middleware) {
14
47
  this.responseMiddlewares.push(middleware);
15
48
  }
49
+ /**
50
+ * Makes an HTTP request with middleware processing.
51
+ *
52
+ * @template T - The expected response type
53
+ * @param url - The URL to request
54
+ * @param init - Request configuration options
55
+ * @returns Promise that resolves to the parsed JSON response
56
+ * @throws The error object from the response if the request fails
57
+ */
16
58
  async request(url, init = {}) {
17
- for (const mw of this.requestMiddlewares) {
18
- [init, url] = await mw(init, url);
59
+ try {
60
+ for (const mw of this.requestMiddlewares) {
61
+ [init, url] = await mw(init, url);
62
+ }
63
+ let res = await fetch(url, {
64
+ credentials: this.credentials,
65
+ ...init,
66
+ });
67
+ for (const mw of this.responseMiddlewares) {
68
+ res = await mw(res);
69
+ }
70
+ if (!res.ok) {
71
+ const body = await res.json().catch(() => ({}));
72
+ throw new errors_1.HttpError(res.status, res.statusText, body, url);
73
+ }
74
+ return res.json();
19
75
  }
20
- let res = await fetch(url, {
21
- credentials: this.credentials,
22
- ...init,
23
- });
24
- for (const mw of this.responseMiddlewares) {
25
- res = await mw(res);
26
- }
27
- if (!res.ok) {
28
- const error = await res.json().catch(() => ({}));
76
+ catch (error) {
77
+ if (error instanceof errors_1.HttpError) {
78
+ throw error;
79
+ }
80
+ if (error instanceof TypeError && error.message.includes('fetch')) {
81
+ throw new errors_1.NetworkError('Failed to fetch', url, error);
82
+ }
29
83
  throw error;
30
84
  }
31
- return res.json();
32
85
  }
86
+ /**
87
+ * Makes a GET request.
88
+ * @template T - The expected response type
89
+ * @param url - The URL to request
90
+ * @returns Promise that resolves to the parsed JSON response
91
+ */
33
92
  get(url) {
34
93
  return this.request(url, { method: 'GET' });
35
94
  }
36
- post(url, body) {
95
+ /**
96
+ * Helper method for requests with JSON body.
97
+ * @template T - The expected response type
98
+ * @param url - The URL to request
99
+ * @param method - The HTTP method
100
+ * @param body - The request body data (will be JSON stringified)
101
+ * @returns Promise that resolves to the parsed JSON response
102
+ */
103
+ requestWithJsonBody(url, method, body) {
37
104
  return this.request(url, {
38
- method: 'POST',
105
+ method,
39
106
  body: JSON.stringify(body),
40
107
  });
41
108
  }
109
+ /**
110
+ * Makes a POST request with JSON body.
111
+ * @template T - The expected response type
112
+ * @param url - The URL to request
113
+ * @param body - The request body data (will be JSON stringified)
114
+ * @returns Promise that resolves to the parsed JSON response
115
+ */
116
+ post(url, body) {
117
+ return this.requestWithJsonBody(url, 'POST', body ?? {});
118
+ }
119
+ /**
120
+ * Makes a PUT request with JSON body.
121
+ * @template T - The expected response type
122
+ * @param url - The URL to request
123
+ * @param body - The request body data (will be JSON stringified)
124
+ * @returns Promise that resolves to the parsed JSON response
125
+ */
42
126
  put(url, body) {
43
- return this.request(url, {
44
- method: 'PUT',
45
- body: JSON.stringify(body),
46
- });
127
+ return this.requestWithJsonBody(url, 'PUT', body ?? {});
47
128
  }
129
+ /**
130
+ * Makes a DELETE request.
131
+ * @template T - The expected response type
132
+ * @param url - The URL to request
133
+ * @returns Promise that resolves to the parsed JSON response
134
+ */
48
135
  del(url) {
49
136
  return this.request(url, { method: 'DELETE' });
50
137
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;;AAUA,MAAa,WAAW;IAKtB,YAAY,SAA4B,EAAE;QAJlC,uBAAkB,GAAwB,EAAE,CAAC;QAC7C,wBAAmB,GAAyB,EAAE,CAAC;QAIrD,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,aAAa,CAAC;IACzD,CAAC;IAEM,oBAAoB,CAAC,UAA6B;QACvD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC3C,CAAC;IAEM,qBAAqB,CAAC,UAA8B;QACzD,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC5C,CAAC;IAEM,KAAK,CAAC,OAAO,CAClB,GAAW,EACX,OAAoB,EAAE;QAEtB,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACzC,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACpC,CAAC;QAED,IAAI,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YACzB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,GAAG,IAAI;SACR,CAAC,CAAC;QAEH,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC1C,GAAG,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACjD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;IAEM,GAAG,CAAI,GAAW;QACvB,OAAO,IAAI,CAAC,OAAO,CAAI,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACjD,CAAC;IAEM,IAAI,CAAI,GAAW,EAAE,IAAS;QACnC,OAAO,IAAI,CAAC,OAAO,CAAI,GAAG,EAAE;YAC1B,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IAEM,GAAG,CAAI,GAAW,EAAE,IAAS;QAClC,OAAO,IAAI,CAAC,OAAO,CAAI,GAAG,EAAE;YAC1B,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IAEM,GAAG,CAAI,GAAW;QACvB,OAAO,IAAI,CAAC,OAAO,CAAI,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACpD,CAAC;CACF;AA/DD,kCA+DC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/csrf.d.ts CHANGED
@@ -1,7 +1,32 @@
1
1
  import { FetchClient } from './client';
2
+ /**
3
+ * Configuration options for CSRF protection middleware.
4
+ */
2
5
  interface CsrfConfig {
6
+ /** Name of the cookie that contains the CSRF token */
3
7
  cookieName: string;
8
+ /** Name of the HTTP header to send the CSRF token in */
4
9
  headerName: string;
5
10
  }
11
+ /**
12
+ * Configures CSRF protection for a FetchClient.
13
+ *
14
+ * This function adds middleware that:
15
+ * - Reads CSRF tokens from cookies and includes them in request headers
16
+ * - Updates CSRF tokens from response headers back to cookies
17
+ * - Automatically sets Content-Type to application/json for requests
18
+ *
19
+ * @param client - The FetchClient instance to configure
20
+ * @param config - CSRF configuration options
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const client = new FetchClient();
25
+ * useCSRF(client, {
26
+ * cookieName: 'csrf_token',
27
+ * headerName: 'X-CSRF-Token'
28
+ * });
29
+ * ```
30
+ */
6
31
  export declare function useCSRF(client: FetchClient, config: CsrfConfig): void;
7
32
  export {};
package/dist/csrf.js CHANGED
@@ -1,6 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useCSRF = useCSRF;
4
+ /**
5
+ * Creates a request middleware that adds CSRF token to requests.
6
+ * Reads the token from a cookie and adds it as a header.
7
+ *
8
+ * @param config - CSRF configuration options
9
+ * @returns Request middleware function
10
+ */
4
11
  function csrfMiddleware(config) {
5
12
  return async (req, url) => {
6
13
  const cookie = document.cookie.match(new RegExp(`${config.cookieName}=([^;]+)`));
@@ -13,6 +20,26 @@ function csrfMiddleware(config) {
13
20
  return [{ ...req, headers }, url];
14
21
  };
15
22
  }
23
+ /**
24
+ * Configures CSRF protection for a FetchClient.
25
+ *
26
+ * This function adds middleware that:
27
+ * - Reads CSRF tokens from cookies and includes them in request headers
28
+ * - Updates CSRF tokens from response headers back to cookies
29
+ * - Automatically sets Content-Type to application/json for requests
30
+ *
31
+ * @param client - The FetchClient instance to configure
32
+ * @param config - CSRF configuration options
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * const client = new FetchClient();
37
+ * useCSRF(client, {
38
+ * cookieName: 'csrf_token',
39
+ * headerName: 'X-CSRF-Token'
40
+ * });
41
+ * ```
42
+ */
16
43
  function useCSRF(client, config) {
17
44
  client.useRequestMiddleware(csrfMiddleware(config));
18
45
  client.useResponseMiddleware(async (res) => {
package/dist/csrf.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"csrf.js","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":";;AAsBA,0BASC;AAxBD,SAAS,cAAc,CAAC,MAAkB;IACxC,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACxB,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAClC,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,UAAU,UAAU,CAAC,CAC3C,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1B,MAAM,OAAO,GAAG;YACd,GAAG,GAAG,CAAC,OAAO;YACd,cAAc,EAAE,kBAAkB;YAClC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,CAAC;SAC7C,CAAC;QACF,OAAO,CAAC,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;IACpC,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,OAAO,CAAC,MAAmB,EAAE,MAAkB;IAC7D,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,MAAM,CAAC,qBAAqB,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACzC,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACrD,IAAI,SAAS,EAAE,CAAC;YACd,QAAQ,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,IAAI,SAAS,WAAW,CAAC;QACjE,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"csrf.js","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":";;AAsDA,0BASC;AAnDD;;;;;;GAMG;AACH,SAAS,cAAc,CAAC,MAAkB;IACxC,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACxB,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAClC,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,UAAU,UAAU,CAAC,CAC3C,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1B,MAAM,OAAO,GAAG;YACd,GAAG,GAAG,CAAC,OAAO;YACd,cAAc,EAAE,kBAAkB;YAClC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,CAAC;SAC7C,CAAC;QACF,OAAO,CAAC,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;IACpC,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,SAAgB,OAAO,CAAC,MAAmB,EAAE,MAAkB;IAC7D,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,MAAM,CAAC,qBAAqB,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACzC,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACrD,IAAI,SAAS,EAAE,CAAC;YACd,QAAQ,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,IAAI,SAAS,WAAW,CAAC;QACjE,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @fileoverview Custom error classes for the fetch client.
3
+ */
4
+ /**
5
+ * Base error class for all fetch client errors.
6
+ */
7
+ export declare class FetchError extends Error {
8
+ /** Optional underlying cause */
9
+ readonly cause?: Error;
10
+ /**
11
+ * Creates a new FetchError.
12
+ * @param message - Error message
13
+ * @param cause - Optional underlying cause
14
+ */
15
+ constructor(message: string, cause?: Error);
16
+ }
17
+ /**
18
+ * Error thrown when an HTTP request fails with a non-2xx status code.
19
+ */
20
+ export declare class HttpError extends FetchError {
21
+ /** The HTTP status code */
22
+ readonly status: number;
23
+ /** The HTTP status text */
24
+ readonly statusText: string;
25
+ /** The response body (if available) */
26
+ readonly body: any;
27
+ /**
28
+ * Creates a new HttpError.
29
+ * @param status - HTTP status code
30
+ * @param statusText - HTTP status text
31
+ * @param body - Response body
32
+ * @param url - The request URL
33
+ */
34
+ constructor(status: number, statusText: string, body: any, url: string);
35
+ }
36
+ /**
37
+ * Error thrown when a network request fails completely.
38
+ */
39
+ export declare class NetworkError extends FetchError {
40
+ /**
41
+ * Creates a new NetworkError.
42
+ * @param message - Error message
43
+ * @param url - The request URL
44
+ * @param cause - The underlying network error
45
+ */
46
+ constructor(message: string, url: string, cause?: Error);
47
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Custom error classes for the fetch client.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.NetworkError = exports.HttpError = exports.FetchError = void 0;
7
+ /**
8
+ * Base error class for all fetch client errors.
9
+ */
10
+ class FetchError extends Error {
11
+ /**
12
+ * Creates a new FetchError.
13
+ * @param message - Error message
14
+ * @param cause - Optional underlying cause
15
+ */
16
+ constructor(message, cause) {
17
+ super(message);
18
+ this.name = 'FetchError';
19
+ this.cause = cause;
20
+ }
21
+ }
22
+ exports.FetchError = FetchError;
23
+ /**
24
+ * Error thrown when an HTTP request fails with a non-2xx status code.
25
+ */
26
+ class HttpError extends FetchError {
27
+ /**
28
+ * Creates a new HttpError.
29
+ * @param status - HTTP status code
30
+ * @param statusText - HTTP status text
31
+ * @param body - Response body
32
+ * @param url - The request URL
33
+ */
34
+ constructor(status, statusText, body, url) {
35
+ super(`HTTP ${status} ${statusText} at ${url}`);
36
+ this.name = 'HttpError';
37
+ this.status = status;
38
+ this.statusText = statusText;
39
+ this.body = body;
40
+ }
41
+ }
42
+ exports.HttpError = HttpError;
43
+ /**
44
+ * Error thrown when a network request fails completely.
45
+ */
46
+ class NetworkError extends FetchError {
47
+ /**
48
+ * Creates a new NetworkError.
49
+ * @param message - Error message
50
+ * @param url - The request URL
51
+ * @param cause - The underlying network error
52
+ */
53
+ constructor(message, url, cause) {
54
+ super(`Network error for ${url}: ${message}`, cause);
55
+ this.name = 'NetworkError';
56
+ }
57
+ }
58
+ exports.NetworkError = NetworkError;
59
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH;;GAEG;AACH,MAAa,UAAW,SAAQ,KAAK;IAInC;;;;OAIG;IACH,YAAY,OAAe,EAAE,KAAa;QACxC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF;AAdD,gCAcC;AAED;;GAEG;AACH,MAAa,SAAU,SAAQ,UAAU;IAQvC;;;;;;OAMG;IACH,YAAY,MAAc,EAAE,UAAkB,EAAE,IAAS,EAAE,GAAW;QACpE,KAAK,CAAC,QAAQ,MAAM,IAAI,UAAU,OAAO,GAAG,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAtBD,8BAsBC;AAED;;GAEG;AACH,MAAa,YAAa,SAAQ,UAAU;IAC1C;;;;;OAKG;IACH,YAAY,OAAe,EAAE,GAAW,EAAE,KAAa;QACrD,KAAK,CAAC,qBAAqB,GAAG,KAAK,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAXD,oCAWC"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,36 @@
1
+ /**
2
+ * @fileoverview Default configured fetch client with CSRF protection and unauthorized handling.
3
+ *
4
+ * This module exports a pre-configured FetchClient instance with:
5
+ * - Same-origin credentials policy
6
+ * - CSRF protection using 'csrf_token' cookie and 'X-CSRF-Token' header
7
+ * - Automatic redirect to '/login' on 401 Unauthorized responses
8
+ */
1
9
  import { FetchClient } from './client';
10
+ /**
11
+ * Pre-configured fetch client with CSRF protection and unauthorized handling.
12
+ *
13
+ * This client is ready to use for applications that need:
14
+ * - CSRF protection
15
+ * - Automatic login redirects on authentication failures
16
+ * - Same-origin cookie handling
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * import api from '@fgrzl/fetch';
21
+ *
22
+ * // GET request
23
+ * const users = await api.get('/api/users');
24
+ *
25
+ * // POST request (automatically includes CSRF token)
26
+ * const newUser = await api.post('/api/users', { name: 'John' });
27
+ * ```
28
+ */
2
29
  declare const api: FetchClient;
3
30
  export default api;
31
+ export { FetchError, HttpError, NetworkError } from './errors';
32
+ export { FetchClient } from './client';
33
+ export type { RequestMiddleware, ResponseMiddleware, FetchClientConfig, } from './client';
34
+ export { useCSRF } from './csrf';
35
+ export { useUnauthorized } from './unauthorized';
36
+ export type { UnauthorizedConfig } from './unauthorized';
package/dist/index.js CHANGED
@@ -1,17 +1,58 @@
1
1
  "use strict";
2
+ /**
3
+ * @fileoverview Default configured fetch client with CSRF protection and unauthorized handling.
4
+ *
5
+ * This module exports a pre-configured FetchClient instance with:
6
+ * - Same-origin credentials policy
7
+ * - CSRF protection using 'csrf_token' cookie and 'X-CSRF-Token' header
8
+ * - Automatic redirect to '/login' on 401 Unauthorized responses
9
+ */
2
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.useUnauthorized = exports.useCSRF = exports.FetchClient = exports.NetworkError = exports.HttpError = exports.FetchError = void 0;
3
12
  const client_1 = require("./client");
4
13
  const csrf_1 = require("./csrf");
5
14
  const unauthorized_1 = require("./unauthorized");
15
+ /**
16
+ * Pre-configured fetch client with CSRF protection and unauthorized handling.
17
+ *
18
+ * This client is ready to use for applications that need:
19
+ * - CSRF protection
20
+ * - Automatic login redirects on authentication failures
21
+ * - Same-origin cookie handling
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * import api from '@fgrzl/fetch';
26
+ *
27
+ * // GET request
28
+ * const users = await api.get('/api/users');
29
+ *
30
+ * // POST request (automatically includes CSRF token)
31
+ * const newUser = await api.post('/api/users', { name: 'John' });
32
+ * ```
33
+ */
6
34
  const api = new client_1.FetchClient({
7
35
  credentials: 'same-origin',
8
36
  });
37
+ // Configure CSRF protection
9
38
  (0, csrf_1.useCSRF)(api, {
10
39
  cookieName: 'csrf_token',
11
40
  headerName: 'X-CSRF-Token',
12
41
  });
42
+ // Configure unauthorized redirect
13
43
  (0, unauthorized_1.useUnauthorized)(api, {
14
44
  loginPath: '/login',
15
45
  });
16
46
  exports.default = api;
47
+ // Export error classes and types for consumers
48
+ var errors_1 = require("./errors");
49
+ Object.defineProperty(exports, "FetchError", { enumerable: true, get: function () { return errors_1.FetchError; } });
50
+ Object.defineProperty(exports, "HttpError", { enumerable: true, get: function () { return errors_1.HttpError; } });
51
+ Object.defineProperty(exports, "NetworkError", { enumerable: true, get: function () { return errors_1.NetworkError; } });
52
+ var client_2 = require("./client");
53
+ Object.defineProperty(exports, "FetchClient", { enumerable: true, get: function () { return client_2.FetchClient; } });
54
+ var csrf_2 = require("./csrf");
55
+ Object.defineProperty(exports, "useCSRF", { enumerable: true, get: function () { return csrf_2.useCSRF; } });
56
+ var unauthorized_2 = require("./unauthorized");
57
+ Object.defineProperty(exports, "useUnauthorized", { enumerable: true, get: function () { return unauthorized_2.useUnauthorized; } });
17
58
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,qCAAuC;AACvC,iCAAiC;AACjC,iDAAiD;AAEjD,MAAM,GAAG,GAAG,IAAI,oBAAW,CAAC;IAC1B,WAAW,EAAE,aAAa;CAC3B,CAAC,CAAC;AAEH,IAAA,cAAO,EAAC,GAAG,EAAE;IACX,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,cAAc;CAC3B,CAAC,CAAC;AAEH,IAAA,8BAAe,EAAC,GAAG,EAAE;IACnB,SAAS,EAAE,QAAQ;CACpB,CAAC,CAAC;AAEH,kBAAe,GAAG,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,qCAAuC;AACvC,iCAAiC;AACjC,iDAAiD;AAEjD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,GAAG,GAAG,IAAI,oBAAW,CAAC;IAC1B,WAAW,EAAE,aAAa;CAC3B,CAAC,CAAC;AAEH,4BAA4B;AAC5B,IAAA,cAAO,EAAC,GAAG,EAAE;IACX,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,cAAc;CAC3B,CAAC,CAAC;AAEH,kCAAkC;AAClC,IAAA,8BAAe,EAAC,GAAG,EAAE;IACnB,SAAS,EAAE,QAAQ;CACpB,CAAC,CAAC;AAEH,kBAAe,GAAG,CAAC;AAEnB,+CAA+C;AAC/C,mCAA+D;AAAtD,oGAAA,UAAU,OAAA;AAAE,mGAAA,SAAS,OAAA;AAAE,sGAAA,YAAY,OAAA;AAC5C,mCAAuC;AAA9B,qGAAA,WAAW,OAAA;AAMpB,+BAAiC;AAAxB,+FAAA,OAAO,OAAA;AAChB,+CAAiD;AAAxC,+GAAA,eAAe,OAAA"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @fileoverview Shared test utilities to reduce duplication across test files.
3
+ */
4
+ /**
5
+ * Sets up mock fetch for testing with automatic cleanup.
6
+ * @returns Object with mockFetch function and cleanup utilities
7
+ */
8
+ export declare function setupMockFetch(): {
9
+ mockFetch: import("vitest").Mock<(...args: any[]) => any>;
10
+ setup: () => void;
11
+ cleanup: () => void;
12
+ };
13
+ /**
14
+ * Creates a mock Response object for testing.
15
+ * @param data - The response data to be JSON stringified
16
+ * @param status - HTTP status code (default: 200)
17
+ * @param headers - Additional headers (default: {})
18
+ * @returns Mock Response object
19
+ */
20
+ export declare function createMockResponse(data: any, status?: number, headers?: Record<string, string>): Response;
21
+ /**
22
+ * Clears all cookies in the document for testing.
23
+ */
24
+ export declare function clearAllCookies(): void;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Shared test utilities to reduce duplication across test files.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.setupMockFetch = setupMockFetch;
7
+ exports.createMockResponse = createMockResponse;
8
+ exports.clearAllCookies = clearAllCookies;
9
+ const vitest_1 = require("vitest");
10
+ /**
11
+ * Sets up mock fetch for testing with automatic cleanup.
12
+ * @returns Object with mockFetch function and cleanup utilities
13
+ */
14
+ function setupMockFetch() {
15
+ const mockFetch = vitest_1.vi.fn();
16
+ const originalFetch = globalThis.fetch;
17
+ const setup = () => {
18
+ vitest_1.vi.resetAllMocks();
19
+ globalThis.fetch = mockFetch;
20
+ };
21
+ const cleanup = () => {
22
+ globalThis.fetch = originalFetch;
23
+ };
24
+ return { mockFetch, setup, cleanup };
25
+ }
26
+ /**
27
+ * Creates a mock Response object for testing.
28
+ * @param data - The response data to be JSON stringified
29
+ * @param status - HTTP status code (default: 200)
30
+ * @param headers - Additional headers (default: {})
31
+ * @returns Mock Response object
32
+ */
33
+ function createMockResponse(data, status = 200, headers = {}) {
34
+ return new Response(JSON.stringify(data), {
35
+ status,
36
+ headers: {
37
+ 'Content-Type': 'application/json',
38
+ ...headers,
39
+ },
40
+ });
41
+ }
42
+ /**
43
+ * Clears all cookies in the document for testing.
44
+ */
45
+ function clearAllCookies() {
46
+ document.cookie.split(';').forEach((c) => {
47
+ const eqPos = c.indexOf('=');
48
+ const name = eqPos > -1 ? c.substring(0, eqPos) : c;
49
+ document.cookie = `${name.trim()}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
50
+ });
51
+ }
52
+ //# sourceMappingURL=test-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAQH,wCAcC;AASD,gDAYC;AAKD,0CAMC;AApDD,mCAA4B;AAE5B;;;GAGG;AACH,SAAgB,cAAc;IAC5B,MAAM,SAAS,GAAG,WAAE,CAAC,EAAE,EAAE,CAAC;IAC1B,MAAM,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC;IAEvC,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,WAAE,CAAC,aAAa,EAAE,CAAC;QACnB,UAAU,CAAC,KAAK,GAAG,SAAS,CAAC;IAC/B,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,UAAU,CAAC,KAAK,GAAG,aAAa,CAAC;IACnC,CAAC,CAAC;IAEF,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACvC,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,kBAAkB,CAChC,IAAS,EACT,SAAiB,GAAG,EACpB,UAAkC,EAAE;IAEpC,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;QACxC,MAAM;QACN,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,GAAG,OAAO;SACX;KACF,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAgB,eAAe;IAC7B,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QACvC,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,gDAAgD,CAAC;IACnF,CAAC,CAAC,CAAC;AACL,CAAC"}