@owlmeans/entrypoint 0.1.18-rc.10 → 0.1.18-rc.12
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 +2 -2
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/entrypoint/SKILL.md +81 -10
- package/build/consts.d.ts.map +1 -1
- package/build/consts.js.map +1 -1
- package/build/entrypoint.d.ts.map +1 -1
- package/build/entrypoint.js +12 -0
- package/build/entrypoint.js.map +1 -1
- package/build/filter.d.ts.map +1 -1
- package/build/helper.d.ts.map +1 -1
- package/build/index.d.ts +2 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/materialize.d.ts +12 -0
- package/build/materialize.d.ts.map +1 -0
- package/build/materialize.js +34 -0
- package/build/materialize.js.map +1 -0
- package/build/protocol.d.ts +209 -0
- package/build/protocol.d.ts.map +1 -0
- package/build/protocol.js +96 -0
- package/build/protocol.js.map +1 -0
- package/build/utils/entrypoint.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/entrypoint.ts +12 -0
- package/src/index.ts +2 -0
- package/src/materialize.ts +49 -0
- package/src/protocol.ts +349 -0
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ entrypoint is registered in — `path()` walks the parent chain, `mount()` adds
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
bun add @owlmeans/entrypoint
|
|
21
|
+
bun add @owlmeans/entrypoint@^0.1.18-rc.10
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
## Usage
|
|
@@ -120,7 +120,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
120
120
|
your project's skill store (`.agents/skills/`):
|
|
121
121
|
|
|
122
122
|
```sh
|
|
123
|
-
npx @owlmeans/agent-skills
|
|
123
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.13
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
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/entrypoint",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-09-
|
|
4
|
+
"version": "0.1.18-rc.12",
|
|
5
|
+
"generatedAt": "2026-09-10T18:54:42.506Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: entrypoint
|
|
3
|
-
description: How to use @owlmeans/entrypoint —
|
|
3
|
+
description: How to use @owlmeans/entrypoint — immutable typed protocols, adapter references, legacy entrypoint declarations, guards/gates/schemas, address accessors, and the transport seam. Auto-invoked when importing from this package or defining a service entrypoint declaration.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
@@ -8,16 +8,22 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/entrypoint
|
|
9
9
|
|
|
10
10
|
**Layer:** Core
|
|
11
|
-
**Install:** `"@owlmeans/entrypoint": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/entrypoint": "^0.1.18-rc.12"` in `dependencies`
|
|
12
12
|
|
|
13
|
-
An entrypoint is
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
An entrypoint is an **addressable unit**. New code declares an immutable typed `protocol` once in a
|
|
14
|
+
shared package, then binds that declaration on the client or server. The older mutable
|
|
15
|
+
`entrypoint(...)` + `elevate(...)` form remains supported while applications migrate.
|
|
16
16
|
|
|
17
17
|
## Key Exports
|
|
18
18
|
|
|
19
19
|
| Export | Description |
|
|
20
20
|
|--------|-------------|
|
|
21
|
+
| `protocol(route, contract, opts?)` / `openProtocol(route, opts?)` | Declare an immutable shared protocol |
|
|
22
|
+
| `contract(...)` / `contract.request(...)` | Declare the request sections and response together |
|
|
23
|
+
| `schema<T>(value)` / `typed<T>()` | Carry runtime validation plus type inference, or type information only |
|
|
24
|
+
| `protocols(tree)` | Flatten a named protocol tree for a layer binding |
|
|
25
|
+
| `entrypointRef<Request, Response>(alias)` | Typed adapter reference for dynamic registries |
|
|
26
|
+
| `decorateEntrypoint(protocol, opts)` | Return an immutable protocol with added access/options |
|
|
21
27
|
| `entrypoint(route, opts?)` | Declare an entrypoint on a route model |
|
|
22
28
|
| `guard(alias, opts?)` | Require a guard; returns options, so it wraps rather than takes them |
|
|
23
29
|
| `gate(alias, params, opts?)` | Require a gate; passed as the `opts` of `guard(...)` |
|
|
@@ -25,12 +31,52 @@ elevates on either side.
|
|
|
25
31
|
| `body(Schema)` / `params(Schema)` / `query(Schema)` / `headers(Schema)` / `response(Schema, code?)` | AJV validators composed into a `Filter` |
|
|
26
32
|
| `CommonEntrypoint` | The entrypoint interface — declaration, guards/gates, address accessors |
|
|
27
33
|
| `AbstractRequest` / `AbstractResponse` | The request and reply shapes every handler sees |
|
|
34
|
+
| `ResolvedEntity` | `req.entity` — the organization entity's `{ id, slug, iamKey }` |
|
|
28
35
|
| `provideResponse(original?)` | Build a reply object a handler resolves or rejects |
|
|
36
|
+
| `EntrypointHandler` | What a handler implements: `(req, res) => value` |
|
|
37
|
+
| `Filter` | The composed validator set: `{ body, params, query, headers, response }` |
|
|
29
38
|
| `GuardService` / `GateService` | What a guard and a gate implement |
|
|
30
39
|
| `EntrypointOutcome` | Enum: Ok, Accepted, Created, Finished |
|
|
31
40
|
| `EntrypointTransport` | `{ protocol, handle }` — a carrier bound to a route protocol |
|
|
32
41
|
| `transportAlias(protocol?)` | The service alias a transport registers under (`transport:<protocol>`) |
|
|
33
42
|
|
|
43
|
+
## Typed protocol form
|
|
44
|
+
|
|
45
|
+
Application contracts export protocol objects, not alias strings or already context-bound
|
|
46
|
+
entrypoints. A protocol owns the route, request/response contract, guards, gate and sticky flag; it
|
|
47
|
+
is frozen and never mutated by either runtime.
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { contract, openProtocol, protocol, protocols, schema, typed } from '@owlmeans/entrypoint'
|
|
51
|
+
import { frontend, route, RouteMethod } from '@owlmeans/route'
|
|
52
|
+
|
|
53
|
+
const ItemParamsSchema = schema<{ id: string }>({
|
|
54
|
+
type: 'object', properties: { id: { type: 'string' } }, required: ['id'], additionalProperties: false,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
const apiBase = protocol(route('api:item', '/items'), contract())
|
|
58
|
+
export const item = {
|
|
59
|
+
base: apiBase,
|
|
60
|
+
get: protocol(
|
|
61
|
+
route('api:item:get', '/:id', { parent: apiBase, method: RouteMethod.GET }),
|
|
62
|
+
contract.request({ params: ItemParamsSchema }, typed<Item>()),
|
|
63
|
+
),
|
|
64
|
+
}
|
|
65
|
+
export const web = {
|
|
66
|
+
items: openProtocol(route('web:items', '/items', frontend())),
|
|
67
|
+
}
|
|
68
|
+
export const itemEntrypoints = protocols(item)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`contract()` means no payload and an `undefined` reply. With one source it declares only the
|
|
72
|
+
response; with two it declares body then response. Use `contract.request` when params, query,
|
|
73
|
+
headers or several request sections participate. `schema<T>` is the preferred source when runtime
|
|
74
|
+
validation exists; `typed<T>()` is only the compile-time half.
|
|
75
|
+
|
|
76
|
+
`context.entrypoint(protocolOrRef)` infers the exact registered `call`/`invoke`/`url` signature.
|
|
77
|
+
Use the protocol object inside an application. Use `entrypointRef` only in an adapter package that
|
|
78
|
+
must address a dynamically registered surface without importing its declaration tree.
|
|
79
|
+
|
|
34
80
|
`guard`, `gate` and `filter` are **options-object combinators, not variadic composers**. Each
|
|
35
81
|
returns a `CommonEntrypointOptions` and takes the next one as its final argument, so they nest:
|
|
36
82
|
|
|
@@ -45,6 +91,12 @@ Guards and gates are **inherited by child entrypoints** and enforced by the fram
|
|
|
45
91
|
handler runs — a handler that re-checks them is duplicating an enforced rule, and is wrong even
|
|
46
92
|
when it agrees.
|
|
47
93
|
|
|
94
|
+
`sticky: true` in the options exempts a frontend entrypoint from the **service** filter the client
|
|
95
|
+
router applies while building its entrypoint tree: without it, only entrypoints that name no service
|
|
96
|
+
or name the context's own service are attached, so a route belonging to another service (an
|
|
97
|
+
authentication dispatcher, say) needs it to reach the router at all. It changes nothing else — not
|
|
98
|
+
the frontend-only restriction, not route matching — and defaults to `false`.
|
|
99
|
+
|
|
48
100
|
## Subpath Exports
|
|
49
101
|
|
|
50
102
|
- `./utils` — entrypoint construction helpers (`isEntrypoint`, `CreateEntrypointSignature`)
|
|
@@ -72,6 +124,18 @@ way in a server and another in a client without being touched.
|
|
|
72
124
|
`getGuards()` and `getGates()` walk the chain afresh on every call and are never memoised: a guard
|
|
73
125
|
attached to an ancestor after this entrypoint was first asked still has to count.
|
|
74
126
|
|
|
127
|
+
## What a handler receives
|
|
128
|
+
|
|
129
|
+
`AbstractRequest` carries `params`, `body`, `query`, `headers` and `path`, plus `auth` once a guard
|
|
130
|
+
has run. `req.entity` is the organization entity resolved from `auth.entitySlug` **once**, at the
|
|
131
|
+
server boundary: `entity.id` is the stable value to key records, grants and generated names by,
|
|
132
|
+
`entity.slug` is the renameable name a person reads, and `entity.iamKey` is the frozen identifier
|
|
133
|
+
external systems already know the organization under. It is absent when no resolver is registered,
|
|
134
|
+
so read it defensively rather than assuming it.
|
|
135
|
+
|
|
136
|
+
`timeout` and `signal` on a request are forwarded to the transport, so a caller can bound or abort a
|
|
137
|
+
single round trip.
|
|
138
|
+
|
|
75
139
|
## Calling an entrypoint
|
|
76
140
|
|
|
77
141
|
Three explicit verbs, so the caller says which answer it wants:
|
|
@@ -123,9 +187,10 @@ context.registerService(transport)
|
|
|
123
187
|
as a broker job. Nothing at the call site changes — which is the point of putting the protocol on
|
|
124
188
|
the route rather than at the call.
|
|
125
189
|
|
|
126
|
-
##
|
|
190
|
+
## Legacy declaration form
|
|
127
191
|
|
|
128
|
-
|
|
192
|
+
Existing applications may define entrypoints in a shared `common` package, then `elevate()` them
|
|
193
|
+
with handlers in server/web packages. Do not introduce this form into a protocol-based surface.
|
|
129
194
|
|
|
130
195
|
```typescript
|
|
131
196
|
import { entrypoint, guard, gate, filter, body } from '@owlmeans/entrypoint'
|
|
@@ -151,6 +216,12 @@ export const managerEntrypoints = [
|
|
|
151
216
|
|
|
152
217
|
## Depends On
|
|
153
218
|
|
|
154
|
-
- `@owlmeans/route` — `
|
|
155
|
-
- `@owlmeans/
|
|
156
|
-
- `@owlmeans/
|
|
219
|
+
- `@owlmeans/route` — `RouteModel`, `RouteAddress`, `RouteProtocols`, and the address helpers under `/utils`
|
|
220
|
+
- `@owlmeans/context` — `appendContextual`, and the `BasicEntrypoint` / service shapes an entrypoint and its guards, gates and transports register as
|
|
221
|
+
- `@owlmeans/auth` — `Auth`, the type behind `req.auth`
|
|
222
|
+
- `ajv` — the JSON-schema types `body()` / `params()` / `query()` / `headers()` / `response()` are declared with
|
|
223
|
+
|
|
224
|
+
Guard and gate **aliases** are not declared here: an entrypoint names a guard by string, and the
|
|
225
|
+
package that implements the guard owns the constant (`DEFAULT_GUARD` comes from
|
|
226
|
+
`@owlmeans/auth-common`, `OIDC_GATE` from `@owlmeans/oidc`). That is what keeps this package free of
|
|
227
|
+
any dependency on the auth stack.
|
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,iBAAiB;IAC3B,EAAE,OAAO;IACT,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,QAAQ,aAAa;CACtB;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,oBAAY,iBAAiB;IAC3B,EAAE,OAAO;IACT,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,QAAQ,aAAa;CACtB;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,cAAc,MAAM,WAAqC,CAAA"}
|
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,iBAKX;AALD,WAAY,iBAAiB;IAC3B,8BAAS,CAAA;IACT,0CAAqB,CAAA;IACrB,wCAAmB,CAAA;IACnB,0CAAqB,CAAA;AACvB,CAAC,EALW,iBAAiB,KAAjB,iBAAiB,QAK5B;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,MAAM,CAAN,IAAY,iBAKX;AALD,WAAY,iBAAiB;IAC3B,8BAAS,CAAA;IACT,0CAAqB,CAAA;IACrB,wCAAmB,CAAA;IACnB,0CAAqB,CAAA;AACvB,CAAC,EALW,iBAAiB,KAAjB,iBAAiB,QAK5B;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAQ,GAAW,MAAM,EAAE,EAAE,CAAC,aAAa,QAAQ,EAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entrypoint.d.ts","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAKlD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAA;AAEjE,eAAO,MAAM,UAAU,EAAE,yBAAyB,CAAC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"entrypoint.d.ts","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAKlD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAA;AAEjE,eAAO,MAAM,UAAU,EAAE,yBAAyB,CAAC,gBAAgB,CAkElE,CAAA"}
|
package/build/entrypoint.js
CHANGED
|
@@ -23,6 +23,18 @@ export const entrypoint = (route, opts) => {
|
|
|
23
23
|
}
|
|
24
24
|
return guards;
|
|
25
25
|
},
|
|
26
|
+
/**
|
|
27
|
+
* The gates standing over this entrypoint: its own, then an ancestor's for each gate service
|
|
28
|
+
* this entrypoint has not already named.
|
|
29
|
+
*
|
|
30
|
+
* KNOWN HAZARD, deliberately left alone: the dedup is by gate SERVICE, and two gates under one
|
|
31
|
+
* service are two different questions because their parameters differ — so a child that
|
|
32
|
+
* declares its own gate silently drops its ancestor's, which is the opposite of what
|
|
33
|
+
* "inherited" means. Anything that needs a group rule AND a member rule must therefore not
|
|
34
|
+
* express the group half as a gate under the same service. Changing this would widen every
|
|
35
|
+
* backend and socket entrypoint that today relies on the replacement, so it is a migration
|
|
36
|
+
* rather than a fix.
|
|
37
|
+
*/
|
|
26
38
|
getGates: () => {
|
|
27
39
|
const gates = ep.gate != null ? [[
|
|
28
40
|
ep.gate, ep.gateParams == null
|
package/build/entrypoint.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entrypoint.js","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"entrypoint.js","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"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"}
|
package/build/filter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExC,eAAO,MAAM,IAAI,GAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExC,eAAO,MAAM,IAAI,GAAI,CAAC,UAAU,cAAc,CAAC,CAAC,CAAC,WAAW,MAAM,KAAG,MAEpE,CAAA;AAED,eAAO,MAAM,KAAK,GAAI,CAAC,UAAU,cAAc,CAAC,CAAC,CAAC,WAAW,MAAM,KAAG,MAErE,CAAA;AAED,eAAO,MAAM,MAAM,GAAI,CAAC,UAAU,cAAc,CAAC,CAAC,CAAC,WAAW,MAAM,KAAG,MAEtE,CAAA;AAED,eAAO,MAAM,QAAQ,GAAI,CAAC,UAAU,cAAc,CAAC,CAAC,CAAC,SAAS,MAAM,WAAW,MAAM,KAAG,MAMvF,CAAA;AAED,eAAO,MAAM,OAAO,GAAI,CAAC,UAAU,cAAc,CAAC,CAAC,CAAC,WAAW,MAAM,KAAG,MAEvE,CAAA"}
|
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,MAAM,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE9E,eAAO,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE9E,eAAO,MAAM,MAAM,WAAY,MAAM,SAAS,uBAAuB,KAAG,uBAAgD,CAAA;AAExH,eAAO,MAAM,KAAK,UAAW,MAAM,SAAS,uBAAuB,KAAG,uBACC,CAAA;AAEvE,eAAO,MAAM,IAAI,SAAU,MAAM,UAAU,MAAM,GAAG,MAAM,EAAE,SAAS,uBAAuB,KAAG,uBACtD,CAAA;AAEzC,eAAO,MAAM,eAAe,GAAI,CAAC,qBAAqB,OAAO,KAAG,gBAAgB,CAAC,CAAC,CAejF,CAAA"}
|
package/build/index.d.ts
CHANGED
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA"}
|
package/build/index.js
CHANGED
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CommonEntrypoint } from './types.js';
|
|
2
|
+
import type { EntrypointProtocolDeclaration } from './protocol.js';
|
|
3
|
+
/** A context-bound entrypoint made from an immutable protocol declaration. */
|
|
4
|
+
export type MaterializedEntrypoint<Protocol extends EntrypointProtocolDeclaration> = CommonEntrypoint & {
|
|
5
|
+
readonly protocol: Protocol;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Make a local, mutable registration from a shared declaration. The protocol is never mutated;
|
|
9
|
+
* guards, route resolution and handlers belong exclusively to this materialized entrypoint.
|
|
10
|
+
*/
|
|
11
|
+
export declare const materializeEntrypoint: <Protocol extends EntrypointProtocolDeclaration>(protocol: Protocol) => MaterializedEntrypoint<Protocol>;
|
|
12
|
+
//# sourceMappingURL=materialize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materialize.d.ts","sourceRoot":"","sources":["../src/materialize.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAmC,MAAM,YAAY,CAAA;AACnF,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAA;AAElE,8EAA8E;AAC9E,MAAM,MAAM,sBAAsB,CAAC,QAAQ,SAAS,6BAA6B,IAAI,gBAAgB,GAAG;IACtG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAC5B,CAAA;AAgCD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,QAAQ,SAAS,6BAA6B,YACxE,QAAQ,KACjB,sBAAsB,CAAC,QAAQ,CAGjC,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { entrypoint } from './entrypoint.js';
|
|
2
|
+
const filterOf = (protocol) => {
|
|
3
|
+
const request = protocol.contract?.requestSchemas;
|
|
4
|
+
const response = protocol.contract?.responseSchemas;
|
|
5
|
+
if (request == null && response == null)
|
|
6
|
+
return undefined;
|
|
7
|
+
return {
|
|
8
|
+
body: request?.body == null ? undefined : structuredClone(request.body),
|
|
9
|
+
params: request?.params == null ? undefined : structuredClone(request.params),
|
|
10
|
+
query: request?.query == null ? undefined : structuredClone(request.query),
|
|
11
|
+
headers: request?.headers == null ? undefined : structuredClone(request.headers),
|
|
12
|
+
response: response?.byStatus == null
|
|
13
|
+
? response?.default == null ? undefined : structuredClone(response.default)
|
|
14
|
+
: {
|
|
15
|
+
...(response.default == null ? {} : { default: structuredClone(response.default) }),
|
|
16
|
+
...Object.fromEntries(Object.entries(response.byStatus).map(([status, schema]) => [
|
|
17
|
+
status, structuredClone(schema),
|
|
18
|
+
])),
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
const optionsOf = (protocol) => ({
|
|
23
|
+
sticky: protocol.sticky,
|
|
24
|
+
guards: [...protocol.guards],
|
|
25
|
+
gate: protocol.gate?.alias,
|
|
26
|
+
gateParams: protocol.gate == null ? undefined : [...protocol.gate.params],
|
|
27
|
+
filter: filterOf(protocol),
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* Make a local, mutable registration from a shared declaration. The protocol is never mutated;
|
|
31
|
+
* guards, route resolution and handlers belong exclusively to this materialized entrypoint.
|
|
32
|
+
*/
|
|
33
|
+
export const materializeEntrypoint = (protocol) => Object.assign(entrypoint(protocol.route, optionsOf(protocol)), { protocol });
|
|
34
|
+
//# sourceMappingURL=materialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materialize.js","sourceRoot":"","sources":["../src/materialize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAS5C,MAAM,QAAQ,GAAG,CAAC,QAAuC,EAAsB,EAAE;IAC/E,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IACjD,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;IAEnD,IAAI,OAAO,IAAI,IAAI,IAAI,QAAQ,IAAI,IAAI;QAAE,OAAO,SAAS,CAAA;IAEzD,OAAO;QACL,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC;QACvE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC;QAC7E,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC;QAC1E,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC;QAChF,QAAQ,EAAE,QAAQ,EAAE,QAAQ,IAAI,IAAI;YAClC,CAAC,CAAC,QAAQ,EAAE,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC;YAC3E,CAAC,CAAC;gBACA,GAAG,CAAC,QAAQ,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBACnF,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;oBAChF,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;iBAChC,CAAC,CAAC;aACN;KACF,CAAA;AACH,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,CAAC,QAAuC,EAA2B,EAAE,CAAC,CAAC;IACvF,MAAM,EAAE,QAAQ,CAAC,MAAM;IACvB,MAAM,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC5B,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK;IAC1B,UAAU,EAAE,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;IACzE,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC;CAC3B,CAAC,CAAA;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,QAAkB,EACgB,EAAE,CAAC,MAAM,CAAC,MAAM,CAClD,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,EAC/C,EAAE,QAAQ,EAAE,CACb,CAAA"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import type { Auth } from '@owlmeans/auth';
|
|
2
|
+
import type { BasicEntrypoint, EntrypointReference } from '@owlmeans/context';
|
|
3
|
+
import type { JSONSchemaType, AnySchemaObject } from 'ajv';
|
|
4
|
+
import type { RouteModel } from '@owlmeans/route';
|
|
5
|
+
import type { EntrypointOutcome } from './consts.js';
|
|
6
|
+
import type { ResolvedEntity } from './types.js';
|
|
7
|
+
/** A deliberately broad value used only by declarations without an I/O contract. */
|
|
8
|
+
export type OpenValue = object | string | number | boolean | bigint | null | undefined;
|
|
9
|
+
/** The request accepted by a declaration that intentionally supplies no contract. */
|
|
10
|
+
export interface OpenRequest {
|
|
11
|
+
body?: object;
|
|
12
|
+
params?: object;
|
|
13
|
+
query?: object;
|
|
14
|
+
headers?: object;
|
|
15
|
+
}
|
|
16
|
+
/** The four independent request sections an entrypoint may declare. */
|
|
17
|
+
export interface RequestShape {
|
|
18
|
+
body?: OpenValue;
|
|
19
|
+
params?: object;
|
|
20
|
+
query?: object;
|
|
21
|
+
headers?: object;
|
|
22
|
+
}
|
|
23
|
+
/** Addressing and transport controls are never part of an entrypoint's payload contract. */
|
|
24
|
+
export interface CallOptions {
|
|
25
|
+
auth?: Auth;
|
|
26
|
+
host?: string;
|
|
27
|
+
base?: string | boolean;
|
|
28
|
+
unsecure?: boolean;
|
|
29
|
+
timeout?: number;
|
|
30
|
+
signal?: AbortSignal;
|
|
31
|
+
}
|
|
32
|
+
interface TypeToken {
|
|
33
|
+
readonly kind: 'entrypoint-type';
|
|
34
|
+
readonly schema?: AnySchemaObject;
|
|
35
|
+
}
|
|
36
|
+
/** A type-only contract source, optionally paired with an AJV schema. */
|
|
37
|
+
export type Typed<T> = TypeToken & {
|
|
38
|
+
readonly value?: T;
|
|
39
|
+
};
|
|
40
|
+
declare const entrypointSchemaType: unique symbol;
|
|
41
|
+
/**
|
|
42
|
+
* A JSON schema carrying the model type it validates. Use `schema<Model>(...)` once beside the
|
|
43
|
+
* model; every protocol that consumes it then infers the model without another generic.
|
|
44
|
+
*/
|
|
45
|
+
export type EntrypointSchema<T> = JSONSchemaType<T> & {
|
|
46
|
+
readonly [entrypointSchemaType]: T;
|
|
47
|
+
};
|
|
48
|
+
export declare const schema: <T>(value: JSONSchemaType<T>) => EntrypointSchema<T>;
|
|
49
|
+
/** A schema or an explicit type-only source for one request/response value. */
|
|
50
|
+
export type ShapeSource<T> = EntrypointSchema<T> | JSONSchemaType<T> | Typed<T>;
|
|
51
|
+
type AnyShapeSource = AnySchemaObject | TypeToken;
|
|
52
|
+
/**
|
|
53
|
+
* Supplies type information where a response has no runtime schema, or attaches a type to an
|
|
54
|
+
* otherwise untyped schema literal at the declaration boundary.
|
|
55
|
+
*/
|
|
56
|
+
export declare function typed<T>(): Typed<T>;
|
|
57
|
+
export declare function typed<T>(schema: JSONSchemaType<T>): Typed<T>;
|
|
58
|
+
export interface RequestSources {
|
|
59
|
+
body?: AnyShapeSource;
|
|
60
|
+
params?: AnyShapeSource;
|
|
61
|
+
query?: AnyShapeSource;
|
|
62
|
+
headers?: AnyShapeSource;
|
|
63
|
+
}
|
|
64
|
+
export interface RuntimeRequestSchemas {
|
|
65
|
+
body?: AnySchemaObject;
|
|
66
|
+
params?: AnySchemaObject;
|
|
67
|
+
query?: AnySchemaObject;
|
|
68
|
+
headers?: AnySchemaObject;
|
|
69
|
+
}
|
|
70
|
+
export interface RuntimeResponseSchemas {
|
|
71
|
+
default?: AnySchemaObject;
|
|
72
|
+
byStatus?: Readonly<Record<number, AnySchemaObject>>;
|
|
73
|
+
}
|
|
74
|
+
/** The runtime schemas and compile-time request/response pair attached to one protocol. */
|
|
75
|
+
export interface EntrypointContract<Request extends RequestShape, Response> {
|
|
76
|
+
readonly kind: 'entrypoint-contract';
|
|
77
|
+
readonly requestSchemas: RuntimeRequestSchemas;
|
|
78
|
+
readonly responseSchemas?: RuntimeResponseSchemas;
|
|
79
|
+
readonly requestType?: Request;
|
|
80
|
+
readonly responseType?: Response;
|
|
81
|
+
}
|
|
82
|
+
/** Runtime fields common to every protocol, regardless of its compile-time request/reply pair. */
|
|
83
|
+
export interface EntrypointProtocolDeclaration {
|
|
84
|
+
readonly kind: 'entrypoint-protocol';
|
|
85
|
+
readonly alias: string;
|
|
86
|
+
readonly route: RouteModel;
|
|
87
|
+
readonly contract?: Pick<EntrypointContract<RequestShape, OpenValue>, 'kind' | 'requestSchemas' | 'responseSchemas'>;
|
|
88
|
+
readonly sticky: boolean;
|
|
89
|
+
readonly guards: readonly string[];
|
|
90
|
+
readonly gate?: {
|
|
91
|
+
readonly alias: string;
|
|
92
|
+
readonly params: readonly string[];
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
type SourceValue<Source> = Source extends Typed<infer Value> ? Value : Source extends EntrypointSchema<infer Value> ? Value : Source extends JSONSchemaType<infer Value> ? Value extends OpenValue ? Value : OpenValue : OpenValue;
|
|
96
|
+
type RequestFromSources<Sources extends RequestSources> = (Sources extends {
|
|
97
|
+
body: infer Source;
|
|
98
|
+
} ? {
|
|
99
|
+
body: SourceValue<Source>;
|
|
100
|
+
} : {}) & (Sources extends {
|
|
101
|
+
params: infer Source;
|
|
102
|
+
} ? {
|
|
103
|
+
params: SourceValue<Source>;
|
|
104
|
+
} : {}) & (Sources extends {
|
|
105
|
+
query: infer Source;
|
|
106
|
+
} ? {
|
|
107
|
+
query: SourceValue<Source>;
|
|
108
|
+
} : {}) & (Sources extends {
|
|
109
|
+
headers: infer Source;
|
|
110
|
+
} ? {
|
|
111
|
+
headers: SourceValue<Source>;
|
|
112
|
+
} : {});
|
|
113
|
+
/**
|
|
114
|
+
* Declare an exact request and response. The primary overload means a body request; use
|
|
115
|
+
* `contract.request` for independently-shaped request sections.
|
|
116
|
+
*/
|
|
117
|
+
export declare function contract(): EntrypointContract<{}, undefined>;
|
|
118
|
+
export declare function contract<Response>(response: ShapeSource<Response>): EntrypointContract<{}, Response>;
|
|
119
|
+
export declare function contract<Body extends OpenValue, Response>(body: ShapeSource<Body>, response: ShapeSource<Response>): EntrypointContract<{
|
|
120
|
+
body: Body;
|
|
121
|
+
}, Response>;
|
|
122
|
+
export declare namespace contract {
|
|
123
|
+
function request<Sources extends RequestSources, Response>(request: Sources, response: ShapeSource<Response>): EntrypointContract<RequestFromSources<Sources>, Response>;
|
|
124
|
+
}
|
|
125
|
+
export interface EntrypointOptions {
|
|
126
|
+
sticky?: boolean;
|
|
127
|
+
guards?: string | readonly string[];
|
|
128
|
+
gate?: {
|
|
129
|
+
alias: string;
|
|
130
|
+
params?: string | readonly string[];
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
export interface EntrypointResult<Response> {
|
|
134
|
+
value: Response;
|
|
135
|
+
outcome: EntrypointOutcome;
|
|
136
|
+
}
|
|
137
|
+
export type CallArguments<Request extends RequestShape> = {} extends Request ? [request?: Request & CallOptions] : [request: Request & CallOptions];
|
|
138
|
+
type UrlRequest<Request extends RequestShape> = (Request extends {
|
|
139
|
+
params: infer Params;
|
|
140
|
+
} ? {
|
|
141
|
+
params: Params;
|
|
142
|
+
} : Request extends {
|
|
143
|
+
params?: infer Params;
|
|
144
|
+
} ? {
|
|
145
|
+
params?: Params;
|
|
146
|
+
} : {}) & (Request extends {
|
|
147
|
+
query: infer Query;
|
|
148
|
+
} ? {
|
|
149
|
+
query: Query;
|
|
150
|
+
} : Request extends {
|
|
151
|
+
query?: infer Query;
|
|
152
|
+
} ? {
|
|
153
|
+
query?: Query;
|
|
154
|
+
} : {});
|
|
155
|
+
export type UrlArguments<Request extends RequestShape> = {} extends UrlRequest<Request> ? [request?: UrlRequest<Request> & CallOptions] : [request: UrlRequest<Request> & CallOptions];
|
|
156
|
+
export interface EntrypointRequestMeta {
|
|
157
|
+
alias: string;
|
|
158
|
+
auth?: Auth;
|
|
159
|
+
entity?: ResolvedEntity;
|
|
160
|
+
path: string;
|
|
161
|
+
canceled?: boolean;
|
|
162
|
+
cancel?: () => void;
|
|
163
|
+
}
|
|
164
|
+
export type HandlerRequest<Request extends RequestShape> = Request & EntrypointRequestMeta;
|
|
165
|
+
/** The context-bound counterpart of an immutable protocol declaration. */
|
|
166
|
+
export interface RegisteredEntrypoint<Request extends RequestShape, Response> extends BasicEntrypoint {
|
|
167
|
+
readonly protocol: EntrypointProtocol<Request, Response>;
|
|
168
|
+
call: (...args: CallArguments<Request>) => Promise<Response>;
|
|
169
|
+
invoke: (...args: CallArguments<Request>) => Promise<EntrypointResult<Response>>;
|
|
170
|
+
url: (...args: UrlArguments<Request>) => Promise<string>;
|
|
171
|
+
validate: (...args: CallArguments<Request>) => Promise<boolean>;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* An immutable shared declaration. Its inherited reference type is what gives a context lookup
|
|
175
|
+
* the exact registered entrypoint type without a consumer-supplied generic.
|
|
176
|
+
*/
|
|
177
|
+
export interface EntrypointProtocol<Request extends RequestShape = RequestShape, Response = OpenValue> extends EntrypointProtocolDeclaration, EntrypointReference<RegisteredEntrypoint<Request, Response>> {
|
|
178
|
+
readonly contract?: EntrypointContract<Request, Response>;
|
|
179
|
+
}
|
|
180
|
+
export type RequestOf<Protocol extends EntrypointProtocolDeclaration> = Protocol extends EntrypointProtocol<infer Request, infer _Response> ? Request : OpenRequest;
|
|
181
|
+
export type ResponseOf<Protocol extends EntrypointProtocolDeclaration> = Protocol extends EntrypointProtocol<infer _Request, infer Response> ? Response : OpenValue;
|
|
182
|
+
export type BodyOf<Protocol extends EntrypointProtocolDeclaration> = RequestOf<Protocol> extends {
|
|
183
|
+
body: infer Body;
|
|
184
|
+
} ? Body : OpenValue;
|
|
185
|
+
export type ParamsOf<Protocol extends EntrypointProtocolDeclaration> = RequestOf<Protocol> extends {
|
|
186
|
+
params: infer Params;
|
|
187
|
+
} ? Params : object;
|
|
188
|
+
export type QueryOf<Protocol extends EntrypointProtocolDeclaration> = RequestOf<Protocol> extends {
|
|
189
|
+
query: infer Query;
|
|
190
|
+
} ? Query : object;
|
|
191
|
+
export type HeadersOf<Protocol extends EntrypointProtocolDeclaration> = RequestOf<Protocol> extends {
|
|
192
|
+
headers: infer Headers;
|
|
193
|
+
} ? Headers : object;
|
|
194
|
+
export type CallRequestOf<Protocol extends EntrypointProtocolDeclaration> = RequestOf<Protocol> & CallOptions;
|
|
195
|
+
/** Create the immutable protocol form while legacy contextual entrypoints are migrated. */
|
|
196
|
+
export declare const protocol: <Request extends RequestShape, Response>(route: RouteModel, entrypointContract: EntrypointContract<Request, Response>, options?: EntrypointOptions) => EntrypointProtocol<Request, Response>;
|
|
197
|
+
export declare const openProtocol: (route: RouteModel, options?: EntrypointOptions) => EntrypointProtocol<OpenRequest, OpenValue>;
|
|
198
|
+
export declare const entrypointRef: <Request extends RequestShape = OpenRequest, Response = OpenValue>(alias: string) => EntrypointReference<RegisteredEntrypoint<Request, Response>>;
|
|
199
|
+
export declare const aliasOf: (reference: EntrypointReference | string) => string;
|
|
200
|
+
export declare const isEntrypointProtocol: (value: object) => value is EntrypointProtocolDeclaration;
|
|
201
|
+
export interface EntrypointTree {
|
|
202
|
+
readonly [key: string]: EntrypointProtocolDeclaration | EntrypointTree;
|
|
203
|
+
}
|
|
204
|
+
/** Flatten an exported protocol tree for a layer-specific materializer. */
|
|
205
|
+
export declare const protocols: (tree: EntrypointTree) => EntrypointProtocolDeclaration[];
|
|
206
|
+
/** Clone an immutable protocol while preserving its request/response pair. */
|
|
207
|
+
export declare const decorateEntrypoint: <Protocol extends EntrypointProtocolDeclaration>(protocol: Protocol, options: EntrypointOptions) => Protocol;
|
|
208
|
+
export {};
|
|
209
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export const schema = (value) => value;
|
|
2
|
+
export function typed(schema) {
|
|
3
|
+
return schema == null
|
|
4
|
+
? { kind: 'entrypoint-type' }
|
|
5
|
+
: { kind: 'entrypoint-type', schema };
|
|
6
|
+
}
|
|
7
|
+
const schemaOf = (source) => {
|
|
8
|
+
if (source == null)
|
|
9
|
+
return undefined;
|
|
10
|
+
const schema = 'kind' in source && source.kind === 'entrypoint-type'
|
|
11
|
+
? source.schema
|
|
12
|
+
: source;
|
|
13
|
+
return schema == null ? undefined : structuredClone(schema);
|
|
14
|
+
};
|
|
15
|
+
const responseSchemasOf = (source) => {
|
|
16
|
+
const schema = schemaOf(source);
|
|
17
|
+
return schema == null ? undefined : { default: schema };
|
|
18
|
+
};
|
|
19
|
+
export function contract(first, second) {
|
|
20
|
+
const body = second == null ? undefined : first;
|
|
21
|
+
const response = second ?? first;
|
|
22
|
+
return {
|
|
23
|
+
kind: 'entrypoint-contract',
|
|
24
|
+
requestSchemas: { body: schemaOf(body) },
|
|
25
|
+
responseSchemas: responseSchemasOf(response),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
(function (contract) {
|
|
29
|
+
function request(request, response) {
|
|
30
|
+
return {
|
|
31
|
+
kind: 'entrypoint-contract',
|
|
32
|
+
requestSchemas: {
|
|
33
|
+
body: schemaOf(request.body),
|
|
34
|
+
params: schemaOf(request.params),
|
|
35
|
+
query: schemaOf(request.query),
|
|
36
|
+
headers: schemaOf(request.headers),
|
|
37
|
+
},
|
|
38
|
+
responseSchemas: responseSchemasOf(response),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
contract.request = request;
|
|
42
|
+
})(contract || (contract = {}));
|
|
43
|
+
const guardsOf = (guards) => guards == null
|
|
44
|
+
? []
|
|
45
|
+
: typeof guards === 'string' ? [guards] : [...guards];
|
|
46
|
+
const gateOf = (gate) => gate == null
|
|
47
|
+
? undefined
|
|
48
|
+
: {
|
|
49
|
+
alias: gate.alias,
|
|
50
|
+
params: gate.params == null ? [] : typeof gate.params === 'string' ? [gate.params] : [...gate.params],
|
|
51
|
+
};
|
|
52
|
+
/** Create the immutable protocol form while legacy contextual entrypoints are migrated. */
|
|
53
|
+
export const protocol = (route, entrypointContract, options) => Object.freeze({
|
|
54
|
+
kind: 'entrypoint-protocol',
|
|
55
|
+
alias: route.route.alias,
|
|
56
|
+
route: Object.freeze({ route: Object.freeze({ ...route.route }) }),
|
|
57
|
+
contract: entrypointContract,
|
|
58
|
+
sticky: options?.sticky ?? false,
|
|
59
|
+
guards: Object.freeze(guardsOf(options?.guards)),
|
|
60
|
+
gate: gateOf(options?.gate),
|
|
61
|
+
});
|
|
62
|
+
export const openProtocol = (route, options) => Object.freeze({
|
|
63
|
+
kind: 'entrypoint-protocol',
|
|
64
|
+
alias: route.route.alias,
|
|
65
|
+
route: Object.freeze({ route: Object.freeze({ ...route.route }) }),
|
|
66
|
+
sticky: options?.sticky ?? false,
|
|
67
|
+
guards: Object.freeze(guardsOf(options?.guards)),
|
|
68
|
+
gate: gateOf(options?.gate),
|
|
69
|
+
});
|
|
70
|
+
export const entrypointRef = (alias) => ({ alias });
|
|
71
|
+
export const aliasOf = (reference) => typeof reference === 'string' ? reference : reference.alias;
|
|
72
|
+
export const isEntrypointProtocol = (value) => 'kind' in value && value.kind === 'entrypoint-protocol';
|
|
73
|
+
/** Flatten an exported protocol tree for a layer-specific materializer. */
|
|
74
|
+
export const protocols = (tree) => {
|
|
75
|
+
const result = [];
|
|
76
|
+
const visit = (node) => {
|
|
77
|
+
Object.values(node).forEach((entry) => {
|
|
78
|
+
if (isEntrypointProtocol(entry)) {
|
|
79
|
+
result.push(entry);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
visit(entry);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
visit(tree);
|
|
87
|
+
return result;
|
|
88
|
+
};
|
|
89
|
+
/** Clone an immutable protocol while preserving its request/response pair. */
|
|
90
|
+
export const decorateEntrypoint = (protocol, options) => Object.freeze({
|
|
91
|
+
...protocol,
|
|
92
|
+
sticky: options.sticky ?? protocol.sticky,
|
|
93
|
+
guards: options.guards == null ? protocol.guards : guardsOf(options.guards),
|
|
94
|
+
gate: options.gate == null ? protocol.gate : gateOf(options.gate),
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entrypoint.d.ts","sourceRoot":"","sources":["../../src/utils/entrypoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE9C,eAAO,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"entrypoint.d.ts","sourceRoot":"","sources":["../../src/utils/entrypoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE9C,eAAO,MAAM,YAAY,QAAS,MAAM,KAAG,GAAG,IAAI,gBAC5B,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/entrypoint",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.12",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@owlmeans/auth": "^0.1.18-rc.
|
|
32
|
-
"@owlmeans/context": "^0.1.18-rc.
|
|
33
|
-
"@owlmeans/route": "^0.1.18-rc.
|
|
31
|
+
"@owlmeans/auth": "^0.1.18-rc.10",
|
|
32
|
+
"@owlmeans/context": "^0.1.18-rc.9",
|
|
33
|
+
"@owlmeans/route": "^0.1.18-rc.10",
|
|
34
34
|
"ajv": "^8.17.1"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
package/src/entrypoint.ts
CHANGED
|
@@ -40,6 +40,18 @@ export const entrypoint: CreateEntrypointSignature<CommonEntrypoint> = (route, o
|
|
|
40
40
|
return guards
|
|
41
41
|
},
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* The gates standing over this entrypoint: its own, then an ancestor's for each gate service
|
|
45
|
+
* this entrypoint has not already named.
|
|
46
|
+
*
|
|
47
|
+
* KNOWN HAZARD, deliberately left alone: the dedup is by gate SERVICE, and two gates under one
|
|
48
|
+
* service are two different questions because their parameters differ — so a child that
|
|
49
|
+
* declares its own gate silently drops its ancestor's, which is the opposite of what
|
|
50
|
+
* "inherited" means. Anything that needs a group rule AND a member rule must therefore not
|
|
51
|
+
* express the group half as a gate under the same service. Changing this would widen every
|
|
52
|
+
* backend and socket entrypoint that today relies on the replacement, so it is a migration
|
|
53
|
+
* rather than a fix.
|
|
54
|
+
*/
|
|
43
55
|
getGates: () => {
|
|
44
56
|
const gates: [string, string[]][] = ep.gate != null ? [[
|
|
45
57
|
ep.gate, ep.gateParams == null
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { entrypoint } from './entrypoint.js'
|
|
2
|
+
import type { CommonEntrypoint, CommonEntrypointOptions, Filter } from './types.js'
|
|
3
|
+
import type { EntrypointProtocolDeclaration } from './protocol.js'
|
|
4
|
+
|
|
5
|
+
/** A context-bound entrypoint made from an immutable protocol declaration. */
|
|
6
|
+
export type MaterializedEntrypoint<Protocol extends EntrypointProtocolDeclaration> = CommonEntrypoint & {
|
|
7
|
+
readonly protocol: Protocol
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const filterOf = (protocol: EntrypointProtocolDeclaration): Filter | undefined => {
|
|
11
|
+
const request = protocol.contract?.requestSchemas
|
|
12
|
+
const response = protocol.contract?.responseSchemas
|
|
13
|
+
|
|
14
|
+
if (request == null && response == null) return undefined
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
body: request?.body == null ? undefined : structuredClone(request.body),
|
|
18
|
+
params: request?.params == null ? undefined : structuredClone(request.params),
|
|
19
|
+
query: request?.query == null ? undefined : structuredClone(request.query),
|
|
20
|
+
headers: request?.headers == null ? undefined : structuredClone(request.headers),
|
|
21
|
+
response: response?.byStatus == null
|
|
22
|
+
? response?.default == null ? undefined : structuredClone(response.default)
|
|
23
|
+
: {
|
|
24
|
+
...(response.default == null ? {} : { default: structuredClone(response.default) }),
|
|
25
|
+
...Object.fromEntries(Object.entries(response.byStatus).map(([status, schema]) => [
|
|
26
|
+
status, structuredClone(schema),
|
|
27
|
+
])),
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const optionsOf = (protocol: EntrypointProtocolDeclaration): CommonEntrypointOptions => ({
|
|
33
|
+
sticky: protocol.sticky,
|
|
34
|
+
guards: [...protocol.guards],
|
|
35
|
+
gate: protocol.gate?.alias,
|
|
36
|
+
gateParams: protocol.gate == null ? undefined : [...protocol.gate.params],
|
|
37
|
+
filter: filterOf(protocol),
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Make a local, mutable registration from a shared declaration. The protocol is never mutated;
|
|
42
|
+
* guards, route resolution and handlers belong exclusively to this materialized entrypoint.
|
|
43
|
+
*/
|
|
44
|
+
export const materializeEntrypoint = <Protocol extends EntrypointProtocolDeclaration>(
|
|
45
|
+
protocol: Protocol,
|
|
46
|
+
): MaterializedEntrypoint<Protocol> => Object.assign(
|
|
47
|
+
entrypoint(protocol.route, optionsOf(protocol)),
|
|
48
|
+
{ protocol },
|
|
49
|
+
)
|
package/src/protocol.ts
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import type { Auth } from '@owlmeans/auth'
|
|
2
|
+
import type { BasicEntrypoint, EntrypointReference } from '@owlmeans/context'
|
|
3
|
+
import type { JSONSchemaType, AnySchemaObject } from 'ajv'
|
|
4
|
+
import type { RouteModel } from '@owlmeans/route'
|
|
5
|
+
import type { EntrypointOutcome } from './consts.js'
|
|
6
|
+
import type { ResolvedEntity } from './types.js'
|
|
7
|
+
|
|
8
|
+
/** A deliberately broad value used only by declarations without an I/O contract. */
|
|
9
|
+
export type OpenValue = object | string | number | boolean | bigint | null | undefined
|
|
10
|
+
|
|
11
|
+
/** The request accepted by a declaration that intentionally supplies no contract. */
|
|
12
|
+
export interface OpenRequest {
|
|
13
|
+
body?: object
|
|
14
|
+
params?: object
|
|
15
|
+
query?: object
|
|
16
|
+
headers?: object
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** The four independent request sections an entrypoint may declare. */
|
|
20
|
+
export interface RequestShape {
|
|
21
|
+
body?: OpenValue
|
|
22
|
+
params?: object
|
|
23
|
+
query?: object
|
|
24
|
+
headers?: object
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Addressing and transport controls are never part of an entrypoint's payload contract. */
|
|
28
|
+
export interface CallOptions {
|
|
29
|
+
auth?: Auth
|
|
30
|
+
host?: string
|
|
31
|
+
base?: string | boolean
|
|
32
|
+
unsecure?: boolean
|
|
33
|
+
timeout?: number
|
|
34
|
+
signal?: AbortSignal
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface TypeToken {
|
|
38
|
+
readonly kind: 'entrypoint-type'
|
|
39
|
+
readonly schema?: AnySchemaObject
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** A type-only contract source, optionally paired with an AJV schema. */
|
|
43
|
+
export type Typed<T> = TypeToken & { readonly value?: T }
|
|
44
|
+
|
|
45
|
+
declare const entrypointSchemaType: unique symbol
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* A JSON schema carrying the model type it validates. Use `schema<Model>(...)` once beside the
|
|
49
|
+
* model; every protocol that consumes it then infers the model without another generic.
|
|
50
|
+
*/
|
|
51
|
+
export type EntrypointSchema<T> = JSONSchemaType<T> & {
|
|
52
|
+
readonly [entrypointSchemaType]: T
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const schema = <T>(value: JSONSchemaType<T>): EntrypointSchema<T> =>
|
|
56
|
+
value as EntrypointSchema<T>
|
|
57
|
+
|
|
58
|
+
/** A schema or an explicit type-only source for one request/response value. */
|
|
59
|
+
export type ShapeSource<T> = EntrypointSchema<T> | JSONSchemaType<T> | Typed<T>
|
|
60
|
+
|
|
61
|
+
type AnyShapeSource = AnySchemaObject | TypeToken
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Supplies type information where a response has no runtime schema, or attaches a type to an
|
|
65
|
+
* otherwise untyped schema literal at the declaration boundary.
|
|
66
|
+
*/
|
|
67
|
+
export function typed<T>(): Typed<T>
|
|
68
|
+
export function typed<T>(schema: JSONSchemaType<T>): Typed<T>
|
|
69
|
+
export function typed<T>(schema?: JSONSchemaType<T>): Typed<T> {
|
|
70
|
+
return schema == null
|
|
71
|
+
? { kind: 'entrypoint-type' }
|
|
72
|
+
: { kind: 'entrypoint-type', schema }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface RequestSources {
|
|
76
|
+
body?: AnyShapeSource
|
|
77
|
+
params?: AnyShapeSource
|
|
78
|
+
query?: AnyShapeSource
|
|
79
|
+
headers?: AnyShapeSource
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface RuntimeRequestSchemas {
|
|
83
|
+
body?: AnySchemaObject
|
|
84
|
+
params?: AnySchemaObject
|
|
85
|
+
query?: AnySchemaObject
|
|
86
|
+
headers?: AnySchemaObject
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface RuntimeResponseSchemas {
|
|
90
|
+
default?: AnySchemaObject
|
|
91
|
+
byStatus?: Readonly<Record<number, AnySchemaObject>>
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** The runtime schemas and compile-time request/response pair attached to one protocol. */
|
|
95
|
+
export interface EntrypointContract<Request extends RequestShape, Response> {
|
|
96
|
+
readonly kind: 'entrypoint-contract'
|
|
97
|
+
readonly requestSchemas: RuntimeRequestSchemas
|
|
98
|
+
readonly responseSchemas?: RuntimeResponseSchemas
|
|
99
|
+
readonly requestType?: Request
|
|
100
|
+
readonly responseType?: Response
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Runtime fields common to every protocol, regardless of its compile-time request/reply pair. */
|
|
104
|
+
export interface EntrypointProtocolDeclaration {
|
|
105
|
+
readonly kind: 'entrypoint-protocol'
|
|
106
|
+
readonly alias: string
|
|
107
|
+
readonly route: RouteModel
|
|
108
|
+
readonly contract?: Pick<EntrypointContract<RequestShape, OpenValue>,
|
|
109
|
+
'kind' | 'requestSchemas' | 'responseSchemas'>
|
|
110
|
+
readonly sticky: boolean
|
|
111
|
+
readonly guards: readonly string[]
|
|
112
|
+
readonly gate?: {
|
|
113
|
+
readonly alias: string
|
|
114
|
+
readonly params: readonly string[]
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
type SourceValue<Source> =
|
|
119
|
+
Source extends Typed<infer Value> ? Value
|
|
120
|
+
: Source extends EntrypointSchema<infer Value> ? Value
|
|
121
|
+
: Source extends JSONSchemaType<infer Value>
|
|
122
|
+
? Value extends OpenValue ? Value : OpenValue
|
|
123
|
+
: OpenValue
|
|
124
|
+
|
|
125
|
+
type RequestFromSources<Sources extends RequestSources> =
|
|
126
|
+
(Sources extends { body: infer Source } ? { body: SourceValue<Source> } : {})
|
|
127
|
+
& (Sources extends { params: infer Source } ? { params: SourceValue<Source> } : {})
|
|
128
|
+
& (Sources extends { query: infer Source } ? { query: SourceValue<Source> } : {})
|
|
129
|
+
& (Sources extends { headers: infer Source } ? { headers: SourceValue<Source> } : {})
|
|
130
|
+
|
|
131
|
+
const schemaOf = (source: AnyShapeSource | undefined): AnySchemaObject | undefined => {
|
|
132
|
+
if (source == null) return undefined
|
|
133
|
+
const schema = 'kind' in source && source.kind === 'entrypoint-type'
|
|
134
|
+
? source.schema
|
|
135
|
+
: source
|
|
136
|
+
|
|
137
|
+
return schema == null ? undefined : structuredClone(schema)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const responseSchemasOf = (source: AnyShapeSource | undefined): RuntimeResponseSchemas | undefined => {
|
|
141
|
+
const schema = schemaOf(source)
|
|
142
|
+
return schema == null ? undefined : { default: schema }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Declare an exact request and response. The primary overload means a body request; use
|
|
147
|
+
* `contract.request` for independently-shaped request sections.
|
|
148
|
+
*/
|
|
149
|
+
export function contract(): EntrypointContract<{}, undefined>
|
|
150
|
+
export function contract<Response>(response: ShapeSource<Response>): EntrypointContract<{}, Response>
|
|
151
|
+
export function contract<Body extends OpenValue, Response>(
|
|
152
|
+
body: ShapeSource<Body>, response: ShapeSource<Response>
|
|
153
|
+
): EntrypointContract<{ body: Body }, Response>
|
|
154
|
+
export function contract(
|
|
155
|
+
first?: AnyShapeSource, second?: AnyShapeSource
|
|
156
|
+
): EntrypointContract<RequestShape, OpenValue> {
|
|
157
|
+
const body = second == null ? undefined : first
|
|
158
|
+
const response = second ?? first
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
kind: 'entrypoint-contract',
|
|
162
|
+
requestSchemas: { body: schemaOf(body) },
|
|
163
|
+
responseSchemas: responseSchemasOf(response),
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export namespace contract {
|
|
168
|
+
export function request<Sources extends RequestSources, Response>(
|
|
169
|
+
request: Sources,
|
|
170
|
+
response: ShapeSource<Response>
|
|
171
|
+
): EntrypointContract<RequestFromSources<Sources>, Response> {
|
|
172
|
+
return {
|
|
173
|
+
kind: 'entrypoint-contract',
|
|
174
|
+
requestSchemas: {
|
|
175
|
+
body: schemaOf(request.body),
|
|
176
|
+
params: schemaOf(request.params),
|
|
177
|
+
query: schemaOf(request.query),
|
|
178
|
+
headers: schemaOf(request.headers),
|
|
179
|
+
},
|
|
180
|
+
responseSchemas: responseSchemasOf(response),
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export interface EntrypointOptions {
|
|
186
|
+
sticky?: boolean
|
|
187
|
+
guards?: string | readonly string[]
|
|
188
|
+
gate?: {
|
|
189
|
+
alias: string
|
|
190
|
+
params?: string | readonly string[]
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export interface EntrypointResult<Response> {
|
|
195
|
+
value: Response
|
|
196
|
+
outcome: EntrypointOutcome
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export type CallArguments<Request extends RequestShape> = {} extends Request
|
|
200
|
+
? [request?: Request & CallOptions]
|
|
201
|
+
: [request: Request & CallOptions]
|
|
202
|
+
|
|
203
|
+
type UrlRequest<Request extends RequestShape> =
|
|
204
|
+
(Request extends { params: infer Params } ? { params: Params }
|
|
205
|
+
: Request extends { params?: infer Params } ? { params?: Params } : {})
|
|
206
|
+
& (Request extends { query: infer Query } ? { query: Query }
|
|
207
|
+
: Request extends { query?: infer Query } ? { query?: Query } : {})
|
|
208
|
+
|
|
209
|
+
export type UrlArguments<Request extends RequestShape> = {} extends UrlRequest<Request>
|
|
210
|
+
? [request?: UrlRequest<Request> & CallOptions]
|
|
211
|
+
: [request: UrlRequest<Request> & CallOptions]
|
|
212
|
+
|
|
213
|
+
export interface EntrypointRequestMeta {
|
|
214
|
+
alias: string
|
|
215
|
+
auth?: Auth
|
|
216
|
+
entity?: ResolvedEntity
|
|
217
|
+
path: string
|
|
218
|
+
canceled?: boolean
|
|
219
|
+
cancel?: () => void
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export type HandlerRequest<Request extends RequestShape> = Request & EntrypointRequestMeta
|
|
223
|
+
|
|
224
|
+
/** The context-bound counterpart of an immutable protocol declaration. */
|
|
225
|
+
export interface RegisteredEntrypoint<Request extends RequestShape, Response> extends BasicEntrypoint {
|
|
226
|
+
readonly protocol: EntrypointProtocol<Request, Response>
|
|
227
|
+
call: (...args: CallArguments<Request>) => Promise<Response>
|
|
228
|
+
invoke: (...args: CallArguments<Request>) => Promise<EntrypointResult<Response>>
|
|
229
|
+
url: (...args: UrlArguments<Request>) => Promise<string>
|
|
230
|
+
validate: (...args: CallArguments<Request>) => Promise<boolean>
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* An immutable shared declaration. Its inherited reference type is what gives a context lookup
|
|
235
|
+
* the exact registered entrypoint type without a consumer-supplied generic.
|
|
236
|
+
*/
|
|
237
|
+
export interface EntrypointProtocol<
|
|
238
|
+
Request extends RequestShape = RequestShape,
|
|
239
|
+
Response = OpenValue,
|
|
240
|
+
> extends EntrypointProtocolDeclaration, EntrypointReference<RegisteredEntrypoint<Request, Response>> {
|
|
241
|
+
readonly contract?: EntrypointContract<Request, Response>
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export type RequestOf<Protocol extends EntrypointProtocolDeclaration> = Protocol extends EntrypointProtocol<infer Request, infer _Response>
|
|
245
|
+
? Request
|
|
246
|
+
: OpenRequest
|
|
247
|
+
|
|
248
|
+
export type ResponseOf<Protocol extends EntrypointProtocolDeclaration> = Protocol extends EntrypointProtocol<infer _Request, infer Response>
|
|
249
|
+
? Response
|
|
250
|
+
: OpenValue
|
|
251
|
+
|
|
252
|
+
export type BodyOf<Protocol extends EntrypointProtocolDeclaration> = RequestOf<Protocol> extends { body: infer Body }
|
|
253
|
+
? Body
|
|
254
|
+
: OpenValue
|
|
255
|
+
|
|
256
|
+
export type ParamsOf<Protocol extends EntrypointProtocolDeclaration> = RequestOf<Protocol> extends { params: infer Params }
|
|
257
|
+
? Params
|
|
258
|
+
: object
|
|
259
|
+
|
|
260
|
+
export type QueryOf<Protocol extends EntrypointProtocolDeclaration> = RequestOf<Protocol> extends { query: infer Query }
|
|
261
|
+
? Query
|
|
262
|
+
: object
|
|
263
|
+
|
|
264
|
+
export type HeadersOf<Protocol extends EntrypointProtocolDeclaration> = RequestOf<Protocol> extends { headers: infer Headers }
|
|
265
|
+
? Headers
|
|
266
|
+
: object
|
|
267
|
+
|
|
268
|
+
export type CallRequestOf<Protocol extends EntrypointProtocolDeclaration> = RequestOf<Protocol> & CallOptions
|
|
269
|
+
|
|
270
|
+
const guardsOf = (guards: EntrypointOptions['guards']): readonly string[] => guards == null
|
|
271
|
+
? []
|
|
272
|
+
: typeof guards === 'string' ? [guards] : [...guards]
|
|
273
|
+
|
|
274
|
+
const gateOf = (gate: EntrypointOptions['gate']): EntrypointProtocol['gate'] => gate == null
|
|
275
|
+
? undefined
|
|
276
|
+
: {
|
|
277
|
+
alias: gate.alias,
|
|
278
|
+
params: gate.params == null ? [] : typeof gate.params === 'string' ? [gate.params] : [...gate.params],
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** Create the immutable protocol form while legacy contextual entrypoints are migrated. */
|
|
282
|
+
export const protocol = <Request extends RequestShape, Response>(
|
|
283
|
+
route: RouteModel,
|
|
284
|
+
entrypointContract: EntrypointContract<Request, Response>,
|
|
285
|
+
options?: EntrypointOptions
|
|
286
|
+
): EntrypointProtocol<Request, Response> => Object.freeze({
|
|
287
|
+
kind: 'entrypoint-protocol' as const,
|
|
288
|
+
alias: route.route.alias,
|
|
289
|
+
route: Object.freeze({ route: Object.freeze({ ...route.route }) }),
|
|
290
|
+
contract: entrypointContract,
|
|
291
|
+
sticky: options?.sticky ?? false,
|
|
292
|
+
guards: Object.freeze(guardsOf(options?.guards)),
|
|
293
|
+
gate: gateOf(options?.gate),
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
export const openProtocol = (
|
|
297
|
+
route: RouteModel,
|
|
298
|
+
options?: EntrypointOptions
|
|
299
|
+
): EntrypointProtocol<OpenRequest, OpenValue> => Object.freeze({
|
|
300
|
+
kind: 'entrypoint-protocol' as const,
|
|
301
|
+
alias: route.route.alias,
|
|
302
|
+
route: Object.freeze({ route: Object.freeze({ ...route.route }) }),
|
|
303
|
+
sticky: options?.sticky ?? false,
|
|
304
|
+
guards: Object.freeze(guardsOf(options?.guards)),
|
|
305
|
+
gate: gateOf(options?.gate),
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
export const entrypointRef = <Request extends RequestShape = OpenRequest, Response = OpenValue>(
|
|
309
|
+
alias: string
|
|
310
|
+
): EntrypointReference<RegisteredEntrypoint<Request, Response>> => ({ alias })
|
|
311
|
+
|
|
312
|
+
export const aliasOf = (reference: EntrypointReference | string): string =>
|
|
313
|
+
typeof reference === 'string' ? reference : reference.alias
|
|
314
|
+
|
|
315
|
+
export const isEntrypointProtocol = (value: object): value is EntrypointProtocolDeclaration =>
|
|
316
|
+
'kind' in value && value.kind === 'entrypoint-protocol'
|
|
317
|
+
|
|
318
|
+
export interface EntrypointTree {
|
|
319
|
+
readonly [key: string]: EntrypointProtocolDeclaration | EntrypointTree
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** Flatten an exported protocol tree for a layer-specific materializer. */
|
|
323
|
+
export const protocols = (tree: EntrypointTree): EntrypointProtocolDeclaration[] => {
|
|
324
|
+
const result: EntrypointProtocolDeclaration[] = []
|
|
325
|
+
|
|
326
|
+
const visit = (node: EntrypointTree): void => {
|
|
327
|
+
Object.values(node).forEach((entry) => {
|
|
328
|
+
if (isEntrypointProtocol(entry)) {
|
|
329
|
+
result.push(entry)
|
|
330
|
+
} else {
|
|
331
|
+
visit(entry)
|
|
332
|
+
}
|
|
333
|
+
})
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
visit(tree)
|
|
337
|
+
return result
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/** Clone an immutable protocol while preserving its request/response pair. */
|
|
341
|
+
export const decorateEntrypoint = <Protocol extends EntrypointProtocolDeclaration>(
|
|
342
|
+
protocol: Protocol,
|
|
343
|
+
options: EntrypointOptions
|
|
344
|
+
): Protocol => Object.freeze({
|
|
345
|
+
...protocol,
|
|
346
|
+
sticky: options.sticky ?? protocol.sticky,
|
|
347
|
+
guards: options.guards == null ? protocol.guards : guardsOf(options.guards),
|
|
348
|
+
gate: options.gate == null ? protocol.gate : gateOf(options.gate),
|
|
349
|
+
})
|