@owlmeans/route 0.1.18-rc.0 → 0.1.18-rc.10
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 +37 -13
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/route/SKILL.md +66 -10
- package/build/consts.d.ts +7 -1
- package/build/consts.d.ts.map +1 -1
- package/build/consts.js +6 -0
- package/build/consts.js.map +1 -1
- package/build/helper.d.ts +8 -2
- package/build/helper.d.ts.map +1 -1
- package/build/helper.js +10 -0
- package/build/helper.js.map +1 -1
- package/build/model.d.ts +3 -3
- package/build/model.d.ts.map +1 -1
- package/build/model.js +5 -10
- package/build/model.js.map +1 -1
- package/build/types.d.ts +46 -15
- package/build/types.d.ts.map +1 -1
- package/build/utils/route.d.ts +25 -5
- package/build/utils/route.d.ts.map +1 -1
- package/build/utils/route.js +68 -67
- package/build/utils/route.js.map +1 -1
- package/build/utils/service.d.ts +1 -0
- package/build/utils/service.d.ts.map +1 -1
- package/build/utils/service.js +2 -1
- package/build/utils/service.js.map +1 -1
- package/package.json +2 -2
- package/src/consts.ts +7 -1
- package/src/helper.ts +15 -2
- package/src/model.ts +9 -15
- package/src/types.ts +48 -15
- package/src/utils/route.ts +101 -71
- package/src/utils/service.ts +2 -1
- package/build/.gitkeep +0 -0
package/README.md
CHANGED
|
@@ -1,49 +1,54 @@
|
|
|
1
1
|
# @owlmeans/route
|
|
2
2
|
|
|
3
|
-
Route model factory and type definitions for OwlMeans
|
|
3
|
+
Route model factory and type definitions for OwlMeans entrypoints.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
- `route()` creates a `
|
|
7
|
+
- `route()` creates a `RouteModel` used as the first argument to `entrypoint()`
|
|
8
8
|
- `frontend()` / `backend()` / `socket()` helpers set the route's `AppType` and parent
|
|
9
9
|
- `RouteMethod` enum covers HTTP verbs; `RouteProtocols` covers `http`/`ws`
|
|
10
|
-
- This package is a dependency of `@owlmeans/
|
|
10
|
+
- This package is a dependency of `@owlmeans/entrypoint` — you rarely use it directly unless defining entrypoint-level routes
|
|
11
|
+
|
|
12
|
+
A `RouteDeclaration` is plain, immutable data: its `path` is the segment the route contributes under
|
|
13
|
+
its parent, and it is never rewritten. Where the route actually answers — the full path, the mount
|
|
14
|
+
under a service base, the host and scheme — is computed on demand from the declaration plus the
|
|
15
|
+
context that asks, so the same declaration serves a server and a browser alike.
|
|
11
16
|
|
|
12
17
|
## Installation
|
|
13
18
|
|
|
14
19
|
```bash
|
|
15
|
-
bun add @owlmeans/route
|
|
20
|
+
bun add @owlmeans/route@^0.1.18-rc.8
|
|
16
21
|
```
|
|
17
22
|
|
|
18
23
|
## Usage
|
|
19
24
|
|
|
20
|
-
Define routes for
|
|
25
|
+
Define routes for entrypoints (typically via `@owlmeans/server-app` re-exports):
|
|
21
26
|
|
|
22
27
|
```typescript
|
|
23
28
|
import { route, frontend, backend, socket, RouteMethod } from '@owlmeans/route'
|
|
24
|
-
import {
|
|
29
|
+
import { entrypoint } from '@owlmeans/entrypoint'
|
|
25
30
|
|
|
26
31
|
// Backend REST route
|
|
27
|
-
const
|
|
32
|
+
const createEntrypoint = entrypoint(
|
|
28
33
|
route('story-create', '/stories', backend('api', RouteMethod.POST))
|
|
29
34
|
)
|
|
30
35
|
|
|
31
36
|
// Frontend client route nested under parent
|
|
32
|
-
const
|
|
37
|
+
const storyEntrypoint = entrypoint(
|
|
33
38
|
route('story-view', '/stories/:id', frontend('app'))
|
|
34
39
|
)
|
|
35
40
|
|
|
36
41
|
// WebSocket route
|
|
37
|
-
const
|
|
42
|
+
const wsEntrypoint = entrypoint(
|
|
38
43
|
route('story-ws', '/stories/stream', socket('api'))
|
|
39
44
|
)
|
|
40
45
|
```
|
|
41
46
|
|
|
42
47
|
## API
|
|
43
48
|
|
|
44
|
-
### `route(alias, path, opts?):
|
|
49
|
+
### `route(alias, path, opts?): RouteModel`
|
|
45
50
|
|
|
46
|
-
Creates a route model. `opts` can be a `RouteOptions` object or the result of `frontend()`, `backend()`, or `socket()`.
|
|
51
|
+
Creates a route model. `path` is the segment this route contributes under its parent. `opts` can be a `RouteOptions` object or the result of `frontend()`, `backend()`, or `socket()`.
|
|
47
52
|
|
|
48
53
|
### `frontend(parent?, sticky?): Partial<RouteOptions>`
|
|
49
54
|
|
|
@@ -69,9 +74,28 @@ enum RouteMethod { GET, POST, PATCH, PUT, DELETE }
|
|
|
69
74
|
enum RouteProtocols { WEB = 'http', SOCKET = 'ws' }
|
|
70
75
|
```
|
|
71
76
|
|
|
77
|
+
The protocol also selects the transport that carries a call to an entrypoint on this route.
|
|
78
|
+
|
|
79
|
+
### Types
|
|
80
|
+
|
|
81
|
+
- `RouteDeclaration` — the plain, immutable data a `route()` call produces: `alias`, `path`,
|
|
82
|
+
`parent`, `method`, `protocol`, `secure`, plus the service coordinates
|
|
83
|
+
- `RouteModel` — `{ route: RouteDeclaration }`, the model an entrypoint carries
|
|
84
|
+
- `RouteAddress` — `{ host, port?, base?, secure, protocol }`, where a route answers once its
|
|
85
|
+
service has been picked
|
|
86
|
+
|
|
87
|
+
### `@owlmeans/route/utils`
|
|
88
|
+
|
|
89
|
+
The pure functions the entrypoint accessors are built on. Each takes a context and a declaration:
|
|
90
|
+
|
|
91
|
+
- `resolveService(ctx, route)` / `isLocalRoute(ctx, route)`
|
|
92
|
+
- `resolvePath(ctx, route)` — the route's segment under every ancestor's
|
|
93
|
+
- `resolveMount(ctx, route)` — that path under the service base
|
|
94
|
+
- `resolveAddress(ctx, route)` — host, port, scheme and protocol
|
|
95
|
+
|
|
72
96
|
## Related Packages
|
|
73
97
|
|
|
74
|
-
- [`@owlmeans/
|
|
98
|
+
- [`@owlmeans/entrypoint`](../entrypoint) — `entrypoint()` takes a `RouteModel` as first argument
|
|
75
99
|
- [`@owlmeans/server-app`](../server-app) — re-exports `route` as `broute` (backend) alongside `route`
|
|
76
100
|
|
|
77
101
|
<!-- owlmeans:agent-guidance:start -->
|
|
@@ -82,7 +106,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
82
106
|
your project's skill store (`.agents/skills/`):
|
|
83
107
|
|
|
84
108
|
```sh
|
|
85
|
-
npx @owlmeans/agent-skills
|
|
109
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.13
|
|
86
110
|
```
|
|
87
111
|
|
|
88
112
|
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.10",
|
|
5
|
+
"generatedAt": "2026-09-10T18:54:42.502Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: route
|
|
3
|
-
description: How to use @owlmeans/route — route()
|
|
3
|
+
description: How to use @owlmeans/route — route() for declaring URL segments, frontend()/backend()/socket()/job() markers, RouteMethod and RouteProtocols enums, and the address helpers under ./utils. Auto-invoked when importing route helpers or defining an entrypoint's URL path.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
@@ -8,21 +8,74 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/route
|
|
9
9
|
|
|
10
10
|
**Layer:** Core
|
|
11
|
-
**Install:** `"@owlmeans/route": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/route": "^0.1.18-rc.10"` in `dependencies`
|
|
12
12
|
|
|
13
13
|
## Key Exports
|
|
14
14
|
|
|
15
15
|
| Export | Description |
|
|
16
16
|
|--------|-------------|
|
|
17
|
-
| `route(alias, path, options?)` |
|
|
18
|
-
| `frontend(options?)` | Mark a route as a React page (web only) |
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
|
|
|
17
|
+
| `route(alias, path, options?)` | Build a route model — `path` is the segment contributed under `parent` |
|
|
18
|
+
| `frontend(options?, default?)` | Mark a route as a React page (web only) |
|
|
19
|
+
| `backend(options?, method?)` | Mark a route as a backend endpoint |
|
|
20
|
+
| `socket(options?, secondary?)` | A backend route answering over `RouteProtocols.SOCKET` |
|
|
21
|
+
| `job(options?, secondary?)` | A backend route carried by the queue (`RouteProtocols.QUEUE`); its declaration adds `queue`, `reply` and `timeout` |
|
|
22
|
+
| `service(alias, options?)` | Point a route at a named service |
|
|
23
|
+
| `RouteMethod` | enum of GET, POST, PUT, PATCH, DELETE |
|
|
24
|
+
| `RouteProtocols` | enum of WEB (`http`), SOCKET (`ws`), QUEUE (`queue`) |
|
|
25
|
+
| `rtype(type, options?)` | The primitive `frontend()` / `backend()` are built from |
|
|
26
|
+
| `createRoute(alias, path, opts?)` / `makeRouteModel(decl)` | The declaration and its wrapper, when you need them apart |
|
|
27
|
+
| `BasicRoute` | `{ type, service?, host?, port?, base?, internalHost?, internalPort? }` |
|
|
28
|
+
| `RouteDeclaration` | The immutable declaration `route()` produces |
|
|
29
|
+
| `RouteOptions` | `Partial<RouteDeclaration>` — what the marker helpers return |
|
|
30
|
+
| `RouteModel` | `{ route }` — the model wrapping a declaration |
|
|
31
|
+
| `RouteAddress` | `{ host, port, base, secure, protocol }` — where a route answers |
|
|
32
|
+
| `CommonServiceRoute` / `ResolvedServiceRoute` | A service entry, and one that knows its host |
|
|
33
|
+
| `normalizePath(path)`, `SEP`, `PARAM` | Path primitives |
|
|
34
|
+
|
|
35
|
+
## Declaration and model
|
|
36
|
+
|
|
37
|
+
`route()` returns a `RouteModel` that does nothing but **wrap an immutable `RouteDeclaration`**. The
|
|
38
|
+
declaration is plain data an application ships in its contract package: `path` stays the segment this
|
|
39
|
+
route contributes under its parent and is never rewritten, and the model carries no state of its own.
|
|
40
|
+
Where the route answers is worked out on demand, against the context that asks — which is what lets
|
|
41
|
+
the same declaration serve a client and a server at once.
|
|
42
|
+
|
|
43
|
+
## Protocol picks the transport
|
|
44
|
+
|
|
45
|
+
A route names the protocol it answers on, and an application binds one by registering a transport
|
|
46
|
+
service under `transportAlias(protocol)`. So the protocol is what decides whether a call travels as
|
|
47
|
+
an HTTP request, a socket frame or a queued job — the call site never says. Both `transportAlias`
|
|
48
|
+
and the `EntrypointTransport` contract a transport implements are exported by `@owlmeans/entrypoint`,
|
|
49
|
+
not by this package; a route only names the protocol.
|
|
50
|
+
|
|
51
|
+
`job()` is `backend()` with `RouteProtocols.QUEUE`. Three declaration fields matter only for that
|
|
52
|
+
protocol: `queue` (which queue carries it), `reply` and `timeout`. `reply: false` resolves once the
|
|
53
|
+
broker has taken the job — the value is the job's identity and the outcome is `Accepted`, not the
|
|
54
|
+
job's result; the default is to wait for the result.
|
|
22
55
|
|
|
23
56
|
## Subpath Exports
|
|
24
57
|
|
|
25
|
-
|
|
58
|
+
`./utils` holds two kinds of helper, and their signatures differ. The six that answer *where* a
|
|
59
|
+
route lives take `(context, declaration)`, because that is a question about the asking context. The
|
|
60
|
+
other four are pure functions over a declaration or a service entry and take **no context**.
|
|
61
|
+
Passing one to them resolves nothing: `overrideParams(ctx, decl)` writes route fields straight into
|
|
62
|
+
the context object instead.
|
|
63
|
+
|
|
64
|
+
| Helper | Signature | Answers |
|
|
65
|
+
|--------|-----------|---------|
|
|
66
|
+
| `resolvePath` | `(context, route)` | Every ancestor's segment, then this one |
|
|
67
|
+
| `resolveMount` | `(context, route)` | `base` + the full path — what a server mounts and a client requests |
|
|
68
|
+
| `resolveService` | `(context, route)` | The service the declaration answers on: the one it names, else the default of its app type, else the first of that type |
|
|
69
|
+
| `resolveAddress` | `(context, route)` | The `RouteAddress`; a hop over a service's INTERNAL host is never TLS |
|
|
70
|
+
| `isLocalRoute` | `(context, route)` | Does the route belong to the service the asking context IS? |
|
|
71
|
+
| `getParentRoute` | `(context, route)` | The parent declaration, with parentship-cycle detection |
|
|
72
|
+
| `overrideParams` | `(route, overrides?, filter?)` | Fill in **only the blank** fields of `route` from `overrides`; `filter` narrows it to the listed keys. Mutates `route` and returns nothing |
|
|
73
|
+
| `prependBase` | `(route, path)` | `path` prefixed with `route.base`, or `path` when there is no base |
|
|
74
|
+
| `isServiceRoute` | `(obj?)` | Type guard: is this a service entry (`type` + `service`, `type` a known `AppType`)? |
|
|
75
|
+
| `isServiceRouteResolved` | `(route)` | Type guard: does that service entry name a host? |
|
|
76
|
+
|
|
77
|
+
Application code rarely calls these directly — `@owlmeans/entrypoint` exposes them as `path()`,
|
|
78
|
+
`mount()`, `service()`, `address()` and `isLocal()` on the entrypoint itself.
|
|
26
79
|
|
|
27
80
|
## Usage
|
|
28
81
|
|
|
@@ -46,5 +99,8 @@ entrypoint(
|
|
|
46
99
|
|
|
47
100
|
## Depends On
|
|
48
101
|
|
|
49
|
-
- `@owlmeans/
|
|
50
|
-
|
|
102
|
+
- `@owlmeans/context` — `AppType`, and the entrypoint registry the address helpers walk
|
|
103
|
+
|
|
104
|
+
That is the only dependency. The address helpers signal a mis-wired route tree by throwing
|
|
105
|
+
`SyntaxError` — an unconfigured service, an unresolved host, a parentship cycle — so the process
|
|
106
|
+
crashes on a wiring mistake instead of serving a wrong URL.
|
package/build/consts.d.ts
CHANGED
|
@@ -7,8 +7,14 @@ export declare enum RouteMethod {
|
|
|
7
7
|
}
|
|
8
8
|
export declare const SEP = "/";
|
|
9
9
|
export declare const PARAM = ":";
|
|
10
|
+
/**
|
|
11
|
+
* How a route is carried. The protocol picks the transport that answers it — an application binds
|
|
12
|
+
* one by registering a service under `transportAlias(protocol)` — so a caller writes `call()` and
|
|
13
|
+
* never learns whether an HTTP request, a socket frame or a queued job did the work.
|
|
14
|
+
*/
|
|
10
15
|
export declare enum RouteProtocols {
|
|
11
16
|
WEB = "http",
|
|
12
|
-
SOCKET = "ws"
|
|
17
|
+
SOCKET = "ws",
|
|
18
|
+
QUEUE = "queue"
|
|
13
19
|
}
|
|
14
20
|
//# sourceMappingURL=consts.d.ts.map
|
package/build/consts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,oBAAY,WAAW;IACrB,GAAG,QAAQ;IACX,IAAI,SAAS;IACb,KAAK,UAAU;IACf,GAAG,QAAQ;IACX,MAAM,WAAW;CAClB;AAED,eAAO,MAAM,GAAG,MAAM,CAAA;AAEtB,eAAO,MAAM,KAAK,MAAM,CAAA;AAExB,oBAAY,cAAc;IACxB,GAAG,SAAS;IACZ,MAAM,OAAO;
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,oBAAY,WAAW;IACrB,GAAG,QAAQ;IACX,IAAI,SAAS;IACb,KAAK,UAAU;IACf,GAAG,QAAQ;IACX,MAAM,WAAW;CAClB;AAED,eAAO,MAAM,GAAG,MAAM,CAAA;AAEtB,eAAO,MAAM,KAAK,MAAM,CAAA;AAExB;;;;GAIG;AACH,oBAAY,cAAc;IACxB,GAAG,SAAS;IACZ,MAAM,OAAO;IACb,KAAK,UAAU;CAChB"}
|
package/build/consts.js
CHANGED
|
@@ -8,9 +8,15 @@ export var RouteMethod;
|
|
|
8
8
|
})(RouteMethod || (RouteMethod = {}));
|
|
9
9
|
export const SEP = '/';
|
|
10
10
|
export const PARAM = ':';
|
|
11
|
+
/**
|
|
12
|
+
* How a route is carried. The protocol picks the transport that answers it — an application binds
|
|
13
|
+
* one by registering a service under `transportAlias(protocol)` — so a caller writes `call()` and
|
|
14
|
+
* never learns whether an HTTP request, a socket frame or a queued job did the work.
|
|
15
|
+
*/
|
|
11
16
|
export var RouteProtocols;
|
|
12
17
|
(function (RouteProtocols) {
|
|
13
18
|
RouteProtocols["WEB"] = "http";
|
|
14
19
|
RouteProtocols["SOCKET"] = "ws";
|
|
20
|
+
RouteProtocols["QUEUE"] = "queue";
|
|
15
21
|
})(RouteProtocols || (RouteProtocols = {}));
|
|
16
22
|
//# sourceMappingURL=consts.js.map
|
package/build/consts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,MAAM,CAAN,IAAY,WAMX;AAND,WAAY,WAAW;IACrB,0BAAW,CAAA;IACX,4BAAa,CAAA;IACb,8BAAe,CAAA;IACf,0BAAW,CAAA;IACX,gCAAiB,CAAA;AACnB,CAAC,EANW,WAAW,KAAX,WAAW,QAMtB;AAED,MAAM,CAAC,MAAM,GAAG,GAAG,GAAG,CAAA;AAEtB,MAAM,CAAC,MAAM,KAAK,GAAG,GAAG,CAAA;AAExB,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,MAAM,CAAN,IAAY,WAMX;AAND,WAAY,WAAW;IACrB,0BAAW,CAAA;IACX,4BAAa,CAAA;IACb,8BAAe,CAAA;IACf,0BAAW,CAAA;IACX,gCAAiB,CAAA;AACnB,CAAC,EANW,WAAW,KAAX,WAAW,QAMtB;AAED,MAAM,CAAC,MAAM,GAAG,GAAG,GAAG,CAAA;AAEtB,MAAM,CAAC,MAAM,KAAK,GAAG,GAAG,CAAA;AAExB;;;;GAIG;AACH,MAAM,CAAN,IAAY,cAIX;AAJD,WAAY,cAAc;IACxB,8BAAY,CAAA;IACZ,+BAAa,CAAA;IACb,iCAAe,CAAA;AACjB,CAAC,EAJW,cAAc,KAAd,cAAc,QAIzB"}
|
package/build/helper.d.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { AppType } from '@owlmeans/context';
|
|
2
2
|
import { RouteMethod } from './consts.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { RouteModel, RouteOptions } from './types.js';
|
|
4
4
|
import type { CreateRouteSignature } from './utils/types.js';
|
|
5
|
-
export declare const route: CreateRouteSignature<
|
|
5
|
+
export declare const route: CreateRouteSignature<RouteModel>;
|
|
6
6
|
export declare const normalizePath: (path: string) => string;
|
|
7
7
|
export declare const rtype: (type: AppType, opts?: RouteOptions | string) => Partial<RouteOptions>;
|
|
8
8
|
export declare const backend: (opts?: RouteOptions | string | null, method?: RouteOptions | RouteMethod) => Partial<RouteOptions>;
|
|
9
9
|
export declare const service: (service: string, opts?: Partial<RouteOptions>) => Partial<RouteOptions>;
|
|
10
10
|
export declare const socket: (opts?: RouteOptions | string | null, secondary?: RouteOptions) => Partial<RouteOptions>;
|
|
11
|
+
/**
|
|
12
|
+
* A backend route carried by the queue rather than by HTTP. Everything else about it is a normal
|
|
13
|
+
* backend route — it has a path, a parent, guards and a filter — so the same declaration is served
|
|
14
|
+
* with `elevate(...)` and called with `call()`; only the transport underneath differs.
|
|
15
|
+
*/
|
|
16
|
+
export declare const job: (opts?: RouteOptions | string | null, secondary?: RouteOptions) => Partial<RouteOptions>;
|
|
11
17
|
export declare const frontend: (opts?: RouteOptions | string | null, def?: RouteOptions | boolean) => Partial<RouteOptions>;
|
|
12
18
|
//# sourceMappingURL=helper.d.ts.map
|
package/build/helper.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAuB,MAAM,aAAa,CAAA;AAE9D,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAuB,MAAM,aAAa,CAAA;AAE9D,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAE5D,eAAO,MAAM,KAAK,EAAE,oBAAoB,CAAC,UAAU,CACH,CAAA;AAEhD,eAAO,MAAM,aAAa,SAAU,MAAM,KAAG,MAM5C,CAAA;AAED,eAAO,MAAM,KAAK,SAAU,OAAO,SAAS,YAAY,GAAG,MAAM,KAAG,OAAO,CAAC,YAAY,CAEvF,CAAA;AAED,eAAO,MAAM,OAAO,UAAW,YAAY,GAAG,MAAM,GAAG,IAAI,WAAW,YAAY,GAAG,WAAW,KAAG,OAAO,CAAC,YAAY,CAQtH,CAAA;AAED,eAAO,MAAM,OAAO,YAAa,MAAM,SAAS,OAAO,CAAC,YAAY,CAAC,KAAG,OAAO,CAAC,YAAY,CAI3F,CAAA;AAED,eAAO,MAAM,MAAM,UAAW,YAAY,GAAG,MAAM,GAAG,IAAI,cAAc,YAAY,KAAG,OAAO,CAAC,YAAY,CAM1G,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,GAAG,UAAW,YAAY,GAAG,MAAM,GAAG,IAAI,cAAc,YAAY,KAAG,OAAO,CAAC,YAAY,CAMvG,CAAA;AAED,eAAO,MAAM,QAAQ,UAAW,YAAY,GAAG,MAAM,GAAG,IAAI,QAAQ,YAAY,GAAG,OAAO,KAAG,OAAO,CAAC,YAAY,CAQhH,CAAA"}
|
package/build/helper.js
CHANGED
|
@@ -28,6 +28,16 @@ export const socket = (opts, secondary) => {
|
|
|
28
28
|
route.protocol = RouteProtocols.SOCKET;
|
|
29
29
|
return route;
|
|
30
30
|
};
|
|
31
|
+
/**
|
|
32
|
+
* A backend route carried by the queue rather than by HTTP. Everything else about it is a normal
|
|
33
|
+
* backend route — it has a path, a parent, guards and a filter — so the same declaration is served
|
|
34
|
+
* with `elevate(...)` and called with `call()`; only the transport underneath differs.
|
|
35
|
+
*/
|
|
36
|
+
export const job = (opts, secondary) => {
|
|
37
|
+
const route = backend(opts, secondary);
|
|
38
|
+
route.protocol = RouteProtocols.QUEUE;
|
|
39
|
+
return route;
|
|
40
|
+
};
|
|
31
41
|
export const frontend = (opts, def) => {
|
|
32
42
|
if (typeof def === 'boolean') {
|
|
33
43
|
opts = typeof opts === 'string' ? { parent: opts, default: def } : { default: def, ...(opts ?? {}) };
|
package/build/helper.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAC3C,OAAO,EAAe,cAAc,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAIxD,MAAM,CAAC,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"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"}
|
package/build/model.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RouteDeclaration, RouteModel } from './types.js';
|
|
2
2
|
import type { CreateRouteSignature } from './utils/types.js';
|
|
3
|
-
export declare const makeRouteModel: (route:
|
|
4
|
-
export declare const createRoute: CreateRouteSignature<
|
|
3
|
+
export declare const makeRouteModel: (route: RouteDeclaration) => RouteModel;
|
|
4
|
+
export declare const createRoute: CreateRouteSignature<RouteDeclaration>;
|
|
5
5
|
//# sourceMappingURL=model.d.ts.map
|
package/build/model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAG5D,eAAO,MAAM,cAAc,UAAW,gBAAgB,KAAG,UAAyB,CAAA;AAElF,eAAO,MAAM,WAAW,EAAE,oBAAoB,CAAC,gBAAgB,CAY9D,CAAA"}
|
package/build/model.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
import { resolve } from './utils/route.js';
|
|
2
1
|
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
|
-
};
|
|
2
|
+
export const makeRouteModel = (route) => ({ route });
|
|
10
3
|
export const createRoute = (alias, path, opts) => {
|
|
4
|
+
const options = typeof opts === 'string' ? { parent: opts } : opts;
|
|
5
|
+
const { parent, ...rest } = options ?? {};
|
|
11
6
|
const route = {
|
|
12
7
|
alias,
|
|
13
8
|
type: AppType.Backend,
|
|
14
9
|
path,
|
|
15
|
-
|
|
16
|
-
...(typeof
|
|
10
|
+
...rest,
|
|
11
|
+
...(parent == null ? {} : { parent: typeof parent === 'string' ? parent : parent.alias }),
|
|
17
12
|
};
|
|
18
13
|
return route;
|
|
19
14
|
};
|
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,
|
|
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,EAAE,EAAE;IACxF,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"}
|
package/build/types.d.ts
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
|
-
import type { AppType,
|
|
1
|
+
import type { AppType, EntrypointReference } from '@owlmeans/context';
|
|
2
2
|
import type { RouteProtocols, RouteMethod } from './consts';
|
|
3
|
-
export interface
|
|
3
|
+
export interface BasicRoute {
|
|
4
|
+
type: AppType;
|
|
5
|
+
service?: string;
|
|
6
|
+
host?: string;
|
|
7
|
+
port?: number;
|
|
8
|
+
base?: string;
|
|
9
|
+
internalHost?: string;
|
|
10
|
+
internalPort?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The plain, declarative half of a route — what a `route()` call produces and what an application
|
|
14
|
+
* ships in its contract package. It is never rewritten: `path` stays the segment this route
|
|
15
|
+
* contributes under its parent, and the address is worked out on demand against a context.
|
|
16
|
+
*/
|
|
17
|
+
export interface RouteDeclaration extends BasicRoute {
|
|
4
18
|
alias: string;
|
|
5
19
|
path: string;
|
|
6
20
|
parent?: string;
|
|
@@ -8,28 +22,45 @@ export interface CommonRoute extends BasicRoute {
|
|
|
8
22
|
method?: RouteMethod;
|
|
9
23
|
protocol?: RouteProtocols;
|
|
10
24
|
secure?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* QUEUE routes only: the queue that carries this entrypoint's jobs. It names an address, not a
|
|
27
|
+
* process — which queues a given process consumes is configuration, never a declaration.
|
|
28
|
+
*/
|
|
29
|
+
queue?: string;
|
|
30
|
+
/**
|
|
31
|
+
* QUEUE routes only: whether the caller waits for the job's return value. `false` resolves as
|
|
32
|
+
* soon as the job is accepted, which is what a long pipeline wants; the default is to wait.
|
|
33
|
+
*/
|
|
34
|
+
reply?: boolean;
|
|
35
|
+
/** How long a caller waits for an answer, in milliseconds, when the transport supports it. */
|
|
36
|
+
timeout?: number;
|
|
11
37
|
}
|
|
12
38
|
export interface CommonServiceRoute extends BasicRoute {
|
|
13
39
|
home?: string;
|
|
14
40
|
service: string;
|
|
15
41
|
default?: boolean;
|
|
16
42
|
}
|
|
17
|
-
export interface BasicRoute {
|
|
18
|
-
type: AppType;
|
|
19
|
-
service?: string;
|
|
20
|
-
host?: string;
|
|
21
|
-
port?: number;
|
|
22
|
-
base?: string;
|
|
23
|
-
resolved: boolean;
|
|
24
|
-
}
|
|
25
43
|
export interface ResolvedServiceRoute extends CommonServiceRoute {
|
|
26
44
|
host: string;
|
|
27
|
-
resolved: true;
|
|
28
45
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
46
|
+
/** Where a route actually answers, once its service has been picked. */
|
|
47
|
+
export interface RouteAddress {
|
|
48
|
+
host: string;
|
|
49
|
+
port?: number;
|
|
50
|
+
base?: string;
|
|
51
|
+
secure: boolean;
|
|
52
|
+
protocol: RouteProtocols;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The model wrapping a declaration. It carries no resolution state of its own — every address
|
|
56
|
+
* question is answered from the declaration plus the context that asks.
|
|
57
|
+
*/
|
|
58
|
+
export interface RouteModel {
|
|
59
|
+
route: RouteDeclaration;
|
|
32
60
|
}
|
|
33
|
-
export
|
|
61
|
+
export type RouteParent = string | EntrypointReference;
|
|
62
|
+
export interface RouteOptions extends Omit<Partial<RouteDeclaration>, 'parent'> {
|
|
63
|
+
/** A parent protocol is preferred in application declarations; strings remain adapter input. */
|
|
64
|
+
parent?: RouteParent;
|
|
34
65
|
}
|
|
35
66
|
//# sourceMappingURL=types.d.ts.map
|
package/build/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3D,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,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,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;IAChB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,8FAA8F;IAC9F,OAAO,CAAC,EAAE,MAAM,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,oBAAqB,SAAQ,kBAAkB;IAC9D,IAAI,EAAE,MAAM,CAAA;CACb;AAED,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,cAAc,CAAA;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,gBAAgB,CAAA;CACxB;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,mBAAmB,CAAA;AAEtD,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,QAAQ,CAAC;IAC7E,gGAAgG;IAChG,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB"}
|
package/build/utils/route.d.ts
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
import type { BasicConfig, BasicContext } from '@owlmeans/context';
|
|
2
|
-
import type {
|
|
2
|
+
import type { RouteAddress, RouteDeclaration, ResolvedServiceRoute } from '../types.js';
|
|
3
3
|
type Config = BasicConfig;
|
|
4
|
-
export declare const getParentRoute: <C extends Config, T extends BasicContext<C>>(context: T, route:
|
|
5
|
-
export declare const overrideParams: (route:
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
export declare const getParentRoute: <C extends Config, T extends BasicContext<C>>(context: T, route: RouteDeclaration) => RouteDeclaration | null;
|
|
5
|
+
export declare const overrideParams: (route: RouteDeclaration, overrides?: Partial<RouteDeclaration>, filter?: string[]) => void;
|
|
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;
|
|
8
28
|
export {};
|
|
9
29
|
//# sourceMappingURL=route.d.ts.map
|
|
@@ -1 +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,
|
|
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,YAAY,EAAE,gBAAgB,EAAkC,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAKvH,KAAK,MAAM,GAAG,WAAW,CAAA;AAWzB,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,WAC/D,CAAC,SAAS,gBAAgB,KAClC,gBAAgB,GAAG,IAWrB,CAAA;AAED,eAAO,MAAM,cAAc,UAAW,gBAAgB,cAAc,OAAO,CAAC,gBAAgB,CAAC,WAAW,MAAM,EAAE,SAO/G,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,WAC/D,CAAC,SAAS,gBAAgB,KAClC,oBA4BF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,WAC5D,CAAC,SAAS,gBAAgB,KAClC,MASF,CAAA;AAED,2EAA2E;AAC3E,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,WAC7D,CAAC,SAAS,gBAAgB,KAClC,MAOF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,WAC/D,CAAC,SAAS,gBAAgB,KAClC,YAYF,CAAA;AAED,mEAAmE;AACnE,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,WAC7D,CAAC,SAAS,gBAAgB,KAClC,OAAyE,CAAA;AAgB5E,eAAO,MAAM,WAAW,UAAW,gBAAgB,QAAQ,MAAM,WAGvD,CAAA"}
|
package/build/utils/route.js
CHANGED
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
import { isServiceRoute, isServiceRouteResolved } from './service.js';
|
|
2
2
|
import { normalizePath } from '../helper.js';
|
|
3
|
-
import { SEP } from '../consts.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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;
|
|
3
|
+
import { RouteProtocols, SEP } from '../consts.js';
|
|
4
|
+
const carrier = (context, alias) => context.entrypoint(alias);
|
|
5
|
+
export const getParentRoute = (context, route) => {
|
|
6
|
+
if (route.parent == null) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const parent = carrier(context, route.parent);
|
|
10
|
+
if (parent.route == null) {
|
|
11
|
+
throw new SyntaxError('Parent entrypoint doesn\'t provide a route');
|
|
20
12
|
}
|
|
21
|
-
|
|
13
|
+
assertCycle(context, route, parent.route.route);
|
|
14
|
+
return parent.route.route;
|
|
22
15
|
};
|
|
23
16
|
export const overrideParams = (route, overrides, filter) => {
|
|
24
17
|
Object.entries(overrides ?? {}).forEach(([key, value]) => {
|
|
@@ -28,59 +21,72 @@ export const overrideParams = (route, overrides, filter) => {
|
|
|
28
21
|
}
|
|
29
22
|
});
|
|
30
23
|
};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Pick the service route this declaration answers on: the one it names, else the default of its
|
|
26
|
+
* app type, else the first of its app type.
|
|
27
|
+
*
|
|
28
|
+
* @throws {SyntaxError}
|
|
29
|
+
*/
|
|
30
|
+
export const resolveService = (context, route) => {
|
|
35
31
|
if (context.cfg.services == null) {
|
|
36
32
|
throw new SyntaxError('Services aren\'t configured to resolve routes');
|
|
37
33
|
}
|
|
38
|
-
const
|
|
39
|
-
if (
|
|
34
|
+
const named = context.cfg.services[route.service ?? context.cfg.service];
|
|
35
|
+
if (named != null && !isServiceRoute(named)) {
|
|
40
36
|
throw new SyntaxError('Service is not a valid service route');
|
|
41
37
|
}
|
|
42
|
-
const service =
|
|
43
|
-
: Object.values(context.cfg.services).find((
|
|
44
|
-
const
|
|
45
|
-
return
|
|
46
|
-
}) ?? Object.values(context.cfg.services).find((
|
|
47
|
-
const _service = service;
|
|
48
|
-
return _service.type === route.type;
|
|
49
|
-
});
|
|
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);
|
|
50
43
|
if (!isServiceRoute(service)) {
|
|
51
44
|
throw new SyntaxError('Service is not a valid service route');
|
|
52
45
|
}
|
|
53
|
-
if (!service.resolved && service.host != null) {
|
|
54
|
-
service.resolved = true;
|
|
55
|
-
}
|
|
56
46
|
if (!isServiceRouteResolved(service)) {
|
|
57
47
|
throw new SyntaxError('Service route is not resolved');
|
|
58
48
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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));
|
|
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;
|
|
76
59
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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;
|
|
83
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,
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
/** Does this route belong to the service the asking context IS? */
|
|
89
|
+
export const isLocalRoute = (context, route) => (route.service ?? context.cfg.service) === context.cfg.service;
|
|
84
90
|
/**
|
|
85
91
|
* @throws {SyntaxError}
|
|
86
92
|
*/
|
|
@@ -89,15 +95,10 @@ const assertCycle = (context, route, parent) => {
|
|
|
89
95
|
if (parent.parent === route.alias) {
|
|
90
96
|
throw new SyntaxError(`Route parentship cycle detected. Parent: ${parent.alias} has his child as ancestor ${route.alias}`);
|
|
91
97
|
}
|
|
92
|
-
parent = context
|
|
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
|
|
98
|
+
parent = carrier(context, parent.parent).route.route;
|
|
100
99
|
}
|
|
101
|
-
return path;
|
|
102
100
|
};
|
|
101
|
+
export const prependBase = (route, path) => route.base != null && route.base.trim() !== ''
|
|
102
|
+
? SEP + normalizePath(route.base) + SEP + normalizePath(path)
|
|
103
|
+
: path;
|
|
103
104
|
//# 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":"AAEA,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/utils/route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAUlD,MAAM,OAAO,GAAG,CAA8C,OAAU,EAAE,KAAa,EAAgB,EAAE,CACvG,OAAO,CAAC,UAAU,CAAe,KAAK,CAAC,CAAA;AAEzC,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,OAAU,EAAE,KAAuB,EACV,EAAE;IAC3B,IAAI,KAAK,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;QACzB,OAAO,IAAI,CAAA;IACb,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAO,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;IACnD,IAAI,MAAM,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,MAAM,IAAI,WAAW,CAAC,4CAA4C,CAAC,CAAA;IACrE,CAAC;IACD,WAAW,CAAO,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAErD,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAA;AAC3B,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAuB,EAAE,SAAqC,EAAE,MAAiB,EAAE,EAAE;IAClH,MAAM,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;QACvD,IAAI,KAAK,CAAC,GAA6B,CAAC,IAAI,IAAI;eAC3C,CAAC,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAC7C,KAAK,CAAC,GAA6B,CAA8C,GAAG,KAAK,CAAA;QAC5F,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,OAAU,EAAE,KAAuB,EACb,EAAE;IACxB,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;QACjC,MAAM,IAAI,WAAW,CAAC,+CAA+C,CAAC,CAAA;IACxE,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACxE,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,WAAW,CAAC,sCAAsC,CAAC,CAAA;IAC/D,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,EAAE,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;QAChD,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CACxC,CAAC,SAAS,EAAmC,EAAE;YAC7C,MAAM,UAAU,GAAG,SAA+B,CAAA;YAClD,OAAO,UAAU,CAAC,OAAO,KAAK,IAAI,IAAI,UAAU,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAA;QACtE,CAAC,CACF,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAC3C,CAAC,SAAS,EAAmC,EAAE,CAAE,SAAgC,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CACtG,CAAA;IAEH,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,WAAW,CAAC,sCAAsC,CAAC,CAAA;IAC/D,CAAC;IACD,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,WAAW,CAAC,+BAA+B,CAAC,CAAA;IACxD,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,OAAU,EAAE,KAAuB,EAC3B,EAAE;IACV,MAAM,MAAM,GAAG,cAAc,CAAO,OAAO,EAAE,KAAK,CAAC,CAAA;IACnD,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QACnB,OAAO,KAAK,CAAC,IAAI,CAAA;IACnB,CAAC;IACD,MAAM,UAAU,GAAG,WAAW,CAAO,OAAO,EAAE,MAAM,CAAC,CAAA;IAErD,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;UAC1C,aAAa,CAAC,aAAa,CAAC,UAAU,CAAC,GAAG,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;AAChF,CAAC,CAAA;AAED,2EAA2E;AAC3E,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,OAAU,EAAE,KAAuB,EAC3B,EAAE;IACV,MAAM,IAAI,GAAG,WAAW,CAAO,OAAO,EAAE,KAAK,CAAC,CAAA;IAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,cAAc,CAAO,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAA;IAEpE,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QACvC,CAAC,CAAC,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC;QACvD,CAAC,CAAC,IAAI,CAAA;AACV,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,OAAU,EAAE,KAAuB,EACrB,EAAE;IAChB,MAAM,OAAO,GAAG,cAAc,CAAO,OAAO,EAAE,KAAK,CAAC,CAAA;IACpD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAA;IACvC,MAAM,YAAY,GAAG,KAAK,CAAC,YAAY,IAAI,OAAO,CAAC,YAAY,CAAA;IAE/D,OAAO;QACL,IAAI;QACJ,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI;QAChC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI;QAChC,MAAM,EAAE,YAAY,IAAI,IAAI,IAAI,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI;QACpF,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,cAAc,CAAC,GAAG;KAC/C,CAAA;AACH,CAAC,CAAA;AAED,mEAAmE;AACnE,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,OAAU,EAAE,KAAuB,EAC1B,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,OAAO,CAAA;AAE5E;;GAEG;AACH,MAAM,WAAW,GAAG,CAClB,OAAU,EAAE,KAAuB,EAAE,MAAwB,EAC7D,EAAE;IACF,OAAO,MAAM,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC;YAClC,MAAM,IAAI,WAAW,CAAC,4CAA4C,MAAM,CAAC,KAAK,8BAA8B,KAAK,CAAC,KAAK,EAAE,CAAC,CAAA;QAC5H,CAAC;QACD,MAAM,GAAG,OAAO,CAAO,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAA;IAC5D,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAuB,EAAE,IAAY,EAAE,EAAE,CACnE,KAAK,CAAC,IAAI,IAAI,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;IAC5C,CAAC,CAAC,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC;IAC7D,CAAC,CAAC,IAAI,CAAA"}
|
package/build/utils/service.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ResolvedServiceRoute, CommonServiceRoute } from '../types.js';
|
|
2
2
|
export declare const isServiceRoute: (obj?: Object) => obj is CommonServiceRoute;
|
|
3
|
+
/** A service route is usable exactly when it knows the host it answers on. */
|
|
3
4
|
export declare const isServiceRouteResolved: (route: CommonServiceRoute) => route is ResolvedServiceRoute;
|
|
4
5
|
//# sourceMappingURL=service.d.ts.map
|
|
@@ -1 +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,
|
|
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,8EAA8E;AAC9E,eAAO,MAAM,sBAAsB,UAAW,kBAAkB,KAAG,KAAK,IAAI,oBAC5B,CAAA"}
|
package/build/utils/service.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AppType } from '@owlmeans/context';
|
|
2
2
|
export const isServiceRoute = (obj) => obj != null && ('type' in obj) && ('service' in obj)
|
|
3
3
|
&& (Object.values(AppType).includes(obj.type));
|
|
4
|
-
|
|
4
|
+
/** A service route is usable exactly when it knows the host it answers on. */
|
|
5
|
+
export const isServiceRouteResolved = (route) => route.host != null && route.host.trim() !== '';
|
|
5
6
|
//# 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;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,
|
|
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,8EAA8E;AAC9E,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,KAAyB,EAAiC,EAAE,CACjG,KAAK,CAAC,IAAI,IAAI,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAA"}
|
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.10",
|
|
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.9"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@owlmeans/dep-config": "workspace:*",
|
package/src/consts.ts
CHANGED
|
@@ -11,7 +11,13 @@ export const SEP = '/'
|
|
|
11
11
|
|
|
12
12
|
export const PARAM = ':'
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* How a route is carried. The protocol picks the transport that answers it — an application binds
|
|
16
|
+
* one by registering a service under `transportAlias(protocol)` — so a caller writes `call()` and
|
|
17
|
+
* never learns whether an HTTP request, a socket frame or a queued job did the work.
|
|
18
|
+
*/
|
|
14
19
|
export enum RouteProtocols {
|
|
15
20
|
WEB = 'http',
|
|
16
|
-
SOCKET = 'ws'
|
|
21
|
+
SOCKET = 'ws',
|
|
22
|
+
QUEUE = 'queue'
|
|
17
23
|
}
|
package/src/helper.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { AppType } from '@owlmeans/context'
|
|
2
2
|
import { RouteMethod, RouteProtocols, SEP } from './consts.js'
|
|
3
3
|
import { createRoute, makeRouteModel } from './model.js'
|
|
4
|
-
import type {
|
|
4
|
+
import type { RouteModel, RouteOptions } from './types.js'
|
|
5
5
|
import type { CreateRouteSignature } from './utils/types.js'
|
|
6
6
|
|
|
7
|
-
export const route: CreateRouteSignature<
|
|
7
|
+
export const route: CreateRouteSignature<RouteModel> = (alias, path, opts?) =>
|
|
8
8
|
makeRouteModel(createRoute(alias, path, opts))
|
|
9
9
|
|
|
10
10
|
export const normalizePath = (path: string): string => {
|
|
@@ -43,6 +43,19 @@ export const socket = (opts?: RouteOptions | string | null, secondary?: RouteOpt
|
|
|
43
43
|
return route
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* A backend route carried by the queue rather than by HTTP. Everything else about it is a normal
|
|
48
|
+
* backend route — it has a path, a parent, guards and a filter — so the same declaration is served
|
|
49
|
+
* with `elevate(...)` and called with `call()`; only the transport underneath differs.
|
|
50
|
+
*/
|
|
51
|
+
export const job = (opts?: RouteOptions | string | null, secondary?: RouteOptions): Partial<RouteOptions> => {
|
|
52
|
+
const route = backend(opts, secondary)
|
|
53
|
+
|
|
54
|
+
route.protocol = RouteProtocols.QUEUE
|
|
55
|
+
|
|
56
|
+
return route
|
|
57
|
+
}
|
|
58
|
+
|
|
46
59
|
export const frontend = (opts?: RouteOptions | string | null, def?: RouteOptions | boolean): Partial<RouteOptions> => {
|
|
47
60
|
if (typeof def === 'boolean') {
|
|
48
61
|
opts = typeof opts === 'string' ? { parent: opts, default: def } : { default: def, ...(opts ?? {}) }
|
package/src/model.ts
CHANGED
|
@@ -1,24 +1,18 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RouteDeclaration, RouteModel } from './types.js'
|
|
2
2
|
import type { CreateRouteSignature } from './utils/types.js'
|
|
3
|
-
import {
|
|
4
|
-
import { AppType, BasicConfig, BasicContext } from '@owlmeans/context'
|
|
3
|
+
import { AppType } from '@owlmeans/context'
|
|
5
4
|
|
|
6
|
-
export const makeRouteModel = (route:
|
|
7
|
-
const model: CommonRouteModel = {
|
|
8
|
-
route,
|
|
9
|
-
resolve: ctx => resolve(route)(ctx as unknown as BasicContext<BasicConfig>)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return model
|
|
13
|
-
}
|
|
5
|
+
export const makeRouteModel = (route: RouteDeclaration): RouteModel => ({ route })
|
|
14
6
|
|
|
15
|
-
export const createRoute: CreateRouteSignature<
|
|
16
|
-
const
|
|
7
|
+
export const createRoute: CreateRouteSignature<RouteDeclaration> = (alias, path, opts?) => {
|
|
8
|
+
const options = typeof opts === 'string' ? { parent: opts } : opts
|
|
9
|
+
const { parent, ...rest } = options ?? {}
|
|
10
|
+
const route: RouteDeclaration = {
|
|
17
11
|
alias,
|
|
18
12
|
type: AppType.Backend,
|
|
19
13
|
path,
|
|
20
|
-
|
|
21
|
-
...(typeof
|
|
14
|
+
...rest,
|
|
15
|
+
...(parent == null ? {} : { parent: typeof parent === 'string' ? parent : parent.alias }),
|
|
22
16
|
}
|
|
23
17
|
|
|
24
18
|
return route
|
package/src/types.ts
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
import type { AppType,
|
|
1
|
+
import type { AppType, EntrypointReference } from '@owlmeans/context'
|
|
2
2
|
import type { RouteProtocols, RouteMethod } from './consts'
|
|
3
3
|
|
|
4
|
-
export interface
|
|
4
|
+
export interface BasicRoute {
|
|
5
|
+
type: AppType
|
|
6
|
+
service?: string
|
|
7
|
+
host?: string
|
|
8
|
+
port?: number
|
|
9
|
+
base?: string
|
|
10
|
+
internalHost?: string
|
|
11
|
+
internalPort?: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The plain, declarative half of a route — what a `route()` call produces and what an application
|
|
16
|
+
* ships in its contract package. It is never rewritten: `path` stays the segment this route
|
|
17
|
+
* contributes under its parent, and the address is worked out on demand against a context.
|
|
18
|
+
*/
|
|
19
|
+
export interface RouteDeclaration extends BasicRoute {
|
|
5
20
|
alias: string
|
|
6
21
|
path: string
|
|
7
22
|
parent?: string
|
|
@@ -9,6 +24,18 @@ export interface CommonRoute extends BasicRoute {
|
|
|
9
24
|
method?: RouteMethod
|
|
10
25
|
protocol?: RouteProtocols
|
|
11
26
|
secure?: boolean
|
|
27
|
+
/**
|
|
28
|
+
* QUEUE routes only: the queue that carries this entrypoint's jobs. It names an address, not a
|
|
29
|
+
* process — which queues a given process consumes is configuration, never a declaration.
|
|
30
|
+
*/
|
|
31
|
+
queue?: string
|
|
32
|
+
/**
|
|
33
|
+
* QUEUE routes only: whether the caller waits for the job's return value. `false` resolves as
|
|
34
|
+
* soon as the job is accepted, which is what a long pipeline wants; the default is to wait.
|
|
35
|
+
*/
|
|
36
|
+
reply?: boolean
|
|
37
|
+
/** How long a caller waits for an answer, in milliseconds, when the transport supports it. */
|
|
38
|
+
timeout?: number
|
|
12
39
|
}
|
|
13
40
|
|
|
14
41
|
export interface CommonServiceRoute extends BasicRoute {
|
|
@@ -17,24 +44,30 @@ export interface CommonServiceRoute extends BasicRoute {
|
|
|
17
44
|
default?: boolean
|
|
18
45
|
}
|
|
19
46
|
|
|
20
|
-
export interface
|
|
21
|
-
|
|
22
|
-
service?: string
|
|
23
|
-
host?: string
|
|
24
|
-
port?: number
|
|
25
|
-
base?: string
|
|
26
|
-
resolved: boolean
|
|
47
|
+
export interface ResolvedServiceRoute extends CommonServiceRoute {
|
|
48
|
+
host: string
|
|
27
49
|
}
|
|
28
50
|
|
|
29
|
-
|
|
51
|
+
/** Where a route actually answers, once its service has been picked. */
|
|
52
|
+
export interface RouteAddress {
|
|
30
53
|
host: string
|
|
31
|
-
|
|
54
|
+
port?: number
|
|
55
|
+
base?: string
|
|
56
|
+
secure: boolean
|
|
57
|
+
protocol: RouteProtocols
|
|
32
58
|
}
|
|
33
59
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
60
|
+
/**
|
|
61
|
+
* The model wrapping a declaration. It carries no resolution state of its own — every address
|
|
62
|
+
* question is answered from the declaration plus the context that asks.
|
|
63
|
+
*/
|
|
64
|
+
export interface RouteModel {
|
|
65
|
+
route: RouteDeclaration
|
|
37
66
|
}
|
|
38
67
|
|
|
39
|
-
export
|
|
68
|
+
export type RouteParent = string | EntrypointReference
|
|
69
|
+
|
|
70
|
+
export interface RouteOptions extends Omit<Partial<RouteDeclaration>, 'parent'> {
|
|
71
|
+
/** A parent protocol is preferred in application declarations; strings remain adapter input. */
|
|
72
|
+
parent?: RouteParent
|
|
40
73
|
}
|
package/src/utils/route.ts
CHANGED
|
@@ -1,121 +1,151 @@
|
|
|
1
1
|
import type { BasicConfig, BasicContext, Contextual } from '@owlmeans/context'
|
|
2
|
-
import type {
|
|
2
|
+
import type { RouteAddress, RouteDeclaration, RouteModel, CommonServiceRoute, ResolvedServiceRoute } from '../types.js'
|
|
3
3
|
import { isServiceRoute, isServiceRouteResolved } from './service.js'
|
|
4
4
|
import { normalizePath } from '../helper.js'
|
|
5
|
-
import { SEP } from '../consts.js'
|
|
5
|
+
import { RouteProtocols, SEP } from '../consts.js'
|
|
6
6
|
|
|
7
7
|
type Config = BasicConfig
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return parent.route.route
|
|
9
|
+
/** What an entrypoint looks like from the route layer: something that carries a route model. */
|
|
10
|
+
interface RouteCarrier extends Contextual {
|
|
11
|
+
_entrypoint: true
|
|
12
|
+
route: RouteModel
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const carrier = <C extends Config, T extends BasicContext<C>>(context: T, alias: string): RouteCarrier =>
|
|
16
|
+
context.entrypoint<RouteCarrier>(alias)
|
|
17
|
+
|
|
18
|
+
export const getParentRoute = <C extends Config, T extends BasicContext<C>>(
|
|
19
|
+
context: T, route: RouteDeclaration
|
|
20
|
+
): RouteDeclaration | null => {
|
|
21
|
+
if (route.parent == null) {
|
|
22
|
+
return null
|
|
24
23
|
}
|
|
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)
|
|
25
29
|
|
|
26
|
-
return
|
|
30
|
+
return parent.route.route
|
|
27
31
|
}
|
|
28
32
|
|
|
29
|
-
export const overrideParams = (route:
|
|
33
|
+
export const overrideParams = (route: RouteDeclaration, overrides?: Partial<RouteDeclaration>, filter?: string[]) => {
|
|
30
34
|
Object.entries(overrides ?? {}).forEach(([key, value]) => {
|
|
31
|
-
if (route[key as keyof
|
|
35
|
+
if (route[key as keyof RouteDeclaration] == null
|
|
32
36
|
&& (filter == null || filter.includes(key))) {
|
|
33
|
-
(route[key as keyof
|
|
37
|
+
(route[key as keyof RouteDeclaration] as RouteDeclaration[keyof RouteDeclaration]) = value
|
|
34
38
|
}
|
|
35
39
|
})
|
|
36
40
|
}
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Pick the service route this declaration answers on: the one it names, else the default of its
|
|
44
|
+
* app type, else the first of its app type.
|
|
45
|
+
*
|
|
46
|
+
* @throws {SyntaxError}
|
|
47
|
+
*/
|
|
48
|
+
export const resolveService = <C extends Config, T extends BasicContext<C>>(
|
|
49
|
+
context: T, route: RouteDeclaration
|
|
50
|
+
): ResolvedServiceRoute => {
|
|
42
51
|
if (context.cfg.services == null) {
|
|
43
52
|
throw new SyntaxError('Services aren\'t configured to resolve routes')
|
|
44
53
|
}
|
|
45
54
|
|
|
46
|
-
const
|
|
47
|
-
if (
|
|
55
|
+
const named = context.cfg.services[route.service ?? context.cfg.service]
|
|
56
|
+
if (named != null && !isServiceRoute(named)) {
|
|
48
57
|
throw new SyntaxError('Service is not a valid service route')
|
|
49
58
|
}
|
|
50
|
-
|
|
59
|
+
|
|
60
|
+
const service = named?.type === route.type ? named
|
|
51
61
|
: Object.values(context.cfg.services).find<CommonServiceRoute>(
|
|
52
|
-
(
|
|
53
|
-
const
|
|
54
|
-
return
|
|
62
|
+
(candidate): candidate is CommonServiceRoute => {
|
|
63
|
+
const _candidate = candidate as CommonServiceRoute
|
|
64
|
+
return _candidate.default === true && _candidate.type === route.type
|
|
55
65
|
}
|
|
56
66
|
) ?? Object.values(context.cfg.services).find<CommonServiceRoute>(
|
|
57
|
-
(
|
|
58
|
-
const _service = service as CommonServiceRoute
|
|
59
|
-
return _service.type === route.type
|
|
60
|
-
}
|
|
67
|
+
(candidate): candidate is CommonServiceRoute => (candidate as CommonServiceRoute).type === route.type
|
|
61
68
|
)
|
|
69
|
+
|
|
62
70
|
if (!isServiceRoute(service)) {
|
|
63
71
|
throw new SyntaxError('Service is not a valid service route')
|
|
64
72
|
}
|
|
65
|
-
if (!service.resolved && service.host != null) {
|
|
66
|
-
service.resolved = true
|
|
67
|
-
}
|
|
68
73
|
if (!isServiceRouteResolved(service)) {
|
|
69
74
|
throw new SyntaxError('Service route is not resolved')
|
|
70
75
|
}
|
|
71
76
|
|
|
72
|
-
|
|
77
|
+
return service
|
|
78
|
+
}
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
/**
|
|
81
|
+
* The full path: every ancestor's declared segment, then this one. Walks the parent chain through
|
|
82
|
+
* the context, so a declaration always states only what it contributes.
|
|
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
|
|
84
90
|
}
|
|
85
|
-
|
|
91
|
+
const parentPath = resolvePath<C, T>(context, parent)
|
|
86
92
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
+ normalizePath(normalizePath(parent.path) + SEP + normalizePath(route.path))
|
|
91
|
-
}
|
|
93
|
+
return (parentPath.startsWith(SEP) ? SEP : '')
|
|
94
|
+
+ normalizePath(normalizePath(parentPath) + SEP + normalizePath(route.path))
|
|
95
|
+
}
|
|
92
96
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
|
98
103
|
|
|
99
|
-
return
|
|
104
|
+
return base != null && base.trim() !== ''
|
|
105
|
+
? SEP + normalizePath(base) + SEP + normalizePath(path)
|
|
106
|
+
: path
|
|
100
107
|
}
|
|
101
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Where the route answers. A backend caller reaching a service over its INTERNAL host is inside the
|
|
111
|
+
* cluster, so that hop is never TLS.
|
|
112
|
+
*/
|
|
113
|
+
export const resolveAddress = <C extends Config, T extends BasicContext<C>>(
|
|
114
|
+
context: T, route: RouteDeclaration
|
|
115
|
+
): RouteAddress => {
|
|
116
|
+
const service = resolveService<C, T>(context, route)
|
|
117
|
+
const host = route.host ?? service.host
|
|
118
|
+
const internalHost = route.internalHost ?? service.internalHost
|
|
119
|
+
|
|
120
|
+
return {
|
|
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,
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Does this route belong to the service the asking context IS? */
|
|
130
|
+
export const isLocalRoute = <C extends Config, T extends BasicContext<C>>(
|
|
131
|
+
context: T, route: RouteDeclaration
|
|
132
|
+
): boolean => (route.service ?? context.cfg.service) === context.cfg.service
|
|
133
|
+
|
|
102
134
|
/**
|
|
103
135
|
* @throws {SyntaxError}
|
|
104
136
|
*/
|
|
105
|
-
const assertCycle = <C extends BasicConfig, T extends BasicContext<C>>(
|
|
137
|
+
const assertCycle = <C extends BasicConfig, T extends BasicContext<C>>(
|
|
138
|
+
context: T, route: RouteDeclaration, parent: RouteDeclaration
|
|
139
|
+
) => {
|
|
106
140
|
while (parent.parent != null) {
|
|
107
141
|
if (parent.parent === route.alias) {
|
|
108
142
|
throw new SyntaxError(`Route parentship cycle detected. Parent: ${parent.alias} has his child as ancestor ${route.alias}`)
|
|
109
143
|
}
|
|
110
|
-
parent =
|
|
144
|
+
parent = carrier<C, T>(context, parent.parent).route.route
|
|
111
145
|
}
|
|
112
146
|
}
|
|
113
147
|
|
|
114
|
-
export const prependBase = (route:
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
// route.path = route.base.startsWith(SEP) ? SEP + route.path : route.path
|
|
119
|
-
}
|
|
120
|
-
return path
|
|
121
|
-
}
|
|
148
|
+
export const prependBase = (route: RouteDeclaration, path: string) =>
|
|
149
|
+
route.base != null && route.base.trim() !== ''
|
|
150
|
+
? SEP + normalizePath(route.base) + SEP + normalizePath(path)
|
|
151
|
+
: path
|
package/src/utils/service.ts
CHANGED
|
@@ -5,5 +5,6 @@ export const isServiceRoute = (obj?: Object): obj is CommonServiceRoute =>
|
|
|
5
5
|
obj != null && ('type' in obj) && ('service' in obj)
|
|
6
6
|
&& (Object.values(AppType).includes(obj.type as AppType))
|
|
7
7
|
|
|
8
|
+
/** A service route is usable exactly when it knows the host it answers on. */
|
|
8
9
|
export const isServiceRouteResolved = (route: CommonServiceRoute): route is ResolvedServiceRoute =>
|
|
9
|
-
route.
|
|
10
|
+
route.host != null && route.host.trim() !== ''
|
package/build/.gitkeep
DELETED
|
File without changes
|