@forestadmin/agent 1.0.0-beta.4 → 1.0.0-beta.42
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 +420 -0
- package/dist/agent/forestadmin-http-driver.d.ts +5 -27
- package/dist/agent/forestadmin-http-driver.js +17 -47
- package/dist/agent/routes/access/api-chart.d.ts +16 -0
- package/dist/agent/routes/access/api-chart.js +45 -0
- package/dist/agent/routes/access/chart.js +47 -23
- package/dist/agent/routes/access/count-related.js +13 -6
- package/dist/agent/routes/access/count.js +14 -7
- package/dist/agent/routes/access/csv-related.js +3 -3
- package/dist/agent/routes/access/csv.js +4 -3
- package/dist/agent/routes/access/get.js +3 -2
- package/dist/agent/routes/access/list-related.js +2 -3
- package/dist/agent/routes/access/list.js +2 -3
- package/dist/agent/routes/base-route.d.ts +0 -1
- package/dist/agent/routes/base-route.js +1 -4
- package/dist/agent/routes/index.js +8 -1
- package/dist/agent/routes/modification/action.d.ts +0 -1
- package/dist/agent/routes/modification/action.js +11 -11
- package/dist/agent/routes/modification/associate-related.d.ts +3 -3
- package/dist/agent/routes/modification/associate-related.js +13 -11
- package/dist/agent/routes/modification/create.js +14 -12
- package/dist/agent/routes/modification/delete.js +3 -2
- package/dist/agent/routes/modification/dissociate-delete-related.js +19 -18
- package/dist/agent/routes/modification/update-relation.js +19 -13
- package/dist/agent/routes/modification/update.js +5 -3
- package/dist/agent/routes/security/authentication.d.ts +1 -2
- package/dist/agent/routes/security/authentication.js +4 -8
- package/dist/agent/routes/system/error-handling.js +18 -4
- package/dist/agent/routes/system/logger.js +4 -5
- package/dist/agent/types.d.ts +2 -1
- package/dist/agent/types.js +2 -1
- package/dist/agent/utils/condition-tree-parser.d.ts +11 -0
- package/dist/agent/utils/condition-tree-parser.js +53 -0
- package/dist/agent/utils/context-filter-factory.js +1 -2
- package/dist/agent/utils/csv-generator.d.ts +2 -2
- package/dist/agent/utils/csv-generator.js +3 -3
- package/dist/agent/utils/forest-http-api.d.ts +1 -0
- package/dist/agent/utils/forest-http-api.js +58 -50
- package/dist/agent/utils/forest-schema/generator-actions.js +2 -2
- package/dist/agent/utils/forest-schema/generator-collection.js +8 -3
- package/dist/agent/utils/forest-schema/generator-fields.d.ts +1 -0
- package/dist/agent/utils/forest-schema/generator-fields.js +56 -27
- package/dist/agent/utils/forest-schema/types.d.ts +9 -3
- package/dist/agent/utils/forest-schema/types.js +1 -1
- package/dist/agent/utils/query-string.d.ts +2 -2
- package/dist/agent/utils/query-string.js +8 -4
- package/dist/builder/agent.d.ts +60 -39
- package/dist/builder/agent.js +200 -52
- package/dist/builder/collection.d.ts +151 -53
- package/dist/builder/collection.js +205 -59
- package/dist/builder/decorators-stack.d.ts +24 -0
- package/dist/builder/decorators-stack.js +39 -0
- package/dist/builder/types.d.ts +15 -2
- package/dist/builder/utils/options-validator.d.ts +13 -0
- package/dist/builder/utils/options-validator.js +103 -0
- package/dist/builder/utils/typing-generator.d.ts +10 -0
- package/dist/builder/utils/typing-generator.js +98 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +13 -5
- package/dist/types.d.ts +4 -8
- package/dist/types.js +1 -9
- package/package.json +15 -5
- package/dist/agent/utils/http-driver-options.d.ts +0 -13
- package/dist/agent/utils/http-driver-options.js +0 -86
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
7
|
+
const condition_tree_parser_1 = __importDefault(require("./condition-tree-parser"));
|
|
4
8
|
const DEFAULT_ITEMS_PER_PAGE = 15;
|
|
5
9
|
const DEFAULT_PAGE_TO_SKIP = 1;
|
|
6
10
|
class QueryStringParser {
|
|
@@ -12,7 +16,7 @@ class QueryStringParser {
|
|
|
12
16
|
if (!filters)
|
|
13
17
|
return null;
|
|
14
18
|
const json = JSON.parse(filters.toString());
|
|
15
|
-
const conditionTree =
|
|
19
|
+
const conditionTree = condition_tree_parser_1.default.fromPlainObject(collection, json);
|
|
16
20
|
datasource_toolkit_1.ConditionTreeValidator.validate(conditionTree, collection);
|
|
17
21
|
return conditionTree;
|
|
18
22
|
}
|
|
@@ -71,7 +75,7 @@ class QueryStringParser {
|
|
|
71
75
|
}
|
|
72
76
|
return segment;
|
|
73
77
|
}
|
|
74
|
-
static
|
|
78
|
+
static parseCaller(context) {
|
|
75
79
|
const timezone = context.request.query.timezone?.toString();
|
|
76
80
|
if (!timezone) {
|
|
77
81
|
throw new datasource_toolkit_1.ValidationError('Missing timezone');
|
|
@@ -87,7 +91,7 @@ class QueryStringParser {
|
|
|
87
91
|
catch {
|
|
88
92
|
throw new datasource_toolkit_1.ValidationError(`Invalid timezone: "${timezone}"`);
|
|
89
93
|
}
|
|
90
|
-
return timezone;
|
|
94
|
+
return { ...context.state.user, timezone };
|
|
91
95
|
}
|
|
92
96
|
static parsePagination(context) {
|
|
93
97
|
const queryItemsPerPage = (context.request.body?.data?.attributes?.all_records_subset_query?.['page[size]'] ??
|
|
@@ -127,4 +131,4 @@ class QueryStringParser {
|
|
|
127
131
|
}
|
|
128
132
|
}
|
|
129
133
|
exports.default = QueryStringParser;
|
|
130
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
134
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVlcnktc3RyaW5nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FnZW50L3V0aWxzL3F1ZXJ5LXN0cmluZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHdFQWF5QztBQUV6QyxvRkFBMEQ7QUFFMUQsTUFBTSxzQkFBc0IsR0FBRyxFQUFFLENBQUM7QUFDbEMsTUFBTSxvQkFBb0IsR0FBRyxDQUFDLENBQUM7QUFFL0IsTUFBcUIsaUJBQWlCO0lBQ3BDLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxVQUFzQixFQUFFLE9BQWdCO1FBQ2hFLElBQUk7WUFDRixNQUFNLE9BQU8sR0FDWCxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLHdCQUF3QixFQUFFLE9BQU87Z0JBQ3pFLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLE9BQU87Z0JBQzdCLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQztZQUVqQyxJQUFJLENBQUMsT0FBTztnQkFBRSxPQUFPLElBQUksQ0FBQztZQUUxQixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBQzVDLE1BQU0sYUFBYSxHQUFHLCtCQUFtQixDQUFDLGVBQWUsQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDNUUsMkNBQXNCLENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRSxVQUFVLENBQUMsQ0FBQztZQUUzRCxPQUFPLGFBQWEsQ0FBQztTQUN0QjtRQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ1YsTUFBTSxJQUFJLG9DQUFlLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxPQUFPLEdBQUcsQ0FBQyxDQUFDO1NBQzdEO0lBQ0gsQ0FBQztJQUVELE1BQU0sQ0FBQyxlQUFlLENBQUMsVUFBc0IsRUFBRSxPQUFnQjtRQUM3RCxJQUFJO1lBQ0YsTUFB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
|
package/dist/builder/agent.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChartDefinition, DataSourceFactory, TCollectionName, TSchema } from '@forestadmin/datasource-toolkit';
|
|
2
2
|
import { AgentOptions } from '../types';
|
|
3
|
+
import { DataSourceOptions } from './types';
|
|
3
4
|
import CollectionBuilder from './collection';
|
|
4
|
-
import ForestAdminHttpDriver, { HttpCallback } from '../agent/forestadmin-http-driver';
|
|
5
5
|
/**
|
|
6
6
|
* Allow to create a new Forest Admin agent from scratch.
|
|
7
7
|
* Builds the application by composing and configuring all the collection decorators.
|
|
@@ -9,73 +9,94 @@ import ForestAdminHttpDriver, { HttpCallback } from '../agent/forestadmin-http-d
|
|
|
9
9
|
* Minimal code to add a datasource
|
|
10
10
|
* @example
|
|
11
11
|
* new AgentBuilder(options)
|
|
12
|
-
* .
|
|
12
|
+
* .addDataSource(new SomeDataSource())
|
|
13
13
|
* .start();
|
|
14
14
|
*/
|
|
15
|
-
export default class AgentBuilder {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
relation: DataSourceDecorator<RelationCollectionDecorator>;
|
|
23
|
-
lateComputed: DataSourceDecorator<ComputedCollectionDecorator>;
|
|
24
|
-
lateOpEmulate: DataSourceDecorator<OperatorsEmulateCollectionDecorator>;
|
|
25
|
-
lateOpReplace: DataSourceDecorator<OperatorsReplaceCollectionDecorator>;
|
|
26
|
-
publication: DataSourceDecorator<PublicationCollectionDecorator>;
|
|
27
|
-
rename: DataSourceDecorator<RenameCollectionDecorator>;
|
|
28
|
-
search: DataSourceDecorator<SearchCollectionDecorator>;
|
|
29
|
-
segment: DataSourceDecorator<SegmentCollectionDecorator>;
|
|
30
|
-
sortEmulate: DataSourceDecorator<SortEmulateCollectionDecorator>;
|
|
31
|
-
write: DataSourceDecorator<WriteCollectionDecorator>;
|
|
32
|
-
/**
|
|
33
|
-
* Native nodejs HttpCallback object
|
|
34
|
-
* @example
|
|
35
|
-
* import http from 'http';
|
|
36
|
-
* ...
|
|
37
|
-
* const server = http.createServer(agent.httpCallback);
|
|
38
|
-
*/
|
|
39
|
-
get httpCallback(): HttpCallback;
|
|
15
|
+
export default class AgentBuilder<S extends TSchema = TSchema> {
|
|
16
|
+
private readonly compositeDataSource;
|
|
17
|
+
private readonly stack;
|
|
18
|
+
private readonly options;
|
|
19
|
+
private customizations;
|
|
20
|
+
private mounts;
|
|
21
|
+
private termination;
|
|
40
22
|
/**
|
|
41
23
|
* Create a new Agent Builder.
|
|
42
24
|
* If any options are missing, the default will be applied:
|
|
43
25
|
* ```
|
|
44
26
|
* clientId: null,
|
|
45
27
|
* forestServerUrl: 'https://api.forestadmin.com',
|
|
46
|
-
* logger: (level, data) => console.error(
|
|
28
|
+
* logger: (level, data) => console.error(level, data),
|
|
47
29
|
* prefix: '/forest',
|
|
48
30
|
* schemaPath: '.forestadmin-schema.json',
|
|
49
31
|
* permissionsCacheDurationInSeconds: 15 * 60,
|
|
50
32
|
* ```
|
|
51
|
-
* @param
|
|
33
|
+
* @param options options
|
|
52
34
|
* @example
|
|
53
35
|
* new AgentBuilder(options)
|
|
54
|
-
* .
|
|
36
|
+
* .addDataSource(new DataSource())
|
|
55
37
|
* .start();
|
|
56
38
|
*/
|
|
57
39
|
constructor(options: AgentOptions);
|
|
58
40
|
/**
|
|
59
41
|
* Add a datasource
|
|
60
|
-
* @param
|
|
42
|
+
* @param factory the datasource to add
|
|
43
|
+
* @param options the options
|
|
61
44
|
*/
|
|
62
|
-
|
|
45
|
+
addDataSource(factory: DataSourceFactory, options?: DataSourceOptions): this;
|
|
46
|
+
/**
|
|
47
|
+
* Create a new API chart
|
|
48
|
+
* @param name name of the chart
|
|
49
|
+
* @param definition definition of the chart
|
|
50
|
+
* @example
|
|
51
|
+
* .addChart('numCustomers', {
|
|
52
|
+
* type: 'Value',
|
|
53
|
+
* render: (context, resultBuilder) => {
|
|
54
|
+
* return resultBuilder.value(123);
|
|
55
|
+
* }
|
|
56
|
+
* })
|
|
57
|
+
*/
|
|
58
|
+
addChart(name: string, definition: ChartDefinition<S>): this;
|
|
63
59
|
/**
|
|
64
60
|
* Allow to interact with a decorated collection
|
|
65
|
-
* @param
|
|
66
|
-
* @param
|
|
61
|
+
* @param name the name of the collection to manipulate
|
|
62
|
+
* @param handle a function that provide a
|
|
67
63
|
* collection builder on the given collection name
|
|
68
64
|
* @example
|
|
69
65
|
* .customizeCollection('books', books => books.renameField('xx', 'yy'))
|
|
70
66
|
*/
|
|
71
|
-
customizeCollection(name:
|
|
67
|
+
customizeCollection<N extends TCollectionName<S>>(name: N, handle: (collection: CollectionBuilder<S, N>) => unknown): this;
|
|
72
68
|
/**
|
|
73
|
-
*
|
|
69
|
+
* Expose the agent on a given port and host
|
|
70
|
+
* @param port port that should be used.
|
|
71
|
+
* @param host host that should be used.
|
|
74
72
|
*/
|
|
75
|
-
|
|
73
|
+
mountOnStandaloneServer(port?: number, host?: string): this;
|
|
74
|
+
/**
|
|
75
|
+
* Mount the agent on an express app.
|
|
76
|
+
* @param express instance of the express app or router.
|
|
77
|
+
*/
|
|
78
|
+
mountOnExpress(express: any): this;
|
|
79
|
+
/**
|
|
80
|
+
* Mount the agent on a fastify app
|
|
81
|
+
* @param fastify instance of the fastify app, or of a fastify context
|
|
82
|
+
*/
|
|
83
|
+
mountOnFastify(fastify: any): this;
|
|
84
|
+
/**
|
|
85
|
+
* Mount the agent on a koa app
|
|
86
|
+
* @param koa instance of a koa app or a koa Router.
|
|
87
|
+
*/
|
|
88
|
+
mountOnKoa(koa: any): this;
|
|
76
89
|
/**
|
|
77
|
-
*
|
|
90
|
+
* Mount the agent on a NestJS app
|
|
91
|
+
* @param nestJs instance of a NestJS application
|
|
78
92
|
*/
|
|
93
|
+
mountOnNestJs(nestJs: any): this;
|
|
94
|
+
/**
|
|
95
|
+
* Start the agent.
|
|
96
|
+
*/
|
|
97
|
+
start(): Promise<void>;
|
|
79
98
|
stop(): Promise<void>;
|
|
99
|
+
private useCallbackOnFastify;
|
|
100
|
+
private getConnectCallback;
|
|
80
101
|
}
|
|
81
102
|
//# sourceMappingURL=agent.d.ts.map
|
package/dist/builder/agent.js
CHANGED
|
@@ -1,11 +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");
|
|
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"));
|
|
7
34
|
const collection_1 = __importDefault(require("./collection"));
|
|
35
|
+
const decorators_stack_1 = __importDefault(require("./decorators-stack"));
|
|
8
36
|
const forestadmin_http_driver_1 = __importDefault(require("../agent/forestadmin-http-driver"));
|
|
37
|
+
const options_validator_1 = __importDefault(require("./utils/options-validator"));
|
|
38
|
+
const typing_generator_1 = __importDefault(require("./utils/typing-generator"));
|
|
9
39
|
/**
|
|
10
40
|
* Allow to create a new Forest Admin agent from scratch.
|
|
11
41
|
* Builds the application by composing and configuring all the collection decorators.
|
|
@@ -13,7 +43,7 @@ const forestadmin_http_driver_1 = __importDefault(require("../agent/forestadmin-
|
|
|
13
43
|
* Minimal code to add a datasource
|
|
14
44
|
* @example
|
|
15
45
|
* new AgentBuilder(options)
|
|
16
|
-
* .
|
|
46
|
+
* .addDataSource(new SomeDataSource())
|
|
17
47
|
* .start();
|
|
18
48
|
*/
|
|
19
49
|
class AgentBuilder {
|
|
@@ -23,91 +53,209 @@ class AgentBuilder {
|
|
|
23
53
|
* ```
|
|
24
54
|
* clientId: null,
|
|
25
55
|
* forestServerUrl: 'https://api.forestadmin.com',
|
|
26
|
-
* logger: (level, data) => console.error(
|
|
56
|
+
* logger: (level, data) => console.error(level, data),
|
|
27
57
|
* prefix: '/forest',
|
|
28
58
|
* schemaPath: '.forestadmin-schema.json',
|
|
29
59
|
* permissionsCacheDurationInSeconds: 15 * 60,
|
|
30
60
|
* ```
|
|
31
|
-
* @param
|
|
61
|
+
* @param options options
|
|
32
62
|
* @example
|
|
33
63
|
* new AgentBuilder(options)
|
|
34
|
-
* .
|
|
64
|
+
* .addDataSource(new DataSource())
|
|
35
65
|
* .start();
|
|
36
66
|
*/
|
|
37
67
|
constructor(options) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
last = this.earlyComputed = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.ComputedCollectionDecorator);
|
|
45
|
-
last = this.earlyOpEmulate = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.OperatorsEmulateCollectionDecorator);
|
|
46
|
-
last = this.earlyOpReplace = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.OperatorsReplaceCollectionDecorator);
|
|
47
|
-
last = this.relation = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.RelationCollectionDecorator);
|
|
48
|
-
last = this.lateComputed = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.ComputedCollectionDecorator);
|
|
49
|
-
last = this.lateOpEmulate = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.OperatorsEmulateCollectionDecorator);
|
|
50
|
-
last = this.lateOpReplace = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.OperatorsReplaceCollectionDecorator);
|
|
51
|
-
// Step 2: Those five need access to all fields. They can be loaded in any order.
|
|
52
|
-
last = this.publication = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.PublicationCollectionDecorator);
|
|
53
|
-
last = this.search = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.SearchCollectionDecorator);
|
|
54
|
-
last = this.segment = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.SegmentCollectionDecorator);
|
|
55
|
-
last = this.sortEmulate = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.SortEmulateCollectionDecorator);
|
|
56
|
-
last = this.write = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.WriteCollectionDecorator);
|
|
57
|
-
// Step 3: Access to all fields AND emulated capabilities
|
|
58
|
-
last = this.action = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.ActionCollectionDecorator);
|
|
59
|
-
// Step 4: Renaming must be either the very first or very last so that naming in customer code
|
|
60
|
-
// is consistent.
|
|
61
|
-
last = this.rename = new datasource_toolkit_1.DataSourceDecorator(last, datasource_toolkit_1.RenameCollectionDecorator);
|
|
62
|
-
/* eslint-enable no-multi-assign */
|
|
63
|
-
this.forestAdminHttpDriver = new forestadmin_http_driver_1.default(last, options);
|
|
68
|
+
this.customizations = [];
|
|
69
|
+
this.mounts = [];
|
|
70
|
+
this.termination = [];
|
|
71
|
+
this.options = options_validator_1.default.withDefaults(options);
|
|
72
|
+
this.compositeDataSource = new datasource_toolkit_1.BaseDataSource();
|
|
73
|
+
this.stack = new decorators_stack_1.default(this.compositeDataSource);
|
|
64
74
|
}
|
|
65
75
|
/**
|
|
66
|
-
*
|
|
67
|
-
* @
|
|
68
|
-
*
|
|
69
|
-
* ...
|
|
70
|
-
* const server = http.createServer(agent.httpCallback);
|
|
76
|
+
* Add a datasource
|
|
77
|
+
* @param factory the datasource to add
|
|
78
|
+
* @param options the options
|
|
71
79
|
*/
|
|
72
|
-
|
|
73
|
-
|
|
80
|
+
addDataSource(factory, options) {
|
|
81
|
+
this.customizations.push(async () => {
|
|
82
|
+
const dataSource = await factory(this.options.logger);
|
|
83
|
+
const decorated = new datasource_toolkit_1.RenameCollectionDataSourceDecorator(dataSource);
|
|
84
|
+
for (const [oldName, newName] of Object.entries(options?.rename ?? {})) {
|
|
85
|
+
decorated.renameCollection(oldName, newName);
|
|
86
|
+
}
|
|
87
|
+
for (const collection of decorated.collections) {
|
|
88
|
+
this.compositeDataSource.addCollection(collection);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
return this;
|
|
74
92
|
}
|
|
75
93
|
/**
|
|
76
|
-
*
|
|
77
|
-
* @param
|
|
94
|
+
* Create a new API chart
|
|
95
|
+
* @param name name of the chart
|
|
96
|
+
* @param definition definition of the chart
|
|
97
|
+
* @example
|
|
98
|
+
* .addChart('numCustomers', {
|
|
99
|
+
* type: 'Value',
|
|
100
|
+
* render: (context, resultBuilder) => {
|
|
101
|
+
* return resultBuilder.value(123);
|
|
102
|
+
* }
|
|
103
|
+
* })
|
|
78
104
|
*/
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
this.
|
|
105
|
+
addChart(name, definition) {
|
|
106
|
+
this.customizations.push(async () => {
|
|
107
|
+
this.stack.chart.addChart(name, definition);
|
|
82
108
|
});
|
|
83
109
|
return this;
|
|
84
110
|
}
|
|
85
111
|
/**
|
|
86
112
|
* Allow to interact with a decorated collection
|
|
87
|
-
* @param
|
|
88
|
-
* @param
|
|
113
|
+
* @param name the name of the collection to manipulate
|
|
114
|
+
* @param handle a function that provide a
|
|
89
115
|
* collection builder on the given collection name
|
|
90
116
|
* @example
|
|
91
117
|
* .customizeCollection('books', books => books.renameField('xx', 'yy'))
|
|
92
118
|
*/
|
|
93
119
|
customizeCollection(name, handle) {
|
|
94
|
-
|
|
95
|
-
|
|
120
|
+
this.customizations.push(async () => {
|
|
121
|
+
if (this.stack.dataSource.getCollection(name)) {
|
|
122
|
+
handle(new collection_1.default(this.stack, name));
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Expose the agent on a given port and host
|
|
129
|
+
* @param port port that should be used.
|
|
130
|
+
* @param host host that should be used.
|
|
131
|
+
*/
|
|
132
|
+
mountOnStandaloneServer(port = 3351, host = 'localhost') {
|
|
133
|
+
const server = http_1.default.createServer(this.getConnectCallback(true));
|
|
134
|
+
server.listen(port, host);
|
|
135
|
+
this.options.logger('Info', `Successfully mounted on Standalone server (http://${host}:${port})`);
|
|
136
|
+
this.termination.push(async () => {
|
|
137
|
+
server.close();
|
|
138
|
+
});
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Mount the agent on an express app.
|
|
143
|
+
* @param express instance of the express app or router.
|
|
144
|
+
*/
|
|
145
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
146
|
+
mountOnExpress(express) {
|
|
147
|
+
express.use('/forest', this.getConnectCallback(false));
|
|
148
|
+
this.options.logger('Info', `Successfully mounted on Express.js`);
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Mount the agent on a fastify app
|
|
153
|
+
* @param fastify instance of the fastify app, or of a fastify context
|
|
154
|
+
*/
|
|
155
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
156
|
+
mountOnFastify(fastify) {
|
|
157
|
+
const callback = this.getConnectCallback(false);
|
|
158
|
+
this.useCallbackOnFastify(fastify, callback);
|
|
159
|
+
this.options.logger('Info', `Successfully mounted on Fastify`);
|
|
160
|
+
return this;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Mount the agent on a koa app
|
|
164
|
+
* @param koa instance of a koa app or a koa Router.
|
|
165
|
+
*/
|
|
166
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
167
|
+
mountOnKoa(koa) {
|
|
168
|
+
const parentRouter = new router_1.default({ prefix: '/forest' });
|
|
169
|
+
koa.use(parentRouter.routes());
|
|
170
|
+
this.options.logger('Info', `Successfully mounted on Koa`);
|
|
171
|
+
this.mounts.push(async (router) => {
|
|
172
|
+
parentRouter.use(router.routes());
|
|
173
|
+
});
|
|
174
|
+
return this;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Mount the agent on a NestJS app
|
|
178
|
+
* @param nestJs instance of a NestJS application
|
|
179
|
+
*/
|
|
180
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
181
|
+
mountOnNestJs(nestJs) {
|
|
182
|
+
const adapter = nestJs.getHttpAdapter();
|
|
183
|
+
const callback = this.getConnectCallback(false);
|
|
184
|
+
if (adapter.constructor.name === 'ExpressAdapter') {
|
|
185
|
+
nestJs.use('/forest', callback);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
this.useCallbackOnFastify(nestJs, callback);
|
|
96
189
|
}
|
|
190
|
+
this.options.logger('Info', `Successfully mounted on NestJS`);
|
|
97
191
|
return this;
|
|
98
192
|
}
|
|
99
193
|
/**
|
|
100
194
|
* Start the agent.
|
|
101
195
|
*/
|
|
102
196
|
async start() {
|
|
103
|
-
|
|
197
|
+
// Customize agent
|
|
198
|
+
for (const task of this.customizations)
|
|
199
|
+
await task(); // eslint-disable-line no-await-in-loop
|
|
200
|
+
// Check that options are valid
|
|
201
|
+
const options = options_validator_1.default.validate(this.options);
|
|
202
|
+
// Write typings file
|
|
203
|
+
if (!options.isProduction && options.typingsPath) {
|
|
204
|
+
const types = typing_generator_1.default.generateTypes(this.stack.action, options.typingsMaxDepth);
|
|
205
|
+
await (0, promises_1.writeFile)(options.typingsPath, types, { encoding: 'utf-8' });
|
|
206
|
+
}
|
|
207
|
+
const httpDriver = new forestadmin_http_driver_1.default(this.stack.dataSource, options);
|
|
208
|
+
await httpDriver.sendSchema();
|
|
209
|
+
const router = await httpDriver.getRouter();
|
|
210
|
+
for (const task of this.mounts)
|
|
211
|
+
await task(router); // eslint-disable-line no-await-in-loop
|
|
104
212
|
}
|
|
105
|
-
/**
|
|
106
|
-
* Stop the agent gracefully.
|
|
107
|
-
*/
|
|
108
213
|
async stop() {
|
|
109
|
-
|
|
214
|
+
for (const task of this.termination)
|
|
215
|
+
await task(); // eslint-disable-line no-await-in-loop
|
|
216
|
+
}
|
|
217
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
218
|
+
useCallbackOnFastify(fastify, callback) {
|
|
219
|
+
try {
|
|
220
|
+
// 'fastify 2' or 'middie' or 'fastify-express'
|
|
221
|
+
fastify.use('/forest', callback);
|
|
222
|
+
}
|
|
223
|
+
catch (e) {
|
|
224
|
+
// 'fastify 3'
|
|
225
|
+
if (e.code === 'FST_ERR_MISSING_MIDDLEWARE') {
|
|
226
|
+
fastify
|
|
227
|
+
.register(Promise.resolve().then(() => __importStar(require('@fastify/express'))))
|
|
228
|
+
.then(() => {
|
|
229
|
+
fastify.use('/forest', callback);
|
|
230
|
+
})
|
|
231
|
+
.catch(err => {
|
|
232
|
+
this.options.logger('Error', err.message);
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
throw e;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
getConnectCallback(nested) {
|
|
241
|
+
let handler = null;
|
|
242
|
+
this.mounts.push(async (driverRouter) => {
|
|
243
|
+
let router = driverRouter;
|
|
244
|
+
if (nested) {
|
|
245
|
+
router = new router_1.default({ prefix: '/forest' }).use(router.routes());
|
|
246
|
+
}
|
|
247
|
+
handler = new koa_1.default().use(router.routes()).callback();
|
|
248
|
+
});
|
|
249
|
+
return (req, res) => {
|
|
250
|
+
if (handler) {
|
|
251
|
+
handler(req, res);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
255
|
+
res.end(JSON.stringify({ error: 'Agent is not started' }));
|
|
256
|
+
}
|
|
257
|
+
};
|
|
110
258
|
}
|
|
111
259
|
}
|
|
112
260
|
exports.default = AgentBuilder;
|
|
113
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
261
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYnVpbGRlci9hZ2VudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsd0VBUXlDO0FBQ3pDLDBDQUF3QztBQUN4Qyw4Q0FBc0I7QUFDdEIseURBQWlDO0FBQ2pDLGdEQUF3QjtBQUl4Qiw4REFBNkM7QUFDN0MsMEVBQWlEO0FBQ2pELCtGQUFxRTtBQUNyRSxrRkFBeUQ7QUFDekQsZ0ZBQXVEO0FBRXZEOzs7Ozs7Ozs7R0FTRztBQUNILE1BQXFCLFlBQVk7SUFRL0I7Ozs7Ozs7Ozs7Ozs7Ozs7T0FnQkc7SUFDSCxZQUFZLE9BQXFCO1FBckJ6QixtQkFBYyxHQUE0QixFQUFFLENBQUM7UUFDN0MsV0FBTSxHQUEwQyxFQUFFLENBQUM7UUFDbkQsZ0JBQVcsR0FBNEIsRUFBRSxDQUFDO1FBb0JoRCxJQUFJLENBQUMsT0FBTyxHQUFHLDJCQUFnQixDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN0RCxJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSxtQ0FBYyxFQUFjLENBQUM7UUFDNUQsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLDBCQUFlLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDN0QsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxhQUFhLENBQUMsT0FBMEIsRUFBRSxPQUEyQjtRQUNuRSxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxLQUFLLElBQUksRUFBRTtZQUNsQyxNQUFNLFVBQVUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3RELE1BQU0sU0FBUyxHQUFHLElBQUksd0RBQW1DLENBQUMsVUFBVSxDQUFDLENBQUM7WUFFdEUsS0FBSyxNQUFNLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxP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
|