@owlmeans/client-entrypoint 0.1.18-rc.10 → 0.1.18-rc.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -13
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/client-entrypoint/SKILL.md +40 -10
- package/build/entrypoint.d.ts +2 -2
- package/build/entrypoint.d.ts.map +1 -1
- package/build/entrypoint.js +13 -11
- package/build/entrypoint.js.map +1 -1
- package/build/errors.d.ts.map +1 -1
- package/build/errors.js.map +1 -1
- package/build/helper.d.ts +7 -0
- package/build/helper.d.ts.map +1 -1
- package/build/helper.js +7 -4
- package/build/helper.js.map +1 -1
- package/build/types.d.ts +30 -8
- package/build/types.d.ts.map +1 -1
- package/build/utils/entrypoint.d.ts.map +1 -1
- package/build/utils/handler.d.ts +3 -3
- package/build/utils/handler.d.ts.map +1 -1
- package/build/utils/handler.js +32 -26
- package/build/utils/handler.js.map +1 -1
- package/package.json +10 -10
- package/src/entrypoint.ts +20 -17
- package/src/helper.ts +7 -4
- package/src/types.ts +34 -10
- package/src/utils/handler.ts +41 -34
package/README.md
CHANGED
|
@@ -5,8 +5,9 @@ Client-side entrypoint system: elevates route definitions into API-calling `Clie
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
7
|
- `elevate(entrypoints, alias, handler?, opts?)` — attaches a client handler to an entrypoint (mirrors server `elevate`)
|
|
8
|
-
- `ClientEntrypoint<T>`
|
|
9
|
-
|
|
8
|
+
- `ClientEntrypoint<T>` exposes three explicit verbs: `call()` for the value, `invoke()` for the value
|
|
9
|
+
plus its outcome, and `url()` for the address
|
|
10
|
+
- `stab` — no-op handler for entrypoints that only need a URL (no logic)
|
|
10
11
|
- `provideRequest(alias, path)` — creates an `AbstractRequest` for programmatic entrypoint calls
|
|
11
12
|
- `pickPerSchema(schema, obj)` — extracts fields from an object matching an AJV schema
|
|
12
13
|
- Re-exported as `celevate` from `@owlmeans/server-app`
|
|
@@ -25,42 +26,60 @@ Define and elevate a client entrypoint for API calls:
|
|
|
25
26
|
import { elevate, stab } from '@owlmeans/client-entrypoint'
|
|
26
27
|
import type { ClientEntrypoint } from '@owlmeans/client-entrypoint'
|
|
27
28
|
|
|
28
|
-
const
|
|
29
|
+
const appEntrypoints = [
|
|
29
30
|
entrypoint(route('project-list', '/projects', frontend('base'))),
|
|
30
31
|
entrypoint(route('project-create', '/projects', backend(RouteMethod.POST))),
|
|
31
32
|
]
|
|
32
33
|
|
|
33
|
-
// Frontend navigation —
|
|
34
|
-
elevate(
|
|
34
|
+
// Frontend navigation — a screen, addressed with url(); call()/invoke() throw on it
|
|
35
|
+
elevate(appEntrypoints, 'project-list', stab)
|
|
35
36
|
|
|
36
37
|
// Backend API call — call() makes a POST request
|
|
37
|
-
elevate(
|
|
38
|
+
elevate(appEntrypoints, 'project-create')
|
|
38
39
|
```
|
|
39
40
|
|
|
40
41
|
Call an entrypoint from a service:
|
|
41
42
|
|
|
42
43
|
```typescript
|
|
43
44
|
const agentEntrypoint = ctx.entrypoint<ClientEntrypoint<Project>>(agent.project.create)
|
|
44
|
-
const
|
|
45
|
-
body: { prompt: payload.prompt, entity: req.auth?.
|
|
45
|
+
const result = await agentEntrypoint.call({
|
|
46
|
+
body: { prompt: payload.prompt, entity: req.auth?.entitySlug }
|
|
46
47
|
})
|
|
47
48
|
```
|
|
48
49
|
|
|
50
|
+
Take the outcome when it decides what happens next, and build a link with `url()`:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
const { value, outcome } = await agentEntrypoint.invoke({ body: payload })
|
|
54
|
+
|
|
55
|
+
const href = await ctx.entrypoint<ClientEntrypoint>('project-list')
|
|
56
|
+
.url({ params: { id: value.id } }, { absolute: true })
|
|
57
|
+
```
|
|
58
|
+
|
|
49
59
|
## API
|
|
50
60
|
|
|
51
61
|
### `elevate<T, R>(entrypoints, alias, handler?, opts?): ClientEntrypoint<T, R>[]`
|
|
52
62
|
|
|
53
|
-
|
|
63
|
+
Replaces the element carrying `alias` with its elevated counterpart, in place, and returns the array typed as `ClientEntrypoint`. The `handler` sets how `call()` behaves. 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.
|
|
54
64
|
|
|
55
65
|
### `stab: RefedEntrypointHandler`
|
|
56
66
|
|
|
57
|
-
No-op handler for frontend-only entrypoints that
|
|
67
|
+
No-op handler for frontend-only entrypoints that are addressed by URL rather than called.
|
|
58
68
|
|
|
59
69
|
### `ClientEntrypoint<T>` (type)
|
|
60
70
|
|
|
61
|
-
- `call(request?)` —
|
|
71
|
+
- `call(request?)` — addresses the entrypoint over the wire and resolves to the value, throwing
|
|
72
|
+
whatever error the reply carried
|
|
73
|
+
- `invoke(request?)` — the same round trip, resolving to `{ value, outcome }`
|
|
74
|
+
- `url(request?, { absolute? })` — builds the URL this entrypoint addresses, with `:params` filled in
|
|
75
|
+
and the query appended; absolute when the route belongs to another service or `absolute` is asked for
|
|
62
76
|
- `validate(request?)` — validates the request against the entrypoint filter schema
|
|
63
|
-
- `
|
|
77
|
+
- `segment()` / `path()` / `mount()` — the segment this entrypoint contributes, that segment under its
|
|
78
|
+
ancestors, and the same path under the service base. All three are computed from the declaration
|
|
79
|
+
and the context on every call — nothing is written back into the route.
|
|
80
|
+
|
|
81
|
+
An entrypoint carrying a renderer *is* a screen: it is addressed by URL, never called over the wire,
|
|
82
|
+
so `call()` and `invoke()` throw and point the caller at `url()`.
|
|
64
83
|
|
|
65
84
|
### `provideRequest<T>(alias, path): AbstractRequest<T>`
|
|
66
85
|
|
|
@@ -70,10 +89,17 @@ Creates a minimal request object for programmatic `call()` invocations.
|
|
|
70
89
|
|
|
71
90
|
Extracts only the keys present in the AJV schema from `obj`.
|
|
72
91
|
|
|
92
|
+
### `@owlmeans/client-entrypoint/utils`
|
|
93
|
+
|
|
94
|
+
The low-level pair the verbs are built on, for code that holds an entrypoint reference directly:
|
|
95
|
+
|
|
96
|
+
- `entrypointUrl(ref, request, opts?)` — the address behind `url()`
|
|
97
|
+
- `apiInvoke(ref, opts?)` — the round trip behind `invoke()`
|
|
98
|
+
|
|
73
99
|
## Related Packages
|
|
74
100
|
|
|
75
101
|
- [`@owlmeans/entrypoint`](../entrypoint) — `CommonEntrypoint` base that gets elevated
|
|
76
|
-
- [`@owlmeans/client`](../client) — `useNavigate`
|
|
102
|
+
- [`@owlmeans/client`](../client) — `useNavigate` navigates by `ClientEntrypoint.url()`
|
|
77
103
|
- [`@owlmeans/server-app`](../server-app) — re-exports `elevate` as `celevate`
|
|
78
104
|
|
|
79
105
|
<!-- owlmeans:agent-guidance:start -->
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/client-entrypoint",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-09-
|
|
4
|
+
"version": "0.1.18-rc.12",
|
|
5
|
+
"generatedAt": "2026-09-01T17:39:40.760Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: client-entrypoint
|
|
3
|
-
description: How to use @owlmeans/client-entrypoint — client-side
|
|
3
|
+
description: How to use @owlmeans/client-entrypoint — client-side entrypoints extending @owlmeans/entrypoint with the call/invoke/url verbs, React component attachment and elevation. Auto-invoked when importing client entrypoint helpers.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
@@ -8,20 +8,24 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/client-entrypoint
|
|
9
9
|
|
|
10
10
|
**Layer:** Client
|
|
11
|
-
**Install:** `"@owlmeans/client-entrypoint": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/client-entrypoint": "^0.1.18-rc.12"` in `dependencies`
|
|
12
12
|
|
|
13
13
|
## Key Exports
|
|
14
14
|
|
|
15
15
|
| Export | Description |
|
|
16
16
|
|--------|-------------|
|
|
17
|
-
| `ClientEntrypoint<T>`
|
|
18
|
-
| `
|
|
17
|
+
| `ClientEntrypoint<T, R>` | Client entrypoint interface — `call`, `invoke`, `url`, `validate`, `request` |
|
|
18
|
+
| `entrypoint(arg, handler?, opts?)` | Build a client entrypoint from a route model or an existing declaration |
|
|
19
|
+
| `elevate(entrypoints, alias, handler?, opts?)` | Make a declared entrypoint client-callable, optionally attaching a screen |
|
|
20
|
+
| `EntrypointCall` / `EntrypointInvoke` / `EntrypointUrl` | The typed signatures of the three verbs |
|
|
21
|
+
| `EntrypointReply<T>` | `{ value, outcome }` — what `invoke` resolves to |
|
|
19
22
|
| `EntrypointRef` / `RefedEntrypointHandler` | Handler reference pattern |
|
|
20
|
-
|
|
|
23
|
+
| `provideRequest(alias, path)` / `pickPerSchema(obj, schema)` | Request construction helpers |
|
|
24
|
+
| `ClientEntrypointError` / `ClientValidationError` | Typed client-side failures |
|
|
21
25
|
|
|
22
26
|
## Subpath Exports
|
|
23
27
|
|
|
24
|
-
- `./utils`
|
|
28
|
+
- `./utils` — `entrypointUrl(ref, req?, opts?)`, `apiInvoke(ref, opts?)`, `apiHandler(ref)`, `validate(ref)`
|
|
25
29
|
|
|
26
30
|
## Usage
|
|
27
31
|
|
|
@@ -31,20 +35,46 @@ Most app code uses `elevate()` from `@owlmeans/web-client` (which builds on this
|
|
|
31
35
|
import type { ClientEntrypoint } from '@owlmeans/client-entrypoint'
|
|
32
36
|
```
|
|
33
37
|
|
|
34
|
-
|
|
38
|
+
Client-side callability is an **explicit opt-in**: a declaration only becomes callable from a client
|
|
39
|
+
once a bare client `elevate` (or `celevate` on the server side) has been applied to it. Elevating is
|
|
40
|
+
idempotent, and guards passed at elevation are added to the ones the declaration already carries.
|
|
35
41
|
|
|
36
|
-
|
|
42
|
+
## The three verbs
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
const ep = context.entrypoint<ClientEntrypoint<Project>>(manager.back.project.create)
|
|
46
|
+
|
|
47
|
+
const project = await ep.call({ body }) // the VALUE; the reply error is thrown
|
|
48
|
+
const { value, outcome } = await ep.invoke({ body }) // value AND outcome
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`call` is the default — it resolves to the value and throws whatever the reply carried, so a caller
|
|
52
|
+
that only needs the result never inspects an outcome. Reach for `invoke` only where the outcome
|
|
53
|
+
(`Ok`, `Accepted`, `Created`, `Finished`) decides what happens next.
|
|
54
|
+
|
|
55
|
+
An entrypoint that carries a **renderer IS a screen**: it is addressed by URL, never called over the
|
|
56
|
+
wire, and it throws from `call()`/`invoke()` saying so.
|
|
57
|
+
|
|
58
|
+
## URL generation
|
|
59
|
+
|
|
60
|
+
`url()` fills in `:params`, appends the query, and returns a **relative** path when the route belongs
|
|
61
|
+
to the asking service — addressing an in-app target absolutely would turn navigation into a full page
|
|
62
|
+
load. Ask for `{ absolute: true }` when the URL leaves the app (redirect URIs, webhook callbacks,
|
|
63
|
+
anything pasted into another system), and a cross-service route is absolute regardless.
|
|
37
64
|
|
|
38
65
|
```typescript
|
|
39
66
|
import type { ClientEntrypoint } from '@owlmeans/client-entrypoint'
|
|
40
67
|
import { HOME } from '@owlmeans/context'
|
|
41
68
|
|
|
42
|
-
const
|
|
69
|
+
const url = await context.entrypoint<ClientEntrypoint<string>>(HOME).url({}, { absolute: true })
|
|
43
70
|
// Returns e.g. "https://app.example.com/"
|
|
44
71
|
```
|
|
45
72
|
|
|
46
|
-
This is the preferred pattern for redirect URIs and navigation targets instead of manual
|
|
73
|
+
This is the preferred pattern for redirect URIs and navigation targets instead of manual
|
|
74
|
+
`window.location` concatenation. The underlying helper is `entrypointUrl(ref, req?, opts?)` from
|
|
75
|
+
`./utils`, which packages building their own addressing (sockets, for instance) call directly.
|
|
47
76
|
|
|
48
77
|
## Depends On
|
|
49
78
|
|
|
50
79
|
- `@owlmeans/entrypoint`, `@owlmeans/client-route`, `@owlmeans/client-context`
|
|
80
|
+
- `@owlmeans/api` (the HTTP carrier), `@owlmeans/config` (`makeSecurityHelper` for absolute URLs)
|
package/build/entrypoint.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClientRouteModel } from '@owlmeans/client-route';
|
|
2
2
|
import type { ClientEntrypoint, ClientEntrypointOptions, RefedEntrypointHandler } from './types.js';
|
|
3
3
|
import type { AbstractRequest, CommonEntrypoint } from '@owlmeans/entrypoint';
|
|
4
|
-
import type {
|
|
5
|
-
export declare const entrypoint: <T, R extends AbstractRequest = AbstractRequest>(arg: CommonEntrypoint | ClientRouteModel |
|
|
4
|
+
import type { RouteModel } from '@owlmeans/route';
|
|
5
|
+
export declare const entrypoint: <T, R extends AbstractRequest = AbstractRequest>(arg: CommonEntrypoint | ClientRouteModel | RouteModel, handler?: RefedEntrypointHandler<T, R> | ClientEntrypointOptions | boolean, opts?: ClientEntrypointOptions | boolean) => ClientEntrypoint<T, 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,uBAAuB,EAAiB,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAClH,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,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,uBAAuB,EAAiB,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAClH,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAK7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAGjD,eAAO,MAAM,UAAU,GAAI,CAAC,EAAE,CAAC,SAAS,eAAe,GAAG,eAAe,EACvE,KAAK,gBAAgB,GAAG,gBAAgB,GAAG,UAAU,EACrD,UAAU,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,uBAAuB,GAAG,OAAO,EAC1E,OAAO,uBAAuB,GAAG,OAAO,KACvC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAoEvB,CAAA"}
|
package/build/entrypoint.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { isEntrypoint, makeBasicEntrypoint, normalizeHelperParams, validate } from './utils/entrypoint.js';
|
|
2
2
|
import { isClientRouteModel, route } from '@owlmeans/client-route';
|
|
3
|
-
import {
|
|
3
|
+
import { apiInvoke, apiHandler, entrypointUrl } from './utils/handler.js';
|
|
4
4
|
import { AppType } from '@owlmeans/context';
|
|
5
|
-
import { normalizePath } from '@owlmeans/route';
|
|
6
5
|
import { provideRequest } from './helper.js';
|
|
7
6
|
export const entrypoint = (arg, handler, opts) => {
|
|
8
7
|
const entrypointHandle = { ref: undefined };
|
|
@@ -16,7 +15,8 @@ export const entrypoint = (arg, handler, opts) => {
|
|
|
16
15
|
const routeModel = route(arg.route, opts?.routeOptions);
|
|
17
16
|
_entrypoint = arg;
|
|
18
17
|
_entrypoint.route = routeModel;
|
|
19
|
-
|
|
18
|
+
// Elevating adds guards, it never swaps them: what the entrypoint declared still applies.
|
|
19
|
+
_entrypoint.guards = [...new Set([...(arg.guards ?? []), ...(opts?.guards ?? [])])];
|
|
20
20
|
_entrypoint.filter = opts?.filter ?? arg.filter;
|
|
21
21
|
_entrypoint.gate = opts?.gate ?? arg.gate;
|
|
22
22
|
_entrypoint.gateParams = opts?.gateParams ?? arg.gateParams;
|
|
@@ -32,13 +32,20 @@ export const entrypoint = (arg, handler, opts) => {
|
|
|
32
32
|
_entrypoint = makeBasicEntrypoint(_route, { ...opts });
|
|
33
33
|
_entrypoint.route = _route;
|
|
34
34
|
}
|
|
35
|
-
_entrypoint.
|
|
36
|
-
|
|
35
|
+
_entrypoint.url = ((req, urlOpts) => entrypointUrl(entrypointHandle, req, urlOpts));
|
|
36
|
+
// An entrypoint carrying a renderer IS a screen: it is addressed by URL, never called over the
|
|
37
|
+
// wire. Saying so here turns what used to be a URL-shaped answer from `call()` into a report.
|
|
38
|
+
_entrypoint.invoke = (handler != null
|
|
39
|
+
? (async () => {
|
|
40
|
+
throw new SyntaxError(`Entrypoint ${_entrypoint.alias} renders a screen - address it with url() instead of call()/invoke()`);
|
|
41
|
+
})
|
|
42
|
+
: apiInvoke(entrypointHandle, opts));
|
|
43
|
+
_entrypoint.call = (async (req) => (await _entrypoint.invoke(req)).value);
|
|
37
44
|
_entrypoint.request = ((request) => {
|
|
38
45
|
if (entrypointHandle.ref == null) {
|
|
39
46
|
throw SyntaxError(`Try to request uninitialized entrypoint ${JSON.stringify(arg)}`);
|
|
40
47
|
}
|
|
41
|
-
const _request = provideRequest(entrypointHandle.ref.
|
|
48
|
+
const _request = provideRequest(entrypointHandle.ref.alias, entrypointHandle.ref.path());
|
|
42
49
|
request != null && Object.entries(request).forEach(([key, value]) => {
|
|
43
50
|
_request[key] = value;
|
|
44
51
|
});
|
|
@@ -46,11 +53,6 @@ export const entrypoint = (arg, handler, opts) => {
|
|
|
46
53
|
});
|
|
47
54
|
_entrypoint.handle = _handler?.(entrypointHandle);
|
|
48
55
|
_entrypoint.validate = validate(entrypointHandle);
|
|
49
|
-
_entrypoint.reinitializeContext = (context) => {
|
|
50
|
-
const newEntrypoint = entrypoint(_entrypoint.route, handler, opts);
|
|
51
|
-
newEntrypoint.ctx = context;
|
|
52
|
-
return newEntrypoint;
|
|
53
|
-
};
|
|
54
56
|
entrypointHandle.ref = _entrypoint;
|
|
55
57
|
return _entrypoint;
|
|
56
58
|
};
|
package/build/entrypoint.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entrypoint.js","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAC1G,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAClE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"entrypoint.js","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"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"}
|
package/build/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,qBAAa,qBAAsB,SAAQ,cAAc;IACvD,OAAuB,QAAQ,SAAsB;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,qBAAa,qBAAsB,SAAQ,cAAc;IACvD,OAAuB,QAAQ,SAAsB;gBAEzC,OAAO,EAAE,MAAM;CAG5B;AAED,qBAAa,qBAAsB,SAAQ,qBAAqB;IAC9D,OAAuB,QAAQ,SAAgD;gBAEnE,OAAO,EAAE,MAAM;CAI5B"}
|
package/build/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,MAAM,OAAO,qBAAsB,SAAQ,cAAc;IAChD,MAAM,CAAU,QAAQ,GAAG,mBAAmB,CAAA;IAErD,YAAY,OAAe;QACzB,KAAK,CAAC,qBAAqB,CAAC,QAAQ,EAAE,iBAAiB,OAAO,EAAE,CAAC,CAAA;IACnE,CAAC
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,MAAM,OAAO,qBAAsB,SAAQ,cAAc;IAChD,MAAM,CAAU,QAAQ,GAAG,mBAAmB,CAAA;IAErD,YAAY,OAAe;QACzB,KAAK,CAAC,qBAAqB,CAAC,QAAQ,EAAE,iBAAiB,OAAO,EAAE,CAAC,CAAA;IACnE,CAAC;;AAGH,MAAM,OAAO,qBAAsB,SAAQ,qBAAqB;IACvD,MAAM,CAAU,QAAQ,GAAG,GAAG,qBAAqB,CAAC,QAAQ,YAAY,CAAA;IAE/E,YAAY,OAAe;QACzB,KAAK,CAAC,cAAc,OAAO,EAAE,CAAC,CAAA;QAC9B,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC,QAAQ,CAAA;IAC5C,CAAC;;AAIH,cAAc,CAAC,kBAAkB,CAAC,qBAAqB,CAAC,CAAA;AACxD,cAAc,CAAC,kBAAkB,CAAC,qBAAqB,CAAC,CAAA"}
|
package/build/helper.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type { ClientEntrypoint, ClientEntrypointOptions, RefedEntrypointHandler } from './types.js';
|
|
2
2
|
import type { AbstractRequest, CommonEntrypoint } from '@owlmeans/entrypoint';
|
|
3
3
|
import type { JSONSchemaType } from "ajv";
|
|
4
|
+
/**
|
|
5
|
+
* Replace the entrypoint declared under `alias` with its elevated counterpart. Elevating is
|
|
6
|
+
* idempotent — calling it again simply replaces the element once more, and the guards it brings
|
|
7
|
+
* are added to the ones already declared.
|
|
8
|
+
*
|
|
9
|
+
* @throws {SyntaxError} when no entrypoint carries the alias
|
|
10
|
+
*/
|
|
4
11
|
export declare const elevate: <T = {}, R extends AbstractRequest = AbstractRequest>(entrypoints: (CommonEntrypoint | ClientEntrypoint<T, R>)[], alias: string, handler?: RefedEntrypointHandler<T, R> | ClientEntrypointOptions | boolean, opts?: ClientEntrypointOptions | boolean) => ClientEntrypoint<T, R>[];
|
|
5
12
|
export declare const stab: RefedEntrypointHandler<{}>;
|
|
6
13
|
export declare const provideRequest: <T extends {} = {}>(alias: string, path: string) => AbstractRequest<T>;
|
package/build/helper.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAEnG,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAE7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAA;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,eAAe,GAAG,eAAe,EACzE,aAAa,CAAC,gBAAgB,GAAG,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAC1D,OAAO,MAAM,EACb,UAAU,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,uBAAuB,GAAG,OAAO,EAC1E,OAAO,uBAAuB,GAAG,OAAO,KACvC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,EAWxB,CAAA;AAED,eAAO,MAAM,IAAI,EAAE,sBAAsB,CAAC,EAAE,CAE3C,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,OAAO,MAAM,EAAE,MAAM,MAAM,KAAG,eAAe,CAAC,CAAC,CAYhG,CAAA;AAED,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,QAAQ,cAAc,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,CAAC,CAQjF,CAAA"}
|
package/build/helper.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { entrypoint } from './entrypoint.js';
|
|
2
|
-
import { isClientRouteModel } from '@owlmeans/client-route';
|
|
3
2
|
import { normalizeHelperParams } from './utils/entrypoint.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
|
+
*/
|
|
4
10
|
export const elevate = (entrypoints, alias, handler, opts) => {
|
|
5
11
|
[handler, opts] = normalizeHelperParams(handler, opts);
|
|
6
12
|
const idx = entrypoints.findIndex(({ route }) => route.route.alias === alias);
|
|
7
13
|
if (idx === -1) {
|
|
8
14
|
throw new SyntaxError(`Entrypoint with alias ${alias} not present`);
|
|
9
15
|
}
|
|
10
|
-
if (isClientRouteModel(entrypoints[idx].route) && opts?.force !== true) {
|
|
11
|
-
throw new SyntaxError(`Entrypoint with alias ${alias} is already elevated`);
|
|
12
|
-
}
|
|
13
16
|
entrypoints[idx] = entrypoint(entrypoints[idx], handler, opts);
|
|
14
17
|
return entrypoints;
|
|
15
18
|
};
|
package/build/helper.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAG7D;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CACrB,WAA0D,EAC1D,KAAa,EACb,OAA0E,EAC1E,IAAwC,EACd,EAAE;IAC5B,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IAEtD,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;IAED,WAAW,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;IAE9D,OAAO,WAAuC,CAAA;AAChD,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,IAAI,GAA+B,GAAG,EAAE,CAAC,GAAG,EAAE;IACzD,OAAO,KAAK,CAAQ,CAAA;AACtB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,CAAoB,KAAa,EAAE,IAAY,EAAsB,EAAE;IACnG,MAAM,OAAO,GAAG;QACd,KAAK;QACL,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,EAAE;QACX,KAAK,EAAE,EAAE;QACT,IAAI;QACJ,QAAQ,EAAE,KAAK;QACf,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,GAAG,IAAI;KACtC,CAAA;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,CAAO,MAAS,EAAE,MAAyB,EAAc,EAAE,CACtF,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CACnC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACX,IAAI,MAAM,CAAC,GAAc,CAAC,IAAI,IAAI,EAAE,CAAC;QACnC,GAAG,CAAC,GAAc,CAAC,GAAG,MAAM,CAAC,GAAc,CAA0B,CAAA;IACvE,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC,EAAE,EAAgB,CACpB,CAAA"}
|
package/build/types.d.ts
CHANGED
|
@@ -1,26 +1,48 @@
|
|
|
1
1
|
import type { ClientRouteModel, ClientRouteOptions } from '@owlmeans/client-route';
|
|
2
|
-
import type { AbstractRequest,
|
|
2
|
+
import type { AbstractRequest, CommonEntrypoint, CommonEntrypointOptions, EntrypointHandler, EntrypointOutcome } from '@owlmeans/entrypoint';
|
|
3
3
|
export interface ClientEntrypoint<T = {}, R extends ClientRequest = ClientRequest> extends CommonEntrypoint {
|
|
4
4
|
route: ClientRouteModel;
|
|
5
|
+
/**
|
|
6
|
+
* Address the entrypoint and resolve to what it answered. The reply's error is thrown, so a
|
|
7
|
+
* caller that only needs the value never inspects an outcome.
|
|
8
|
+
*/
|
|
5
9
|
call: EntrypointCall<T, R>;
|
|
10
|
+
/**
|
|
11
|
+
* The same round trip as {@link ClientEntrypoint.call}, resolving to the value AND the outcome.
|
|
12
|
+
* Use it only where the outcome decides what happens next.
|
|
13
|
+
*/
|
|
14
|
+
invoke: EntrypointInvoke<T, R>;
|
|
15
|
+
/**
|
|
16
|
+
* Build the URL this entrypoint addresses, with `:params` filled in and the query appended.
|
|
17
|
+
* Absolute when the route belongs to another service, or when `absolute` is asked for.
|
|
18
|
+
*/
|
|
19
|
+
url: EntrypointUrl<R>;
|
|
6
20
|
validate: EntrypointFilter<R>;
|
|
7
|
-
getPath: (partial?: boolean) => string;
|
|
8
21
|
request: (request?: Partial<R>) => R;
|
|
9
22
|
}
|
|
10
23
|
export interface EntrypointCall<T, Req extends ClientRequest = ClientRequest> {
|
|
11
|
-
<Type extends T, R extends Req = Req
|
|
24
|
+
<Type extends T, R extends Req = Req>(req?: Partial<R>): Promise<Type>;
|
|
25
|
+
}
|
|
26
|
+
export interface EntrypointInvoke<T, Req extends ClientRequest = ClientRequest> {
|
|
27
|
+
<Type extends T, R extends Req = Req>(req?: Partial<R>): Promise<EntrypointReply<Type>>;
|
|
28
|
+
}
|
|
29
|
+
export interface EntrypointReply<T> {
|
|
30
|
+
value: T;
|
|
31
|
+
outcome: EntrypointOutcome;
|
|
32
|
+
}
|
|
33
|
+
export interface EntrypointUrl<Req extends ClientRequest = ClientRequest> {
|
|
34
|
+
<R extends Req = Req>(req?: Partial<R>, opts?: EntrypointUrlOptions): Promise<string>;
|
|
35
|
+
}
|
|
36
|
+
export interface EntrypointUrlOptions {
|
|
37
|
+
/** Force a fully qualified URL even when the route belongs to the current service. */
|
|
38
|
+
absolute?: boolean;
|
|
12
39
|
}
|
|
13
40
|
export interface EntrypointFilter<Req extends AbstractRequest = AbstractRequest> {
|
|
14
41
|
<R extends Req>(req?: Partial<R>): Promise<boolean>;
|
|
15
42
|
}
|
|
16
43
|
export interface ClientRequest<T extends {} = {}> extends AbstractRequest<T> {
|
|
17
|
-
full?: boolean;
|
|
18
44
|
}
|
|
19
45
|
export interface ClientEntrypointOptions extends CommonEntrypointOptions {
|
|
20
|
-
/**
|
|
21
|
-
* Force entrypoint to be elevated even if it is already elevated
|
|
22
|
-
*/
|
|
23
|
-
force?: boolean;
|
|
24
46
|
routeOptions?: ClientRouteOptions;
|
|
25
47
|
validateOnCall?: boolean;
|
|
26
48
|
}
|
package/build/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAClF,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,
|
|
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,eAAe,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAE5I,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,aAAa,GAAG,aAAa,CAAE,SAAQ,gBAAgB;IACzG,KAAK,EAAE,gBAAgB,CAAA;IACvB;;;OAGG;IACH,IAAI,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC1B;;;OAGG;IACH,MAAM,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC9B;;;OAGG;IACH,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;IACrB,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;IAC7B,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;CACrC;AAED,MAAM,WAAW,cAAc,CAAC,CAAC,EAAE,GAAG,SAAS,aAAa,GAAG,aAAa;IAC1E,CAAC,IAAI,SAAS,CAAC,EAAE,CAAC,SAAS,GAAG,GAAG,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACvE;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,EAAE,GAAG,SAAS,aAAa,GAAG,aAAa;IAC5E,CAAC,IAAI,SAAS,CAAC,EAAE,CAAC,SAAS,GAAG,GAAG,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAA;CACxF;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,KAAK,EAAE,CAAC,CAAA;IACR,OAAO,EAAE,iBAAiB,CAAA;CAC3B;AAED,MAAM,WAAW,aAAa,CAAC,GAAG,SAAS,aAAa,GAAG,aAAa;IACtE,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACtF;AAED,MAAM,WAAW,oBAAoB;IACnC,sFAAsF;IACtF,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,gBAAgB,CAAC,GAAG,SAAS,eAAe,GAAG,eAAe;IAC7E,CAAC,CAAC,SAAS,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACpD;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,EAAE,GAAG,EAAE,CAAE,SAAQ,eAAe,CAAC,CAAC,CAAC;CAC3E;AAED,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACtE,YAAY,CAAC,EAAE,kBAAkB,CAAA;IACjC,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,EAAE,CAAC,SAAS,eAAe,GAAG,eAAe;IAC3E,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;CAC7B;AAED,MAAM,WAAW,sBAAsB,CAAC,CAAC,EAAE,CAAC,SAAS,eAAe,GAAG,eAAe;IACpF,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,iBAAiB,CAAA;CAC9C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entrypoint.d.ts","sourceRoot":"","sources":["../../src/utils/entrypoint.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAE5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAGxE,OAAO,EAAE,UAAU,IAAI,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAKzD;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,SAAS,eAAe,GAAG,eAAe,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,gBAiClG,CAAA;AAEH,eAAO,MAAM,qBAAqB,GAAI,CAAC,EAAE,CAAC,SAAS,eAAe,GAAG,eAAe,
|
|
1
|
+
{"version":3,"file":"entrypoint.d.ts","sourceRoot":"","sources":["../../src/utils/entrypoint.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAE5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAGxE,OAAO,EAAE,UAAU,IAAI,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAKzD;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,SAAS,eAAe,GAAG,eAAe,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,gBAiClG,CAAA;AAEH,eAAO,MAAM,qBAAqB,GAAI,CAAC,EAAE,CAAC,SAAS,eAAe,GAAG,eAAe,EAClF,UAAU,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,uBAAuB,GAAG,OAAO,EAC1E,OAAO,uBAAuB,GAAG,OAAO,KACvC,CAAC,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,EAAE,uBAAuB,GAAG,SAAS,CAShF,CAAA"}
|
package/build/utils/handler.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AbstractRequest, EntrypointHandler } from '@owlmeans/entrypoint';
|
|
2
|
-
import type {
|
|
2
|
+
import type { EntrypointInvoke, EntrypointUrlOptions, ClientEntrypointOptions, EntrypointRef, ClientRequest } from '../types.js';
|
|
3
3
|
export declare const apiHandler: <T, R extends AbstractRequest = AbstractRequest>(ref: EntrypointRef<T, R>) => EntrypointHandler;
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
4
|
+
export declare const apiInvoke: <T, R extends AbstractRequest = AbstractRequest>(ref: EntrypointRef<T, R>, opts?: ClientEntrypointOptions) => EntrypointInvoke<T, R>;
|
|
5
|
+
export declare const entrypointUrl: <T, R extends ClientRequest = ClientRequest>(ref: EntrypointRef<T, R>, req?: Partial<R>, opts?: EntrypointUrlOptions) => Promise<string>;
|
|
6
6
|
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/utils/handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/utils/handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAuB,MAAM,sBAAsB,CAAA;AAEnG,OAAO,KAAK,EAAoB,gBAAgB,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAWlJ,eAAO,MAAM,UAAU,EAAE,CACvB,CAAC,EAAE,CAAC,SAAS,eAAe,GAAG,eAAe,EAC9C,GAAG,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,iBAqC9B,CAAA;AAED,eAAO,MAAM,SAAS,EAAE,CACtB,CAAC,EAAE,CAAC,SAAS,eAAe,GAAG,eAAe,EAC9C,GAAG,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,uBAAuB,KAAK,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAoDvD,CAAA;AAE7B,eAAO,MAAM,aAAa,EAAE,CAC1B,CAAC,EAAE,CAAC,SAAS,aAAa,GAAG,aAAa,EAC1C,GAAG,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,MAAM,CA6B3F,CAAA"}
|
package/build/utils/handler.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_KEY } from '@owlmeans/client-config';
|
|
2
|
-
import { EntrypointOutcome, provideResponse } from '@owlmeans/entrypoint';
|
|
2
|
+
import { EntrypointOutcome, provideResponse, transportAlias } from '@owlmeans/entrypoint';
|
|
3
3
|
import { validate } from './entrypoint.js';
|
|
4
4
|
import { extractParams } from '@owlmeans/client-route';
|
|
5
5
|
import { PARAM } from '@owlmeans/route';
|
|
@@ -13,20 +13,28 @@ export const apiHandler = (ref) => async (req, res) => {
|
|
|
13
13
|
throw new SyntaxError('No webService provided');
|
|
14
14
|
}
|
|
15
15
|
const ep = context.entrypoint(req.alias);
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
// A route names the protocol it answers on, and a protocol may be carried by something other than
|
|
17
|
+
// HTTP — a queue, say. Whatever is bound under this protocol takes the call, so a consumer writes
|
|
18
|
+
// `ep.call(...)` and never learns which of them ran.
|
|
19
|
+
const transport = transportAlias(ep.route.route.protocol);
|
|
20
|
+
if (context.hasService(transport)) {
|
|
21
|
+
req.path = ep.path();
|
|
22
|
+
return context.service(transport).handle(req, res);
|
|
23
|
+
}
|
|
24
|
+
// Which web client carries this call is decided by the service the route answers on — the one it
|
|
25
|
+
// names, or the one the context picks for its app type when it names none.
|
|
26
|
+
const route = ep.service();
|
|
27
|
+
const alias = typeof context.cfg.webService === 'string'
|
|
18
28
|
? context.cfg.webService
|
|
19
|
-
:
|
|
20
|
-
? context.cfg.webService[route.service] ?? context.cfg.webService[DEFAULT_KEY]
|
|
21
|
-
: context.cfg.webService[DEFAULT_KEY]);
|
|
29
|
+
: context.cfg.webService[route.service] ?? context.cfg.webService[DEFAULT_KEY];
|
|
22
30
|
if (alias == null) {
|
|
23
31
|
throw new SyntaxError(`Can't cast web service alias for ${ep.alias} entrypoint`);
|
|
24
32
|
}
|
|
25
33
|
const service = context.service(alias);
|
|
26
|
-
req.path = ep.
|
|
34
|
+
req.path = ep.path();
|
|
27
35
|
return service.handler(req, res);
|
|
28
36
|
};
|
|
29
|
-
export const
|
|
37
|
+
export const apiInvoke = (ref, opts) => (async (req) => {
|
|
30
38
|
const ep = ref.ref;
|
|
31
39
|
if (ep == null) {
|
|
32
40
|
throw new SyntaxError('Try to make API call before the entrypoint is created');
|
|
@@ -35,9 +43,8 @@ export const apiCall = (ref, opts) => (async (req, res) => {
|
|
|
35
43
|
if (ctx == null) {
|
|
36
44
|
throw new SyntaxError(`No context provided in apiCall for ${ep.alias} entrypoint`);
|
|
37
45
|
}
|
|
38
|
-
await ep.route.resolve(ctx);
|
|
39
46
|
if (req?.canceled) {
|
|
40
|
-
return;
|
|
47
|
+
return { value: null, outcome: EntrypointOutcome.Ok };
|
|
41
48
|
}
|
|
42
49
|
const request = {
|
|
43
50
|
alias: ep.alias,
|
|
@@ -47,7 +54,7 @@ export const apiCall = (ref, opts) => (async (req, res) => {
|
|
|
47
54
|
query: req?.query ?? {},
|
|
48
55
|
host: req?.host,
|
|
49
56
|
base: req?.base,
|
|
50
|
-
path: ep.
|
|
57
|
+
path: ep.path(),
|
|
51
58
|
timeout: req?.timeout,
|
|
52
59
|
signal: req?.signal,
|
|
53
60
|
};
|
|
@@ -67,10 +74,6 @@ export const apiCall = (ref, opts) => (async (req, res) => {
|
|
|
67
74
|
throw e;
|
|
68
75
|
}
|
|
69
76
|
}
|
|
70
|
-
if (res != null) {
|
|
71
|
-
await apiHandler(ref)(request, res);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
77
|
const reply = provideResponse();
|
|
75
78
|
if (ctx == null && ep.ctx == null) {
|
|
76
79
|
throw new SyntaxError(`Use entrypoint ${ep.alias} without context`);
|
|
@@ -79,28 +82,31 @@ export const apiCall = (ref, opts) => (async (req, res) => {
|
|
|
79
82
|
if (reply.error != null) {
|
|
80
83
|
throw reply.error;
|
|
81
84
|
}
|
|
82
|
-
return
|
|
85
|
+
return { value: reply.value ?? null, outcome: reply.outcome ?? EntrypointOutcome.Ok };
|
|
83
86
|
});
|
|
84
|
-
export const
|
|
87
|
+
export const entrypointUrl = async (ref, req, opts) => {
|
|
85
88
|
const ep = ref.ref;
|
|
86
89
|
if (ep == null) {
|
|
87
90
|
throw new SyntaxError('Try to make URL before the entrypoint is created');
|
|
88
91
|
}
|
|
89
92
|
const ctx = ep.ctx;
|
|
90
93
|
if (ctx == null) {
|
|
91
|
-
throw new SyntaxError(`No context provided in
|
|
94
|
+
throw new SyntaxError(`No context provided in entrypointUrl for ${ep.alias} entrypoint`);
|
|
92
95
|
}
|
|
93
|
-
|
|
94
|
-
|
|
96
|
+
// The base is left off here: an in-service URL is addressed relative to it, and the absolute
|
|
97
|
+
// branch below has `makeUrl` prepend it.
|
|
98
|
+
const epPath = ep.path();
|
|
99
|
+
const pathParams = extractParams(epPath);
|
|
95
100
|
let path = pathParams.reduce((p, param) => {
|
|
96
101
|
return p.replace(`${PARAM}${param}`, `${req?.params?.[param]}`);
|
|
97
|
-
},
|
|
98
|
-
|
|
99
|
-
|
|
102
|
+
}, epPath) + (req?.query != null ? `?${stringify(req?.query)}` : '');
|
|
103
|
+
// Locality is a question about the RESOLVED service, not about what the declaration happens to
|
|
104
|
+
// name: a route that names no service belongs to the asking context, and addressing it absolutely
|
|
105
|
+
// would turn in-app navigation into a full page load.
|
|
106
|
+
if (!ep.isLocal() || opts?.absolute === true) {
|
|
100
107
|
const helper = makeSecurityHelper(ctx);
|
|
101
|
-
path = helper.makeUrl(ep.
|
|
108
|
+
path = helper.makeUrl(ep.address(), path, { host: req?.host, base: req?.base, forceUnsecure: req?.unsecure });
|
|
102
109
|
}
|
|
103
|
-
|
|
104
|
-
return [path, EntrypointOutcome.Ok];
|
|
110
|
+
return path;
|
|
105
111
|
};
|
|
106
112
|
//# sourceMappingURL=handler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/utils/handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAGrD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/utils/handler.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/client-entrypoint",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.12",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -28,15 +28,15 @@
|
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@owlmeans/api": "^0.1.18-rc.
|
|
32
|
-
"@owlmeans/client-config": "^0.1.18-rc.
|
|
33
|
-
"@owlmeans/client-context": "^0.1.18-rc.
|
|
34
|
-
"@owlmeans/client-route": "^0.1.18-rc.
|
|
35
|
-
"@owlmeans/config": "^0.1.18-rc.
|
|
36
|
-
"@owlmeans/context": "^0.1.18-rc.
|
|
37
|
-
"@owlmeans/entrypoint": "^0.1.18-rc.
|
|
38
|
-
"@owlmeans/error": "^0.1.18-rc.
|
|
39
|
-
"@owlmeans/route": "^0.1.18-rc.
|
|
31
|
+
"@owlmeans/api": "^0.1.18-rc.12",
|
|
32
|
+
"@owlmeans/client-config": "^0.1.18-rc.11",
|
|
33
|
+
"@owlmeans/client-context": "^0.1.18-rc.12",
|
|
34
|
+
"@owlmeans/client-route": "^0.1.18-rc.12",
|
|
35
|
+
"@owlmeans/config": "^0.1.18-rc.11",
|
|
36
|
+
"@owlmeans/context": "^0.1.18-rc.7",
|
|
37
|
+
"@owlmeans/entrypoint": "^0.1.18-rc.10",
|
|
38
|
+
"@owlmeans/error": "^0.1.18-rc.7",
|
|
39
|
+
"@owlmeans/route": "^0.1.18-rc.8",
|
|
40
40
|
"ajv-formats": "^3.0.1",
|
|
41
41
|
"qs": "^6.13.0"
|
|
42
42
|
},
|
package/src/entrypoint.ts
CHANGED
|
@@ -3,15 +3,13 @@ import type { ClientEntrypoint, ClientEntrypointOptions, EntrypointRef, RefedEnt
|
|
|
3
3
|
import type { AbstractRequest, CommonEntrypoint } from '@owlmeans/entrypoint'
|
|
4
4
|
import { isEntrypoint, makeBasicEntrypoint, normalizeHelperParams, validate } from './utils/entrypoint.js'
|
|
5
5
|
import { isClientRouteModel, route } from '@owlmeans/client-route'
|
|
6
|
-
import {
|
|
6
|
+
import { apiInvoke, apiHandler, entrypointUrl } from './utils/handler.js'
|
|
7
7
|
import { AppType } from '@owlmeans/context'
|
|
8
|
-
import type {
|
|
9
|
-
import { normalizePath } from '@owlmeans/route'
|
|
10
|
-
import type { CommonRouteModel } from '@owlmeans/route'
|
|
8
|
+
import type { RouteModel } from '@owlmeans/route'
|
|
11
9
|
import { provideRequest } from './helper.js'
|
|
12
10
|
|
|
13
11
|
export const entrypoint = <T, R extends AbstractRequest = AbstractRequest>(
|
|
14
|
-
arg: CommonEntrypoint | ClientRouteModel |
|
|
12
|
+
arg: CommonEntrypoint | ClientRouteModel | RouteModel,
|
|
15
13
|
handler?: RefedEntrypointHandler<T, R> | ClientEntrypointOptions | boolean,
|
|
16
14
|
opts?: ClientEntrypointOptions | boolean
|
|
17
15
|
): ClientEntrypoint<T, R> => {
|
|
@@ -30,7 +28,8 @@ export const entrypoint = <T, R extends AbstractRequest = AbstractRequest>(
|
|
|
30
28
|
const routeModel = route(arg.route, opts?.routeOptions)
|
|
31
29
|
_entrypoint = arg as ClientEntrypoint<T, R>
|
|
32
30
|
_entrypoint.route = routeModel
|
|
33
|
-
|
|
31
|
+
// Elevating adds guards, it never swaps them: what the entrypoint declared still applies.
|
|
32
|
+
_entrypoint.guards = [...new Set([...(arg.guards ?? []), ...(opts?.guards ?? [])])]
|
|
34
33
|
_entrypoint.filter = opts?.filter ?? arg.filter
|
|
35
34
|
_entrypoint.gate = opts?.gate ?? arg.gate
|
|
36
35
|
_entrypoint.gateParams = opts?.gateParams ?? arg.gateParams
|
|
@@ -45,16 +44,27 @@ export const entrypoint = <T, R extends AbstractRequest = AbstractRequest>(
|
|
|
45
44
|
_entrypoint.route = _route
|
|
46
45
|
}
|
|
47
46
|
|
|
48
|
-
_entrypoint.
|
|
49
|
-
|
|
47
|
+
_entrypoint.url = ((req?: Partial<R>, urlOpts?: { absolute?: boolean }) =>
|
|
48
|
+
entrypointUrl<T, R>(entrypointHandle, req as never, urlOpts)) as ClientEntrypoint<T, R>['url']
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
// An entrypoint carrying a renderer IS a screen: it is addressed by URL, never called over the
|
|
51
|
+
// wire. Saying so here turns what used to be a URL-shaped answer from `call()` into a report.
|
|
52
|
+
_entrypoint.invoke = (handler != null
|
|
53
|
+
? (async () => {
|
|
54
|
+
throw new SyntaxError(
|
|
55
|
+
`Entrypoint ${_entrypoint.alias} renders a screen - address it with url() instead of call()/invoke()`
|
|
56
|
+
)
|
|
57
|
+
})
|
|
58
|
+
: apiInvoke<T, R>(entrypointHandle, opts)) as ClientEntrypoint<T, R>['invoke']
|
|
59
|
+
|
|
60
|
+
_entrypoint.call = (async (req?: Partial<R>) =>
|
|
61
|
+
(await _entrypoint.invoke(req)).value) as ClientEntrypoint<T, R>['call']
|
|
52
62
|
|
|
53
63
|
_entrypoint.request = ((request: R): R => {
|
|
54
64
|
if (entrypointHandle.ref == null) {
|
|
55
65
|
throw SyntaxError(`Try to request uninitialized entrypoint ${JSON.stringify(arg)}`)
|
|
56
66
|
}
|
|
57
|
-
const _request = provideRequest(entrypointHandle.ref.
|
|
67
|
+
const _request = provideRequest(entrypointHandle.ref.alias, entrypointHandle.ref.path()) as R
|
|
58
68
|
|
|
59
69
|
request != null && Object.entries(request).forEach(([key, value]) => {
|
|
60
70
|
_request[key as keyof R] = value
|
|
@@ -67,13 +77,6 @@ export const entrypoint = <T, R extends AbstractRequest = AbstractRequest>(
|
|
|
67
77
|
|
|
68
78
|
_entrypoint.validate = validate(entrypointHandle)
|
|
69
79
|
|
|
70
|
-
_entrypoint.reinitializeContext = <T>(context: BasicContext<any>) => {
|
|
71
|
-
const newEntrypoint = entrypoint(_entrypoint.route, handler, opts)
|
|
72
|
-
newEntrypoint.ctx = context
|
|
73
|
-
|
|
74
|
-
return newEntrypoint as T
|
|
75
|
-
}
|
|
76
|
-
|
|
77
80
|
entrypointHandle.ref = _entrypoint
|
|
78
81
|
|
|
79
82
|
return _entrypoint
|
package/src/helper.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import type { ClientEntrypoint, ClientEntrypointOptions, RefedEntrypointHandler } from './types.js'
|
|
2
2
|
import { entrypoint } from './entrypoint.js'
|
|
3
|
-
import { isClientRouteModel } from '@owlmeans/client-route'
|
|
4
3
|
import type { AbstractRequest, CommonEntrypoint } from '@owlmeans/entrypoint'
|
|
5
4
|
import { normalizeHelperParams } from './utils/entrypoint.js'
|
|
6
5
|
import type { JSONSchemaType } from "ajv"
|
|
7
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Replace the entrypoint declared under `alias` with its elevated counterpart. Elevating is
|
|
9
|
+
* idempotent — calling it again simply replaces the element once more, and the guards it brings
|
|
10
|
+
* are added to the ones already declared.
|
|
11
|
+
*
|
|
12
|
+
* @throws {SyntaxError} when no entrypoint carries the alias
|
|
13
|
+
*/
|
|
8
14
|
export const elevate = <T = {}, R extends AbstractRequest = AbstractRequest>(
|
|
9
15
|
entrypoints: (CommonEntrypoint | ClientEntrypoint<T, R>)[],
|
|
10
16
|
alias: string,
|
|
@@ -17,9 +23,6 @@ export const elevate = <T = {}, R extends AbstractRequest = AbstractRequest>(
|
|
|
17
23
|
if (idx === -1) {
|
|
18
24
|
throw new SyntaxError(`Entrypoint with alias ${alias} not present`)
|
|
19
25
|
}
|
|
20
|
-
if (isClientRouteModel(entrypoints[idx].route) && opts?.force !== true) {
|
|
21
|
-
throw new SyntaxError(`Entrypoint with alias ${alias} is already elevated`)
|
|
22
|
-
}
|
|
23
26
|
|
|
24
27
|
entrypoints[idx] = entrypoint(entrypoints[idx], handler, opts)
|
|
25
28
|
|
package/src/types.ts
CHANGED
|
@@ -1,18 +1,47 @@
|
|
|
1
1
|
import type { ClientRouteModel, ClientRouteOptions } from '@owlmeans/client-route'
|
|
2
|
-
import type { AbstractRequest,
|
|
2
|
+
import type { AbstractRequest, CommonEntrypoint, CommonEntrypointOptions, EntrypointHandler, EntrypointOutcome } from '@owlmeans/entrypoint'
|
|
3
3
|
|
|
4
4
|
export interface ClientEntrypoint<T = {}, R extends ClientRequest = ClientRequest> extends CommonEntrypoint {
|
|
5
5
|
route: ClientRouteModel
|
|
6
|
+
/**
|
|
7
|
+
* Address the entrypoint and resolve to what it answered. The reply's error is thrown, so a
|
|
8
|
+
* caller that only needs the value never inspects an outcome.
|
|
9
|
+
*/
|
|
6
10
|
call: EntrypointCall<T, R>
|
|
11
|
+
/**
|
|
12
|
+
* The same round trip as {@link ClientEntrypoint.call}, resolving to the value AND the outcome.
|
|
13
|
+
* Use it only where the outcome decides what happens next.
|
|
14
|
+
*/
|
|
15
|
+
invoke: EntrypointInvoke<T, R>
|
|
16
|
+
/**
|
|
17
|
+
* Build the URL this entrypoint addresses, with `:params` filled in and the query appended.
|
|
18
|
+
* Absolute when the route belongs to another service, or when `absolute` is asked for.
|
|
19
|
+
*/
|
|
20
|
+
url: EntrypointUrl<R>
|
|
7
21
|
validate: EntrypointFilter<R>
|
|
8
|
-
getPath: (partial?: boolean) => string
|
|
9
22
|
request: (request?: Partial<R>) => R
|
|
10
23
|
}
|
|
11
24
|
|
|
12
25
|
export interface EntrypointCall<T, Req extends ClientRequest = ClientRequest> {
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
26
|
+
<Type extends T, R extends Req = Req>(req?: Partial<R>): Promise<Type>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface EntrypointInvoke<T, Req extends ClientRequest = ClientRequest> {
|
|
30
|
+
<Type extends T, R extends Req = Req>(req?: Partial<R>): Promise<EntrypointReply<Type>>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface EntrypointReply<T> {
|
|
34
|
+
value: T
|
|
35
|
+
outcome: EntrypointOutcome
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface EntrypointUrl<Req extends ClientRequest = ClientRequest> {
|
|
39
|
+
<R extends Req = Req>(req?: Partial<R>, opts?: EntrypointUrlOptions): Promise<string>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface EntrypointUrlOptions {
|
|
43
|
+
/** Force a fully qualified URL even when the route belongs to the current service. */
|
|
44
|
+
absolute?: boolean
|
|
16
45
|
}
|
|
17
46
|
|
|
18
47
|
export interface EntrypointFilter<Req extends AbstractRequest = AbstractRequest> {
|
|
@@ -20,14 +49,9 @@ export interface EntrypointFilter<Req extends AbstractRequest = AbstractRequest>
|
|
|
20
49
|
}
|
|
21
50
|
|
|
22
51
|
export interface ClientRequest<T extends {} = {}> extends AbstractRequest<T> {
|
|
23
|
-
full?: boolean
|
|
24
52
|
}
|
|
25
53
|
|
|
26
54
|
export interface ClientEntrypointOptions extends CommonEntrypointOptions {
|
|
27
|
-
/**
|
|
28
|
-
* Force entrypoint to be elevated even if it is already elevated
|
|
29
|
-
*/
|
|
30
|
-
force?: boolean
|
|
31
55
|
routeOptions?: ClientRouteOptions
|
|
32
56
|
validateOnCall?: boolean
|
|
33
57
|
}
|
package/src/utils/handler.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { ApiClient } from '@owlmeans/api'
|
|
2
2
|
import { DEFAULT_KEY } from '@owlmeans/client-config'
|
|
3
3
|
import type { ClientConfig, ClientContext } from '@owlmeans/client-context'
|
|
4
|
-
import type { AbstractRequest, EntrypointHandler } from '@owlmeans/entrypoint'
|
|
5
|
-
import { EntrypointOutcome, provideResponse } from '@owlmeans/entrypoint'
|
|
6
|
-
import type { ClientEntrypoint,
|
|
4
|
+
import type { AbstractRequest, EntrypointHandler, EntrypointTransport } from '@owlmeans/entrypoint'
|
|
5
|
+
import { EntrypointOutcome, provideResponse, transportAlias } from '@owlmeans/entrypoint'
|
|
6
|
+
import type { ClientEntrypoint, EntrypointInvoke, EntrypointUrlOptions, ClientEntrypointOptions, EntrypointRef, ClientRequest } from '../types.js'
|
|
7
7
|
import { validate } from './entrypoint.js'
|
|
8
8
|
import { extractParams } from '@owlmeans/client-route'
|
|
9
9
|
import { PARAM } from '@owlmeans/route'
|
|
@@ -25,13 +25,24 @@ export const apiHandler: <
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const ep = context.entrypoint<ClientEntrypoint>(req.alias)
|
|
28
|
-
const route = await ep.route.resolve<Config, Context>(context)
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
// A route names the protocol it answers on, and a protocol may be carried by something other than
|
|
30
|
+
// HTTP — a queue, say. Whatever is bound under this protocol takes the call, so a consumer writes
|
|
31
|
+
// `ep.call(...)` and never learns which of them ran.
|
|
32
|
+
const transport = transportAlias(ep.route.route.protocol)
|
|
33
|
+
if (context.hasService(transport)) {
|
|
34
|
+
req.path = ep.path()
|
|
35
|
+
|
|
36
|
+
return context.service<EntrypointTransport>(transport).handle(req, res)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Which web client carries this call is decided by the service the route answers on — the one it
|
|
40
|
+
// names, or the one the context picks for its app type when it names none.
|
|
41
|
+
const route = ep.service()
|
|
42
|
+
|
|
43
|
+
const alias: string | undefined = typeof context.cfg.webService === 'string'
|
|
31
44
|
? context.cfg.webService
|
|
32
|
-
:
|
|
33
|
-
? context.cfg.webService[route.service] ?? context.cfg.webService[DEFAULT_KEY]
|
|
34
|
-
: context.cfg.webService[DEFAULT_KEY])
|
|
45
|
+
: context.cfg.webService[route.service] ?? context.cfg.webService[DEFAULT_KEY]
|
|
35
46
|
|
|
36
47
|
if (alias == null) {
|
|
37
48
|
throw new SyntaxError(`Can't cast web service alias for ${ep.alias} entrypoint`)
|
|
@@ -39,15 +50,15 @@ export const apiHandler: <
|
|
|
39
50
|
|
|
40
51
|
const service: ApiClient = context.service(alias)
|
|
41
52
|
|
|
42
|
-
req.path = ep.
|
|
53
|
+
req.path = ep.path()
|
|
43
54
|
|
|
44
55
|
return service.handler(req, res as any)
|
|
45
56
|
}
|
|
46
57
|
|
|
47
|
-
export const
|
|
58
|
+
export const apiInvoke: <
|
|
48
59
|
T, R extends AbstractRequest = AbstractRequest
|
|
49
|
-
>(ref: EntrypointRef<T, R>, opts?: ClientEntrypointOptions) =>
|
|
50
|
-
(ref, opts) => (async (req
|
|
60
|
+
>(ref: EntrypointRef<T, R>, opts?: ClientEntrypointOptions) => EntrypointInvoke<T, R> =
|
|
61
|
+
(ref, opts) => (async (req) => {
|
|
51
62
|
const ep = ref.ref
|
|
52
63
|
if (ep == null) {
|
|
53
64
|
throw new SyntaxError('Try to make API call before the entrypoint is created')
|
|
@@ -56,10 +67,9 @@ export const apiCall: <
|
|
|
56
67
|
if (ctx == null) {
|
|
57
68
|
throw new SyntaxError(`No context provided in apiCall for ${ep.alias} entrypoint`)
|
|
58
69
|
}
|
|
59
|
-
await ep.route.resolve(ctx)
|
|
60
70
|
|
|
61
71
|
if (req?.canceled) {
|
|
62
|
-
return
|
|
72
|
+
return { value: null, outcome: EntrypointOutcome.Ok }
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
const request: AbstractRequest = {
|
|
@@ -70,7 +80,7 @@ export const apiCall: <
|
|
|
70
80
|
query: req?.query ?? {},
|
|
71
81
|
host: req?.host,
|
|
72
82
|
base: req?.base,
|
|
73
|
-
path: ep.
|
|
83
|
+
path: ep.path(),
|
|
74
84
|
timeout: req?.timeout,
|
|
75
85
|
signal: req?.signal,
|
|
76
86
|
}
|
|
@@ -89,10 +99,6 @@ export const apiCall: <
|
|
|
89
99
|
throw e
|
|
90
100
|
}
|
|
91
101
|
}
|
|
92
|
-
if (res != null) {
|
|
93
|
-
await apiHandler(ref)(request, res)
|
|
94
|
-
return
|
|
95
|
-
}
|
|
96
102
|
const reply = provideResponse<unknown>()
|
|
97
103
|
if (ctx == null && ep.ctx == null) {
|
|
98
104
|
throw new SyntaxError(`Use entrypoint ${ep.alias} without context`)
|
|
@@ -102,37 +108,38 @@ export const apiCall: <
|
|
|
102
108
|
throw reply.error
|
|
103
109
|
}
|
|
104
110
|
|
|
105
|
-
return
|
|
106
|
-
}) as
|
|
111
|
+
return { value: reply.value ?? null, outcome: reply.outcome ?? EntrypointOutcome.Ok }
|
|
112
|
+
}) as EntrypointInvoke<any>
|
|
107
113
|
|
|
108
|
-
export const
|
|
114
|
+
export const entrypointUrl: <
|
|
109
115
|
T, R extends ClientRequest = ClientRequest
|
|
110
|
-
>(ref: EntrypointRef<T, R>, opts?:
|
|
116
|
+
>(ref: EntrypointRef<T, R>, req?: Partial<R>, opts?: EntrypointUrlOptions) => Promise<string> = async (ref, req, opts) => {
|
|
111
117
|
const ep = ref.ref
|
|
112
118
|
if (ep == null) {
|
|
113
119
|
throw new SyntaxError('Try to make URL before the entrypoint is created')
|
|
114
120
|
}
|
|
115
121
|
const ctx = ep.ctx
|
|
116
122
|
if (ctx == null) {
|
|
117
|
-
throw new SyntaxError(`No context provided in
|
|
123
|
+
throw new SyntaxError(`No context provided in entrypointUrl for ${ep.alias} entrypoint`)
|
|
118
124
|
}
|
|
119
|
-
await ep.route.resolve(ctx)
|
|
120
125
|
|
|
121
|
-
|
|
126
|
+
// The base is left off here: an in-service URL is addressed relative to it, and the absolute
|
|
127
|
+
// branch below has `makeUrl` prepend it.
|
|
128
|
+
const epPath = ep.path()
|
|
129
|
+
const pathParams = extractParams(epPath)
|
|
122
130
|
let path = pathParams.reduce((p, param) => {
|
|
123
131
|
return p.replace(`${PARAM}${param}`, `${req?.params?.[param as keyof typeof req.params]}`)
|
|
124
|
-
},
|
|
132
|
+
}, epPath) + (req?.query != null ? `?${stringify(req?.query)}` : '')
|
|
125
133
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
134
|
+
// Locality is a question about the RESOLVED service, not about what the declaration happens to
|
|
135
|
+
// name: a route that names no service belongs to the asking context, and addressing it absolutely
|
|
136
|
+
// would turn in-app navigation into a full page load.
|
|
137
|
+
if (!ep.isLocal() || opts?.absolute === true) {
|
|
129
138
|
const helper = makeSecurityHelper(ctx)
|
|
130
139
|
path = helper.makeUrl(
|
|
131
|
-
ep.
|
|
140
|
+
ep.address(), path, { host: req?.host, base: req?.base, forceUnsecure: req?.unsecure }
|
|
132
141
|
)
|
|
133
142
|
}
|
|
134
143
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
return [path as any, EntrypointOutcome.Ok]
|
|
144
|
+
return path
|
|
138
145
|
}
|