@aura-stack/router 0.2.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/package.json CHANGED
@@ -1,8 +1,31 @@
1
1
  {
2
2
  "name": "@aura-stack/router",
3
- "version": "0.2.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
  ],
@@ -22,19 +45,13 @@
22
45
  "import": "./dist/endpoint.js",
23
46
  "require": "./dist/endpoint.cjs"
24
47
  },
48
+ "./error": {
49
+ "types": "./dist/error.d.ts",
50
+ "import": "./dist/error.js",
51
+ "require": "./dist/error.cjs"
52
+ },
25
53
  "./types": "./dist/types.d.ts"
26
54
  },
27
- "keywords": [
28
- "router",
29
- "endpoints",
30
- "api",
31
- "aura",
32
- "aura stack",
33
- "typescript",
34
- "nodejs"
35
- ],
36
- "author": "Aura Stack <auraauthoss@gmail.com> | Hernan Alvarado <hernanvid123@gmail.com>",
37
- "license": "MIT",
38
55
  "devDependencies": {
39
56
  "prettier": "^3.6.2",
40
57
  "tsup": "^8.5.0",
@@ -50,8 +67,10 @@
50
67
  "format:check": "prettier --check .",
51
68
  "test": "vitest --run",
52
69
  "test:watch": "vitest",
70
+ "test:bench": "vitest --run bench",
53
71
  "type-check": "tsc --noEmit",
54
72
  "clean": "rm -rf dist",
55
- "clean:cts": "rm -rf dist/*.cts"
73
+ "clean:cts": "rm -rf dist/*.cts",
74
+ "prepublish": "pnpm clean:cts"
56
75
  }
57
76
  }
package/dist/assert.d.cts DELETED
@@ -1,32 +0,0 @@
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 };
@@ -1,72 +0,0 @@
1
- import {
2
- getBody,
3
- getHeaders,
4
- getRouteParams,
5
- getSearchParams
6
- } from "./chunk-OXDCFAMF.js";
7
- import {
8
- createRoutePattern
9
- } from "./chunk-YUX3YHXF.js";
10
- import {
11
- executeGlobalMiddlewares,
12
- executeMiddlewares
13
- } from "./chunk-O6SY753N.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 = /* @__PURE__ */ new Map();
22
- for (const endpoint of endpoints) {
23
- if (!groups.has(endpoint.method)) {
24
- groups.set(endpoint.method, []);
25
- }
26
- groups.get(endpoint.method)?.push(endpoint);
27
- }
28
- for (const method of groups.keys()) {
29
- server[method] = async (request) => {
30
- try {
31
- const globalRequest = await executeGlobalMiddlewares(request, config.middlewares);
32
- if (globalRequest instanceof Response) {
33
- return globalRequest;
34
- }
35
- const url = new URL(globalRequest.url);
36
- const pathname = url.pathname;
37
- const endpoint = groups.get(method)?.find((endpoint2) => {
38
- const withBasePath = config.basePath ? `${config.basePath}${endpoint2.route}` : endpoint2.route;
39
- const regex = createRoutePattern(withBasePath);
40
- return regex.test(pathname);
41
- });
42
- if (endpoint) {
43
- const withBasePath = config.basePath ? `${config.basePath}${endpoint.route}` : endpoint.route;
44
- const body = await getBody(globalRequest, endpoint.config);
45
- const params = getRouteParams(withBasePath, pathname);
46
- const searchParams = getSearchParams(globalRequest.url, endpoint.config);
47
- const headers = getHeaders(globalRequest);
48
- const context = {
49
- params,
50
- searchParams,
51
- headers,
52
- body
53
- };
54
- await executeMiddlewares(globalRequest, context, endpoint.config.middlewares);
55
- return endpoint.handler(globalRequest, context);
56
- }
57
- return Response.json({ message: "Not Found" }, { status: 404 });
58
- } catch (error) {
59
- if (error instanceof AuraStackRouterError) {
60
- const { message, status, statusText } = error;
61
- return Response.json({ message }, { status, statusText });
62
- }
63
- return Response.json({ message: "Internal Server Error" }, { status: 500 });
64
- }
65
- };
66
- }
67
- return server;
68
- };
69
-
70
- export {
71
- createRouter
72
- };
@@ -1,41 +0,0 @@
1
- import {
2
- AuraStackRouterError
3
- } from "./chunk-RFYOPPMW.js";
4
-
5
- // src/middlewares.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
- };
@@ -1,78 +0,0 @@
1
- import {
2
- createRoutePattern
3
- } from "./chunk-YUX3YHXF.js";
4
- import {
5
- isSupportedBodyMethod
6
- } from "./chunk-JRJKKBSH.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
- };
@@ -1,36 +0,0 @@
1
- import {
2
- isSupportedMethod,
3
- isValidHandler,
4
- isValidRoute
5
- } from "./chunk-JRJKKBSH.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
- };
@@ -1,84 +0,0 @@
1
- import { RoutePattern, Params, EndpointConfig, ContextSearchParams } from './types.cjs';
2
- import 'zod';
3
-
4
- /**
5
- * Extracts route parameters from a given path using the specified route pattern.
6
- *
7
- * This function matches the provided path against the route pattern
8
- * (e.g., "/users/:userId/posts/:postId") and returns an object mapping parameter
9
- * names to their decoded values.
10
- *
11
- * @param route - The route pattern, typically defined in the endpoint configuration.
12
- * @param path - The actual request path to extract parameters from.
13
- * @returns An object containing the extracted route parameters as key-value pairs.
14
- *
15
- * @example
16
- * const route = "/users/:userId/posts/:postId";
17
- * const path = "/users/123/posts/456";
18
- *
19
- * // Expected: { userId: "123", postId: "456" }
20
- * const params = getRouteParams(route, path);
21
- */
22
- declare const getRouteParams: <Route extends RoutePattern>(route: Route, path: string) => Params<Route>;
23
- /**
24
- * Extracts and validates search parameters from a given URL from the request.
25
- *
26
- * If a schema is provided in the endpoint configuration, the search parameters
27
- * are validated against it using Zod and returned the parsed data. If validation
28
- * fails, an error is thrown. Otherwise, a URLSearchParams object is returned.
29
- *
30
- * @param url - The actual request URL to extract search parameters from.
31
- * @param config - Configuration object that may include a schema for validation.
32
- * @returns Either a URLSearchParams object or a parsed object based on the provided schema.
33
- * @example
34
- * // With schema
35
- * const url = "https://example.com/api?search=test&page=2";
36
- * const config: EndpointConfig = {
37
- * schemas: {
38
- * searchParams: z.object({
39
- * search: z.string(),
40
- * page: z.number().optional(),
41
- * }),
42
- * },
43
- * }
44
- *
45
- * // Expected: { search: "test", page: 2 }
46
- * const searchParams = getSearchParams(url, config);
47
- *
48
- * // Without schema
49
- * const url2 = "https://example.com/api?query=example";
50
- *
51
- * // Expected: URLSearchParams { 'query' => 'example' }
52
- * const searchParams2 = getSearchParams(url2, {} as EndpointConfig);
53
- */
54
- declare const getSearchParams: <Config extends EndpointConfig>(url: string, config: Config) => ContextSearchParams<Config["schemas"]>["searchParams"];
55
- /**
56
- * Extracts headers from the given Request object and returns them as a Headers instance.
57
- *
58
- * @param request - The Request object from which to extract headers.
59
- * @returns A Headers instance containing all headers from the request.
60
- * @example
61
- * const request = new Request("https://example.com/api", {
62
- * headers: {
63
- * "Content-Type": "application/json",
64
- * "Authorization": "Bearer token",
65
- * },
66
- * });
67
- * const headers = getHeaders(request);
68
- */
69
- declare const getHeaders: (request: Request) => Headers;
70
- /**
71
- * Extracts and parses the body of a Request object based on its Content-Type header.
72
- *
73
- * If a schema is provided in the endpoint configuration, the body is validated against
74
- * it using Zod and returned the parsed data. If validation fails, an error is thrown.
75
- *
76
- * In some cases, the browser includes text/plain;charset=UTF-8 as the default Content-Type
77
- *
78
- * @param request - The Request object from which to extract the body.
79
- * @param config - Configuration object that may include a schema for validation.
80
- * @returns The parsed body of the request or an error if validation fails.
81
- */
82
- declare const getBody: <Config extends EndpointConfig>(request: Request, config: Config) => Promise<any>;
83
-
84
- export { getBody, getHeaders, getRouteParams, getSearchParams };
@@ -1,59 +0,0 @@
1
- import { RoutePattern, HTTPMethod, EndpointSchemas, RouteHandler, EndpointConfig, RouteEndpoint } from './types.cjs';
2
- import 'zod';
3
-
4
- /**
5
- * Create a RegExp pattern from a route string. This function allows segment the
6
- * dynamic params in the route. For example, the route `/users/:id` will be
7
- * converted to a regex pattern that captures the `id` parameter.
8
- *
9
- * @param route - The route pattern string
10
- * @returns A RegExp object that matches the route pattern
11
- * @example
12
- * // Expected: /^\/users\/([^/]+)$/
13
- * const pattern = createRoutePattern("/users/:id");
14
- */
15
- declare const createRoutePattern: (route: RoutePattern) => RegExp;
16
- /**
17
- * Defines an API endpoint for the router by specifying the HTTP method, route pattern,
18
- * handler function, and optional configuration such as validation schemas or middlewares.
19
- * Validates all parameters for correctness. The resulting endpoint should be passed
20
- * to the `createRouter` function.
21
- *
22
- * @param method - The HTTP method (e.g., GET, POST, PUT, DELETE, PATCH)
23
- * @param route - The route pattern to associate with the endpoint (supports dynamic params)
24
- * @param handler - The function to handle requests matching the method and route
25
- * @param config - Optional configuration including validation schemas, middlewares, etc.
26
- * @returns An object representing the configured endpoint
27
- * @example
28
- * const signIn = createEndpoint("POST", "/auth/signin", async (req, ctx) => {
29
- * return new Response("Signed in");
30
- * });
31
- */
32
- declare const createEndpoint: <const Method extends Uppercase<HTTPMethod>, const Route extends RoutePattern, const Schemas extends EndpointSchemas>(method: Method, route: Route, handler: RouteHandler<Route, {
33
- schemas: Schemas;
34
- }>, config?: EndpointConfig<Route, Schemas>) => RouteEndpoint<Method, Route, {}>;
35
- /**
36
- * Create an endpoint configuration to be passed to the `createEndpoint` function.
37
- * This function is primarily for type inference and does not perform any runtime checks.
38
- *
39
- * @experimental
40
- * @param config - The endpoint configuration object
41
- * @returns The same configuration object, typed as EndpointConfig
42
- * @example
43
- * const config = createEndpointConfig({
44
- * middlewares: [myMiddleware],
45
- * schemas: {
46
- * searchParams: z.object({
47
- * q: z.string().min(3),
48
- * })
49
- * }
50
- * })
51
- *
52
- * const search = createEndpoint("GET", "/search", async (request, ctx) => {
53
- * return new Response("Search results");
54
- * }, config);
55
- */
56
- declare function createEndpointConfig<Schemas extends EndpointSchemas>(config: EndpointConfig<RoutePattern, Schemas>): EndpointConfig<RoutePattern, Schemas>;
57
- declare function createEndpointConfig<Route extends RoutePattern, S extends EndpointSchemas>(route: Route, config: EndpointConfig<Route, S>): EndpointConfig<Route, S>;
58
-
59
- export { createEndpoint, createEndpointConfig, createRoutePattern };
package/dist/error.d.cts DELETED
@@ -1,40 +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
- /**
31
- * Defines the errors used in AuraStack Router. Includes HTTP status code and
32
- * status text.
33
- */
34
- declare class AuraStackRouterError extends Error {
35
- readonly status: number;
36
- readonly statusText: keyof typeof statusCode;
37
- constructor(type: keyof typeof statusCode, message: string, name?: string);
38
- }
39
-
40
- export { AuraStackRouterError };
package/dist/index.d.cts DELETED
@@ -1,4 +0,0 @@
1
- export { createEndpoint, createEndpointConfig } from './endpoint.cjs';
2
- export { createRouter } from './router.cjs';
3
- export { ContentType, ContextBody, ContextSearchParams, EndpointConfig, EndpointSchemas, GetHttpHandlers, GetRouteParams, GlobalMiddleware, HTTPMethod, InferMethod, MiddlewareFunction, Params, Prettify, RequestContext, RouteEndpoint, RouteHandler, RoutePattern, RouterConfig } from './types.cjs';
4
- import 'zod';
@@ -1,22 +0,0 @@
1
- import { RouterConfig, EndpointConfig, RequestContext, MiddlewareFunction } from './types.cjs';
2
- import 'zod';
3
-
4
- /**
5
- * Executes the middlewares in sequence, passing the request to each middleware.
6
- *
7
- * @param request - Original request made from the client
8
- * @param middlewares - Array of global middleware functions to be executed
9
- * @returns - The modified request after all middlewares have been executed
10
- */
11
- declare const executeGlobalMiddlewares: (request: Request, middlewares: RouterConfig["middlewares"]) => Promise<Request | Response>;
12
- /**
13
- * Executes middlewares in sequence, passing the request and context to each middleware.
14
- *
15
- * @param request - Original request made from the client
16
- * @param context - Context object of the endpoint functionality
17
- * @param middlewares - Array of middleware functions to be executed
18
- * @returns The modified context after all middlewares have been executed
19
- */
20
- 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>>;
21
-
22
- export { executeGlobalMiddlewares, executeMiddlewares };
package/dist/router.d.cts DELETED
@@ -1,15 +0,0 @@
1
- import { RouteEndpoint, RouterConfig, GetHttpHandlers } from './types.cjs';
2
- import 'zod';
3
-
4
- /**
5
- * Creates the entry point for the server, handling the endpoints defined in the router.
6
- * It groups endpoints by HTTP method and matches incoming requests to the appropriate endpoint.
7
- * It accepts an optional configuration object to set a base path and middlewares for all endpoints.
8
- *
9
- * @param endpoints - Array of route endpoints to be handled by the router
10
- * @param config - Optional configuration object for the router
11
- * @returns An object with methods corresponding to HTTP methods, each handling requests for that method
12
- */
13
- declare const createRouter: <const Endpoints extends RouteEndpoint[]>(endpoints: Endpoints, config?: RouterConfig) => GetHttpHandlers<Endpoints>;
14
-
15
- export { createRouter };