@owlmeans/server-entrypoint 0.1.18-rc.9 → 0.1.18

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 CHANGED
@@ -1,72 +1,150 @@
1
1
  # @owlmeans/server-entrypoint
2
2
 
3
- Elevates route definitions into runnable server entrypoints with attached request handlers.
4
-
5
- ## Overview
6
-
7
- - `elevate(entrypoints, alias, handler?, opts?)` attaches a `RefedEntrypointHandler` to an existing entrypoint in place
8
- - `entrypoint(commonEntrypoint, handler?, opts?)` wraps a `CommonEntrypoint` into a `ServerEntrypoint`
9
- - `guard(alias, opts?)` creates `EntrypointOptions` requiring a named guard service
10
- - Used internally by `@owlmeans/server-app`'s `elevate` re-export
3
+ Server-side entrypoint binding: turns an immutable protocol declaration from the shared package into
4
+ a server-local entrypoint that carries its route, guards, gate and handler. An application calls
5
+ `bind` / `bindAll` in its `entrypoints.ts` (often through the `@owlmeans/server-app` re-export) to
6
+ build the list it registers on the context. It does not write handlers — use `handlers<Context>()`
7
+ from `@owlmeans/server-api` for HTTP and `connection()` from `@owlmeans/server-socket` for sockets —
8
+ and a browser app binds the same protocols with `@owlmeans/client-entrypoint` instead.
11
9
 
12
10
  ## Installation
13
11
 
14
12
  ```bash
15
- bun add @owlmeans/server-entrypoint
13
+ bun add @owlmeans/server-entrypoint@^0.1.18
16
14
  ```
17
15
 
16
+ ## Concepts
17
+
18
+ - **Protocol declaration** — the frozen `protocol()` / `openProtocol()` object from
19
+ `@owlmeans/entrypoint`, shared by callers and servers. It is data; binding never changes it.
20
+ - **Server entrypoint** — what `bind` returns: a materialized copy with a server route, merged
21
+ guards, gate, filter, optional fixer and handler, plus a `protocol` field pointing at its
22
+ declaration.
23
+ - **Bound handler** — `{ protocol, bind }`, produced by `handlers<Context>()` or `connection()`. It
24
+ is inseparable from the protocol whose request it accepts.
25
+ - **Group node** — a parent declaration (`base`) bound without a handler. It contributes the path
26
+ prefix, guards and gate its children inherit and is never mounted as a route itself.
27
+ - **Intermediate** — an entrypoint whose handler runs before matching routes and may replace the
28
+ request context; declared per route or forced with `{ intermediate: true }`.
29
+
18
30
  ## Usage
19
31
 
20
- Typical pattern — define entrypoints separately, elevate with handlers:
32
+ ### Bind leaves and their parents
21
33
 
22
- ```typescript
23
- import { elevate, guard } from '@owlmeans/server-app'
24
- import { handleBody, handleParams } from '@owlmeans/server-app'
34
+ ```ts
35
+ import { bind } from '@owlmeans/server-entrypoint'
36
+ import { handlers } from '@owlmeans/server-api'
37
+ import { projectProtocols } from 'my-app-common'
38
+ import type { Context } from './context.js'
25
39
 
26
- const appEntrypoints = [
27
- entrypoint(route('project-create', '/projects', backend(RouteMethod.POST)), guard('auth')),
28
- entrypoint(route('project-get', '/projects/:id', backend())),
40
+ const api = handlers<Context>()
41
+
42
+ export const serverBindings = [
43
+ bind(projectProtocols.base),
44
+ bind(projectProtocols.create, api.body(projectProtocols.create, async (body, context) =>
45
+ context.project().create(body))),
46
+ bind(projectProtocols.get, api.params(projectProtocols.get, async ({ id }, context) =>
47
+ context.project().load(id))),
29
48
  ]
49
+ ```
30
50
 
31
- elevate(appEntrypoints, 'project-create', handleBody(async (payload, ctx) => {
32
- return await ctx.project().create(payload)
33
- }))
51
+ ### Bind a flat collection
34
52
 
35
- elevate(appEntrypoints, 'project-get', handleParams(async (params, ctx) => {
36
- return await ctx.project().get(params.id)
37
- }))
38
- ```
53
+ `bindAll` pairs each declaration with the implementation whose `protocol` is the same object.
54
+ Declarations without an implementation are bound as group nodes. Flatten a tree with `protocols()`
55
+ only here, at the registration boundary.
39
56
 
40
- ## API
57
+ ```ts
58
+ import { bindAll } from '@owlmeans/server-entrypoint'
59
+ import { protocols } from '@owlmeans/entrypoint'
60
+ import * as project from './app/project.js'
41
61
 
42
- ### `elevate<R>(entrypoints, alias, handler?, opts?): ServerEntrypoint<R>[]`
62
+ export const projectBindings = bindAll(protocols(projectProtocols), [
63
+ project.list,
64
+ project.create,
65
+ project.get,
66
+ ])
67
+ ```
43
68
 
44
- Replaces the element carrying `alias` with its elevated counterpart, in place, attaching `handler`. Elevating the same alias again just replaces it again; guards passed here are added to the ones the entrypoint declared. Throws when no entrypoint carries the alias.
69
+ ### Bind a tree by path
45
70
 
46
- ### `entrypoint<R>(commonEntrypoint, handler?, opts?): ServerEntrypoint<R>`
71
+ Larger services walk the protocol tree and look up the implementation at the same path, so a new or
72
+ renamed declaration stays type-checked at its binding site:
47
73
 
48
- Wraps a single `CommonEntrypoint` into a `ServerEntrypoint`. Lower-level than `elevate`.
74
+ ```ts
75
+ import { bind } from '@owlmeans/server-entrypoint'
76
+ import type { ServerEntrypoint } from '@owlmeans/server-entrypoint'
77
+ import { isEntrypointProtocol } from '@owlmeans/entrypoint'
78
+ import type { EntrypointTree } from '@owlmeans/entrypoint'
49
79
 
50
- ### `guard<R>(guard, opts?): EntrypointOptions<R>`
80
+ type Implementations = Record<string, unknown>
51
81
 
52
- Returns `EntrypointOptions` that require the named guard service to pass before the handler runs.
82
+ const bindTree = (tree: EntrypointTree, implementations: Implementations = {}): ServerEntrypoint<object>[] =>
83
+ Object.entries(tree).flatMap(([key, declaration]) => {
84
+ const implementation = implementations[key]
85
+ if (isEntrypointProtocol(declaration)) {
86
+ return [bind(declaration, implementation as never)]
87
+ }
88
+ return bindTree(declaration, (implementation ?? {}) as Implementations)
89
+ })
53
90
 
54
- ### `ServerEntrypoint<R>`
91
+ export const serverBindings = bindTree({ project: projectProtocols, invoice: invoiceProtocols }, {
92
+ project: { list: project.list, create: project.create, get: project.get },
93
+ invoice: { list: invoice.list, pay: invoice.pay },
94
+ })
95
+ ```
55
96
 
56
- Extends `CommonEntrypoint` with:
57
- - `route: ServerRouteModel<R>` — the server route declaration; `route.match(request, entrypoint.mount())`
58
- answers whether a request hits it
59
- - `handle: RefedEntrypointHandler<R>` — the attached handler
97
+ ### Server-local options
60
98
 
61
- ### `RefedEntrypointHandler<R>`
99
+ The third argument adjusts only the local binding. `guards` are merged with the declaration's,
100
+ `fixer` names a `FixerService` that answers errors instead of the default mapping, and
101
+ `intermediate` forces the entrypoint to run as an intermediate.
62
102
 
63
- A handler factory: `(ref: { ref?: { ctx?: Context } }) => EntrypointHandler`.
103
+ ```ts
104
+ import { bind } from '@owlmeans/server-entrypoint'
64
105
 
65
- ## Related Packages
106
+ export const serverBindings = [
107
+ bind(sessionProtocols.base, undefined, { intermediate: true }),
108
+ bind(invoiceProtocols.download, invoice.download, { fixer: MY_APP_DOWNLOAD_FIXER }),
109
+ ]
110
+ ```
111
+
112
+ ## API
66
113
 
67
- - [`@owlmeans/entrypoint`](../entrypoint) — `CommonEntrypoint` base that gets elevated
68
- - [`@owlmeans/server-api`](../server-api) — handler wrappers (`handleBody`, etc.) used with `elevate`
69
- - [`@owlmeans/server-app`](../server-app) — re-exports `elevate`, `entrypoint`, `guard`
114
+ | Symbol | Kind | Purpose |
115
+ |---|---|---|
116
+ | `bind(protocol, implementation?, options?)` | function | Materialize one declaration and attach a bound handler (or a `RefedEntrypointHandler`); returns `ServerProtocolEntrypoint<Protocol>` |
117
+ | `bindAll(declarations, implementations = [])` | function | Bind a flat declaration list, pairing implementations by `implementation.protocol === declaration` |
118
+ | `ServerEntrypoint<R>` | type | `CommonEntrypoint` with `route: ServerRouteModel<R>`, `handle: EntrypointHandler`, `fixer?` |
119
+ | `ServerProtocolEntrypoint<Protocol>` | type | `ServerEntrypoint<object>` plus `readonly protocol` |
120
+ | `BoundEntrypointHandler<Protocol>` | type | `{ readonly protocol, bind: RefedEntrypointHandler }` |
121
+ | `RefedEntrypointHandler<R>` | type | `(ref: EntrypointRef<R>) => EntrypointHandler`; the handler reads the bound entrypoint (and its context) from `ref.ref` |
122
+ | `EntrypointRef<R>` | type | `{ ref?: ServerEntrypoint<R> }` |
123
+ | `EntrypointOptions<R>` | type | `CommonEntrypointOptions` plus `fixer?`, `intermediate?`, `routeOptions?` |
124
+ | `FixerService` | type | Service with `handle(reply, error)` used when a binding names a `fixer` |
125
+
126
+ ## Common pitfalls
127
+
128
+ - A handler carries its `protocol`, and collections match by object identity. Never attach, find or
129
+ replace a handler by alias.
130
+ - A decorated tree (`withOidcGuard(tree)`, `decorateEntrypoint(...)`) consists of new objects. Make
131
+ handlers from the same decorated protocols you bind, or `bindAll` will not pair them.
132
+ - Do not mutate a declaration or create a mutable contextual declaration; decorate the tree before
133
+ binding instead.
134
+ - Bind parent declarations too. A route whose parent is not registered loses its inherited path,
135
+ guards and gate.
136
+ - A binding without a handler is never mounted as an HTTP route — that is how group nodes work, and
137
+ also why a forgotten implementation shows up as a 404.
138
+ - HTTP handlers come from `handlers<Context>()`; socket handlers from `connection(protocol, callback)`.
139
+
140
+ ## Related packages
141
+
142
+ - [`@owlmeans/entrypoint`](../entrypoint) — immutable protocol declarations
143
+ - [`@owlmeans/server-api`](../server-api) — `handlers<Context>()` for HTTP bindings
144
+ - [`@owlmeans/server-socket`](../server-socket) — `connection()` for socket bindings
145
+ - [`@owlmeans/server-route`](../server-route) — the server route model a binding carries
146
+ - [`@owlmeans/server-app`](../server-app) — re-exports `bind` / `bindAll` and registers the list
147
+ - [`@owlmeans/client-entrypoint`](../client-entrypoint) — the browser-side binding of the same protocols
70
148
 
71
149
  <!-- owlmeans:agent-guidance:start -->
72
150
  ## Agent guidance
@@ -76,7 +154,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
76
154
  your project's skill store (`.agents/skills/`):
77
155
 
78
156
  ```sh
79
- npx @owlmeans/agent-skills
157
+ npx @owlmeans/agent-skills@^0.1.18
80
158
  ```
81
159
 
82
160
  The embedded files are version-matched to this package release. Do not edit them
@@ -1,8 +1,8 @@
1
1
  {
2
- "schemaVersion": 2,
2
+ "schemaVersion": 3,
3
3
  "package": "@owlmeans/server-entrypoint",
4
- "version": "0.1.18-rc.9",
5
- "generatedAt": "2026-09-01T16:28:56.991Z",
4
+ "version": "0.1.18",
5
+ "generatedAt": "2026-10-28T00:31:34.739Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -1,62 +1,39 @@
1
1
  ---
2
2
  name: server-entrypoint
3
- description: How to use @owlmeans/server-entrypoint — server-side entrypoints extending @owlmeans/entrypoint with handler attachment, intermediates and mount(). Auto-invoked when importing server-entrypoint types.
3
+ description: Bind immutable @owlmeans/entrypoint declarations to protocol-bound server implementations. Load when serving a shared API, socket, or queue entrypoint.
4
4
  user-invocable: false
5
5
  ---
6
6
  <!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
7
7
 
8
8
  # @owlmeans/server-entrypoint
9
9
 
10
- **Layer:** Server
11
- **Install:** `"@owlmeans/server-entrypoint": "^0.1.18-rc.9"` in `dependencies`
10
+ **Install:** `bun add @owlmeans/server-entrypoint@^0.1.18`
12
11
 
13
- ## Key Exports
12
+ Bind the imported protocol object to the implementation that serves it:
14
13
 
15
- | Export | Description |
16
- |--------|-------------|
17
- | `ServerEntrypoint<R>` | Server entrypoint interface — a `ServerRouteModel` plus a `handle` |
18
- | `entrypoint(arg, handler?, opts?)` | Build a server entrypoint from a route model or an existing declaration |
19
- | `elevate(entrypoints, alias, handler?, opts?)` | Attach a handler (or just guards) to a declared entrypoint |
20
- | `guard(alias, opts?)` | Require a guard, returning server entrypoint options |
21
- | `EntrypointOptions<R>` | Options for elevating: `handler`, `fixer`, `intermediate`, `routeOptions`, guards/gates/filter |
22
- | `EntrypointRef` / `RefedEntrypointHandler` | Handler reference pattern |
23
- | `FixerService` | Per-entrypoint error rendering (`handle(reply, error)`) |
14
+ ```ts
15
+ import { bind } from '@owlmeans/server-entrypoint'
16
+ import { handlers } from '@owlmeans/server-api'
24
17
 
25
- ## Usage
18
+ const api = handlers<AppContext>()
26
19
 
27
- Most app code uses `elevate()` from `@owlmeans/server-app` (which builds on this package). Import directly only when implementing custom entrypoint helpers.
28
-
29
- ```typescript
30
- import type { ServerEntrypoint } from '@owlmeans/server-entrypoint'
20
+ export const serverBindings = [
21
+ bind(projectProtocols.create, api.body(projectProtocols.create, async (body, context) =>
22
+ context.projects.create(body)
23
+ )),
24
+ ]
31
25
  ```
32
26
 
33
- Elevating is **idempotent** — elevating the same alias again simply replaces the element once more,
34
- and an intermediate stays intermediate unless the new call says otherwise. Guards passed at
35
- elevation are **unioned** with the ones the declaration already carries, so what the entrypoint
36
- declared still applies.
37
-
38
- ## What a server registers
39
-
40
- `mount()` is the address a server binds: `base` plus every ancestor's segment, then this one. The
41
- declaration itself only ever states the segment it contributes, so composing the rest takes the
42
- context the entrypoint is registered in — which is why route registration happens after `init()`,
43
- never at declaration time.
44
-
45
- ```typescript
46
- server.route({ url: entrypoint.mount(), method, handler })
47
- entrypoint.route.match(request, entrypoint.mount()) // intermediates test the same mount
48
- ```
49
-
50
- ## Cross-Service URL Generation
51
-
52
- Use `makeSecurityHelper` from `@owlmeans/config` to build URLs pointing at other services (OAuth redirect URIs, webhook callbacks, etc.):
53
-
54
- ```typescript
55
- import { makeSecurityHelper } from '@owlmeans/config'
56
- const helper = makeSecurityHelper<Config, Context>(ctx)
57
- const url = helper.makeUrl(entrypoint.address(), '/callback')
58
- ```
27
+ `bind(protocol, handler?, options?)` returns a `ServerProtocolEntrypoint<Protocol>`.
28
+ `bindAll(declarations, handlers?)` is for a flat protocol collection at a registration boundary. A handler carries its
29
+ `protocol`, and a collection is matched by object identity; an alias is never used to find or
30
+ replace it. HTTP code should use `handlers<Context>()`; sockets use `connection(protocol, callback)`.
59
31
 
60
- ## Depends On
32
+ The second argument is either a protocol-bound handler (from `handlers<Context>()` above, or a
33
+ library factory that returns one) or omitted entirely for a parent route. A plain callback passed
34
+ directly to `bind()` is NOT the same thing: it is treated as a ref handler and invoked once, at
35
+ bind time, with the entrypoint ref as its only argument — not per-request. Wrap it with
36
+ `handlers<Context>()` first.
61
37
 
62
- - `@owlmeans/entrypoint`, `@owlmeans/server-route`, `@owlmeans/server-context`
38
+ Do not create a mutable contextual declaration, use a compatibility entrypoint type, or attach a
39
+ handler with an alias. The declaration is shared data; the binding is its server-local runtime.
@@ -1,6 +1,6 @@
1
1
  import type { ServerRouteModel } from '@owlmeans/server-route';
2
2
  import type { ServerEntrypoint, EntrypointOptions, RefedEntrypointHandler } from './types.js';
3
3
  import type { CommonEntrypoint } from '@owlmeans/entrypoint';
4
- import type { RouteModel } from '@owlmeans/route';
5
- export declare const entrypoint: <R>(arg: CommonEntrypoint | ServerRouteModel<R> | RouteModel, handler?: RefedEntrypointHandler<R>, opts?: EntrypointOptions<R>) => ServerEntrypoint<R>;
4
+ import type { CommonRouteModel } from '@owlmeans/route';
5
+ export declare const entrypoint: <R>(arg: CommonEntrypoint | ServerRouteModel<R> | CommonRouteModel, handler?: RefedEntrypointHandler<R>, opts?: EntrypointOptions<R>) => ServerEntrypoint<R>;
6
6
  //# sourceMappingURL=entrypoint.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entrypoint.d.ts","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAiB,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAG5G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD,eAAO,MAAM,UAAU,GAAI,CAAC,EAC1B,KAAK,gBAAgB,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,UAAU,EAAE,UAAU,sBAAsB,CAAC,CAAC,CAAC,EAAE,OAAO,iBAAiB,CAAC,CAAC,CAAC,KACzH,gBAAgB,CAAC,CAAC,CAmCpB,CAAA"}
1
+ {"version":3,"file":"entrypoint.d.ts","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAiB,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAG5G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAIvD,eAAO,MAAM,UAAU,GAAI,CAAC,EAC1B,KAAK,gBAAgB,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,gBAAgB,EAAE,UAAU,sBAAsB,CAAC,CAAC,CAAC,EAAE,OAAO,iBAAiB,CAAC,CAAC,CAAC,KAC/H,gBAAgB,CAAC,CAAC,CAuCpB,CAAA"}
@@ -1,19 +1,15 @@
1
1
  import { isEntrypoint, makeCommonEntrypoint } from './utils/entrypoint.js';
2
2
  import { isServerRouteModel, route } from '@owlmeans/server-route';
3
+ import { prependBase } from '@owlmeans/route/utils';
3
4
  export const entrypoint = (arg, handler, opts) => {
4
5
  const entrypointHandle = { ref: undefined };
5
6
  let _entrypoint;
6
7
  if (isEntrypoint(arg)) {
7
- // Elevating the same alias again is legal, so an intermediate route stays intermediate unless
8
- // this call says otherwise.
9
- const intermediate = opts?.intermediate
10
- ?? (isServerRouteModel(arg.route) ? arg.route.isIntermediate() : false);
11
- const routeModel = route(arg.route, intermediate, opts?.routeOptions);
8
+ const routeModel = route(arg.route, opts?.intermediate ?? false, opts?.routeOptions);
12
9
  _entrypoint = arg;
13
10
  _entrypoint.route = routeModel;
14
11
  _entrypoint.filter = opts?.filter ?? arg.filter;
15
- // Elevating adds guards, it never swaps them: what the entrypoint declared still applies.
16
- _entrypoint.guards = [...new Set([...(arg.guards ?? []), ...(opts?.guards ?? [])])];
12
+ _entrypoint.guards = [...(arg.guards ?? []), ...(opts?.guards ?? [])];
17
13
  _entrypoint.gate = opts?.gate ?? arg.gate;
18
14
  _entrypoint.gateParams = opts?.gateParams ?? arg.gateParams;
19
15
  }
@@ -26,10 +22,16 @@ export const entrypoint = (arg, handler, opts) => {
26
22
  _entrypoint = makeCommonEntrypoint(_route, { ...opts });
27
23
  _entrypoint.route = _route;
28
24
  }
29
- _entrypoint.fixer = opts?.fixer ?? _entrypoint.fixer;
25
+ _entrypoint.fixer = opts?.fixer;
30
26
  if (handler != null) {
31
27
  _entrypoint.handle = handler(entrypointHandle);
32
28
  }
29
+ _entrypoint.reinitializeContext = (context) => {
30
+ const newEntrypoint = entrypoint(arg, handler, opts);
31
+ newEntrypoint.ctx = context;
32
+ return newEntrypoint;
33
+ };
34
+ _entrypoint.getPath = () => prependBase(_entrypoint.route.route);
33
35
  entrypointHandle.ref = _entrypoint;
34
36
  return _entrypoint;
35
37
  };
@@ -1 +1 @@
1
- {"version":3,"file":"entrypoint.js","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAC1E,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAIlE,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,GAAwD,EAAE,OAAmC,EAAE,IAA2B,EACrG,EAAE;IACvB,MAAM,gBAAgB,GAAqB,EAAE,GAAG,EAAE,SAAS,EAAE,CAAA;IAE7D,IAAI,WAAgC,CAAA;IAEpC,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,8FAA8F;QAC9F,4BAA4B;QAC5B,MAAM,YAAY,GAAG,IAAI,EAAE,YAAY;eAClC,CAAC,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;QACzE,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,CAAC,CAAA;QACrE,WAAW,GAAG,GAA0B,CAAA;QACxC,WAAW,CAAC,KAAK,GAAG,UAAU,CAAA;QAC9B,WAAW,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,CAAA;QAC/C,0FAA0F;QAC1F,WAAW,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QACnF,WAAW,CAAC,IAAI,GAAG,IAAI,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI,CAAA;QACzC,WAAW,CAAC,UAAU,GAAG,IAAI,EAAE,UAAU,IAAI,GAAG,CAAC,UAAU,CAAA;IAC7D,CAAC;SAAM,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,WAAW,GAAG,oBAAoB,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,CAAwB,CAAA;QAC3E,WAAW,CAAC,KAAK,GAAG,GAAG,CAAA;IACzB,CAAC;SAAM,CAAC;QACN,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,YAAY,IAAI,KAAK,EAAE,IAAI,EAAE,YAAY,CAAC,CAAA;QAC1E,WAAW,GAAG,oBAAoB,CAAC,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,CAAwB,CAAA;QAC9E,WAAW,CAAC,KAAK,GAAG,MAAM,CAAA;IAC5B,CAAC;IAED,WAAW,CAAC,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,WAAW,CAAC,KAAK,CAAA;IACpD,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACpB,WAAW,CAAC,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;IAChD,CAAC;IAED,gBAAgB,CAAC,GAAG,GAAG,WAAW,CAAA;IAElC,OAAO,WAAW,CAAA;AACpB,CAAC,CAAA"}
1
+ {"version":3,"file":"entrypoint.js","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAC1E,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAIlE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAEnD,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,GAA8D,EAAE,OAAmC,EAAE,IAA2B,EAC3G,EAAE;IACvB,MAAM,gBAAgB,GAAqB,EAAE,GAAG,EAAE,SAAS,EAAE,CAAA;IAE7D,IAAI,WAAgC,CAAA;IAEpC,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,IAAI,KAAK,EAAE,IAAI,EAAE,YAAY,CAAC,CAAA;QACpF,WAAW,GAAG,GAA0B,CAAA;QACxC,WAAW,CAAC,KAAK,GAAG,UAAU,CAAA;QAC9B,WAAW,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,CAAA;QAC/C,WAAW,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,CAAA;QACrE,WAAW,CAAC,IAAI,GAAG,IAAI,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI,CAAA;QACzC,WAAW,CAAC,UAAU,GAAG,IAAI,EAAE,UAAU,IAAI,GAAG,CAAC,UAAU,CAAA;IAC7D,CAAC;SAAM,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,WAAW,GAAG,oBAAoB,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,CAAwB,CAAA;QAC3E,WAAW,CAAC,KAAK,GAAG,GAAG,CAAA;IACzB,CAAC;SAAM,CAAC;QACN,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,YAAY,IAAI,KAAK,EAAE,IAAI,EAAE,YAAY,CAAC,CAAA;QAC1E,WAAW,GAAG,oBAAoB,CAAC,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,CAAwB,CAAA;QAC9E,WAAW,CAAC,KAAK,GAAG,MAAM,CAAA;IAC5B,CAAC;IAED,WAAW,CAAC,KAAK,GAAG,IAAI,EAAE,KAAK,CAAA;IAC/B,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACpB,WAAW,CAAC,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;IAChD,CAAC;IAED,WAAW,CAAC,mBAAmB,GAAG,CAAI,OAA0B,EAAE,EAAE;QAClE,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;QACpD,aAAa,CAAC,GAAG,GAAG,OAAO,CAAA;QAE3B,OAAO,aAAkB,CAAA;IAC3B,CAAC,CAAA;IAED,WAAW,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAEhE,gBAAgB,CAAC,GAAG,GAAG,WAAW,CAAA;IAElC,OAAO,WAAW,CAAA;AACpB,CAAC,CAAA"}
package/build/helper.d.ts CHANGED
@@ -1,12 +1,5 @@
1
1
  import type { ServerEntrypoint, EntrypointOptions, RefedEntrypointHandler } from './types.js';
2
2
  import type { CommonEntrypoint } from '@owlmeans/entrypoint';
3
- /**
4
- * Replace the entrypoint declared under `alias` with its elevated counterpart. Elevating is
5
- * idempotent — calling it again simply replaces the element once more, and the guards it brings
6
- * are added to the ones already declared.
7
- *
8
- * @throws {SyntaxError} when no entrypoint carries the alias
9
- */
10
3
  export declare const elevate: <R>(entrypoints: (CommonEntrypoint | ServerEntrypoint<R>)[], alias: string, handler?: RefedEntrypointHandler<R> | boolean | EntrypointOptions<R>, opts?: boolean | EntrypointOptions<R>) => ServerEntrypoint<R>[];
11
4
  export declare const guard: <R>(guard: string, opts?: EntrypointOptions<R>) => EntrypointOptions<R>;
12
5
  //# sourceMappingURL=helper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAG7F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAE5D;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,EACvB,aAAa,CAAC,gBAAgB,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,EACvD,OAAO,MAAM,EACb,UAAU,sBAAsB,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,iBAAiB,CAAC,CAAC,CAAC,EACpE,OAAO,OAAO,GAAG,iBAAiB,CAAC,CAAC,CAAC,KACpC,gBAAgB,CAAC,CAAC,CAAC,EAmBrB,CAAA;AAED,eAAO,MAAM,KAAK,GAAI,CAAC,EAAE,OAAO,MAAM,EAAE,OAAO,iBAAiB,CAAC,CAAC,CAAC,KAAG,iBAAiB,CAAC,CAAC,CACjD,CAAA"}
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAI7F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAE5D,eAAO,MAAM,OAAO,GAAI,CAAC,EACvB,aAAa,CAAC,gBAAgB,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,EACvD,OAAO,MAAM,EACb,UAAU,sBAAsB,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,iBAAiB,CAAC,CAAC,CAAC,EACpE,OAAO,OAAO,GAAG,iBAAiB,CAAC,CAAC,CAAC,KACpC,gBAAgB,CAAC,CAAC,CAAC,EAuBrB,CAAA;AAED,eAAO,MAAM,KAAK,GAAI,CAAC,EAAE,OAAO,MAAM,EAAE,OAAO,iBAAiB,CAAC,CAAC,CAAC,KAAG,iBAAiB,CAAC,CAAC,CACjD,CAAA"}
package/build/helper.js CHANGED
@@ -1,12 +1,6 @@
1
1
  import { entrypoint } from './entrypoint.js';
2
+ import { isServerRouteModel } from '@owlmeans/server-route';
2
3
  import { createBasicGuard } from './utils/helper.js';
3
- /**
4
- * Replace the entrypoint declared under `alias` with its elevated counterpart. Elevating is
5
- * idempotent — calling it again simply replaces the element once more, and the guards it brings
6
- * are added to the ones already declared.
7
- *
8
- * @throws {SyntaxError} when no entrypoint carries the alias
9
- */
10
4
  export const elevate = (entrypoints, alias, handler, opts) => {
11
5
  const idx = entrypoints.findIndex(({ route }) => route.route.alias === alias);
12
6
  if (idx === -1) {
@@ -20,6 +14,10 @@ export const elevate = (entrypoints, alias, handler, opts) => {
20
14
  opts = handler;
21
15
  handler = undefined;
22
16
  }
17
+ const force = typeof opts === 'object' && opts.force;
18
+ if (isServerRouteModel(entrypoints[idx].route) && !force) {
19
+ throw new SyntaxError(`Entrypoint with alias ${alias} is already elevated`);
20
+ }
23
21
  entrypoints[idx] = entrypoint(entrypoints[idx], handler, typeof opts === 'boolean' ? { intermediate: opts } : opts);
24
22
  return entrypoints;
25
23
  };
@@ -1 +1 @@
1
- {"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAGpD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CACrB,WAAuD,EACvD,KAAa,EACb,OAAoE,EACpE,IAAqC,EACd,EAAE;IACzB,MAAM,GAAG,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,CAAA;IAC7E,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,WAAW,CAAC,yBAAyB,KAAK,cAAc,CAAC,CAAA;IACrE,CAAC;IACD,IAAI,OAAO,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,IAAI,GAAG,OAAO,CAAA;QACd,OAAO,GAAG,SAAS,CAAA;IACrB,CAAC;IACD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;QACjE,IAAI,GAAG,OAAO,CAAA;QACd,OAAO,GAAG,SAAS,CAAA;IACrB,CAAC;IAED,WAAW,CAAC,GAAG,CAAC,GAAG,UAAU,CAC3B,WAAW,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CACrF,CAAA;IAED,OAAO,WAAoC,CAAA;AAC7C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAI,KAAa,EAAE,IAA2B,EAAwB,EAAE,CAC3F,CAAC,EAAE,GAAG,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA"}
1
+ {"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAGpD,MAAM,CAAC,MAAM,OAAO,GAAG,CACrB,WAAuD,EACvD,KAAa,EACb,OAAoE,EACpE,IAAqC,EACd,EAAE;IACzB,MAAM,GAAG,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,CAAA;IAC7E,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,WAAW,CAAC,yBAAyB,KAAK,cAAc,CAAC,CAAA;IACrE,CAAC;IACD,IAAI,OAAO,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,IAAI,GAAG,OAAO,CAAA;QACd,OAAO,GAAG,SAAS,CAAA;IACrB,CAAC;IACD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;QACjE,IAAI,GAAG,OAAO,CAAA;QACd,OAAO,GAAG,SAAS,CAAA;IACrB,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAA;IACpD,IAAI,kBAAkB,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACzD,MAAM,IAAI,WAAW,CAAC,yBAAyB,KAAK,sBAAsB,CAAC,CAAA;IAC7E,CAAC;IAED,WAAW,CAAC,GAAG,CAAC,GAAG,UAAU,CAC3B,WAAW,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CACrF,CAAA;IAED,OAAO,WAAoC,CAAA;AAC7C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAI,KAAa,EAAE,IAA2B,EAAwB,EAAE,CAC3F,CAAC,EAAE,GAAG,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA"}
package/build/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export * from './helper.js';
2
1
  export type * from './types.js';
3
- export * from './entrypoint.js';
2
+ export * from './protocol.js';
4
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAC3B,mBAAmB,YAAY,CAAA;AAC/B,cAAc,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,eAAe,CAAA"}
package/build/index.js CHANGED
@@ -1,3 +1,2 @@
1
- export * from './helper.js';
2
- export * from './entrypoint.js';
1
+ export * from './protocol.js';
3
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAE3B,cAAc,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,eAAe,CAAA"}
@@ -0,0 +1,8 @@
1
+ import { type EntrypointProtocolDeclaration } from '@owlmeans/entrypoint';
2
+ import type { BoundEntrypointHandler, EntrypointOptions, ServerProtocolEntrypoint } from './types.js';
3
+ import type { ServerBinding } from './types.local.js';
4
+ /** Bind one immutable protocol and, when present, its protocol-bound implementation. */
5
+ export declare const bind: <Protocol extends EntrypointProtocolDeclaration>(protocol: Protocol, implementation?: ServerBinding<Protocol>, options?: EntrypointOptions<object>) => ServerProtocolEntrypoint<Protocol>;
6
+ /** Bind a flat declaration collection and pair each protocol with its own implementation. */
7
+ export declare const bindAll: <Protocol extends EntrypointProtocolDeclaration>(declarations: readonly Protocol[], implementations?: readonly BoundEntrypointHandler<Protocol>[]) => ServerProtocolEntrypoint<Protocol>[];
8
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,6BAA6B,EAAE,MAAM,sBAAsB,CAAA;AAEvH,OAAO,KAAK,EACV,sBAAsB,EAAE,iBAAiB,EACzC,wBAAwB,EACzB,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAyBrD,wFAAwF;AACxF,eAAO,MAAM,IAAI,GAAI,QAAQ,SAAS,6BAA6B,YACvD,QAAQ,mBACD,aAAa,CAAC,QAAQ,CAAC,YAC9B,iBAAiB,CAAC,MAAM,CAAC,KAClC,wBAAwB,CAAC,QAAQ,CAWnC,CAAA;AAED,6FAA6F;AAC7F,eAAO,MAAM,OAAO,GAAI,QAAQ,SAAS,6BAA6B,gBACtD,SAAS,QAAQ,EAAE,oBAChB,SAAS,sBAAsB,CAAC,QAAQ,CAAC,EAAE,KAC3D,wBAAwB,CAAC,QAAQ,CAAC,EAEpC,CAAA"}
@@ -0,0 +1,30 @@
1
+ import { materializeEntrypoint } from '@owlmeans/entrypoint';
2
+ import { isServerRouteModel, route } from '@owlmeans/server-route';
3
+ /** Attach a server implementation to an entrypoint materialized from a protocol declaration. */
4
+ const bindMaterializedEntrypoint = (declaration, handler, options) => {
5
+ const ref = { ref: undefined };
6
+ const intermediate = options?.intermediate
7
+ ?? (isServerRouteModel(declaration.route) ? declaration.route.isIntermediate() : false);
8
+ const bound = declaration;
9
+ bound.route = route(declaration.route, intermediate, options?.routeOptions);
10
+ bound.filter = options?.filter ?? declaration.filter;
11
+ bound.guards = [...new Set([...(declaration.guards ?? []), ...(options?.guards ?? [])])];
12
+ bound.gate = options?.gate ?? declaration.gate;
13
+ bound.gateParams = options?.gateParams ?? declaration.gateParams;
14
+ bound.fixer = options?.fixer ?? bound.fixer;
15
+ if (handler != null)
16
+ bound.handle = handler(ref);
17
+ ref.ref = bound;
18
+ return bound;
19
+ };
20
+ /** Bind one immutable protocol and, when present, its protocol-bound implementation. */
21
+ export const bind = (protocol, implementation, options) => {
22
+ const handler = typeof implementation === 'function'
23
+ ? implementation
24
+ : implementation?.bind;
25
+ const bound = Object.assign(bindMaterializedEntrypoint(materializeEntrypoint(protocol), handler, options), { protocol });
26
+ return bound;
27
+ };
28
+ /** Bind a flat declaration collection and pair each protocol with its own implementation. */
29
+ export const bindAll = (declarations, implementations = []) => declarations.map(declaration => bind(declaration, implementations.find(implementation => implementation.protocol === declaration)));
30
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAA6D,MAAM,sBAAsB,CAAA;AACvH,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAOlE,gGAAgG;AAChG,MAAM,0BAA0B,GAAG,CACjC,WAA6B,EAC7B,OAAmC,EACnC,OAA8B,EACT,EAAE;IACvB,MAAM,GAAG,GAAqB,EAAE,GAAG,EAAE,SAAS,EAAE,CAAA;IAChD,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY;WACrC,CAAC,kBAAkB,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;IACzF,MAAM,KAAK,GAAG,WAAkC,CAAA;IAEhD,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,CAAC,CAAA;IAC3E,KAAK,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,WAAW,CAAC,MAAM,CAAA;IACpD,KAAK,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IACxF,KAAK,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,WAAW,CAAC,IAAI,CAAA;IAC9C,KAAK,CAAC,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,WAAW,CAAC,UAAU,CAAA;IAChE,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,KAAK,CAAC,KAAK,CAAA;IAC3C,IAAI,OAAO,IAAI,IAAI;QAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;IAChD,GAAG,CAAC,GAAG,GAAG,KAAK,CAAA;IAEf,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAED,wFAAwF;AACxF,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,QAAkB,EAClB,cAAwC,EACxC,OAAmC,EACC,EAAE;IACtC,MAAM,OAAO,GAAG,OAAO,cAAc,KAAK,UAAU;QAClD,CAAC,CAAC,cAAc;QAChB,CAAC,CAAC,cAAc,EAAE,IAAI,CAAA;IACxB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,0BAA0B,CACpD,qBAAqB,CAAC,QAAQ,CAAC,EAC/B,OAAO,EACP,OAAO,CACR,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAA;IAEhB,OAAO,KAA2C,CAAA;AACpD,CAAC,CAAA;AAED,6FAA6F;AAC7F,MAAM,CAAC,MAAM,OAAO,GAAG,CACrB,YAAiC,EACjC,eAAe,GAAgD,EAAE,EAC3B,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CACxE,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,cAAc,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAC,CACnG,CAAA"}
package/build/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ServerRouteModel, ServerRouteOptions } from '@owlmeans/server-route';
2
- import type { CommonEntrypoint, EntrypointHandler, CommonEntrypointOptions } from '@owlmeans/entrypoint';
2
+ import type { CommonEntrypoint, EntrypointHandler, CommonEntrypointOptions, EntrypointProtocolDeclaration } from '@owlmeans/entrypoint';
3
3
  import type { Service } from '@owlmeans/context';
4
4
  export interface ServerEntrypoint<R> extends CommonEntrypoint {
5
5
  route: ServerRouteModel<R>;
@@ -20,4 +20,13 @@ export interface EntrypointRef<R> {
20
20
  export interface RefedEntrypointHandler<R = {}> {
21
21
  (ref: EntrypointRef<R>): EntrypointHandler;
22
22
  }
23
+ /** The server-local representation of a shared protocol declaration. */
24
+ export interface ServerProtocolEntrypoint<Protocol extends EntrypointProtocolDeclaration> extends ServerEntrypoint<object> {
25
+ readonly protocol: Protocol;
26
+ }
27
+ /** A handler that is inseparable from the protocol whose request it accepts. */
28
+ export interface BoundEntrypointHandler<Protocol extends EntrypointProtocolDeclaration> {
29
+ readonly protocol: Protocol;
30
+ bind: RefedEntrypointHandler;
31
+ }
23
32
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAClF,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AACxG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAEhD,MAAM,WAAW,gBAAgB,CAAC,CAAC,CAAE,SAAQ,gBAAgB;IAC3D,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,CAAE,SAAQ,uBAAuB;IACnE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,YAAY,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAA;CACrC;AAED,MAAM,WAAW,YAAa,SAAQ,OAAO;IAC3C,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CAC5C;AAED,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;CAC1B;AAED,MAAM,WAAW,sBAAsB,CAAC,CAAC,GAAG,EAAE;IAC5C,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAA;CAC3C"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAClF,OAAO,KAAK,EACV,gBAAgB,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,6BAA6B,EAC5F,MAAM,sBAAsB,CAAA;AAC7B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAEhD,MAAM,WAAW,gBAAgB,CAAC,CAAC,CAAE,SAAQ,gBAAgB;IAC3D,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,CAAE,SAAQ,uBAAuB;IACnE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,YAAY,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAA;CACrC;AAED,MAAM,WAAW,YAAa,SAAQ,OAAO;IAC3C,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CAC5C;AAED,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;CAC1B;AAED,MAAM,WAAW,sBAAsB,CAAC,CAAC,GAAG,EAAE;IAC5C,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAA;CAC3C;AAED,wEAAwE;AACxE,MAAM,WAAW,wBAAwB,CAAC,QAAQ,SAAS,6BAA6B,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IAAG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE;AAE1J,gFAAgF;AAChF,MAAM,WAAW,sBAAsB,CAAC,QAAQ,SAAS,6BAA6B;IACpF,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,IAAI,EAAE,sBAAsB,CAAA;CAC7B"}
@@ -0,0 +1,4 @@
1
+ import type { EntrypointProtocolDeclaration } from '@owlmeans/entrypoint';
2
+ import type { BoundEntrypointHandler, RefedEntrypointHandler } from './types.js';
3
+ export type ServerBinding<Protocol extends EntrypointProtocolDeclaration> = BoundEntrypointHandler<Protocol> | RefedEntrypointHandler;
4
+ //# sourceMappingURL=types.local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.local.d.ts","sourceRoot":"","sources":["../src/types.local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAA;AACzE,OAAO,KAAK,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAEhF,MAAM,MAAM,aAAa,CAAC,QAAQ,SAAS,6BAA6B,IACpE,sBAAsB,CAAC,QAAQ,CAAC,GAChC,sBAAsB,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.local.js","sourceRoot":"","sources":["../src/types.local.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/server-entrypoint",
3
- "version": "0.1.18-rc.9",
3
+ "version": "0.1.18",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -21,14 +21,14 @@
21
21
  }
22
22
  },
23
23
  "dependencies": {
24
- "@owlmeans/context": "^0.1.18-rc.7",
25
- "@owlmeans/entrypoint": "^0.1.18-rc.9",
26
- "@owlmeans/route": "^0.1.18-rc.7",
27
- "@owlmeans/server-route": "^0.1.18-rc.7"
24
+ "@owlmeans/context": "^0.1.18",
25
+ "@owlmeans/entrypoint": "^0.1.18",
26
+ "@owlmeans/route": "^0.1.18",
27
+ "@owlmeans/server-route": "^0.1.18"
28
28
  },
29
29
  "devDependencies": {
30
- "@owlmeans/dep-config": "workspace:*",
31
- "@types/node": "^26.1.0",
30
+ "@owlmeans/dep-config": "^0.1.18",
31
+ "@types/node": "^26.6.4",
32
32
  "nodemon": "^3.1.14",
33
33
  "typescript": "^7.0.2"
34
34
  },
package/src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
1
 
2
- export * from './helper.js'
3
2
  export type * from './types.js'
4
- export * from './entrypoint.js'
3
+ export * from './protocol.js'
@@ -0,0 +1,56 @@
1
+ import { materializeEntrypoint, type CommonEntrypoint, type EntrypointProtocolDeclaration } from '@owlmeans/entrypoint'
2
+ import { isServerRouteModel, route } from '@owlmeans/server-route'
3
+ import type {
4
+ BoundEntrypointHandler, EntrypointOptions, EntrypointRef, RefedEntrypointHandler, ServerEntrypoint,
5
+ ServerProtocolEntrypoint,
6
+ } from './types.js'
7
+ import type { ServerBinding } from './types.local.js'
8
+
9
+ /** Attach a server implementation to an entrypoint materialized from a protocol declaration. */
10
+ const bindMaterializedEntrypoint = <R>(
11
+ declaration: CommonEntrypoint,
12
+ handler?: RefedEntrypointHandler<R>,
13
+ options?: EntrypointOptions<R>,
14
+ ): ServerEntrypoint<R> => {
15
+ const ref: EntrypointRef<R> = { ref: undefined }
16
+ const intermediate = options?.intermediate
17
+ ?? (isServerRouteModel(declaration.route) ? declaration.route.isIntermediate() : false)
18
+ const bound = declaration as ServerEntrypoint<R>
19
+
20
+ bound.route = route(declaration.route, intermediate, options?.routeOptions)
21
+ bound.filter = options?.filter ?? declaration.filter
22
+ bound.guards = [...new Set([...(declaration.guards ?? []), ...(options?.guards ?? [])])]
23
+ bound.gate = options?.gate ?? declaration.gate
24
+ bound.gateParams = options?.gateParams ?? declaration.gateParams
25
+ bound.fixer = options?.fixer ?? bound.fixer
26
+ if (handler != null) bound.handle = handler(ref)
27
+ ref.ref = bound
28
+
29
+ return bound
30
+ }
31
+
32
+ /** Bind one immutable protocol and, when present, its protocol-bound implementation. */
33
+ export const bind = <Protocol extends EntrypointProtocolDeclaration>(
34
+ protocol: Protocol,
35
+ implementation?: ServerBinding<Protocol>,
36
+ options?: EntrypointOptions<object>,
37
+ ): ServerProtocolEntrypoint<Protocol> => {
38
+ const handler = typeof implementation === 'function'
39
+ ? implementation
40
+ : implementation?.bind
41
+ const bound = Object.assign(bindMaterializedEntrypoint(
42
+ materializeEntrypoint(protocol),
43
+ handler,
44
+ options,
45
+ ), { protocol })
46
+
47
+ return bound as ServerProtocolEntrypoint<Protocol>
48
+ }
49
+
50
+ /** Bind a flat declaration collection and pair each protocol with its own implementation. */
51
+ export const bindAll = <Protocol extends EntrypointProtocolDeclaration>(
52
+ declarations: readonly Protocol[],
53
+ implementations: readonly BoundEntrypointHandler<Protocol>[] = [],
54
+ ): ServerProtocolEntrypoint<Protocol>[] => declarations.map(declaration =>
55
+ bind(declaration, implementations.find(implementation => implementation.protocol === declaration)),
56
+ )
@@ -0,0 +1,6 @@
1
+ import type { EntrypointProtocolDeclaration } from '@owlmeans/entrypoint'
2
+ import type { BoundEntrypointHandler, RefedEntrypointHandler } from './types.js'
3
+
4
+ export type ServerBinding<Protocol extends EntrypointProtocolDeclaration> =
5
+ | BoundEntrypointHandler<Protocol>
6
+ | RefedEntrypointHandler
package/src/types.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import type { ServerRouteModel, ServerRouteOptions } from '@owlmeans/server-route'
2
- import type { CommonEntrypoint, EntrypointHandler, CommonEntrypointOptions } from '@owlmeans/entrypoint'
2
+ import type {
3
+ CommonEntrypoint, EntrypointHandler, CommonEntrypointOptions, EntrypointProtocolDeclaration,
4
+ } from '@owlmeans/entrypoint'
3
5
  import type { Service } from '@owlmeans/context'
4
6
 
5
7
  export interface ServerEntrypoint<R> extends CommonEntrypoint {
@@ -25,3 +27,12 @@ export interface EntrypointRef<R> {
25
27
  export interface RefedEntrypointHandler<R = {}> {
26
28
  (ref: EntrypointRef<R>): EntrypointHandler
27
29
  }
30
+
31
+ /** The server-local representation of a shared protocol declaration. */
32
+ export interface ServerProtocolEntrypoint<Protocol extends EntrypointProtocolDeclaration> extends ServerEntrypoint<object> { readonly protocol: Protocol }
33
+
34
+ /** A handler that is inseparable from the protocol whose request it accepts. */
35
+ export interface BoundEntrypointHandler<Protocol extends EntrypointProtocolDeclaration> {
36
+ readonly protocol: Protocol
37
+ bind: RefedEntrypointHandler
38
+ }
package/src/entrypoint.ts DELETED
@@ -1,45 +0,0 @@
1
- import type { ServerRouteModel } from '@owlmeans/server-route'
2
- import type { ServerEntrypoint, EntrypointOptions, EntrypointRef, RefedEntrypointHandler } from './types.js'
3
- import { isEntrypoint, makeCommonEntrypoint } from './utils/entrypoint.js'
4
- import { isServerRouteModel, route } from '@owlmeans/server-route'
5
- import type { CommonEntrypoint } from '@owlmeans/entrypoint'
6
- import type { RouteModel } from '@owlmeans/route'
7
-
8
- export const entrypoint = <R>(
9
- arg: CommonEntrypoint | ServerRouteModel<R> | RouteModel, handler?: RefedEntrypointHandler<R>, opts?: EntrypointOptions<R>
10
- ): ServerEntrypoint<R> => {
11
- const entrypointHandle: EntrypointRef<R> = { ref: undefined }
12
-
13
- let _entrypoint: ServerEntrypoint<R>
14
-
15
- if (isEntrypoint(arg)) {
16
- // Elevating the same alias again is legal, so an intermediate route stays intermediate unless
17
- // this call says otherwise.
18
- const intermediate = opts?.intermediate
19
- ?? (isServerRouteModel(arg.route) ? arg.route.isIntermediate() : false)
20
- const routeModel = route(arg.route, intermediate, opts?.routeOptions)
21
- _entrypoint = arg as ServerEntrypoint<R>
22
- _entrypoint.route = routeModel
23
- _entrypoint.filter = opts?.filter ?? arg.filter
24
- // Elevating adds guards, it never swaps them: what the entrypoint declared still applies.
25
- _entrypoint.guards = [...new Set([...(arg.guards ?? []), ...(opts?.guards ?? [])])]
26
- _entrypoint.gate = opts?.gate ?? arg.gate
27
- _entrypoint.gateParams = opts?.gateParams ?? arg.gateParams
28
- } else if (isServerRouteModel(arg)) {
29
- _entrypoint = makeCommonEntrypoint(arg, { ...opts }) as ServerEntrypoint<R>
30
- _entrypoint.route = arg
31
- } else {
32
- const _route = route(arg, opts?.intermediate ?? false, opts?.routeOptions)
33
- _entrypoint = makeCommonEntrypoint(_route, { ...opts }) as ServerEntrypoint<R>
34
- _entrypoint.route = _route
35
- }
36
-
37
- _entrypoint.fixer = opts?.fixer ?? _entrypoint.fixer
38
- if (handler != null) {
39
- _entrypoint.handle = handler(entrypointHandle)
40
- }
41
-
42
- entrypointHandle.ref = _entrypoint
43
-
44
- return _entrypoint
45
- }
package/src/helper.ts DELETED
@@ -1,40 +0,0 @@
1
- import type { ServerEntrypoint, EntrypointOptions, RefedEntrypointHandler } from './types.js'
2
- import { entrypoint } from './entrypoint.js'
3
- import { createBasicGuard } from './utils/helper.js'
4
- import type { CommonEntrypoint } from '@owlmeans/entrypoint'
5
-
6
- /**
7
- * Replace the entrypoint declared under `alias` with its elevated counterpart. Elevating is
8
- * idempotent — calling it again simply replaces the element once more, and the guards it brings
9
- * are added to the ones already declared.
10
- *
11
- * @throws {SyntaxError} when no entrypoint carries the alias
12
- */
13
- export const elevate = <R>(
14
- entrypoints: (CommonEntrypoint | ServerEntrypoint<R>)[],
15
- alias: string,
16
- handler?: RefedEntrypointHandler<R> | boolean | EntrypointOptions<R>,
17
- opts?: boolean | EntrypointOptions<R>
18
- ): ServerEntrypoint<R>[] => {
19
- const idx = entrypoints.findIndex(({ route }) => route.route.alias === alias)
20
- if (idx === -1) {
21
- throw new SyntaxError(`Entrypoint with alias ${alias} not present`)
22
- }
23
- if (typeof handler === 'boolean') {
24
- opts = handler
25
- handler = undefined
26
- }
27
- if (typeof handler === 'object' && typeof handler !== 'function') {
28
- opts = handler
29
- handler = undefined
30
- }
31
-
32
- entrypoints[idx] = entrypoint(
33
- entrypoints[idx], handler, typeof opts === 'boolean' ? { intermediate: opts } : opts
34
- )
35
-
36
- return entrypoints as ServerEntrypoint<R>[]
37
- }
38
-
39
- export const guard = <R>(guard: string, opts?: EntrypointOptions<R>): EntrypointOptions<R> =>
40
- ({ ...createBasicGuard(guard, opts) })
@@ -1,3 +0,0 @@
1
-
2
- export { entrypoint as makeCommonEntrypoint } from '@owlmeans/entrypoint'
3
- export { isEntrypoint } from '@owlmeans/entrypoint/utils'
@@ -1,2 +0,0 @@
1
-
2
- export { guard as createBasicGuard } from '@owlmeans/entrypoint'