@aura-stack/router 0.1.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/LICENSE +21 -0
- package/README.md +128 -0
- package/dist/assert.cjs +50 -0
- package/dist/assert.d.cts +32 -0
- package/dist/assert.d.ts +32 -0
- package/dist/assert.js +12 -0
- package/dist/chunk-6UBPSXKR.js +36 -0
- package/dist/chunk-ENOBC3XN.js +23 -0
- package/dist/chunk-NNCUFWPI.js +78 -0
- package/dist/chunk-RFYOPPMW.js +45 -0
- package/dist/chunk-RVJ2F7OL.js +41 -0
- package/dist/chunk-VBI7H3AK.js +75 -0
- package/dist/context.cjs +151 -0
- package/dist/context.d.cts +84 -0
- package/dist/context.d.ts +84 -0
- package/dist/context.js +15 -0
- package/dist/endpoint.cjs +110 -0
- package/dist/endpoint.d.cts +59 -0
- package/dist/endpoint.d.ts +59 -0
- package/dist/endpoint.js +12 -0
- package/dist/error.cjs +69 -0
- package/dist/error.d.cts +40 -0
- package/dist/error.d.ts +40 -0
- package/dist/error.js +6 -0
- package/dist/index.cjs +264 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +16 -0
- package/dist/middleware.cjs +106 -0
- package/dist/middleware.d.cts +22 -0
- package/dist/middleware.d.ts +22 -0
- package/dist/middleware.js +9 -0
- package/dist/router.cjs +233 -0
- package/dist/router.d.cts +15 -0
- package/dist/router.d.ts +15 -0
- package/dist/router.js +11 -0
- package/dist/types.cjs +18 -0
- package/dist/types.d.cts +134 -0
- package/dist/types.d.ts +134 -0
- package/dist/types.js +0 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Aura Stack
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# `@aura-stack/router`
|
|
2
|
+
|
|
3
|
+
A modern, **TypeScript-first** router and endpoint definition library for Node.js.
|
|
4
|
+
Build fully-typed APIs with declarative endpoints, automatic parameter inference, and first-class middleware support — all returning native `Response` objects for seamless compatibility with the Fetch API.
|
|
5
|
+
|
|
6
|
+
## Table of Contents
|
|
7
|
+
|
|
8
|
+
- [Features](#features)
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Quick Start](#quick-start)
|
|
11
|
+
- [Defining Endpoints](#defining-endpoints)
|
|
12
|
+
- [Validation & Middlewares](#validation--middlewares)
|
|
13
|
+
- [API Reference](#api-reference)
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- `Type-safe routing` — only configured HTTP methods are available at compile time.
|
|
18
|
+
- `Declarative API` — define endpoints using `createEndpoint` and group them with `createRouter`.
|
|
19
|
+
- `Typed params & queries` — automatic inference of path (`/users/:id`) and search parameters.
|
|
20
|
+
- `Schema validation` — built-in support for `zod` to validate request bodies, queries, or params.
|
|
21
|
+
- `Middleware chaining` — supports global and per-endpoint middleware execution, with short-circuit control.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm add @aura-stack/router
|
|
27
|
+
# or
|
|
28
|
+
npm install @aura-stack/router
|
|
29
|
+
# or
|
|
30
|
+
yarn add @aura-stack/router
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { createEndpoint, createRouter } from "@aura-stack/router"
|
|
37
|
+
|
|
38
|
+
const session = createEndpoint("GET", "/auth/session", async (_, ctx) => {
|
|
39
|
+
return Response.json(
|
|
40
|
+
{
|
|
41
|
+
session: {
|
|
42
|
+
userId: "uuid",
|
|
43
|
+
username: "John",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{ headers: ctx.headers }
|
|
47
|
+
)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const { GET } = createRouter([session])
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Defining Endpoints
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { z } from "zod"
|
|
57
|
+
import { createEndpoint, createEndpointConfig } from "@aura-stack/router"
|
|
58
|
+
|
|
59
|
+
const credentialsConfig = createEndpointConfig({
|
|
60
|
+
schemas: {
|
|
61
|
+
body: z.object({
|
|
62
|
+
username: z.string(),
|
|
63
|
+
password: z.string(),
|
|
64
|
+
}),
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
export const signIn = createEndpoint(
|
|
69
|
+
"POST",
|
|
70
|
+
"/auth/credentials",
|
|
71
|
+
async (request, ctx) => {
|
|
72
|
+
const { body, headers } = ctx
|
|
73
|
+
headers.set("x-login", "success")
|
|
74
|
+
return Response.json({ status: "ok", body }, { headers })
|
|
75
|
+
},
|
|
76
|
+
credentialsConfig
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Validation & Middlewares
|
|
81
|
+
|
|
82
|
+
**Validation.** Provide Zod schemas in `createEndpointConfig`:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { createEndpoint, createEndpointConfig } from "@aura-stack/router"
|
|
86
|
+
|
|
87
|
+
const config = createEndpointConfig({
|
|
88
|
+
schemas: {
|
|
89
|
+
searchParams: z.object({
|
|
90
|
+
redirect_uri: z.string(),
|
|
91
|
+
}),
|
|
92
|
+
},
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const oauth = createEndpoint(
|
|
96
|
+
"GET",
|
|
97
|
+
"/auth/signin/:provider",
|
|
98
|
+
async (_req, ctx) => {
|
|
99
|
+
const { provider } = ctx.params
|
|
100
|
+
const { redirect_uri } = ctx.searchParams
|
|
101
|
+
return Response.json({ provider, redirect_uri }, { status: 302 })
|
|
102
|
+
},
|
|
103
|
+
config
|
|
104
|
+
)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
If validation fails, the helper throws an informative error before your handler executes.
|
|
108
|
+
|
|
109
|
+
**Middlewares.** Provide async middleware functions to read or modify the request.
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { createRouter, type GlobalMiddleware } from "@aura-stack/router"
|
|
113
|
+
|
|
114
|
+
const audit: GlobalMiddleware = async (request) => {
|
|
115
|
+
request.headers.set("x-request-id", crypto.randomUUID())
|
|
116
|
+
return request
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const router = createRouter([oauth], { middlewares: [audit] })
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## API Reference
|
|
123
|
+
|
|
124
|
+
| Function | Description |
|
|
125
|
+
| ------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
126
|
+
| `createEndpoint(method, route, handler, config?)` | Define a type-safe endpoint with optional validation and middlewares. |
|
|
127
|
+
| `createEndpointConfig(config)` | Helper that preserves Zod inference for endpoint schemas. |
|
|
128
|
+
| `createRouter(endpoints, config?)` | Build a router that dispatches native Fetch requests to the right handler. |
|
package/dist/assert.cjs
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/assert.ts
|
|
21
|
+
var assert_exports = {};
|
|
22
|
+
__export(assert_exports, {
|
|
23
|
+
isSupportedBodyMethod: () => isSupportedBodyMethod,
|
|
24
|
+
isSupportedMethod: () => isSupportedMethod,
|
|
25
|
+
isValidHandler: () => isValidHandler,
|
|
26
|
+
isValidRoute: () => isValidRoute
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(assert_exports);
|
|
29
|
+
var supportedMethods = ["GET", "POST", "DELETE", "PUT", "PATCH"];
|
|
30
|
+
var supportedBodyMethods = ["POST", "PUT", "PATCH"];
|
|
31
|
+
var isSupportedMethod = (method) => {
|
|
32
|
+
return supportedMethods.includes(method);
|
|
33
|
+
};
|
|
34
|
+
var isSupportedBodyMethod = (method) => {
|
|
35
|
+
return supportedBodyMethods.includes(method);
|
|
36
|
+
};
|
|
37
|
+
var isValidRoute = (route) => {
|
|
38
|
+
const routePattern = /^\/[a-zA-Z0-9/_:-]*$/;
|
|
39
|
+
return routePattern.test(route);
|
|
40
|
+
};
|
|
41
|
+
var isValidHandler = (handler) => {
|
|
42
|
+
return typeof handler === "function";
|
|
43
|
+
};
|
|
44
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
45
|
+
0 && (module.exports = {
|
|
46
|
+
isSupportedBodyMethod,
|
|
47
|
+
isSupportedMethod,
|
|
48
|
+
isValidHandler,
|
|
49
|
+
isValidRoute
|
|
50
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { HTTPMethod, RoutePattern, RouteHandler } from './types.cjs';
|
|
2
|
+
import 'zod';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Checks if the provided method is a supported HTTP method.
|
|
6
|
+
*
|
|
7
|
+
* @param method - The HTTP method to check.
|
|
8
|
+
* @returns True if the method is supported, false otherwise.
|
|
9
|
+
*/
|
|
10
|
+
declare const isSupportedMethod: (method: string) => method is HTTPMethod;
|
|
11
|
+
/**
|
|
12
|
+
* Check if the provided method can includes a body as per HTTP specification.
|
|
13
|
+
* @param method - The HTTP method to check.
|
|
14
|
+
* @returns True if the method can include a body, false otherwise.
|
|
15
|
+
*/
|
|
16
|
+
declare const isSupportedBodyMethod: (method: string) => method is HTTPMethod;
|
|
17
|
+
/**
|
|
18
|
+
* Checks if the provided route is a valid route pattern.
|
|
19
|
+
*
|
|
20
|
+
* @param route - The route pattern to check.
|
|
21
|
+
* @returns True if the route is valid, false otherwise.
|
|
22
|
+
*/
|
|
23
|
+
declare const isValidRoute: (route: string) => route is RoutePattern;
|
|
24
|
+
/**
|
|
25
|
+
* Checks if the provided handler is a valid route handler function.
|
|
26
|
+
*
|
|
27
|
+
* @param handler - The handler to check.
|
|
28
|
+
* @returns True if the handler is valid, false otherwise.
|
|
29
|
+
*/
|
|
30
|
+
declare const isValidHandler: (handler: unknown) => handler is RouteHandler<any, any>;
|
|
31
|
+
|
|
32
|
+
export { isSupportedBodyMethod, isSupportedMethod, isValidHandler, isValidRoute };
|
package/dist/assert.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { HTTPMethod, RoutePattern, RouteHandler } from './types.js';
|
|
2
|
+
import 'zod';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Checks if the provided method is a supported HTTP method.
|
|
6
|
+
*
|
|
7
|
+
* @param method - The HTTP method to check.
|
|
8
|
+
* @returns True if the method is supported, false otherwise.
|
|
9
|
+
*/
|
|
10
|
+
declare const isSupportedMethod: (method: string) => method is HTTPMethod;
|
|
11
|
+
/**
|
|
12
|
+
* Check if the provided method can includes a body as per HTTP specification.
|
|
13
|
+
* @param method - The HTTP method to check.
|
|
14
|
+
* @returns True if the method can include a body, false otherwise.
|
|
15
|
+
*/
|
|
16
|
+
declare const isSupportedBodyMethod: (method: string) => method is HTTPMethod;
|
|
17
|
+
/**
|
|
18
|
+
* Checks if the provided route is a valid route pattern.
|
|
19
|
+
*
|
|
20
|
+
* @param route - The route pattern to check.
|
|
21
|
+
* @returns True if the route is valid, false otherwise.
|
|
22
|
+
*/
|
|
23
|
+
declare const isValidRoute: (route: string) => route is RoutePattern;
|
|
24
|
+
/**
|
|
25
|
+
* Checks if the provided handler is a valid route handler function.
|
|
26
|
+
*
|
|
27
|
+
* @param handler - The handler to check.
|
|
28
|
+
* @returns True if the handler is valid, false otherwise.
|
|
29
|
+
*/
|
|
30
|
+
declare const isValidHandler: (handler: unknown) => handler is RouteHandler<any, any>;
|
|
31
|
+
|
|
32
|
+
export { isSupportedBodyMethod, isSupportedMethod, isValidHandler, isValidRoute };
|
package/dist/assert.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isSupportedMethod,
|
|
3
|
+
isValidHandler,
|
|
4
|
+
isValidRoute
|
|
5
|
+
} from "./chunk-ENOBC3XN.js";
|
|
6
|
+
import {
|
|
7
|
+
AuraStackRouterError
|
|
8
|
+
} from "./chunk-RFYOPPMW.js";
|
|
9
|
+
|
|
10
|
+
// src/endpoint.ts
|
|
11
|
+
var createRoutePattern = (route) => {
|
|
12
|
+
const pattern = route.replace(/:[^/]+/g, "([^/]+)").replace(/\//g, "\\/");
|
|
13
|
+
return new RegExp(`^${pattern}$`);
|
|
14
|
+
};
|
|
15
|
+
var createEndpoint = (method, route, handler, config = {}) => {
|
|
16
|
+
if (!isSupportedMethod(method)) {
|
|
17
|
+
throw new AuraStackRouterError("METHOD_NOT_ALLOWED", `Unsupported HTTP method: ${method}`);
|
|
18
|
+
}
|
|
19
|
+
if (!isValidRoute(route)) {
|
|
20
|
+
throw new AuraStackRouterError("BAD_REQUEST", `Invalid route format: ${route}`);
|
|
21
|
+
}
|
|
22
|
+
if (!isValidHandler(handler)) {
|
|
23
|
+
throw new AuraStackRouterError("BAD_REQUEST", "Handler must be a function");
|
|
24
|
+
}
|
|
25
|
+
return { method, route, handler, config };
|
|
26
|
+
};
|
|
27
|
+
function createEndpointConfig(...args) {
|
|
28
|
+
if (typeof args[0] === "string") return args[1];
|
|
29
|
+
return args[0];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
createRoutePattern,
|
|
34
|
+
createEndpoint,
|
|
35
|
+
createEndpointConfig
|
|
36
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// src/assert.ts
|
|
2
|
+
var supportedMethods = ["GET", "POST", "DELETE", "PUT", "PATCH"];
|
|
3
|
+
var supportedBodyMethods = ["POST", "PUT", "PATCH"];
|
|
4
|
+
var isSupportedMethod = (method) => {
|
|
5
|
+
return supportedMethods.includes(method);
|
|
6
|
+
};
|
|
7
|
+
var isSupportedBodyMethod = (method) => {
|
|
8
|
+
return supportedBodyMethods.includes(method);
|
|
9
|
+
};
|
|
10
|
+
var isValidRoute = (route) => {
|
|
11
|
+
const routePattern = /^\/[a-zA-Z0-9/_:-]*$/;
|
|
12
|
+
return routePattern.test(route);
|
|
13
|
+
};
|
|
14
|
+
var isValidHandler = (handler) => {
|
|
15
|
+
return typeof handler === "function";
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
isSupportedMethod,
|
|
20
|
+
isSupportedBodyMethod,
|
|
21
|
+
isValidRoute,
|
|
22
|
+
isValidHandler
|
|
23
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createRoutePattern
|
|
3
|
+
} from "./chunk-6UBPSXKR.js";
|
|
4
|
+
import {
|
|
5
|
+
isSupportedBodyMethod
|
|
6
|
+
} from "./chunk-ENOBC3XN.js";
|
|
7
|
+
import {
|
|
8
|
+
AuraStackRouterError
|
|
9
|
+
} from "./chunk-RFYOPPMW.js";
|
|
10
|
+
|
|
11
|
+
// src/context.ts
|
|
12
|
+
var getRouteParams = (route, path) => {
|
|
13
|
+
const routeRegex = createRoutePattern(route);
|
|
14
|
+
if (!routeRegex.test(path)) {
|
|
15
|
+
throw new AuraStackRouterError("BAD_REQUEST", `Missing required route params for route: ${route}`);
|
|
16
|
+
}
|
|
17
|
+
const params = routeRegex.exec(route)?.slice(1).map((seg) => seg.replace(":", ""));
|
|
18
|
+
if (!params) return {};
|
|
19
|
+
const values = routeRegex.exec(path)?.slice(1);
|
|
20
|
+
return params.reduce(
|
|
21
|
+
(previous, now, idx) => ({
|
|
22
|
+
...previous,
|
|
23
|
+
[now]: decodeURIComponent(values?.[idx] ?? "")
|
|
24
|
+
}),
|
|
25
|
+
{}
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
var getSearchParams = (url, config) => {
|
|
29
|
+
const route = new URL(url);
|
|
30
|
+
if (config.schemas?.searchParams) {
|
|
31
|
+
const parsed = config.schemas.searchParams.safeParse(Object.fromEntries(route.searchParams.entries()));
|
|
32
|
+
if (!parsed.success) {
|
|
33
|
+
throw new AuraStackRouterError("UNPROCESSABLE_ENTITY", "Invalid search parameters");
|
|
34
|
+
}
|
|
35
|
+
return parsed.data;
|
|
36
|
+
}
|
|
37
|
+
return new URLSearchParams(route.searchParams.toString());
|
|
38
|
+
};
|
|
39
|
+
var getHeaders = (request) => {
|
|
40
|
+
return new Headers(request.headers);
|
|
41
|
+
};
|
|
42
|
+
var getBody = async (request, config) => {
|
|
43
|
+
if (!isSupportedBodyMethod(request.method)) {
|
|
44
|
+
return void 0;
|
|
45
|
+
}
|
|
46
|
+
const contentType = request.headers.get("Content-Type") ?? "";
|
|
47
|
+
if (contentType.includes("application/json")) {
|
|
48
|
+
const json = await request.json();
|
|
49
|
+
if (config.schemas?.body) {
|
|
50
|
+
const parsed = config.schemas.body.safeParse(json);
|
|
51
|
+
if (!parsed.success) {
|
|
52
|
+
throw new AuraStackRouterError("UNPROCESSABLE_ENTITY", "Invalid request body");
|
|
53
|
+
}
|
|
54
|
+
return parsed.data;
|
|
55
|
+
}
|
|
56
|
+
return json;
|
|
57
|
+
}
|
|
58
|
+
if (contentType.includes("application/x-www-form-urlencoded") || contentType.includes("multipart/form-data")) {
|
|
59
|
+
return await request.formData();
|
|
60
|
+
}
|
|
61
|
+
if (contentType.includes("text/")) {
|
|
62
|
+
return await request.text();
|
|
63
|
+
}
|
|
64
|
+
if (contentType.includes("application/octet-stream")) {
|
|
65
|
+
return await request.arrayBuffer();
|
|
66
|
+
}
|
|
67
|
+
if (contentType.includes("image/") || contentType.includes("video/") || contentType.includes("audio/")) {
|
|
68
|
+
return await request.blob();
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
getRouteParams,
|
|
75
|
+
getSearchParams,
|
|
76
|
+
getHeaders,
|
|
77
|
+
getBody
|
|
78
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// src/error.ts
|
|
2
|
+
var statusCode = {
|
|
3
|
+
OK: 200,
|
|
4
|
+
CREATED: 201,
|
|
5
|
+
ACCEPTED: 202,
|
|
6
|
+
NO_CONTENT: 204,
|
|
7
|
+
MULTIPLE_CHOICES: 300,
|
|
8
|
+
MOVED_PERMANENTLY: 301,
|
|
9
|
+
FOUND: 302,
|
|
10
|
+
SEE_OTHER: 303,
|
|
11
|
+
NOT_MODIFIED: 304,
|
|
12
|
+
TEMPORARY_REDIRECT: 307,
|
|
13
|
+
BAD_REQUEST: 400,
|
|
14
|
+
UNAUTHORIZED: 401,
|
|
15
|
+
PAYMENT_REQUIRED: 402,
|
|
16
|
+
FORBIDDEN: 403,
|
|
17
|
+
NOT_FOUND: 404,
|
|
18
|
+
METHOD_NOT_ALLOWED: 405,
|
|
19
|
+
NOT_ACCEPTABLE: 406,
|
|
20
|
+
PROXY_AUTHENTICATION_REQUIRED: 407,
|
|
21
|
+
UNPROCESSABLE_ENTITY: 422,
|
|
22
|
+
INTERNAL_SERVER_ERROR: 500,
|
|
23
|
+
NOT_IMPLEMENTED: 501,
|
|
24
|
+
BAD_GATEWAY: 502,
|
|
25
|
+
SERVICE_UNAVAILABLE: 503,
|
|
26
|
+
HTTP_VERSION_NOT_SUPPORTED: 505
|
|
27
|
+
};
|
|
28
|
+
var statusText = Object.entries(statusCode).reduce(
|
|
29
|
+
(previous, [status, code]) => {
|
|
30
|
+
return { ...previous, [code]: status };
|
|
31
|
+
},
|
|
32
|
+
{}
|
|
33
|
+
);
|
|
34
|
+
var AuraStackRouterError = class extends Error {
|
|
35
|
+
constructor(type, message, name) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = name ?? "AuraStackRouterError";
|
|
38
|
+
this.status = statusCode[type];
|
|
39
|
+
this.statusText = statusText[this.status];
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export {
|
|
44
|
+
AuraStackRouterError
|
|
45
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuraStackRouterError
|
|
3
|
+
} from "./chunk-RFYOPPMW.js";
|
|
4
|
+
|
|
5
|
+
// src/middleware.ts
|
|
6
|
+
var executeGlobalMiddlewares = async (request, middlewares) => {
|
|
7
|
+
if (!middlewares) return request;
|
|
8
|
+
for (const middleware of middlewares) {
|
|
9
|
+
if (typeof middleware !== "function") {
|
|
10
|
+
throw new AuraStackRouterError("BAD_REQUEST", "Global middlewares must be functions");
|
|
11
|
+
}
|
|
12
|
+
const executed = await middleware(request);
|
|
13
|
+
if (executed instanceof Response) {
|
|
14
|
+
return executed;
|
|
15
|
+
}
|
|
16
|
+
request = executed;
|
|
17
|
+
}
|
|
18
|
+
if (!request || !(request instanceof Request)) {
|
|
19
|
+
throw new AuraStackRouterError("BAD_REQUEST", "Global middleware must return a Request or Response object");
|
|
20
|
+
}
|
|
21
|
+
return request;
|
|
22
|
+
};
|
|
23
|
+
var executeMiddlewares = async (request, context, middlewares = []) => {
|
|
24
|
+
try {
|
|
25
|
+
let ctx = context;
|
|
26
|
+
for (const middleware of middlewares) {
|
|
27
|
+
if (typeof middleware !== "function") {
|
|
28
|
+
throw new AuraStackRouterError("BAD_REQUEST", "Middleware must be a function");
|
|
29
|
+
}
|
|
30
|
+
ctx = await middleware(request, ctx);
|
|
31
|
+
}
|
|
32
|
+
return ctx;
|
|
33
|
+
} catch {
|
|
34
|
+
throw new AuraStackRouterError("BAD_REQUEST", "Handler threw an error");
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
executeGlobalMiddlewares,
|
|
40
|
+
executeMiddlewares
|
|
41
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getBody,
|
|
3
|
+
getHeaders,
|
|
4
|
+
getRouteParams,
|
|
5
|
+
getSearchParams
|
|
6
|
+
} from "./chunk-NNCUFWPI.js";
|
|
7
|
+
import {
|
|
8
|
+
createRoutePattern
|
|
9
|
+
} from "./chunk-6UBPSXKR.js";
|
|
10
|
+
import {
|
|
11
|
+
executeGlobalMiddlewares,
|
|
12
|
+
executeMiddlewares
|
|
13
|
+
} from "./chunk-RVJ2F7OL.js";
|
|
14
|
+
import {
|
|
15
|
+
AuraStackRouterError
|
|
16
|
+
} from "./chunk-RFYOPPMW.js";
|
|
17
|
+
|
|
18
|
+
// src/router.ts
|
|
19
|
+
var createRouter = (endpoints, config = {}) => {
|
|
20
|
+
const server = {};
|
|
21
|
+
const groups = {
|
|
22
|
+
GET: [],
|
|
23
|
+
POST: [],
|
|
24
|
+
DELETE: [],
|
|
25
|
+
PUT: [],
|
|
26
|
+
PATCH: []
|
|
27
|
+
};
|
|
28
|
+
endpoints.forEach((endpoint) => groups[endpoint.method].push(endpoint));
|
|
29
|
+
for (const method in groups) {
|
|
30
|
+
server[method] = async (request, ctx) => {
|
|
31
|
+
try {
|
|
32
|
+
const globalRequest = await executeGlobalMiddlewares(request, config.middlewares);
|
|
33
|
+
if (globalRequest instanceof Response) {
|
|
34
|
+
return globalRequest;
|
|
35
|
+
}
|
|
36
|
+
const url = new URL(globalRequest.url);
|
|
37
|
+
const pathname = url.pathname;
|
|
38
|
+
const endpoint = groups[method].find((endpoint2) => {
|
|
39
|
+
const withBasePath = config.basePath ? `${config.basePath}${endpoint2.route}` : endpoint2.route;
|
|
40
|
+
const regex = createRoutePattern(withBasePath);
|
|
41
|
+
return regex.test(pathname);
|
|
42
|
+
});
|
|
43
|
+
if (endpoint) {
|
|
44
|
+
const withBasePath = config.basePath ? `${config.basePath}${endpoint.route}` : endpoint.route;
|
|
45
|
+
const body = await getBody(globalRequest, endpoint.config);
|
|
46
|
+
const params = getRouteParams(withBasePath, pathname);
|
|
47
|
+
const searchParams = getSearchParams(globalRequest.url, endpoint.config);
|
|
48
|
+
const headers = getHeaders(globalRequest);
|
|
49
|
+
const context = {
|
|
50
|
+
...ctx,
|
|
51
|
+
params,
|
|
52
|
+
searchParams,
|
|
53
|
+
headers,
|
|
54
|
+
body
|
|
55
|
+
};
|
|
56
|
+
await executeMiddlewares(globalRequest, context, endpoint.config.middlewares);
|
|
57
|
+
return endpoint.handler(globalRequest, context);
|
|
58
|
+
}
|
|
59
|
+
return Response.json({ message: "Not Found" }, { status: 404 });
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (error instanceof AuraStackRouterError) {
|
|
62
|
+
const { message, status, statusText } = error;
|
|
63
|
+
console.log("StatusText: ", statusText);
|
|
64
|
+
return Response.json({ message }, { status, statusText });
|
|
65
|
+
}
|
|
66
|
+
return Response.json({ message: "Internal Server Error" }, { status: 500 });
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return server;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
createRouter
|
|
75
|
+
};
|