@owlmeans/route 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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +561 -0
  3. package/build/.gitkeep +0 -0
  4. package/build/consts.d.ts +13 -0
  5. package/build/consts.d.ts.map +1 -0
  6. package/build/consts.js +15 -0
  7. package/build/consts.js.map +1 -0
  8. package/build/helper.d.ts +12 -0
  9. package/build/helper.d.ts.map +1 -0
  10. package/build/helper.js +40 -0
  11. package/build/helper.js.map +1 -0
  12. package/build/index.d.ts +5 -0
  13. package/build/index.d.ts.map +1 -0
  14. package/build/index.js +5 -0
  15. package/build/index.js.map +1 -0
  16. package/build/model.d.ts +5 -0
  17. package/build/model.d.ts.map +1 -0
  18. package/build/model.js +20 -0
  19. package/build/model.js.map +1 -0
  20. package/build/types.d.ts +35 -0
  21. package/build/types.d.ts.map +1 -0
  22. package/build/types.js +2 -0
  23. package/build/types.js.map +1 -0
  24. package/build/utils/index.d.ts +4 -0
  25. package/build/utils/index.d.ts.map +1 -0
  26. package/build/utils/index.js +4 -0
  27. package/build/utils/index.js.map +1 -0
  28. package/build/utils/route.d.ts +9 -0
  29. package/build/utils/route.d.ts.map +1 -0
  30. package/build/utils/route.js +103 -0
  31. package/build/utils/route.js.map +1 -0
  32. package/build/utils/service.d.ts +4 -0
  33. package/build/utils/service.d.ts.map +1 -0
  34. package/build/utils/service.js +5 -0
  35. package/build/utils/service.js.map +1 -0
  36. package/build/utils/types.d.ts +5 -0
  37. package/build/utils/types.d.ts.map +1 -0
  38. package/build/utils/types.js +2 -0
  39. package/build/utils/types.js.map +1 -0
  40. package/package.json +40 -0
  41. package/src/consts.ts +16 -0
  42. package/src/helper.ts +54 -0
  43. package/src/index.ts +5 -0
  44. package/src/model.ts +25 -0
  45. package/src/types.ts +40 -0
  46. package/src/utils/index.ts +4 -0
  47. package/src/utils/route.ts +121 -0
  48. package/src/utils/service.ts +9 -0
  49. package/src/utils/types.ts +5 -0
  50. package/tsconfig.json +14 -0
  51. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,5 @@
1
+ export * from './types.js';
2
+ export * from './consts.js';
3
+ export * from './helper.js';
4
+ export * from './model.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA"}
package/build/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './types.js';
2
+ export * from './consts.js';
3
+ export * from './helper.js';
4
+ export * from './model.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA"}
@@ -0,0 +1,5 @@
1
+ import type { CommonRoute, CommonRouteModel } from './types.js';
2
+ import type { CreateRouteSignature } from './utils/types.js';
3
+ export declare const makeRouteModel: (route: CommonRoute) => CommonRouteModel;
4
+ export declare const createRoute: CreateRouteSignature<CommonRoute>;
5
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAI5D,eAAO,MAAM,cAAc,UAAW,WAAW,KAAG,gBAOnD,CAAA;AAED,eAAO,MAAM,WAAW,EAAE,oBAAoB,CAAC,WAAW,CAUzD,CAAA"}
package/build/model.js ADDED
@@ -0,0 +1,20 @@
1
+ import { resolve } from './utils/route.js';
2
+ import { AppType } from '@owlmeans/context';
3
+ export const makeRouteModel = (route) => {
4
+ const model = {
5
+ route,
6
+ resolve: ctx => resolve(route)(ctx)
7
+ };
8
+ return model;
9
+ };
10
+ export const createRoute = (alias, path, opts) => {
11
+ const route = {
12
+ alias,
13
+ type: AppType.Backend,
14
+ path,
15
+ resolved: false,
16
+ ...(typeof opts === 'string' ? { parent: opts } : opts)
17
+ };
18
+ return route;
19
+ };
20
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAA6B,MAAM,mBAAmB,CAAA;AAEtE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAkB,EAAoB,EAAE;IACrE,MAAM,KAAK,GAAqB;QAC9B,KAAK;QACL,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAA2C,CAAC;KAC5E,CAAA;IAED,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,WAAW,GAAsC,CAAC,KAAK,EAAE,IAAI,EAAE,IAAK,EAAE,EAAE;IACnF,MAAM,KAAK,GAAgB;QACzB,KAAK;QACL,IAAI,EAAE,OAAO,CAAC,OAAO;QACrB,IAAI;QACJ,QAAQ,EAAE,KAAK;QACf,GAAG,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;KACxD,CAAA;IAED,OAAO,KAAK,CAAA;AACd,CAAC,CAAA"}
@@ -0,0 +1,35 @@
1
+ import type { AppType, BasicContext, BasicConfig } from '@owlmeans/context';
2
+ import type { RouteProtocols, RouteMethod } from './consts';
3
+ export interface CommonRoute extends BasicRoute {
4
+ alias: string;
5
+ path: string;
6
+ parent?: string;
7
+ default?: boolean;
8
+ method?: RouteMethod;
9
+ protocol?: RouteProtocols;
10
+ secure?: boolean;
11
+ }
12
+ export interface CommonServiceRoute extends BasicRoute {
13
+ home?: string;
14
+ service: string;
15
+ default?: boolean;
16
+ }
17
+ export interface BasicRoute {
18
+ type: AppType;
19
+ service?: string;
20
+ host?: string;
21
+ port?: number;
22
+ base?: string;
23
+ resolved: boolean;
24
+ }
25
+ export interface ResolvedServiceRoute extends CommonServiceRoute {
26
+ host: string;
27
+ resolved: true;
28
+ }
29
+ export interface CommonRouteModel {
30
+ route: CommonRoute;
31
+ resolve: <C extends BasicConfig, T extends BasicContext<C>>(context: T) => Promise<CommonRoute>;
32
+ }
33
+ export interface RouteOptions extends Partial<CommonRoute> {
34
+ }
35
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3D,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,oBAAqB,SAAQ,kBAAkB;IAC9D,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,IAAI,CAAA;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,WAAW,CAAA;IAClB,OAAO,EAAE,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;CAChG;AAED,MAAM,WAAW,YAAa,SAAQ,OAAO,CAAC,WAAW,CAAC;CACzD"}
package/build/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ export * from './types.js';
2
+ export * from './service.js';
3
+ export * from './route.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA"}
@@ -0,0 +1,4 @@
1
+ export * from './types.js';
2
+ export * from './service.js';
3
+ export * from './route.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA"}
@@ -0,0 +1,9 @@
1
+ import type { BasicConfig, BasicContext } from '@owlmeans/context';
2
+ import type { CommonRoute } from '../types.js';
3
+ type Config = BasicConfig;
4
+ export declare const getParentRoute: <C extends Config, T extends BasicContext<C>>(context: T, route: CommonRoute) => Promise<CommonRoute | null>;
5
+ export declare const overrideParams: (route: CommonRoute, overrides?: Partial<CommonRoute>, filter?: string[]) => void;
6
+ export declare const resolve: <C extends Config, T extends BasicContext<C>>(route: CommonRoute) => (context: T) => Promise<CommonRoute>;
7
+ export declare const prependBase: (route: CommonRoute) => string;
8
+ export {};
9
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/utils/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAc,MAAM,mBAAmB,CAAA;AAC9E,OAAO,KAAK,EAAE,WAAW,EAAwC,MAAM,aAAa,CAAA;AAKpF,KAAK,MAAM,GAAG,WAAW,CAAA;AAEzB,eAAO,MAAM,cAAc,GAAU,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,WAAW,KAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAkB5I,CAAA;AAED,eAAO,MAAM,cAAc,UAAW,WAAW,cAAc,OAAO,CAAC,WAAW,CAAC,WAAW,MAAM,EAAE,SAOrG,CAAA;AAED,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,SAAS,WAAW,eAAqB,CAAC,yBA8D5G,CAAA;AAcD,eAAO,MAAM,WAAW,UAAW,WAAW,WAO7C,CAAA"}
@@ -0,0 +1,103 @@
1
+ import { isServiceRoute, isServiceRouteResolved } from './service.js';
2
+ import { normalizePath } from '../helper.js';
3
+ import { SEP } from '../consts.js';
4
+ export const getParentRoute = async (context, route) => {
5
+ if (route.parent != null) {
6
+ const parent = context.module(route.parent);
7
+ assertCycle(context, route, parent.route.route);
8
+ if (parent.route == null) {
9
+ throw new SyntaxError('Parent module doesn\'t provide a route');
10
+ }
11
+ if (!parent.route.route.resolved) {
12
+ if (parent.resolve != null) {
13
+ await parent.resolve();
14
+ }
15
+ else {
16
+ return await parent.route.resolve(context);
17
+ }
18
+ }
19
+ return parent.route.route;
20
+ }
21
+ return null;
22
+ };
23
+ export const overrideParams = (route, overrides, filter) => {
24
+ Object.entries(overrides ?? {}).forEach(([key, value]) => {
25
+ if (route[key] == null
26
+ && (filter == null || filter.includes(key))) {
27
+ route[key] = value;
28
+ }
29
+ });
30
+ };
31
+ export const resolve = (route) => async (context) => {
32
+ if (route.resolved)
33
+ return route;
34
+ route.resolved = true;
35
+ if (context.cfg.services == null) {
36
+ throw new SyntaxError('Services aren\'t configured to resolve routes');
37
+ }
38
+ const firstGuessService = context.cfg.services[route.service ?? context.cfg.service];
39
+ if (firstGuessService != null && !isServiceRoute(firstGuessService)) {
40
+ throw new SyntaxError('Service is not a valid service route');
41
+ }
42
+ const service = firstGuessService?.type === route.type ? firstGuessService
43
+ : Object.values(context.cfg.services).find((service) => {
44
+ const _service = service;
45
+ return _service.default === true && _service.type === route.type;
46
+ }) ?? Object.values(context.cfg.services).find((service) => {
47
+ const _service = service;
48
+ return _service.type === route.type;
49
+ });
50
+ if (!isServiceRoute(service)) {
51
+ throw new SyntaxError('Service is not a valid service route');
52
+ }
53
+ if (!service.resolved && service.host != null) {
54
+ service.resolved = true;
55
+ }
56
+ if (!isServiceRouteResolved(service)) {
57
+ throw new SyntaxError('Service route is not resolved');
58
+ }
59
+ overrideParams(route, service, ['host', 'port', 'service', 'base']);
60
+ // Internal host access is non secure only
61
+ // it's required for server side client routes
62
+ if ("internalHost" in route) {
63
+ if (route.internalHost === route.host) {
64
+ route.secure = false;
65
+ }
66
+ }
67
+ else if ("internalHost" in service) {
68
+ if (service.internalHost === route.host) {
69
+ route.secure = false;
70
+ }
71
+ }
72
+ const parent = await getParentRoute(context, route);
73
+ if (parent != null) {
74
+ route.path = (parent.path.startsWith(SEP) ? SEP : '')
75
+ + normalizePath(normalizePath(parent.path) + SEP + normalizePath(route.path));
76
+ }
77
+ // Moved base resolution to the final service
78
+ // if (parent == null && route.base != null && route.base.trim() !== '') {
79
+ // route.path = SEP + normalizePath(route.base) + SEP + normalizePath(route.path)
80
+ // // route.path = route.base.startsWith(SEP) ? SEP + route.path : route.path
81
+ // }
82
+ return route;
83
+ };
84
+ /**
85
+ * @throws {SyntaxError}
86
+ */
87
+ const assertCycle = (context, route, parent) => {
88
+ while (parent.parent != null) {
89
+ if (parent.parent === route.alias) {
90
+ throw new SyntaxError(`Route parentship cycle detected. Parent: ${parent.alias} has his child as ancestor ${route.alias}`);
91
+ }
92
+ parent = context.module(parent.parent).route.route;
93
+ }
94
+ };
95
+ export const prependBase = (route) => {
96
+ let path = route.path;
97
+ if (route.base != null && route.base.trim() !== '') {
98
+ path = SEP + normalizePath(route.base) + SEP + normalizePath(route.path);
99
+ // route.path = route.base.startsWith(SEP) ? SEP + route.path : route.path
100
+ }
101
+ return path;
102
+ };
103
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/utils/route.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ResolvedServiceRoute, CommonServiceRoute } from '../types.js';
2
+ export declare const isServiceRoute: (obj?: Object) => obj is CommonServiceRoute;
3
+ export declare const isServiceRouteResolved: (route: CommonServiceRoute) => route is ResolvedServiceRoute;
4
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/utils/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAE3E,eAAO,MAAM,cAAc,SAAU,MAAM,KAAG,GAAG,IAAI,kBAEM,CAAA;AAE3D,eAAO,MAAM,sBAAsB,UAAW,kBAAkB,KAAG,KAAK,IAAI,oBACnD,CAAA"}
@@ -0,0 +1,5 @@
1
+ import { AppType } from '@owlmeans/context';
2
+ export const isServiceRoute = (obj) => obj != null && ('type' in obj) && ('service' in obj)
3
+ && (Object.values(AppType).includes(obj.type));
4
+ export const isServiceRouteResolved = (route) => route.resolved === true;
5
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/utils/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAG3C,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAY,EAA6B,EAAE,CACxE,GAAG,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC;OACjD,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAe,CAAC,CAAC,CAAA;AAE3D,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,KAAyB,EAAiC,EAAE,CACjG,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAA"}
@@ -0,0 +1,5 @@
1
+ import type { RouteOptions } from '../types.js';
2
+ export interface CreateRouteSignature<R> {
3
+ (alias: string, path: string, opts?: RouteOptions | string): R;
4
+ }
5
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/C,MAAM,WAAW,oBAAoB,CAAC,CAAC;IACrC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,CAAC,CAAA;CAC/D"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@owlmeans/route",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsc -b",
7
+ "dev": "sleep 258 && nodemon -e ts,tsx,json --watch src --exec \"tsc -p ./tsconfig.json\"",
8
+ "watch": "tsc -b -w --preserveWatchOutput --pretty"
9
+ },
10
+ "main": "build/index.js",
11
+ "module": "build/index.js",
12
+ "types": "build/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "import": "./build/index.js",
16
+ "require": "./build/index.js",
17
+ "default": "./build/index.js",
18
+ "module": "./build/index.js",
19
+ "types": "./build/index.d.ts"
20
+ },
21
+ "./utils": {
22
+ "default": "./build/utils/index.js",
23
+ "import": "./build/utils/index.js",
24
+ "require": "./build/utils/index.js",
25
+ "module": "./build/utils/index.js",
26
+ "types": "./build/utils/index.d.ts"
27
+ }
28
+ },
29
+ "dependencies": {
30
+ "@owlmeans/context": "^0.1.0"
31
+ },
32
+ "devDependencies": {
33
+ "nodemon": "^3.1.7",
34
+ "typescript": "^5.6.3"
35
+ },
36
+ "private": false,
37
+ "publishConfig": {
38
+ "access": "public"
39
+ }
40
+ }
package/src/consts.ts ADDED
@@ -0,0 +1,16 @@
1
+
2
+ export enum RouteMethod {
3
+ GET = 'get',
4
+ POST = 'post',
5
+ PATCH = 'patch',
6
+ PUT = 'put'
7
+ }
8
+
9
+ export const SEP = '/'
10
+
11
+ export const PARAM = ':'
12
+
13
+ export enum RouteProtocols {
14
+ WEB = 'http',
15
+ SOCKET = 'ws'
16
+ }
package/src/helper.ts ADDED
@@ -0,0 +1,54 @@
1
+ import { AppType } from '@owlmeans/context'
2
+ import { RouteMethod, RouteProtocols, SEP } from './consts.js'
3
+ import { createRoute, makeRouteModel } from './model.js'
4
+ import type { CommonRouteModel, RouteOptions } from './types.js'
5
+ import type { CreateRouteSignature } from './utils/types.js'
6
+
7
+ export const route: CreateRouteSignature<CommonRouteModel> = (alias, path, opts?) =>
8
+ makeRouteModel(createRoute(alias, path, opts))
9
+
10
+ export const normalizePath = (path: string): string => {
11
+ path = path.trim()
12
+ path = path.endsWith(SEP) ? path.slice(0, -1) : path
13
+ path = path.startsWith(SEP) ? path.substring(1) : path
14
+
15
+ return path
16
+ }
17
+
18
+ export const rtype = (type: AppType, opts?: RouteOptions | string): Partial<RouteOptions> => (
19
+ { type, ...(typeof opts === 'string' ? { parent: opts } : opts) }
20
+ )
21
+
22
+ export const backend = (opts?: RouteOptions | string | null, method?: RouteOptions | RouteMethod): Partial<RouteOptions> => {
23
+ if (typeof method === 'string') {
24
+ opts = typeof opts === 'string' ? { parent: opts, method } : { method, ...(opts ?? {}) }
25
+ } else if (typeof method === 'object') {
26
+ opts = typeof opts === 'string' ? { ...method, parent: opts } : { ...opts, ...method }
27
+ }
28
+
29
+ return rtype(AppType.Backend, opts as RouteOptions)
30
+ }
31
+
32
+ export const service = (service: string, opts?: Partial<RouteOptions>): Partial<RouteOptions> => {
33
+ opts = opts ?? {}
34
+ opts.service = service
35
+ return opts
36
+ }
37
+
38
+ export const socket = (opts?: RouteOptions | string | null, secondary?: RouteOptions): Partial<RouteOptions> => {
39
+ const route = backend(opts, secondary)
40
+
41
+ route.protocol = RouteProtocols.SOCKET
42
+
43
+ return route
44
+ }
45
+
46
+ export const frontend = (opts?: RouteOptions | string | null, def?: RouteOptions | boolean): Partial<RouteOptions> => {
47
+ if (typeof def === 'boolean') {
48
+ opts = typeof opts === 'string' ? { parent: opts, default: def } : { default: def, ...(opts ?? {}) }
49
+ } else if (typeof def === 'object') {
50
+ opts = typeof opts === 'object' ? { ...opts, ...def } : { parent: opts, ...def }
51
+ }
52
+
53
+ return rtype(AppType.Frontend, opts as RouteOptions)
54
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+
2
+ export * from './types.js'
3
+ export * from './consts.js'
4
+ export * from './helper.js'
5
+ export * from './model.js'
package/src/model.ts ADDED
@@ -0,0 +1,25 @@
1
+ import type { CommonRoute, CommonRouteModel } from './types.js'
2
+ import type { CreateRouteSignature } from './utils/types.js'
3
+ import { resolve } from './utils/route.js'
4
+ import { AppType, BasicConfig, BasicContext } from '@owlmeans/context'
5
+
6
+ export const makeRouteModel = (route: CommonRoute): CommonRouteModel => {
7
+ const model: CommonRouteModel = {
8
+ route,
9
+ resolve: ctx => resolve(route)(ctx as unknown as BasicContext<BasicConfig>)
10
+ }
11
+
12
+ return model
13
+ }
14
+
15
+ export const createRoute: CreateRouteSignature<CommonRoute> = (alias, path, opts?) => {
16
+ const route: CommonRoute = {
17
+ alias,
18
+ type: AppType.Backend,
19
+ path,
20
+ resolved: false,
21
+ ...(typeof opts === 'string' ? { parent: opts } : opts)
22
+ }
23
+
24
+ return route
25
+ }
package/src/types.ts ADDED
@@ -0,0 +1,40 @@
1
+ import type { AppType, BasicContext, BasicConfig } from '@owlmeans/context'
2
+ import type { RouteProtocols, RouteMethod } from './consts'
3
+
4
+ export interface CommonRoute extends BasicRoute {
5
+ alias: string
6
+ path: string
7
+ parent?: string
8
+ default?: boolean
9
+ method?: RouteMethod
10
+ protocol?: RouteProtocols
11
+ secure?: boolean
12
+ }
13
+
14
+ export interface CommonServiceRoute extends BasicRoute {
15
+ home?: string
16
+ service: string
17
+ default?: boolean
18
+ }
19
+
20
+ export interface BasicRoute {
21
+ type: AppType
22
+ service?: string
23
+ host?: string
24
+ port?: number
25
+ base?: string
26
+ resolved: boolean
27
+ }
28
+
29
+ export interface ResolvedServiceRoute extends CommonServiceRoute {
30
+ host: string
31
+ resolved: true
32
+ }
33
+
34
+ export interface CommonRouteModel {
35
+ route: CommonRoute
36
+ resolve: <C extends BasicConfig, T extends BasicContext<C>>(context: T) => Promise<CommonRoute>
37
+ }
38
+
39
+ export interface RouteOptions extends Partial<CommonRoute> {
40
+ }
@@ -0,0 +1,4 @@
1
+
2
+ export * from './types.js'
3
+ export * from './service.js'
4
+ export * from './route.js'
@@ -0,0 +1,121 @@
1
+ import type { BasicConfig, BasicContext, Contextual } from '@owlmeans/context'
2
+ import type { CommonRoute, CommonRouteModel, CommonServiceRoute } from '../types.js'
3
+ import { isServiceRoute, isServiceRouteResolved } from './service.js'
4
+ import { normalizePath } from '../helper.js'
5
+ import { SEP } from '../consts.js'
6
+
7
+ type Config = BasicConfig
8
+
9
+ export const getParentRoute = async <C extends Config, T extends BasicContext<C>>(context: T, route: CommonRoute): Promise<CommonRoute | null> => {
10
+ if (route.parent != null) {
11
+ const parent = context.module<Contextual & { _module: true, route: CommonRouteModel, resolve?: () => Promise<void> }>(route.parent)
12
+ assertCycle<C, T>(context, route, parent.route.route)
13
+ if (parent.route == null) {
14
+ throw new SyntaxError('Parent module doesn\'t provide a route')
15
+ }
16
+ if (!parent.route.route.resolved) {
17
+ if (parent.resolve != null) {
18
+ await parent.resolve()
19
+ } else {
20
+ return await parent.route.resolve<C, T>(context)
21
+ }
22
+ }
23
+ return parent.route.route
24
+ }
25
+
26
+ return null
27
+ }
28
+
29
+ export const overrideParams = (route: CommonRoute, overrides?: Partial<CommonRoute>, filter?: string[]) => {
30
+ Object.entries(overrides ?? {}).forEach(([key, value]) => {
31
+ if (route[key as keyof CommonRoute] == null
32
+ && (filter == null || filter.includes(key))) {
33
+ (route[key as keyof CommonRoute] as CommonRoute[keyof CommonRoute]) = value
34
+ }
35
+ })
36
+ }
37
+
38
+ export const resolve = <C extends Config, T extends BasicContext<C>>(route: CommonRoute) => async (context: T) => {
39
+ if (route.resolved) return route
40
+ route.resolved = true
41
+
42
+ if (context.cfg.services == null) {
43
+ throw new SyntaxError('Services aren\'t configured to resolve routes')
44
+ }
45
+
46
+ const firstGuessService = context.cfg.services[route.service ?? context.cfg.service]
47
+ if (firstGuessService != null && !isServiceRoute(firstGuessService)) {
48
+ throw new SyntaxError('Service is not a valid service route')
49
+ }
50
+ const service = firstGuessService?.type === route.type ? firstGuessService
51
+ : Object.values(context.cfg.services).find<CommonServiceRoute>(
52
+ (service): service is CommonServiceRoute => {
53
+ const _service = service as CommonServiceRoute
54
+ return _service.default === true && _service.type === route.type
55
+ }
56
+ ) ?? Object.values(context.cfg.services).find<CommonServiceRoute>(
57
+ (service): service is CommonServiceRoute => {
58
+ const _service = service as CommonServiceRoute
59
+ return _service.type === route.type
60
+ }
61
+ )
62
+ if (!isServiceRoute(service)) {
63
+ throw new SyntaxError('Service is not a valid service route')
64
+ }
65
+ if (!service.resolved && service.host != null) {
66
+ service.resolved = true
67
+ }
68
+ if (!isServiceRouteResolved(service)) {
69
+ throw new SyntaxError('Service route is not resolved')
70
+ }
71
+
72
+ overrideParams(route, service, ['host', 'port', 'service', 'base'])
73
+
74
+ // Internal host access is non secure only
75
+ // it's required for server side client routes
76
+ if ("internalHost" in route) {
77
+ if (route.internalHost === route.host) {
78
+ route.secure = false
79
+ }
80
+ } else if ("internalHost" in service) {
81
+ if (service.internalHost === route.host) {
82
+ route.secure = false
83
+ }
84
+ }
85
+
86
+
87
+ const parent = await getParentRoute<C, T>(context, route)
88
+ if (parent != null) {
89
+ route.path = (parent.path.startsWith(SEP) ? SEP : '')
90
+ + normalizePath(normalizePath(parent.path) + SEP + normalizePath(route.path))
91
+ }
92
+
93
+ // Moved base resolution to the final service
94
+ // if (parent == null && route.base != null && route.base.trim() !== '') {
95
+ // route.path = SEP + normalizePath(route.base) + SEP + normalizePath(route.path)
96
+ // // route.path = route.base.startsWith(SEP) ? SEP + route.path : route.path
97
+ // }
98
+
99
+ return route
100
+ }
101
+
102
+ /**
103
+ * @throws {SyntaxError}
104
+ */
105
+ const assertCycle = <C extends BasicConfig, T extends BasicContext<C>>(context: T, route: CommonRoute, parent: CommonRoute) => {
106
+ while (parent.parent != null) {
107
+ if (parent.parent === route.alias) {
108
+ throw new SyntaxError(`Route parentship cycle detected. Parent: ${parent.alias} has his child as ancestor ${route.alias}`)
109
+ }
110
+ parent = context.module<Contextual & { _module: true, route: CommonRouteModel }>(parent.parent).route.route
111
+ }
112
+ }
113
+
114
+ export const prependBase = (route: CommonRoute) => {
115
+ let path = route.path
116
+ if (route.base != null && route.base.trim() !== '') {
117
+ path = SEP + normalizePath(route.base) + SEP + normalizePath(route.path)
118
+ // route.path = route.base.startsWith(SEP) ? SEP + route.path : route.path
119
+ }
120
+ return path
121
+ }
@@ -0,0 +1,9 @@
1
+ import { AppType } from '@owlmeans/context'
2
+ import type { ResolvedServiceRoute, CommonServiceRoute } from '../types.js'
3
+
4
+ export const isServiceRoute = (obj?: Object): obj is CommonServiceRoute =>
5
+ obj != null && ('type' in obj) && ('service' in obj)
6
+ && (Object.values(AppType).includes(obj.type as AppType))
7
+
8
+ export const isServiceRouteResolved = (route: CommonServiceRoute): route is ResolvedServiceRoute =>
9
+ route.resolved === true
@@ -0,0 +1,5 @@
1
+ import type { RouteOptions } from '../types.js'
2
+
3
+ export interface CreateRouteSignature<R> {
4
+ (alias: string, path: string, opts?: RouteOptions | string): R
5
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": [
3
+ "../tsconfig.default.json",
4
+ ],
5
+ "compilerOptions": {
6
+ "rootDir": "./src/", /* Specify the root folder within your source files. */
7
+ "outDir": "./build/", /* Specify an output folder for all emitted files. */
8
+ },
9
+ "exclude": [
10
+ "./dist/**/*",
11
+ "./build/**/*",
12
+ "./*.ts"
13
+ ]
14
+ }
@@ -0,0 +1 @@
1
+ {"root":["./src/consts.ts","./src/helper.ts","./src/index.ts","./src/model.ts","./src/types.ts","./src/utils/index.ts","./src/utils/route.ts","./src/utils/service.ts","./src/utils/types.ts"],"version":"5.6.3"}