@kaito-http/core 4.0.0-beta.7 → 4.0.0-beta.9

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.
@@ -48,15 +48,25 @@ function experimental_createOriginMatcher(origins) {
48
48
  return (origin) => regex.test(origin);
49
49
  }
50
50
  function experimental_createCORSTransform(origins) {
51
- const matcher = experimental_createOriginMatcher(origins);
52
- return (request, response) => {
53
- const origin = request.headers.get("Origin");
54
- if (origin && matcher(origin)) {
55
- response.headers.set("Access-Control-Allow-Origin", origin);
56
- response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
57
- response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
58
- response.headers.set("Access-Control-Max-Age", "86400");
59
- response.headers.set("Access-Control-Allow-Credentials", "true");
51
+ let matcher = experimental_createOriginMatcher(origins);
52
+ return {
53
+ before: (request) => {
54
+ if (request.method === "OPTIONS") {
55
+ return new Response(null, { status: 204 });
56
+ }
57
+ },
58
+ transform: (request, response) => {
59
+ const origin = request.headers.get("Origin");
60
+ if (origin && matcher(origin)) {
61
+ response.headers.set("Access-Control-Allow-Origin", origin);
62
+ response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
63
+ response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
64
+ response.headers.set("Access-Control-Max-Age", "86400");
65
+ response.headers.set("Access-Control-Allow-Credentials", "true");
66
+ }
67
+ },
68
+ setOrigins: (newOrigins) => {
69
+ matcher = experimental_createOriginMatcher(newOrigins);
60
70
  }
61
71
  };
62
72
  }
@@ -55,42 +55,57 @@
55
55
  */
56
56
  declare function experimental_createOriginMatcher(origins: string[]): (origin: string) => boolean;
57
57
  /**
58
- * Create a function to apply CORS headers with sane defaults for most apps.
58
+ * Create a CORS handler with sane defaults for most apps.
59
59
  *
60
60
  * **⚠️ This API is experimental and may change or even be removed in the future. ⚠️**
61
61
  *
62
- * @param options Options object
63
- * @returns A function that will mutate the Response object by applying the CORS headers
62
+ * @param origins 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 dynamically update the allowed origins
70
+ *
64
71
  * @example
65
72
  * ```ts
66
- * const cors = experimental_createCORSTransform([
67
- * // Exact matches
68
- * 'https://example.com',
69
- * 'http://localhost:3000',
73
+ * const corsHandler = experimental_createCORSTransform([
74
+ * // Exact matches
75
+ * 'https://example.com',
76
+ * 'http://localhost:3000',
70
77
  *
71
- * // Wildcard subdomain matches
72
- * 'https://*.myapp.com', // matches https://dashboard.myapp.com
73
- * 'http://*.myapp.com', // matches http://dashboard.myapp.com
78
+ * // Wildcard subdomain matches
79
+ * 'https://*.myapp.com', // matches https://dashboard.myapp.com
80
+ * 'http://*.myapp.com', // matches http://dashboard.myapp.com
74
81
  *
75
- * // Match both subdomain and root domain
76
- * 'https://*.staging.com', // matches https://app.staging.com
77
- * 'https://staging.com' // matches https://staging.com
78
- * ]);
82
+ * // Match both subdomain and root domain
83
+ * 'https://*.staging.com', // matches https://app.staging.com
84
+ * 'https://staging.com' // matches https://staging.com
85
+ * ]);
79
86
  *
80
87
  * const router = create({
81
- * before: async req => {
82
- * if (req.method === 'OPTIONS') {
83
- * // Return early to skip the router. This response still gets passed to `.transform()`
84
- * // So our CORS headers will still be applied
85
- * return new Response(null, {status: 204});
86
- * }
87
- * },
88
- * transform: async (request, response) => {
89
- * cors(request, response);
90
- * }
88
+ * // Handle preflight requests
89
+ * before: corsHandler.before,
90
+ *
91
+ * // Or expanded
92
+ * before: (request) => {
93
+ * const res = cors.before(request);
94
+ * if (res) return res;
95
+ * },
96
+ *
97
+ * // Apply CORS headers to all responses
98
+ * transform: corsHandler.transform,
91
99
  * });
100
+ *
101
+ * // Optionally update allowed origins later
102
+ * corsHandler.setOrigins(['https://newdomain.com']);
92
103
  * ```
93
104
  */
94
- declare function experimental_createCORSTransform(origins: string[]): (request: Request, response: Response) => void;
105
+ declare function experimental_createCORSTransform(origins: string[]): {
106
+ before: (request: Request) => Response | undefined;
107
+ transform: (request: Request, response: Response) => void;
108
+ setOrigins: (newOrigins: string[]) => void;
109
+ };
95
110
 
96
111
  export { experimental_createCORSTransform, experimental_createOriginMatcher };
@@ -55,42 +55,57 @@
55
55
  */
56
56
  declare function experimental_createOriginMatcher(origins: string[]): (origin: string) => boolean;
57
57
  /**
58
- * Create a function to apply CORS headers with sane defaults for most apps.
58
+ * Create a CORS handler with sane defaults for most apps.
59
59
  *
60
60
  * **⚠️ This API is experimental and may change or even be removed in the future. ⚠️**
61
61
  *
62
- * @param options Options object
63
- * @returns A function that will mutate the Response object by applying the CORS headers
62
+ * @param origins 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 dynamically update the allowed origins
70
+ *
64
71
  * @example
65
72
  * ```ts
66
- * const cors = experimental_createCORSTransform([
67
- * // Exact matches
68
- * 'https://example.com',
69
- * 'http://localhost:3000',
73
+ * const corsHandler = experimental_createCORSTransform([
74
+ * // Exact matches
75
+ * 'https://example.com',
76
+ * 'http://localhost:3000',
70
77
  *
71
- * // Wildcard subdomain matches
72
- * 'https://*.myapp.com', // matches https://dashboard.myapp.com
73
- * 'http://*.myapp.com', // matches http://dashboard.myapp.com
78
+ * // Wildcard subdomain matches
79
+ * 'https://*.myapp.com', // matches https://dashboard.myapp.com
80
+ * 'http://*.myapp.com', // matches http://dashboard.myapp.com
74
81
  *
75
- * // Match both subdomain and root domain
76
- * 'https://*.staging.com', // matches https://app.staging.com
77
- * 'https://staging.com' // matches https://staging.com
78
- * ]);
82
+ * // Match both subdomain and root domain
83
+ * 'https://*.staging.com', // matches https://app.staging.com
84
+ * 'https://staging.com' // matches https://staging.com
85
+ * ]);
79
86
  *
80
87
  * const router = create({
81
- * before: async req => {
82
- * if (req.method === 'OPTIONS') {
83
- * // Return early to skip the router. This response still gets passed to `.transform()`
84
- * // So our CORS headers will still be applied
85
- * return new Response(null, {status: 204});
86
- * }
87
- * },
88
- * transform: async (request, response) => {
89
- * cors(request, response);
90
- * }
88
+ * // Handle preflight requests
89
+ * before: corsHandler.before,
90
+ *
91
+ * // Or expanded
92
+ * before: (request) => {
93
+ * const res = cors.before(request);
94
+ * if (res) return res;
95
+ * },
96
+ *
97
+ * // Apply CORS headers to all responses
98
+ * transform: corsHandler.transform,
91
99
  * });
100
+ *
101
+ * // Optionally update allowed origins later
102
+ * corsHandler.setOrigins(['https://newdomain.com']);
92
103
  * ```
93
104
  */
94
- declare function experimental_createCORSTransform(origins: string[]): (request: Request, response: Response) => void;
105
+ declare function experimental_createCORSTransform(origins: string[]): {
106
+ before: (request: Request) => Response | undefined;
107
+ transform: (request: Request, response: Response) => void;
108
+ setOrigins: (newOrigins: string[]) => void;
109
+ };
95
110
 
96
111
  export { experimental_createCORSTransform, experimental_createOriginMatcher };
package/dist/cors/cors.js CHANGED
@@ -23,15 +23,25 @@ function experimental_createOriginMatcher(origins) {
23
23
  return (origin) => regex.test(origin);
24
24
  }
25
25
  function experimental_createCORSTransform(origins) {
26
- const matcher = experimental_createOriginMatcher(origins);
27
- return (request, response) => {
28
- const origin = request.headers.get("Origin");
29
- if (origin && matcher(origin)) {
30
- response.headers.set("Access-Control-Allow-Origin", origin);
31
- response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
32
- response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
33
- response.headers.set("Access-Control-Max-Age", "86400");
34
- response.headers.set("Access-Control-Allow-Credentials", "true");
26
+ let matcher = experimental_createOriginMatcher(origins);
27
+ return {
28
+ before: (request) => {
29
+ if (request.method === "OPTIONS") {
30
+ return new Response(null, { status: 204 });
31
+ }
32
+ },
33
+ transform: (request, response) => {
34
+ const origin = request.headers.get("Origin");
35
+ if (origin && matcher(origin)) {
36
+ response.headers.set("Access-Control-Allow-Origin", origin);
37
+ response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
38
+ response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
39
+ response.headers.set("Access-Control-Max-Age", "86400");
40
+ response.headers.set("Access-Control-Allow-Credentials", "true");
41
+ }
42
+ },
43
+ setOrigins: (newOrigins) => {
44
+ matcher = experimental_createOriginMatcher(newOrigins);
35
45
  }
36
46
  };
37
47
  }
package/dist/index.cjs CHANGED
@@ -178,7 +178,10 @@ var Router = class _Router {
178
178
  merge = (pathPrefix, other) => {
179
179
  const newRoutes = [...other.state.routes].map((route) => ({
180
180
  ...route,
181
- path: `${pathPrefix}${route.path}`
181
+ // handle pathPrefix = / & route.path = / case causing //
182
+ // we intentionally are replacing on the joining path and not the pathPrefix, in case of
183
+ // /named -> merged to -> / causing /named/ not /named
184
+ path: `${pathPrefix}${route.path === "/" ? "" : route.path}`
182
185
  }));
183
186
  return new _Router({
184
187
  ...this.state,
@@ -366,7 +369,7 @@ var Router = class _Router {
366
369
  const item = {
367
370
  description: route.openapi?.description ?? "Successful response",
368
371
  responses: {
369
- default: {
372
+ 200: {
370
373
  description: route.openapi?.description ?? "Successful response",
371
374
  content
372
375
  }
package/dist/index.d.cts CHANGED
@@ -148,7 +148,7 @@ type Route<ContextTo, Result, Path extends string, AdditionalParams extends Reco
148
148
  };
149
149
  type AnyRoute = Route<any, any, any, any, any, any, any>;
150
150
 
151
- type PrefixRoutesPathInner<R extends AnyRoute, Prefix extends `/${string}`> = R extends Route<infer ContextTo, infer Result, infer Path, infer AdditionalParams, infer Method, infer Query, infer BodyOutput> ? Route<ContextTo, Result, `${Prefix}${Path}`, AdditionalParams, Method, Query, BodyOutput> : never;
151
+ type PrefixRoutesPathInner<R extends AnyRoute, Prefix extends `/${string}`> = R extends Route<infer ContextTo, infer Result, infer Path, infer AdditionalParams, infer Method, infer Query, infer BodyOutput> ? Route<ContextTo, Result, `${Prefix}${Path extends '/' ? '' : Path}`, AdditionalParams, Method, Query, BodyOutput> : never;
152
152
  type PrefixRoutesPath<Prefix extends `/${string}`, R extends AnyRoute> = R extends R ? PrefixRoutesPathInner<R, Prefix> : never;
153
153
  type RouterState<ContextFrom, ContextTo, RequiredParams extends Record<string, unknown>, Routes extends AnyRoute> = {
154
154
  routes: Set<Routes>;
package/dist/index.d.ts CHANGED
@@ -148,7 +148,7 @@ type Route<ContextTo, Result, Path extends string, AdditionalParams extends Reco
148
148
  };
149
149
  type AnyRoute = Route<any, any, any, any, any, any, any>;
150
150
 
151
- type PrefixRoutesPathInner<R extends AnyRoute, Prefix extends `/${string}`> = R extends Route<infer ContextTo, infer Result, infer Path, infer AdditionalParams, infer Method, infer Query, infer BodyOutput> ? Route<ContextTo, Result, `${Prefix}${Path}`, AdditionalParams, Method, Query, BodyOutput> : never;
151
+ type PrefixRoutesPathInner<R extends AnyRoute, Prefix extends `/${string}`> = R extends Route<infer ContextTo, infer Result, infer Path, infer AdditionalParams, infer Method, infer Query, infer BodyOutput> ? Route<ContextTo, Result, `${Prefix}${Path extends '/' ? '' : Path}`, AdditionalParams, Method, Query, BodyOutput> : never;
152
152
  type PrefixRoutesPath<Prefix extends `/${string}`, R extends AnyRoute> = R extends R ? PrefixRoutesPathInner<R, Prefix> : never;
153
153
  type RouterState<ContextFrom, ContextTo, RequiredParams extends Record<string, unknown>, Routes extends AnyRoute> = {
154
154
  routes: Set<Routes>;
package/dist/index.js CHANGED
@@ -148,7 +148,10 @@ var Router = class _Router {
148
148
  merge = (pathPrefix, other) => {
149
149
  const newRoutes = [...other.state.routes].map((route) => ({
150
150
  ...route,
151
- path: `${pathPrefix}${route.path}`
151
+ // handle pathPrefix = / & route.path = / case causing //
152
+ // we intentionally are replacing on the joining path and not the pathPrefix, in case of
153
+ // /named -> merged to -> / causing /named/ not /named
154
+ path: `${pathPrefix}${route.path === "/" ? "" : route.path}`
152
155
  }));
153
156
  return new _Router({
154
157
  ...this.state,
@@ -336,7 +339,7 @@ var Router = class _Router {
336
339
  const item = {
337
340
  description: route.openapi?.description ?? "Successful response",
338
341
  responses: {
339
- default: {
342
+ 200: {
340
343
  description: route.openapi?.description ?? "Successful response",
341
344
  content
342
345
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaito-http/core",
3
- "version": "4.0.0-beta.7",
3
+ "version": "4.0.0-beta.9",
4
4
  "author": "Alistair Smith <hi@alistair.sh>",
5
5
  "repository": "https://github.com/kaito-http/kaito",
6
6
  "devDependencies": {