@kaito-http/core 4.0.0-beta.1 → 4.0.0-beta.11
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/cors/cors.cjs +85 -17
- package/dist/cors/cors.d.cts +122 -26
- package/dist/cors/cors.d.ts +122 -26
- package/dist/cors/cors.js +85 -17
- package/dist/index.cjs +59 -25
- package/dist/index.d.cts +47 -36
- package/dist/index.d.ts +47 -36
- package/dist/index.js +61 -26
- package/dist/stream/stream.cjs +3 -0
- package/dist/stream/stream.d.cts +1 -0
- package/dist/stream/stream.d.ts +1 -0
- package/dist/stream/stream.js +3 -0
- package/package.json +1 -1
package/dist/cors/cors.cjs
CHANGED
|
@@ -24,33 +24,101 @@ __export(cors_exports, {
|
|
|
24
24
|
experimental_createOriginMatcher: () => experimental_createOriginMatcher
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(cors_exports);
|
|
27
|
-
function experimental_createOriginMatcher(
|
|
27
|
+
function experimental_createOriginMatcher(originIterator) {
|
|
28
|
+
const origins = Array.from(originIterator);
|
|
28
29
|
if (origins.length === 0) {
|
|
29
30
|
return () => false;
|
|
30
31
|
}
|
|
32
|
+
const escapedCharsRegex = /[.+?^${}()|[\]\\]/g;
|
|
31
33
|
const source = origins.map((origin) => {
|
|
32
|
-
if (origin.
|
|
33
|
-
const
|
|
34
|
-
|
|
34
|
+
if (origin.includes("://*.")) {
|
|
35
|
+
const parts = origin.split("://");
|
|
36
|
+
if (parts.length !== 2) {
|
|
37
|
+
throw new Error(`Invalid origin pattern: ${origin}. Must include protocol (e.g., https://*.example.com)`);
|
|
38
|
+
}
|
|
39
|
+
const [protocol, rest] = parts;
|
|
40
|
+
const domain = rest.slice(2).replace(escapedCharsRegex, "\\$&");
|
|
41
|
+
const pattern = `^${protocol.replace(escapedCharsRegex, "\\$&")}:\\/\\/[^.]+\\.${domain}$`;
|
|
42
|
+
return pattern;
|
|
35
43
|
} else {
|
|
36
|
-
const
|
|
37
|
-
return
|
|
44
|
+
const pattern = `^${origin.replace(escapedCharsRegex, "\\$&")}$`;
|
|
45
|
+
return pattern;
|
|
38
46
|
}
|
|
39
47
|
}).join("|");
|
|
40
48
|
const regex = new RegExp(source);
|
|
41
49
|
return (origin) => regex.test(origin);
|
|
42
50
|
}
|
|
43
|
-
function experimental_createCORSTransform(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
function experimental_createCORSTransform(originsIterator) {
|
|
52
|
+
let allowedOrigins = new Set(originsIterator);
|
|
53
|
+
let matcher = experimental_createOriginMatcher(allowedOrigins);
|
|
54
|
+
const updateMatcher = () => {
|
|
55
|
+
matcher = experimental_createOriginMatcher(allowedOrigins);
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
/**
|
|
59
|
+
* Handle OPTIONS requests in Kaito's `before()` hook
|
|
60
|
+
*
|
|
61
|
+
* @param request - The request object
|
|
62
|
+
* @returns A 204 response
|
|
63
|
+
*/
|
|
64
|
+
before: (request) => {
|
|
65
|
+
if (request.method === "OPTIONS") {
|
|
66
|
+
return new Response(null, { status: 204 });
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
/**
|
|
70
|
+
* Apply CORS headers to the response if origin matches.
|
|
71
|
+
*
|
|
72
|
+
* @param request - The request object
|
|
73
|
+
* @param response - The response object
|
|
74
|
+
*/
|
|
75
|
+
transform: (request, response) => {
|
|
76
|
+
const origin = request.headers.get("Origin");
|
|
77
|
+
if (origin && matcher(origin)) {
|
|
78
|
+
response.headers.set("Access-Control-Allow-Origin", origin);
|
|
79
|
+
response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
|
|
80
|
+
response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
81
|
+
response.headers.set("Access-Control-Max-Age", "86400");
|
|
82
|
+
response.headers.set("Access-Control-Allow-Credentials", "true");
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
/**
|
|
86
|
+
* Replace all allowed origins with a new set.
|
|
87
|
+
*
|
|
88
|
+
* @param newOrigins - The new set of allowed origins
|
|
89
|
+
*/
|
|
90
|
+
setOrigins: (newOrigins) => {
|
|
91
|
+
allowedOrigins = new Set(newOrigins);
|
|
92
|
+
updateMatcher();
|
|
93
|
+
},
|
|
94
|
+
/**
|
|
95
|
+
* Add one or more origins to the allowed list.
|
|
96
|
+
*
|
|
97
|
+
* @param origins - The origins to add
|
|
98
|
+
*/
|
|
99
|
+
addOrigins: (...origins) => {
|
|
100
|
+
for (const origin of origins) {
|
|
101
|
+
allowedOrigins.add(origin);
|
|
102
|
+
}
|
|
103
|
+
updateMatcher();
|
|
104
|
+
},
|
|
105
|
+
/**
|
|
106
|
+
* Remove one or more origins from the allowed list.
|
|
107
|
+
*
|
|
108
|
+
* @param origins - The origins to remove
|
|
109
|
+
*/
|
|
110
|
+
removeOrigins: (...origins) => {
|
|
111
|
+
for (const origin of origins) {
|
|
112
|
+
allowedOrigins.delete(origin);
|
|
113
|
+
}
|
|
114
|
+
updateMatcher();
|
|
115
|
+
},
|
|
116
|
+
/**
|
|
117
|
+
* Clones the current set of allowed origins and returns it
|
|
118
|
+
*
|
|
119
|
+
* @returns A set of allowed origins
|
|
120
|
+
*/
|
|
121
|
+
getOrigins: () => new Set(allowedOrigins)
|
|
54
122
|
};
|
|
55
123
|
}
|
|
56
124
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/cors/cors.d.cts
CHANGED
|
@@ -1,55 +1,151 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Creates a function that matches origins against a predefined set of patterns, supporting wildcards.
|
|
3
|
-
* The matcher handles both exact matches and wildcard subdomain patterns
|
|
3
|
+
* The matcher handles both exact matches and wildcard subdomain patterns.
|
|
4
4
|
*
|
|
5
5
|
* **⚠️ This API is experimental and may change or even be removed in the future. ⚠️**
|
|
6
6
|
*
|
|
7
|
-
* @param
|
|
8
|
-
*
|
|
7
|
+
* @param originIterator Array of origin patterns to match against.
|
|
8
|
+
* Each pattern MUST include the protocol (http:// or https://).
|
|
9
|
+
* Two types of patterns are supported:
|
|
10
|
+
* 1. Exact matches (e.g., 'https://example.com') - matches only the exact domain with exact protocol
|
|
11
|
+
* 2. Wildcard subdomain patterns (e.g., 'https://*.example.com') - matches ONLY subdomains with exact protocol
|
|
12
|
+
*
|
|
13
|
+
* Important matching rules:
|
|
14
|
+
* - Protocol is always matched exactly - if you need both HTTP and HTTPS, include both patterns
|
|
15
|
+
* - Wildcard patterns (e.g., 'https://*.example.com') will ONLY match subdomains, NOT the root domain
|
|
16
|
+
* - To match both subdomains AND the root domain, include both patterns:
|
|
17
|
+
* ['https://*.example.com', 'https://example.com']
|
|
18
|
+
*
|
|
9
19
|
* @returns A function that tests if an origin matches any of the patterns
|
|
10
20
|
*
|
|
11
21
|
* @example
|
|
12
22
|
* ```typescript
|
|
13
23
|
* const allowedOrigins = [
|
|
14
|
-
*
|
|
15
|
-
* '
|
|
24
|
+
* // Exact matches - protocol required
|
|
25
|
+
* 'https://example.com', // matches only https://example.com
|
|
26
|
+
* 'http://example.com', // matches only http://example.com
|
|
27
|
+
*
|
|
28
|
+
* // Wildcard subdomain matches - protocol required
|
|
29
|
+
* 'https://*.example.com', // matches https://app.example.com, https://api.example.com
|
|
30
|
+
* // does NOT match https://example.com
|
|
31
|
+
*
|
|
32
|
+
* // To match both HTTP and HTTPS, include both
|
|
33
|
+
* 'https://*.staging.com', // matches https://app.staging.com
|
|
34
|
+
* 'http://*.staging.com', // matches http://app.staging.com
|
|
35
|
+
*
|
|
36
|
+
* // To match both subdomains and root domain, include both
|
|
37
|
+
* 'https://*.production.com', // matches https://app.production.com
|
|
38
|
+
* 'https://production.com', // matches https://production.com
|
|
16
39
|
* ];
|
|
17
40
|
*
|
|
18
41
|
* const matcher = createOriginMatcher(allowedOrigins);
|
|
19
42
|
*
|
|
20
|
-
* // Exact
|
|
21
|
-
*
|
|
22
|
-
*
|
|
43
|
+
* // Exact matches
|
|
44
|
+
* matcher('https://example.com'); // true
|
|
45
|
+
* matcher('http://example.com'); // true
|
|
23
46
|
*
|
|
24
|
-
* //
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
47
|
+
* // Subdomain matches (protocol specific)
|
|
48
|
+
* matcher('https://app.example.com'); // true
|
|
49
|
+
* matcher('http://app.example.com'); // false - wrong protocol
|
|
50
|
+
*
|
|
51
|
+
* // Root domain with wildcard pattern
|
|
52
|
+
* matcher('https://example.com'); // false - wildcards don't match root
|
|
53
|
+
* matcher('https://production.com'); // true - matched by exact pattern
|
|
29
54
|
* ```
|
|
30
55
|
*/
|
|
31
|
-
declare function experimental_createOriginMatcher(
|
|
56
|
+
declare function experimental_createOriginMatcher(originIterator: Iterable<string>): (origin: string) => boolean;
|
|
32
57
|
/**
|
|
33
|
-
* Create a
|
|
58
|
+
* Create a CORS handler with sane defaults for most apps.
|
|
34
59
|
*
|
|
35
60
|
* **⚠️ This API is experimental and may change or even be removed in the future. ⚠️**
|
|
36
61
|
*
|
|
37
|
-
* @param
|
|
38
|
-
*
|
|
62
|
+
* @param originsIterator Array of allowed origin patterns. Each pattern must include protocol (http:// or https://).
|
|
63
|
+
* Supports both exact matches and wildcard subdomain patterns. See {@link experimental_createOriginMatcher}
|
|
64
|
+
* for detailed pattern matching rules.
|
|
65
|
+
*
|
|
66
|
+
* @returns An object containing:
|
|
67
|
+
* - `before`: A handler for OPTIONS requests that returns a 204 response
|
|
68
|
+
* - `transform`: A function that applies CORS headers to the response if origin matches
|
|
69
|
+
* - `setOrigins`: A function to replace all allowed origins with a new set
|
|
70
|
+
* - `appendOrigin`: A function to add a new origin to the allowed list
|
|
71
|
+
* - `removeOrigin`: A function to remove an origin from the allowed list
|
|
72
|
+
* - `getOrigins`: A function that returns the current list of allowed origins
|
|
73
|
+
*
|
|
39
74
|
* @example
|
|
40
75
|
* ```ts
|
|
41
|
-
* const
|
|
42
|
-
*
|
|
43
|
-
*
|
|
76
|
+
* const corsHandler = experimental_createCORSTransform([
|
|
77
|
+
* // Exact matches
|
|
78
|
+
* 'https://example.com',
|
|
79
|
+
* 'http://localhost:3000',
|
|
80
|
+
*
|
|
81
|
+
* // Wildcard subdomain matches
|
|
82
|
+
* 'https://*.myapp.com', // matches https://dashboard.myapp.com
|
|
83
|
+
* 'http://*.myapp.com', // matches http://dashboard.myapp.com
|
|
44
84
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
85
|
+
* // Match both subdomain and root domain
|
|
86
|
+
* 'https://*.staging.com', // matches https://app.staging.com
|
|
87
|
+
* 'https://staging.com' // matches https://staging.com
|
|
88
|
+
* ]);
|
|
89
|
+
*
|
|
90
|
+
* const router = create({
|
|
91
|
+
* // Handle preflight requests
|
|
92
|
+
* before: corsHandler.before,
|
|
93
|
+
*
|
|
94
|
+
* // Or expanded
|
|
95
|
+
* before: (request) => {
|
|
96
|
+
* const res = cors.before(request);
|
|
97
|
+
* if (res) return res;
|
|
98
|
+
* },
|
|
99
|
+
*
|
|
100
|
+
* // Apply CORS headers to all responses
|
|
101
|
+
* transform: corsHandler.transform,
|
|
50
102
|
* });
|
|
103
|
+
*
|
|
104
|
+
* // Manage origins dynamically
|
|
105
|
+
* corsHandler.appendOrigin('https://newdomain.com');
|
|
106
|
+
* corsHandler.removeOrigin('http://localhost:3000');
|
|
107
|
+
* corsHandler.setOrigins(['https://completely-new-domain.com']);
|
|
51
108
|
* ```
|
|
52
109
|
*/
|
|
53
|
-
declare function experimental_createCORSTransform(
|
|
110
|
+
declare function experimental_createCORSTransform(originsIterator: Iterable<string>): {
|
|
111
|
+
/**
|
|
112
|
+
* Handle OPTIONS requests in Kaito's `before()` hook
|
|
113
|
+
*
|
|
114
|
+
* @param request - The request object
|
|
115
|
+
* @returns A 204 response
|
|
116
|
+
*/
|
|
117
|
+
before: (request: Request) => Response | undefined;
|
|
118
|
+
/**
|
|
119
|
+
* Apply CORS headers to the response if origin matches.
|
|
120
|
+
*
|
|
121
|
+
* @param request - The request object
|
|
122
|
+
* @param response - The response object
|
|
123
|
+
*/
|
|
124
|
+
transform: (request: Request, response: Response) => void;
|
|
125
|
+
/**
|
|
126
|
+
* Replace all allowed origins with a new set.
|
|
127
|
+
*
|
|
128
|
+
* @param newOrigins - The new set of allowed origins
|
|
129
|
+
*/
|
|
130
|
+
setOrigins: (newOrigins: Iterable<string>) => void;
|
|
131
|
+
/**
|
|
132
|
+
* Add one or more origins to the allowed list.
|
|
133
|
+
*
|
|
134
|
+
* @param origins - The origins to add
|
|
135
|
+
*/
|
|
136
|
+
addOrigins: (...origins: string[]) => void;
|
|
137
|
+
/**
|
|
138
|
+
* Remove one or more origins from the allowed list.
|
|
139
|
+
*
|
|
140
|
+
* @param origins - The origins to remove
|
|
141
|
+
*/
|
|
142
|
+
removeOrigins: (...origins: string[]) => void;
|
|
143
|
+
/**
|
|
144
|
+
* Clones the current set of allowed origins and returns it
|
|
145
|
+
*
|
|
146
|
+
* @returns A set of allowed origins
|
|
147
|
+
*/
|
|
148
|
+
getOrigins: () => Set<string>;
|
|
149
|
+
};
|
|
54
150
|
|
|
55
151
|
export { experimental_createCORSTransform, experimental_createOriginMatcher };
|
package/dist/cors/cors.d.ts
CHANGED
|
@@ -1,55 +1,151 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Creates a function that matches origins against a predefined set of patterns, supporting wildcards.
|
|
3
|
-
* The matcher handles both exact matches and wildcard subdomain patterns
|
|
3
|
+
* The matcher handles both exact matches and wildcard subdomain patterns.
|
|
4
4
|
*
|
|
5
5
|
* **⚠️ This API is experimental and may change or even be removed in the future. ⚠️**
|
|
6
6
|
*
|
|
7
|
-
* @param
|
|
8
|
-
*
|
|
7
|
+
* @param originIterator Array of origin patterns to match against.
|
|
8
|
+
* Each pattern MUST include the protocol (http:// or https://).
|
|
9
|
+
* Two types of patterns are supported:
|
|
10
|
+
* 1. Exact matches (e.g., 'https://example.com') - matches only the exact domain with exact protocol
|
|
11
|
+
* 2. Wildcard subdomain patterns (e.g., 'https://*.example.com') - matches ONLY subdomains with exact protocol
|
|
12
|
+
*
|
|
13
|
+
* Important matching rules:
|
|
14
|
+
* - Protocol is always matched exactly - if you need both HTTP and HTTPS, include both patterns
|
|
15
|
+
* - Wildcard patterns (e.g., 'https://*.example.com') will ONLY match subdomains, NOT the root domain
|
|
16
|
+
* - To match both subdomains AND the root domain, include both patterns:
|
|
17
|
+
* ['https://*.example.com', 'https://example.com']
|
|
18
|
+
*
|
|
9
19
|
* @returns A function that tests if an origin matches any of the patterns
|
|
10
20
|
*
|
|
11
21
|
* @example
|
|
12
22
|
* ```typescript
|
|
13
23
|
* const allowedOrigins = [
|
|
14
|
-
*
|
|
15
|
-
* '
|
|
24
|
+
* // Exact matches - protocol required
|
|
25
|
+
* 'https://example.com', // matches only https://example.com
|
|
26
|
+
* 'http://example.com', // matches only http://example.com
|
|
27
|
+
*
|
|
28
|
+
* // Wildcard subdomain matches - protocol required
|
|
29
|
+
* 'https://*.example.com', // matches https://app.example.com, https://api.example.com
|
|
30
|
+
* // does NOT match https://example.com
|
|
31
|
+
*
|
|
32
|
+
* // To match both HTTP and HTTPS, include both
|
|
33
|
+
* 'https://*.staging.com', // matches https://app.staging.com
|
|
34
|
+
* 'http://*.staging.com', // matches http://app.staging.com
|
|
35
|
+
*
|
|
36
|
+
* // To match both subdomains and root domain, include both
|
|
37
|
+
* 'https://*.production.com', // matches https://app.production.com
|
|
38
|
+
* 'https://production.com', // matches https://production.com
|
|
16
39
|
* ];
|
|
17
40
|
*
|
|
18
41
|
* const matcher = createOriginMatcher(allowedOrigins);
|
|
19
42
|
*
|
|
20
|
-
* // Exact
|
|
21
|
-
*
|
|
22
|
-
*
|
|
43
|
+
* // Exact matches
|
|
44
|
+
* matcher('https://example.com'); // true
|
|
45
|
+
* matcher('http://example.com'); // true
|
|
23
46
|
*
|
|
24
|
-
* //
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
47
|
+
* // Subdomain matches (protocol specific)
|
|
48
|
+
* matcher('https://app.example.com'); // true
|
|
49
|
+
* matcher('http://app.example.com'); // false - wrong protocol
|
|
50
|
+
*
|
|
51
|
+
* // Root domain with wildcard pattern
|
|
52
|
+
* matcher('https://example.com'); // false - wildcards don't match root
|
|
53
|
+
* matcher('https://production.com'); // true - matched by exact pattern
|
|
29
54
|
* ```
|
|
30
55
|
*/
|
|
31
|
-
declare function experimental_createOriginMatcher(
|
|
56
|
+
declare function experimental_createOriginMatcher(originIterator: Iterable<string>): (origin: string) => boolean;
|
|
32
57
|
/**
|
|
33
|
-
* Create a
|
|
58
|
+
* Create a CORS handler with sane defaults for most apps.
|
|
34
59
|
*
|
|
35
60
|
* **⚠️ This API is experimental and may change or even be removed in the future. ⚠️**
|
|
36
61
|
*
|
|
37
|
-
* @param
|
|
38
|
-
*
|
|
62
|
+
* @param originsIterator Array of allowed origin patterns. Each pattern must include protocol (http:// or https://).
|
|
63
|
+
* Supports both exact matches and wildcard subdomain patterns. See {@link experimental_createOriginMatcher}
|
|
64
|
+
* for detailed pattern matching rules.
|
|
65
|
+
*
|
|
66
|
+
* @returns An object containing:
|
|
67
|
+
* - `before`: A handler for OPTIONS requests that returns a 204 response
|
|
68
|
+
* - `transform`: A function that applies CORS headers to the response if origin matches
|
|
69
|
+
* - `setOrigins`: A function to replace all allowed origins with a new set
|
|
70
|
+
* - `appendOrigin`: A function to add a new origin to the allowed list
|
|
71
|
+
* - `removeOrigin`: A function to remove an origin from the allowed list
|
|
72
|
+
* - `getOrigins`: A function that returns the current list of allowed origins
|
|
73
|
+
*
|
|
39
74
|
* @example
|
|
40
75
|
* ```ts
|
|
41
|
-
* const
|
|
42
|
-
*
|
|
43
|
-
*
|
|
76
|
+
* const corsHandler = experimental_createCORSTransform([
|
|
77
|
+
* // Exact matches
|
|
78
|
+
* 'https://example.com',
|
|
79
|
+
* 'http://localhost:3000',
|
|
80
|
+
*
|
|
81
|
+
* // Wildcard subdomain matches
|
|
82
|
+
* 'https://*.myapp.com', // matches https://dashboard.myapp.com
|
|
83
|
+
* 'http://*.myapp.com', // matches http://dashboard.myapp.com
|
|
44
84
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
85
|
+
* // Match both subdomain and root domain
|
|
86
|
+
* 'https://*.staging.com', // matches https://app.staging.com
|
|
87
|
+
* 'https://staging.com' // matches https://staging.com
|
|
88
|
+
* ]);
|
|
89
|
+
*
|
|
90
|
+
* const router = create({
|
|
91
|
+
* // Handle preflight requests
|
|
92
|
+
* before: corsHandler.before,
|
|
93
|
+
*
|
|
94
|
+
* // Or expanded
|
|
95
|
+
* before: (request) => {
|
|
96
|
+
* const res = cors.before(request);
|
|
97
|
+
* if (res) return res;
|
|
98
|
+
* },
|
|
99
|
+
*
|
|
100
|
+
* // Apply CORS headers to all responses
|
|
101
|
+
* transform: corsHandler.transform,
|
|
50
102
|
* });
|
|
103
|
+
*
|
|
104
|
+
* // Manage origins dynamically
|
|
105
|
+
* corsHandler.appendOrigin('https://newdomain.com');
|
|
106
|
+
* corsHandler.removeOrigin('http://localhost:3000');
|
|
107
|
+
* corsHandler.setOrigins(['https://completely-new-domain.com']);
|
|
51
108
|
* ```
|
|
52
109
|
*/
|
|
53
|
-
declare function experimental_createCORSTransform(
|
|
110
|
+
declare function experimental_createCORSTransform(originsIterator: Iterable<string>): {
|
|
111
|
+
/**
|
|
112
|
+
* Handle OPTIONS requests in Kaito's `before()` hook
|
|
113
|
+
*
|
|
114
|
+
* @param request - The request object
|
|
115
|
+
* @returns A 204 response
|
|
116
|
+
*/
|
|
117
|
+
before: (request: Request) => Response | undefined;
|
|
118
|
+
/**
|
|
119
|
+
* Apply CORS headers to the response if origin matches.
|
|
120
|
+
*
|
|
121
|
+
* @param request - The request object
|
|
122
|
+
* @param response - The response object
|
|
123
|
+
*/
|
|
124
|
+
transform: (request: Request, response: Response) => void;
|
|
125
|
+
/**
|
|
126
|
+
* Replace all allowed origins with a new set.
|
|
127
|
+
*
|
|
128
|
+
* @param newOrigins - The new set of allowed origins
|
|
129
|
+
*/
|
|
130
|
+
setOrigins: (newOrigins: Iterable<string>) => void;
|
|
131
|
+
/**
|
|
132
|
+
* Add one or more origins to the allowed list.
|
|
133
|
+
*
|
|
134
|
+
* @param origins - The origins to add
|
|
135
|
+
*/
|
|
136
|
+
addOrigins: (...origins: string[]) => void;
|
|
137
|
+
/**
|
|
138
|
+
* Remove one or more origins from the allowed list.
|
|
139
|
+
*
|
|
140
|
+
* @param origins - The origins to remove
|
|
141
|
+
*/
|
|
142
|
+
removeOrigins: (...origins: string[]) => void;
|
|
143
|
+
/**
|
|
144
|
+
* Clones the current set of allowed origins and returns it
|
|
145
|
+
*
|
|
146
|
+
* @returns A set of allowed origins
|
|
147
|
+
*/
|
|
148
|
+
getOrigins: () => Set<string>;
|
|
149
|
+
};
|
|
54
150
|
|
|
55
151
|
export { experimental_createCORSTransform, experimental_createOriginMatcher };
|
package/dist/cors/cors.js
CHANGED
|
@@ -1,31 +1,99 @@
|
|
|
1
1
|
// src/cors/cors.ts
|
|
2
|
-
function experimental_createOriginMatcher(
|
|
2
|
+
function experimental_createOriginMatcher(originIterator) {
|
|
3
|
+
const origins = Array.from(originIterator);
|
|
3
4
|
if (origins.length === 0) {
|
|
4
5
|
return () => false;
|
|
5
6
|
}
|
|
7
|
+
const escapedCharsRegex = /[.+?^${}()|[\]\\]/g;
|
|
6
8
|
const source = origins.map((origin) => {
|
|
7
|
-
if (origin.
|
|
8
|
-
const
|
|
9
|
-
|
|
9
|
+
if (origin.includes("://*.")) {
|
|
10
|
+
const parts = origin.split("://");
|
|
11
|
+
if (parts.length !== 2) {
|
|
12
|
+
throw new Error(`Invalid origin pattern: ${origin}. Must include protocol (e.g., https://*.example.com)`);
|
|
13
|
+
}
|
|
14
|
+
const [protocol, rest] = parts;
|
|
15
|
+
const domain = rest.slice(2).replace(escapedCharsRegex, "\\$&");
|
|
16
|
+
const pattern = `^${protocol.replace(escapedCharsRegex, "\\$&")}:\\/\\/[^.]+\\.${domain}$`;
|
|
17
|
+
return pattern;
|
|
10
18
|
} else {
|
|
11
|
-
const
|
|
12
|
-
return
|
|
19
|
+
const pattern = `^${origin.replace(escapedCharsRegex, "\\$&")}$`;
|
|
20
|
+
return pattern;
|
|
13
21
|
}
|
|
14
22
|
}).join("|");
|
|
15
23
|
const regex = new RegExp(source);
|
|
16
24
|
return (origin) => regex.test(origin);
|
|
17
25
|
}
|
|
18
|
-
function experimental_createCORSTransform(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
function experimental_createCORSTransform(originsIterator) {
|
|
27
|
+
let allowedOrigins = new Set(originsIterator);
|
|
28
|
+
let matcher = experimental_createOriginMatcher(allowedOrigins);
|
|
29
|
+
const updateMatcher = () => {
|
|
30
|
+
matcher = experimental_createOriginMatcher(allowedOrigins);
|
|
31
|
+
};
|
|
32
|
+
return {
|
|
33
|
+
/**
|
|
34
|
+
* Handle OPTIONS requests in Kaito's `before()` hook
|
|
35
|
+
*
|
|
36
|
+
* @param request - The request object
|
|
37
|
+
* @returns A 204 response
|
|
38
|
+
*/
|
|
39
|
+
before: (request) => {
|
|
40
|
+
if (request.method === "OPTIONS") {
|
|
41
|
+
return new Response(null, { status: 204 });
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
/**
|
|
45
|
+
* Apply CORS headers to the response if origin matches.
|
|
46
|
+
*
|
|
47
|
+
* @param request - The request object
|
|
48
|
+
* @param response - The response object
|
|
49
|
+
*/
|
|
50
|
+
transform: (request, response) => {
|
|
51
|
+
const origin = request.headers.get("Origin");
|
|
52
|
+
if (origin && matcher(origin)) {
|
|
53
|
+
response.headers.set("Access-Control-Allow-Origin", origin);
|
|
54
|
+
response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
|
|
55
|
+
response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
56
|
+
response.headers.set("Access-Control-Max-Age", "86400");
|
|
57
|
+
response.headers.set("Access-Control-Allow-Credentials", "true");
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
/**
|
|
61
|
+
* Replace all allowed origins with a new set.
|
|
62
|
+
*
|
|
63
|
+
* @param newOrigins - The new set of allowed origins
|
|
64
|
+
*/
|
|
65
|
+
setOrigins: (newOrigins) => {
|
|
66
|
+
allowedOrigins = new Set(newOrigins);
|
|
67
|
+
updateMatcher();
|
|
68
|
+
},
|
|
69
|
+
/**
|
|
70
|
+
* Add one or more origins to the allowed list.
|
|
71
|
+
*
|
|
72
|
+
* @param origins - The origins to add
|
|
73
|
+
*/
|
|
74
|
+
addOrigins: (...origins) => {
|
|
75
|
+
for (const origin of origins) {
|
|
76
|
+
allowedOrigins.add(origin);
|
|
77
|
+
}
|
|
78
|
+
updateMatcher();
|
|
79
|
+
},
|
|
80
|
+
/**
|
|
81
|
+
* Remove one or more origins from the allowed list.
|
|
82
|
+
*
|
|
83
|
+
* @param origins - The origins to remove
|
|
84
|
+
*/
|
|
85
|
+
removeOrigins: (...origins) => {
|
|
86
|
+
for (const origin of origins) {
|
|
87
|
+
allowedOrigins.delete(origin);
|
|
88
|
+
}
|
|
89
|
+
updateMatcher();
|
|
90
|
+
},
|
|
91
|
+
/**
|
|
92
|
+
* Clones the current set of allowed origins and returns it
|
|
93
|
+
*
|
|
94
|
+
* @returns A set of allowed origins
|
|
95
|
+
*/
|
|
96
|
+
getOrigins: () => new Set(allowedOrigins)
|
|
29
97
|
};
|
|
30
98
|
}
|
|
31
99
|
export {
|