@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/README.md +1068 -9
- package/dist/client.d.ts +95 -2
- package/dist/client.js +105 -18
- package/dist/client.js.map +1 -1
- package/dist/csrf.d.ts +25 -0
- package/dist/csrf.js +27 -0
- package/dist/csrf.js.map +1 -1
- package/dist/errors.d.ts +47 -0
- package/dist/errors.js +59 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -1
- package/dist/test-utils.d.ts +24 -0
- package/dist/test-utils.js +52 -0
- package/dist/test-utils.js.map +1 -0
- package/dist/unauthorized.d.ts +22 -0
- package/dist/unauthorized.js +25 -0
- package/dist/unauthorized.js.map +1 -1
- package/package.json +11 -7
- package/dist/index.test.d.ts +0 -1
- package/dist/index.test.js +0 -51
- package/dist/index.test.js.map +0 -1
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
|
-
|
|
16
|
-
|
|
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
|
-
|
|
18
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
}
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;;
|
|
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":";;
|
|
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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -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":"
|
|
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"}
|