@aura-stack/router 0.3.0 → 0.4.0
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 +2 -2
- package/dist/{chunk-FWDOXDWG.js → chunk-CFAIW6YL.js} +8 -8
- package/dist/{chunk-JIA6NLL6.js → chunk-CL5D7UJU.js} +21 -15
- package/dist/context.d.ts +3 -3
- package/dist/index.cjs +53 -47
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/middlewares.cjs +8 -8
- package/dist/middlewares.d.ts +3 -3
- package/dist/middlewares.js +1 -1
- package/dist/router.cjs +53 -47
- package/dist/router.js +2 -2
- package/dist/types.d.ts +26 -5
- package/package.json +26 -13
- package/dist/assert.d.cts +0 -52
- package/dist/context.d.cts +0 -85
- package/dist/endpoint.d.cts +0 -60
- package/dist/error.d.cts +0 -65
- package/dist/index.d.cts +0 -6
- package/dist/middlewares.d.cts +0 -23
- package/dist/router.d.cts +0 -37
- package/dist/types.d.cts +0 -191
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# `@aura-stack/router`
|
|
2
|
-
|
|
3
1
|
<div align="center">
|
|
4
2
|
|
|
3
|
+
<h1>Aura Router</h1>
|
|
4
|
+
|
|
5
5
|
**A modern, TypeScript-first router and endpoint definition library**
|
|
6
6
|
|
|
7
7
|
Build fully-typed APIs with declarative endpoints, automatic parameter inference, and first-class middleware support — all returning native `Response` objects.
|
|
@@ -3,31 +3,31 @@ import {
|
|
|
3
3
|
} from "./chunk-GJC3ODME.js";
|
|
4
4
|
|
|
5
5
|
// src/middlewares.ts
|
|
6
|
-
var executeGlobalMiddlewares = async (
|
|
7
|
-
if (!middlewares) return
|
|
6
|
+
var executeGlobalMiddlewares = async (context, middlewares) => {
|
|
7
|
+
if (!middlewares) return context;
|
|
8
8
|
for (const middleware of middlewares) {
|
|
9
9
|
if (typeof middleware !== "function") {
|
|
10
10
|
throw new RouterError("BAD_REQUEST", "Global middlewares must be functions");
|
|
11
11
|
}
|
|
12
|
-
const executed = await middleware(
|
|
12
|
+
const executed = await middleware(context);
|
|
13
13
|
if (executed instanceof Response) {
|
|
14
14
|
return executed;
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
context = executed;
|
|
17
17
|
}
|
|
18
|
-
if (!
|
|
18
|
+
if (!context || !(context.request instanceof Request)) {
|
|
19
19
|
throw new RouterError("BAD_REQUEST", "Global middleware must return a Request or Response object");
|
|
20
20
|
}
|
|
21
|
-
return
|
|
21
|
+
return context;
|
|
22
22
|
};
|
|
23
|
-
var executeMiddlewares = async (
|
|
23
|
+
var executeMiddlewares = async (context, middlewares = []) => {
|
|
24
24
|
try {
|
|
25
25
|
let ctx = context;
|
|
26
26
|
for (const middleware of middlewares) {
|
|
27
27
|
if (typeof middleware !== "function") {
|
|
28
28
|
throw new RouterError("BAD_REQUEST", "Middleware must be a function");
|
|
29
29
|
}
|
|
30
|
-
ctx = await middleware(
|
|
30
|
+
ctx = await middleware(ctx);
|
|
31
31
|
}
|
|
32
32
|
return ctx;
|
|
33
33
|
} catch {
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
executeGlobalMiddlewares,
|
|
13
13
|
executeMiddlewares
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-CFAIW6YL.js";
|
|
15
15
|
import {
|
|
16
16
|
RouterError,
|
|
17
17
|
statusText
|
|
@@ -92,29 +92,35 @@ var handleRequest = async (method, request, config, root) => {
|
|
|
92
92
|
if (!isSupportedMethod(request.method)) {
|
|
93
93
|
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${request.method}' is not supported`);
|
|
94
94
|
}
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
const globalContext = { request, context: config.context ?? {} };
|
|
96
|
+
const globalRequestContext = await executeGlobalMiddlewares(globalContext, config.middlewares);
|
|
97
|
+
if (globalRequestContext instanceof Response) return globalRequestContext;
|
|
98
|
+
const url = new URL(globalRequestContext.request.url);
|
|
98
99
|
const pathnameWithBase = url.pathname;
|
|
99
|
-
if (
|
|
100
|
-
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${
|
|
100
|
+
if (globalRequestContext.request.method !== method) {
|
|
101
|
+
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${globalRequestContext.request.method}' is not allowed`);
|
|
101
102
|
}
|
|
102
103
|
const { endpoint, params } = search(method, root, pathnameWithBase);
|
|
103
|
-
if (endpoint.method !==
|
|
104
|
-
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${
|
|
104
|
+
if (endpoint.method !== globalRequestContext.request.method) {
|
|
105
|
+
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${globalRequestContext.request.method}' is not allowed`);
|
|
105
106
|
}
|
|
106
107
|
const dynamicParams = getRouteParams(params, endpoint.config);
|
|
107
|
-
const body = await getBody(
|
|
108
|
-
const searchParams = getSearchParams(
|
|
109
|
-
const headers = getHeaders(
|
|
110
|
-
|
|
108
|
+
const body = await getBody(globalRequestContext.request, endpoint.config);
|
|
109
|
+
const searchParams = getSearchParams(globalRequestContext.request.url, endpoint.config);
|
|
110
|
+
const headers = getHeaders(globalRequestContext.request);
|
|
111
|
+
let context = {
|
|
111
112
|
params: dynamicParams,
|
|
112
113
|
searchParams,
|
|
113
114
|
headers,
|
|
114
|
-
body
|
|
115
|
+
body,
|
|
116
|
+
request: globalRequestContext.request,
|
|
117
|
+
url,
|
|
118
|
+
method: globalRequestContext.request.method,
|
|
119
|
+
route: endpoint.route,
|
|
120
|
+
context: config.context ?? {}
|
|
115
121
|
};
|
|
116
|
-
await executeMiddlewares(
|
|
117
|
-
const response = await endpoint.handler(
|
|
122
|
+
context = await executeMiddlewares(context, endpoint.config.middlewares);
|
|
123
|
+
const response = await endpoint.handler(context);
|
|
118
124
|
return response;
|
|
119
125
|
} catch (error) {
|
|
120
126
|
return handleError(error, request, config);
|
package/dist/context.d.ts
CHANGED
|
@@ -9,9 +9,9 @@ import './error.js';
|
|
|
9
9
|
* (e.g., "/users/:userId/posts/:postId") and returns an object mapping parameter
|
|
10
10
|
* names to their decoded values.
|
|
11
11
|
*
|
|
12
|
-
* @param
|
|
13
|
-
* @param
|
|
14
|
-
* @returns An object containing the extracted route parameters
|
|
12
|
+
* @param params - The extracted route parameters as key-value pairs.
|
|
13
|
+
* @param config - The endpoint configuration which may include schemas for validation.
|
|
14
|
+
* @returns An object containing the extracted and validated route parameters.
|
|
15
15
|
*
|
|
16
16
|
* @example
|
|
17
17
|
* const route = "/users/:userId/posts/:postId";
|
package/dist/index.cjs
CHANGED
|
@@ -116,6 +116,39 @@ function createEndpointConfig(...args) {
|
|
|
116
116
|
return args[0];
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
// src/middlewares.ts
|
|
120
|
+
var executeGlobalMiddlewares = async (context, middlewares) => {
|
|
121
|
+
if (!middlewares) return context;
|
|
122
|
+
for (const middleware of middlewares) {
|
|
123
|
+
if (typeof middleware !== "function") {
|
|
124
|
+
throw new RouterError("BAD_REQUEST", "Global middlewares must be functions");
|
|
125
|
+
}
|
|
126
|
+
const executed = await middleware(context);
|
|
127
|
+
if (executed instanceof Response) {
|
|
128
|
+
return executed;
|
|
129
|
+
}
|
|
130
|
+
context = executed;
|
|
131
|
+
}
|
|
132
|
+
if (!context || !(context.request instanceof Request)) {
|
|
133
|
+
throw new RouterError("BAD_REQUEST", "Global middleware must return a Request or Response object");
|
|
134
|
+
}
|
|
135
|
+
return context;
|
|
136
|
+
};
|
|
137
|
+
var executeMiddlewares = async (context, middlewares = []) => {
|
|
138
|
+
try {
|
|
139
|
+
let ctx = context;
|
|
140
|
+
for (const middleware of middlewares) {
|
|
141
|
+
if (typeof middleware !== "function") {
|
|
142
|
+
throw new RouterError("BAD_REQUEST", "Middleware must be a function");
|
|
143
|
+
}
|
|
144
|
+
ctx = await middleware(ctx);
|
|
145
|
+
}
|
|
146
|
+
return ctx;
|
|
147
|
+
} catch {
|
|
148
|
+
throw new RouterError("BAD_REQUEST", "Handler threw an error");
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
119
152
|
// src/context.ts
|
|
120
153
|
var getRouteParams = (params, config) => {
|
|
121
154
|
if (config.schemas?.params) {
|
|
@@ -181,39 +214,6 @@ var createContentTypeRegex = (contentTypes, contenType) => {
|
|
|
181
214
|
return regex.test(contenType);
|
|
182
215
|
};
|
|
183
216
|
|
|
184
|
-
// src/middlewares.ts
|
|
185
|
-
var executeGlobalMiddlewares = async (request, middlewares) => {
|
|
186
|
-
if (!middlewares) return request;
|
|
187
|
-
for (const middleware of middlewares) {
|
|
188
|
-
if (typeof middleware !== "function") {
|
|
189
|
-
throw new RouterError("BAD_REQUEST", "Global middlewares must be functions");
|
|
190
|
-
}
|
|
191
|
-
const executed = await middleware(request);
|
|
192
|
-
if (executed instanceof Response) {
|
|
193
|
-
return executed;
|
|
194
|
-
}
|
|
195
|
-
request = executed;
|
|
196
|
-
}
|
|
197
|
-
if (!request || !(request instanceof Request)) {
|
|
198
|
-
throw new RouterError("BAD_REQUEST", "Global middleware must return a Request or Response object");
|
|
199
|
-
}
|
|
200
|
-
return request;
|
|
201
|
-
};
|
|
202
|
-
var executeMiddlewares = async (request, context, middlewares = []) => {
|
|
203
|
-
try {
|
|
204
|
-
let ctx = context;
|
|
205
|
-
for (const middleware of middlewares) {
|
|
206
|
-
if (typeof middleware !== "function") {
|
|
207
|
-
throw new RouterError("BAD_REQUEST", "Middleware must be a function");
|
|
208
|
-
}
|
|
209
|
-
ctx = await middleware(request, ctx);
|
|
210
|
-
}
|
|
211
|
-
return ctx;
|
|
212
|
-
} catch {
|
|
213
|
-
throw new RouterError("BAD_REQUEST", "Handler threw an error");
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
|
|
217
217
|
// src/router.ts
|
|
218
218
|
var createNode = () => ({
|
|
219
219
|
statics: /* @__PURE__ */ new Map(),
|
|
@@ -289,29 +289,35 @@ var handleRequest = async (method, request, config, root) => {
|
|
|
289
289
|
if (!isSupportedMethod(request.method)) {
|
|
290
290
|
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${request.method}' is not supported`);
|
|
291
291
|
}
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
292
|
+
const globalContext = { request, context: config.context ?? {} };
|
|
293
|
+
const globalRequestContext = await executeGlobalMiddlewares(globalContext, config.middlewares);
|
|
294
|
+
if (globalRequestContext instanceof Response) return globalRequestContext;
|
|
295
|
+
const url = new URL(globalRequestContext.request.url);
|
|
295
296
|
const pathnameWithBase = url.pathname;
|
|
296
|
-
if (
|
|
297
|
-
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${
|
|
297
|
+
if (globalRequestContext.request.method !== method) {
|
|
298
|
+
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${globalRequestContext.request.method}' is not allowed`);
|
|
298
299
|
}
|
|
299
300
|
const { endpoint, params } = search(method, root, pathnameWithBase);
|
|
300
|
-
if (endpoint.method !==
|
|
301
|
-
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${
|
|
301
|
+
if (endpoint.method !== globalRequestContext.request.method) {
|
|
302
|
+
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${globalRequestContext.request.method}' is not allowed`);
|
|
302
303
|
}
|
|
303
304
|
const dynamicParams = getRouteParams(params, endpoint.config);
|
|
304
|
-
const body = await getBody(
|
|
305
|
-
const searchParams = getSearchParams(
|
|
306
|
-
const headers = getHeaders(
|
|
307
|
-
|
|
305
|
+
const body = await getBody(globalRequestContext.request, endpoint.config);
|
|
306
|
+
const searchParams = getSearchParams(globalRequestContext.request.url, endpoint.config);
|
|
307
|
+
const headers = getHeaders(globalRequestContext.request);
|
|
308
|
+
let context = {
|
|
308
309
|
params: dynamicParams,
|
|
309
310
|
searchParams,
|
|
310
311
|
headers,
|
|
311
|
-
body
|
|
312
|
+
body,
|
|
313
|
+
request: globalRequestContext.request,
|
|
314
|
+
url,
|
|
315
|
+
method: globalRequestContext.request.method,
|
|
316
|
+
route: endpoint.route,
|
|
317
|
+
context: config.context ?? {}
|
|
312
318
|
};
|
|
313
|
-
await executeMiddlewares(
|
|
314
|
-
const response = await endpoint.handler(
|
|
319
|
+
context = await executeMiddlewares(context, endpoint.config.middlewares);
|
|
320
|
+
const response = await endpoint.handler(context);
|
|
315
321
|
return response;
|
|
316
322
|
} catch (error) {
|
|
317
323
|
return handleError(error, request, config);
|
package/dist/index.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ export { createEndpoint, createEndpointConfig } from './endpoint.js';
|
|
|
2
2
|
export { createRouter } from './router.js';
|
|
3
3
|
export { isRouterError } from './assert.js';
|
|
4
4
|
export { RouterError, statusCode, statusText } from './error.js';
|
|
5
|
-
export { ContentType, ContextBody, ContextParams, ContextSearchParams, EndpointConfig, EndpointSchemas, GetHttpHandlers, GetRouteParams, GlobalMiddleware, HTTPMethod, InferMethod, MiddlewareFunction, Prettify, RequestContext, RouteEndpoint, RouteHandler, RoutePattern, RouterConfig } from './types.js';
|
|
5
|
+
export { ContentType, ContextBody, ContextParams, ContextSearchParams, EndpointConfig, EndpointSchemas, GetHttpHandlers, GetRouteParams, GlobalContext, GlobalCtx, GlobalMiddleware, GlobalMiddlewareContext, HTTPMethod, InferMethod, MiddlewareFunction, Prettify, RequestContext, RouteEndpoint, RouteHandler, RoutePattern, RouterConfig } from './types.js';
|
|
6
6
|
import 'zod';
|
package/dist/index.js
CHANGED
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
} from "./chunk-6PZEXNTS.js";
|
|
5
5
|
import {
|
|
6
6
|
createRouter
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-CL5D7UJU.js";
|
|
8
8
|
import "./chunk-PT4GU6PH.js";
|
|
9
9
|
import {
|
|
10
10
|
isRouterError
|
|
11
11
|
} from "./chunk-JNMXLKDG.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-CFAIW6YL.js";
|
|
13
13
|
import {
|
|
14
14
|
RouterError,
|
|
15
15
|
statusCode,
|
package/dist/middlewares.cjs
CHANGED
|
@@ -74,31 +74,31 @@ var RouterError = class extends AuraStackRouterError {
|
|
|
74
74
|
};
|
|
75
75
|
|
|
76
76
|
// src/middlewares.ts
|
|
77
|
-
var executeGlobalMiddlewares = async (
|
|
78
|
-
if (!middlewares) return
|
|
77
|
+
var executeGlobalMiddlewares = async (context, middlewares) => {
|
|
78
|
+
if (!middlewares) return context;
|
|
79
79
|
for (const middleware of middlewares) {
|
|
80
80
|
if (typeof middleware !== "function") {
|
|
81
81
|
throw new RouterError("BAD_REQUEST", "Global middlewares must be functions");
|
|
82
82
|
}
|
|
83
|
-
const executed = await middleware(
|
|
83
|
+
const executed = await middleware(context);
|
|
84
84
|
if (executed instanceof Response) {
|
|
85
85
|
return executed;
|
|
86
86
|
}
|
|
87
|
-
|
|
87
|
+
context = executed;
|
|
88
88
|
}
|
|
89
|
-
if (!
|
|
89
|
+
if (!context || !(context.request instanceof Request)) {
|
|
90
90
|
throw new RouterError("BAD_REQUEST", "Global middleware must return a Request or Response object");
|
|
91
91
|
}
|
|
92
|
-
return
|
|
92
|
+
return context;
|
|
93
93
|
};
|
|
94
|
-
var executeMiddlewares = async (
|
|
94
|
+
var executeMiddlewares = async (context, middlewares = []) => {
|
|
95
95
|
try {
|
|
96
96
|
let ctx = context;
|
|
97
97
|
for (const middleware of middlewares) {
|
|
98
98
|
if (typeof middleware !== "function") {
|
|
99
99
|
throw new RouterError("BAD_REQUEST", "Middleware must be a function");
|
|
100
100
|
}
|
|
101
|
-
ctx = await middleware(
|
|
101
|
+
ctx = await middleware(ctx);
|
|
102
102
|
}
|
|
103
103
|
return ctx;
|
|
104
104
|
} catch {
|
package/dist/middlewares.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RouterConfig, EndpointConfig, RequestContext, MiddlewareFunction } from './types.js';
|
|
1
|
+
import { GlobalMiddlewareContext, RouterConfig, EndpointConfig, RequestContext, MiddlewareFunction } from './types.js';
|
|
2
2
|
import 'zod';
|
|
3
3
|
import './error.js';
|
|
4
4
|
|
|
@@ -9,7 +9,7 @@ import './error.js';
|
|
|
9
9
|
* @param middlewares - Array of global middleware functions to be executed
|
|
10
10
|
* @returns - The modified request after all middlewares have been executed
|
|
11
11
|
*/
|
|
12
|
-
declare const executeGlobalMiddlewares: (
|
|
12
|
+
declare const executeGlobalMiddlewares: (context: GlobalMiddlewareContext, middlewares: RouterConfig["middlewares"]) => Promise<GlobalMiddlewareContext | Response>;
|
|
13
13
|
/**
|
|
14
14
|
* Executes middlewares in sequence, passing the request and context to each middleware.
|
|
15
15
|
*
|
|
@@ -18,6 +18,6 @@ declare const executeGlobalMiddlewares: (request: Request, middlewares: RouterCo
|
|
|
18
18
|
* @param middlewares - Array of middleware functions to be executed
|
|
19
19
|
* @returns The modified context after all middlewares have been executed
|
|
20
20
|
*/
|
|
21
|
-
declare const executeMiddlewares: <const RouteParams extends Record<string, string>, const Config extends EndpointConfig>(
|
|
21
|
+
declare const executeMiddlewares: <const RouteParams extends Record<string, string>, const Config extends EndpointConfig>(context: RequestContext<RouteParams, Config>, middlewares?: MiddlewareFunction<RouteParams, Config>[]) => Promise<RequestContext<RouteParams, Config>>;
|
|
22
22
|
|
|
23
23
|
export { executeGlobalMiddlewares, executeMiddlewares };
|
package/dist/middlewares.js
CHANGED
package/dist/router.cjs
CHANGED
|
@@ -88,6 +88,39 @@ var isRouterError = (error) => {
|
|
|
88
88
|
return error instanceof RouterError;
|
|
89
89
|
};
|
|
90
90
|
|
|
91
|
+
// src/middlewares.ts
|
|
92
|
+
var executeGlobalMiddlewares = async (context, middlewares) => {
|
|
93
|
+
if (!middlewares) return context;
|
|
94
|
+
for (const middleware of middlewares) {
|
|
95
|
+
if (typeof middleware !== "function") {
|
|
96
|
+
throw new RouterError("BAD_REQUEST", "Global middlewares must be functions");
|
|
97
|
+
}
|
|
98
|
+
const executed = await middleware(context);
|
|
99
|
+
if (executed instanceof Response) {
|
|
100
|
+
return executed;
|
|
101
|
+
}
|
|
102
|
+
context = executed;
|
|
103
|
+
}
|
|
104
|
+
if (!context || !(context.request instanceof Request)) {
|
|
105
|
+
throw new RouterError("BAD_REQUEST", "Global middleware must return a Request or Response object");
|
|
106
|
+
}
|
|
107
|
+
return context;
|
|
108
|
+
};
|
|
109
|
+
var executeMiddlewares = async (context, middlewares = []) => {
|
|
110
|
+
try {
|
|
111
|
+
let ctx = context;
|
|
112
|
+
for (const middleware of middlewares) {
|
|
113
|
+
if (typeof middleware !== "function") {
|
|
114
|
+
throw new RouterError("BAD_REQUEST", "Middleware must be a function");
|
|
115
|
+
}
|
|
116
|
+
ctx = await middleware(ctx);
|
|
117
|
+
}
|
|
118
|
+
return ctx;
|
|
119
|
+
} catch {
|
|
120
|
+
throw new RouterError("BAD_REQUEST", "Handler threw an error");
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
91
124
|
// src/context.ts
|
|
92
125
|
var getRouteParams = (params, config) => {
|
|
93
126
|
if (config.schemas?.params) {
|
|
@@ -153,39 +186,6 @@ var createContentTypeRegex = (contentTypes, contenType) => {
|
|
|
153
186
|
return regex.test(contenType);
|
|
154
187
|
};
|
|
155
188
|
|
|
156
|
-
// src/middlewares.ts
|
|
157
|
-
var executeGlobalMiddlewares = async (request, middlewares) => {
|
|
158
|
-
if (!middlewares) return request;
|
|
159
|
-
for (const middleware of middlewares) {
|
|
160
|
-
if (typeof middleware !== "function") {
|
|
161
|
-
throw new RouterError("BAD_REQUEST", "Global middlewares must be functions");
|
|
162
|
-
}
|
|
163
|
-
const executed = await middleware(request);
|
|
164
|
-
if (executed instanceof Response) {
|
|
165
|
-
return executed;
|
|
166
|
-
}
|
|
167
|
-
request = executed;
|
|
168
|
-
}
|
|
169
|
-
if (!request || !(request instanceof Request)) {
|
|
170
|
-
throw new RouterError("BAD_REQUEST", "Global middleware must return a Request or Response object");
|
|
171
|
-
}
|
|
172
|
-
return request;
|
|
173
|
-
};
|
|
174
|
-
var executeMiddlewares = async (request, context, middlewares = []) => {
|
|
175
|
-
try {
|
|
176
|
-
let ctx = context;
|
|
177
|
-
for (const middleware of middlewares) {
|
|
178
|
-
if (typeof middleware !== "function") {
|
|
179
|
-
throw new RouterError("BAD_REQUEST", "Middleware must be a function");
|
|
180
|
-
}
|
|
181
|
-
ctx = await middleware(request, ctx);
|
|
182
|
-
}
|
|
183
|
-
return ctx;
|
|
184
|
-
} catch {
|
|
185
|
-
throw new RouterError("BAD_REQUEST", "Handler threw an error");
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
|
|
189
189
|
// src/router.ts
|
|
190
190
|
var createNode = () => ({
|
|
191
191
|
statics: /* @__PURE__ */ new Map(),
|
|
@@ -261,29 +261,35 @@ var handleRequest = async (method, request, config, root) => {
|
|
|
261
261
|
if (!isSupportedMethod(request.method)) {
|
|
262
262
|
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${request.method}' is not supported`);
|
|
263
263
|
}
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
264
|
+
const globalContext = { request, context: config.context ?? {} };
|
|
265
|
+
const globalRequestContext = await executeGlobalMiddlewares(globalContext, config.middlewares);
|
|
266
|
+
if (globalRequestContext instanceof Response) return globalRequestContext;
|
|
267
|
+
const url = new URL(globalRequestContext.request.url);
|
|
267
268
|
const pathnameWithBase = url.pathname;
|
|
268
|
-
if (
|
|
269
|
-
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${
|
|
269
|
+
if (globalRequestContext.request.method !== method) {
|
|
270
|
+
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${globalRequestContext.request.method}' is not allowed`);
|
|
270
271
|
}
|
|
271
272
|
const { endpoint, params } = search(method, root, pathnameWithBase);
|
|
272
|
-
if (endpoint.method !==
|
|
273
|
-
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${
|
|
273
|
+
if (endpoint.method !== globalRequestContext.request.method) {
|
|
274
|
+
throw new RouterError("METHOD_NOT_ALLOWED", `The HTTP method '${globalRequestContext.request.method}' is not allowed`);
|
|
274
275
|
}
|
|
275
276
|
const dynamicParams = getRouteParams(params, endpoint.config);
|
|
276
|
-
const body = await getBody(
|
|
277
|
-
const searchParams = getSearchParams(
|
|
278
|
-
const headers = getHeaders(
|
|
279
|
-
|
|
277
|
+
const body = await getBody(globalRequestContext.request, endpoint.config);
|
|
278
|
+
const searchParams = getSearchParams(globalRequestContext.request.url, endpoint.config);
|
|
279
|
+
const headers = getHeaders(globalRequestContext.request);
|
|
280
|
+
let context = {
|
|
280
281
|
params: dynamicParams,
|
|
281
282
|
searchParams,
|
|
282
283
|
headers,
|
|
283
|
-
body
|
|
284
|
+
body,
|
|
285
|
+
request: globalRequestContext.request,
|
|
286
|
+
url,
|
|
287
|
+
method: globalRequestContext.request.method,
|
|
288
|
+
route: endpoint.route,
|
|
289
|
+
context: config.context ?? {}
|
|
284
290
|
};
|
|
285
|
-
await executeMiddlewares(
|
|
286
|
-
const response = await endpoint.handler(
|
|
291
|
+
context = await executeMiddlewares(context, endpoint.config.middlewares);
|
|
292
|
+
const response = await endpoint.handler(context);
|
|
287
293
|
return response;
|
|
288
294
|
} catch (error) {
|
|
289
295
|
return handleError(error, request, config);
|
package/dist/router.js
CHANGED
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
createRouter,
|
|
4
4
|
insert,
|
|
5
5
|
search
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CL5D7UJU.js";
|
|
7
7
|
import "./chunk-PT4GU6PH.js";
|
|
8
8
|
import "./chunk-JNMXLKDG.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-CFAIW6YL.js";
|
|
10
10
|
import "./chunk-GJC3ODME.js";
|
|
11
11
|
export {
|
|
12
12
|
createNode,
|
package/dist/types.d.ts
CHANGED
|
@@ -50,6 +50,13 @@ interface EndpointSchemas {
|
|
|
50
50
|
searchParams?: ZodObject<any>;
|
|
51
51
|
params?: ZodObject<any>;
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Global context type that can be extended when creating the router. It allows passing
|
|
55
|
+
* additional data to all route handlers and middlewares. For a type-inference use module
|
|
56
|
+
* augmentation to extend the GlobalContext interface.
|
|
57
|
+
*/
|
|
58
|
+
interface GlobalContext {
|
|
59
|
+
}
|
|
53
60
|
/**
|
|
54
61
|
* Configuration for an endpoint, including optional schemas for request validation and middlewares.
|
|
55
62
|
*/
|
|
@@ -98,22 +105,31 @@ interface RequestContext<RouteParams = Record<string, string>, Config extends En
|
|
|
98
105
|
headers: Headers;
|
|
99
106
|
body: ContextBody<Config["schemas"]>["body"];
|
|
100
107
|
searchParams: ContextSearchParams<Config["schemas"]>["searchParams"];
|
|
108
|
+
request: Request;
|
|
109
|
+
url: URL;
|
|
110
|
+
method: HTTPMethod;
|
|
111
|
+
route: RoutePattern;
|
|
112
|
+
context: GlobalContext;
|
|
113
|
+
}
|
|
114
|
+
interface GlobalMiddlewareContext {
|
|
115
|
+
request: Request;
|
|
116
|
+
context: GlobalContext;
|
|
101
117
|
}
|
|
102
118
|
/**
|
|
103
119
|
* Global middleware function type that represent a function that runs before the route matching.
|
|
104
120
|
*/
|
|
105
|
-
type GlobalMiddleware = (
|
|
121
|
+
type GlobalMiddleware = (ctx: GlobalMiddlewareContext) => Response | GlobalMiddlewareContext | Promise<Response | GlobalMiddlewareContext>;
|
|
106
122
|
/**
|
|
107
123
|
* Middleware function type that represent a function that runs before the route handler
|
|
108
124
|
* defined in the `createEndpoint/createEndpointConfig` function or globally in the `createRouter` function.
|
|
109
125
|
*/
|
|
110
|
-
type MiddlewareFunction<RouteParams = Record<string, string>, Config extends EndpointConfig = EndpointConfig> = (
|
|
126
|
+
type MiddlewareFunction<RouteParams = Record<string, string>, Config extends EndpointConfig = EndpointConfig> = (ctx: Prettify<RequestContext<RouteParams, Config>>) => Response | RequestContext<RouteParams, Config> | Promise<Response | RequestContext<RouteParams, Config>>;
|
|
111
127
|
/**
|
|
112
128
|
* Defines a route handler function that processes an incoming request and returns a response.
|
|
113
129
|
* The handler receives the request object and a context containing route parameters, headers,
|
|
114
130
|
* and optionally validated body and search parameters based on the endpoint configuration.
|
|
115
131
|
*/
|
|
116
|
-
type RouteHandler<Route extends RoutePattern, Config extends EndpointConfig> = (
|
|
132
|
+
type RouteHandler<Route extends RoutePattern, Config extends EndpointConfig> = (ctx: Prettify<RequestContext<GetRouteParams<Route>, Config>>) => Response | Promise<Response>;
|
|
117
133
|
/**
|
|
118
134
|
* Represents a route endpoint definition, specifying the HTTP method, route pattern,
|
|
119
135
|
* handler function with inferred context types, and associated configuration.
|
|
@@ -135,10 +151,15 @@ type InferMethod<Endpoints extends RouteEndpoint[]> = Endpoints extends unknown[
|
|
|
135
151
|
type GetHttpHandlers<Endpoints extends RouteEndpoint[]> = {
|
|
136
152
|
[Method in InferMethod<Endpoints>]: (req: Request) => Response | Promise<Response>;
|
|
137
153
|
};
|
|
154
|
+
type GlobalCtx = keyof GlobalContext extends never ? {
|
|
155
|
+
context?: GlobalContext;
|
|
156
|
+
} : {
|
|
157
|
+
context: GlobalContext;
|
|
158
|
+
};
|
|
138
159
|
/**
|
|
139
160
|
* Configuration options for `createRouter` function.
|
|
140
161
|
*/
|
|
141
|
-
interface RouterConfig {
|
|
162
|
+
interface RouterConfig extends GlobalCtx {
|
|
142
163
|
/**
|
|
143
164
|
* Prefix path for all routes/endpoints defined in the router.
|
|
144
165
|
*
|
|
@@ -188,4 +209,4 @@ interface RouterConfig {
|
|
|
188
209
|
onError?: (error: Error | RouterError, request: Request) => Response | Promise<Response>;
|
|
189
210
|
}
|
|
190
211
|
|
|
191
|
-
export type { ContentType, ContextBody, ContextParams, ContextSearchParams, EndpointConfig, EndpointSchemas, GetHttpHandlers, GetRouteParams, GlobalMiddleware, HTTPMethod, InferMethod, MiddlewareFunction, Prettify, RequestContext, RouteEndpoint, RouteHandler, RoutePattern, RouterConfig };
|
|
212
|
+
export type { ContentType, ContextBody, ContextParams, ContextSearchParams, EndpointConfig, EndpointSchemas, GetHttpHandlers, GetRouteParams, GlobalContext, GlobalCtx, GlobalMiddleware, GlobalMiddlewareContext, HTTPMethod, InferMethod, MiddlewareFunction, Prettify, RequestContext, RouteEndpoint, RouteHandler, RoutePattern, RouterConfig };
|
package/package.json
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aura-stack/router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A lightweight TypeScript library for building, managing, and validating API routes and endpoints in Node.js applications.",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/aura-stack-ts/router"
|
|
9
|
+
},
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public",
|
|
12
|
+
"registry": "https://registry.npmjs.org/@aura-stack/router"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"router",
|
|
16
|
+
"endpoints",
|
|
17
|
+
"api",
|
|
18
|
+
"aura",
|
|
19
|
+
"aura stack",
|
|
20
|
+
"typescript",
|
|
21
|
+
"nodejs"
|
|
22
|
+
],
|
|
23
|
+
"author": "Aura Stack <auraauthoss@gmail.com> | Hernan Alvarado <hernanvid123@gmail.com>",
|
|
24
|
+
"homepage": "https://github.com/aura-stack-ts/router",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/aura-stack-ts/router/issues"
|
|
27
|
+
},
|
|
28
|
+
"license": "MIT",
|
|
6
29
|
"files": [
|
|
7
30
|
"dist"
|
|
8
31
|
],
|
|
@@ -29,17 +52,6 @@
|
|
|
29
52
|
},
|
|
30
53
|
"./types": "./dist/types.d.ts"
|
|
31
54
|
},
|
|
32
|
-
"keywords": [
|
|
33
|
-
"router",
|
|
34
|
-
"endpoints",
|
|
35
|
-
"api",
|
|
36
|
-
"aura",
|
|
37
|
-
"aura stack",
|
|
38
|
-
"typescript",
|
|
39
|
-
"nodejs"
|
|
40
|
-
],
|
|
41
|
-
"author": "Aura Stack <auraauthoss@gmail.com> | Hernan Alvarado <hernanvid123@gmail.com>",
|
|
42
|
-
"license": "MIT",
|
|
43
55
|
"devDependencies": {
|
|
44
56
|
"prettier": "^3.6.2",
|
|
45
57
|
"tsup": "^8.5.0",
|
|
@@ -58,6 +70,7 @@
|
|
|
58
70
|
"test:bench": "vitest --run bench",
|
|
59
71
|
"type-check": "tsc --noEmit",
|
|
60
72
|
"clean": "rm -rf dist",
|
|
61
|
-
"clean:cts": "rm -rf dist/*.cts"
|
|
73
|
+
"clean:cts": "rm -rf dist/*.cts",
|
|
74
|
+
"prepublish": "pnpm clean:cts"
|
|
62
75
|
}
|
|
63
76
|
}
|
package/dist/assert.d.cts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { RouterError } from './error.cjs';
|
|
2
|
-
import { HTTPMethod, RoutePattern, RouteHandler } from './types.cjs';
|
|
3
|
-
import 'zod';
|
|
4
|
-
|
|
5
|
-
declare const supportedProtocols: Set<string>;
|
|
6
|
-
/**
|
|
7
|
-
* Checks if the provided method is a supported HTTP method.
|
|
8
|
-
*
|
|
9
|
-
* @param method - The HTTP method to check.
|
|
10
|
-
* @returns True if the method is supported, false otherwise.
|
|
11
|
-
*/
|
|
12
|
-
declare const isSupportedMethod: (method: string) => method is HTTPMethod;
|
|
13
|
-
/**
|
|
14
|
-
* Check if the provided method can includes a body as per HTTP specification.
|
|
15
|
-
* @param method - The HTTP method to check.
|
|
16
|
-
* @returns True if the method can include a body, false otherwise.
|
|
17
|
-
*/
|
|
18
|
-
declare const isSupportedBodyMethod: (method: string) => method is HTTPMethod;
|
|
19
|
-
/**
|
|
20
|
-
* Checks if the provided route is a valid route pattern.
|
|
21
|
-
*
|
|
22
|
-
* @param route - The route pattern to check.
|
|
23
|
-
* @returns True if the route is valid, false otherwise.
|
|
24
|
-
*/
|
|
25
|
-
declare const isValidRoute: (route: string) => route is RoutePattern;
|
|
26
|
-
/**
|
|
27
|
-
* Checks if the provided handler is a valid route handler function.
|
|
28
|
-
*
|
|
29
|
-
* @param handler - The handler to check.
|
|
30
|
-
* @returns True if the handler is valid, false otherwise.
|
|
31
|
-
*/
|
|
32
|
-
declare const isValidHandler: (handler: unknown) => handler is RouteHandler<any, any>;
|
|
33
|
-
/**
|
|
34
|
-
* Asserts that the error is an instance of RouterError. It is useful if you want
|
|
35
|
-
* to check if the error thrown by the router is an RouterError or by other sources.
|
|
36
|
-
*
|
|
37
|
-
* @param error - The error to check
|
|
38
|
-
* @returns True if the error is an instance of RouterError, false otherwise.
|
|
39
|
-
* @example
|
|
40
|
-
* import { isRouterError } from "aura-stack/router";
|
|
41
|
-
*
|
|
42
|
-
* try {
|
|
43
|
-
* // Some router operation that may throw an error
|
|
44
|
-
* } catch (error) {
|
|
45
|
-
* if (isRouterError(error)) {
|
|
46
|
-
* // Handle RouterError
|
|
47
|
-
* }
|
|
48
|
-
* }
|
|
49
|
-
*/
|
|
50
|
-
declare const isRouterError: (error: unknown) => error is RouterError;
|
|
51
|
-
|
|
52
|
-
export { isRouterError, isSupportedBodyMethod, isSupportedMethod, isValidHandler, isValidRoute, supportedProtocols };
|
package/dist/context.d.cts
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { EndpointConfig, ContextSearchParams } from './types.cjs';
|
|
2
|
-
import 'zod';
|
|
3
|
-
import './error.cjs';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Extracts route parameters from a given path using the specified route pattern.
|
|
7
|
-
*
|
|
8
|
-
* This function matches the provided path against the route pattern
|
|
9
|
-
* (e.g., "/users/:userId/posts/:postId") and returns an object mapping parameter
|
|
10
|
-
* names to their decoded values.
|
|
11
|
-
*
|
|
12
|
-
* @param route - The route pattern, typically defined in the endpoint configuration.
|
|
13
|
-
* @param path - The actual request path to extract parameters from.
|
|
14
|
-
* @returns An object containing the extracted route parameters as key-value pairs.
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* const route = "/users/:userId/posts/:postId";
|
|
18
|
-
* const path = "/users/123/posts/456";
|
|
19
|
-
*
|
|
20
|
-
* // Expected: { userId: "123", postId: "456" }
|
|
21
|
-
* const params = getRouteParams(route, path);
|
|
22
|
-
*/
|
|
23
|
-
declare const getRouteParams: (params: Record<string, string>, config: EndpointConfig) => Record<string, unknown>;
|
|
24
|
-
/**
|
|
25
|
-
* Extracts and validates search parameters from a given URL from the request.
|
|
26
|
-
*
|
|
27
|
-
* If a schema is provided in the endpoint configuration, the search parameters
|
|
28
|
-
* are validated against it using Zod and returned the parsed data. If validation
|
|
29
|
-
* fails, an error is thrown. Otherwise, a URLSearchParams object is returned.
|
|
30
|
-
*
|
|
31
|
-
* @param url - The actual request URL to extract search parameters from.
|
|
32
|
-
* @param config - Configuration object that may include a schema for validation.
|
|
33
|
-
* @returns Either a URLSearchParams object or a parsed object based on the provided schema.
|
|
34
|
-
* @example
|
|
35
|
-
* // With schema
|
|
36
|
-
* const url = "https://example.com/api?search=test&page=2";
|
|
37
|
-
* const config: EndpointConfig = {
|
|
38
|
-
* schemas: {
|
|
39
|
-
* searchParams: z.object({
|
|
40
|
-
* search: z.string(),
|
|
41
|
-
* page: z.number().optional(),
|
|
42
|
-
* }),
|
|
43
|
-
* },
|
|
44
|
-
* }
|
|
45
|
-
*
|
|
46
|
-
* // Expected: { search: "test", page: 2 }
|
|
47
|
-
* const searchParams = getSearchParams(url, config);
|
|
48
|
-
*
|
|
49
|
-
* // Without schema
|
|
50
|
-
* const url2 = "https://example.com/api?query=example";
|
|
51
|
-
*
|
|
52
|
-
* // Expected: URLSearchParams { 'query' => 'example' }
|
|
53
|
-
* const searchParams2 = getSearchParams(url2, {} as EndpointConfig);
|
|
54
|
-
*/
|
|
55
|
-
declare const getSearchParams: <Config extends EndpointConfig>(url: string, config: Config) => ContextSearchParams<Config["schemas"]>["searchParams"];
|
|
56
|
-
/**
|
|
57
|
-
* Extracts headers from the given Request object and returns them as a Headers instance.
|
|
58
|
-
*
|
|
59
|
-
* @param request - The Request object from which to extract headers.
|
|
60
|
-
* @returns A Headers instance containing all headers from the request.
|
|
61
|
-
* @example
|
|
62
|
-
* const request = new Request("https://example.com/api", {
|
|
63
|
-
* headers: {
|
|
64
|
-
* "Content-Type": "application/json",
|
|
65
|
-
* "Authorization": "Bearer token",
|
|
66
|
-
* },
|
|
67
|
-
* });
|
|
68
|
-
* const headers = getHeaders(request);
|
|
69
|
-
*/
|
|
70
|
-
declare const getHeaders: (request: Request) => Headers;
|
|
71
|
-
/**
|
|
72
|
-
* Extracts and parses the body of a Request object based on its Content-Type header.
|
|
73
|
-
*
|
|
74
|
-
* If a schema is provided in the endpoint configuration, the body is validated against
|
|
75
|
-
* it using Zod and returned the parsed data. If validation fails, an error is thrown.
|
|
76
|
-
*
|
|
77
|
-
* In some cases, the browser includes text/plain;charset=UTF-8 as the default Content-Type
|
|
78
|
-
*
|
|
79
|
-
* @param request - The Request object from which to extract the body.
|
|
80
|
-
* @param config - Configuration object that may include a schema for validation.
|
|
81
|
-
* @returns The parsed body of the request or an error if validation fails.
|
|
82
|
-
*/
|
|
83
|
-
declare const getBody: <Config extends EndpointConfig>(request: Request, config: Config) => Promise<any>;
|
|
84
|
-
|
|
85
|
-
export { getBody, getHeaders, getRouteParams, getSearchParams };
|
package/dist/endpoint.d.cts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { HTTPMethod, RoutePattern, EndpointSchemas, RouteHandler, EndpointConfig, RouteEndpoint } from './types.cjs';
|
|
2
|
-
import 'zod';
|
|
3
|
-
import './error.cjs';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Defines an API endpoint for the router by specifying the HTTP method, route pattern,
|
|
7
|
-
* handler function, and optional configuration such as validation schemas or middlewares.
|
|
8
|
-
* Validates all parameters for correctness. The resulting endpoint should be passed
|
|
9
|
-
* to the `createRouter` function.
|
|
10
|
-
*
|
|
11
|
-
* @param method - The HTTP method (e.g., GET, POST, PUT, DELETE, PATCH)
|
|
12
|
-
* @param route - The route pattern to associate with the endpoint (supports dynamic params)
|
|
13
|
-
* @param handler - The function to handle requests matching the method and route
|
|
14
|
-
* @param config - Optional configuration including validation schemas, middlewares, etc.
|
|
15
|
-
* @returns An object representing the configured endpoint
|
|
16
|
-
* @example
|
|
17
|
-
* const signIn = createEndpoint("POST", "/auth/signin", async (req, ctx) => {
|
|
18
|
-
* return new Response("Signed in");
|
|
19
|
-
* });
|
|
20
|
-
*/
|
|
21
|
-
declare const createEndpoint: <const Method extends Uppercase<HTTPMethod>, const Route extends RoutePattern, const Schemas extends EndpointSchemas>(method: Method, route: Route, handler: RouteHandler<Route, {
|
|
22
|
-
schemas: Schemas;
|
|
23
|
-
}>, config?: EndpointConfig<Route, Schemas>) => RouteEndpoint<Method, Route, {}>;
|
|
24
|
-
/**
|
|
25
|
-
* Create an endpoint configuration to be passed to the `createEndpoint` function.
|
|
26
|
-
* This function is primarily for type inference and does not perform any runtime checks.
|
|
27
|
-
*
|
|
28
|
-
* This overload is recommended when the route pattern does not need to be specified explicitly,
|
|
29
|
-
* otherwise use the overload that accepts the route pattern as the first argument.
|
|
30
|
-
*
|
|
31
|
-
* @param config - The endpoint configuration object
|
|
32
|
-
* @returns The same configuration object, typed as EndpointConfig
|
|
33
|
-
* @example
|
|
34
|
-
* // Without route pattern
|
|
35
|
-
* const config = createEndpointConfig({
|
|
36
|
-
* middlewares: [myMiddleware],
|
|
37
|
-
* schemas: {
|
|
38
|
-
* searchParams: z.object({
|
|
39
|
-
* q: z.string().min(3),
|
|
40
|
-
* })
|
|
41
|
-
* }
|
|
42
|
-
* })
|
|
43
|
-
*
|
|
44
|
-
* const search = createEndpoint("GET", "/search", async (request, ctx) => {
|
|
45
|
-
* return new Response("Search results");
|
|
46
|
-
* }, config);
|
|
47
|
-
*
|
|
48
|
-
* // Overload with route pattern
|
|
49
|
-
* const config = createEndpointConfig("/users/:userId", {
|
|
50
|
-
* middlewares: [myMiddleware],
|
|
51
|
-
* })
|
|
52
|
-
*
|
|
53
|
-
* const getUser = createEndpoint("GET", "/users/:userId", async (request, ctx) => {
|
|
54
|
-
* return new Response("User details");
|
|
55
|
-
* }, config);
|
|
56
|
-
*/
|
|
57
|
-
declare function createEndpointConfig<Schemas extends EndpointSchemas>(config: EndpointConfig<RoutePattern, Schemas>): EndpointConfig<RoutePattern, Schemas>;
|
|
58
|
-
declare function createEndpointConfig<Route extends RoutePattern, Schemas extends EndpointSchemas>(route: Route, config: EndpointConfig<Route, Schemas>): EndpointConfig<Route, Schemas>;
|
|
59
|
-
|
|
60
|
-
export { createEndpoint, createEndpointConfig };
|
package/dist/error.d.cts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The HTTP status codes used in AuraStack Router.
|
|
3
|
-
*/
|
|
4
|
-
declare const statusCode: {
|
|
5
|
-
OK: number;
|
|
6
|
-
CREATED: number;
|
|
7
|
-
ACCEPTED: number;
|
|
8
|
-
NO_CONTENT: number;
|
|
9
|
-
MULTIPLE_CHOICES: number;
|
|
10
|
-
MOVED_PERMANENTLY: number;
|
|
11
|
-
FOUND: number;
|
|
12
|
-
SEE_OTHER: number;
|
|
13
|
-
NOT_MODIFIED: number;
|
|
14
|
-
TEMPORARY_REDIRECT: number;
|
|
15
|
-
BAD_REQUEST: number;
|
|
16
|
-
UNAUTHORIZED: number;
|
|
17
|
-
PAYMENT_REQUIRED: number;
|
|
18
|
-
FORBIDDEN: number;
|
|
19
|
-
NOT_FOUND: number;
|
|
20
|
-
METHOD_NOT_ALLOWED: number;
|
|
21
|
-
NOT_ACCEPTABLE: number;
|
|
22
|
-
PROXY_AUTHENTICATION_REQUIRED: number;
|
|
23
|
-
UNPROCESSABLE_ENTITY: number;
|
|
24
|
-
INTERNAL_SERVER_ERROR: number;
|
|
25
|
-
NOT_IMPLEMENTED: number;
|
|
26
|
-
BAD_GATEWAY: number;
|
|
27
|
-
SERVICE_UNAVAILABLE: number;
|
|
28
|
-
HTTP_VERSION_NOT_SUPPORTED: number;
|
|
29
|
-
};
|
|
30
|
-
type StatusCode = keyof typeof statusCode;
|
|
31
|
-
/**
|
|
32
|
-
* Reverse mapping of status codes to their corresponding status text.
|
|
33
|
-
*/
|
|
34
|
-
declare const statusText: Record<"OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "FOUND" | "SEE_OTHER" | "NOT_MODIFIED" | "TEMPORARY_REDIRECT" | "BAD_REQUEST" | "UNAUTHORIZED" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "NOT_FOUND" | "METHOD_NOT_ALLOWED" | "NOT_ACCEPTABLE" | "PROXY_AUTHENTICATION_REQUIRED" | "UNPROCESSABLE_ENTITY" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "HTTP_VERSION_NOT_SUPPORTED", "OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "FOUND" | "SEE_OTHER" | "NOT_MODIFIED" | "TEMPORARY_REDIRECT" | "BAD_REQUEST" | "UNAUTHORIZED" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "NOT_FOUND" | "METHOD_NOT_ALLOWED" | "NOT_ACCEPTABLE" | "PROXY_AUTHENTICATION_REQUIRED" | "UNPROCESSABLE_ENTITY" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "HTTP_VERSION_NOT_SUPPORTED">;
|
|
35
|
-
/**
|
|
36
|
-
* Defines the errors used in AuraStack Router. Includes HTTP status code and
|
|
37
|
-
* status text.
|
|
38
|
-
* @deprecated Use RouterError instead
|
|
39
|
-
*/
|
|
40
|
-
declare class AuraStackRouterError extends Error {
|
|
41
|
-
/**
|
|
42
|
-
* The HTTP status code associated with the error.
|
|
43
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status
|
|
44
|
-
* @example
|
|
45
|
-
* NOT_FOUND: 404
|
|
46
|
-
* METHOD_NOT_ALLOWED: 405
|
|
47
|
-
* INTERNAL_SERVER_ERROR: 500
|
|
48
|
-
*/
|
|
49
|
-
readonly status: number;
|
|
50
|
-
/**
|
|
51
|
-
* The HTTP status text associated with the status code of the error.
|
|
52
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status
|
|
53
|
-
* @example
|
|
54
|
-
* NOT_FOUND: NOT_FOUND
|
|
55
|
-
* METHOD_NOT_ALLOWED: METHOD_NOT_ALLOWED
|
|
56
|
-
* INTERNAL_SERVER_ERROR: INTERNAL_SERVER_ERROR
|
|
57
|
-
*/
|
|
58
|
-
readonly statusText: StatusCode;
|
|
59
|
-
constructor(type: StatusCode, message: string, name?: string);
|
|
60
|
-
}
|
|
61
|
-
declare class RouterError extends AuraStackRouterError {
|
|
62
|
-
constructor(type: StatusCode, message: string, name?: string);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export { AuraStackRouterError, RouterError, statusCode, statusText };
|
package/dist/index.d.cts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { createEndpoint, createEndpointConfig } from './endpoint.cjs';
|
|
2
|
-
export { createRouter } from './router.cjs';
|
|
3
|
-
export { isRouterError } from './assert.cjs';
|
|
4
|
-
export { RouterError, statusCode, statusText } from './error.cjs';
|
|
5
|
-
export { ContentType, ContextBody, ContextParams, ContextSearchParams, EndpointConfig, EndpointSchemas, GetHttpHandlers, GetRouteParams, GlobalMiddleware, HTTPMethod, InferMethod, MiddlewareFunction, Prettify, RequestContext, RouteEndpoint, RouteHandler, RoutePattern, RouterConfig } from './types.cjs';
|
|
6
|
-
import 'zod';
|
package/dist/middlewares.d.cts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { RouterConfig, EndpointConfig, RequestContext, MiddlewareFunction } from './types.cjs';
|
|
2
|
-
import 'zod';
|
|
3
|
-
import './error.cjs';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Executes the middlewares in sequence, passing the request to each middleware.
|
|
7
|
-
*
|
|
8
|
-
* @param request - Original request made from the client
|
|
9
|
-
* @param middlewares - Array of global middleware functions to be executed
|
|
10
|
-
* @returns - The modified request after all middlewares have been executed
|
|
11
|
-
*/
|
|
12
|
-
declare const executeGlobalMiddlewares: (request: Request, middlewares: RouterConfig["middlewares"]) => Promise<Request | Response>;
|
|
13
|
-
/**
|
|
14
|
-
* Executes middlewares in sequence, passing the request and context to each middleware.
|
|
15
|
-
*
|
|
16
|
-
* @param request - Original request made from the client
|
|
17
|
-
* @param context - Context object of the endpoint functionality
|
|
18
|
-
* @param middlewares - Array of middleware functions to be executed
|
|
19
|
-
* @returns The modified context after all middlewares have been executed
|
|
20
|
-
*/
|
|
21
|
-
declare const executeMiddlewares: <const RouteParams extends Record<string, string>, const Config extends EndpointConfig>(request: Request, context: RequestContext<RouteParams, Config>, middlewares?: MiddlewareFunction<RouteParams, Config>[]) => Promise<RequestContext<RouteParams, Config>>;
|
|
22
|
-
|
|
23
|
-
export { executeGlobalMiddlewares, executeMiddlewares };
|
package/dist/router.d.cts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { RouteEndpoint, RouterConfig, GetHttpHandlers, HTTPMethod, RoutePattern, EndpointSchemas, MiddlewareFunction } from './types.cjs';
|
|
2
|
-
import 'zod';
|
|
3
|
-
import './error.cjs';
|
|
4
|
-
|
|
5
|
-
interface TrieNode {
|
|
6
|
-
statics: Map<string, TrieNode>;
|
|
7
|
-
param?: {
|
|
8
|
-
name: string;
|
|
9
|
-
node: TrieNode;
|
|
10
|
-
};
|
|
11
|
-
endpoints: Map<HTTPMethod, RouteEndpoint>;
|
|
12
|
-
}
|
|
13
|
-
declare const createNode: () => TrieNode;
|
|
14
|
-
declare const insert: (root: TrieNode, endpoint: RouteEndpoint) => void;
|
|
15
|
-
declare const search: (method: HTTPMethod, root: TrieNode, pathname: string) => {
|
|
16
|
-
endpoint: RouteEndpoint<HTTPMethod, RoutePattern, {
|
|
17
|
-
schemas?: EndpointSchemas | undefined;
|
|
18
|
-
middlewares?: MiddlewareFunction<{} | {
|
|
19
|
-
[x: string]: string;
|
|
20
|
-
}, {
|
|
21
|
-
schemas: EndpointSchemas;
|
|
22
|
-
}>[] | undefined;
|
|
23
|
-
}>;
|
|
24
|
-
params: Record<string, string>;
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* Creates the entry point for the server, handling the endpoints defined in the router.
|
|
28
|
-
* It groups endpoints by HTTP method and matches incoming requests to the appropriate endpoint.
|
|
29
|
-
* It accepts an optional configuration object to set a base path and middlewares for all endpoints.
|
|
30
|
-
*
|
|
31
|
-
* @param endpoints - Array of route endpoints to be handled by the router
|
|
32
|
-
* @param config - Optional configuration object for the router
|
|
33
|
-
* @returns An object with methods corresponding to HTTP methods, each handling requests for that method
|
|
34
|
-
*/
|
|
35
|
-
declare const createRouter: <const Endpoints extends RouteEndpoint[]>(endpoints: Endpoints, config?: RouterConfig) => GetHttpHandlers<Endpoints>;
|
|
36
|
-
|
|
37
|
-
export { createNode, createRouter, insert, search };
|
package/dist/types.d.cts
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { ZodObject, z } from 'zod';
|
|
2
|
-
import { RouterError } from './error.cjs';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Route pattern must start with a slash and can contain parameters prefixed with a colon.
|
|
6
|
-
* @example
|
|
7
|
-
* const getUser:RoutePattern = "/users/:userId"
|
|
8
|
-
* const getPostsComments:RoutePattern = "/posts/:postId/comments/:commentId"
|
|
9
|
-
*/
|
|
10
|
-
type RoutePattern = `/${string}` | `/${string}/:${string}`;
|
|
11
|
-
/**
|
|
12
|
-
* HTTP methods defined in HTTP/1.1 specification.
|
|
13
|
-
* @see https://datatracker.ietf.org/doc/html/rfc7231#section-4.3
|
|
14
|
-
*/
|
|
15
|
-
type HTTPMethod = "GET" | "POST" | "DELETE" | "PUT" | "PATCH" | "OPTIONS" | "HEAD" | "TRACE" | "CONNECT";
|
|
16
|
-
/**
|
|
17
|
-
* Content types supported by the router.
|
|
18
|
-
*/
|
|
19
|
-
type ContentType = "application/json" | "application/x-www-form-urlencoded" | "text/plain" | "multipart/form-data" | "application/xml" | "application/octet-stream" | `text/${string}` | `image/${string}` | `video/${string}` | `audio/${string}` | "application/pdf";
|
|
20
|
-
type Prettify<Obj extends object> = {
|
|
21
|
-
[Key in keyof Obj]: Obj[Key];
|
|
22
|
-
} & {};
|
|
23
|
-
/**
|
|
24
|
-
* Extracts route parameters from a given route pattern through colon-prefixed segments.
|
|
25
|
-
* Returns an object type where keys are parameter names and values are strings.
|
|
26
|
-
* If no parameters are found, returns an empty object type.
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
* // Expected: { userId: string }
|
|
30
|
-
* type UserParams = Params<"/users/:userId">;
|
|
31
|
-
*
|
|
32
|
-
* // Expected: { postId: string; commentId: string }
|
|
33
|
-
* type PostCommentParams = Params<"/posts/:postId/comments/:commentId">;
|
|
34
|
-
*
|
|
35
|
-
* // Expected: {}
|
|
36
|
-
* type NoParams = Params<"/about">;
|
|
37
|
-
*/
|
|
38
|
-
type GetRouteParams<Route extends RoutePattern> = Route extends `/${string}/:${infer Param}/${infer Str}` ? Prettify<{
|
|
39
|
-
[K in Param]: string;
|
|
40
|
-
} & GetRouteParams<`/${Str}`>> : Route extends `/${string}/:${infer Param}` ? Prettify<{
|
|
41
|
-
[K in Param]: string;
|
|
42
|
-
}> : Route extends `/:${infer Param}` ? Prettify<{
|
|
43
|
-
[K in Param]: string;
|
|
44
|
-
}> : {};
|
|
45
|
-
/**
|
|
46
|
-
* Available schemas validation for an endpoint. It can include body and searchParams schemas.
|
|
47
|
-
*/
|
|
48
|
-
interface EndpointSchemas {
|
|
49
|
-
body?: ZodObject<any>;
|
|
50
|
-
searchParams?: ZodObject<any>;
|
|
51
|
-
params?: ZodObject<any>;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Configuration for an endpoint, including optional schemas for request validation and middlewares.
|
|
55
|
-
*/
|
|
56
|
-
type EndpointConfig<RouteParams extends RoutePattern = RoutePattern, Schemas extends EndpointSchemas = EndpointSchemas> = Prettify<{
|
|
57
|
-
schemas?: Schemas;
|
|
58
|
-
middlewares?: MiddlewareFunction<GetRouteParams<RouteParams>, {
|
|
59
|
-
schemas: Schemas;
|
|
60
|
-
}>[];
|
|
61
|
-
}>;
|
|
62
|
-
/**
|
|
63
|
-
* Infer the type of search parameters from the provided value in the `EndpointConfig`.
|
|
64
|
-
*/
|
|
65
|
-
type ContextSearchParams<Schemas extends EndpointConfig["schemas"]> = Schemas extends {
|
|
66
|
-
searchParams: ZodObject;
|
|
67
|
-
} ? {
|
|
68
|
-
searchParams: z.infer<Schemas["searchParams"]>;
|
|
69
|
-
} : {
|
|
70
|
-
searchParams: URLSearchParams;
|
|
71
|
-
};
|
|
72
|
-
/**
|
|
73
|
-
* Infer the type of body from the provided value in the `EndpointConfig`.
|
|
74
|
-
*/
|
|
75
|
-
type ContextBody<Schemas extends EndpointConfig["schemas"]> = Schemas extends {
|
|
76
|
-
body: ZodObject;
|
|
77
|
-
} ? {
|
|
78
|
-
body: z.infer<Schemas["body"]>;
|
|
79
|
-
} : {
|
|
80
|
-
body: undefined;
|
|
81
|
-
};
|
|
82
|
-
/**
|
|
83
|
-
* Infer the type of route parameters from the provided value in the `EndpointConfig`.
|
|
84
|
-
*/
|
|
85
|
-
type ContextParams<Schemas extends EndpointConfig["schemas"], Default = Record<string, string>> = Schemas extends {
|
|
86
|
-
params: ZodObject;
|
|
87
|
-
} ? {
|
|
88
|
-
params: z.infer<Schemas["params"]>;
|
|
89
|
-
} : {
|
|
90
|
-
params: Default;
|
|
91
|
-
};
|
|
92
|
-
/**
|
|
93
|
-
* Context object passed to route handlers and middlewares defined in the
|
|
94
|
-
* `createEndpoint/createEndpointConfig` function or globally in the `createRouter` function.
|
|
95
|
-
*/
|
|
96
|
-
interface RequestContext<RouteParams = Record<string, string>, Config extends EndpointConfig = EndpointConfig> {
|
|
97
|
-
params: ContextParams<Config["schemas"], RouteParams>["params"];
|
|
98
|
-
headers: Headers;
|
|
99
|
-
body: ContextBody<Config["schemas"]>["body"];
|
|
100
|
-
searchParams: ContextSearchParams<Config["schemas"]>["searchParams"];
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Global middleware function type that represent a function that runs before the route matching.
|
|
104
|
-
*/
|
|
105
|
-
type GlobalMiddleware = (request: Request) => Promise<Request | Response>;
|
|
106
|
-
/**
|
|
107
|
-
* Middleware function type that represent a function that runs before the route handler
|
|
108
|
-
* defined in the `createEndpoint/createEndpointConfig` function or globally in the `createRouter` function.
|
|
109
|
-
*/
|
|
110
|
-
type MiddlewareFunction<RouteParams = Record<string, string>, Config extends EndpointConfig = EndpointConfig> = (request: Request, ctx: Prettify<RequestContext<RouteParams, Config>>) => Promise<RequestContext<RouteParams, Config>>;
|
|
111
|
-
/**
|
|
112
|
-
* Defines a route handler function that processes an incoming request and returns a response.
|
|
113
|
-
* The handler receives the request object and a context containing route parameters, headers,
|
|
114
|
-
* and optionally validated body and search parameters based on the endpoint configuration.
|
|
115
|
-
*/
|
|
116
|
-
type RouteHandler<Route extends RoutePattern, Config extends EndpointConfig> = (request: Request, ctx: Prettify<RequestContext<GetRouteParams<Route>, Config>>) => Response | Promise<Response>;
|
|
117
|
-
/**
|
|
118
|
-
* Represents a route endpoint definition, specifying the HTTP method, route pattern,
|
|
119
|
-
* handler function with inferred context types, and associated configuration.
|
|
120
|
-
*/
|
|
121
|
-
interface RouteEndpoint<Method extends HTTPMethod = HTTPMethod, Route extends RoutePattern = RoutePattern, Config extends EndpointConfig = EndpointConfig> {
|
|
122
|
-
method: Method;
|
|
123
|
-
route: Route;
|
|
124
|
-
handler: RouteHandler<Route, Config>;
|
|
125
|
-
config: Config;
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Infer the HTTP methods defined in the provided array of route endpoints.
|
|
129
|
-
*/
|
|
130
|
-
type InferMethod<Endpoints extends RouteEndpoint[]> = Endpoints extends unknown[] ? Endpoints[number]["method"] : "unknown";
|
|
131
|
-
/**
|
|
132
|
-
* Generates an object with HTTP methods available by the router from `createRouter` function.
|
|
133
|
-
* Each method is a function that takes a request and context, returning a promise of a response.
|
|
134
|
-
*/
|
|
135
|
-
type GetHttpHandlers<Endpoints extends RouteEndpoint[]> = {
|
|
136
|
-
[Method in InferMethod<Endpoints>]: (req: Request) => Response | Promise<Response>;
|
|
137
|
-
};
|
|
138
|
-
/**
|
|
139
|
-
* Configuration options for `createRouter` function.
|
|
140
|
-
*/
|
|
141
|
-
interface RouterConfig {
|
|
142
|
-
/**
|
|
143
|
-
* Prefix path for all routes/endpoints defined in the router.
|
|
144
|
-
*
|
|
145
|
-
* @example
|
|
146
|
-
* basePath: "/api/v1"
|
|
147
|
-
*
|
|
148
|
-
* // will match the "/users" endpoint.
|
|
149
|
-
* new Request("https://example.com/api/v1/users")
|
|
150
|
-
*
|
|
151
|
-
* // will NOT match the "/users" endpoint.
|
|
152
|
-
* new Request("https://example.com/users")
|
|
153
|
-
*/
|
|
154
|
-
basePath?: RoutePattern;
|
|
155
|
-
/**
|
|
156
|
-
* Global middlewares that run before route matching for all endpoints in the router.
|
|
157
|
-
* You can use this to modify the request or return a response early.
|
|
158
|
-
*
|
|
159
|
-
* @example
|
|
160
|
-
* middlewares: [
|
|
161
|
-
* async (request) => {
|
|
162
|
-
* if(request.headers.get("Authorization")?.startsWith("Bearer ")) {
|
|
163
|
-
* return Response.json({ message: "Unauthorized" }, { status: 401 })
|
|
164
|
-
* }
|
|
165
|
-
* return request
|
|
166
|
-
* }
|
|
167
|
-
* ]
|
|
168
|
-
*/
|
|
169
|
-
middlewares?: GlobalMiddleware[];
|
|
170
|
-
/**
|
|
171
|
-
* Error handler function that runs when an error is thrown in a router handler or middleware.
|
|
172
|
-
* It can be used to customize the default error response provided by the router. If is an internal
|
|
173
|
-
* error the error is from the `RouterError` class, otherwise the error is a generic
|
|
174
|
-
* `Error` instance which was caused by a handler or middleware, for how to distinguish them you can use
|
|
175
|
-
* the `isRouterError` function from the `assert` module.
|
|
176
|
-
*
|
|
177
|
-
* @param error - The error thrown in the router
|
|
178
|
-
* @param request - The original request that caused the error
|
|
179
|
-
* @returns A response to be sent back to the client
|
|
180
|
-
* @example
|
|
181
|
-
* onError: (error, request) => {
|
|
182
|
-
* if(isRouterError(error)) {
|
|
183
|
-
* return Response.json({ message: error.message }, { status: error.statusCode })
|
|
184
|
-
* }
|
|
185
|
-
* return Response.json({ message: "Internal Server Error" }, { status: 500 })
|
|
186
|
-
* }
|
|
187
|
-
*/
|
|
188
|
-
onError?: (error: Error | RouterError, request: Request) => Response | Promise<Response>;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export type { ContentType, ContextBody, ContextParams, ContextSearchParams, EndpointConfig, EndpointSchemas, GetHttpHandlers, GetRouteParams, GlobalMiddleware, HTTPMethod, InferMethod, MiddlewareFunction, Prettify, RequestContext, RouteEndpoint, RouteHandler, RoutePattern, RouterConfig };
|