@forestadmin/agent 1.0.0-beta.26 → 1.0.0-beta.29
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/CHANGELOG.md +21 -0
- package/dist/agent/forestadmin-http-driver.d.ts +5 -27
- package/dist/agent/forestadmin-http-driver.js +21 -61
- package/dist/agent/routes/base-route.d.ts +0 -1
- package/dist/agent/routes/base-route.js +1 -4
- package/dist/builder/agent.d.ts +32 -14
- package/dist/builder/agent.js +158 -28
- package/dist/builder/types.d.ts +3 -0
- package/dist/builder/utils/options-validator.d.ts +13 -0
- package/dist/builder/utils/options-validator.js +103 -0
- package/dist/builder/{typing-generator.d.ts → utils/typing-generator.d.ts} +0 -0
- package/dist/builder/utils/typing-generator.js +98 -0
- package/package.json +12 -2
- package/dist/agent/utils/http-driver-options.d.ts +0 -13
- package/dist/agent/utils/http-driver-options.js +0 -100
- package/dist/builder/typing-generator.js +0 -98
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# @forestadmin/agent [1.0.0-beta.29](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/agent@1.0.0-beta.28...@forestadmin/agent@1.0.0-beta.29) (2022-05-18)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **agent:** import fastify/express only if needed ([#312](https://github.com/ForestAdmin/agent-nodejs/issues/312)) ([81933c1](https://github.com/ForestAdmin/agent-nodejs/commit/81933c1aa67a5e08ef89c7c9d913da9518fdb660))
|
|
7
|
+
|
|
8
|
+
# @forestadmin/agent [1.0.0-beta.28](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/agent@1.0.0-beta.27...@forestadmin/agent@1.0.0-beta.28) (2022-05-18)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* compatibility with Express.js, Koa, Fastify & NestJS ([#300](https://github.com/ForestAdmin/agent-nodejs/issues/300)) ([904639e](https://github.com/ForestAdmin/agent-nodejs/commit/904639ec66f4116b3c5557d83ec43656e55ccbbc))
|
|
14
|
+
|
|
15
|
+
# @forestadmin/agent [1.0.0-beta.27](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/agent@1.0.0-beta.26...@forestadmin/agent@1.0.0-beta.27) (2022-05-17)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* add support for standalone mode ([#304](https://github.com/ForestAdmin/agent-nodejs/issues/304)) ([c2bca75](https://github.com/ForestAdmin/agent-nodejs/commit/c2bca75a882c1591ad7560583ba0c56fb8020e12))
|
|
21
|
+
|
|
1
22
|
# @forestadmin/agent [1.0.0-beta.26](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/agent@1.0.0-beta.25...@forestadmin/agent@1.0.0-beta.26) (2022-05-16)
|
|
2
23
|
|
|
3
24
|
|
|
@@ -1,34 +1,12 @@
|
|
|
1
|
-
/// <reference types="
|
|
1
|
+
/// <reference types="koa__router" />
|
|
2
2
|
import { DataSource } from '@forestadmin/datasource-toolkit';
|
|
3
|
-
import
|
|
4
|
-
import { AgentOptions } from '../types';
|
|
3
|
+
import Router from '@koa/router';
|
|
5
4
|
import { AgentOptionsWithDefaults } from './types';
|
|
6
|
-
import BaseRoute from './routes/base-route';
|
|
7
|
-
import { ForestAdminHttpDriverServices } from './services';
|
|
8
|
-
/** Native Node.js callback that can be passed to an HTTP Server */
|
|
9
|
-
export declare type HttpCallback = (req: IncomingMessage, res: ServerResponse) => void;
|
|
10
5
|
export default class ForestAdminHttpDriver {
|
|
11
6
|
readonly dataSource: DataSource;
|
|
12
7
|
readonly options: AgentOptionsWithDefaults;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
private status;
|
|
17
|
-
/**
|
|
18
|
-
* Native request handler.
|
|
19
|
-
* Can be used directly with express.js or the Node.js http module.
|
|
20
|
-
* Other frameworks will require adapters.
|
|
21
|
-
*/
|
|
22
|
-
get handler(): HttpCallback;
|
|
23
|
-
constructor(dataSource: DataSource, options: AgentOptions);
|
|
24
|
-
/**
|
|
25
|
-
* Builds the underlying application from the datasource.
|
|
26
|
-
* This method can only be called once.
|
|
27
|
-
*/
|
|
28
|
-
start(): Promise<void>;
|
|
29
|
-
/**
|
|
30
|
-
* Tear down all routes (close open sockets, ...)
|
|
31
|
-
*/
|
|
32
|
-
stop(): Promise<void>;
|
|
8
|
+
constructor(dataSource: DataSource, options: AgentOptionsWithDefaults);
|
|
9
|
+
getRouter(): Promise<Router>;
|
|
10
|
+
sendSchema(): Promise<void>;
|
|
33
11
|
}
|
|
34
12
|
//# sourceMappingURL=forestadmin-http-driver.d.ts.map
|
|
@@ -3,81 +3,41 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const koa_1 = __importDefault(require("koa"));
|
|
7
6
|
const router_1 = __importDefault(require("@koa/router"));
|
|
8
7
|
const koa_bodyparser_1 = __importDefault(require("koa-bodyparser"));
|
|
9
8
|
const cors_1 = __importDefault(require("@koa/cors"));
|
|
10
|
-
const path_1 = __importDefault(require("path"));
|
|
11
9
|
const forest_http_api_1 = __importDefault(require("./utils/forest-http-api"));
|
|
12
|
-
const http_driver_options_1 = __importDefault(require("./utils/http-driver-options"));
|
|
13
10
|
const emitter_1 = __importDefault(require("./utils/forest-schema/emitter"));
|
|
14
11
|
const routes_1 = __importDefault(require("./routes"));
|
|
15
12
|
const services_1 = __importDefault(require("./services"));
|
|
16
13
|
class ForestAdminHttpDriver {
|
|
17
14
|
constructor(dataSource, options) {
|
|
18
|
-
this.routes = [];
|
|
19
|
-
this.app = new koa_1.default();
|
|
20
|
-
this.status = 'waiting';
|
|
21
15
|
this.dataSource = dataSource;
|
|
22
|
-
this.options =
|
|
23
|
-
this.services = (0, services_1.default)(this.options);
|
|
24
|
-
http_driver_options_1.default.validate(this.options);
|
|
16
|
+
this.options = options;
|
|
25
17
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
18
|
+
async getRouter() {
|
|
19
|
+
// Bootstrap app
|
|
20
|
+
const services = (0, services_1.default)(this.options);
|
|
21
|
+
const routes = (0, routes_1.default)(this.dataSource, this.options, services);
|
|
22
|
+
await Promise.all(routes.map(route => route.bootstrap()));
|
|
23
|
+
// Build router
|
|
24
|
+
const router = new router_1.default();
|
|
25
|
+
router.all('(.*)', (0, cors_1.default)({ credentials: true, maxAge: 24 * 3600, privateNetworkAccess: true }));
|
|
26
|
+
router.use((0, koa_bodyparser_1.default)({ jsonLimit: '50mb' }));
|
|
27
|
+
routes.forEach(route => route.setupRoutes(router));
|
|
28
|
+
return router;
|
|
33
29
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
throw new Error('Agent cannot be restarted.');
|
|
30
|
+
async sendSchema() {
|
|
31
|
+
const schema = await emitter_1.default.getSerializedSchema(this.options, this.dataSource);
|
|
32
|
+
const schemaIsKnown = await forest_http_api_1.default.hasSchema(this.options, schema.meta.schemaFileHash);
|
|
33
|
+
if (!schemaIsKnown) {
|
|
34
|
+
this.options.logger('Info', 'Schema was updated, sending new version');
|
|
35
|
+
await forest_http_api_1.default.uploadSchema(this.options, schema);
|
|
41
36
|
}
|
|
42
|
-
|
|
43
|
-
this.
|
|
44
|
-
// Build http application
|
|
45
|
-
const router = new router_1.default({ prefix: path_1.default.join('/', this.options.prefix) });
|
|
46
|
-
this.routes = (0, routes_1.default)(this.dataSource, this.options, this.services);
|
|
47
|
-
this.routes.forEach(route => route.setupRoutes(router));
|
|
48
|
-
await Promise.all(this.routes.map(route => route.bootstrap()));
|
|
49
|
-
this.app
|
|
50
|
-
.use((0, cors_1.default)({ credentials: true, maxAge: 24 * 3600, privateNetworkAccess: true }))
|
|
51
|
-
.use((0, koa_bodyparser_1.default)({ jsonLimit: '50mb' }))
|
|
52
|
-
.use(router.routes());
|
|
53
|
-
// Send schema to forestadmin-server (if relevant).
|
|
54
|
-
const schema = await emitter_1.default.getSerializedSchema(this.options, this.dataSource);
|
|
55
|
-
const schemaIsKnown = await forest_http_api_1.default.hasSchema(this.options, schema.meta.schemaFileHash);
|
|
56
|
-
if (!schemaIsKnown) {
|
|
57
|
-
this.options.logger('Info', 'Schema was updated, sending new version');
|
|
58
|
-
await forest_http_api_1.default.uploadSchema(this.options, schema);
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
this.options.logger('Info', 'Schema was not updated since last run');
|
|
62
|
-
}
|
|
63
|
-
this.options.logger('Info', 'Started');
|
|
37
|
+
else {
|
|
38
|
+
this.options.logger('Info', 'Schema was not updated since last run');
|
|
64
39
|
}
|
|
65
|
-
catch (e) {
|
|
66
|
-
this.options.logger('Error', e.message);
|
|
67
|
-
this.status = 'done';
|
|
68
|
-
throw e;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Tear down all routes (close open sockets, ...)
|
|
73
|
-
*/
|
|
74
|
-
async stop() {
|
|
75
|
-
if (this.status !== 'running') {
|
|
76
|
-
throw new Error('Agent is not running.');
|
|
77
|
-
}
|
|
78
|
-
this.status = 'done';
|
|
79
|
-
await Promise.all(this.routes.map(route => route.tearDown()));
|
|
80
40
|
}
|
|
81
41
|
}
|
|
82
42
|
exports.default = ForestAdminHttpDriver;
|
|
83
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
43
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yZXN0YWRtaW4taHR0cC1kcml2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWdlbnQvZm9yZXN0YWRtaW4taHR0cC1kcml2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFDQSx5REFBaUM7QUFDakMsb0VBQXdDO0FBQ3hDLHFEQUE2QjtBQUc3Qiw4RUFBb0Q7QUFDcEQsNEVBQTBEO0FBQzFELHNEQUFrQztBQUNsQywwREFBc0M7QUFFdEMsTUFBcUIscUJBQXFCO0lBSXhDLFlBQVksVUFBc0IsRUFBRSxPQUFpQztRQUNuRSxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztRQUM3QixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztJQUN6QixDQUFDO0lBRUQsS0FBSyxDQUFDLFNBQVM7UUFDYixnQkFBZ0I7UUFDaEIsTUFBTSxRQUFRLEdBQUcsSUFBQSxrQkFBWSxFQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM1QyxNQUFNLE1BQU0sR0FBRyxJQUFBLGdCQUFVLEVBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQ25FLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUUxRCxlQUFlO1FBQ2YsTUFBTSxNQUFNLEdBQUcsSUFBSSxnQkFBTSxFQUFFLENBQUM7UUFDNUIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsSUFBQSxjQUFJLEVBQUMsRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxFQUFFLEdBQUcsSUFBSSxFQUFFLG9CQUFvQixFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztRQUMvRixNQUFNLENBQUMsR0FBRyxDQUFDLElBQUEsd0JBQVUsRUFBQyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDOUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUVuRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQsS0FBSyxDQUFDLFVBQVU7UUFDZCxNQUFNLE1BQU0sR0FBRyxNQUFNLGlCQUFhLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDdEYsTUFBTSxhQUFhLEdBQUcsTUFBTSx5QkFBYSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7UUFFOUYsSUFBSSxDQUFDLGFBQWEsRUFBRTtZQUNsQixJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUseUNBQXlDLENBQUMsQ0FBQztZQUN2RSxNQUFNLHlCQUFhLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7U0FDeEQ7YUFBTTtZQUNMLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSx1Q0FBdUMsQ0FBQyxDQUFDO1NBQ3RFO0lBQ0gsQ0FBQztDQUNGO0FBbkNELHdDQW1DQyJ9
|
|
@@ -8,7 +8,6 @@ export default abstract class BaseRoute {
|
|
|
8
8
|
abstract get type(): RouteType;
|
|
9
9
|
constructor(services: ForestAdminHttpDriverServices, options: AgentOptionsWithDefaults);
|
|
10
10
|
bootstrap(): Promise<void>;
|
|
11
|
-
tearDown(): Promise<void>;
|
|
12
11
|
abstract setupRoutes(router: Router): void;
|
|
13
12
|
}
|
|
14
13
|
//# sourceMappingURL=base-route.d.ts.map
|
|
@@ -8,9 +8,6 @@ class BaseRoute {
|
|
|
8
8
|
async bootstrap() {
|
|
9
9
|
// Do nothing by default
|
|
10
10
|
}
|
|
11
|
-
async tearDown() {
|
|
12
|
-
// Do nothing by default
|
|
13
|
-
}
|
|
14
11
|
}
|
|
15
12
|
exports.default = BaseRoute;
|
|
16
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
13
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1yb3V0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hZ2VudC9yb3V0ZXMvYmFzZS1yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUtBLE1BQThCLFNBQVM7SUFNckMsWUFBWSxRQUF1QyxFQUFFLE9BQWlDO1FBQ3BGLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO0lBQ3pCLENBQUM7SUFFRCxLQUFLLENBQUMsU0FBUztRQUNiLHdCQUF3QjtJQUMxQixDQUFDO0NBR0Y7QUFoQkQsNEJBZ0JDIn0=
|
package/dist/builder/agent.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ChartDefinition, DataSourceFactory, TCollectionName, TSchema } from '@forestadmin/datasource-toolkit';
|
|
2
2
|
import { AgentOptions } from '../types';
|
|
3
3
|
import CollectionBuilder from './collection';
|
|
4
|
-
import { HttpCallback } from '../agent/forestadmin-http-driver';
|
|
5
4
|
/**
|
|
6
5
|
* Allow to create a new Forest Admin agent from scratch.
|
|
7
6
|
* Builds the application by composing and configuring all the collection decorators.
|
|
@@ -13,18 +12,12 @@ import { HttpCallback } from '../agent/forestadmin-http-driver';
|
|
|
13
12
|
* .start();
|
|
14
13
|
*/
|
|
15
14
|
export default class AgentBuilder<S extends TSchema = TSchema> {
|
|
16
|
-
private readonly forestAdminHttpDriver;
|
|
17
15
|
private readonly compositeDataSource;
|
|
18
16
|
private readonly stack;
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
* import http from 'http';
|
|
24
|
-
* ...
|
|
25
|
-
* const server = http.createServer(agent.httpCallback);
|
|
26
|
-
*/
|
|
27
|
-
get httpCallback(): HttpCallback;
|
|
17
|
+
private readonly options;
|
|
18
|
+
private customizations;
|
|
19
|
+
private mounts;
|
|
20
|
+
private termination;
|
|
28
21
|
/**
|
|
29
22
|
* Create a new Agent Builder.
|
|
30
23
|
* If any options are missing, the default will be applied:
|
|
@@ -71,12 +64,37 @@ export default class AgentBuilder<S extends TSchema = TSchema> {
|
|
|
71
64
|
*/
|
|
72
65
|
customizeCollection<N extends TCollectionName<S>>(name: N, handle: (collection: CollectionBuilder<S, N>) => unknown): this;
|
|
73
66
|
/**
|
|
74
|
-
*
|
|
67
|
+
* Expose the agent on a given port and host
|
|
68
|
+
* @param port port that should be used.
|
|
69
|
+
* @param host host that should be used.
|
|
75
70
|
*/
|
|
76
|
-
|
|
71
|
+
mountOnStandaloneServer(port?: number, host?: string): this;
|
|
72
|
+
/**
|
|
73
|
+
* Mount the agent on an express app.
|
|
74
|
+
* @param express instance of the express app or router.
|
|
75
|
+
*/
|
|
76
|
+
mountOnExpress(express: any): this;
|
|
77
77
|
/**
|
|
78
|
-
*
|
|
78
|
+
* Mount the agent on a fastify app
|
|
79
|
+
* @param fastify instance of the fastify app, or of a fastify context
|
|
79
80
|
*/
|
|
81
|
+
mountOnFastify(fastify: any): this;
|
|
82
|
+
/**
|
|
83
|
+
* Mount the agent on a koa app
|
|
84
|
+
* @param koa instance of a koa app or a koa Router.
|
|
85
|
+
*/
|
|
86
|
+
mountOnKoa(koa: any): this;
|
|
87
|
+
/**
|
|
88
|
+
* Mount the agent on a NestJS app
|
|
89
|
+
* @param nestJs instance of a NestJS application
|
|
90
|
+
*/
|
|
91
|
+
mountOnNestJs(nestJs: any): this;
|
|
92
|
+
/**
|
|
93
|
+
* Start the agent.
|
|
94
|
+
*/
|
|
95
|
+
start(): Promise<void>;
|
|
80
96
|
stop(): Promise<void>;
|
|
97
|
+
private useCallbackOnFastify;
|
|
98
|
+
private getConnectCallback;
|
|
81
99
|
}
|
|
82
100
|
//# sourceMappingURL=agent.d.ts.map
|
package/dist/builder/agent.js
CHANGED
|
@@ -1,14 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
27
|
};
|
|
5
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
29
|
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
7
30
|
const promises_1 = require("fs/promises");
|
|
31
|
+
const koa_1 = __importDefault(require("koa"));
|
|
32
|
+
const router_1 = __importDefault(require("@koa/router"));
|
|
33
|
+
const http_1 = __importDefault(require("http"));
|
|
8
34
|
const collection_1 = __importDefault(require("./collection"));
|
|
9
35
|
const decorators_stack_1 = __importDefault(require("./decorators-stack"));
|
|
10
36
|
const forestadmin_http_driver_1 = __importDefault(require("../agent/forestadmin-http-driver"));
|
|
11
|
-
const
|
|
37
|
+
const options_validator_1 = __importDefault(require("./utils/options-validator"));
|
|
38
|
+
const typing_generator_1 = __importDefault(require("./utils/typing-generator"));
|
|
12
39
|
/**
|
|
13
40
|
* Allow to create a new Forest Admin agent from scratch.
|
|
14
41
|
* Builds the application by composing and configuring all the collection decorators.
|
|
@@ -38,28 +65,20 @@ class AgentBuilder {
|
|
|
38
65
|
* .start();
|
|
39
66
|
*/
|
|
40
67
|
constructor(options) {
|
|
41
|
-
this.
|
|
68
|
+
this.customizations = [];
|
|
69
|
+
this.mounts = [];
|
|
70
|
+
this.termination = [];
|
|
71
|
+
this.options = options_validator_1.default.withDefaults(options);
|
|
42
72
|
this.compositeDataSource = new datasource_toolkit_1.BaseDataSource();
|
|
43
73
|
this.stack = new decorators_stack_1.default(this.compositeDataSource);
|
|
44
|
-
this.forestAdminHttpDriver = new forestadmin_http_driver_1.default(this.stack.dataSource, options);
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Native nodejs HttpCallback object
|
|
48
|
-
* @example
|
|
49
|
-
* import http from 'http';
|
|
50
|
-
* ...
|
|
51
|
-
* const server = http.createServer(agent.httpCallback);
|
|
52
|
-
*/
|
|
53
|
-
get httpCallback() {
|
|
54
|
-
return this.forestAdminHttpDriver.handler;
|
|
55
74
|
}
|
|
56
75
|
/**
|
|
57
76
|
* Add a datasource
|
|
58
77
|
* @param factory the datasource to add
|
|
59
78
|
*/
|
|
60
79
|
addDataSource(factory) {
|
|
61
|
-
this.
|
|
62
|
-
const datasource = await factory(this.
|
|
80
|
+
this.customizations.push(async () => {
|
|
81
|
+
const datasource = await factory(this.options.logger);
|
|
63
82
|
datasource.collections.forEach(collection => {
|
|
64
83
|
this.compositeDataSource.addCollection(collection);
|
|
65
84
|
});
|
|
@@ -79,7 +98,7 @@ class AgentBuilder {
|
|
|
79
98
|
* })
|
|
80
99
|
*/
|
|
81
100
|
addChart(name, definition) {
|
|
82
|
-
this.
|
|
101
|
+
this.customizations.push(async () => {
|
|
83
102
|
this.stack.chart.addChart(name, definition);
|
|
84
103
|
});
|
|
85
104
|
return this;
|
|
@@ -93,34 +112,145 @@ class AgentBuilder {
|
|
|
93
112
|
* .customizeCollection('books', books => books.renameField('xx', 'yy'))
|
|
94
113
|
*/
|
|
95
114
|
customizeCollection(name, handle) {
|
|
96
|
-
this.
|
|
115
|
+
this.customizations.push(async () => {
|
|
97
116
|
if (this.stack.dataSource.getCollection(name)) {
|
|
98
117
|
handle(new collection_1.default(this.stack, name));
|
|
99
118
|
}
|
|
100
119
|
});
|
|
101
120
|
return this;
|
|
102
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Expose the agent on a given port and host
|
|
124
|
+
* @param port port that should be used.
|
|
125
|
+
* @param host host that should be used.
|
|
126
|
+
*/
|
|
127
|
+
mountOnStandaloneServer(port = 3351, host = 'localhost') {
|
|
128
|
+
const server = http_1.default.createServer(this.getConnectCallback(true));
|
|
129
|
+
server.listen(port, host);
|
|
130
|
+
this.options.logger('Info', `Successfully mounted on Standalone server (http://${host}:${port})`);
|
|
131
|
+
this.termination.push(async () => {
|
|
132
|
+
server.close();
|
|
133
|
+
});
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Mount the agent on an express app.
|
|
138
|
+
* @param express instance of the express app or router.
|
|
139
|
+
*/
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
141
|
+
mountOnExpress(express) {
|
|
142
|
+
express.use('/forest', this.getConnectCallback(false));
|
|
143
|
+
this.options.logger('Info', `Successfully mounted on Express.js`);
|
|
144
|
+
return this;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Mount the agent on a fastify app
|
|
148
|
+
* @param fastify instance of the fastify app, or of a fastify context
|
|
149
|
+
*/
|
|
150
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
151
|
+
mountOnFastify(fastify) {
|
|
152
|
+
const callback = this.getConnectCallback(false);
|
|
153
|
+
this.useCallbackOnFastify(fastify, callback);
|
|
154
|
+
this.options.logger('Info', `Successfully mounted on Fastify`);
|
|
155
|
+
return this;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Mount the agent on a koa app
|
|
159
|
+
* @param koa instance of a koa app or a koa Router.
|
|
160
|
+
*/
|
|
161
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
162
|
+
mountOnKoa(koa) {
|
|
163
|
+
const parentRouter = new router_1.default({ prefix: '/forest' });
|
|
164
|
+
koa.use(parentRouter.routes());
|
|
165
|
+
this.options.logger('Info', `Successfully mounted on Koa`);
|
|
166
|
+
this.mounts.push(async (router) => {
|
|
167
|
+
parentRouter.use(router.routes());
|
|
168
|
+
});
|
|
169
|
+
return this;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Mount the agent on a NestJS app
|
|
173
|
+
* @param nestJs instance of a NestJS application
|
|
174
|
+
*/
|
|
175
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
176
|
+
mountOnNestJs(nestJs) {
|
|
177
|
+
const adapter = nestJs.getHttpAdapter();
|
|
178
|
+
const callback = this.getConnectCallback(false);
|
|
179
|
+
if (adapter.constructor.name === 'ExpressAdapter') {
|
|
180
|
+
nestJs.use('/forest', callback);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
this.useCallbackOnFastify(nestJs, callback);
|
|
184
|
+
}
|
|
185
|
+
this.options.logger('Info', `Successfully mounted on NestJS`);
|
|
186
|
+
return this;
|
|
187
|
+
}
|
|
103
188
|
/**
|
|
104
189
|
* Start the agent.
|
|
105
190
|
*/
|
|
106
191
|
async start() {
|
|
107
|
-
|
|
108
|
-
for (const task of this.
|
|
109
|
-
// eslint-disable-
|
|
110
|
-
|
|
111
|
-
|
|
192
|
+
// Customize agent
|
|
193
|
+
for (const task of this.customizations)
|
|
194
|
+
await task(); // eslint-disable-line no-await-in-loop
|
|
195
|
+
// Check that options are valid
|
|
196
|
+
const options = options_validator_1.default.validate(this.options);
|
|
197
|
+
// Write typings file
|
|
112
198
|
if (!options.isProduction && options.typingsPath) {
|
|
113
199
|
const types = typing_generator_1.default.generateTypes(this.stack.action, options.typingsMaxDepth);
|
|
114
200
|
await (0, promises_1.writeFile)(options.typingsPath, types, { encoding: 'utf-8' });
|
|
115
201
|
}
|
|
116
|
-
|
|
202
|
+
const httpDriver = new forestadmin_http_driver_1.default(this.stack.dataSource, options);
|
|
203
|
+
await httpDriver.sendSchema();
|
|
204
|
+
const router = await httpDriver.getRouter();
|
|
205
|
+
for (const task of this.mounts)
|
|
206
|
+
await task(router); // eslint-disable-line no-await-in-loop
|
|
117
207
|
}
|
|
118
|
-
/**
|
|
119
|
-
* Stop the agent gracefully.
|
|
120
|
-
*/
|
|
121
208
|
async stop() {
|
|
122
|
-
|
|
209
|
+
for (const task of this.termination)
|
|
210
|
+
await task(); // eslint-disable-line no-await-in-loop
|
|
211
|
+
}
|
|
212
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
213
|
+
useCallbackOnFastify(fastify, callback) {
|
|
214
|
+
try {
|
|
215
|
+
// 'fastify 2' or 'middie' or 'fastify-express'
|
|
216
|
+
fastify.use('/forest', callback);
|
|
217
|
+
}
|
|
218
|
+
catch (e) {
|
|
219
|
+
// 'fastify 3'
|
|
220
|
+
if (e.code === 'FST_ERR_MISSING_MIDDLEWARE') {
|
|
221
|
+
fastify
|
|
222
|
+
.register(Promise.resolve().then(() => __importStar(require('@fastify/express'))))
|
|
223
|
+
.then(() => {
|
|
224
|
+
fastify.use('/forest', callback);
|
|
225
|
+
})
|
|
226
|
+
.catch(err => {
|
|
227
|
+
this.options.logger('Error', err.message);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
throw e;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
getConnectCallback(nested) {
|
|
236
|
+
let handler = null;
|
|
237
|
+
this.mounts.push(async (driverRouter) => {
|
|
238
|
+
let router = driverRouter;
|
|
239
|
+
if (nested) {
|
|
240
|
+
router = new router_1.default({ prefix: '/forest' }).use(router.routes());
|
|
241
|
+
}
|
|
242
|
+
handler = new koa_1.default().use(router.routes()).callback();
|
|
243
|
+
});
|
|
244
|
+
return (req, res) => {
|
|
245
|
+
if (handler) {
|
|
246
|
+
handler(req, res);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
250
|
+
res.end(JSON.stringify({ error: 'Agent is not started' }));
|
|
251
|
+
}
|
|
252
|
+
};
|
|
123
253
|
}
|
|
124
254
|
}
|
|
125
255
|
exports.default = AgentBuilder;
|
|
126
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
256
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYnVpbGRlci9hZ2VudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsd0VBT3lDO0FBQ3pDLDBDQUF3QztBQUN4Qyw4Q0FBc0I7QUFDdEIseURBQWlDO0FBQ2pDLGdEQUF3QjtBQUl4Qiw4REFBNkM7QUFDN0MsMEVBQWlEO0FBQ2pELCtGQUFxRTtBQUNyRSxrRkFBeUQ7QUFDekQsZ0ZBQXVEO0FBRXZEOzs7Ozs7Ozs7R0FTRztBQUNILE1BQXFCLFlBQVk7SUFRL0I7Ozs7Ozs7Ozs7Ozs7Ozs7T0FnQkc7SUFDSCxZQUFZLE9BQXFCO1FBckJ6QixtQkFBYyxHQUE0QixFQUFFLENBQUM7UUFDN0MsV0FBTSxHQUEwQyxFQUFFLENBQUM7UUFDbkQsZ0JBQVcsR0FBNEIsRUFBRSxDQUFDO1FBb0JoRCxJQUFJLENBQUMsT0FBTyxHQUFHLDJCQUFnQixDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN0RCxJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSxtQ0FBYyxFQUFjLENBQUM7UUFDNUQsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLDBCQUFlLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDN0QsQ0FBQztJQUVEOzs7T0FHRztJQUNILGFBQWEsQ0FBQyxPQUEwQjtRQUN0QyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxLQUFLLElBQUksRUFBRTtZQUNsQyxNQUFNLFVBQVUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3RELFVBQVUsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxFQUFFO2dCQUMxQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ3JELENBQUMsQ0FBQyxD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
|
package/dist/builder/types.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import { ComputedDefinition, TCollectionName, TSchema } from '@forestadmin/datasource-toolkit';
|
|
3
|
+
import { IncomingMessage, ServerResponse } from 'http';
|
|
2
4
|
export declare type FieldDefinition<S extends TSchema = TSchema, N extends TCollectionName<S> = TCollectionName<S>> = ComputedDefinition<S, N> & {
|
|
3
5
|
beforeRelations?: boolean;
|
|
4
6
|
};
|
|
7
|
+
export declare type HttpCallback = (req: IncomingMessage, res: ServerResponse) => void;
|
|
5
8
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AgentOptions } from '../../types';
|
|
2
|
+
import { AgentOptionsWithDefaults } from '../../agent/types';
|
|
3
|
+
export default class OptionsValidator {
|
|
4
|
+
private static loggerPrefix;
|
|
5
|
+
static withDefaults(options: AgentOptions): AgentOptions;
|
|
6
|
+
static validate(options: AgentOptions): AgentOptionsWithDefaults;
|
|
7
|
+
private static checkForestServerOptions;
|
|
8
|
+
private static checkAuthOptions;
|
|
9
|
+
private static checkOtherOptions;
|
|
10
|
+
private static isExistingPath;
|
|
11
|
+
private static isUrl;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=options-validator.d.ts.map
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const fs_1 = require("fs");
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
class OptionsValidator {
|
|
6
|
+
static withDefaults(options) {
|
|
7
|
+
const copyOptions = { ...options };
|
|
8
|
+
const defaultLogger = (level, data) => {
|
|
9
|
+
const loggerLevel = options.loggerLevel ?? 'Info';
|
|
10
|
+
const levels = Object.keys(this.loggerPrefix);
|
|
11
|
+
if (levels.indexOf(level) >= levels.indexOf(loggerLevel)) {
|
|
12
|
+
console.error(OptionsValidator.loggerPrefix[level], data);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
copyOptions.logger = copyOptions.logger || defaultLogger;
|
|
16
|
+
copyOptions.schemaPath = copyOptions.schemaPath || '.forestadmin-schema.json';
|
|
17
|
+
copyOptions.forestServerUrl = copyOptions.forestServerUrl || 'https://api.forestadmin.com';
|
|
18
|
+
copyOptions.typingsMaxDepth = copyOptions.typingsMaxDepth ?? 5;
|
|
19
|
+
const parsed = new URL(options.agentUrl);
|
|
20
|
+
copyOptions.prefix ?? (copyOptions.prefix = (0, path_1.join)('/', parsed.pathname, 'forest'));
|
|
21
|
+
return {
|
|
22
|
+
clientId: null,
|
|
23
|
+
loggerLevel: 'Info',
|
|
24
|
+
prefix: '/forest',
|
|
25
|
+
permissionsCacheDurationInSeconds: 15 * 60,
|
|
26
|
+
...copyOptions,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
static validate(options) {
|
|
30
|
+
OptionsValidator.checkForestServerOptions(options);
|
|
31
|
+
OptionsValidator.checkAuthOptions(options);
|
|
32
|
+
OptionsValidator.checkOtherOptions(options);
|
|
33
|
+
return options;
|
|
34
|
+
}
|
|
35
|
+
static checkForestServerOptions(options) {
|
|
36
|
+
if (typeof options.envSecret !== 'string' || !/^[0-9a-f]{64}$/.test(options.envSecret)) {
|
|
37
|
+
throw new Error('options.envSecret is invalid. You can retrieve its value from ' +
|
|
38
|
+
'https://www.forestadmin.com');
|
|
39
|
+
}
|
|
40
|
+
if (!OptionsValidator.isUrl(options.forestServerUrl)) {
|
|
41
|
+
throw new Error('options.forestServerUrl is invalid. It should contain an URL ' +
|
|
42
|
+
'(i.e. "https://api.forestadmin.com")');
|
|
43
|
+
}
|
|
44
|
+
if (!OptionsValidator.isExistingPath(options.schemaPath)) {
|
|
45
|
+
throw new Error('options.schemaPath is invalid. It should contain a relative filepath ' +
|
|
46
|
+
'where the schema should be loaded/updated (i.e. "./.forestadmin-schema.json")');
|
|
47
|
+
}
|
|
48
|
+
if (options.typingsPath && !OptionsValidator.isExistingPath(options.typingsPath)) {
|
|
49
|
+
throw new Error('options.typingsPath is invalid. It should contain a relative filepath ' +
|
|
50
|
+
'where the schema should be loaded/updated (i.e. "./src/typings.ts")');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
static checkAuthOptions(options) {
|
|
54
|
+
if (!OptionsValidator.isUrl(options.agentUrl)) {
|
|
55
|
+
throw new Error('options.agentUrl is invalid. It should contain an url where your agent is reachable ' +
|
|
56
|
+
'(i.e. "https://api-forestadmin.mycompany.com")');
|
|
57
|
+
}
|
|
58
|
+
if (typeof options.authSecret !== 'string') {
|
|
59
|
+
throw new Error('options.authSecret is invalid. Any long random string should work ' +
|
|
60
|
+
'(i.e. "OfpssLrbgF3P4vHJTTpb"');
|
|
61
|
+
}
|
|
62
|
+
if (options.clientId === null) {
|
|
63
|
+
options.logger?.('Warn', 'options.clientId was not provided. Using Node.js cluster mode, ' +
|
|
64
|
+
'or multiple instances of the agent will break authentication');
|
|
65
|
+
}
|
|
66
|
+
else if (typeof options.clientId !== 'string') {
|
|
67
|
+
throw new Error('options.clientId is invalid.');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
static checkOtherOptions(options) {
|
|
71
|
+
if (typeof options.prefix !== 'string' || !/[-/a-z+]/.test(options.prefix)) {
|
|
72
|
+
throw new Error('options.prefix is invalid. It should contain the prefix on which ' +
|
|
73
|
+
'forest admin routes should be mounted (i.e. "/forest")');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
static isExistingPath(string) {
|
|
77
|
+
if (typeof string !== 'string') {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const parsed = (0, path_1.parse)(string);
|
|
81
|
+
return parsed.dir.length ? (0, fs_1.existsSync)(parsed.dir) : true;
|
|
82
|
+
}
|
|
83
|
+
static isUrl(string) {
|
|
84
|
+
if (typeof string !== 'string') {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const url = new URL(string);
|
|
89
|
+
return url.protocol === 'http:' || url.protocol === 'https:';
|
|
90
|
+
}
|
|
91
|
+
catch (_) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.default = OptionsValidator;
|
|
97
|
+
OptionsValidator.loggerPrefix = {
|
|
98
|
+
Debug: '\x1b[34mdebug:\x1b[0m',
|
|
99
|
+
Info: '\x1b[32minfo:\x1b[0m',
|
|
100
|
+
Warn: '\x1b[33mwarning:\x1b[0m',
|
|
101
|
+
Error: '\x1b[31merror:\x1b[0m',
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3B0aW9ucy12YWxpZGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYnVpbGRlci91dGlscy9vcHRpb25zLXZhbGlkYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLDJCQUFnQztBQUNoQywrQkFBNEQ7QUFLNUQsTUFBcUIsZ0JBQWdCO0lBUW5DLE1BQU0sQ0FBQyxZQUFZLENBQUMsT0FBcUI7UUFDdkMsTUFBTSxXQUFXLEdBQUcsRUFBRSxHQUFHLE9BQU8sRUFBRSxDQUFDO1FBRW5DLE1BQU0sYUFBYSxHQUFHLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFO1lBQ3BDLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxXQUFXLElBQUksTUFBTSxDQUFDO1lBQ2xELE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBRTlDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxFQUFFO2dCQUN4RCxPQUFPLENBQUMsS0FBSyxDQUFDLGdCQUFnQixDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQzthQUMzRDtRQUNILENBQUMsQ0FBQztRQUVGLFdBQVcsQ0FBQyxNQUFNLEdBQUcsV0FBVyxDQUFDLE1BQU0sSUFBSSxhQUFhLENBQUM7UUFDekQsV0FBVyxDQUFDLFVBQVUsR0FBRyxXQUFXLENBQUMsVUFBVSxJQUFJLDBCQUEwQixDQUFDO1FBQzlFLFdBQVcsQ0FBQyxlQUFlLEdBQUcsV0FBVyxDQUFDLGVBQWUsSUFBSSw2QkFBNkIsQ0FBQztRQUMzRixXQUFXLENBQUMsZUFBZSxHQUFHLFdBQVcsQ0FBQyxlQUFlLElBQUksQ0FBQyxDQUFDO1FBRS9ELE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMs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
|
|
File without changes
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
4
|
+
class TypingGenerator {
|
|
5
|
+
static generateTypes(dataSource, maxDepth) {
|
|
6
|
+
const collections = [...dataSource.collections].sort((a, b) => a.name.localeCompare(b.name));
|
|
7
|
+
return [
|
|
8
|
+
`/* eslint-disable */`,
|
|
9
|
+
'export type Schema = {',
|
|
10
|
+
...collections.map(collection => [
|
|
11
|
+
` ${collection.name}: {`,
|
|
12
|
+
this.getRow(collection),
|
|
13
|
+
this.getRelations(collection),
|
|
14
|
+
this.getFlatRelations(collection, maxDepth),
|
|
15
|
+
' };',
|
|
16
|
+
].join(`\n`)),
|
|
17
|
+
'};\n',
|
|
18
|
+
].join('\n');
|
|
19
|
+
}
|
|
20
|
+
static getRow(collection) {
|
|
21
|
+
const content = Object.entries(collection.schema.fields).reduce((memo, [name, field]) => {
|
|
22
|
+
return field.type === 'Column' ? [...memo, ` ${name}: ${this.getType(field)};`] : memo;
|
|
23
|
+
}, []);
|
|
24
|
+
return ` plain: {\n${content.join('\n')}\n };`;
|
|
25
|
+
}
|
|
26
|
+
static getRelations(collection) {
|
|
27
|
+
const content = Object.entries(collection.schema.fields).reduce((memo, [name, field]) => {
|
|
28
|
+
if (field.type === 'ManyToOne' || field.type === 'OneToOne') {
|
|
29
|
+
const relation = field.foreignCollection;
|
|
30
|
+
return [
|
|
31
|
+
...memo,
|
|
32
|
+
` ${name}: Schema['${relation}']['plain'] & Schema['${relation}']['nested'];`,
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
return memo;
|
|
36
|
+
}, []);
|
|
37
|
+
return content.length ? ` nested: {\n${content.join('\n')}\n };` : ` nested: {};`;
|
|
38
|
+
}
|
|
39
|
+
static getFlatRelations(collection, maxDepth) {
|
|
40
|
+
const fields = this.getFieldsRec(collection, maxDepth, []);
|
|
41
|
+
return fields.length
|
|
42
|
+
? ` flat: {\n ${fields.join('\n ')}\n };`
|
|
43
|
+
: ` flat: {};`;
|
|
44
|
+
}
|
|
45
|
+
static getFieldsRec(collection, maxDepth, traversed) {
|
|
46
|
+
const columns = traversed.length > 0
|
|
47
|
+
? Object.entries(collection.schema.fields)
|
|
48
|
+
.filter(([, schema]) => schema.type === 'Column')
|
|
49
|
+
.map(([name, schema]) => `'${name}': ${this.getType(schema)};`)
|
|
50
|
+
: [];
|
|
51
|
+
const relations = Object.entries(collection.schema.fields).reduce((memo, [name, schema]) => {
|
|
52
|
+
if (schema.type !== 'ManyToOne' && schema.type !== 'OneToOne')
|
|
53
|
+
return memo;
|
|
54
|
+
const subCollection = collection.dataSource.getCollection(schema.foreignCollection);
|
|
55
|
+
const inverse = datasource_toolkit_1.CollectionUtils.getInverseRelation(collection, name);
|
|
56
|
+
// Do not expand inverse relations, as those create useless cycles
|
|
57
|
+
const expand = traversed.length < maxDepth &&
|
|
58
|
+
!traversed.find(({ c, r }) => c === subCollection && r === inverse);
|
|
59
|
+
if (!expand)
|
|
60
|
+
return memo;
|
|
61
|
+
// Manually expand the field type (cycles are not allowed in template literal types)
|
|
62
|
+
return [
|
|
63
|
+
...memo,
|
|
64
|
+
...this.getFieldsRec(subCollection, maxDepth, [
|
|
65
|
+
...traversed,
|
|
66
|
+
{ c: collection, r: name },
|
|
67
|
+
]).map(f => `'${name}:${f.slice(1)}`),
|
|
68
|
+
];
|
|
69
|
+
}, []);
|
|
70
|
+
return [...columns, ...relations];
|
|
71
|
+
}
|
|
72
|
+
static getType(field) {
|
|
73
|
+
if (Array.isArray(field.columnType)) {
|
|
74
|
+
return `Array<${this.getType({ columnType: field.columnType[0] })}>`;
|
|
75
|
+
}
|
|
76
|
+
if (field.columnType === 'Enum') {
|
|
77
|
+
return field.enumValues.map(v => `'${v.replace(/'/g, "\\'")}'`).join(' | ');
|
|
78
|
+
}
|
|
79
|
+
if (typeof field.columnType === 'string') {
|
|
80
|
+
return {
|
|
81
|
+
Boolean: 'boolean',
|
|
82
|
+
Date: 'string',
|
|
83
|
+
Dateonly: 'string',
|
|
84
|
+
Json: 'any',
|
|
85
|
+
Number: 'number',
|
|
86
|
+
Point: '[number, number]',
|
|
87
|
+
String: 'string',
|
|
88
|
+
Timeonly: 'string',
|
|
89
|
+
Uuid: 'string',
|
|
90
|
+
}[field.columnType];
|
|
91
|
+
}
|
|
92
|
+
return `{${Object.entries(field.columnType)
|
|
93
|
+
.map(([key, subType]) => `${key}: ${this.getType({ columnType: subType })}`)
|
|
94
|
+
.join('; ')}}`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
exports.default = TypingGenerator;
|
|
98
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwaW5nLWdlbmVyYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9idWlsZGVyL3V0aWxzL3R5cGluZy1nZW5lcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSx3RUFNeUM7QUFFekMsTUFBcUIsZUFBZTtJQUNsQyxNQUFNLENBQUMsYUFBYSxDQUFDLFVBQXNCLEVBQUUsUUFBZ0I7UUFDM0QsTUFBTSxXQUFXLEdBQUcsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUU3RixPQUFPO1lBQ0wsc0JBQXNCO1lBQ3RCLHdCQUF3QjtZQUN4QixHQUFHLFdBQVcsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FDOUI7Z0JBQ0UsS0FBSyxVQUFVLENBQUMsSUFBSSxLQUFLO2dCQUN6QixJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQztnQkFDdkIsSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUM7Z0JBQzdCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLEVBQUUsUUFBUSxDQUFDO2dCQUMzQyxNQUFNO2FBQ1AsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQ2I7WUFDRCxNQUFNO1NBQ1AsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDZixDQUFDO0lBRU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxVQUFzQjtRQUMxQyxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxFQUFFLEVBQUU7WUFDdEYsT0FBTyxL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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forestadmin/agent",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.29",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@fast-csv/format": "^4.3.5",
|
|
16
|
+
"@fastify/express": "^1.1.0",
|
|
16
17
|
"@forestadmin/datasource-toolkit": "1.0.0-beta.16",
|
|
17
18
|
"@koa/cors": "^3.3.0",
|
|
18
19
|
"@koa/router": "^10.1.1",
|
|
@@ -50,6 +51,15 @@
|
|
|
50
51
|
"@types/koa__cors": "^3.1.1",
|
|
51
52
|
"@types/koa__router": "^8.0.11",
|
|
52
53
|
"@types/superagent": "^4.1.15",
|
|
53
|
-
"fishery": "^2.1.0"
|
|
54
|
+
"fishery": "^2.1.0",
|
|
55
|
+
"@nestjs/common": "^8.4.5",
|
|
56
|
+
"@nestjs/core": "^8.4.5",
|
|
57
|
+
"@nestjs/platform-express": "^8.4.5",
|
|
58
|
+
"@nestjs/platform-fastify": "^8.4.5",
|
|
59
|
+
"express": "^4.18.1",
|
|
60
|
+
"fastify": "^3.29.0",
|
|
61
|
+
"fastify2": "npm:fastify@^2.15.3",
|
|
62
|
+
"reflect-metadata": "^0.1.13",
|
|
63
|
+
"rxjs": "^7.5.5"
|
|
54
64
|
}
|
|
55
65
|
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { AgentOptions } from '../../types';
|
|
2
|
-
import { AgentOptionsWithDefaults } from '../types';
|
|
3
|
-
export default class OptionsUtils {
|
|
4
|
-
private static loggerPrefix;
|
|
5
|
-
static withDefaults(options: AgentOptions): AgentOptionsWithDefaults;
|
|
6
|
-
static validate(options: AgentOptionsWithDefaults): void;
|
|
7
|
-
private static checkForestServerOptions;
|
|
8
|
-
private static checkAuthOptions;
|
|
9
|
-
private static checkOtherOptions;
|
|
10
|
-
private static isExistingPath;
|
|
11
|
-
private static isUrl;
|
|
12
|
-
}
|
|
13
|
-
//# sourceMappingURL=http-driver-options.d.ts.map
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const fs_1 = require("fs");
|
|
4
|
-
const path_1 = require("path");
|
|
5
|
-
class OptionsUtils {
|
|
6
|
-
static withDefaults(options) {
|
|
7
|
-
const copyOptions = { ...options };
|
|
8
|
-
const defaultLogger = (level, data) => {
|
|
9
|
-
const loggerLevel = options.loggerLevel ?? 'Info';
|
|
10
|
-
const levels = Object.keys(this.loggerPrefix);
|
|
11
|
-
if (levels.indexOf(level) >= levels.indexOf(loggerLevel)) {
|
|
12
|
-
console.error(OptionsUtils.loggerPrefix[level], data);
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
copyOptions.logger = copyOptions.logger || defaultLogger;
|
|
16
|
-
copyOptions.schemaPath = copyOptions.schemaPath || '.forestadmin-schema.json';
|
|
17
|
-
copyOptions.forestServerUrl = copyOptions.forestServerUrl || 'https://api.forestadmin.com';
|
|
18
|
-
copyOptions.typingsMaxDepth = copyOptions.typingsMaxDepth ?? 5;
|
|
19
|
-
return Object.freeze({
|
|
20
|
-
clientId: null,
|
|
21
|
-
loggerLevel: 'Info',
|
|
22
|
-
prefix: '/forest',
|
|
23
|
-
permissionsCacheDurationInSeconds: 15 * 60,
|
|
24
|
-
...copyOptions,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
static validate(options) {
|
|
28
|
-
OptionsUtils.checkForestServerOptions(options);
|
|
29
|
-
OptionsUtils.checkAuthOptions(options);
|
|
30
|
-
OptionsUtils.checkOtherOptions(options);
|
|
31
|
-
}
|
|
32
|
-
static checkForestServerOptions(options) {
|
|
33
|
-
if (typeof options.envSecret !== 'string' || !/^[0-9a-f]{64}$/.test(options.envSecret)) {
|
|
34
|
-
throw new Error('options.envSecret is invalid. You can retrieve its value from ' +
|
|
35
|
-
'https://www.forestadmin.com');
|
|
36
|
-
}
|
|
37
|
-
if (!OptionsUtils.isUrl(options.forestServerUrl)) {
|
|
38
|
-
throw new Error('options.forestServerUrl is invalid. It should contain an URL ' +
|
|
39
|
-
'(i.e. "https://api.forestadmin.com")');
|
|
40
|
-
}
|
|
41
|
-
if (!OptionsUtils.isExistingPath(options.schemaPath)) {
|
|
42
|
-
throw new Error('options.schemaPath is invalid. It should contain a relative filepath ' +
|
|
43
|
-
'where the schema should be loaded/updated (i.e. "./.forestadmin-schema.json")');
|
|
44
|
-
}
|
|
45
|
-
if (options.typingsPath && !OptionsUtils.isExistingPath(options.typingsPath)) {
|
|
46
|
-
throw new Error('options.typingsPath is invalid. It should contain a relative filepath ' +
|
|
47
|
-
'where the schema should be loaded/updated (i.e. "./src/typings.ts")');
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
static checkAuthOptions(options) {
|
|
51
|
-
if (!OptionsUtils.isUrl(options.agentUrl)) {
|
|
52
|
-
throw new Error('options.agentUrl is invalid. It should contain an url where your agent is reachable ' +
|
|
53
|
-
'(i.e. "https://api-forestadmin.mycompany.com")');
|
|
54
|
-
}
|
|
55
|
-
if (typeof options.authSecret !== 'string') {
|
|
56
|
-
throw new Error('options.authSecret is invalid. Any long random string should work ' +
|
|
57
|
-
'(i.e. "OfpssLrbgF3P4vHJTTpb"');
|
|
58
|
-
}
|
|
59
|
-
if (options.clientId === null) {
|
|
60
|
-
options.logger?.('Warn', 'options.clientId was not provided. Using Node.js cluster mode, ' +
|
|
61
|
-
'or multiple instances of the agent will break authentication');
|
|
62
|
-
}
|
|
63
|
-
else if (typeof options.clientId !== 'string') {
|
|
64
|
-
throw new Error('options.clientId is invalid.');
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
static checkOtherOptions(options) {
|
|
68
|
-
if (typeof options.prefix !== 'string' || !/[-/a-z+]/.test(options.prefix)) {
|
|
69
|
-
throw new Error('options.prefix is invalid. It should contain the prefix on which ' +
|
|
70
|
-
'forest admin routes should be mounted (i.e. "/forest")');
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
static isExistingPath(string) {
|
|
74
|
-
if (typeof string !== 'string') {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
const parsed = (0, path_1.parse)(string);
|
|
78
|
-
return parsed.dir.length ? (0, fs_1.existsSync)(parsed.dir) : true;
|
|
79
|
-
}
|
|
80
|
-
static isUrl(string) {
|
|
81
|
-
if (typeof string !== 'string') {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
try {
|
|
85
|
-
const url = new URL(string);
|
|
86
|
-
return url.protocol === 'http:' || url.protocol === 'https:';
|
|
87
|
-
}
|
|
88
|
-
catch (_) {
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
exports.default = OptionsUtils;
|
|
94
|
-
OptionsUtils.loggerPrefix = {
|
|
95
|
-
Debug: '\x1b[34mdebug:\x1b[0m',
|
|
96
|
-
Info: '\x1b[32minfo:\x1b[0m',
|
|
97
|
-
Warn: '\x1b[33mwarning:\x1b[0m',
|
|
98
|
-
Error: '\x1b[31merror:\x1b[0m',
|
|
99
|
-
};
|
|
100
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC1kcml2ZXItb3B0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hZ2VudC91dGlscy9odHRwLWRyaXZlci1vcHRpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsMkJBQWdDO0FBQ2hDLCtCQUEwQztBQUsxQyxNQUFxQixZQUFZO0lBUS9CLE1BQU0sQ0FBQyxZQUFZLENBQUMsT0FBcUI7UUFDdkMsTUFBTSxXQUFXLEdBQUcsRUFBRSxHQUFHLE9BQU8sRUFBRSxDQUFDO1FBRW5DLE1BQU0sYUFBYSxHQUFHLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFO1lBQ3BDLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxXQUFXLElBQUksTUFBTSxDQUFDO1lBQ2xELE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBRTlDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxFQUFFO2dCQUN4RCxPQUFPLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7YUFDdkQ7UUFDSCxDQUFDLENBQUM7UUFFRixXQUFXLENBQUMsTUFBTSxHQUFHLFdBQVcsQ0FBQyxNQUFNLElBQUksYUFBYSxDQUFDO1FBQ3pELFdBQVcsQ0FBQyxVQUFVLEdBQUcsV0FBVyxDQUFDLFVBQVUsSUFBSSwwQkFBMEIsQ0FBQztRQUM5RSxXQUFXLENBQUMsZUFBZSxHQUFHLFdBQVcsQ0FBQyxlQUFlLElBQUksNkJBQTZCLENBQUM7UUFDM0YsV0FBVyxDQUFDLGVBQWUsR0FBRyxXQUFXLENBQUMsZUFBZSxJQUFJLENBQUMsQ0FBQztRQUUvRCxPQUFpQyxNQUFNLENBQUMsTUFBTSxDQUFDO1lBQzdDLFFBQVEsRUFBRSxJQUFJO1lBQ2Qs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
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
4
|
-
class TypingGenerator {
|
|
5
|
-
static generateTypes(dataSource, maxDepth) {
|
|
6
|
-
const collections = [...dataSource.collections].sort((a, b) => a.name.localeCompare(b.name));
|
|
7
|
-
return [
|
|
8
|
-
`/* eslint-disable */`,
|
|
9
|
-
'export type Schema = {',
|
|
10
|
-
...collections.map(collection => [
|
|
11
|
-
` ${collection.name}: {`,
|
|
12
|
-
this.getRow(collection),
|
|
13
|
-
this.getRelations(collection),
|
|
14
|
-
this.getFlatRelations(collection, maxDepth),
|
|
15
|
-
' };',
|
|
16
|
-
].join(`\n`)),
|
|
17
|
-
'};\n',
|
|
18
|
-
].join('\n');
|
|
19
|
-
}
|
|
20
|
-
static getRow(collection) {
|
|
21
|
-
const content = Object.entries(collection.schema.fields).reduce((memo, [name, field]) => {
|
|
22
|
-
return field.type === 'Column' ? [...memo, ` ${name}: ${this.getType(field)};`] : memo;
|
|
23
|
-
}, []);
|
|
24
|
-
return ` plain: {\n${content.join('\n')}\n };`;
|
|
25
|
-
}
|
|
26
|
-
static getRelations(collection) {
|
|
27
|
-
const content = Object.entries(collection.schema.fields).reduce((memo, [name, field]) => {
|
|
28
|
-
if (field.type === 'ManyToOne' || field.type === 'OneToOne') {
|
|
29
|
-
const relation = field.foreignCollection;
|
|
30
|
-
return [
|
|
31
|
-
...memo,
|
|
32
|
-
` ${name}: Schema['${relation}']['plain'] & Schema['${relation}']['nested'];`,
|
|
33
|
-
];
|
|
34
|
-
}
|
|
35
|
-
return memo;
|
|
36
|
-
}, []);
|
|
37
|
-
return content.length ? ` nested: {\n${content.join('\n')}\n };` : ` nested: {};`;
|
|
38
|
-
}
|
|
39
|
-
static getFlatRelations(collection, maxDepth) {
|
|
40
|
-
const fields = this.getFieldsRec(collection, maxDepth, []);
|
|
41
|
-
return fields.length
|
|
42
|
-
? ` flat: {\n ${fields.join('\n ')}\n };`
|
|
43
|
-
: ` flat: {};`;
|
|
44
|
-
}
|
|
45
|
-
static getFieldsRec(collection, maxDepth, traversed) {
|
|
46
|
-
const columns = traversed.length > 0
|
|
47
|
-
? Object.entries(collection.schema.fields)
|
|
48
|
-
.filter(([, schema]) => schema.type === 'Column')
|
|
49
|
-
.map(([name, schema]) => `'${name}': ${this.getType(schema)};`)
|
|
50
|
-
: [];
|
|
51
|
-
const relations = Object.entries(collection.schema.fields).reduce((memo, [name, schema]) => {
|
|
52
|
-
if (schema.type !== 'ManyToOne' && schema.type !== 'OneToOne')
|
|
53
|
-
return memo;
|
|
54
|
-
const subCollection = collection.dataSource.getCollection(schema.foreignCollection);
|
|
55
|
-
const inverse = datasource_toolkit_1.CollectionUtils.getInverseRelation(collection, name);
|
|
56
|
-
// Do not expand inverse relations, as those create useless cycles
|
|
57
|
-
const expand = traversed.length < maxDepth &&
|
|
58
|
-
!traversed.find(({ c, r }) => c === subCollection && r === inverse);
|
|
59
|
-
if (!expand)
|
|
60
|
-
return memo;
|
|
61
|
-
// Manually expand the field type (cycles are not allowed in template literal types)
|
|
62
|
-
return [
|
|
63
|
-
...memo,
|
|
64
|
-
...this.getFieldsRec(subCollection, maxDepth, [
|
|
65
|
-
...traversed,
|
|
66
|
-
{ c: collection, r: name },
|
|
67
|
-
]).map(f => `'${name}:${f.slice(1)}`),
|
|
68
|
-
];
|
|
69
|
-
}, []);
|
|
70
|
-
return [...columns, ...relations];
|
|
71
|
-
}
|
|
72
|
-
static getType(field) {
|
|
73
|
-
if (Array.isArray(field.columnType)) {
|
|
74
|
-
return `Array<${this.getType({ columnType: field.columnType[0] })}>`;
|
|
75
|
-
}
|
|
76
|
-
if (field.columnType === 'Enum') {
|
|
77
|
-
return field.enumValues.map(v => `'${v.replace(/'/g, "\\'")}'`).join(' | ');
|
|
78
|
-
}
|
|
79
|
-
if (typeof field.columnType === 'string') {
|
|
80
|
-
return {
|
|
81
|
-
Boolean: 'boolean',
|
|
82
|
-
Date: 'string',
|
|
83
|
-
Dateonly: 'string',
|
|
84
|
-
Json: 'any',
|
|
85
|
-
Number: 'number',
|
|
86
|
-
Point: '[number, number]',
|
|
87
|
-
String: 'string',
|
|
88
|
-
Timeonly: 'string',
|
|
89
|
-
Uuid: 'string',
|
|
90
|
-
}[field.columnType];
|
|
91
|
-
}
|
|
92
|
-
return `{${Object.entries(field.columnType)
|
|
93
|
-
.map(([key, subType]) => `${key}: ${this.getType({ columnType: subType })}`)
|
|
94
|
-
.join('; ')}}`;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
exports.default = TypingGenerator;
|
|
98
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwaW5nLWdlbmVyYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9idWlsZGVyL3R5cGluZy1nZW5lcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSx3RUFNeUM7QUFFekMsTUFBcUIsZUFBZTtJQUNsQyxNQUFNLENBQUMsYUFBYSxDQUFDLFVBQXNCLEVBQUUsUUFBZ0I7UUFDM0QsTUFBTSxXQUFXLEdBQUcsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUU3RixPQUFPO1lBQ0wsc0JBQXNCO1lBQ3RCLHdCQUF3QjtZQUN4QixHQUFHLFdBQVcsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FDOUI7Z0JBQ0UsS0FBSyxVQUFVLENBQUMsSUFBSSxLQUFLO2dCQUN6QixJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQztnQkFDdkIsSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUM7Z0JBQzdCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLEVBQUUsUUFBUSxDQUFDO2dCQUMzQyxNQUFNO2FBQ1AsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQ2I7WUFDRCxNQUFNO1NBQ1AsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDZixDQUFDO0lBRU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxVQUFzQjtRQUMxQyxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxFQUFFLEVBQUU7WUFDdEYsT0FBTyxLQUFLLENBQUMs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
|