@esportsplus/routing 0.6.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/.editorconfig +9 -0
- package/.gitattributes +2 -0
- package/.github/dependabot.yml +25 -0
- package/.github/workflows/bump.yml +9 -0
- package/.github/workflows/dependabot.yml +12 -0
- package/.github/workflows/publish.yml +16 -0
- package/README.md +217 -0
- package/build/client/constants.d.ts +9 -0
- package/build/client/constants.js +9 -0
- package/build/client/index.d.ts +17 -0
- package/build/client/index.js +143 -0
- package/build/client/router/index.d.ts +64 -0
- package/build/client/router/index.js +172 -0
- package/build/client/router/node.d.ts +18 -0
- package/build/client/router/node.js +80 -0
- package/build/client/types.d.ts +54 -0
- package/build/client/types.js +1 -0
- package/build/constants.d.ts +2 -0
- package/build/constants.js +2 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +1 -0
- package/package.json +38 -0
- package/src/client/constants.ts +22 -0
- package/src/client/index.ts +195 -0
- package/src/client/router/index.ts +294 -0
- package/src/client/router/node.ts +122 -0
- package/src/client/types.ts +105 -0
- package/src/constants.ts +4 -0
- package/src/index.ts +0 -0
- package/test/dist/test.js +1912 -0
- package/test/dist/test.js.map +1 -0
- package/test/index.ts +648 -0
- package/test/vite.config.ts +23 -0
- package/tsconfig.json +8 -0
package/.editorconfig
ADDED
package/.gitattributes
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
|
|
8
|
+
registries:
|
|
9
|
+
npm-npmjs:
|
|
10
|
+
token: ${{secrets.NPM_TOKEN}}
|
|
11
|
+
type: npm-registry
|
|
12
|
+
url: https://registry.npmjs.org
|
|
13
|
+
|
|
14
|
+
updates:
|
|
15
|
+
- package-ecosystem: "npm"
|
|
16
|
+
directory: "/"
|
|
17
|
+
groups:
|
|
18
|
+
production-dependencies:
|
|
19
|
+
dependency-type: "production"
|
|
20
|
+
development-dependencies:
|
|
21
|
+
dependency-type: "development"
|
|
22
|
+
registries:
|
|
23
|
+
- npm-npmjs
|
|
24
|
+
schedule:
|
|
25
|
+
interval: "daily"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
workflow_run:
|
|
8
|
+
workflows: [bump version]
|
|
9
|
+
types:
|
|
10
|
+
- completed
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
secrets:
|
|
15
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
16
|
+
uses: esportsplus/typescript/.github/workflows/publish.yml@main
|
package/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# @esportsplus/routing
|
|
2
|
+
|
|
3
|
+
Type-safe client-side router with radix tree matching, middleware pipelines, and reactive navigation.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @esportsplus/routing
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Type-safe route names and path parameters
|
|
14
|
+
- Radix tree matching (static > params > wildcards)
|
|
15
|
+
- Composable middleware pipeline
|
|
16
|
+
- Reactive navigation via `@esportsplus/reactivity`
|
|
17
|
+
- Named routes with URI generation
|
|
18
|
+
- Route factories for modular definitions
|
|
19
|
+
- Subdomain routing
|
|
20
|
+
- HTTP method routing (GET, POST, PUT, DELETE)
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Define Routes
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { router, Middleware, Next, Request, Route, RouteFactory } from '@esportsplus/routing/client';
|
|
28
|
+
|
|
29
|
+
type Response = HTMLElement;
|
|
30
|
+
|
|
31
|
+
// Route factory for modular definitions
|
|
32
|
+
const homeRoutes: RouteFactory<Response> = (r) => r
|
|
33
|
+
.get({
|
|
34
|
+
name: 'home',
|
|
35
|
+
path: '/',
|
|
36
|
+
responder: (req) => renderHome()
|
|
37
|
+
})
|
|
38
|
+
.get({
|
|
39
|
+
name: 'about',
|
|
40
|
+
path: '/about',
|
|
41
|
+
responder: (req) => renderAbout()
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const userRoutes: RouteFactory<Response> = (r) => r
|
|
45
|
+
.get({
|
|
46
|
+
name: 'user',
|
|
47
|
+
path: '/users/:id',
|
|
48
|
+
responder: (req) => renderUser(req.data.parameters?.id)
|
|
49
|
+
})
|
|
50
|
+
.get({
|
|
51
|
+
name: 'user.settings',
|
|
52
|
+
path: '/users/:id/settings',
|
|
53
|
+
middleware: [authMiddleware],
|
|
54
|
+
responder: (req) => renderSettings(req.data.parameters?.id)
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Create Router
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// Compose route factories
|
|
62
|
+
const app = router(homeRoutes, userRoutes);
|
|
63
|
+
|
|
64
|
+
// Navigate
|
|
65
|
+
app.redirect('home');
|
|
66
|
+
app.redirect('user', { id: 123 });
|
|
67
|
+
|
|
68
|
+
// Generate URIs
|
|
69
|
+
app.uri('user', { id: 456 }); // '#/users/456'
|
|
70
|
+
|
|
71
|
+
// History navigation
|
|
72
|
+
app.back();
|
|
73
|
+
app.forward();
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Middleware
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const authMiddleware: Middleware<Response> = (req, next) => {
|
|
80
|
+
if (!isAuthenticated()) {
|
|
81
|
+
return renderLogin();
|
|
82
|
+
}
|
|
83
|
+
return next(req);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const loggerMiddleware: Middleware<Response> = (req, next) => {
|
|
87
|
+
console.log(`${req.method} ${req.path}`);
|
|
88
|
+
return next(req);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Apply global middleware and dispatch
|
|
92
|
+
app.middleware(loggerMiddleware).dispatch;
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Reactive Matching
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// Create fallback route
|
|
99
|
+
const notFound: Route<Response> = {
|
|
100
|
+
name: 'not-found',
|
|
101
|
+
path: null,
|
|
102
|
+
pipeline: pipeline<Request<Response>, Response>(),
|
|
103
|
+
subdomain: null
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// Middleware that reactively matches routes
|
|
107
|
+
const matchMiddleware = app.middleware.match(notFound);
|
|
108
|
+
|
|
109
|
+
// Compose and dispatch
|
|
110
|
+
app.middleware(matchMiddleware, loggerMiddleware).dispatch;
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Route Groups
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const apiRoutes: RouteFactory<Response> = (r) => r
|
|
117
|
+
.group({
|
|
118
|
+
path: '/api/v1',
|
|
119
|
+
middleware: [apiAuth]
|
|
120
|
+
})
|
|
121
|
+
.routes((r) => r
|
|
122
|
+
.get({
|
|
123
|
+
name: 'api.users',
|
|
124
|
+
path: '/users',
|
|
125
|
+
responder: handleUsers
|
|
126
|
+
})
|
|
127
|
+
.post({
|
|
128
|
+
name: 'api.users.create',
|
|
129
|
+
path: '/users',
|
|
130
|
+
responder: handleCreateUser
|
|
131
|
+
})
|
|
132
|
+
);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Path Parameters
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// Required parameter
|
|
139
|
+
.get({ name: 'user', path: '/users/:id', responder })
|
|
140
|
+
|
|
141
|
+
// Optional parameter (prefix with ?)
|
|
142
|
+
.get({ name: 'archive', path: '/posts/?:year/?:month', responder })
|
|
143
|
+
|
|
144
|
+
// Wildcard (captures rest of path)
|
|
145
|
+
.get({ name: 'files', path: '/files/*:path', responder })
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Subdomain Routing
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
const adminRoutes: RouteFactory<Response> = (r) => r
|
|
152
|
+
.get({
|
|
153
|
+
name: 'admin.dashboard',
|
|
154
|
+
path: '/dashboard',
|
|
155
|
+
subdomain: 'admin',
|
|
156
|
+
responder: renderAdminDashboard
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Types
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
// Route factory function
|
|
164
|
+
type RouteFactory<T> = (router: Router<T, any>) => Router<T, RouteRegistry>;
|
|
165
|
+
|
|
166
|
+
// Middleware function
|
|
167
|
+
type Middleware<T> = (input: Request<T>, next: Next<T>) => T;
|
|
168
|
+
|
|
169
|
+
// Next function in middleware chain
|
|
170
|
+
type Next<T> = (input: Request<T>) => T;
|
|
171
|
+
|
|
172
|
+
// Request object
|
|
173
|
+
type Request<T> = {
|
|
174
|
+
data: Record<PropertyKey, unknown> & { parameters?: Record<string, unknown>; route?: Route<T> };
|
|
175
|
+
hostname: string;
|
|
176
|
+
href: string;
|
|
177
|
+
method: string;
|
|
178
|
+
origin: string;
|
|
179
|
+
path: string;
|
|
180
|
+
port: string;
|
|
181
|
+
protocol: string;
|
|
182
|
+
query: Record<string, unknown>;
|
|
183
|
+
subdomain?: string;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Route definition
|
|
187
|
+
type Route<T> = {
|
|
188
|
+
name: string | null;
|
|
189
|
+
path: string | null;
|
|
190
|
+
pipeline: Pipeline<Request<T>, T>;
|
|
191
|
+
subdomain: string | null;
|
|
192
|
+
};
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Route Matching Priority
|
|
196
|
+
|
|
197
|
+
1. **Static paths** - exact match (`/users`)
|
|
198
|
+
2. **Parameters** - dynamic segments (`/users/:id`)
|
|
199
|
+
3. **Wildcards** - catch-all (`/files/*:path`)
|
|
200
|
+
|
|
201
|
+
Static paths always take precedence over parameterized paths for the same position.
|
|
202
|
+
|
|
203
|
+
## Hash-Based Navigation
|
|
204
|
+
|
|
205
|
+
Routes use hash-based URLs (`#/path`) for client-side navigation without server configuration.
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
// URL: https://example.com/#/users/123?tab=profile
|
|
209
|
+
|
|
210
|
+
request.path // '/users/123'
|
|
211
|
+
request.query // { tab: 'profile' }
|
|
212
|
+
request.hostname // 'example.com'
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## License
|
|
216
|
+
|
|
217
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare const ON_DELETE: string[];
|
|
2
|
+
declare const ON_GET: string[];
|
|
3
|
+
declare const ON_POST: string[];
|
|
4
|
+
declare const ON_PUT: string[];
|
|
5
|
+
declare const PARAMETER = 0;
|
|
6
|
+
declare const STATIC = 1;
|
|
7
|
+
declare const WILDCARD = 2;
|
|
8
|
+
export { ON_DELETE, ON_GET, ON_POST, ON_PUT, PARAMETER, STATIC, WILDCARD };
|
|
9
|
+
export { PACKAGE_NAME } from '../constants.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const ON_DELETE = ['DELETE'];
|
|
2
|
+
const ON_GET = ['GET'];
|
|
3
|
+
const ON_POST = ['POST'];
|
|
4
|
+
const ON_PUT = ['PUT'];
|
|
5
|
+
const PARAMETER = 0;
|
|
6
|
+
const STATIC = 1;
|
|
7
|
+
const WILDCARD = 2;
|
|
8
|
+
export { ON_DELETE, ON_GET, ON_POST, ON_PUT, PARAMETER, STATIC, WILDCARD };
|
|
9
|
+
export { PACKAGE_NAME } from '../constants.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AccumulateRoutes, ExtractOptionalParams, ExtractRequiredParams, InferOutput, Middleware, Next, PathParamsObject, Request, Route, RouteFactory, RoutePath } from './types.js';
|
|
2
|
+
declare function back(): void;
|
|
3
|
+
declare function forward(): void;
|
|
4
|
+
declare const router: <const Factories extends readonly RouteFactory<any>[]>(...factories: Factories) => {
|
|
5
|
+
back: typeof back;
|
|
6
|
+
forward: typeof forward;
|
|
7
|
+
middleware: {
|
|
8
|
+
(...stages: Middleware<InferOutput<Factories[number]>>[]): InferOutput<Factories[number]>;
|
|
9
|
+
dispatch(request: Request<InferOutput<Factories[number]>>): InferOutput<Factories[number]>;
|
|
10
|
+
match(fallback: Route<InferOutput<Factories[number]>>): (request: Request<InferOutput<Factories[number]>>, next: Next<InferOutput<Factories[number]>>) => InferOutput<Factories[number]>;
|
|
11
|
+
};
|
|
12
|
+
redirect: <RouteName extends keyof AccumulateRoutes<Factories>>(name: RouteName, ...values: ExtractRequiredParams<RoutePath<AccumulateRoutes<Factories>, RouteName>> extends never ? ExtractOptionalParams<RoutePath<AccumulateRoutes<Factories>, RouteName>> extends never ? [] : [params?: PathParamsObject<RoutePath<AccumulateRoutes<Factories>, RouteName>>] : [params: PathParamsObject<RoutePath<AccumulateRoutes<Factories>, RouteName>>]) => void;
|
|
13
|
+
routes: Record<string, Route<InferOutput<Factories[number]>>>;
|
|
14
|
+
uri: <RouteName extends keyof AccumulateRoutes<Factories>>(name: RouteName, ...values: ExtractRequiredParams<RoutePath<AccumulateRoutes<Factories>, RouteName>> extends never ? ExtractOptionalParams<RoutePath<AccumulateRoutes<Factories>, RouteName>> extends never ? [] : [params?: PathParamsObject<RoutePath<AccumulateRoutes<Factories>, RouteName>>] : [params: PathParamsObject<RoutePath<AccumulateRoutes<Factories>, RouteName>>]) => string;
|
|
15
|
+
};
|
|
16
|
+
export { router };
|
|
17
|
+
export type { Middleware, Next, Request, Route, RouteFactory } from './types.js';
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import * as reactivity_fa31f85817714b2e94bba1bba5e367420 from '@esportsplus/reactivity';
|
|
2
|
+
import { effect, root } from '@esportsplus/reactivity';
|
|
3
|
+
import { Router } from './router/index.js';
|
|
4
|
+
import pipeline from '@esportsplus/pipeline';
|
|
5
|
+
import { PACKAGE_NAME } from './constants.js';
|
|
6
|
+
class ReactiveObject_fa31f85817714b2e94bba1bba5e367421 extends reactivity_fa31f85817714b2e94bba1bba5e367420.ReactiveObject {
|
|
7
|
+
#parameters;
|
|
8
|
+
#route;
|
|
9
|
+
constructor(_p0, _p1) {
|
|
10
|
+
super(null);
|
|
11
|
+
this.#parameters = this[reactivity_fa31f85817714b2e94bba1bba5e367420.SIGNAL](_p0);
|
|
12
|
+
this.#route = this[reactivity_fa31f85817714b2e94bba1bba5e367420.SIGNAL](_p1);
|
|
13
|
+
}
|
|
14
|
+
get parameters() {
|
|
15
|
+
return reactivity_fa31f85817714b2e94bba1bba5e367420.read(this.#parameters);
|
|
16
|
+
}
|
|
17
|
+
set parameters(_v0) {
|
|
18
|
+
reactivity_fa31f85817714b2e94bba1bba5e367420.write(this.#parameters, _v0);
|
|
19
|
+
}
|
|
20
|
+
get route() {
|
|
21
|
+
return reactivity_fa31f85817714b2e94bba1bba5e367420.read(this.#route);
|
|
22
|
+
}
|
|
23
|
+
set route(_v1) {
|
|
24
|
+
reactivity_fa31f85817714b2e94bba1bba5e367420.write(this.#route, _v1);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
let cache = [], location = window.location;
|
|
28
|
+
function back() {
|
|
29
|
+
window.history.back();
|
|
30
|
+
}
|
|
31
|
+
function forward() {
|
|
32
|
+
window.history.forward();
|
|
33
|
+
}
|
|
34
|
+
function href() {
|
|
35
|
+
let hash = location.hash || '#/', path = hash ? hash.slice(1).split('?') : ['/', ''], request = {
|
|
36
|
+
hostname: location.hostname,
|
|
37
|
+
href: location.href,
|
|
38
|
+
method: 'GET',
|
|
39
|
+
origin: location.origin,
|
|
40
|
+
path: path[0],
|
|
41
|
+
port: location.port,
|
|
42
|
+
protocol: location.protocol,
|
|
43
|
+
query: {}
|
|
44
|
+
};
|
|
45
|
+
if (path[1]) {
|
|
46
|
+
let params = new URLSearchParams(path[1]), query = request.query;
|
|
47
|
+
for (let [key, value] of params.entries()) {
|
|
48
|
+
query[key] = value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return request;
|
|
52
|
+
}
|
|
53
|
+
function match(request, router, subdomain) {
|
|
54
|
+
if (router.subdomains !== null) {
|
|
55
|
+
let hostname = request.hostname, subdomains = router.subdomains;
|
|
56
|
+
for (let i = 0, n = subdomains.length; i < n; i++) {
|
|
57
|
+
if (!hostname.startsWith(subdomains[i])) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
subdomain = subdomains[i];
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return router.match(request.method, request.path, subdomain || '');
|
|
65
|
+
}
|
|
66
|
+
function middleware(request, router) {
|
|
67
|
+
let middleware = pipeline();
|
|
68
|
+
function host(...stages) {
|
|
69
|
+
for (let i = 0, n = stages.length; i < n; i++) {
|
|
70
|
+
middleware.add(stages[i]);
|
|
71
|
+
}
|
|
72
|
+
return middleware.dispatch(request);
|
|
73
|
+
}
|
|
74
|
+
;
|
|
75
|
+
host.dispatch = (request) => {
|
|
76
|
+
let { route } = request.data;
|
|
77
|
+
if (route === undefined) {
|
|
78
|
+
throw new Error(`${PACKAGE_NAME}: route is undefined!`);
|
|
79
|
+
}
|
|
80
|
+
return route.pipeline.dispatch(request);
|
|
81
|
+
};
|
|
82
|
+
host.match = (fallback) => {
|
|
83
|
+
let state = new ReactiveObject_fa31f85817714b2e94bba1bba5e367421(undefined, undefined);
|
|
84
|
+
if (fallback === undefined) {
|
|
85
|
+
throw new Error(`${PACKAGE_NAME}: fallback route does not exist`);
|
|
86
|
+
}
|
|
87
|
+
effect(() => {
|
|
88
|
+
let { parameters, route } = match(request, router);
|
|
89
|
+
state.parameters = parameters;
|
|
90
|
+
state.route = route || fallback;
|
|
91
|
+
});
|
|
92
|
+
return (request, next) => {
|
|
93
|
+
if (state.route === undefined) {
|
|
94
|
+
throw new Error(`${PACKAGE_NAME}: route is undefined`);
|
|
95
|
+
}
|
|
96
|
+
return root(() => {
|
|
97
|
+
request.data = {
|
|
98
|
+
parameters: state.parameters,
|
|
99
|
+
route: state.route
|
|
100
|
+
};
|
|
101
|
+
return next(request);
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
return host;
|
|
106
|
+
}
|
|
107
|
+
function normalize(uri) {
|
|
108
|
+
if (uri[0] === '/') {
|
|
109
|
+
return '#' + uri;
|
|
110
|
+
}
|
|
111
|
+
return uri;
|
|
112
|
+
}
|
|
113
|
+
function onpopstate() {
|
|
114
|
+
let values = href();
|
|
115
|
+
for (let i = 0, n = cache.length; i < n; i++) {
|
|
116
|
+
let state = cache[i];
|
|
117
|
+
for (let key in values) {
|
|
118
|
+
state[key] = values[key];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const router = (...factories) => {
|
|
123
|
+
let instance = factories.reduce((r, factory) => factory(r), new Router()), request = reactivity_fa31f85817714b2e94bba1bba5e367420.reactive(Object.assign(href(), { data: {} }));
|
|
124
|
+
if (cache.push(request) === 1) {
|
|
125
|
+
window.addEventListener('hashchange', onpopstate);
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
back,
|
|
129
|
+
forward,
|
|
130
|
+
middleware: middleware(request, instance),
|
|
131
|
+
redirect: (name, ...values) => {
|
|
132
|
+
if (name.indexOf('://') !== -1) {
|
|
133
|
+
return window.location.replace(name);
|
|
134
|
+
}
|
|
135
|
+
window.location.hash = normalize(instance.uri(name, values));
|
|
136
|
+
},
|
|
137
|
+
routes: instance.routes,
|
|
138
|
+
uri: (name, ...values) => {
|
|
139
|
+
return normalize(instance.uri(name, values));
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
export { router };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Route, Name, Options, PathParamsTuple, RouteOptions, RouteRegistry } from '../types.js';
|
|
2
|
+
import { Node } from './node.js';
|
|
3
|
+
declare function key(method: string, subdomain?: string | null): string;
|
|
4
|
+
declare class Router<T, TRoutes extends RouteRegistry = {}> {
|
|
5
|
+
bucket: Record<ReturnType<typeof key>, {
|
|
6
|
+
root: Node<T>;
|
|
7
|
+
static: Record<string, Route<T>>;
|
|
8
|
+
}>;
|
|
9
|
+
groups: Options<T>[];
|
|
10
|
+
routes: Record<Name, Route<T>>;
|
|
11
|
+
subdomains: string[] | null;
|
|
12
|
+
private add;
|
|
13
|
+
private create;
|
|
14
|
+
delete<RouteName extends string = string, RoutePath extends string = string>(options: RouteOptions<T> & {
|
|
15
|
+
name?: RouteName;
|
|
16
|
+
path?: RoutePath;
|
|
17
|
+
}): Router<T, TRoutes & (RouteName extends string ? RoutePath extends string ? {
|
|
18
|
+
[K in RouteName]: {
|
|
19
|
+
path: RoutePath;
|
|
20
|
+
};
|
|
21
|
+
} : TRoutes : TRoutes)>;
|
|
22
|
+
get<RouteName extends string = string, RoutePath extends string = string>(options: RouteOptions<T> & {
|
|
23
|
+
name?: RouteName;
|
|
24
|
+
path?: RoutePath;
|
|
25
|
+
}): Router<T, TRoutes & (RouteName extends string ? RoutePath extends string ? {
|
|
26
|
+
[K in RouteName]: {
|
|
27
|
+
path: RoutePath;
|
|
28
|
+
};
|
|
29
|
+
} : TRoutes : TRoutes)>;
|
|
30
|
+
group(options: Options<T>): {
|
|
31
|
+
routes: (fn: (router: Router<T, TRoutes>) => void) => Router<T, TRoutes>;
|
|
32
|
+
};
|
|
33
|
+
match(method: string, path: string, subdomain?: string | null): {
|
|
34
|
+
parameters?: Readonly<Record<PropertyKey, unknown>>;
|
|
35
|
+
route?: Readonly<Route<T>> | undefined;
|
|
36
|
+
};
|
|
37
|
+
on<RouteName extends string = string, RoutePath extends string = string>(methods: string[], options: RouteOptions<T> & {
|
|
38
|
+
name?: RouteName;
|
|
39
|
+
path?: RoutePath;
|
|
40
|
+
}): Router<T, TRoutes & (RouteName extends string ? RoutePath extends string ? {
|
|
41
|
+
[K in RouteName]: {
|
|
42
|
+
path: RoutePath;
|
|
43
|
+
};
|
|
44
|
+
} : TRoutes : TRoutes)>;
|
|
45
|
+
post<RouteName extends string = string, RoutePath extends string = string>(options: RouteOptions<T> & {
|
|
46
|
+
name?: RouteName;
|
|
47
|
+
path?: RoutePath;
|
|
48
|
+
}): Router<T, TRoutes & (RouteName extends string ? RoutePath extends string ? {
|
|
49
|
+
[K in RouteName]: {
|
|
50
|
+
path: RoutePath;
|
|
51
|
+
};
|
|
52
|
+
} : TRoutes : TRoutes)>;
|
|
53
|
+
put<RouteName extends string = string, RoutePath extends string = string>(options: RouteOptions<T> & {
|
|
54
|
+
name?: RouteName;
|
|
55
|
+
path?: RoutePath;
|
|
56
|
+
}): Router<T, TRoutes & (RouteName extends string ? RoutePath extends string ? {
|
|
57
|
+
[K in RouteName]: {
|
|
58
|
+
path: RoutePath;
|
|
59
|
+
};
|
|
60
|
+
} : TRoutes : TRoutes)>;
|
|
61
|
+
uri<RouteName extends keyof TRoutes & string>(name: RouteName, values?: PathParamsTuple<TRoutes[RouteName]['path']>): string;
|
|
62
|
+
}
|
|
63
|
+
export { Router };
|
|
64
|
+
export type { Route };
|