@owlmeans/entrypoint 0.1.18-rc.1 → 0.1.18-rc.11

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
@@ -4,16 +4,21 @@ Entrypoint system — the URL unit abstraction shared between server and client
4
4
 
5
5
  ## Overview
6
6
 
7
- - An **entrypoint** is a URL unit: an alias + path + optional guards/gates/filters
7
+ - An **entrypoint** is a URL unit: an alias + a route declaration + optional guards/gates/filters
8
8
  - On the server, entrypoints become API routes with attached handlers
9
9
  - On the client, entrypoints provide URL generation and navigation
10
10
  - All AJV validation schemas are defined at entrypoint level, keeping data contracts consistent fullstack
11
11
  - Most commonly used via re-exports in `@owlmeans/server-app` or `@owlmeans/client-entrypoint`
12
12
 
13
+ The route declaration an entrypoint carries is immutable: its `path` always stays the segment this
14
+ entrypoint contributes under its parent. Addresses are computed on demand against the context the
15
+ entrypoint is registered in — `path()` walks the parent chain, `mount()` adds the service base,
16
+ `address()` picks host, port and scheme — so one declaration answers correctly on both sides.
17
+
13
18
  ## Installation
14
19
 
15
20
  ```bash
16
- bun add @owlmeans/entrypoint
21
+ bun add @owlmeans/entrypoint@^0.1.18-rc.10
17
22
  ```
18
23
 
19
24
  ## Usage
@@ -24,7 +29,7 @@ Define an entrypoint with body validation and a guard:
24
29
  import { entrypoint, guard, filter, body, params } from '@owlmeans/server-app'
25
30
  import { route } from '@owlmeans/route'
26
31
 
27
- const createStoryModule = entrypoint(
32
+ const createStoryEntrypoint = entrypoint(
28
33
  route('story-create', '/stories', { method: 'POST', parent: 'api' }),
29
34
  filter(body({
30
35
  type: 'object',
@@ -67,14 +72,24 @@ Attaches validation schemas (AJV format) to the entrypoint.
67
72
 
68
73
  Build a `Filter` object with the given AJV schema applied to the corresponding request part.
69
74
 
70
- ### `parent(entrypoint, parentAlias): CommonEntrypoint`
75
+ ### Parentship
71
76
 
72
- Sets a parent-child relationship so child entrypoints inherit guards/gates.
77
+ A child names its parent in the route declaration (`route('story-create', '/stories', { parent: 'api' })`).
78
+ `path()` prefixes the parent's segments, and `getGuards()` / `getGates()` collect the parent's on
79
+ every call — so a guard added to a parent later still applies.
73
80
 
74
81
  ### `provideResponse<T>(): AbstractResponse<T>`
75
82
 
76
83
  Creates a response object for use in non-elevated handlers.
77
84
 
85
+ ### Transport
86
+
87
+ A route's protocol picks the carrier. Register a service under `transportAlias(protocol)` —
88
+ `transport:<protocol>` — implementing `EntrypointTransport { protocol, handle }`, and every call to
89
+ an entrypoint on that protocol goes through it. A consumer writes `ep.call(...)` and never learns
90
+ whether that became an HTTP request, a socket message or a queued job. Without a registered
91
+ transport the call goes over HTTP.
92
+
78
93
  ### `EntrypointOutcome`
79
94
 
80
95
  ```typescript
@@ -85,7 +100,10 @@ enum EntrypointOutcome { Ok, Accepted, Created, Finished }
85
100
 
86
101
  - `AbstractRequest<T>` — request with `params`, `body`, `query`, `headers`, `auth`
87
102
  - `AbstractResponse<T>` — response with `resolve(value, outcome?)` and `reject(error)`
88
- - `CommonEntrypoint` — entrypoint with `getAlias()`, `getPath()`, `getGuards()`, `handle`
103
+ - `CommonEntrypoint` — entrypoint with `alias`, `route`, `handle`, and the context-computed
104
+ `segment()`, `path()`, `mount()`, `service()`, `address()`, `isLocal()`, `parent()`,
105
+ `getGuards()`, `getGates()`
106
+ - `EntrypointTransport` — `{ protocol, handle }`, the service that carries a call for one protocol
89
107
 
90
108
  ## Related Packages
91
109
 
@@ -102,7 +120,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
102
120
  your project's skill store (`.agents/skills/`):
103
121
 
104
122
  ```sh
105
- npx @owlmeans/agent-skills
123
+ npx @owlmeans/agent-skills@^0.1.18-rc.12
106
124
  ```
107
125
 
108
126
  The embedded files are version-matched to this package release. Do not edit them
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/entrypoint",
4
- "version": "0.1.18-rc.0",
5
- "generatedAt": "2026-08-16T22:20:50.515Z",
4
+ "version": "0.1.18-rc.11",
5
+ "generatedAt": "2026-09-04T22:43:25.452Z",
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 — declarative entrypoint/route definitions with entrypoint(), guard(), gate(), filter(), body(), params(), query() builders. Auto-invoked when importing from this package or defining a service entrypoint declaration. Also covers the deprecated @owlmeans/module reexport shim (module() → entrypoint()).
3
+ description: How to use @owlmeans/entrypoint — declarative entrypoint definitions over immutable route declarations, with entrypoint(), guard(), gate(), filter(), body(), params(), query() builders, the 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,27 +8,142 @@ user-invocable: false
8
8
  # @owlmeans/entrypoint
9
9
 
10
10
  **Layer:** Core
11
- **Install:** `"@owlmeans/entrypoint": "^0.1.18-rc.0"` in `dependencies`
11
+ **Install:** `"@owlmeans/entrypoint": "^0.1.18-rc.11"` in `dependencies`
12
+
13
+ An entrypoint is a **URL unit**: an immutable route declaration plus the guards, gates and schemas
14
+ it answers under. It is the single concept an application declares once in a shared package and
15
+ elevates on either side.
12
16
 
13
17
  ## Key Exports
14
18
 
15
19
  | Export | Description |
16
20
  |--------|-------------|
17
- | `entrypoint(...builders)` | Compose an entrypoint declaration from builders |
18
- | `guard(alias, ...gates)` | Attach a security guard |
19
- | `gate(alias, scopes[])` | Define an auth gate (used inside a guard) |
20
- | `filter(...validators)` | Attach request validators |
21
- | `body(Schema)` | AJV body validator |
22
- | `params(Schema)` | URL params validator |
23
- | `query(Schema)` | Query string validator |
24
- | `ClientEntrypoint<T>` types | Resolved entrypoint type used for `ctx.entrypoint<...>(alias).call(...)` |
21
+ | `entrypoint(route, opts?)` | Declare an entrypoint on a route model |
22
+ | `guard(alias, opts?)` | Require a guard; returns options, so it wraps rather than takes them |
23
+ | `gate(alias, params, opts?)` | Require a gate; passed as the `opts` of `guard(...)` |
24
+ | `filter(filter, opts?)` | Attach request validators |
25
+ | `body(Schema)` / `params(Schema)` / `query(Schema)` / `headers(Schema)` / `response(Schema, code?)` | AJV validators composed into a `Filter` |
26
+ | `CommonEntrypoint` | The entrypoint interface — declaration, guards/gates, address accessors |
27
+ | `AbstractRequest` / `AbstractResponse` | The request and reply shapes every handler sees |
28
+ | `ResolvedEntity` | `req.entity` — the organization entity's `{ id, slug, iamKey }` |
29
+ | `provideResponse(original?)` | Build a reply object a handler resolves or rejects |
30
+ | `EntrypointHandler` | What a handler implements: `(req, res) => value` |
31
+ | `Filter` | The composed validator set: `{ body, params, query, headers, response }` |
32
+ | `GuardService` / `GateService` | What a guard and a gate implement |
25
33
  | `EntrypointOutcome` | Enum: Ok, Accepted, Created, Finished |
26
- | Constants | Built-in entrypoint aliases |
34
+ | `EntrypointTransport` | `{ protocol, handle }` — a carrier bound to a route protocol |
35
+ | `transportAlias(protocol?)` | The service alias a transport registers under (`transport:<protocol>`) |
36
+
37
+ `guard`, `gate` and `filter` are **options-object combinators, not variadic composers**. Each
38
+ returns a `CommonEntrypointOptions` and takes the next one as its final argument, so they nest:
39
+
40
+ ```typescript
41
+ entrypoint(
42
+ route(app.api.item.remove, '/:id', { parent: app.api.item, method: RouteMethod.DELETE }),
43
+ guard(DEFAULT_GUARD, gate(OIDC_GATE, ['item--delete@id']))
44
+ )
45
+ ```
46
+
47
+ Guards and gates are **inherited by child entrypoints** and enforced by the framework before a
48
+ handler runs — a handler that re-checks them is duplicating an enforced rule, and is wrong even
49
+ when it agrees.
50
+
51
+ `sticky: true` in the options exempts a frontend entrypoint from the **service** filter the client
52
+ router applies while building its entrypoint tree: without it, only entrypoints that name no service
53
+ or name the context's own service are attached, so a route belonging to another service (an
54
+ authentication dispatcher, say) needs it to reach the router at all. It changes nothing else — not
55
+ the frontend-only restriction, not route matching — and defaults to `false`.
27
56
 
28
57
  ## Subpath Exports
29
58
 
30
59
  - `./utils` — entrypoint construction helpers (`isEntrypoint`, `CreateEntrypointSignature`)
31
60
 
61
+ ## Declaration and model
62
+
63
+ The `RouteDeclaration` an entrypoint carries is plain, immutable data: its `path` is the **segment**
64
+ this entrypoint contributes under its parent, and nothing rewrites it. `RouteModel` only wraps that
65
+ declaration. Every address question is therefore a question about the declaration asked **against
66
+ the context that asks it** — computed on demand, never stored — so the same declaration answers one
67
+ way in a server and another in a client without being touched.
68
+
69
+ | Accessor | Answers |
70
+ |----------|---------|
71
+ | `segment()` | The segment declared under the parent |
72
+ | `path()` | Every ancestor's segment, then this one |
73
+ | `mount()` | `base` + `path()` — what a server registers and a client requests |
74
+ | `service()` | The resolved service route this entrypoint answers on |
75
+ | `address()` | `{ host, port, base, secure, protocol }` — where it actually answers |
76
+ | `isLocal()` | Does it belong to the service the asking context IS? |
77
+ | `parent()` | The parent entrypoint, or `null` |
78
+ | `getGuards()` | Own guards plus every ancestor's, deduped |
79
+ | `getGates()` | Own gate plus every ancestor's, as `[gate, params]` |
80
+
81
+ `getGuards()` and `getGates()` walk the chain afresh on every call and are never memoised: a guard
82
+ attached to an ancestor after this entrypoint was first asked still has to count.
83
+
84
+ ## What a handler receives
85
+
86
+ `AbstractRequest` carries `params`, `body`, `query`, `headers` and `path`, plus `auth` once a guard
87
+ has run. `req.entity` is the organization entity resolved from `auth.entitySlug` **once**, at the
88
+ server boundary: `entity.id` is the stable value to key records, grants and generated names by,
89
+ `entity.slug` is the renameable name a person reads, and `entity.iamKey` is the frozen identifier
90
+ external systems already know the organization under. It is absent when no resolver is registered,
91
+ so read it defensively rather than assuming it.
92
+
93
+ `timeout` and `signal` on a request are forwarded to the transport, so a caller can bound or abort a
94
+ single round trip.
95
+
96
+ ## Calling an entrypoint
97
+
98
+ Three explicit verbs, so the caller says which answer it wants:
99
+
100
+ ```typescript
101
+ const project = await ep.call({ params: { id } }) // the VALUE; the reply error is thrown
102
+ const { value, outcome } = await ep.invoke({ body }) // value AND outcome
103
+ const href = await ep.url({ params: { id } }, { absolute: true }) // the URL string
104
+ ```
105
+
106
+ Use `invoke` only where the outcome decides what happens next; `call` covers everything else. An
107
+ entrypoint that **renders a screen** is addressed by URL and never over the wire — it throws from
108
+ `call()`/`invoke()` telling the caller to use `url()`.
109
+
110
+ The three verbs sit on the callable entrypoint that `@owlmeans/client-entrypoint` produces; the
111
+ declaration built here is what they address.
112
+
113
+ ## Elevation
114
+
115
+ `elevate` replaces the declaration in the entrypoint list with its elevated counterpart, so it is
116
+ **idempotent**: elevating the same alias again simply replaces the element once more. Guards passed
117
+ at elevation are **unioned** with the ones the entrypoint declared — elevating adds guards, it never
118
+ swaps them. Server-side elevation lives in `@owlmeans/server-entrypoint`, client-side callability is
119
+ an explicit opt-in through `@owlmeans/client-entrypoint`.
120
+
121
+ ## Transport seam
122
+
123
+ A route names the protocol it answers on, and a protocol may be carried by something other than
124
+ HTTP. A service registered under `transportAlias(protocol)` implementing `EntrypointTransport` takes
125
+ the call, so a consumer writes `ep.call(...)` and never learns whether that became an HTTP request,
126
+ a socket message or a queued job. Bind nothing and the call goes over HTTP.
127
+
128
+ ```typescript
129
+ import { transportAlias } from '@owlmeans/entrypoint'
130
+ import type { EntrypointTransport } from '@owlmeans/entrypoint'
131
+ import { RouteProtocols } from '@owlmeans/route'
132
+ import { createService } from '@owlmeans/context'
133
+
134
+ const transport = createService<EntrypointTransport>(transportAlias(RouteProtocols.SOCKET), {
135
+ protocol: RouteProtocols.SOCKET,
136
+ handle: async (req, res) => { /* carry the call, resolve or reject res */ }
137
+ }, service => async () => { service.initialized = true })
138
+
139
+ context.registerService(transport)
140
+ ```
141
+
142
+ `@owlmeans/queue` is the worked example: `appendQueueTransport(context)` binds
143
+ `RouteProtocols.QUEUE`, and a declaration built with `job()` instead of `backend()` is then carried
144
+ as a broker job. Nothing at the call site changes — which is the point of putting the protocol on
145
+ the route rather than at the call.
146
+
32
147
  ## Usage
33
148
 
34
149
  Define entrypoints in a shared `common` package, then `elevate()` them with handlers in server/web packages:
@@ -40,7 +155,7 @@ import { DEFAULT_GUARD } from '@owlmeans/auth-common'
40
155
  import { OIDC_GATE } from '@owlmeans/oidc'
41
156
  import { CreateProjectSchema } from './schemas.js'
42
157
 
43
- export const managerModules = [
158
+ export const managerEntrypoints = [
44
159
  entrypoint(
45
160
  route(manager.back.account.base, '/account'),
46
161
  guard(DEFAULT_GUARD, gate(OIDC_GATE, [`my-service-account-{entity}`]))
@@ -57,6 +172,12 @@ export const managerModules = [
57
172
 
58
173
  ## Depends On
59
174
 
60
- - `@owlmeans/route` — `route()`, `RouteMethod`
61
- - `@owlmeans/auth-common` — guard aliases (`DEFAULT_GUARD`)
62
- - `@owlmeans/error`, `@owlmeans/i18n`
175
+ - `@owlmeans/route` — `RouteModel`, `RouteAddress`, `RouteProtocols`, and the address helpers under `/utils`
176
+ - `@owlmeans/context` — `appendContextual`, and the `BasicEntrypoint` / service shapes an entrypoint and its guards, gates and transports register as
177
+ - `@owlmeans/auth` — `Auth`, the type behind `req.auth`
178
+ - `ajv` — the JSON-schema types `body()` / `params()` / `query()` / `headers()` / `response()` are declared with
179
+
180
+ Guard and gate **aliases** are not declared here: an entrypoint names a guard by string, and the
181
+ package that implements the guard owns the constant (`DEFAULT_GUARD` comes from
182
+ `@owlmeans/auth-common`, `OIDC_GATE` from `@owlmeans/oidc`). That is what keeps this package free of
183
+ any dependency on the auth stack.
package/build/consts.d.ts CHANGED
@@ -4,4 +4,9 @@ export declare enum EntrypointOutcome {
4
4
  Created = "created",
5
5
  Finished = "finished"
6
6
  }
7
+ /**
8
+ * Service alias a transport registers under. The default protocol is the web one, so an application
9
+ * that binds nothing keeps talking HTTP.
10
+ */
11
+ export declare const transportAlias: (protocol?: string) => string;
7
12
  //# sourceMappingURL=consts.d.ts.map
@@ -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"}
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 CHANGED
@@ -5,4 +5,9 @@ export var EntrypointOutcome;
5
5
  EntrypointOutcome["Created"] = "created";
6
6
  EntrypointOutcome["Finished"] = "finished";
7
7
  })(EntrypointOutcome || (EntrypointOutcome = {}));
8
+ /**
9
+ * Service alias a transport registers under. The default protocol is the web one, so an application
10
+ * that binds nothing keeps talking HTTP.
11
+ */
12
+ export const transportAlias = (protocol = 'http') => `transport:${protocol}`;
8
13
  //# sourceMappingURL=consts.js.map
@@ -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"}
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,5 +1,4 @@
1
1
  import type { CommonEntrypoint } from './types.js';
2
2
  import type { CreateEntrypointSignature } from './utils/types.js';
3
3
  export declare const entrypoint: CreateEntrypointSignature<CommonEntrypoint>;
4
- export declare const parent: <T extends CommonEntrypoint | CommonEntrypoint[]>(ep: T, aliasOrParent: string, _parent?: string) => T;
5
4
  //# 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,YAAY,CAAA;AAElD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAA;AAEjE,eAAO,MAAM,UAAU,EAAE,yBAAyB,CAAC,gBAAgB,CAqFlE,CAAA;AAED,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,EAAE,MAAM,CAAC,iBAAiB,MAAM,YAAY,MAAM,KAAG,CAcxH,CAAA"}
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"}
@@ -1,61 +1,49 @@
1
1
  import { appendContextual } from '@owlmeans/context';
2
+ import { isLocalRoute, resolveAddress, resolveMount, resolvePath, resolveService } from '@owlmeans/route/utils';
2
3
  export const entrypoint = (route, opts) => {
3
- let guards = null;
4
- let gates = null;
5
4
  const ep = appendContextual(route.route.alias, {
6
5
  _entrypoint: true,
7
- _module: true,
8
6
  sticky: false,
9
7
  route,
10
- getAlias: () => ep.route.route.alias,
11
- getPath: () => ep.route.route.path,
12
- getParentAlias: () => ep.route.route.parent ?? null,
13
- hasParent: () => ep.getParentAlias() != null,
14
- resolve: async () => {
15
- if (ep.ctx == null) {
16
- throw new SyntaxError(`Entrypoint has no context yet - ${ep.getAlias()}`);
17
- }
18
- await ep.route.resolve(ep.ctx);
19
- return ep;
20
- },
21
- getParent: () => {
22
- const parentAlias = ep.getParentAlias();
23
- if (parentAlias == null) {
24
- throw new SyntaxError(`Entrypoint has no parent - ${ep.getAlias()}`);
25
- }
26
- if (ep.ctx == null) {
27
- throw new SyntaxError(`Entrypoint has no context yet - ${ep.getAlias()}`);
28
- }
29
- return ep.ctx.entrypoint(parentAlias);
30
- },
31
- setService: service => {
32
- if (ep.route.route.resolved) {
33
- throw new SyntaxError(`Cannot update a resolved entrypoint - ${ep.getAlias()}`);
34
- }
35
- ep.route.route.service = service;
36
- },
8
+ segment: () => ep.route.route.path,
9
+ path: () => resolvePath(ep.assertCtx(), ep.route.route),
10
+ mount: () => resolveMount(ep.assertCtx(), ep.route.route),
11
+ service: () => resolveService(ep.assertCtx(), ep.route.route),
12
+ address: () => resolveAddress(ep.assertCtx(), ep.route.route),
13
+ isLocal: () => isLocalRoute(ep.assertCtx(), ep.route.route),
14
+ parent: () => ep.route.route.parent == null ? null
15
+ : ep.assertCtx().entrypoint(ep.route.route.parent),
16
+ // Walked afresh on every call: a guard attached to an ancestor after this entrypoint was first
17
+ // asked still has to count.
37
18
  getGuards: () => {
38
- if (guards != null) {
39
- return guards;
40
- }
41
- guards = ep.guards ?? [];
42
- if (ep.hasParent()) {
43
- guards.push(...ep.getParent().getGuards().filter(guard => !guards?.includes(guard)));
19
+ const guards = [...ep.guards ?? []];
20
+ const parent = ep.parent();
21
+ if (parent != null) {
22
+ guards.push(...parent.getGuards().filter(guard => !guards.includes(guard)));
44
23
  }
45
24
  return guards;
46
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
+ */
47
38
  getGates: () => {
48
- if (gates != null) {
49
- return gates;
50
- }
51
- gates = ep.gate != null ? [[
39
+ const gates = ep.gate != null ? [[
52
40
  ep.gate, ep.gateParams == null
53
41
  ? [] : Array.isArray(ep.gateParams)
54
42
  ? ep.gateParams : [ep.gateParams]
55
43
  ]] : [];
56
- if (ep.hasParent()) {
57
- gates.push(...ep.getParent().getGates()
58
- .filter(([gate]) => !gates?.some(([g]) => g === gate)));
44
+ const parent = ep.parent();
45
+ if (parent != null) {
46
+ gates.push(...parent.getGates().filter(([gate]) => !gates.some(([g]) => g === gate)));
59
47
  }
60
48
  return gates;
61
49
  },
@@ -63,18 +51,4 @@ export const entrypoint = (route, opts) => {
63
51
  });
64
52
  return ep;
65
53
  };
66
- export const parent = (ep, aliasOrParent, _parent) => {
67
- if (Array.isArray(ep)) {
68
- if (_parent == null) {
69
- throw SyntaxError('Elevating parent requires parent name to be specified');
70
- }
71
- ep = ep.find(e => e.route.route.alias === aliasOrParent);
72
- if (ep == null) {
73
- throw SyntaxError(`Entrypoint not found ${aliasOrParent}`);
74
- }
75
- return parent(ep, _parent);
76
- }
77
- ep.route.route.parent = aliasOrParent;
78
- return ep;
79
- };
80
54
  //# sourceMappingURL=entrypoint.js.map
@@ -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/helper.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- import { Filter, CommonEntrypointOptions, AbstractResponse, CommonEntrypoint } from './types.js';
1
+ import { Filter, CommonEntrypointOptions, AbstractResponse } from './types.js';
2
2
  export declare const filter: (filter: Filter, opts?: CommonEntrypointOptions) => CommonEntrypointOptions;
3
3
  export declare const guard: (guard: string, opts?: CommonEntrypointOptions) => CommonEntrypointOptions;
4
4
  export declare const gate: (gate: string, params: string | string[], opts?: CommonEntrypointOptions) => CommonEntrypointOptions;
5
5
  export declare const provideResponse: <T>(originalResponse?: unknown) => AbstractResponse<T>;
6
- export declare const clone: <M extends CommonEntrypoint>(entrypoints: M[], from: string, to: string, service: string) => void;
7
6
  //# sourceMappingURL=helper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAGhG,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;AAED,eAAO,MAAM,KAAK,GAAI,CAAC,SAAS,gBAAgB,eAAe,CAAC,EAAE,QAAQ,MAAM,MAAM,MAAM,WAAW,MAAM,SAO5G,CAAA"}
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/helper.js CHANGED
@@ -1,5 +1,3 @@
1
- import { route } from '@owlmeans/route';
2
- import { entrypoint } from './entrypoint.js';
3
1
  export const filter = (filter, opts) => ({ filter, ...opts });
4
2
  export const guard = (guard, opts) => ({ ...opts, guards: [...new Set([guard, ...(opts?.guards ?? [])])] });
5
3
  export const gate = (gate, params, opts) => ({ ...opts, gate, gateParams: params });
@@ -16,11 +14,4 @@ export const provideResponse = (originalResponse) => {
16
14
  };
17
15
  return handler;
18
16
  };
19
- export const clone = (entrypoints, from, to, service) => {
20
- const source = entrypoints.find(e => e.alias === from);
21
- if (source?.route.route != null) {
22
- const _route = { ...source.route.route, service, resolved: false, alias: to };
23
- entrypoints.push(entrypoint(route(to, _route.path, _route)));
24
- }
25
- };
26
17
  //# sourceMappingURL=helper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAEvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,MAAc,EAAE,IAA8B,EAA2B,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,CAAA;AAExH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,IAA8B,EAA2B,EAAE,CAC9F,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;AAEvE,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,MAAyB,EAAE,IAA8B,EAA2B,EAAE,CACvH,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAA;AAEzC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAI,gBAA0B,EAAuB,EAAE;IACpF,MAAM,OAAO,GAAwB;QACnC,gBAAgB,EAAE,gBAAgB;QAElC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAC1B,OAAO,CAAC,KAAK,GAAG,KAAK,CAAA;YACrB,OAAO,CAAC,OAAO,GAAG,OAAO,CAAA;QAC3B,CAAC;QAED,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAChB,OAAO,CAAC,KAAK,GAAG,KAAK,CAAA;QACvB,CAAC;KACF,CAAA;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAA6B,WAAgB,EAAE,IAAY,EAAE,EAAU,EAAE,OAAe,EAAE,EAAE;IAC/G,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAA;IAEtD,IAAI,MAAM,EAAE,KAAK,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;QAC7E,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAM,CAAC,CAAA;IACnE,CAAC;AACH,CAAC,CAAA"}
1
+ {"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,MAAc,EAAE,IAA8B,EAA2B,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,CAAA;AAExH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,IAA8B,EAA2B,EAAE,CAC9F,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;AAEvE,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,MAAyB,EAAE,IAA8B,EAA2B,EAAE,CACvH,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAA;AAEzC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAI,gBAA0B,EAAuB,EAAE;IACpF,MAAM,OAAO,GAAwB;QACnC,gBAAgB,EAAE,gBAAgB;QAElC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAC1B,OAAO,CAAC,KAAK,GAAG,KAAK,CAAA;YACrB,OAAO,CAAC,OAAO,GAAG,OAAO,CAAA;QAC3B,CAAC;QAED,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAChB,OAAO,CAAC,KAAK,GAAG,KAAK,CAAA;QACvB,CAAC;KACF,CAAA;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
package/build/types.d.ts CHANGED
@@ -1,28 +1,42 @@
1
- import type { CommonRouteModel } from '@owlmeans/route';
1
+ import type { ResolvedServiceRoute, RouteAddress, RouteModel, RouteProtocols } from '@owlmeans/route';
2
2
  import type { InitializedService, LazyService, BasicEntrypoint } from '@owlmeans/context';
3
3
  import type { AnySchemaObject } from 'ajv';
4
4
  import type { EntrypointOutcome } from './consts.js';
5
5
  import type { Auth } from '@owlmeans/auth';
6
+ /**
7
+ * A URL unit: an immutable route declaration plus what guards, gates and schemas it answers under.
8
+ *
9
+ * Nothing here is rewritten once declared. Every address question — segment, path, mount, service,
10
+ * host — is a question about the declaration asked against the context the entrypoint is registered
11
+ * in, so the same declaration answers differently in a client and in a server without being touched.
12
+ */
6
13
  export interface CommonEntrypoint extends BasicEntrypoint {
7
- route: CommonRouteModel;
14
+ route: RouteModel;
8
15
  /**
9
16
  * @property {boolean} - if true — router attaches this entrypoint unconditionally
10
17
  * @default false
11
18
  */
12
19
  sticky: boolean;
13
- filter?: Filter;
20
+ /** The guards declared on this entrypoint alone — see `getGuards()` for the inherited set. */
14
21
  guards?: string[];
15
22
  gate?: string;
16
23
  gateParams?: string | string[];
24
+ filter?: Filter;
17
25
  handle?: EntrypointHandler;
18
- getAlias: () => string;
19
- getPath: () => string;
20
- getParentAlias: () => string | null;
21
- hasParent: () => boolean;
22
- resolve: <M extends CommonEntrypoint>() => Promise<M>;
23
- getParent: <M extends CommonEntrypoint>() => M;
24
- setService: (service: string) => void;
26
+ /** The segment this entrypoint contributes under its parent. */
27
+ segment: () => string;
28
+ /** Every ancestor's segment, then this one. */
29
+ path: () => string;
30
+ /** `base` + `path()` — what a server mounts and a client requests. */
31
+ mount: () => string;
32
+ service: () => ResolvedServiceRoute;
33
+ address: () => RouteAddress;
34
+ /** Does this entrypoint belong to the service its context IS? */
35
+ isLocal: () => boolean;
36
+ parent: () => CommonEntrypoint | null;
37
+ /** Own guards and every ancestor's, deduped. Recomputed on each call. */
25
38
  getGuards: () => string[];
39
+ /** Own gate and every ancestor's, as `[gate, params]`. Recomputed on each call. */
26
40
  getGates: () => [string, string[]][];
27
41
  }
28
42
  export interface CommonEntrypointOptions extends Partial<CommonEntrypoint> {
@@ -39,6 +53,17 @@ export interface EntrypointAssert {
39
53
  export interface AbstractRequest<T extends {} = {}> {
40
54
  alias: string;
41
55
  auth?: Auth;
56
+ /**
57
+ * The organization entity this request acts for, resolved from `auth.entitySlug` once, at the
58
+ * server boundary.
59
+ *
60
+ * The slug on the token is renameable and therefore unusable as a key; `entity.id` is the stable
61
+ * value that records, grants and minted infrastructure names are keyed by. Resolving it here —
62
+ * rather than in each handler — is what keeps a rename from meaning a sweep of every call site,
63
+ * and it is absent whenever no resolver is registered (an implementation that has no notion of
64
+ * an organization store), so consumers must handle that rather than assume it.
65
+ */
66
+ entity?: ResolvedEntity;
42
67
  params: Record<string, string | number | undefined | null> | Partial<T>;
43
68
  body?: Record<string, any> | Partial<T>;
44
69
  headers: Record<string, string[] | string | undefined>;
@@ -53,6 +78,20 @@ export interface AbstractRequest<T extends {} = {}> {
53
78
  timeout?: number;
54
79
  signal?: AbortSignal;
55
80
  }
81
+ /**
82
+ * An organization entity as request handlers see it: the stable id to key by, the current slug to
83
+ * compose user-facing names from, and the frozen key that external systems already know it under.
84
+ */
85
+ export interface ResolvedEntity {
86
+ id: string;
87
+ slug: string;
88
+ /**
89
+ * The identifier this organization is known by in systems whose names cannot be rewritten —
90
+ * an IAM realm, an object-storage prefix, a cluster object. Minted once and never recomputed,
91
+ * so it stays valid across every later rename.
92
+ */
93
+ iamKey: string;
94
+ }
56
95
  export interface AbstractResponse<T> {
57
96
  responseProvider?: any;
58
97
  value?: T;
@@ -80,4 +119,15 @@ export interface Filter {
80
119
  response?: AnySchemaObject;
81
120
  headers?: AnySchemaObject;
82
121
  }
122
+ /**
123
+ * How a call to an entrypoint is actually carried.
124
+ *
125
+ * The transport is chosen by the route's protocol, so a consumer always writes `ep.call(...)` and
126
+ * never learns whether that became an HTTP request, a socket message or a queued job. An
127
+ * application binds a protocol by registering a transport service under `transportAlias(protocol)`.
128
+ */
129
+ export interface EntrypointTransport extends InitializedService {
130
+ readonly protocol: RouteProtocols;
131
+ handle: EntrypointHandler;
132
+ }
83
133
  //# 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,MAAM,iBAAiB,CAAA;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACzF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,KAAK,CAAA;AAC1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAE1C,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,KAAK,EAAE,gBAAgB,CAAA;IACvB;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC9B,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,QAAQ,EAAE,MAAM,MAAM,CAAA;IACtB,OAAO,EAAE,MAAM,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,MAAM,GAAG,IAAI,CAAA;IACnC,SAAS,EAAE,MAAM,OAAO,CAAA;IACxB,OAAO,EAAE,CAAC,CAAC,SAAS,gBAAgB,OAAO,OAAO,CAAC,CAAC,CAAC,CAAA;IACrD,SAAS,EAAE,CAAC,CAAC,SAAS,gBAAgB,OAAO,CAAC,CAAA;IAC9C,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,MAAM,EAAE,CAAA;IACzB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,CAAA;CACrC;AAED,MAAM,WAAW,uBAAwB,SAAQ,OAAO,CAAC,gBAAgB,CAAC;CAAI;AAE9E,MAAM,WAAW,eAAe;IAC9B,CAAC,CAAC,SAAS,eAAe,EAAE,CAAC,SAAS,gBAAgB,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAC/F;AAED,MAAM,WAAW,iBAAiB;IAChC,CACE,CAAC,EAAE,CAAC,SAAS,eAAe,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,EACxD,CAAC,SAAS,gBAAgB,CAAC,GAAG,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,EACvD,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,CAAC,CAAC,SAAS,eAAe,EAAE,CAAC,SAAS,gBAAgB,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9G;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,EAAE,GAAG,EAAE;IAChD,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACvC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC,CAAA;IACtD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACtE,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,GAAG,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAGlB,OAAO,CAAC,EAAE,MAAM,CAAA;IAGhB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,gBAAgB,CAAC,EAAE,GAAG,CAAA;IACtB,KAAK,CAAC,EAAE,CAAC,CAAC;IACV,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,iBAAiB,KAAK,IAAI,CAAA;IACxD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CAC/B;AAED,MAAM,WAAW,YAAa,SAAQ,kBAAkB;IAEtD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAEzE,KAAK,EAAE,eAAe,CAAA;IACtB,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAED,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C;;OAEG;IACH,MAAM,EAAE,gBAAgB,CAAA;CACzB;AAED,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,MAAM,CAAC,EAAE,eAAe,CAAA;IACxB,IAAI,CAAC,EAAE,eAAe,CAAA;IACtB,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,OAAO,CAAC,EAAE,eAAe,CAAA;CAC1B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.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,QAAS,MAAM,KAAG,GAAG,IAAI,gBACR,CAAA"}
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"}
@@ -1,2 +1,2 @@
1
- export const isEntrypoint = (obj) => '_entrypoint' in obj || '_module' in obj;
1
+ export const isEntrypoint = (obj) => '_entrypoint' in obj;
2
2
  //# sourceMappingURL=entrypoint.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"entrypoint.js","sourceRoot":"","sources":["../../src/utils/entrypoint.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAW,EAA2B,EAAE,CACnE,aAAa,IAAI,GAAG,IAAI,SAAS,IAAI,GAAG,CAAA"}
1
+ {"version":3,"file":"entrypoint.js","sourceRoot":"","sources":["../../src/utils/entrypoint.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAW,EAA2B,EAAE,CACnE,aAAa,IAAI,GAAG,CAAA"}
@@ -1,6 +1,6 @@
1
- import { CommonRouteModel } from '@owlmeans/route';
1
+ import { RouteModel } from '@owlmeans/route';
2
2
  import { CommonEntrypointOptions } from '../types.js';
3
3
  export interface CreateEntrypointSignature<M> {
4
- (route: CommonRouteModel, opts?: CommonEntrypointOptions): M;
4
+ (route: RouteModel, opts?: CommonEntrypointOptions): M;
5
5
  }
6
6
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAErD,MAAM,WAAW,yBAAyB,CAAC,CAAC;IAC1C,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,uBAAuB,GAAG,CAAC,CAAC;CAC9D"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAErD,MAAM,WAAW,yBAAyB,CAAC,CAAC;IAC1C,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,uBAAuB,GAAG,CAAC,CAAC;CACxD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/entrypoint",
3
- "version": "0.1.18-rc.1",
3
+ "version": "0.1.18-rc.11",
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.1",
32
- "@owlmeans/context": "^0.1.18-rc.1",
33
- "@owlmeans/route": "^0.1.18-rc.1",
31
+ "@owlmeans/auth": "^0.1.18-rc.9",
32
+ "@owlmeans/context": "^0.1.18-rc.8",
33
+ "@owlmeans/route": "^0.1.18-rc.9",
34
34
  "ajv": "^8.17.1"
35
35
  },
36
36
  "devDependencies": {
package/src/consts.ts CHANGED
@@ -5,3 +5,9 @@ export enum EntrypointOutcome {
5
5
  Created = 'created',
6
6
  Finished = 'finished'
7
7
  }
8
+
9
+ /**
10
+ * Service alias a transport registers under. The default protocol is the web one, so an application
11
+ * that binds nothing keeps talking HTTP.
12
+ */
13
+ export const transportAlias = (protocol: string = 'http') => `transport:${protocol}`
package/src/entrypoint.ts CHANGED
@@ -1,83 +1,67 @@
1
1
  import type { CommonEntrypoint } from './types.js'
2
2
  import { appendContextual } from '@owlmeans/context'
3
+ import {
4
+ isLocalRoute, resolveAddress, resolveMount, resolvePath, resolveService
5
+ } from '@owlmeans/route/utils'
3
6
  import type { CreateEntrypointSignature } from './utils/types.js'
4
7
 
5
8
  export const entrypoint: CreateEntrypointSignature<CommonEntrypoint> = (route, opts) => {
6
- let guards: string[] | null = null
7
- let gates: [string, string[]][] | null = null
8
9
  const ep: CommonEntrypoint = appendContextual<CommonEntrypoint>(route.route.alias, {
9
10
  _entrypoint: true,
10
- _module: true,
11
11
 
12
12
  sticky: false,
13
13
 
14
14
  route,
15
15
 
16
- getAlias: () => ep.route.route.alias,
17
- getPath: () => ep.route.route.path,
18
- getParentAlias: () => ep.route.route.parent ?? null,
19
- hasParent: () => ep.getParentAlias() != null,
16
+ segment: () => ep.route.route.path,
20
17
 
21
- resolve: async <M extends CommonEntrypoint>() => {
22
- if (ep.ctx == null) {
23
- throw new SyntaxError(`Entrypoint has no context yet - ${ep.getAlias()}`)
24
- }
18
+ path: () => resolvePath(ep.assertCtx(), ep.route.route),
25
19
 
26
- await ep.route.resolve(ep.ctx)
20
+ mount: () => resolveMount(ep.assertCtx(), ep.route.route),
27
21
 
28
- return ep as M
29
- },
22
+ service: () => resolveService(ep.assertCtx(), ep.route.route),
30
23
 
31
- getParent: () => {
32
- const parentAlias = ep.getParentAlias()
33
- if (parentAlias == null) {
34
- throw new SyntaxError(`Entrypoint has no parent - ${ep.getAlias()}`)
35
- }
36
- if (ep.ctx == null) {
37
- throw new SyntaxError(`Entrypoint has no context yet - ${ep.getAlias()}`)
38
- }
24
+ address: () => resolveAddress(ep.assertCtx(), ep.route.route),
39
25
 
40
- return ep.ctx.entrypoint(parentAlias)
41
- },
26
+ isLocal: () => isLocalRoute(ep.assertCtx(), ep.route.route),
42
27
 
43
- setService: service => {
44
- if (ep.route.route.resolved) {
45
- throw new SyntaxError(`Cannot update a resolved entrypoint - ${ep.getAlias()}`)
46
- }
47
- ep.route.route.service = service
48
- },
28
+ parent: () => ep.route.route.parent == null ? null
29
+ : ep.assertCtx().entrypoint<CommonEntrypoint>(ep.route.route.parent),
49
30
 
31
+ // Walked afresh on every call: a guard attached to an ancestor after this entrypoint was first
32
+ // asked still has to count.
50
33
  getGuards: () => {
51
- if (guards != null) {
52
- return guards
53
- }
54
- guards = ep.guards ?? []
55
-
56
- if (ep.hasParent()) {
57
- guards.push(
58
- ...ep.getParent().getGuards().filter(guard => !guards?.includes(guard))
59
- )
34
+ const guards = [...ep.guards ?? []]
35
+ const parent = ep.parent()
36
+ if (parent != null) {
37
+ guards.push(...parent.getGuards().filter(guard => !guards.includes(guard)))
60
38
  }
61
39
 
62
40
  return guards
63
41
  },
64
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
+ */
65
55
  getGates: () => {
66
- if (gates != null) {
67
- return gates
68
- }
69
-
70
- gates = ep.gate != null ? [[
56
+ const gates: [string, string[]][] = ep.gate != null ? [[
71
57
  ep.gate, ep.gateParams == null
72
58
  ? [] : Array.isArray(ep.gateParams)
73
59
  ? ep.gateParams : [ep.gateParams]
74
60
  ]] : []
75
61
 
76
- if (ep.hasParent()) {
77
- gates.push(
78
- ...ep.getParent().getGates()
79
- .filter(([gate]) => !gates?.some(([g]) => g === gate))
80
- )
62
+ const parent = ep.parent()
63
+ if (parent != null) {
64
+ gates.push(...parent.getGates().filter(([gate]) => !gates.some(([g]) => g === gate)))
81
65
  }
82
66
 
83
67
  return gates
@@ -88,19 +72,3 @@ export const entrypoint: CreateEntrypointSignature<CommonEntrypoint> = (route, o
88
72
 
89
73
  return ep
90
74
  }
91
-
92
- export const parent = <T extends CommonEntrypoint | CommonEntrypoint[]>(ep: T, aliasOrParent: string, _parent?: string): T => {
93
- if (Array.isArray(ep)) {
94
- if (_parent == null) {
95
- throw SyntaxError('Elevating parent requires parent name to be specified')
96
- }
97
- ep = ep.find(e => e.route.route.alias === aliasOrParent) as T
98
- if (ep == null) {
99
- throw SyntaxError(`Entrypoint not found ${aliasOrParent}`)
100
- }
101
- return parent(ep, _parent)
102
- }
103
- ep.route.route.parent = aliasOrParent
104
-
105
- return ep
106
- }
package/src/helper.ts CHANGED
@@ -1,6 +1,4 @@
1
- import { route } from '@owlmeans/route'
2
- import { Filter, CommonEntrypointOptions, AbstractResponse, CommonEntrypoint } from './types.js'
3
- import { entrypoint } from './entrypoint.js'
1
+ import { Filter, CommonEntrypointOptions, AbstractResponse } from './types.js'
4
2
 
5
3
  export const filter = (filter: Filter, opts?: CommonEntrypointOptions): CommonEntrypointOptions => ({ filter, ...opts })
6
4
 
@@ -26,12 +24,3 @@ export const provideResponse = <T>(originalResponse?: unknown): AbstractResponse
26
24
 
27
25
  return handler
28
26
  }
29
-
30
- export const clone = <M extends CommonEntrypoint>(entrypoints: M[], from: string, to: string, service: string) => {
31
- const source = entrypoints.find(e => e.alias === from)
32
-
33
- if (source?.route.route != null) {
34
- const _route = { ...source.route.route, service, resolved: false, alias: to }
35
- entrypoints.push(entrypoint(route(to, _route.path, _route)) as M)
36
- }
37
- }
package/src/types.ts CHANGED
@@ -1,29 +1,44 @@
1
- import type { CommonRouteModel } from '@owlmeans/route'
1
+ import type { ResolvedServiceRoute, RouteAddress, RouteModel, RouteProtocols } from '@owlmeans/route'
2
2
  import type { InitializedService, LazyService, BasicEntrypoint } from '@owlmeans/context'
3
3
  import type { AnySchemaObject } from 'ajv'
4
4
  import type { EntrypointOutcome } from './consts.js'
5
5
  import type { Auth } from '@owlmeans/auth'
6
6
 
7
+ /**
8
+ * A URL unit: an immutable route declaration plus what guards, gates and schemas it answers under.
9
+ *
10
+ * Nothing here is rewritten once declared. Every address question — segment, path, mount, service,
11
+ * host — is a question about the declaration asked against the context the entrypoint is registered
12
+ * in, so the same declaration answers differently in a client and in a server without being touched.
13
+ */
7
14
  export interface CommonEntrypoint extends BasicEntrypoint {
8
- route: CommonRouteModel
15
+ route: RouteModel
9
16
  /**
10
17
  * @property {boolean} - if true — router attaches this entrypoint unconditionally
11
18
  * @default false
12
19
  */
13
20
  sticky: boolean
14
- filter?: Filter
21
+ /** The guards declared on this entrypoint alone — see `getGuards()` for the inherited set. */
15
22
  guards?: string[]
16
23
  gate?: string
17
24
  gateParams?: string | string[]
25
+ filter?: Filter
18
26
  handle?: EntrypointHandler
19
- getAlias: () => string
20
- getPath: () => string
21
- getParentAlias: () => string | null
22
- hasParent: () => boolean
23
- resolve: <M extends CommonEntrypoint>() => Promise<M>
24
- getParent: <M extends CommonEntrypoint>() => M
25
- setService: (service: string) => void
27
+
28
+ /** The segment this entrypoint contributes under its parent. */
29
+ segment: () => string
30
+ /** Every ancestor's segment, then this one. */
31
+ path: () => string
32
+ /** `base` + `path()` — what a server mounts and a client requests. */
33
+ mount: () => string
34
+ service: () => ResolvedServiceRoute
35
+ address: () => RouteAddress
36
+ /** Does this entrypoint belong to the service its context IS? */
37
+ isLocal: () => boolean
38
+ parent: () => CommonEntrypoint | null
39
+ /** Own guards and every ancestor's, deduped. Recomputed on each call. */
26
40
  getGuards: () => string[]
41
+ /** Own gate and every ancestor's, as `[gate, params]`. Recomputed on each call. */
27
42
  getGates: () => [string, string[]][]
28
43
  }
29
44
 
@@ -47,6 +62,17 @@ export interface EntrypointAssert {
47
62
  export interface AbstractRequest<T extends {} = {}> {
48
63
  alias: string
49
64
  auth?: Auth
65
+ /**
66
+ * The organization entity this request acts for, resolved from `auth.entitySlug` once, at the
67
+ * server boundary.
68
+ *
69
+ * The slug on the token is renameable and therefore unusable as a key; `entity.id` is the stable
70
+ * value that records, grants and minted infrastructure names are keyed by. Resolving it here —
71
+ * rather than in each handler — is what keeps a rename from meaning a sweep of every call site,
72
+ * and it is absent whenever no resolver is registered (an implementation that has no notion of
73
+ * an organization store), so consumers must handle that rather than assume it.
74
+ */
75
+ entity?: ResolvedEntity
50
76
  params: Record<string, string | number | undefined | null> | Partial<T>
51
77
  body?: Record<string, any> | Partial<T>
52
78
  headers: Record<string, string[] | string | undefined>
@@ -66,6 +92,21 @@ export interface AbstractRequest<T extends {} = {}> {
66
92
  signal?: AbortSignal
67
93
  }
68
94
 
95
+ /**
96
+ * An organization entity as request handlers see it: the stable id to key by, the current slug to
97
+ * compose user-facing names from, and the frozen key that external systems already know it under.
98
+ */
99
+ export interface ResolvedEntity {
100
+ id: string
101
+ slug: string
102
+ /**
103
+ * The identifier this organization is known by in systems whose names cannot be rewritten —
104
+ * an IAM realm, an object-storage prefix, a cluster object. Minted once and never recomputed,
105
+ * so it stays valid across every later rename.
106
+ */
107
+ iamKey: string
108
+ }
109
+
69
110
  export interface AbstractResponse<T> {
70
111
  responseProvider?: any
71
112
  value?: T,
@@ -98,3 +139,15 @@ export interface Filter {
98
139
  response?: AnySchemaObject
99
140
  headers?: AnySchemaObject
100
141
  }
142
+
143
+ /**
144
+ * How a call to an entrypoint is actually carried.
145
+ *
146
+ * The transport is chosen by the route's protocol, so a consumer always writes `ep.call(...)` and
147
+ * never learns whether that became an HTTP request, a socket message or a queued job. An
148
+ * application binds a protocol by registering a transport service under `transportAlias(protocol)`.
149
+ */
150
+ export interface EntrypointTransport extends InitializedService {
151
+ readonly protocol: RouteProtocols
152
+ handle: EntrypointHandler
153
+ }
@@ -1,4 +1,4 @@
1
1
  import { CommonEntrypoint } from '../types.js'
2
2
 
3
3
  export const isEntrypoint = (obj: object): obj is CommonEntrypoint =>
4
- '_entrypoint' in obj || '_module' in obj
4
+ '_entrypoint' in obj
@@ -1,6 +1,6 @@
1
- import { CommonRouteModel } from '@owlmeans/route'
1
+ import { RouteModel } from '@owlmeans/route'
2
2
  import { CommonEntrypointOptions } from '../types.js'
3
3
 
4
4
  export interface CreateEntrypointSignature<M> {
5
- (route: CommonRouteModel, opts?: CommonEntrypointOptions): M,
5
+ (route: RouteModel, opts?: CommonEntrypointOptions): M,
6
6
  }