@owlmeans/client-entrypoint 0.1.3
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 +77 -0
- package/build/entrypoint.d.ts +6 -0
- package/build/entrypoint.d.ts.map +1 -0
- package/build/entrypoint.js +62 -0
- package/build/entrypoint.js.map +1 -0
- package/build/errors.d.ts +10 -0
- package/build/errors.d.ts.map +1 -0
- package/build/errors.js +17 -0
- package/build/errors.js.map +1 -0
- package/build/helper.d.ts +8 -0
- package/build/helper.d.ts.map +1 -0
- package/build/helper.js +37 -0
- package/build/helper.js.map +1 -0
- package/build/index.d.ts +5 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +4 -0
- package/build/index.js.map +1 -0
- package/build/types.d.ts +33 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/build/utils/entrypoint.d.ts +12 -0
- package/build/utils/entrypoint.d.ts.map +1 -0
- package/build/utils/entrypoint.js +51 -0
- package/build/utils/entrypoint.js.map +1 -0
- package/build/utils/handler.d.ts +6 -0
- package/build/utils/handler.d.ts.map +1 -0
- package/build/utils/handler.js +104 -0
- package/build/utils/handler.js.map +1 -0
- package/build/utils/index.d.ts +3 -0
- package/build/utils/index.d.ts.map +1 -0
- package/build/utils/index.js +3 -0
- package/build/utils/index.js.map +1 -0
- package/package.json +56 -0
- package/src/entrypoint.ts +88 -0
- package/src/errors.ts +23 -0
- package/src/helper.ts +55 -0
- package/src/index.ts +5 -0
- package/src/types.ts +41 -0
- package/src/utils/entrypoint.ts +66 -0
- package/src/utils/handler.ts +136 -0
- package/src/utils/index.ts +3 -0
- package/tsconfig.json +10 -0
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# @owlmeans/client-entrypoint
|
|
2
|
+
|
|
3
|
+
Client-side entrypoint system: elevates route definitions into API-calling `ClientEntrypoint` instances.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
- `elevate(entrypoints, alias, handler?, opts?)` — attaches a client handler to an entrypoint (mirrors server `elevate`)
|
|
8
|
+
- `ClientEntrypoint<T>` has a `call(request?)` method that resolves the URL and makes an HTTP/WS request
|
|
9
|
+
- `stab` — no-op handler for entrypoints that only need URL resolution (no logic)
|
|
10
|
+
- `provideRequest(alias, path)` — creates an `AbstractRequest` for programmatic entrypoint calls
|
|
11
|
+
- `pickPerSchema(schema, obj)` — extracts fields from an object matching an AJV schema
|
|
12
|
+
- Re-exported as `celevate` from `@owlmeans/server-app`
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
bun add @owlmeans/client-entrypoint
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
Define and elevate a client entrypoint for API calls:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { elevate, stab } from '@owlmeans/client-entrypoint'
|
|
26
|
+
import type { ClientEntrypoint } from '@owlmeans/client-entrypoint'
|
|
27
|
+
|
|
28
|
+
const appModules = [
|
|
29
|
+
entrypoint(route('project-list', '/projects', frontend('base'))),
|
|
30
|
+
entrypoint(route('project-create', '/projects', backend(RouteMethod.POST))),
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
// Frontend navigation — just a stub, no network call
|
|
34
|
+
elevate(appModules, 'project-list', stab)
|
|
35
|
+
|
|
36
|
+
// Backend API call — call() makes a POST request
|
|
37
|
+
elevate(appModules, 'project-create')
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Call an entrypoint from a service:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
const agentEntrypoint = ctx.entrypoint<ClientEntrypoint<Project>>(agent.project.create)
|
|
44
|
+
const [result] = await agentEntrypoint.call({
|
|
45
|
+
body: { prompt: payload.prompt, entity: req.auth?.entityId }
|
|
46
|
+
})
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## API
|
|
50
|
+
|
|
51
|
+
### `elevate<T, R>(entrypoints, alias, handler?, opts?): ClientEntrypoint<T, R>[]`
|
|
52
|
+
|
|
53
|
+
Mutates `entrypoints` in-place and returns the array typed as `ClientEntrypoint`. The `handler` sets how `call()` behaves.
|
|
54
|
+
|
|
55
|
+
### `stab: RefedEntrypointHandler`
|
|
56
|
+
|
|
57
|
+
No-op handler for frontend-only entrypoints that just need URL resolution.
|
|
58
|
+
|
|
59
|
+
### `ClientEntrypoint<T>` (type)
|
|
60
|
+
|
|
61
|
+
- `call(request?)` — resolves URL, makes HTTP request, returns `[T, EntrypointOutcome]`
|
|
62
|
+
- `validate(request?)` — validates the request against the entrypoint filter schema
|
|
63
|
+
- `getPath(partial?)` — returns the URL path (with or without path params)
|
|
64
|
+
|
|
65
|
+
### `provideRequest<T>(alias, path): AbstractRequest<T>`
|
|
66
|
+
|
|
67
|
+
Creates a minimal request object for programmatic `call()` invocations.
|
|
68
|
+
|
|
69
|
+
### `pickPerSchema<T>(schema, obj): Partial<T>`
|
|
70
|
+
|
|
71
|
+
Extracts only the keys present in the AJV schema from `obj`.
|
|
72
|
+
|
|
73
|
+
## Related Packages
|
|
74
|
+
|
|
75
|
+
- [`@owlmeans/entrypoint`](../entrypoint) — `CommonEntrypoint` base that gets elevated
|
|
76
|
+
- [`@owlmeans/client`](../client) — `useNavigate` uses `ClientEntrypoint.call()`
|
|
77
|
+
- [`@owlmeans/server-app`](../server-app) — re-exports `elevate` as `celevate`
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ClientRouteModel } from '@owlmeans/client-route';
|
|
2
|
+
import type { ClientEntrypoint, ClientEntrypointOptions, RefedEntrypointHandler } from './types.js';
|
|
3
|
+
import type { AbstractRequest, CommonEntrypoint } from '@owlmeans/entrypoint';
|
|
4
|
+
import type { CommonRouteModel } from '@owlmeans/route';
|
|
5
|
+
export declare const entrypoint: <T, R extends AbstractRequest = AbstractRequest>(arg: CommonEntrypoint | ClientRouteModel | CommonRouteModel, handler?: RefedEntrypointHandler<T, R> | ClientEntrypointOptions | boolean, opts?: ClientEntrypointOptions | boolean) => ClientEntrypoint<T, R>;
|
|
6
|
+
//# sourceMappingURL=entrypoint.d.ts.map
|
|
@@ -0,0 +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;AAO7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAGvD,eAAO,MAAM,UAAU,GAAI,CAAC,EAAE,CAAC,SAAS,eAAe,GAAG,eAAe,EACvE,KAAK,gBAAgB,GAAG,gBAAgB,GAAG,gBAAgB,EAC3D,UAAU,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,uBAAuB,GAAG,OAAO,EAC1E,OAAO,uBAAuB,GAAG,OAAO,KACvC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CA+DvB,CAAA"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { isEntrypoint, makeBasicEntrypoint, normalizeHelperParams, validate } from './utils/entrypoint.js';
|
|
2
|
+
import { isClientRouteModel, route } from '@owlmeans/client-route';
|
|
3
|
+
import { apiCall, apiHandler, urlCall } from './utils/handler.js';
|
|
4
|
+
import { AppType } from '@owlmeans/context';
|
|
5
|
+
import { normalizePath } from '@owlmeans/route';
|
|
6
|
+
import { provideRequest } from './helper.js';
|
|
7
|
+
export const entrypoint = (arg, handler, opts) => {
|
|
8
|
+
const entrypointHandle = { ref: undefined };
|
|
9
|
+
let _entrypoint;
|
|
10
|
+
[handler, opts] = normalizeHelperParams(handler, opts);
|
|
11
|
+
const _handler = handler ??
|
|
12
|
+
(('route' in arg.route ? arg.route.route.type : arg.route.type)
|
|
13
|
+
=== AppType.Backend ? apiHandler : undefined);
|
|
14
|
+
if (isEntrypoint(arg)) {
|
|
15
|
+
assertExplicitHandler(arg.route.route.type, handler);
|
|
16
|
+
const routeModel = route(arg.route, opts?.routeOptions);
|
|
17
|
+
_entrypoint = arg;
|
|
18
|
+
_entrypoint.route = routeModel;
|
|
19
|
+
_entrypoint.guards = opts?.guards ?? arg.guards;
|
|
20
|
+
_entrypoint.filter = opts?.filter ?? arg.filter;
|
|
21
|
+
_entrypoint.gate = opts?.gate ?? arg.gate;
|
|
22
|
+
_entrypoint.gateParams = opts?.gateParams ?? arg.gateParams;
|
|
23
|
+
}
|
|
24
|
+
else if (isClientRouteModel(arg)) {
|
|
25
|
+
assertExplicitHandler(arg.route.type, handler);
|
|
26
|
+
_entrypoint = makeBasicEntrypoint(arg, { ...opts });
|
|
27
|
+
_entrypoint.route = arg;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
assertExplicitHandler(arg.route.type, handler);
|
|
31
|
+
const _route = route(arg, opts?.routeOptions);
|
|
32
|
+
_entrypoint = makeBasicEntrypoint(_route, { ...opts });
|
|
33
|
+
_entrypoint.route = _route;
|
|
34
|
+
}
|
|
35
|
+
_entrypoint.getPath = (partial) => partial === true ? normalizePath(_entrypoint.route.route.partialPath) : _entrypoint.route.route.path;
|
|
36
|
+
_entrypoint.call = handler != null ? urlCall(entrypointHandle, opts) : apiCall(entrypointHandle, opts);
|
|
37
|
+
_entrypoint.request = ((request) => {
|
|
38
|
+
if (entrypointHandle.ref == null) {
|
|
39
|
+
throw SyntaxError(`Try to request uninitialized entrypoint ${JSON.stringify(arg)}`);
|
|
40
|
+
}
|
|
41
|
+
const _request = provideRequest(entrypointHandle.ref.getAlias(), entrypointHandle.ref.getPath());
|
|
42
|
+
request != null && Object.entries(request).forEach(([key, value]) => {
|
|
43
|
+
_request[key] = value;
|
|
44
|
+
});
|
|
45
|
+
return _request;
|
|
46
|
+
});
|
|
47
|
+
_entrypoint.handle = _handler?.(entrypointHandle);
|
|
48
|
+
_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
|
+
entrypointHandle.ref = _entrypoint;
|
|
55
|
+
return _entrypoint;
|
|
56
|
+
};
|
|
57
|
+
const assertExplicitHandler = (type, handler) => {
|
|
58
|
+
if (type === AppType.Backend && handler != null) {
|
|
59
|
+
throw new SyntaxError('We can\'t provide explicit handler to backend client entrypoint');
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=entrypoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entrypoint.js","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ResilientError } from '@owlmeans/error';
|
|
2
|
+
export declare class ClientEntrypointError extends ResilientError {
|
|
3
|
+
static typeName: string;
|
|
4
|
+
constructor(message: string);
|
|
5
|
+
}
|
|
6
|
+
export declare class ClientValidationError extends ClientEntrypointError {
|
|
7
|
+
static typeName: string;
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +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;gBAEzC,OAAO,EAAE,MAAM;CAG5B;AAED,qBAAa,qBAAsB,SAAQ,qBAAqB;IAC9D,OAAuB,QAAQ,SAAgD;gBAEnE,OAAO,EAAE,MAAM;CAI5B"}
|
package/build/errors.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ResilientError } from '@owlmeans/error';
|
|
2
|
+
export class ClientEntrypointError extends ResilientError {
|
|
3
|
+
static typeName = 'ClientModuleError';
|
|
4
|
+
constructor(message) {
|
|
5
|
+
super(ClientEntrypointError.typeName, `clinet-module:${message}`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export class ClientValidationError extends ClientEntrypointError {
|
|
9
|
+
static typeName = `${ClientEntrypointError.typeName}Validation`;
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(`validation:${message}`);
|
|
12
|
+
this.type = ClientValidationError.typeName;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
ResilientError.registerErrorClass(ClientEntrypointError);
|
|
16
|
+
ResilientError.registerErrorClass(ClientValidationError);
|
|
17
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +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;;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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ClientEntrypoint, ClientEntrypointOptions, RefedEntrypointHandler } from './types.js';
|
|
2
|
+
import type { AbstractRequest, CommonEntrypoint } from '@owlmeans/entrypoint';
|
|
3
|
+
import type { JSONSchemaType } from "ajv";
|
|
4
|
+
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
|
+
export declare const stab: RefedEntrypointHandler<{}>;
|
|
6
|
+
export declare const provideRequest: <T extends {} = {}>(alias: string, path: string) => AbstractRequest<T>;
|
|
7
|
+
export declare const pickPerSchema: <T, R>(object: T, schema: JSONSchemaType<R>) => Partial<R>;
|
|
8
|
+
//# sourceMappingURL=helper.d.ts.map
|
|
@@ -0,0 +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;AAGnG,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAE7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAA;AAEzC,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,EAcxB,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
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { entrypoint } from './entrypoint.js';
|
|
2
|
+
import { isClientRouteModel } from '@owlmeans/client-route';
|
|
3
|
+
import { normalizeHelperParams } from './utils/entrypoint.js';
|
|
4
|
+
export const elevate = (entrypoints, alias, handler, opts) => {
|
|
5
|
+
[handler, opts] = normalizeHelperParams(handler, opts);
|
|
6
|
+
const idx = entrypoints.findIndex(({ route }) => route.route.alias === alias);
|
|
7
|
+
if (idx === -1) {
|
|
8
|
+
throw new SyntaxError(`Entrypoint with alias ${alias} not present`);
|
|
9
|
+
}
|
|
10
|
+
if (isClientRouteModel(entrypoints[idx].route) && opts?.force !== true) {
|
|
11
|
+
throw new SyntaxError(`Entrypoint with alias ${alias} is already elevated`);
|
|
12
|
+
}
|
|
13
|
+
entrypoints[idx] = entrypoint(entrypoints[idx], handler, opts);
|
|
14
|
+
return entrypoints;
|
|
15
|
+
};
|
|
16
|
+
export const stab = () => () => {
|
|
17
|
+
return void 0;
|
|
18
|
+
};
|
|
19
|
+
export const provideRequest = (alias, path) => {
|
|
20
|
+
const request = {
|
|
21
|
+
alias,
|
|
22
|
+
params: {},
|
|
23
|
+
headers: {},
|
|
24
|
+
query: {},
|
|
25
|
+
path,
|
|
26
|
+
canceled: false,
|
|
27
|
+
cancel: () => request.canceled = true
|
|
28
|
+
};
|
|
29
|
+
return request;
|
|
30
|
+
};
|
|
31
|
+
export const pickPerSchema = (object, schema) => Object.keys(schema.properties).reduce((acc, key) => {
|
|
32
|
+
if (object[key] != null) {
|
|
33
|
+
acc[key] = object[key];
|
|
34
|
+
}
|
|
35
|
+
return acc;
|
|
36
|
+
}, {});
|
|
37
|
+
//# sourceMappingURL=helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAE3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAG7D,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;IACD,IAAI,kBAAkB,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,CAAC;QACvE,MAAM,IAAI,WAAW,CAAC,yBAAyB,KAAK,sBAAsB,CAAC,CAAA;IAC7E,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/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAC3B,mBAAmB,YAAY,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAE3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA"}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ClientRouteModel, ClientRouteOptions } from '@owlmeans/client-route';
|
|
2
|
+
import type { AbstractRequest, AbstractResponse, CommonEntrypoint, CommonEntrypointOptions, EntrypointHandler, EntrypointOutcome } from '@owlmeans/entrypoint';
|
|
3
|
+
export interface ClientEntrypoint<T = {}, R extends ClientRequest = ClientRequest> extends CommonEntrypoint {
|
|
4
|
+
route: ClientRouteModel;
|
|
5
|
+
call: EntrypointCall<T, R>;
|
|
6
|
+
validate: EntrypointFilter<R>;
|
|
7
|
+
getPath: (partial?: boolean) => string;
|
|
8
|
+
request: (request?: Partial<R>) => R;
|
|
9
|
+
}
|
|
10
|
+
export interface EntrypointCall<T, Req extends ClientRequest = ClientRequest> {
|
|
11
|
+
<Type extends T, R extends Req = Req, P extends AbstractResponse<Type> = AbstractResponse<Type>>(req?: Partial<R>, res?: P): Promise<[Type, EntrypointOutcome]>;
|
|
12
|
+
}
|
|
13
|
+
export interface EntrypointFilter<Req extends AbstractRequest = AbstractRequest> {
|
|
14
|
+
<R extends Req>(req?: Partial<R>): Promise<boolean>;
|
|
15
|
+
}
|
|
16
|
+
export interface ClientRequest<T extends {} = {}> extends AbstractRequest<T> {
|
|
17
|
+
full?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface ClientEntrypointOptions extends CommonEntrypointOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Force entrypoint to be elevated even if it is already elevated
|
|
22
|
+
*/
|
|
23
|
+
force?: boolean;
|
|
24
|
+
routeOptions?: ClientRouteOptions;
|
|
25
|
+
validateOnCall?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface EntrypointRef<T, R extends AbstractRequest = AbstractRequest> {
|
|
28
|
+
ref?: ClientEntrypoint<T, R>;
|
|
29
|
+
}
|
|
30
|
+
export interface RefedEntrypointHandler<T, R extends AbstractRequest = AbstractRequest> {
|
|
31
|
+
(ref: EntrypointRef<T, R>): EntrypointHandler;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +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,gBAAgB,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAE9J,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,aAAa,GAAG,aAAa,CAAE,SAAQ,gBAAgB;IACzG,KAAK,EAAE,gBAAgB,CAAA;IACvB,IAAI,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC1B,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;IAC7B,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,MAAM,CAAA;IACtC,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,CACE,IAAI,SAAS,CAAC,EAAE,CAAC,SAAS,GAAG,GAAG,GAAG,EAAE,CAAC,SAAS,gBAAgB,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC,IAAI,CAAC,EAC9F,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAA;CACjE;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;IAC1E,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACtE;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,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"}
|
package/build/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { EntrypointFilter, ClientEntrypointOptions } from '../types.js';
|
|
2
|
+
import type { AbstractRequest } from '@owlmeans/entrypoint';
|
|
3
|
+
import type { EntrypointRef, RefedEntrypointHandler } from '../types.js';
|
|
4
|
+
export { entrypoint as makeBasicEntrypoint } from '@owlmeans/entrypoint';
|
|
5
|
+
export { isEntrypoint } from '@owlmeans/entrypoint/utils';
|
|
6
|
+
/**
|
|
7
|
+
* @throws {SyntaxError} if data shape doesn't match validation
|
|
8
|
+
* @throws {ClientValidationError} if request is not valid
|
|
9
|
+
*/
|
|
10
|
+
export declare const validate: <T, R extends AbstractRequest = AbstractRequest>(ref: EntrypointRef<T, R>) => EntrypointFilter;
|
|
11
|
+
export declare const normalizeHelperParams: <T, R extends AbstractRequest = AbstractRequest>(handler?: RefedEntrypointHandler<T, R> | ClientEntrypointOptions | boolean, opts?: ClientEntrypointOptions | boolean) => [RefedEntrypointHandler<T, R> | undefined, ClientEntrypointOptions | undefined];
|
|
12
|
+
//# sourceMappingURL=entrypoint.d.ts.map
|
|
@@ -0,0 +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,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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Ajv from 'ajv';
|
|
2
|
+
import { ClientValidationError } from '../errors.js';
|
|
3
|
+
import formatsPlugin from 'ajv-formats';
|
|
4
|
+
export { entrypoint as makeBasicEntrypoint } from '@owlmeans/entrypoint';
|
|
5
|
+
export { isEntrypoint } from '@owlmeans/entrypoint/utils';
|
|
6
|
+
const ajv = new Ajv({ strict: false });
|
|
7
|
+
formatsPlugin(ajv);
|
|
8
|
+
/**
|
|
9
|
+
* @throws {SyntaxError} if data shape doesn't match validation
|
|
10
|
+
* @throws {ClientValidationError} if request is not valid
|
|
11
|
+
*/
|
|
12
|
+
export const validate = (ref) => async (req) => {
|
|
13
|
+
const ep = ref.ref;
|
|
14
|
+
if (ep == null) {
|
|
15
|
+
throw new SyntaxError('Try to make API call before without entrypoint');
|
|
16
|
+
}
|
|
17
|
+
if (req?.alias == null) {
|
|
18
|
+
throw new SyntaxError(`Can't validate for unknown entrypoint (request.alias required)`);
|
|
19
|
+
}
|
|
20
|
+
if (ep.filter == null) {
|
|
21
|
+
throw new SyntaxError(`Entrypoint ${req.alias} has no filter to validate against`);
|
|
22
|
+
}
|
|
23
|
+
const results = await Promise.all(Object.entries(ep.filter).filter(([key]) => !['headers', 'response'].includes(key))
|
|
24
|
+
.map(async ([key, filter]) => {
|
|
25
|
+
if (req[key] == null) {
|
|
26
|
+
throw new SyntaxError(`Request has no required section ${key}`);
|
|
27
|
+
}
|
|
28
|
+
const validateFn = ajv.compile(filter);
|
|
29
|
+
validateFn(req[key]);
|
|
30
|
+
if (validateFn.errors == null) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return validateFn.errors;
|
|
35
|
+
}
|
|
36
|
+
}));
|
|
37
|
+
if (results.some((result) => result !== true)) {
|
|
38
|
+
const errors = results.find(result => result !== true && result != null);
|
|
39
|
+
throw new ClientValidationError(`${errors[0].instancePath}|${errors[0].message}`);
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
};
|
|
43
|
+
export const normalizeHelperParams = (handler, opts) => {
|
|
44
|
+
if (typeof handler !== 'function' && handler != null) {
|
|
45
|
+
opts = handler;
|
|
46
|
+
handler = undefined;
|
|
47
|
+
}
|
|
48
|
+
opts = typeof opts === 'boolean' ? { validateOnCall: opts } : opts;
|
|
49
|
+
return [handler, opts];
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=entrypoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entrypoint.js","sourceRoot":"","sources":["../../src/utils/entrypoint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AbstractRequest, EntrypointHandler } from '@owlmeans/entrypoint';
|
|
2
|
+
import type { EntrypointCall, ClientEntrypointOptions, EntrypointRef, ClientRequest } from '../types.js';
|
|
3
|
+
export declare const apiHandler: <T, R extends AbstractRequest = AbstractRequest>(ref: EntrypointRef<T, R>) => EntrypointHandler;
|
|
4
|
+
export declare const apiCall: <T, R extends AbstractRequest = AbstractRequest>(ref: EntrypointRef<T, R>, opts?: ClientEntrypointOptions) => EntrypointCall<T, R>;
|
|
5
|
+
export declare const urlCall: <T, R extends ClientRequest = ClientRequest>(ref: EntrypointRef<T, R>, opts?: ClientEntrypointOptions) => EntrypointCall<T, R>;
|
|
6
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/utils/handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAE9E,OAAO,KAAK,EAAoB,cAAc,EAAE,uBAAuB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAW1H,eAAO,MAAM,UAAU,EAAE,CACvB,CAAC,EAAE,CAAC,SAAS,eAAe,GAAG,eAAe,EAC9C,GAAG,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,iBA0B9B,CAAA;AAED,eAAO,MAAM,OAAO,EAAE,CACpB,CAAC,EAAE,CAAC,SAAS,eAAe,GAAG,eAAe,EAC9C,GAAG,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,uBAAuB,KAAK,cAAc,CAAC,CAAC,EAAE,CAAC,CAuDvD,CAAA;AAE3B,eAAO,MAAM,OAAO,EAAE,CACpB,CAAC,EAAE,CAAC,SAAS,aAAa,GAAG,aAAa,EAC1C,GAAG,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,uBAAuB,KAAK,cAAc,CAAC,CAAC,EAAE,CAAC,CA4BjF,CAAA"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { DEFAULT_KEY } from '@owlmeans/client-config';
|
|
2
|
+
import { EntrypointOutcome, provideResponse } from '@owlmeans/entrypoint';
|
|
3
|
+
import { validate } from './entrypoint.js';
|
|
4
|
+
import { extractParams } from '@owlmeans/client-route';
|
|
5
|
+
import { PARAM } from '@owlmeans/route';
|
|
6
|
+
import { stringify } from 'qs';
|
|
7
|
+
import { assertContext } from '@owlmeans/context';
|
|
8
|
+
import { makeSecurityHelper } from '@owlmeans/config';
|
|
9
|
+
export const apiHandler = (ref) => async (req, res) => {
|
|
10
|
+
const location = `client-entrypoint:api-handler:${ref.ref?.alias}`;
|
|
11
|
+
const context = assertContext(ref.ref?.ctx, location);
|
|
12
|
+
if (context.cfg.webService == null) {
|
|
13
|
+
throw new SyntaxError('No webService provided');
|
|
14
|
+
}
|
|
15
|
+
const ep = context.entrypoint(req.alias);
|
|
16
|
+
const route = await ep.route.resolve(context);
|
|
17
|
+
let alias = typeof context.cfg.webService === 'string'
|
|
18
|
+
? context.cfg.webService
|
|
19
|
+
: (route.service != null
|
|
20
|
+
? context.cfg.webService[route.service] ?? context.cfg.webService[DEFAULT_KEY]
|
|
21
|
+
: context.cfg.webService[DEFAULT_KEY]);
|
|
22
|
+
if (alias == null) {
|
|
23
|
+
throw new SyntaxError(`Can't cast web service alias for ${ep.alias} entrypoint`);
|
|
24
|
+
}
|
|
25
|
+
const service = context.service(alias);
|
|
26
|
+
req.path = ep.getPath();
|
|
27
|
+
return service.handler(req, res);
|
|
28
|
+
};
|
|
29
|
+
export const apiCall = (ref, opts) => (async (req, res) => {
|
|
30
|
+
const ep = ref.ref;
|
|
31
|
+
if (ep == null) {
|
|
32
|
+
throw new SyntaxError('Try to make API call before the entrypoint is created');
|
|
33
|
+
}
|
|
34
|
+
const ctx = ep.ctx;
|
|
35
|
+
if (ctx == null) {
|
|
36
|
+
throw new SyntaxError(`No context provided in apiCall for ${ep.alias} entrypoint`);
|
|
37
|
+
}
|
|
38
|
+
await ep.route.resolve(ctx);
|
|
39
|
+
if (req?.canceled) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const request = {
|
|
43
|
+
alias: ep.alias,
|
|
44
|
+
params: req?.params ?? {},
|
|
45
|
+
body: req?.body,
|
|
46
|
+
headers: req?.headers ?? {},
|
|
47
|
+
query: req?.query ?? {},
|
|
48
|
+
host: req?.host,
|
|
49
|
+
base: req?.base,
|
|
50
|
+
path: ep.getPath(),
|
|
51
|
+
};
|
|
52
|
+
if (req?.cancel != null) {
|
|
53
|
+
const cancel = req.cancel;
|
|
54
|
+
req.cancel = () => {
|
|
55
|
+
cancel();
|
|
56
|
+
request.canceled = true;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (opts?.validateOnCall) {
|
|
60
|
+
try {
|
|
61
|
+
await validate(ref)(request);
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
console.error(e);
|
|
65
|
+
throw e;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (res != null) {
|
|
69
|
+
await apiHandler(ref)(request, res);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const reply = provideResponse();
|
|
73
|
+
if (ctx == null && ep.ctx == null) {
|
|
74
|
+
throw new SyntaxError(`Use entrypoint ${ep.alias} without context`);
|
|
75
|
+
}
|
|
76
|
+
await apiHandler(ref)(request, reply);
|
|
77
|
+
if (reply.error != null) {
|
|
78
|
+
throw reply.error;
|
|
79
|
+
}
|
|
80
|
+
return [reply.value ?? null, reply.outcome ?? EntrypointOutcome.Ok];
|
|
81
|
+
});
|
|
82
|
+
export const urlCall = ref => async (req, res) => {
|
|
83
|
+
const ep = ref.ref;
|
|
84
|
+
if (ep == null) {
|
|
85
|
+
throw new SyntaxError('Try to make URL before the entrypoint is created');
|
|
86
|
+
}
|
|
87
|
+
const ctx = ep.ctx;
|
|
88
|
+
if (ctx == null) {
|
|
89
|
+
throw new SyntaxError(`No context provided in urlCall for ${ep.alias} entrypoint`);
|
|
90
|
+
}
|
|
91
|
+
await ep.route.resolve(ctx);
|
|
92
|
+
const pathParams = extractParams(ep.getPath());
|
|
93
|
+
let path = pathParams.reduce((p, param) => {
|
|
94
|
+
return p.replace(`${PARAM}${param}`, `${req?.params?.[param]}`);
|
|
95
|
+
}, ep.getPath()) + (req?.query != null ? `?${stringify(req?.query)}` : '');
|
|
96
|
+
if (ep.route.route.service !== null && (ctx.cfg.service !== ep.route.route.service
|
|
97
|
+
|| req?.full === true)) {
|
|
98
|
+
const helper = makeSecurityHelper(ctx);
|
|
99
|
+
path = helper.makeUrl(ep.route.route, path, { host: req?.host, base: req?.base, forceUnsecure: req?.unsecure });
|
|
100
|
+
}
|
|
101
|
+
res?.resolve(path, EntrypointOutcome.Ok);
|
|
102
|
+
return [path, EntrypointOutcome.Ok];
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/utils/handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@owlmeans/client-entrypoint",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc -b",
|
|
8
|
+
"dev": "sleep 102 && nodemon -e ts,tsx,json --watch src --exec \"tsc -p ./tsconfig.json\"",
|
|
9
|
+
"watch": "tsc -b -w --preserveWatchOutput --pretty"
|
|
10
|
+
},
|
|
11
|
+
"main": "build/index.js",
|
|
12
|
+
"module": "build/index.js",
|
|
13
|
+
"types": "build/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": "./build/index.js",
|
|
17
|
+
"require": "./build/index.js",
|
|
18
|
+
"default": "./build/index.js",
|
|
19
|
+
"module": "./build/index.js",
|
|
20
|
+
"types": "./build/index.d.ts"
|
|
21
|
+
},
|
|
22
|
+
"./utils": {
|
|
23
|
+
"import": "./build/utils/index.js",
|
|
24
|
+
"require": "./build/utils/index.js",
|
|
25
|
+
"default": "./build/utils/index.js",
|
|
26
|
+
"module": "./build/utils/index.js",
|
|
27
|
+
"types": "./build/utils/index.d.ts"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@owlmeans/api": "^0.1.3",
|
|
32
|
+
"@owlmeans/client-config": "^0.1.3",
|
|
33
|
+
"@owlmeans/client-context": "^0.1.3",
|
|
34
|
+
"@owlmeans/client-route": "^0.1.3",
|
|
35
|
+
"@owlmeans/config": "^0.1.3",
|
|
36
|
+
"@owlmeans/context": "^0.1.3",
|
|
37
|
+
"@owlmeans/entrypoint": "^0.1.3",
|
|
38
|
+
"@owlmeans/error": "^0.1.3",
|
|
39
|
+
"@owlmeans/route": "^0.1.3",
|
|
40
|
+
"ajv-formats": "^3.0.1",
|
|
41
|
+
"qs": "^6.13.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"ajv": "*"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@owlmeans/dep-config": "workspace:*",
|
|
48
|
+
"@types/qs": "^6.9.16",
|
|
49
|
+
"nodemon": "^3.1.11",
|
|
50
|
+
"npm-check": "^6.0.1",
|
|
51
|
+
"typescript": "^6.0.2"
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { ClientRouteModel } from '@owlmeans/client-route'
|
|
2
|
+
import type { ClientEntrypoint, ClientEntrypointOptions, EntrypointRef, RefedEntrypointHandler } from './types.js'
|
|
3
|
+
import type { AbstractRequest, CommonEntrypoint } from '@owlmeans/entrypoint'
|
|
4
|
+
import { isEntrypoint, makeBasicEntrypoint, normalizeHelperParams, validate } from './utils/entrypoint.js'
|
|
5
|
+
import { isClientRouteModel, route } from '@owlmeans/client-route'
|
|
6
|
+
import { apiCall, apiHandler, urlCall } from './utils/handler.js'
|
|
7
|
+
import { AppType } from '@owlmeans/context'
|
|
8
|
+
import type { BasicContext } from '@owlmeans/context'
|
|
9
|
+
import { normalizePath } from '@owlmeans/route'
|
|
10
|
+
import type { CommonRouteModel } from '@owlmeans/route'
|
|
11
|
+
import { provideRequest } from './helper.js'
|
|
12
|
+
|
|
13
|
+
export const entrypoint = <T, R extends AbstractRequest = AbstractRequest>(
|
|
14
|
+
arg: CommonEntrypoint | ClientRouteModel | CommonRouteModel,
|
|
15
|
+
handler?: RefedEntrypointHandler<T, R> | ClientEntrypointOptions | boolean,
|
|
16
|
+
opts?: ClientEntrypointOptions | boolean
|
|
17
|
+
): ClientEntrypoint<T, R> => {
|
|
18
|
+
const entrypointHandle: EntrypointRef<T, R> = { ref: undefined }
|
|
19
|
+
|
|
20
|
+
let _entrypoint: ClientEntrypoint<T, R>
|
|
21
|
+
|
|
22
|
+
;[handler, opts] = normalizeHelperParams(handler, opts)
|
|
23
|
+
|
|
24
|
+
const _handler = handler as RefedEntrypointHandler<T, R> | undefined ??
|
|
25
|
+
(('route' in arg.route ? arg.route.route.type : arg.route.type)
|
|
26
|
+
=== AppType.Backend ? apiHandler : undefined)
|
|
27
|
+
|
|
28
|
+
if (isEntrypoint(arg)) {
|
|
29
|
+
assertExplicitHandler(arg.route.route.type, handler as RefedEntrypointHandler<T, R>)
|
|
30
|
+
const routeModel = route(arg.route, opts?.routeOptions)
|
|
31
|
+
_entrypoint = arg as ClientEntrypoint<T, R>
|
|
32
|
+
_entrypoint.route = routeModel
|
|
33
|
+
_entrypoint.guards = opts?.guards ?? arg.guards
|
|
34
|
+
_entrypoint.filter = opts?.filter ?? arg.filter
|
|
35
|
+
_entrypoint.gate = opts?.gate ?? arg.gate
|
|
36
|
+
_entrypoint.gateParams = opts?.gateParams ?? arg.gateParams
|
|
37
|
+
} else if (isClientRouteModel(arg)) {
|
|
38
|
+
assertExplicitHandler(arg.route.type, handler as RefedEntrypointHandler<T, R>)
|
|
39
|
+
_entrypoint = makeBasicEntrypoint(arg, { ...opts }) as ClientEntrypoint<T, R>
|
|
40
|
+
_entrypoint.route = arg
|
|
41
|
+
} else {
|
|
42
|
+
assertExplicitHandler(arg.route.type, handler as RefedEntrypointHandler<T, R>)
|
|
43
|
+
const _route = route(arg, opts?.routeOptions)
|
|
44
|
+
_entrypoint = makeBasicEntrypoint(_route, { ...opts }) as ClientEntrypoint<T, R>
|
|
45
|
+
_entrypoint.route = _route
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
_entrypoint.getPath = (partial?: boolean) =>
|
|
49
|
+
partial === true ? normalizePath(_entrypoint.route.route.partialPath) : _entrypoint.route.route.path
|
|
50
|
+
|
|
51
|
+
_entrypoint.call = handler != null ? urlCall<T, R>(entrypointHandle, opts) : apiCall<T, R>(entrypointHandle, opts)
|
|
52
|
+
|
|
53
|
+
_entrypoint.request = ((request: R): R => {
|
|
54
|
+
if (entrypointHandle.ref == null) {
|
|
55
|
+
throw SyntaxError(`Try to request uninitialized entrypoint ${JSON.stringify(arg)}`)
|
|
56
|
+
}
|
|
57
|
+
const _request = provideRequest(entrypointHandle.ref.getAlias(), entrypointHandle.ref.getPath()) as R
|
|
58
|
+
|
|
59
|
+
request != null && Object.entries(request).forEach(([key, value]) => {
|
|
60
|
+
_request[key as keyof R] = value
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
return _request
|
|
64
|
+
}) as any
|
|
65
|
+
|
|
66
|
+
_entrypoint.handle = _handler?.(entrypointHandle)
|
|
67
|
+
|
|
68
|
+
_entrypoint.validate = validate(entrypointHandle)
|
|
69
|
+
|
|
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
|
+
entrypointHandle.ref = _entrypoint
|
|
78
|
+
|
|
79
|
+
return _entrypoint
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const assertExplicitHandler = <T, R extends AbstractRequest = AbstractRequest>(
|
|
83
|
+
type: AppType, handler: RefedEntrypointHandler<T, R> | undefined
|
|
84
|
+
) => {
|
|
85
|
+
if (type === AppType.Backend && handler != null) {
|
|
86
|
+
throw new SyntaxError('We can\'t provide explicit handler to backend client entrypoint')
|
|
87
|
+
}
|
|
88
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
import { ResilientError } from '@owlmeans/error'
|
|
3
|
+
|
|
4
|
+
export class ClientEntrypointError extends ResilientError {
|
|
5
|
+
public static override typeName = 'ClientModuleError'
|
|
6
|
+
|
|
7
|
+
constructor(message: string) {
|
|
8
|
+
super(ClientEntrypointError.typeName, `clinet-module:${message}`)
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class ClientValidationError extends ClientEntrypointError {
|
|
13
|
+
public static override typeName = `${ClientEntrypointError.typeName}Validation`
|
|
14
|
+
|
|
15
|
+
constructor(message: string) {
|
|
16
|
+
super(`validation:${message}`)
|
|
17
|
+
this.type = ClientValidationError.typeName
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
ResilientError.registerErrorClass(ClientEntrypointError)
|
|
23
|
+
ResilientError.registerErrorClass(ClientValidationError)
|
package/src/helper.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ClientEntrypoint, ClientEntrypointOptions, RefedEntrypointHandler } from './types.js'
|
|
2
|
+
import { entrypoint } from './entrypoint.js'
|
|
3
|
+
import { isClientRouteModel } from '@owlmeans/client-route'
|
|
4
|
+
import type { AbstractRequest, CommonEntrypoint } from '@owlmeans/entrypoint'
|
|
5
|
+
import { normalizeHelperParams } from './utils/entrypoint.js'
|
|
6
|
+
import type { JSONSchemaType } from "ajv"
|
|
7
|
+
|
|
8
|
+
export const elevate = <T = {}, R extends AbstractRequest = AbstractRequest>(
|
|
9
|
+
entrypoints: (CommonEntrypoint | ClientEntrypoint<T, R>)[],
|
|
10
|
+
alias: string,
|
|
11
|
+
handler?: RefedEntrypointHandler<T, R> | ClientEntrypointOptions | boolean,
|
|
12
|
+
opts?: ClientEntrypointOptions | boolean
|
|
13
|
+
): ClientEntrypoint<T, R>[] => {
|
|
14
|
+
[handler, opts] = normalizeHelperParams(handler, opts)
|
|
15
|
+
|
|
16
|
+
const idx = entrypoints.findIndex(({ route }) => route.route.alias === alias)
|
|
17
|
+
if (idx === -1) {
|
|
18
|
+
throw new SyntaxError(`Entrypoint with alias ${alias} not present`)
|
|
19
|
+
}
|
|
20
|
+
if (isClientRouteModel(entrypoints[idx].route) && opts?.force !== true) {
|
|
21
|
+
throw new SyntaxError(`Entrypoint with alias ${alias} is already elevated`)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
entrypoints[idx] = entrypoint(entrypoints[idx], handler, opts)
|
|
25
|
+
|
|
26
|
+
return entrypoints as ClientEntrypoint<T, R>[]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const stab: RefedEntrypointHandler<{}> = () => () => {
|
|
30
|
+
return void 0 as any
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const provideRequest = <T extends {} = {}>(alias: string, path: string): AbstractRequest<T> => {
|
|
34
|
+
const request = {
|
|
35
|
+
alias,
|
|
36
|
+
params: {},
|
|
37
|
+
headers: {},
|
|
38
|
+
query: {},
|
|
39
|
+
path,
|
|
40
|
+
canceled: false,
|
|
41
|
+
cancel: () => request.canceled = true
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return request
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const pickPerSchema = <T, R>(object: T, schema: JSONSchemaType<R>): Partial<R> =>
|
|
48
|
+
Object.keys(schema.properties).reduce(
|
|
49
|
+
(acc, key) => {
|
|
50
|
+
if (object[key as keyof T] != null) {
|
|
51
|
+
acc[key as keyof R] = object[key as keyof T] as unknown as R[keyof R]
|
|
52
|
+
}
|
|
53
|
+
return acc
|
|
54
|
+
}, {} as Partial<R>
|
|
55
|
+
)
|
package/src/index.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ClientRouteModel, ClientRouteOptions } from '@owlmeans/client-route'
|
|
2
|
+
import type { AbstractRequest, AbstractResponse, CommonEntrypoint, CommonEntrypointOptions, EntrypointHandler, EntrypointOutcome } from '@owlmeans/entrypoint'
|
|
3
|
+
|
|
4
|
+
export interface ClientEntrypoint<T = {}, R extends ClientRequest = ClientRequest> extends CommonEntrypoint {
|
|
5
|
+
route: ClientRouteModel
|
|
6
|
+
call: EntrypointCall<T, R>
|
|
7
|
+
validate: EntrypointFilter<R>
|
|
8
|
+
getPath: (partial?: boolean) => string
|
|
9
|
+
request: (request?: Partial<R>) => R
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface EntrypointCall<T, Req extends ClientRequest = ClientRequest> {
|
|
13
|
+
<
|
|
14
|
+
Type extends T, R extends Req = Req, P extends AbstractResponse<Type> = AbstractResponse<Type>
|
|
15
|
+
>(req?: Partial<R>, res?: P): Promise<[Type, EntrypointOutcome]>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface EntrypointFilter<Req extends AbstractRequest = AbstractRequest> {
|
|
19
|
+
<R extends Req>(req?: Partial<R>): Promise<boolean>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ClientRequest<T extends {} = {}> extends AbstractRequest<T> {
|
|
23
|
+
full?: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ClientEntrypointOptions extends CommonEntrypointOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Force entrypoint to be elevated even if it is already elevated
|
|
29
|
+
*/
|
|
30
|
+
force?: boolean
|
|
31
|
+
routeOptions?: ClientRouteOptions
|
|
32
|
+
validateOnCall?: boolean
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface EntrypointRef<T, R extends AbstractRequest = AbstractRequest> {
|
|
36
|
+
ref?: ClientEntrypoint<T, R>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface RefedEntrypointHandler<T, R extends AbstractRequest = AbstractRequest> {
|
|
40
|
+
(ref: EntrypointRef<T, R>): EntrypointHandler
|
|
41
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import Ajv from 'ajv'
|
|
2
|
+
import type { ErrorObject } from 'ajv'
|
|
3
|
+
import type { EntrypointFilter, ClientEntrypointOptions } from '../types.js'
|
|
4
|
+
import { ClientValidationError } from '../errors.js'
|
|
5
|
+
import type { AbstractRequest } from '@owlmeans/entrypoint'
|
|
6
|
+
import type { EntrypointRef, RefedEntrypointHandler } from '../types.js'
|
|
7
|
+
import formatsPlugin from 'ajv-formats'
|
|
8
|
+
|
|
9
|
+
export { entrypoint as makeBasicEntrypoint } from '@owlmeans/entrypoint'
|
|
10
|
+
export { isEntrypoint } from '@owlmeans/entrypoint/utils'
|
|
11
|
+
|
|
12
|
+
const ajv = new Ajv({ strict: false })
|
|
13
|
+
formatsPlugin(ajv as any)
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @throws {SyntaxError} if data shape doesn't match validation
|
|
17
|
+
* @throws {ClientValidationError} if request is not valid
|
|
18
|
+
*/
|
|
19
|
+
export const validate: <T, R extends AbstractRequest = AbstractRequest>(ref: EntrypointRef<T, R>) => EntrypointFilter =
|
|
20
|
+
(ref) => async (req) => {
|
|
21
|
+
const ep = ref.ref
|
|
22
|
+
if (ep == null) {
|
|
23
|
+
throw new SyntaxError('Try to make API call before without entrypoint')
|
|
24
|
+
}
|
|
25
|
+
if (req?.alias == null) {
|
|
26
|
+
throw new SyntaxError(`Can't validate for unknown entrypoint (request.alias required)`)
|
|
27
|
+
}
|
|
28
|
+
if (ep.filter == null) {
|
|
29
|
+
throw new SyntaxError(`Entrypoint ${req.alias} has no filter to validate against`)
|
|
30
|
+
}
|
|
31
|
+
const results = await Promise.all(Object.entries(ep.filter).filter(([key]) => !['headers', 'response'].includes(key))
|
|
32
|
+
.map(async ([key, filter]) => {
|
|
33
|
+
if (req[key as keyof typeof req] == null) {
|
|
34
|
+
throw new SyntaxError(`Request has no required section ${key}`)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const validateFn = ajv.compile(filter)
|
|
38
|
+
validateFn(req[key as keyof typeof req])
|
|
39
|
+
if (validateFn.errors == null) {
|
|
40
|
+
return true
|
|
41
|
+
} else {
|
|
42
|
+
return validateFn.errors
|
|
43
|
+
}
|
|
44
|
+
}))
|
|
45
|
+
if (results.some((result) => result !== true)) {
|
|
46
|
+
const errors = results.find(result => result !== true && result != null)! as ErrorObject[]
|
|
47
|
+
|
|
48
|
+
throw new ClientValidationError(`${errors[0].instancePath}|${errors[0].message}`)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return true
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const normalizeHelperParams = <T, R extends AbstractRequest = AbstractRequest>(
|
|
55
|
+
handler?: RefedEntrypointHandler<T, R> | ClientEntrypointOptions | boolean,
|
|
56
|
+
opts?: ClientEntrypointOptions | boolean
|
|
57
|
+
): [RefedEntrypointHandler<T, R> | undefined, ClientEntrypointOptions | undefined] => {
|
|
58
|
+
if (typeof handler !== 'function' && handler != null) {
|
|
59
|
+
opts = handler as ClientEntrypointOptions | boolean
|
|
60
|
+
handler = undefined
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
opts = typeof opts === 'boolean' ? { validateOnCall: opts } : opts
|
|
64
|
+
|
|
65
|
+
return [handler, opts]
|
|
66
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { ApiClient } from '@owlmeans/api'
|
|
2
|
+
import { DEFAULT_KEY } from '@owlmeans/client-config'
|
|
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, EntrypointCall, ClientEntrypointOptions, EntrypointRef, ClientRequest } from '../types.js'
|
|
7
|
+
import { validate } from './entrypoint.js'
|
|
8
|
+
import { extractParams } from '@owlmeans/client-route'
|
|
9
|
+
import { PARAM } from '@owlmeans/route'
|
|
10
|
+
import { stringify } from 'qs'
|
|
11
|
+
import { assertContext } from '@owlmeans/context'
|
|
12
|
+
import { makeSecurityHelper } from '@owlmeans/config'
|
|
13
|
+
|
|
14
|
+
type Config = ClientConfig
|
|
15
|
+
interface Context<C extends Config = Config> extends ClientContext<C> { }
|
|
16
|
+
|
|
17
|
+
export const apiHandler: <
|
|
18
|
+
T, R extends AbstractRequest = AbstractRequest
|
|
19
|
+
>(ref: EntrypointRef<T, R>) => EntrypointHandler = (ref) => async (req, res) => {
|
|
20
|
+
const location = `client-entrypoint:api-handler:${ref.ref?.alias}`
|
|
21
|
+
const context = assertContext<Config, Context>(ref.ref?.ctx as Context, location)
|
|
22
|
+
|
|
23
|
+
if (context.cfg.webService == null) {
|
|
24
|
+
throw new SyntaxError('No webService provided')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const ep = context.entrypoint<ClientEntrypoint>(req.alias)
|
|
28
|
+
const route = await ep.route.resolve<Config, Context>(context)
|
|
29
|
+
|
|
30
|
+
let alias: string | undefined = typeof context.cfg.webService === 'string'
|
|
31
|
+
? context.cfg.webService
|
|
32
|
+
: (route.service != null
|
|
33
|
+
? context.cfg.webService[route.service] ?? context.cfg.webService[DEFAULT_KEY]
|
|
34
|
+
: context.cfg.webService[DEFAULT_KEY])
|
|
35
|
+
|
|
36
|
+
if (alias == null) {
|
|
37
|
+
throw new SyntaxError(`Can't cast web service alias for ${ep.alias} entrypoint`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const service: ApiClient = context.service(alias)
|
|
41
|
+
|
|
42
|
+
req.path = ep.getPath()
|
|
43
|
+
|
|
44
|
+
return service.handler(req, res as any)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const apiCall: <
|
|
48
|
+
T, R extends AbstractRequest = AbstractRequest
|
|
49
|
+
>(ref: EntrypointRef<T, R>, opts?: ClientEntrypointOptions) => EntrypointCall<T, R> =
|
|
50
|
+
(ref, opts) => (async (req, res) => {
|
|
51
|
+
const ep = ref.ref
|
|
52
|
+
if (ep == null) {
|
|
53
|
+
throw new SyntaxError('Try to make API call before the entrypoint is created')
|
|
54
|
+
}
|
|
55
|
+
const ctx = ep.ctx
|
|
56
|
+
if (ctx == null) {
|
|
57
|
+
throw new SyntaxError(`No context provided in apiCall for ${ep.alias} entrypoint`)
|
|
58
|
+
}
|
|
59
|
+
await ep.route.resolve(ctx)
|
|
60
|
+
|
|
61
|
+
if (req?.canceled) {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const request: AbstractRequest = {
|
|
66
|
+
alias: ep.alias,
|
|
67
|
+
params: req?.params ?? {},
|
|
68
|
+
body: req?.body,
|
|
69
|
+
headers: req?.headers ?? {},
|
|
70
|
+
query: req?.query ?? {},
|
|
71
|
+
host: req?.host,
|
|
72
|
+
base: req?.base,
|
|
73
|
+
path: ep.getPath(),
|
|
74
|
+
}
|
|
75
|
+
if (req?.cancel != null) {
|
|
76
|
+
const cancel = req.cancel
|
|
77
|
+
req.cancel = () => {
|
|
78
|
+
cancel()
|
|
79
|
+
request.canceled = true
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (opts?.validateOnCall) {
|
|
83
|
+
try {
|
|
84
|
+
await validate(ref)(request)
|
|
85
|
+
} catch (e) {
|
|
86
|
+
console.error(e)
|
|
87
|
+
throw e
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (res != null) {
|
|
91
|
+
await apiHandler(ref)(request, res)
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
const reply = provideResponse<unknown>()
|
|
95
|
+
if (ctx == null && ep.ctx == null) {
|
|
96
|
+
throw new SyntaxError(`Use entrypoint ${ep.alias} without context`)
|
|
97
|
+
}
|
|
98
|
+
await apiHandler(ref)(request, reply)
|
|
99
|
+
if (reply.error != null) {
|
|
100
|
+
throw reply.error
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return [reply.value ?? null, reply.outcome ?? EntrypointOutcome.Ok]
|
|
104
|
+
}) as EntrypointCall<any>
|
|
105
|
+
|
|
106
|
+
export const urlCall: <
|
|
107
|
+
T, R extends ClientRequest = ClientRequest
|
|
108
|
+
>(ref: EntrypointRef<T, R>, opts?: ClientEntrypointOptions) => EntrypointCall<T, R> = ref => async (req, res) => {
|
|
109
|
+
const ep = ref.ref
|
|
110
|
+
if (ep == null) {
|
|
111
|
+
throw new SyntaxError('Try to make URL before the entrypoint is created')
|
|
112
|
+
}
|
|
113
|
+
const ctx = ep.ctx
|
|
114
|
+
if (ctx == null) {
|
|
115
|
+
throw new SyntaxError(`No context provided in urlCall for ${ep.alias} entrypoint`)
|
|
116
|
+
}
|
|
117
|
+
await ep.route.resolve(ctx)
|
|
118
|
+
|
|
119
|
+
const pathParams = extractParams(ep.getPath())
|
|
120
|
+
let path = pathParams.reduce((p, param) => {
|
|
121
|
+
return p.replace(`${PARAM}${param}`, `${req?.params?.[param as keyof typeof req.params]}`)
|
|
122
|
+
}, ep.getPath()) + (req?.query != null ? `?${stringify(req?.query)}` : '')
|
|
123
|
+
|
|
124
|
+
if (ep.route.route.service !== null && (
|
|
125
|
+
ctx.cfg.service !== ep.route.route.service
|
|
126
|
+
|| req?.full === true)) {
|
|
127
|
+
const helper = makeSecurityHelper(ctx)
|
|
128
|
+
path = helper.makeUrl(
|
|
129
|
+
ep.route.route, path, { host: req?.host, base: req?.base, forceUnsecure: req?.unsecure }
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
res?.resolve(path as any, EntrypointOutcome.Ok)
|
|
134
|
+
|
|
135
|
+
return [path as any, EntrypointOutcome.Ok]
|
|
136
|
+
}
|