@jsango/router 1.0.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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +8 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/internal/path-utils.d.ts +5 -0
  8. package/dist/internal/path-utils.d.ts.map +1 -0
  9. package/dist/internal/path-utils.js +40 -0
  10. package/dist/internal/path-utils.js.map +1 -0
  11. package/dist/internal/radix-node.d.ts +20 -0
  12. package/dist/internal/radix-node.d.ts.map +1 -0
  13. package/dist/internal/radix-node.js +11 -0
  14. package/dist/internal/radix-node.js.map +1 -0
  15. package/dist/internal/radix-tree.d.ts +14 -0
  16. package/dist/internal/radix-tree.d.ts.map +1 -0
  17. package/dist/internal/radix-tree.js +272 -0
  18. package/dist/internal/radix-tree.js.map +1 -0
  19. package/dist/public/constraints.d.ts +5 -0
  20. package/dist/public/constraints.d.ts.map +1 -0
  21. package/dist/public/constraints.js +35 -0
  22. package/dist/public/constraints.js.map +1 -0
  23. package/dist/public/errors.d.ts +20 -0
  24. package/dist/public/errors.d.ts.map +1 -0
  25. package/dist/public/errors.js +48 -0
  26. package/dist/public/errors.js.map +1 -0
  27. package/dist/public/group.d.ts +29 -0
  28. package/dist/public/group.d.ts.map +1 -0
  29. package/dist/public/group.js +75 -0
  30. package/dist/public/group.js.map +1 -0
  31. package/dist/public/index.d.ts +8 -0
  32. package/dist/public/index.d.ts.map +1 -0
  33. package/dist/public/index.js +8 -0
  34. package/dist/public/index.js.map +1 -0
  35. package/dist/public/result.d.ts +24 -0
  36. package/dist/public/result.d.ts.map +1 -0
  37. package/dist/public/result.js +10 -0
  38. package/dist/public/result.js.map +1 -0
  39. package/dist/public/route.d.ts +26 -0
  40. package/dist/public/route.d.ts.map +1 -0
  41. package/dist/public/route.js +31 -0
  42. package/dist/public/route.js.map +1 -0
  43. package/dist/public/router-interface.d.ts +19 -0
  44. package/dist/public/router-interface.d.ts.map +1 -0
  45. package/dist/public/router-interface.js +2 -0
  46. package/dist/public/router-interface.js.map +1 -0
  47. package/dist/public/router.d.ts +37 -0
  48. package/dist/public/router.d.ts.map +1 -0
  49. package/dist/public/router.js +210 -0
  50. package/dist/public/router.js.map +1 -0
  51. package/package.json +35 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group.d.ts","sourceRoot":"","sources":["../../src/public/group.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACxD,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,CAAC;CACtD;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACxD,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,CAAC;CACtD;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IACjC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5D,SAAgB,UAAU,EAAE,SAAS,OAAO,EAAE,CAAC;gBAEnC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB;IAOrE,KAAK,CACV,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,EACrB,OAAO,GAAE,YAAiB,GACzB,KAAK;IAcD,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI3E,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI5E,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI3E,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI7E,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI9E,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI5E,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI/E,KAAK,CACV,cAAc,EAAE,MAAM,GAAG,gBAAgB,EACzC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,EACrC,OAAO,GAAE,iBAAsB,GAC9B,IAAI;CA4BR"}
@@ -0,0 +1,75 @@
1
+ import { joinPaths } from '../internal/path-utils.js';
2
+ export class RouteGroup {
3
+ router;
4
+ prefix;
5
+ metadata;
6
+ middleware;
7
+ constructor(router, prefix, options = {}) {
8
+ this.router = router;
9
+ this.prefix = prefix;
10
+ this.metadata = Object.freeze({ ...(options.metadata ?? {}) });
11
+ this.middleware = Object.freeze([...(options.middleware ?? [])]);
12
+ }
13
+ route(method, path, handler, options = {}) {
14
+ const fullPath = joinPaths(this.prefix, path);
15
+ const mergedMetadata = {
16
+ ...this.metadata,
17
+ ...(options.metadata ?? {}),
18
+ };
19
+ const mergedMiddleware = [...this.middleware, ...(options.middleware ?? [])];
20
+ return this.router.route(method, fullPath, handler, {
21
+ ...options,
22
+ metadata: mergedMetadata,
23
+ middleware: mergedMiddleware,
24
+ });
25
+ }
26
+ get(path, handler, options = {}) {
27
+ return this.route('GET', path, handler, options);
28
+ }
29
+ post(path, handler, options = {}) {
30
+ return this.route('POST', path, handler, options);
31
+ }
32
+ put(path, handler, options = {}) {
33
+ return this.route('PUT', path, handler, options);
34
+ }
35
+ patch(path, handler, options = {}) {
36
+ return this.route('PATCH', path, handler, options);
37
+ }
38
+ delete(path, handler, options = {}) {
39
+ return this.route('DELETE', path, handler, options);
40
+ }
41
+ head(path, handler, options = {}) {
42
+ return this.route('HEAD', path, handler, options);
43
+ }
44
+ options(path, handler, options = {}) {
45
+ return this.route('OPTIONS', path, handler, options);
46
+ }
47
+ group(prefixOrConfig, callback, options = {}) {
48
+ let subPrefix;
49
+ let groupMetadata = {};
50
+ let groupMiddleware = [];
51
+ if (typeof prefixOrConfig === 'string') {
52
+ subPrefix = prefixOrConfig;
53
+ groupMetadata = options.metadata ?? {};
54
+ groupMiddleware = options.middleware ?? [];
55
+ }
56
+ else {
57
+ subPrefix = prefixOrConfig.prefix;
58
+ groupMetadata = prefixOrConfig.metadata ?? {};
59
+ groupMiddleware = prefixOrConfig.middleware ?? [];
60
+ }
61
+ const fullPrefix = joinPaths(this.prefix, subPrefix);
62
+ const mergedMetadata = {
63
+ ...this.metadata,
64
+ ...groupMetadata,
65
+ };
66
+ const mergedMiddleware = [...this.middleware, ...groupMiddleware];
67
+ const subGroup = new RouteGroup(this.router, fullPrefix, {
68
+ metadata: mergedMetadata,
69
+ middleware: mergedMiddleware,
70
+ });
71
+ callback(subGroup);
72
+ return this;
73
+ }
74
+ }
75
+ //# sourceMappingURL=group.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group.js","sourceRoot":"","sources":["../../src/public/group.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export * from './errors.js';
2
+ export * from './constraints.js';
3
+ export * from './route.js';
4
+ export * from './result.js';
5
+ export * from './group.js';
6
+ export * from './router-interface.js';
7
+ export * from './router.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/public/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC"}
@@ -0,0 +1,8 @@
1
+ export * from './errors.js';
2
+ export * from './constraints.js';
3
+ export * from './route.js';
4
+ export * from './result.js';
5
+ export * from './group.js';
6
+ export * from './router-interface.js';
7
+ export * from './router.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/public/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { HttpMethod } from '@jsango/http';
2
+ import type { Route, RouteHandler } from './route.js';
3
+ export interface RouteMatch {
4
+ readonly type: 'MATCHED';
5
+ readonly route: Route;
6
+ readonly handler: RouteHandler;
7
+ readonly params: Readonly<Record<string, string>>;
8
+ readonly metadata: Readonly<Record<string, unknown>>;
9
+ readonly isHeadFallback?: boolean | undefined;
10
+ }
11
+ export interface MethodNotAllowedMatch {
12
+ readonly type: 'METHOD_NOT_ALLOWED';
13
+ readonly allowedMethods: readonly HttpMethod[];
14
+ readonly pathname: string;
15
+ }
16
+ export interface NotFoundMatch {
17
+ readonly type: 'NOT_FOUND';
18
+ readonly pathname: string;
19
+ }
20
+ export type RouteMatchResult = RouteMatch | MethodNotAllowedMatch | NotFoundMatch;
21
+ export declare function isRouteMatch(result: RouteMatchResult): result is RouteMatch;
22
+ export declare function isMethodNotAllowedMatch(result: RouteMatchResult): result is MethodNotAllowedMatch;
23
+ export declare function isNotFoundMatch(result: RouteMatchResult): result is NotFoundMatch;
24
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../src/public/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,qBAAqB,GAAG,aAAa,CAAC;AAElF,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,IAAI,UAAU,CAE3E;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,IAAI,qBAAqB,CAEjG;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,IAAI,aAAa,CAEjF"}
@@ -0,0 +1,10 @@
1
+ export function isRouteMatch(result) {
2
+ return result.type === 'MATCHED';
3
+ }
4
+ export function isMethodNotAllowedMatch(result) {
5
+ return result.type === 'METHOD_NOT_ALLOWED';
6
+ }
7
+ export function isNotFoundMatch(result) {
8
+ return result.type === 'NOT_FOUND';
9
+ }
10
+ //# sourceMappingURL=result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/public/result.ts"],"names":[],"mappings":"AAyBA,MAAM,UAAU,YAAY,CAAC,MAAwB;IACnD,OAAO,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,MAAwB;IAC9D,OAAO,MAAM,CAAC,IAAI,KAAK,oBAAoB,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAwB;IACtD,OAAO,MAAM,CAAC,IAAI,KAAK,WAAW,CAAC;AACrC,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { HttpMethod, HttpResponse, RequestContext } from '@jsango/http';
2
+ import type { RouteConstraintDefinition } from './constraints.js';
3
+ export type RouteHandler = (ctx: RequestContext) => Promise<HttpResponse | unknown> | HttpResponse | unknown;
4
+ export interface RouteOptions {
5
+ readonly name?: string | undefined;
6
+ readonly metadata?: Record<string, unknown> | undefined;
7
+ readonly constraints?: Record<string, RouteConstraintDefinition> | undefined;
8
+ readonly middleware?: readonly unknown[] | undefined;
9
+ }
10
+ export declare class Route {
11
+ readonly method: HttpMethod;
12
+ readonly path: string;
13
+ readonly handler: RouteHandler;
14
+ readonly metadata: Readonly<Record<string, unknown>>;
15
+ readonly constraints: Readonly<Record<string, RouteConstraintDefinition>>;
16
+ readonly paramNames: readonly string[];
17
+ readonly middleware: readonly unknown[];
18
+ private _name?;
19
+ constructor(method: HttpMethod, path: string, handler: RouteHandler, options?: RouteOptions, paramNames?: readonly string[]);
20
+ get routeName(): string | undefined;
21
+ /**
22
+ * Fluent method to assign or update the route's unique name.
23
+ */
24
+ name(name: string): this;
25
+ }
26
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/public/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAElE,MAAM,MAAM,YAAY,GAAG,CACzB,GAAG,EAAE,cAAc,KAChB,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,GAAG,YAAY,GAAG,OAAO,CAAC;AAE9D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACxD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,GAAG,SAAS,CAAC;IAC7E,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,CAAC;CACtD;AAED,qBAAa,KAAK;IAChB,SAAgB,MAAM,EAAE,UAAU,CAAC;IACnC,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,OAAO,EAAE,YAAY,CAAC;IACtC,SAAgB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5D,SAAgB,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC,CAAC;IACjF,SAAgB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,SAAgB,UAAU,EAAE,SAAS,OAAO,EAAE,CAAC;IAC/C,OAAO,CAAC,KAAK,CAAC,CAAqB;gBAGjC,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,EACrB,OAAO,GAAE,YAAiB,EAC1B,UAAU,GAAE,SAAS,MAAM,EAAO;IAYpC,IAAW,SAAS,IAAI,MAAM,GAAG,SAAS,CAEzC;IAED;;OAEG;IACI,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;CAIhC"}
@@ -0,0 +1,31 @@
1
+ export class Route {
2
+ method;
3
+ path;
4
+ handler;
5
+ metadata;
6
+ constraints;
7
+ paramNames;
8
+ middleware;
9
+ _name;
10
+ constructor(method, path, handler, options = {}, paramNames = []) {
11
+ this.method = method;
12
+ this.path = path;
13
+ this.handler = handler;
14
+ this._name = options.name;
15
+ this.metadata = Object.freeze({ ...(options.metadata ?? {}) });
16
+ this.constraints = Object.freeze({ ...(options.constraints ?? {}) });
17
+ this.paramNames = Object.freeze([...paramNames]);
18
+ this.middleware = Object.freeze([...(options.middleware ?? [])]);
19
+ }
20
+ get routeName() {
21
+ return this._name;
22
+ }
23
+ /**
24
+ * Fluent method to assign or update the route's unique name.
25
+ */
26
+ name(name) {
27
+ this._name = name;
28
+ return this;
29
+ }
30
+ }
31
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/public/route.ts"],"names":[],"mappings":"AAcA,MAAM,OAAO,KAAK;IACA,MAAM,CAAa;IACnB,IAAI,CAAS;IACb,OAAO,CAAe;IACtB,QAAQ,CAAoC;IAC5C,WAAW,CAAsD;IACjE,UAAU,CAAoB;IAC9B,UAAU,CAAqB;IACvC,KAAK,CAAsB;IAEnC,YACE,MAAkB,EAClB,IAAY,EACZ,OAAqB,EACrB,UAAwB,EAAE,EAC1B,aAAgC,EAAE;QAElC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QACrE,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;QACjD,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACnE,CAAC;IAED,IAAW,SAAS;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;OAEG;IACI,IAAI,CAAC,IAAY;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ import type { HttpMethod } from '@jsango/http';
2
+ import type { Route, RouteHandler, RouteOptions } from './route.js';
3
+ import type { RouteGroup, RouteGroupConfig, RouteGroupOptions } from './group.js';
4
+ import type { RouteMatchResult } from './result.js';
5
+ export interface IRouter {
6
+ route(method: HttpMethod, path: string, handler: RouteHandler, options?: RouteOptions): Route;
7
+ get(path: string, handler: RouteHandler, options?: RouteOptions): Route;
8
+ post(path: string, handler: RouteHandler, options?: RouteOptions): Route;
9
+ put(path: string, handler: RouteHandler, options?: RouteOptions): Route;
10
+ patch(path: string, handler: RouteHandler, options?: RouteOptions): Route;
11
+ delete(path: string, handler: RouteHandler, options?: RouteOptions): Route;
12
+ head(path: string, handler: RouteHandler, options?: RouteOptions): Route;
13
+ options(path: string, handler: RouteHandler, options?: RouteOptions): Route;
14
+ group(prefixOrConfig: string | RouteGroupConfig, callback: (group: RouteGroup) => void, options?: RouteGroupOptions): this;
15
+ match(method: HttpMethod, path: string): RouteMatchResult;
16
+ routes(): readonly Route[];
17
+ url(name: string, params?: Record<string, string | number>): string;
18
+ }
19
+ //# sourceMappingURL=router-interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router-interface.d.ts","sourceRoot":"","sources":["../../src/public/router-interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,WAAW,OAAO;IACtB,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IAC9F,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IACxE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IACzE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IACxE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IAC1E,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IAC3E,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IACzE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IAC5E,KAAK,CACH,cAAc,EAAE,MAAM,GAAG,gBAAgB,EACzC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,EACrC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,IAAI,CAAC;IACR,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC1D,MAAM,IAAI,SAAS,KAAK,EAAE,CAAC;IAC3B,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC;CACrE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=router-interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router-interface.js","sourceRoot":"","sources":["../../src/public/router-interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import type { HttpMethod, RequestContext } from '@jsango/http';
2
+ import { HttpResponse } from '@jsango/http';
3
+ import { Route, type RouteHandler, type RouteOptions } from './route.js';
4
+ import { RouteGroup, type RouteGroupConfig, type RouteGroupOptions } from './group.js';
5
+ import type { IRouter } from './router-interface.js';
6
+ import type { RouteMatchResult } from './result.js';
7
+ export type RouterState = 'registering' | 'compiled' | 'locked';
8
+ export declare class Router implements IRouter {
9
+ private readonly tree;
10
+ private readonly registeredRoutes;
11
+ private readonly namedRoutes;
12
+ private _state;
13
+ get state(): RouterState;
14
+ get isLocked(): boolean;
15
+ compile(): this;
16
+ lock(): this;
17
+ private assertNotLocked;
18
+ route(method: HttpMethod, path: string, handler: RouteHandler, options?: RouteOptions): Route;
19
+ private registerRouteName;
20
+ get(path: string, handler: RouteHandler, options?: RouteOptions): Route;
21
+ post(path: string, handler: RouteHandler, options?: RouteOptions): Route;
22
+ put(path: string, handler: RouteHandler, options?: RouteOptions): Route;
23
+ patch(path: string, handler: RouteHandler, options?: RouteOptions): Route;
24
+ delete(path: string, handler: RouteHandler, options?: RouteOptions): Route;
25
+ head(path: string, handler: RouteHandler, options?: RouteOptions): Route;
26
+ options(path: string, handler: RouteHandler, options?: RouteOptions): Route;
27
+ group(prefixOrConfig: string | RouteGroupConfig, callback: (group: RouteGroup) => void, options?: RouteGroupOptions): this;
28
+ match(method: HttpMethod, path: string): RouteMatchResult;
29
+ routes(): readonly Route[];
30
+ getRouteByName(name: string): Route | undefined;
31
+ url(name: string, params?: Record<string, string | number>): string;
32
+ /**
33
+ * Dispatches a RequestContext against the route table and returns the resulting HttpResponse.
34
+ */
35
+ handle(ctx: RequestContext): Promise<HttpResponse>;
36
+ }
37
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/public/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAc,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACvF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAUpD,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEhE,qBAAa,MAAO,YAAW,OAAO;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmB;IACxC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAe;IAChD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA4B;IACxD,OAAO,CAAC,MAAM,CAA8B;IAE5C,IAAW,KAAK,IAAI,WAAW,CAE9B;IAED,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAEM,OAAO,IAAI,IAAI;IAQf,IAAI,IAAI,IAAI;IAInB,OAAO,CAAC,eAAe;IAMhB,KAAK,CACV,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,EACrB,OAAO,GAAE,YAAiB,GACzB,KAAK;IAsBR,OAAO,CAAC,iBAAiB;IAQlB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI3E,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI5E,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI3E,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI7E,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI9E,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI5E,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK;IAI/E,KAAK,CACV,cAAc,EAAE,MAAM,GAAG,gBAAgB,EACzC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,EACrC,OAAO,GAAE,iBAAsB,GAC9B,IAAI;IAwBA,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB;IAIzD,MAAM,IAAI,SAAS,KAAK,EAAE;IAI1B,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAI/C,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAM,GAAG,MAAM;IAsE9E;;OAEG;IACU,MAAM,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;CAsDhE"}
@@ -0,0 +1,210 @@
1
+ import { HttpResponse, HttpStatus } from '@jsango/http';
2
+ import { Route } from './route.js';
3
+ import { RouteGroup } from './group.js';
4
+ import { RadixTree } from '../internal/radix-tree.js';
5
+ import { normalizePath } from '../internal/path-utils.js';
6
+ import { DuplicateRouteNameError, RouteNotFoundError, RouterLockedError, InvalidRoutePatternError, } from './errors.js';
7
+ export class Router {
8
+ tree = new RadixTree();
9
+ registeredRoutes = [];
10
+ namedRoutes = new Map();
11
+ _state = 'registering';
12
+ get state() {
13
+ return this._state;
14
+ }
15
+ get isLocked() {
16
+ return this._state === 'locked' || this._state === 'compiled';
17
+ }
18
+ compile() {
19
+ if (!this.isLocked) {
20
+ this._state = 'locked';
21
+ this.tree.lock();
22
+ }
23
+ return this;
24
+ }
25
+ lock() {
26
+ return this.compile();
27
+ }
28
+ assertNotLocked() {
29
+ if (this.isLocked) {
30
+ throw new RouterLockedError();
31
+ }
32
+ }
33
+ route(method, path, handler, options = {}) {
34
+ this.assertNotLocked();
35
+ const normalized = normalizePath(path);
36
+ const routeInstance = new Route(method, normalized, handler, options);
37
+ this.tree.insert(routeInstance);
38
+ this.registeredRoutes.push(routeInstance);
39
+ if (options.name) {
40
+ this.registerRouteName(options.name, routeInstance);
41
+ }
42
+ // Intercept fluent .name() call
43
+ const originalNameMethod = routeInstance.name.bind(routeInstance);
44
+ routeInstance.name = (newName) => {
45
+ this.registerRouteName(newName, routeInstance);
46
+ return originalNameMethod(newName);
47
+ };
48
+ return routeInstance;
49
+ }
50
+ registerRouteName(name, route) {
51
+ const existing = this.namedRoutes.get(name);
52
+ if (existing && existing !== route) {
53
+ throw new DuplicateRouteNameError(name, existing.path, route.path);
54
+ }
55
+ this.namedRoutes.set(name, route);
56
+ }
57
+ get(path, handler, options = {}) {
58
+ return this.route('GET', path, handler, options);
59
+ }
60
+ post(path, handler, options = {}) {
61
+ return this.route('POST', path, handler, options);
62
+ }
63
+ put(path, handler, options = {}) {
64
+ return this.route('PUT', path, handler, options);
65
+ }
66
+ patch(path, handler, options = {}) {
67
+ return this.route('PATCH', path, handler, options);
68
+ }
69
+ delete(path, handler, options = {}) {
70
+ return this.route('DELETE', path, handler, options);
71
+ }
72
+ head(path, handler, options = {}) {
73
+ return this.route('HEAD', path, handler, options);
74
+ }
75
+ options(path, handler, options = {}) {
76
+ return this.route('OPTIONS', path, handler, options);
77
+ }
78
+ group(prefixOrConfig, callback, options = {}) {
79
+ this.assertNotLocked();
80
+ let prefix;
81
+ let groupMetadata = {};
82
+ let groupMiddleware = [];
83
+ if (typeof prefixOrConfig === 'string') {
84
+ prefix = prefixOrConfig;
85
+ groupMetadata = options.metadata ?? {};
86
+ groupMiddleware = options.middleware ?? [];
87
+ }
88
+ else {
89
+ prefix = prefixOrConfig.prefix;
90
+ groupMetadata = prefixOrConfig.metadata ?? {};
91
+ groupMiddleware = prefixOrConfig.middleware ?? [];
92
+ }
93
+ const groupInstance = new RouteGroup(this, prefix, {
94
+ metadata: groupMetadata,
95
+ middleware: groupMiddleware,
96
+ });
97
+ callback(groupInstance);
98
+ return this;
99
+ }
100
+ match(method, path) {
101
+ return this.tree.search(method, path);
102
+ }
103
+ routes() {
104
+ return Object.freeze([...this.registeredRoutes]);
105
+ }
106
+ getRouteByName(name) {
107
+ return this.namedRoutes.get(name);
108
+ }
109
+ url(name, params = {}) {
110
+ const route = this.namedRoutes.get(name);
111
+ if (!route) {
112
+ throw new RouteNotFoundError(name);
113
+ }
114
+ let generatedPath = route.path;
115
+ const unusedParams = { ...params };
116
+ // Replace optional parameters: /:param? or /:param<constraint>?
117
+ generatedPath = generatedPath.replace(/\/?:([a-zA-Z0-9_]+)(?:<.+?>)?\?/g, (match, paramName) => {
118
+ const val = unusedParams[paramName];
119
+ if (typeof val !== 'undefined') {
120
+ delete unusedParams[paramName];
121
+ return match.startsWith('/')
122
+ ? `/${encodeURIComponent(String(val))}`
123
+ : encodeURIComponent(String(val));
124
+ }
125
+ return '';
126
+ });
127
+ // Replace required parameters: :param or :param<constraint>
128
+ generatedPath = generatedPath.replace(/:([a-zA-Z0-9_]+)(?:<.+?>)?/g, (_, paramName) => {
129
+ const val = unusedParams[paramName];
130
+ if (typeof val === 'undefined') {
131
+ throw new InvalidRoutePatternError(route.path, `Missing required route parameter "${paramName}" for route "${name}".`);
132
+ }
133
+ delete unusedParams[paramName];
134
+ return encodeURIComponent(String(val));
135
+ });
136
+ // Replace *wildcards
137
+ generatedPath = generatedPath.replace(/\*([a-zA-Z0-9_]*)/g, (_, wildcardName) => {
138
+ const key = wildcardName || 'wildcard';
139
+ const val = unusedParams[key];
140
+ if (typeof val === 'undefined') {
141
+ return '';
142
+ }
143
+ delete unusedParams[key];
144
+ return String(val);
145
+ });
146
+ // Ensure generatedPath starts with / and clean duplicate slashes
147
+ if (!generatedPath.startsWith('/')) {
148
+ generatedPath = '/' + generatedPath;
149
+ }
150
+ generatedPath = generatedPath.replace(/\/+/g, '/');
151
+ if (generatedPath.length > 1 && generatedPath.endsWith('/')) {
152
+ generatedPath = generatedPath.slice(0, -1);
153
+ }
154
+ // Append extra parameters as query string
155
+ const remainingKeys = Object.keys(unusedParams);
156
+ if (remainingKeys.length > 0) {
157
+ const searchParams = new URLSearchParams();
158
+ for (const key of remainingKeys) {
159
+ searchParams.append(key, String(unusedParams[key]));
160
+ }
161
+ generatedPath += `?${searchParams.toString()}`;
162
+ }
163
+ return generatedPath;
164
+ }
165
+ /**
166
+ * Dispatches a RequestContext against the route table and returns the resulting HttpResponse.
167
+ */
168
+ async handle(ctx) {
169
+ const match = this.match(ctx.request.method, ctx.request.pathname);
170
+ if (match.type === 'MATCHED') {
171
+ // Expose matched parameters on request
172
+ ctx.request.params = match.params;
173
+ const raw = await match.handler(ctx);
174
+ const response = raw instanceof HttpResponse
175
+ ? raw
176
+ : raw === undefined || raw === null
177
+ ? HttpResponse.empty()
178
+ : typeof raw === 'string'
179
+ ? HttpResponse.text(raw)
180
+ : HttpResponse.json(raw);
181
+ // If HEAD request matched a GET handler via fallback, discard response body
182
+ if (match.isHeadFallback && ctx.request.method === 'HEAD') {
183
+ response.body = null;
184
+ }
185
+ return response;
186
+ }
187
+ if (match.type === 'METHOD_NOT_ALLOWED') {
188
+ const allowHeader = match.allowedMethods.join(', ');
189
+ return HttpResponse.json({
190
+ error: {
191
+ code: 'ERR_HTTP_METHOD_NOT_ALLOWED',
192
+ message: `Method ${ctx.request.method} is not allowed for path "${ctx.request.pathname}".`,
193
+ },
194
+ }, {
195
+ status: HttpStatus.METHOD_NOT_ALLOWED,
196
+ headers: {
197
+ allow: allowHeader,
198
+ },
199
+ });
200
+ }
201
+ // NOT_FOUND
202
+ return HttpResponse.json({
203
+ error: {
204
+ code: 'ERR_HTTP_NOT_FOUND',
205
+ message: `Cannot ${ctx.request.method} ${ctx.request.pathname}`,
206
+ },
207
+ }, { status: HttpStatus.NOT_FOUND });
208
+ }
209
+ }
210
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/public/router.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@jsango/router",
3
+ "version": "1.0.0",
4
+ "description": "Route registration and route matching for jsango",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "dependencies": {
15
+ "@jsango/core": "1.0.0",
16
+ "@jsango/http": "1.0.0"
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/flutterbuddy1/jsango.git",
25
+ "directory": "packages/router"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "scripts": {
31
+ "build": "tsc -b",
32
+ "typecheck": "tsc -b",
33
+ "clean": "rm -rf dist *.tsbuildinfo"
34
+ }
35
+ }