@owlmeans/route 0.1.18-rc.33 → 0.1.18-rc.35
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/README.md +21 -18
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/route/SKILL.md +1 -1
- package/build/model.js.map +1 -1
- package/build/utils/declaration/types.d.ts +9 -0
- package/build/utils/declaration/types.d.ts.map +1 -0
- package/build/utils/declaration/types.js +2 -0
- package/build/utils/declaration/types.js.map +1 -0
- package/build/utils/declaration.d.ts +4 -0
- package/build/utils/declaration.d.ts.map +1 -0
- package/build/utils/declaration.js +18 -0
- package/build/utils/declaration.js.map +1 -0
- package/build/utils/index.d.ts +4 -0
- package/build/utils/index.d.ts.map +1 -1
- package/build/utils/index.js +1 -0
- package/build/utils/index.js.map +1 -1
- package/build/utils/route/types.d.ts +35 -0
- package/build/utils/route/types.d.ts.map +1 -0
- package/build/utils/route/types.js +2 -0
- package/build/utils/route/types.js.map +1 -0
- package/build/utils/route.d.ts +5 -28
- package/build/utils/route.d.ts.map +1 -1
- package/build/utils/route.js +76 -97
- package/build/utils/route.js.map +1 -1
- package/build/utils/service/types.d.ts +9 -0
- package/build/utils/service/types.d.ts.map +1 -0
- package/build/utils/service/types.js +2 -0
- package/build/utils/service/types.js.map +1 -0
- package/build/utils/service.d.ts +3 -4
- package/build/utils/service.d.ts.map +1 -1
- package/build/utils/service.js +7 -4
- package/build/utils/service.js.map +1 -1
- package/build/utils/types.local.d.ts +9 -0
- package/build/utils/types.local.d.ts.map +1 -0
- package/build/utils/types.local.js +2 -0
- package/build/utils/types.local.js.map +1 -0
- package/package.json +2 -2
- package/src/model.ts +1 -1
- package/src/utils/declaration/types.ts +9 -0
- package/src/utils/declaration.ts +24 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/route/types.ts +35 -0
- package/src/utils/route.ts +85 -125
- package/src/utils/service/types.ts +9 -0
- package/src/utils/service.ts +12 -6
- package/src/utils/types.local.ts +10 -0
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ context that asks, so the same declaration serves a server and a browser alike.
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
bun add @owlmeans/route@^0.1.18-rc.
|
|
19
|
+
bun add @owlmeans/route@^0.1.18-rc.35
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
## Concepts
|
|
@@ -148,7 +148,7 @@ Once protocols are registered on a context, the entrypoint accessors answer addr
|
|
|
148
148
|
```ts
|
|
149
149
|
import { AppType } from '@owlmeans/context'
|
|
150
150
|
import { service } from '@owlmeans/config'
|
|
151
|
-
import {
|
|
151
|
+
import { routeAddressOf } from '@owlmeans/route/utils'
|
|
152
152
|
import { invoiceProtocols } from 'my-app-common'
|
|
153
153
|
|
|
154
154
|
// Config side: the service the backend routes resolve against
|
|
@@ -163,8 +163,9 @@ entrypoint.isLocal() // true inside the my-app-api process
|
|
|
163
163
|
|
|
164
164
|
// Same answers from a declaration
|
|
165
165
|
const declaration = invoiceProtocols.create.route.route
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
const addresses = routeAddressOf(context)
|
|
167
|
+
addresses.resolveMount(declaration)
|
|
168
|
+
addresses.resolveAddress(declaration)
|
|
168
169
|
```
|
|
169
170
|
|
|
170
171
|
## API
|
|
@@ -197,20 +198,22 @@ resolveAddress(context, declaration)
|
|
|
197
198
|
|
|
198
199
|
### `@owlmeans/route/utils`
|
|
199
200
|
|
|
200
|
-
|
|
201
|
+
`routeAddressOf(context)` answers address questions against a context (one helper per context,
|
|
202
|
+
built on first use; `makeRouteAddressHelper(context)` builds a fresh one). `routeDeclarationHelper`
|
|
203
|
+
and `serviceRouteHelper` are pure and take no context.
|
|
201
204
|
|
|
202
205
|
| Symbol | Kind | Purpose |
|
|
203
206
|
|--------|------|---------|
|
|
204
|
-
| `resolvePath(
|
|
205
|
-
| `resolveMount(
|
|
206
|
-
| `resolveService(
|
|
207
|
-
| `resolveAddress(
|
|
208
|
-
| `isLocalRoute(
|
|
209
|
-
| `getParentRoute(
|
|
210
|
-
| `overrideParams(route, overrides?, filter?)` |
|
|
211
|
-
| `prependBase(route, path)` |
|
|
212
|
-
| `isServiceRoute(obj?)` | type guard | Is `obj` a `CommonServiceRoute` with a known `AppType` |
|
|
213
|
-
| `isServiceRouteResolved(route)` | type guard | Does the service entry name a host |
|
|
207
|
+
| `routeAddressOf(context).resolvePath(route)` | helper member | Every ancestor's segment, then this one |
|
|
208
|
+
| `routeAddressOf(context).resolveMount(route)` | helper member | Service `base` + the full path |
|
|
209
|
+
| `routeAddressOf(context).resolveService(route)` | helper member | The named service, else the default of the route's type, else the first of that type |
|
|
210
|
+
| `routeAddressOf(context).resolveAddress(route)` | helper member | The `RouteAddress`; a hop over the service's internal host is never TLS |
|
|
211
|
+
| `routeAddressOf(context).isLocalRoute(route)` | helper member | Does the route belong to the context's own service |
|
|
212
|
+
| `routeAddressOf(context).getParentRoute(route)` | helper member | The parent declaration, with parentship-cycle detection |
|
|
213
|
+
| `routeDeclarationHelper.overrideParams(route, overrides?, filter?)` | helper member | Fill only blank fields of `route` from `overrides`; mutates, returns nothing |
|
|
214
|
+
| `routeDeclarationHelper.prependBase(route, path)` | helper member | `path` prefixed with `route.base` when set |
|
|
215
|
+
| `serviceRouteHelper.isServiceRoute(obj?)` | type guard | Is `obj` a `CommonServiceRoute` with a known `AppType` |
|
|
216
|
+
| `serviceRouteHelper.isServiceRouteResolved(route)` | type guard | Does the service entry name a host |
|
|
214
217
|
| `CreateRouteSignature<R>` | interface | Call signature shared by `route()` and `createRoute()` |
|
|
215
218
|
|
|
216
219
|
## Common pitfalls
|
|
@@ -224,8 +227,8 @@ The first six take `(context, declaration)`; the other four are pure and take no
|
|
|
224
227
|
the chain.
|
|
225
228
|
- Custom transport options are opaque here. Validate them through the package that owns the
|
|
226
229
|
protocol.
|
|
227
|
-
- Do not pass a context to the pure `./utils` helpers: `overrideParams(ctx, decl)`
|
|
228
|
-
fields into the context object instead of resolving anything.
|
|
230
|
+
- Do not pass a context to the pure `./utils` helpers: `routeDeclarationHelper.overrideParams(ctx, decl)`
|
|
231
|
+
writes route fields into the context object instead of resolving anything.
|
|
229
232
|
- A mis-wired tree (no `cfg.services`, a service without a host, a parentship cycle) throws
|
|
230
233
|
`SyntaxError` when an address is resolved. Fix the config; do not catch it.
|
|
231
234
|
- `transportAlias` and `EntrypointTransport` live in `@owlmeans/entrypoint`, not here. A route only
|
|
@@ -250,7 +253,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
250
253
|
your project's skill store (`.agents/skills/`):
|
|
251
254
|
|
|
252
255
|
```sh
|
|
253
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
256
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.49
|
|
254
257
|
```
|
|
255
258
|
|
|
256
259
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/route",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-
|
|
4
|
+
"version": "0.1.18-rc.35",
|
|
5
|
+
"generatedAt": "2026-10-05T21:03:06.407Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
package/build/model.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAE3C,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAuB,EAAc,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;AAElF,MAAM,CAAC,MAAM,WAAW,GAA2C,CAAC,KAAK,EAAE,IAAI,EAAE,IAAK,
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAE3C,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAuB,EAAc,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;AAElF,MAAM,CAAC,MAAM,WAAW,GAA2C,CAAC,KAAK,EAAE,IAAI,EAAE,IAAK,EAAoB,EAAE;IAC1G,MAAM,OAAO,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IAClE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,IAAI,EAAE,CAAA;IACzC,MAAM,KAAK,GAAqB;QAC9B,KAAK;QACL,IAAI,EAAE,OAAO,CAAC,OAAO;QACrB,IAAI;QACJ,GAAG,IAAI;QACP,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;KAC1F,CAAA;IAED,OAAO,KAAK,CAAA;AACd,CAAC,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RouteDeclaration } from '../../types.js';
|
|
2
|
+
/** Context-free edits and reads of one route declaration. */
|
|
3
|
+
export interface RouteDeclarationHelper {
|
|
4
|
+
/** Fills the declaration's unset fields from `overrides`, limited to `filter` keys when given. */
|
|
5
|
+
overrideParams: (route: RouteDeclaration, overrides?: Partial<RouteDeclaration>, filter?: string[]) => void;
|
|
6
|
+
/** `path` under the declaration's own `base`, when it has one. */
|
|
7
|
+
prependBase: (route: RouteDeclaration, path: string) => string;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/declaration/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEtD,6DAA6D;AAC7D,MAAM,WAAW,sBAAsB;IACrC,kGAAkG;IAClG,cAAc,EAAE,CAAC,KAAK,EAAE,gBAAgB,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;IAC3G,kEAAkE;IAClE,WAAW,EAAE,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAC/D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/declaration/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declaration.d.ts","sourceRoot":"","sources":["../../src/utils/declaration.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAEpE,eAAO,MAAM,4BAA4B,QAAO,sBAgB/C,CAAA;AAED,eAAO,MAAM,sBAAsB,wBAAiC,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { normalizePath } from '../helper.js';
|
|
2
|
+
import { SEP } from '../consts.js';
|
|
3
|
+
export const createRouteDeclarationHelper = () => {
|
|
4
|
+
const overrideParams = (route, overrides, filter) => {
|
|
5
|
+
Object.entries(overrides ?? {}).forEach(([key, value]) => {
|
|
6
|
+
if (route[key] == null
|
|
7
|
+
&& (filter == null || filter.includes(key))) {
|
|
8
|
+
route[key] = value;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
const prependBase = (route, path) => route.base != null && route.base.trim() !== ''
|
|
13
|
+
? SEP + normalizePath(route.base) + SEP + normalizePath(path)
|
|
14
|
+
: path;
|
|
15
|
+
return { overrideParams, prependBase };
|
|
16
|
+
};
|
|
17
|
+
export const routeDeclarationHelper = createRouteDeclarationHelper();
|
|
18
|
+
//# sourceMappingURL=declaration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declaration.js","sourceRoot":"","sources":["../../src/utils/declaration.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAGlC,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAA2B,EAAE;IACvE,MAAM,cAAc,GAAG,CAAC,KAAuB,EAAE,SAAqC,EAAE,MAAiB,EAAQ,EAAE;QACjH,MAAM,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;YACvD,IAAI,KAAK,CAAC,GAA6B,CAAC,IAAI,IAAI;mBAC3C,CAAC,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBAC7C,KAAK,CAAC,GAA6B,CAA8C,GAAG,KAAK,CAAA;YAC5F,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,MAAM,WAAW,GAAG,CAAC,KAAuB,EAAE,IAAY,EAAU,EAAE,CACpE,KAAK,CAAC,IAAI,IAAI,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAC5C,CAAC,CAAC,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC;QAC7D,CAAC,CAAC,IAAI,CAAA;IAEV,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,CAAA;AACxC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,4BAA4B,EAAE,CAAA"}
|
package/build/utils/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export * from './types.js';
|
|
2
|
+
export type * from './route/types.js';
|
|
3
|
+
export type * from './declaration/types.js';
|
|
4
|
+
export type * from './service/types.js';
|
|
2
5
|
export * from './service.js';
|
|
3
6
|
export * from './route.js';
|
|
7
|
+
export * from './declaration.js';
|
|
4
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;AAC1B,mBAAmB,kBAAkB,CAAA;AACrC,mBAAmB,wBAAwB,CAAA;AAC3C,mBAAmB,oBAAoB,CAAA;AACvC,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA"}
|
package/build/utils/index.js
CHANGED
package/build/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;AAI1B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { RouteAddress, RouteDeclaration, ResolvedServiceRoute } from '../../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Where routes answer, worked out on demand against the context that asks — a declaration states
|
|
4
|
+
* only what it contributes and every address question walks the parent chain through the context.
|
|
5
|
+
*/
|
|
6
|
+
export interface RouteAddressHelper {
|
|
7
|
+
/**
|
|
8
|
+
* The declaration of the route's parent entrypoint, or `null` for a root route.
|
|
9
|
+
*
|
|
10
|
+
* @throws {SyntaxError} when the parent provides no route or the parent chain is a cycle
|
|
11
|
+
*/
|
|
12
|
+
getParentRoute: (route: RouteDeclaration) => RouteDeclaration | null;
|
|
13
|
+
/**
|
|
14
|
+
* Pick the service route this declaration answers on: the one it names, else the default of its
|
|
15
|
+
* app type, else the first of its app type.
|
|
16
|
+
*
|
|
17
|
+
* @throws {SyntaxError}
|
|
18
|
+
*/
|
|
19
|
+
resolveService: (route: RouteDeclaration) => ResolvedServiceRoute;
|
|
20
|
+
/**
|
|
21
|
+
* The full path: every ancestor's declared segment, then this one. Walks the parent chain through
|
|
22
|
+
* the context, so a declaration always states only what it contributes.
|
|
23
|
+
*/
|
|
24
|
+
resolvePath: (route: RouteDeclaration) => string;
|
|
25
|
+
/** `base` + the full path — what a server mounts and a client requests. */
|
|
26
|
+
resolveMount: (route: RouteDeclaration) => string;
|
|
27
|
+
/**
|
|
28
|
+
* Where the route answers. A backend caller reaching a service over its INTERNAL host is inside the
|
|
29
|
+
* cluster, so that hop is never TLS.
|
|
30
|
+
*/
|
|
31
|
+
resolveAddress: (route: RouteDeclaration) => RouteAddress;
|
|
32
|
+
/** Does this route belong to the service the asking context IS? */
|
|
33
|
+
isLocalRoute: (route: RouteDeclaration) => boolean;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/route/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAE1F;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,cAAc,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,gBAAgB,GAAG,IAAI,CAAA;IACpE;;;;;OAKG;IACH,cAAc,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,oBAAoB,CAAA;IACjE;;;OAGG;IACH,WAAW,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,MAAM,CAAA;IAChD,2EAA2E;IAC3E,YAAY,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,MAAM,CAAA;IACjD;;;OAGG;IACH,cAAc,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,YAAY,CAAA;IACzD,mEAAmE;IACnE,YAAY,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,OAAO,CAAA;CACnD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/route/types.ts"],"names":[],"mappings":""}
|
package/build/utils/route.d.ts
CHANGED
|
@@ -1,29 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
type
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
6
|
-
/**
|
|
7
|
-
* Pick the service route this declaration answers on: the one it names, else the default of its
|
|
8
|
-
* app type, else the first of its app type.
|
|
9
|
-
*
|
|
10
|
-
* @throws {SyntaxError}
|
|
11
|
-
*/
|
|
12
|
-
export declare const resolveService: <C extends Config, T extends BasicContext<C>>(context: T, route: RouteDeclaration) => ResolvedServiceRoute;
|
|
13
|
-
/**
|
|
14
|
-
* The full path: every ancestor's declared segment, then this one. Walks the parent chain through
|
|
15
|
-
* the context, so a declaration always states only what it contributes.
|
|
16
|
-
*/
|
|
17
|
-
export declare const resolvePath: <C extends Config, T extends BasicContext<C>>(context: T, route: RouteDeclaration) => string;
|
|
18
|
-
/** `base` + the full path — what a server mounts and a client requests. */
|
|
19
|
-
export declare const resolveMount: <C extends Config, T extends BasicContext<C>>(context: T, route: RouteDeclaration) => string;
|
|
20
|
-
/**
|
|
21
|
-
* Where the route answers. A backend caller reaching a service over its INTERNAL host is inside the
|
|
22
|
-
* cluster, so that hop is never TLS.
|
|
23
|
-
*/
|
|
24
|
-
export declare const resolveAddress: <C extends Config, T extends BasicContext<C>>(context: T, route: RouteDeclaration) => RouteAddress;
|
|
25
|
-
/** Does this route belong to the service the asking context IS? */
|
|
26
|
-
export declare const isLocalRoute: <C extends Config, T extends BasicContext<C>>(context: T, route: RouteDeclaration) => boolean;
|
|
27
|
-
export declare const prependBase: (route: RouteDeclaration, path: string) => string;
|
|
28
|
-
export {};
|
|
1
|
+
import type { BasicContext } from '@owlmeans/context';
|
|
2
|
+
import type { Config } from './types.local.js';
|
|
3
|
+
import type { RouteAddressHelper } from './route/types.js';
|
|
4
|
+
export declare const makeRouteAddressHelper: <C extends Config, T extends BasicContext<C>>(context: T) => RouteAddressHelper;
|
|
5
|
+
export declare const routeAddressOf: <C extends Config, T extends BasicContext<C>>(target: T) => RouteAddressHelper;
|
|
29
6
|
//# sourceMappingURL=route.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/utils/route.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/utils/route.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAKrD,OAAO,KAAK,EAAE,MAAM,EAAgB,MAAM,kBAAkB,CAAA;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAE1D,eAAO,MAAM,sBAAsB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,KAAG,kBAmGhG,CAAA;AAED,eAAO,MAAM,cAAc,GArGY,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,kCAqGV,CAAA"}
|
package/build/utils/route.js
CHANGED
|
@@ -1,104 +1,83 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { memoHelper } from '@owlmeans/context';
|
|
2
|
+
import { serviceRouteHelper } from './service.js';
|
|
2
3
|
import { normalizePath } from '../helper.js';
|
|
3
4
|
import { RouteProtocols, SEP } from '../consts.js';
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (parent.route == null) {
|
|
11
|
-
throw new SyntaxError('Parent entrypoint doesn\'t provide a route');
|
|
12
|
-
}
|
|
13
|
-
assertCycle(context, route, parent.route.route);
|
|
14
|
-
return parent.route.route;
|
|
15
|
-
};
|
|
16
|
-
export const overrideParams = (route, overrides, filter) => {
|
|
17
|
-
Object.entries(overrides ?? {}).forEach(([key, value]) => {
|
|
18
|
-
if (route[key] == null
|
|
19
|
-
&& (filter == null || filter.includes(key))) {
|
|
20
|
-
route[key] = value;
|
|
5
|
+
export const makeRouteAddressHelper = (context) => {
|
|
6
|
+
const { isServiceRoute, isServiceRouteResolved } = serviceRouteHelper;
|
|
7
|
+
const carrier = (alias) => context.entrypoint(alias);
|
|
8
|
+
const getParentRoute = (route) => {
|
|
9
|
+
if (route.parent == null) {
|
|
10
|
+
return null;
|
|
21
11
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
* @throws {SyntaxError}
|
|
29
|
-
*/
|
|
30
|
-
export const resolveService = (context, route) => {
|
|
31
|
-
if (context.cfg.services == null) {
|
|
32
|
-
throw new SyntaxError('Services aren\'t configured to resolve routes');
|
|
33
|
-
}
|
|
34
|
-
const named = context.cfg.services[route.service ?? context.cfg.service];
|
|
35
|
-
if (named != null && !isServiceRoute(named)) {
|
|
36
|
-
throw new SyntaxError('Service is not a valid service route');
|
|
37
|
-
}
|
|
38
|
-
const service = named?.type === route.type ? named
|
|
39
|
-
: Object.values(context.cfg.services).find((candidate) => {
|
|
40
|
-
const _candidate = candidate;
|
|
41
|
-
return _candidate.default === true && _candidate.type === route.type;
|
|
42
|
-
}) ?? Object.values(context.cfg.services).find((candidate) => candidate.type === route.type);
|
|
43
|
-
if (!isServiceRoute(service)) {
|
|
44
|
-
throw new SyntaxError('Service is not a valid service route');
|
|
45
|
-
}
|
|
46
|
-
if (!isServiceRouteResolved(service)) {
|
|
47
|
-
throw new SyntaxError('Service route is not resolved');
|
|
48
|
-
}
|
|
49
|
-
return service;
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* The full path: every ancestor's declared segment, then this one. Walks the parent chain through
|
|
53
|
-
* the context, so a declaration always states only what it contributes.
|
|
54
|
-
*/
|
|
55
|
-
export const resolvePath = (context, route) => {
|
|
56
|
-
const parent = getParentRoute(context, route);
|
|
57
|
-
if (parent == null) {
|
|
58
|
-
return route.path;
|
|
59
|
-
}
|
|
60
|
-
const parentPath = resolvePath(context, parent);
|
|
61
|
-
return (parentPath.startsWith(SEP) ? SEP : '')
|
|
62
|
-
+ normalizePath(normalizePath(parentPath) + SEP + normalizePath(route.path));
|
|
63
|
-
};
|
|
64
|
-
/** `base` + the full path — what a server mounts and a client requests. */
|
|
65
|
-
export const resolveMount = (context, route) => {
|
|
66
|
-
const path = resolvePath(context, route);
|
|
67
|
-
const base = route.base ?? resolveService(context, route).base;
|
|
68
|
-
return base != null && base.trim() !== ''
|
|
69
|
-
? SEP + normalizePath(base) + SEP + normalizePath(path)
|
|
70
|
-
: path;
|
|
71
|
-
};
|
|
72
|
-
/**
|
|
73
|
-
* Where the route answers. A backend caller reaching a service over its INTERNAL host is inside the
|
|
74
|
-
* cluster, so that hop is never TLS.
|
|
75
|
-
*/
|
|
76
|
-
export const resolveAddress = (context, route) => {
|
|
77
|
-
const service = resolveService(context, route);
|
|
78
|
-
const host = route.host ?? service.host;
|
|
79
|
-
const internalHost = route.internalHost ?? service.internalHost;
|
|
80
|
-
return {
|
|
81
|
-
host,
|
|
82
|
-
port: route.port ?? service.port,
|
|
83
|
-
base: route.base ?? service.base,
|
|
84
|
-
secure: internalHost != null && internalHost === host ? false : route.secure ?? true,
|
|
85
|
-
protocol: route.protocol ?? RouteProtocols.WEB,
|
|
12
|
+
const parent = carrier(route.parent);
|
|
13
|
+
if (parent.route == null) {
|
|
14
|
+
throw new SyntaxError('Parent entrypoint doesn\'t provide a route');
|
|
15
|
+
}
|
|
16
|
+
assertCycle(route, parent.route.route);
|
|
17
|
+
return parent.route.route;
|
|
86
18
|
};
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
19
|
+
const resolveService = (route) => {
|
|
20
|
+
if (context.cfg.services == null) {
|
|
21
|
+
throw new SyntaxError('Services aren\'t configured to resolve routes');
|
|
22
|
+
}
|
|
23
|
+
const named = context.cfg.services[route.service ?? context.cfg.service];
|
|
24
|
+
if (named != null && !isServiceRoute(named)) {
|
|
25
|
+
throw new SyntaxError('Service is not a valid service route');
|
|
26
|
+
}
|
|
27
|
+
const service = named?.type === route.type ? named
|
|
28
|
+
: Object.values(context.cfg.services).find((candidate) => {
|
|
29
|
+
const _candidate = candidate;
|
|
30
|
+
return _candidate.default === true && _candidate.type === route.type;
|
|
31
|
+
}) ?? Object.values(context.cfg.services).find((candidate) => candidate.type === route.type);
|
|
32
|
+
if (!isServiceRoute(service)) {
|
|
33
|
+
throw new SyntaxError('Service is not a valid service route');
|
|
97
34
|
}
|
|
98
|
-
|
|
99
|
-
|
|
35
|
+
if (!isServiceRouteResolved(service)) {
|
|
36
|
+
throw new SyntaxError('Service route is not resolved');
|
|
37
|
+
}
|
|
38
|
+
return service;
|
|
39
|
+
};
|
|
40
|
+
const resolvePath = (route) => {
|
|
41
|
+
const parent = getParentRoute(route);
|
|
42
|
+
if (parent == null) {
|
|
43
|
+
return route.path;
|
|
44
|
+
}
|
|
45
|
+
const parentPath = resolvePath(parent);
|
|
46
|
+
return (parentPath.startsWith(SEP) ? SEP : '')
|
|
47
|
+
+ normalizePath(normalizePath(parentPath) + SEP + normalizePath(route.path));
|
|
48
|
+
};
|
|
49
|
+
const resolveMount = (route) => {
|
|
50
|
+
const path = resolvePath(route);
|
|
51
|
+
const base = route.base ?? resolveService(route).base;
|
|
52
|
+
return base != null && base.trim() !== ''
|
|
53
|
+
? SEP + normalizePath(base) + SEP + normalizePath(path)
|
|
54
|
+
: path;
|
|
55
|
+
};
|
|
56
|
+
const resolveAddress = (route) => {
|
|
57
|
+
const service = resolveService(route);
|
|
58
|
+
const host = route.host ?? service.host;
|
|
59
|
+
const internalHost = route.internalHost ?? service.internalHost;
|
|
60
|
+
return {
|
|
61
|
+
host,
|
|
62
|
+
port: route.port ?? service.port,
|
|
63
|
+
base: route.base ?? service.base,
|
|
64
|
+
secure: internalHost != null && internalHost === host ? false : route.secure ?? true,
|
|
65
|
+
protocol: route.protocol ?? RouteProtocols.WEB,
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
const isLocalRoute = (route) => (route.service ?? context.cfg.service) === context.cfg.service;
|
|
69
|
+
/**
|
|
70
|
+
* @throws {SyntaxError}
|
|
71
|
+
*/
|
|
72
|
+
const assertCycle = (route, parent) => {
|
|
73
|
+
while (parent.parent != null) {
|
|
74
|
+
if (parent.parent === route.alias) {
|
|
75
|
+
throw new SyntaxError(`Route parentship cycle detected. Parent: ${parent.alias} has his child as ancestor ${route.alias}`);
|
|
76
|
+
}
|
|
77
|
+
parent = carrier(parent.parent).route.route;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
return { getParentRoute, resolveService, resolvePath, resolveMount, resolveAddress, isLocalRoute };
|
|
100
81
|
};
|
|
101
|
-
export const
|
|
102
|
-
? SEP + normalizePath(route.base) + SEP + normalizePath(path)
|
|
103
|
-
: path;
|
|
82
|
+
export const routeAddressOf = memoHelper.oncePer(makeRouteAddressHelper);
|
|
104
83
|
//# sourceMappingURL=route.js.map
|
package/build/utils/route.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/utils/route.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/utils/route.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CommonServiceRoute, ResolvedServiceRoute } from '../../types.js';
|
|
2
|
+
/** Recognizes configured service routes. */
|
|
3
|
+
export interface ServiceRouteHelper {
|
|
4
|
+
/** Whether a configured value is a service route: it names a service and a known app type. */
|
|
5
|
+
isServiceRoute: (obj?: Object) => obj is CommonServiceRoute;
|
|
6
|
+
/** A service route is usable exactly when it knows the host it answers on. */
|
|
7
|
+
isServiceRouteResolved: (route: CommonServiceRoute) => route is ResolvedServiceRoute;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/service/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAE9E,4CAA4C;AAC5C,MAAM,WAAW,kBAAkB;IACjC,8FAA8F;IAC9F,cAAc,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,KAAK,GAAG,IAAI,kBAAkB,CAAA;IAC3D,8EAA8E;IAC9E,sBAAsB,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,KAAK,IAAI,oBAAoB,CAAA;CACrF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/service/types.ts"],"names":[],"mappings":""}
|
package/build/utils/service.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare const
|
|
3
|
-
|
|
4
|
-
export declare const isServiceRouteResolved: (route: CommonServiceRoute) => route is ResolvedServiceRoute;
|
|
1
|
+
import type { ServiceRouteHelper } from './service/types.js';
|
|
2
|
+
export declare const createServiceRouteHelper: () => ServiceRouteHelper;
|
|
3
|
+
export declare const serviceRouteHelper: ServiceRouteHelper;
|
|
5
4
|
//# sourceMappingURL=service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/utils/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/utils/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAE5D,eAAO,MAAM,wBAAwB,QAAO,kBAS3C,CAAA;AAED,eAAO,MAAM,kBAAkB,oBAA6B,CAAA"}
|
package/build/utils/service.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { AppType } from '@owlmeans/context';
|
|
2
|
-
export const
|
|
3
|
-
&& (
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
export const createServiceRouteHelper = () => {
|
|
3
|
+
const isServiceRoute = (obj) => obj != null && ('type' in obj) && ('service' in obj)
|
|
4
|
+
&& (Object.values(AppType).includes(obj.type));
|
|
5
|
+
const isServiceRouteResolved = (route) => route.host != null && route.host.trim() !== '';
|
|
6
|
+
return { isServiceRoute, isServiceRouteResolved };
|
|
7
|
+
};
|
|
8
|
+
export const serviceRouteHelper = createServiceRouteHelper();
|
|
6
9
|
//# sourceMappingURL=service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/utils/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/utils/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAI3C,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAuB,EAAE;IAC/D,MAAM,cAAc,GAAG,CAAC,GAAY,EAA6B,EAAE,CACjE,GAAG,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC;WACjD,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAe,CAAC,CAAC,CAAA;IAE3D,MAAM,sBAAsB,GAAG,CAAC,KAAyB,EAAiC,EAAE,CAC1F,KAAK,CAAC,IAAI,IAAI,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAA;IAEhD,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,CAAA;AACnD,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,wBAAwB,EAAE,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BasicConfig, Contextual } from '@owlmeans/context';
|
|
2
|
+
import type { RouteModel } from '../types.js';
|
|
3
|
+
export type Config = BasicConfig;
|
|
4
|
+
/** What an entrypoint looks like from the route layer: something that carries a route model. */
|
|
5
|
+
export interface RouteCarrier extends Contextual {
|
|
6
|
+
_entrypoint: true;
|
|
7
|
+
route: RouteModel;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=types.local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.local.d.ts","sourceRoot":"","sources":["../../src/utils/types.local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE7C,MAAM,MAAM,MAAM,GAAG,WAAW,CAAA;AAEhC,gGAAgG;AAChG,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C,WAAW,EAAE,IAAI,CAAA;IACjB,KAAK,EAAE,UAAU,CAAA;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.local.js","sourceRoot":"","sources":["../../src/utils/types.local.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/route",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.35",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@owlmeans/context": "^0.1.18-rc.
|
|
31
|
+
"@owlmeans/context": "^0.1.18-rc.34"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@owlmeans/dep-config": "workspace:*",
|
package/src/model.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { AppType } from '@owlmeans/context'
|
|
|
4
4
|
|
|
5
5
|
export const makeRouteModel = (route: RouteDeclaration): RouteModel => ({ route })
|
|
6
6
|
|
|
7
|
-
export const createRoute: CreateRouteSignature<RouteDeclaration> = (alias, path, opts?) => {
|
|
7
|
+
export const createRoute: CreateRouteSignature<RouteDeclaration> = (alias, path, opts?): RouteDeclaration => {
|
|
8
8
|
const options = typeof opts === 'string' ? { parent: opts } : opts
|
|
9
9
|
const { parent, ...rest } = options ?? {}
|
|
10
10
|
const route: RouteDeclaration = {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RouteDeclaration } from '../../types.js'
|
|
2
|
+
|
|
3
|
+
/** Context-free edits and reads of one route declaration. */
|
|
4
|
+
export interface RouteDeclarationHelper {
|
|
5
|
+
/** Fills the declaration's unset fields from `overrides`, limited to `filter` keys when given. */
|
|
6
|
+
overrideParams: (route: RouteDeclaration, overrides?: Partial<RouteDeclaration>, filter?: string[]) => void
|
|
7
|
+
/** `path` under the declaration's own `base`, when it has one. */
|
|
8
|
+
prependBase: (route: RouteDeclaration, path: string) => string
|
|
9
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RouteDeclaration } from '../types.js'
|
|
2
|
+
import { normalizePath } from '../helper.js'
|
|
3
|
+
import { SEP } from '../consts.js'
|
|
4
|
+
import type { RouteDeclarationHelper } from './declaration/types.js'
|
|
5
|
+
|
|
6
|
+
export const createRouteDeclarationHelper = (): RouteDeclarationHelper => {
|
|
7
|
+
const overrideParams = (route: RouteDeclaration, overrides?: Partial<RouteDeclaration>, filter?: string[]): void => {
|
|
8
|
+
Object.entries(overrides ?? {}).forEach(([key, value]) => {
|
|
9
|
+
if (route[key as keyof RouteDeclaration] == null
|
|
10
|
+
&& (filter == null || filter.includes(key))) {
|
|
11
|
+
(route[key as keyof RouteDeclaration] as RouteDeclaration[keyof RouteDeclaration]) = value
|
|
12
|
+
}
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const prependBase = (route: RouteDeclaration, path: string): string =>
|
|
17
|
+
route.base != null && route.base.trim() !== ''
|
|
18
|
+
? SEP + normalizePath(route.base) + SEP + normalizePath(path)
|
|
19
|
+
: path
|
|
20
|
+
|
|
21
|
+
return { overrideParams, prependBase }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const routeDeclarationHelper = createRouteDeclarationHelper()
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { RouteAddress, RouteDeclaration, ResolvedServiceRoute } from '../../types.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Where routes answer, worked out on demand against the context that asks — a declaration states
|
|
5
|
+
* only what it contributes and every address question walks the parent chain through the context.
|
|
6
|
+
*/
|
|
7
|
+
export interface RouteAddressHelper {
|
|
8
|
+
/**
|
|
9
|
+
* The declaration of the route's parent entrypoint, or `null` for a root route.
|
|
10
|
+
*
|
|
11
|
+
* @throws {SyntaxError} when the parent provides no route or the parent chain is a cycle
|
|
12
|
+
*/
|
|
13
|
+
getParentRoute: (route: RouteDeclaration) => RouteDeclaration | null
|
|
14
|
+
/**
|
|
15
|
+
* Pick the service route this declaration answers on: the one it names, else the default of its
|
|
16
|
+
* app type, else the first of its app type.
|
|
17
|
+
*
|
|
18
|
+
* @throws {SyntaxError}
|
|
19
|
+
*/
|
|
20
|
+
resolveService: (route: RouteDeclaration) => ResolvedServiceRoute
|
|
21
|
+
/**
|
|
22
|
+
* The full path: every ancestor's declared segment, then this one. Walks the parent chain through
|
|
23
|
+
* the context, so a declaration always states only what it contributes.
|
|
24
|
+
*/
|
|
25
|
+
resolvePath: (route: RouteDeclaration) => string
|
|
26
|
+
/** `base` + the full path — what a server mounts and a client requests. */
|
|
27
|
+
resolveMount: (route: RouteDeclaration) => string
|
|
28
|
+
/**
|
|
29
|
+
* Where the route answers. A backend caller reaching a service over its INTERNAL host is inside the
|
|
30
|
+
* cluster, so that hop is never TLS.
|
|
31
|
+
*/
|
|
32
|
+
resolveAddress: (route: RouteDeclaration) => RouteAddress
|
|
33
|
+
/** Does this route belong to the service the asking context IS? */
|
|
34
|
+
isLocalRoute: (route: RouteDeclaration) => boolean
|
|
35
|
+
}
|
package/src/utils/route.ts
CHANGED
|
@@ -1,151 +1,111 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type {
|
|
3
|
-
import {
|
|
1
|
+
import { memoHelper } from '@owlmeans/context'
|
|
2
|
+
import type { BasicContext } from '@owlmeans/context'
|
|
3
|
+
import type { RouteAddress, RouteDeclaration, CommonServiceRoute, ResolvedServiceRoute } from '../types.js'
|
|
4
|
+
import { serviceRouteHelper } from './service.js'
|
|
4
5
|
import { normalizePath } from '../helper.js'
|
|
5
6
|
import { RouteProtocols, SEP } from '../consts.js'
|
|
7
|
+
import type { Config, RouteCarrier } from './types.local.js'
|
|
8
|
+
import type { RouteAddressHelper } from './route/types.js'
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
export const makeRouteAddressHelper = <C extends Config, T extends BasicContext<C>>(context: T): RouteAddressHelper => {
|
|
11
|
+
const { isServiceRoute, isServiceRouteResolved } = serviceRouteHelper
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
_entrypoint: true
|
|
12
|
-
route: RouteModel
|
|
13
|
-
}
|
|
13
|
+
const carrier = (alias: string): RouteCarrier =>
|
|
14
|
+
context.entrypoint<RouteCarrier>(alias)
|
|
14
15
|
|
|
15
|
-
const
|
|
16
|
-
|
|
16
|
+
const getParentRoute = (route: RouteDeclaration): RouteDeclaration | null => {
|
|
17
|
+
if (route.parent == null) {
|
|
18
|
+
return null
|
|
19
|
+
}
|
|
20
|
+
const parent = carrier(route.parent)
|
|
21
|
+
if (parent.route == null) {
|
|
22
|
+
throw new SyntaxError('Parent entrypoint doesn\'t provide a route')
|
|
23
|
+
}
|
|
24
|
+
assertCycle(route, parent.route.route)
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
context: T, route: RouteDeclaration
|
|
20
|
-
): RouteDeclaration | null => {
|
|
21
|
-
if (route.parent == null) {
|
|
22
|
-
return null
|
|
26
|
+
return parent.route.route
|
|
23
27
|
}
|
|
24
|
-
const parent = carrier<C, T>(context, route.parent)
|
|
25
|
-
if (parent.route == null) {
|
|
26
|
-
throw new SyntaxError('Parent entrypoint doesn\'t provide a route')
|
|
27
|
-
}
|
|
28
|
-
assertCycle<C, T>(context, route, parent.route.route)
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
const resolveService = (route: RouteDeclaration): ResolvedServiceRoute => {
|
|
30
|
+
if (context.cfg.services == null) {
|
|
31
|
+
throw new SyntaxError('Services aren\'t configured to resolve routes')
|
|
32
|
+
}
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
&& (filter == null || filter.includes(key))) {
|
|
37
|
-
(route[key as keyof RouteDeclaration] as RouteDeclaration[keyof RouteDeclaration]) = value
|
|
34
|
+
const named = context.cfg.services[route.service ?? context.cfg.service]
|
|
35
|
+
if (named != null && !isServiceRoute(named)) {
|
|
36
|
+
throw new SyntaxError('Service is not a valid service route')
|
|
38
37
|
}
|
|
39
|
-
})
|
|
40
|
-
}
|
|
41
38
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
39
|
+
const service = named?.type === route.type ? named
|
|
40
|
+
: Object.values(context.cfg.services).find<CommonServiceRoute>(
|
|
41
|
+
(candidate): candidate is CommonServiceRoute => {
|
|
42
|
+
const _candidate = candidate as CommonServiceRoute
|
|
43
|
+
return _candidate.default === true && _candidate.type === route.type
|
|
44
|
+
}
|
|
45
|
+
) ?? Object.values(context.cfg.services).find<CommonServiceRoute>(
|
|
46
|
+
(candidate): candidate is CommonServiceRoute => (candidate as CommonServiceRoute).type === route.type
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
if (!isServiceRoute(service)) {
|
|
50
|
+
throw new SyntaxError('Service is not a valid service route')
|
|
51
|
+
}
|
|
52
|
+
if (!isServiceRouteResolved(service)) {
|
|
53
|
+
throw new SyntaxError('Service route is not resolved')
|
|
54
|
+
}
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
if (named != null && !isServiceRoute(named)) {
|
|
57
|
-
throw new SyntaxError('Service is not a valid service route')
|
|
56
|
+
return service
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
) ?? Object.values(context.cfg.services).find<CommonServiceRoute>(
|
|
67
|
-
(candidate): candidate is CommonServiceRoute => (candidate as CommonServiceRoute).type === route.type
|
|
68
|
-
)
|
|
59
|
+
const resolvePath = (route: RouteDeclaration): string => {
|
|
60
|
+
const parent = getParentRoute(route)
|
|
61
|
+
if (parent == null) {
|
|
62
|
+
return route.path
|
|
63
|
+
}
|
|
64
|
+
const parentPath = resolvePath(parent)
|
|
69
65
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
if (!isServiceRouteResolved(service)) {
|
|
74
|
-
throw new SyntaxError('Service route is not resolved')
|
|
66
|
+
return (parentPath.startsWith(SEP) ? SEP : '')
|
|
67
|
+
+ normalizePath(normalizePath(parentPath) + SEP + normalizePath(route.path))
|
|
75
68
|
}
|
|
76
69
|
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
const resolveMount = (route: RouteDeclaration): string => {
|
|
71
|
+
const path = resolvePath(route)
|
|
72
|
+
const base = route.base ?? resolveService(route).base
|
|
79
73
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
*/
|
|
84
|
-
export const resolvePath = <C extends Config, T extends BasicContext<C>>(
|
|
85
|
-
context: T, route: RouteDeclaration
|
|
86
|
-
): string => {
|
|
87
|
-
const parent = getParentRoute<C, T>(context, route)
|
|
88
|
-
if (parent == null) {
|
|
89
|
-
return route.path
|
|
74
|
+
return base != null && base.trim() !== ''
|
|
75
|
+
? SEP + normalizePath(base) + SEP + normalizePath(path)
|
|
76
|
+
: path
|
|
90
77
|
}
|
|
91
|
-
const parentPath = resolvePath<C, T>(context, parent)
|
|
92
|
-
|
|
93
|
-
return (parentPath.startsWith(SEP) ? SEP : '')
|
|
94
|
-
+ normalizePath(normalizePath(parentPath) + SEP + normalizePath(route.path))
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** `base` + the full path — what a server mounts and a client requests. */
|
|
98
|
-
export const resolveMount = <C extends Config, T extends BasicContext<C>>(
|
|
99
|
-
context: T, route: RouteDeclaration
|
|
100
|
-
): string => {
|
|
101
|
-
const path = resolvePath<C, T>(context, route)
|
|
102
|
-
const base = route.base ?? resolveService<C, T>(context, route).base
|
|
103
|
-
|
|
104
|
-
return base != null && base.trim() !== ''
|
|
105
|
-
? SEP + normalizePath(base) + SEP + normalizePath(path)
|
|
106
|
-
: path
|
|
107
|
-
}
|
|
108
78
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
host,
|
|
122
|
-
port: route.port ?? service.port,
|
|
123
|
-
base: route.base ?? service.base,
|
|
124
|
-
secure: internalHost != null && internalHost === host ? false : route.secure ?? true,
|
|
125
|
-
protocol: route.protocol ?? RouteProtocols.WEB,
|
|
79
|
+
const resolveAddress = (route: RouteDeclaration): RouteAddress => {
|
|
80
|
+
const service = resolveService(route)
|
|
81
|
+
const host = route.host ?? service.host
|
|
82
|
+
const internalHost = route.internalHost ?? service.internalHost
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
host,
|
|
86
|
+
port: route.port ?? service.port,
|
|
87
|
+
base: route.base ?? service.base,
|
|
88
|
+
secure: internalHost != null && internalHost === host ? false : route.secure ?? true,
|
|
89
|
+
protocol: route.protocol ?? RouteProtocols.WEB,
|
|
90
|
+
}
|
|
126
91
|
}
|
|
127
|
-
}
|
|
128
92
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (parent.parent === route.alias) {
|
|
142
|
-
throw new SyntaxError(`Route parentship cycle detected. Parent: ${parent.alias} has his child as ancestor ${route.alias}`)
|
|
93
|
+
const isLocalRoute = (route: RouteDeclaration): boolean =>
|
|
94
|
+
(route.service ?? context.cfg.service) === context.cfg.service
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @throws {SyntaxError}
|
|
98
|
+
*/
|
|
99
|
+
const assertCycle = (route: RouteDeclaration, parent: RouteDeclaration): void => {
|
|
100
|
+
while (parent.parent != null) {
|
|
101
|
+
if (parent.parent === route.alias) {
|
|
102
|
+
throw new SyntaxError(`Route parentship cycle detected. Parent: ${parent.alias} has his child as ancestor ${route.alias}`)
|
|
103
|
+
}
|
|
104
|
+
parent = carrier(parent.parent).route.route
|
|
143
105
|
}
|
|
144
|
-
parent = carrier<C, T>(context, parent.parent).route.route
|
|
145
106
|
}
|
|
107
|
+
|
|
108
|
+
return { getParentRoute, resolveService, resolvePath, resolveMount, resolveAddress, isLocalRoute }
|
|
146
109
|
}
|
|
147
110
|
|
|
148
|
-
export const
|
|
149
|
-
route.base != null && route.base.trim() !== ''
|
|
150
|
-
? SEP + normalizePath(route.base) + SEP + normalizePath(path)
|
|
151
|
-
: path
|
|
111
|
+
export const routeAddressOf = memoHelper.oncePer(makeRouteAddressHelper)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CommonServiceRoute, ResolvedServiceRoute } from '../../types.js'
|
|
2
|
+
|
|
3
|
+
/** Recognizes configured service routes. */
|
|
4
|
+
export interface ServiceRouteHelper {
|
|
5
|
+
/** Whether a configured value is a service route: it names a service and a known app type. */
|
|
6
|
+
isServiceRoute: (obj?: Object) => obj is CommonServiceRoute
|
|
7
|
+
/** A service route is usable exactly when it knows the host it answers on. */
|
|
8
|
+
isServiceRouteResolved: (route: CommonServiceRoute) => route is ResolvedServiceRoute
|
|
9
|
+
}
|
package/src/utils/service.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { AppType } from '@owlmeans/context'
|
|
2
2
|
import type { ResolvedServiceRoute, CommonServiceRoute } from '../types.js'
|
|
3
|
+
import type { ServiceRouteHelper } from './service/types.js'
|
|
3
4
|
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export const createServiceRouteHelper = (): ServiceRouteHelper => {
|
|
6
|
+
const isServiceRoute = (obj?: Object): obj is CommonServiceRoute =>
|
|
7
|
+
obj != null && ('type' in obj) && ('service' in obj)
|
|
8
|
+
&& (Object.values(AppType).includes(obj.type as AppType))
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
const isServiceRouteResolved = (route: CommonServiceRoute): route is ResolvedServiceRoute =>
|
|
11
|
+
route.host != null && route.host.trim() !== ''
|
|
12
|
+
|
|
13
|
+
return { isServiceRoute, isServiceRouteResolved }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const serviceRouteHelper = createServiceRouteHelper()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BasicConfig, Contextual } from '@owlmeans/context'
|
|
2
|
+
import type { RouteModel } from '../types.js'
|
|
3
|
+
|
|
4
|
+
export type Config = BasicConfig
|
|
5
|
+
|
|
6
|
+
/** What an entrypoint looks like from the route layer: something that carries a route model. */
|
|
7
|
+
export interface RouteCarrier extends Contextual {
|
|
8
|
+
_entrypoint: true
|
|
9
|
+
route: RouteModel
|
|
10
|
+
}
|