@forestadmin/agent 1.0.0-alpha.1

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.
Files changed (119) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +0 -0
  3. package/dist/agent.d.ts +76 -0
  4. package/dist/agent.js +133 -0
  5. package/dist/framework-mounter.d.ts +43 -0
  6. package/dist/framework-mounter.js +157 -0
  7. package/dist/index.d.ts +8 -0
  8. package/dist/index.js +15 -0
  9. package/dist/routes/access/api-chart.d.ts +16 -0
  10. package/dist/routes/access/api-chart.js +47 -0
  11. package/dist/routes/access/chart.d.ts +18 -0
  12. package/dist/routes/access/chart.js +162 -0
  13. package/dist/routes/access/count-related.d.ts +9 -0
  14. package/dist/routes/access/count-related.js +31 -0
  15. package/dist/routes/access/count.d.ts +9 -0
  16. package/dist/routes/access/count.js +31 -0
  17. package/dist/routes/access/csv-related.d.ts +9 -0
  18. package/dist/routes/access/csv-related.js +33 -0
  19. package/dist/routes/access/csv.d.ts +9 -0
  20. package/dist/routes/access/csv.js +31 -0
  21. package/dist/routes/access/get.d.ts +9 -0
  22. package/dist/routes/access/get.js +29 -0
  23. package/dist/routes/access/list-related.d.ts +9 -0
  24. package/dist/routes/access/list-related.js +25 -0
  25. package/dist/routes/access/list.d.ts +9 -0
  26. package/dist/routes/access/list.js +22 -0
  27. package/dist/routes/base-route.d.ts +13 -0
  28. package/dist/routes/base-route.js +13 -0
  29. package/dist/routes/collection-route.d.ts +12 -0
  30. package/dist/routes/collection-route.js +20 -0
  31. package/dist/routes/index.d.ts +30 -0
  32. package/dist/routes/index.js +108 -0
  33. package/dist/routes/modification/action.d.ts +16 -0
  34. package/dist/routes/modification/action.js +104 -0
  35. package/dist/routes/modification/associate-related.d.ts +12 -0
  36. package/dist/routes/modification/associate-related.js +51 -0
  37. package/dist/routes/modification/create.d.ts +14 -0
  38. package/dist/routes/modification/create.js +83 -0
  39. package/dist/routes/modification/delete.d.ts +11 -0
  40. package/dist/routes/modification/delete.js +41 -0
  41. package/dist/routes/modification/dissociate-delete-related.d.ts +20 -0
  42. package/dist/routes/modification/dissociate-delete-related.js +89 -0
  43. package/dist/routes/modification/update-field.d.ts +9 -0
  44. package/dist/routes/modification/update-field.js +39 -0
  45. package/dist/routes/modification/update-relation.d.ts +11 -0
  46. package/dist/routes/modification/update-relation.js +59 -0
  47. package/dist/routes/modification/update.d.ts +9 -0
  48. package/dist/routes/modification/update.js +31 -0
  49. package/dist/routes/relation-route.d.ts +10 -0
  50. package/dist/routes/relation-route.js +18 -0
  51. package/dist/routes/security/authentication.d.ts +15 -0
  52. package/dist/routes/security/authentication.js +74 -0
  53. package/dist/routes/security/ip-whitelist.d.ts +14 -0
  54. package/dist/routes/security/ip-whitelist.js +35 -0
  55. package/dist/routes/security/scope-invalidation.d.ts +11 -0
  56. package/dist/routes/security/scope-invalidation.js +28 -0
  57. package/dist/routes/system/error-handling.d.ts +13 -0
  58. package/dist/routes/system/error-handling.js +75 -0
  59. package/dist/routes/system/healthcheck.d.ts +11 -0
  60. package/dist/routes/system/healthcheck.js +22 -0
  61. package/dist/routes/system/logger.d.ts +10 -0
  62. package/dist/routes/system/logger.js +35 -0
  63. package/dist/services/authorization/authorization.d.ts +15 -0
  64. package/dist/services/authorization/authorization.js +45 -0
  65. package/dist/services/authorization/index.d.ts +5 -0
  66. package/dist/services/authorization/index.js +16 -0
  67. package/dist/services/authorization/internal/action-permission.d.ts +16 -0
  68. package/dist/services/authorization/internal/action-permission.js +68 -0
  69. package/dist/services/authorization/internal/generate-action-identifier.d.ts +4 -0
  70. package/dist/services/authorization/internal/generate-action-identifier.js +12 -0
  71. package/dist/services/authorization/internal/generate-actions-from-permissions.d.ts +8 -0
  72. package/dist/services/authorization/internal/generate-actions-from-permissions.js +87 -0
  73. package/dist/services/authorization/internal/types.d.ts +61 -0
  74. package/dist/services/authorization/internal/types.js +26 -0
  75. package/dist/services/index.d.ts +12 -0
  76. package/dist/services/index.js +16 -0
  77. package/dist/services/permissions.d.ts +19 -0
  78. package/dist/services/permissions.js +85 -0
  79. package/dist/services/serializer.d.ts +12 -0
  80. package/dist/services/serializer.js +120 -0
  81. package/dist/types.d.ts +41 -0
  82. package/dist/types.js +23 -0
  83. package/dist/utils/body-parser.d.ts +7 -0
  84. package/dist/utils/body-parser.js +18 -0
  85. package/dist/utils/condition-tree-parser.d.ts +11 -0
  86. package/dist/utils/condition-tree-parser.js +53 -0
  87. package/dist/utils/context-filter-factory.d.ts +7 -0
  88. package/dist/utils/context-filter-factory.js +28 -0
  89. package/dist/utils/csv-generator.d.ts +12 -0
  90. package/dist/utils/csv-generator.js +39 -0
  91. package/dist/utils/csv-route-context.d.ts +5 -0
  92. package/dist/utils/csv-route-context.js +14 -0
  93. package/dist/utils/forest-http-api.d.ts +68 -0
  94. package/dist/utils/forest-http-api.js +202 -0
  95. package/dist/utils/forest-schema/action-values.d.ts +34 -0
  96. package/dist/utils/forest-schema/action-values.js +144 -0
  97. package/dist/utils/forest-schema/emitter.d.ts +20 -0
  98. package/dist/utils/forest-schema/emitter.js +70 -0
  99. package/dist/utils/forest-schema/filterable.d.ts +16 -0
  100. package/dist/utils/forest-schema/filterable.js +68 -0
  101. package/dist/utils/forest-schema/generator-actions.d.ts +14 -0
  102. package/dist/utils/forest-schema/generator-actions.js +99 -0
  103. package/dist/utils/forest-schema/generator-collection.d.ts +7 -0
  104. package/dist/utils/forest-schema/generator-collection.js +36 -0
  105. package/dist/utils/forest-schema/generator-fields.d.ts +14 -0
  106. package/dist/utils/forest-schema/generator-fields.js +160 -0
  107. package/dist/utils/forest-schema/generator-segments.d.ts +6 -0
  108. package/dist/utils/forest-schema/generator-segments.js +9 -0
  109. package/dist/utils/forest-schema/types.d.ts +85 -0
  110. package/dist/utils/forest-schema/types.js +16 -0
  111. package/dist/utils/forest-schema/validation.d.ts +10 -0
  112. package/dist/utils/forest-schema/validation.js +28 -0
  113. package/dist/utils/id.d.ts +8 -0
  114. package/dist/utils/id.js +43 -0
  115. package/dist/utils/options-validator.d.ts +12 -0
  116. package/dist/utils/options-validator.js +92 -0
  117. package/dist/utils/query-string.d.ts +14 -0
  118. package/dist/utils/query-string.js +134 -0
  119. package/package.json +66 -0
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const object_hash_1 = __importDefault(require("object-hash"));
7
+ const superagent_1 = __importDefault(require("superagent"));
8
+ class ForestHttpApi {
9
+ static async getIpWhitelistConfiguration(options) {
10
+ try {
11
+ const response = await superagent_1.default
12
+ .get(new URL('/liana/v1/ip-whitelist-rules', options.forestServerUrl).toString())
13
+ .set('forest-secret-key', options.envSecret);
14
+ const { attributes } = response.body.data;
15
+ return { isFeatureEnabled: attributes.use_ip_whitelist, ipRules: attributes.rules };
16
+ }
17
+ catch (e) {
18
+ this.handleResponseError(e);
19
+ }
20
+ }
21
+ static async getOpenIdIssuerMetadata(options) {
22
+ try {
23
+ const response = await superagent_1.default
24
+ .get(new URL('/oidc/.well-known/openid-configuration', options.forestServerUrl).toString())
25
+ .set('forest-secret-key', options.envSecret);
26
+ return response.body;
27
+ }
28
+ catch (e) {
29
+ this.handleResponseError(e);
30
+ }
31
+ }
32
+ static async getUserInformation(options, renderingId, accessToken) {
33
+ try {
34
+ const url = new URL(`/liana/v2/renderings/${renderingId}/authorization`, options.forestServerUrl);
35
+ const response = await superagent_1.default
36
+ .get(url.toString())
37
+ .set('forest-token', accessToken)
38
+ .set('forest-secret-key', options.envSecret);
39
+ const { attributes, id } = response.body.data;
40
+ return {
41
+ id: Number(id),
42
+ email: attributes.email,
43
+ firstName: attributes.first_name,
44
+ lastName: attributes.last_name,
45
+ team: attributes.teams[0],
46
+ role: attributes.role,
47
+ tags: attributes.tags?.reduce((memo, { key, value }) => ({ ...memo, [key]: value }), {}),
48
+ renderingId,
49
+ permissionLevel: attributes.permission_level,
50
+ };
51
+ }
52
+ catch (e) {
53
+ this.handleResponseError(e);
54
+ }
55
+ }
56
+ static async hasSchema(options, hash) {
57
+ try {
58
+ const response = await superagent_1.default
59
+ .post(new URL('/forest/apimaps/hashcheck', options.forestServerUrl).toString())
60
+ .send({ schemaFileHash: hash })
61
+ .set('forest-secret-key', options.envSecret);
62
+ return !response?.body?.sendSchema;
63
+ }
64
+ catch (e) {
65
+ this.handleResponseError(e);
66
+ }
67
+ }
68
+ static async uploadSchema(options, apimap) {
69
+ try {
70
+ await superagent_1.default
71
+ .post(new URL('/forest/apimaps', options.forestServerUrl).toString())
72
+ .send(apimap)
73
+ .set('forest-secret-key', options.envSecret);
74
+ }
75
+ catch (e) {
76
+ this.handleResponseError(e);
77
+ }
78
+ }
79
+ static async getPermissions(options, renderingId) {
80
+ try {
81
+ const { body } = await superagent_1.default
82
+ .get(`${options.forestServerUrl}/liana/v3/permissions`)
83
+ .set('forest-secret-key', options.envSecret)
84
+ .query(`renderingId=${renderingId}`);
85
+ if (!body.meta?.rolesACLActivated) {
86
+ throw new Error('Roles V2 are unsupported');
87
+ }
88
+ const actions = new Set();
89
+ const actionsByUser = {};
90
+ ForestHttpApi.decodeChartPermissions(body?.stats ?? {}, actions);
91
+ ForestHttpApi.decodeActionPermissions(body?.data?.collections ?? {}, actions, actionsByUser);
92
+ return {
93
+ actions,
94
+ actionsByUser,
95
+ scopes: ForestHttpApi.decodeScopePermissions(body?.data?.renderings?.[renderingId] ?? {}),
96
+ };
97
+ }
98
+ catch (e) {
99
+ this.handleResponseError(e);
100
+ }
101
+ }
102
+ static async getEnvironmentPermissions(options) {
103
+ try {
104
+ const { body } = await superagent_1.default
105
+ .get(`${options.forestServerUrl}/liana/v4/permissions/environment`)
106
+ .set('forest-secret-key', options.envSecret);
107
+ return body;
108
+ }
109
+ catch (e) {
110
+ this.handleResponseError(e);
111
+ }
112
+ }
113
+ static async getUsers(options) {
114
+ try {
115
+ const { body } = await superagent_1.default
116
+ .get(`${options.forestServerUrl}/liana/v4/permissions/users`)
117
+ .set('forest-secret-key', options.envSecret);
118
+ return body;
119
+ }
120
+ catch (e) {
121
+ this.handleResponseError(e);
122
+ }
123
+ }
124
+ /** Helper to format permissions into something easy to validate against */
125
+ static decodeChartPermissions(chartsByType, actions) {
126
+ const serverCharts = Object.values(chartsByType).flat();
127
+ const frontendCharts = serverCharts.map(chart => ({
128
+ type: chart.type,
129
+ filters: chart.filter,
130
+ aggregate: chart.aggregator,
131
+ aggregate_field: chart.aggregateFieldName,
132
+ collection: chart.sourceCollectionId,
133
+ time_range: chart.timeRange,
134
+ group_by_date_field: (chart.type === 'Line' && chart.groupByFieldName) || null,
135
+ group_by_field: (chart.type !== 'Line' && chart.groupByFieldName) || null,
136
+ limit: chart.limit,
137
+ label_field: chart.labelFieldName,
138
+ relationship_field: chart.relationshipFieldName,
139
+ }));
140
+ const hashes = frontendCharts.map(chart => (0, object_hash_1.default)(chart, {
141
+ respectType: false,
142
+ excludeKeys: key => chart[key] === null || chart[key] === undefined,
143
+ }));
144
+ hashes.forEach(hash => actions.add(`chart:${hash}`));
145
+ }
146
+ /**
147
+ * Helper to format permissions into something easy to validate against
148
+ * Note that the format the server is sending varies depending on if we're using a remote or
149
+ * local environment.
150
+ */
151
+ static decodeActionPermissions(collections, actions, actionsByUser) {
152
+ for (const [name, settings] of Object.entries(collections)) {
153
+ for (const [actionName, userIds] of Object.entries(settings.collection ?? {})) {
154
+ const shortName = actionName.substring(0, actionName.length - 'Enabled'.length);
155
+ if (typeof userIds === 'boolean')
156
+ actions.add(`${shortName}:${name}`);
157
+ else
158
+ actionsByUser[`${shortName}:${name}`] = new Set(userIds);
159
+ }
160
+ for (const [actionName, actionPerms] of Object.entries(settings.actions ?? {})) {
161
+ const userIds = actionPerms.triggerEnabled;
162
+ if (typeof userIds === 'boolean')
163
+ actions.add(`custom:${actionName}:${name}`);
164
+ else
165
+ actionsByUser[`custom:${actionName}:${name}`] = new Set(userIds);
166
+ }
167
+ }
168
+ }
169
+ /** Helper to format permissions into something easy to validate against */
170
+ static decodeScopePermissions(rendering) {
171
+ const scopes = {};
172
+ for (const [name, { scope }] of Object.entries(rendering)) {
173
+ scopes[name] = scope && {
174
+ conditionTree: scope.filter,
175
+ dynamicScopeValues: scope.dynamicScopesValues?.users ?? {},
176
+ };
177
+ }
178
+ return scopes;
179
+ }
180
+ static handleResponseError(e) {
181
+ if (/certificate/i.test(e.message))
182
+ throw new Error('ForestAdmin server TLS certificate cannot be verified. ' +
183
+ 'Please check that your system time is set properly.');
184
+ if (e.response) {
185
+ const status = e?.response?.status;
186
+ // 0 == offline, 502 == bad gateway from proxy
187
+ if (status === 0 || status === 502)
188
+ throw new Error('Failed to reach ForestAdmin server. Are you online?');
189
+ if (status === 404)
190
+ throw new Error('ForestAdmin server failed to find the project related to the envSecret you configured.' +
191
+ ' Can you check that you copied it properly in the Forest initialization?');
192
+ if (status === 503)
193
+ throw new Error('Forest is in maintenance for a few minutes. We are upgrading your experience in ' +
194
+ 'the forest. We just need a few more minutes to get it right.');
195
+ throw new Error('An unexpected error occured while contacting the ForestAdmin server. ' +
196
+ 'Please contact support@forestadmin.com for further investigations.');
197
+ }
198
+ throw e;
199
+ }
200
+ }
201
+ exports.default = ForestHttpApi;
202
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yZXN0LWh0dHAtYXBpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL2ZvcmVzdC1odHRwLWFwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUlBLDhEQUFxQztBQUNyQyw0REFBaUU7QUF5Q2pFLE1BQXFCLGFBQWE7SUFDaEMsTUFBTSxDQUFDLEtBQUssQ0FBQywyQkFBMkIsQ0FDdEMsT0FBb0I7UUFFcEIsSUFBSTtZQUNGLE1BQU0sUUFBUSxHQUFhLE1BQU0sb0JBQVU7aUJBQ3hDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsQ0FBQyw4QkFBOEIsRUFBRSxPQUFPLENBQUMsZUFBZSxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUM7aUJBQ2hGLEdBQUcsQ0FBQyxtQkFBbUIsRUFBRSxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7WUFFL0MsTUFBTSxFQUFFLFVBQVUsRUFBRSxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1lBRTFDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxVQUFVLENBQUMsZ0JBQWdCLEVBQUUsT0FBTyxFQUFFLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztTQUNyRjtRQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ1YsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQzdCO0lBQ0gsQ0FBQztJQUVELE1BQU0sQ0FBQyxLQUFLLENBQUMsdUJBQXVCLENBQUMsT0FBb0I7UUFDdkQsSUFBSTtZQUNGLE1BQU0sUUFBUSxHQUFhLE1BQU0sb0JBQVU7aUJBQ3hDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsQ0FBQyx3Q0FBd0MsRUFBRSxPQUFPLENBQUMsZUFBZSxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUM7aUJBQzFGLEdBQUcsQ0FBQyxtQkFBbUIsRUFBRSxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7WUFFL0MsT0FBTyxRQUFRLENBQUMsSUFBSSxDQUFDO1NBQ3RCO1FBQUMsT0FB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
@@ -0,0 +1,34 @@
1
+ import { ActionField, DataSource } from '@forestadmin/datasource-toolkit';
2
+ declare type FormData = Record<string, unknown>;
3
+ /**
4
+ * This utility class converts form values from our internal format to the format that is
5
+ * used in the frontend for action forms.
6
+ */
7
+ export default class ForestValueConverter {
8
+ /**
9
+ * Proper form data parser which converts data from an action form result to the format
10
+ * that is internally used in datasources.
11
+ */
12
+ static makeFormData(dataSource: DataSource, rawData: FormData, fields: ActionField[]): FormData;
13
+ /**
14
+ * Form data parser which extracts the data from what is provided by the frontend when
15
+ * change hooks are called.
16
+ */
17
+ static makeFormDataFromFields(dataSource: DataSource, fields: any[]): FormData;
18
+ /**
19
+ * This last form data parser tries to guess the types from the data itself.
20
+ *
21
+ * - Fields with type "Collection" which target collections where the pk is not a string or
22
+ * derivative (mongoid, uuid, ...) won't be parser correctly, as we don't have enough information
23
+ * to properly guess the type
24
+ * - Fields of type "String" but where the final user entered a data-uri manually in the frontend
25
+ * will be wrongfully parsed.
26
+ */
27
+ static makeFormDataUnsafe(rawData: FormData): FormData;
28
+ static valueToForest(field: ActionField, value: unknown): unknown;
29
+ private static parseDataUri;
30
+ private static makeDataUri;
31
+ private static isDataUri;
32
+ }
33
+ export {};
34
+ //# sourceMappingURL=action-values.d.ts.map
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const id_1 = __importDefault(require("../id"));
7
+ const generator_actions_1 = __importDefault(require("./generator-actions"));
8
+ /**
9
+ * This utility class converts form values from our internal format to the format that is
10
+ * used in the frontend for action forms.
11
+ */
12
+ class ForestValueConverter {
13
+ /**
14
+ * Proper form data parser which converts data from an action form result to the format
15
+ * that is internally used in datasources.
16
+ */
17
+ static makeFormData(dataSource, rawData, fields) {
18
+ const data = {};
19
+ for (const [key, value] of Object.entries(rawData)) {
20
+ const field = fields.find(f => f.label === key);
21
+ // Skip fields from the default form
22
+ if (!generator_actions_1.default.defaultFields.map(f => f.field).includes(key)) {
23
+ if (field?.type === 'Collection' && value) {
24
+ const collection = dataSource.getCollection(field.collectionName);
25
+ data[key] = id_1.default.unpackId(collection.schema, value);
26
+ }
27
+ else if (field?.type === 'File') {
28
+ data[key] = this.parseDataUri(value);
29
+ }
30
+ else if (field?.type === 'FileList') {
31
+ data[key] = value?.map(v => this.parseDataUri(v));
32
+ }
33
+ else {
34
+ data[key] = value;
35
+ }
36
+ }
37
+ }
38
+ return data;
39
+ }
40
+ /**
41
+ * Form data parser which extracts the data from what is provided by the frontend when
42
+ * change hooks are called.
43
+ */
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ static makeFormDataFromFields(dataSource, fields) {
46
+ const data = {};
47
+ for (const field of fields) {
48
+ // Skip fields from the default form
49
+ if (!generator_actions_1.default.defaultFields.map(f => f.field).includes(field.field)) {
50
+ if (field.reference && field.value) {
51
+ const [collectionName] = field.reference.split('.');
52
+ const collection = dataSource.getCollection(collectionName);
53
+ data[field.field] = id_1.default.unpackId(collection.schema, field.value);
54
+ }
55
+ else if (field.type === 'File') {
56
+ data[field.field] = this.parseDataUri(field.value);
57
+ }
58
+ else if (Array.isArray(field.type) && field.type[0] === 'File') {
59
+ data[field.field] = field.value?.map(v => this.parseDataUri(v));
60
+ }
61
+ else {
62
+ data[field.field] = field.value;
63
+ }
64
+ }
65
+ }
66
+ return data;
67
+ }
68
+ /**
69
+ * This last form data parser tries to guess the types from the data itself.
70
+ *
71
+ * - Fields with type "Collection" which target collections where the pk is not a string or
72
+ * derivative (mongoid, uuid, ...) won't be parser correctly, as we don't have enough information
73
+ * to properly guess the type
74
+ * - Fields of type "String" but where the final user entered a data-uri manually in the frontend
75
+ * will be wrongfully parsed.
76
+ */
77
+ static makeFormDataUnsafe(rawData) {
78
+ const data = {};
79
+ for (const [key, value] of Object.entries(rawData)) {
80
+ // Skip fields from the default form
81
+ if (!generator_actions_1.default.defaultFields.map(f => f.field).includes(key)) {
82
+ if (Array.isArray(value) && value.every(v => this.isDataUri(v))) {
83
+ data[key] = value.map(uri => this.parseDataUri(uri));
84
+ }
85
+ else if (this.isDataUri(value)) {
86
+ data[key] = this.parseDataUri(value);
87
+ }
88
+ else {
89
+ data[key] = value;
90
+ }
91
+ }
92
+ }
93
+ return data;
94
+ }
95
+ static valueToForest(field, value) {
96
+ if (field.type === 'Enum') {
97
+ return field.enumValues.includes(value) ? value : null;
98
+ }
99
+ if (field.type === 'EnumList') {
100
+ return value?.filter(v => field.enumValues.includes(v));
101
+ }
102
+ if (field.type === 'Collection') {
103
+ return value?.join('|');
104
+ }
105
+ if (field.type === 'File') {
106
+ return this.makeDataUri(value);
107
+ }
108
+ if (field.type === 'FileList') {
109
+ return value?.map(f => this.makeDataUri(f));
110
+ }
111
+ return value;
112
+ }
113
+ static parseDataUri(dataUri) {
114
+ if (!dataUri)
115
+ return null;
116
+ // Poor man's data uri parser (spec compliants one don't get the filename).
117
+ // Hopefully this does not break.
118
+ const [header, data] = dataUri.substring(5).split(',');
119
+ const [mimeType, ...mediaTypes] = header.split(';');
120
+ const result = { mimeType, buffer: Buffer.from(data, 'base64') };
121
+ for (const mediaType of mediaTypes) {
122
+ const index = mediaType.indexOf('=');
123
+ if (index !== -1)
124
+ result[mediaType.substring(0, index)] = decodeURIComponent(mediaType.substring(index + 1));
125
+ }
126
+ return result;
127
+ }
128
+ static makeDataUri(file) {
129
+ if (!file)
130
+ return null;
131
+ const { mimeType, buffer, ...rest } = file;
132
+ const mediaTypes = Object.entries(rest)
133
+ .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
134
+ .join(';');
135
+ return mediaTypes.length
136
+ ? `data:${file.mimeType};${mediaTypes};base64,${buffer.toString('base64')}`
137
+ : `data:${file.mimeType};base64,${buffer.toString('base64')}`;
138
+ }
139
+ static isDataUri(value) {
140
+ return typeof value === 'string' && value.startsWith('data:');
141
+ }
142
+ }
143
+ exports.default = ForestValueConverter;
144
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLXZhbHVlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy91dGlscy9mb3Jlc3Qtc2NoZW1hL2FjdGlvbi12YWx1ZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFDQSwrQ0FBNEI7QUFDNUIsNEVBQXlEO0FBSXpEOzs7R0FHRztBQUNILE1BQXFCLG9CQUFvQjtJQUN2Qzs7O09BR0c7SUFDSCxNQUFNLENBQUMsWUFBWSxDQUFDLFVBQXNCLEVBQUUsT0FBaUIsRUFBRSxNQUFxQjtRQUNsRixNQUFNLElBQUksR0FBRyxFQUFFLENBQUM7UUFFaEIsS0FBSyxNQUFNLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUU7WUFDbEQsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUssR0FBRyxDQUFDLENBQUM7WUFFaEQsb0NBQW9DO1lBQ3BDLElBQUksQ0FBQywyQkFBc0IsQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRTtnQkFDekUsSUFBSSxLQUFLLEVBQUUsSUFBSSxLQUFLLFlBQVksSUFBSSxLQUFLLEVBQUU7b0JBQ3pDLE1BQU0sVUFBVSxHQUFHLFVBQVUsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDO29CQUVsRSxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsWUFBTyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLEtBQWUsQ0FBQyxDQUFDO2lCQUNsRTtxQkFBTSxJQUFJLEtBQUssRUFBRSxJQUFJLEtBQUssTUFBTSxFQUFFO29CQUNqQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBSSxD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
@@ -0,0 +1,20 @@
1
+ import { DataSource } from '@forestadmin/datasource-toolkit';
2
+ import { AgentOptions } from '../../types';
3
+ declare type SerializedSchema = {
4
+ meta: {
5
+ schemaFileHash: string;
6
+ };
7
+ };
8
+ declare type Options = Pick<AgentOptions, 'isProduction' | 'schemaPath'>;
9
+ /**
10
+ * Generate and dispatch dataSource schema on agent start.
11
+ */
12
+ export default class SchemaEmitter {
13
+ private static readonly meta;
14
+ static getSerializedSchema(options: Options, dataSource: DataSource): Promise<SerializedSchema>;
15
+ private static loadFromDisk;
16
+ private static generate;
17
+ private static serialize;
18
+ }
19
+ export {};
20
+ //# sourceMappingURL=emitter.d.ts.map
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const promises_1 = require("fs/promises");
7
+ const json_api_serializer_1 = __importDefault(require("json-api-serializer"));
8
+ const crypto_1 = __importDefault(require("crypto"));
9
+ const json_stringify_pretty_compact_1 = __importDefault(require("json-stringify-pretty-compact"));
10
+ const generator_collection_1 = __importDefault(require("./generator-collection"));
11
+ // Load version from package.json at startup
12
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
13
+ const { version } = require('../../../package.json');
14
+ /**
15
+ * Generate and dispatch dataSource schema on agent start.
16
+ */
17
+ class SchemaEmitter {
18
+ static async getSerializedSchema(options, dataSource) {
19
+ const schema = options.isProduction
20
+ ? await SchemaEmitter.loadFromDisk(options.schemaPath)
21
+ : await SchemaEmitter.generate(dataSource);
22
+ if (!options.isProduction) {
23
+ const pretty = (0, json_stringify_pretty_compact_1.default)(schema, { maxLength: 80 });
24
+ await (0, promises_1.writeFile)(options.schemaPath, pretty, { encoding: 'utf-8' });
25
+ }
26
+ const hash = crypto_1.default.createHash('sha1').update(JSON.stringify(schema)).digest('hex');
27
+ return SchemaEmitter.serialize(schema, hash);
28
+ }
29
+ static async loadFromDisk(schemaPath) {
30
+ try {
31
+ const fileContent = await (0, promises_1.readFile)(schemaPath, { encoding: 'utf-8' });
32
+ return JSON.parse(fileContent);
33
+ }
34
+ catch (e) {
35
+ throw new Error(`Cannot load ${schemaPath}. Providing a schema is mandatory in production mode.`);
36
+ }
37
+ }
38
+ static async generate(dataSource) {
39
+ const allCollectionSchemas = [];
40
+ const dataSourceCollectionSchemas = dataSource.collections.map(collection => generator_collection_1.default.buildSchema(collection));
41
+ allCollectionSchemas.push(...dataSourceCollectionSchemas);
42
+ return Promise.all(allCollectionSchemas);
43
+ }
44
+ static serialize(schema, hash) {
45
+ // Build serializer
46
+ const serializer = new json_api_serializer_1.default();
47
+ serializer.register('collections', {
48
+ // Pass the metadata provided to the serialization fn
49
+ topLevelMeta: (extraData) => extraData,
50
+ relationships: {
51
+ segments: { type: 'segments' },
52
+ actions: { type: 'actions' },
53
+ },
54
+ });
55
+ serializer.register('segments', {});
56
+ serializer.register('actions', {});
57
+ // Serialize
58
+ return serializer.serialize('collections', schema.map(c => ({ id: c.name, ...c })), { ...SchemaEmitter.meta, schemaFileHash: hash });
59
+ }
60
+ }
61
+ exports.default = SchemaEmitter;
62
+ SchemaEmitter.meta = {
63
+ liana: 'forest-nodejs-agent',
64
+ liana_version: version,
65
+ stack: {
66
+ engine: 'nodejs',
67
+ engine_version: process.versions && process.versions.node,
68
+ },
69
+ };
70
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW1pdHRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy91dGlscy9mb3Jlc3Qtc2NoZW1hL2VtaXR0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFDQSwwQ0FBa0Q7QUFDbEQsOEVBQW9EO0FBQ3BELG9EQUE0QjtBQUM1QixrR0FBc0Q7QUFJdEQsa0ZBQStEO0FBTS9ELDRDQUE0QztBQUM1Qyw4REFBOEQ7QUFDOUQsTUFBTSxFQUFFLE9BQU8sRUFBRSxHQUFHLE9BQU8sQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0FBRXJEOztHQUVHO0FBQ0gsTUFBcUIsYUFBYTtJQVVoQyxNQUFNLENBQUMsS0FBSyxDQUFDLG1CQUFtQixDQUM5QixPQUFnQixFQUNoQixVQUFzQjtRQUV0QixNQUFNLE1BQU0sR0FBYyxPQUFPLENBQUMsWUFBWTtZQUM1QyxDQUFDLENBQUMsTUFBTSxhQUFhLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUM7WUFDdEQsQ0FBQyxDQUFDLE1BQU0sYUFBYSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUU3QyxJQUFJLENBQUMsT0FBTyxDQUFDLFlBQVksRUFBRTtZQUN6QixNQUFNLE1BQU0sR0FBRyxJQUFBLHVDQUFTLEVBQUMsTUFBTSxFQUFFLEVBQUUsU0FBUyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDcEQsTUFBTSxJQUFBLG9CQUFTLEVBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxNQUFNLEVBQUUsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztTQUNwRTtRQUVELE1BQU0sSUFBSSxHQUFHLGdCQUFNLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRXBGLE9BQU8sYUFBYSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVPLE1BQU0sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLFVBQWtCO1FBQ2xELElBQUk7WUFDRixNQUFNLFdBQVcsR0FBRyxNQUFNLElBQUEsbUJBQVEsRUFBQyxVQUFVLEVBQUUsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUV0RSxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUM7U0FDaEM7UUFBQyxPQUFPLENBQUMsRUFBRTtZQUNWLE1BQU0sSUFBSSxLQUFLLENBQ2IsZUFBZSxVQUFVLHVEQUF1RCxDQUNqRixDQUFDO1NBQ0g7SUFDSCxDQUFDO0lBRU8sTUFBTSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsVUFBc0I7UUFDbEQsTUFBTSxvQkFBb0IsR0FBRyxFQUFFLENBQUM7UUFFaEMsTUFBTSwyQkFBMkIsR0FBRyxVQUFVLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUMxRSw4QkFBeUIsQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLENBQ2xELENBQUM7UUFDRixvQkFBb0IsQ0FBQyxJQUFJLENBQUMsR0FBRywyQkFBMkIsQ0FBQyxDQUFDO1FBRTFELE9BQU8sT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFTyxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQWlCLEVBQUUsSUFBWTtRQUN0RCxtQkFBbUI7UUFDbkIsTUFBTSxVQUFVLEdBQUcsSUFBSSw2QkFBaUIsRUFBRSxDQUFDO1FBRTNDLFVBQVUsQ0FBQyxRQUFRLENBQUMsYUFBYSxFQUFFO1lBQ2pDLHFEQUFxRDtZQUNyRCxZQUFZLEVBQUUsQ0FBQyxTQUFrQixFQUFFLEVBQUUsQ0FBQyxTQUFTO1lBQy9DLGFBQWEsRUFBRTtnQkFDYixRQUFRLEVBQUUsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFO2dCQUM5QixPQUFPLEVBQUUsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFO2FBQzdCO1NBQ0YsQ0FBQyxDQUFDO1FBQ0gsVUFBVSxDQUFDLFFBQVEsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDcEMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFbkMsWUFBWTtRQUNaLE9BQU8sVUFBVSxDQUFDLFNBQVMsQ0FDekIsYUFBYSxFQUNiLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQ3ZDLEVBQUUsR0FBRyxhQUFhLENBQUMsSUFBSSxFQUFFLGNBQWMsRUFBRSxJQUFJLEVBQUUsQ0FDNUIsQ0FBQztJQUN4QixDQUFDOztBQXhFSCxnQ0F5RUM7QUF4RXlCLGtCQUFJLEdBQUc7SUFDN0IsS0FBSyxFQUFFLHFCQUFxQjtJQUM1QixhQUFhLEVBQUUsT0FBTztJQUN0QixLQUFLLEVBQUU7UUFDTCxNQUFNLEVBQUUsUUFBUTtRQUNoQixjQUFjLEVBQUUsT0FBTyxDQUFDLFFBQVEsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUk7S0FDMUQ7Q0FDRixDQUFDIn0=
@@ -0,0 +1,16 @@
1
+ import { ColumnType, Operator } from '@forestadmin/datasource-toolkit';
2
+ export default class FrontendFilterableUtils {
3
+ private static readonly baseOperators;
4
+ private static readonly dateOperators;
5
+ private static readonly operatorByType;
6
+ /**
7
+ * Compute if a column if filterable according to forestadmin's frontend.
8
+ *
9
+ * @param type column's type (string, number, or a composite type)
10
+ * @param operators list of operators that the column supports
11
+ * @returns either if the frontend would consider this column filterable or not.
12
+ */
13
+ static isFilterable(type: ColumnType, operators?: Set<Operator>): boolean;
14
+ static getRequiredOperators(type: ColumnType): Operator[] | null;
15
+ }
16
+ //# sourceMappingURL=filterable.d.ts.map
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class FrontendFilterableUtils {
4
+ /**
5
+ * Compute if a column if filterable according to forestadmin's frontend.
6
+ *
7
+ * @param type column's type (string, number, or a composite type)
8
+ * @param operators list of operators that the column supports
9
+ * @returns either if the frontend would consider this column filterable or not.
10
+ */
11
+ static isFilterable(type, operators) {
12
+ const neededOperators = FrontendFilterableUtils.getRequiredOperators(type);
13
+ const supportedOperators = operators ?? new Set();
14
+ return Boolean(neededOperators && neededOperators.every(op => supportedOperators.has(op)));
15
+ }
16
+ static getRequiredOperators(type) {
17
+ if (typeof type === 'string' && FrontendFilterableUtils.operatorByType[type]) {
18
+ return FrontendFilterableUtils.operatorByType[type];
19
+ }
20
+ // It sound highly unlikely that this operator can work with dates, or nested objects
21
+ // and they should be more restricted, however the frontend code does not seems to check the
22
+ // array's content so I'm replicating the same test here
23
+ if (Array.isArray(type)) {
24
+ return ['IncludesAll'];
25
+ }
26
+ return null;
27
+ }
28
+ }
29
+ exports.default = FrontendFilterableUtils;
30
+ FrontendFilterableUtils.baseOperators = ['Equal', 'NotEqual', 'Present', 'Blank'];
31
+ FrontendFilterableUtils.dateOperators = [
32
+ ...FrontendFilterableUtils.baseOperators,
33
+ 'LessThan',
34
+ 'GreaterThan',
35
+ 'Today',
36
+ 'Yesterday',
37
+ 'PreviousXDays',
38
+ 'PreviousWeek',
39
+ 'PreviousQuarter',
40
+ 'PreviousYear',
41
+ 'PreviousXDaysToDate',
42
+ 'PreviousWeekToDate',
43
+ 'PreviousMonthToDate',
44
+ 'PreviousQuarterToDate',
45
+ 'PreviousYearToDate',
46
+ 'Past',
47
+ 'Future',
48
+ 'BeforeXHoursAgo',
49
+ 'AfterXHoursAgo',
50
+ ];
51
+ FrontendFilterableUtils.operatorByType = {
52
+ Boolean: FrontendFilterableUtils.baseOperators,
53
+ Date: FrontendFilterableUtils.dateOperators,
54
+ Dateonly: FrontendFilterableUtils.dateOperators,
55
+ Enum: [...FrontendFilterableUtils.baseOperators, 'In'],
56
+ Number: [...FrontendFilterableUtils.baseOperators, 'In', 'GreaterThan', 'LessThan'],
57
+ String: [
58
+ ...FrontendFilterableUtils.baseOperators,
59
+ 'In',
60
+ 'StartsWith',
61
+ 'EndsWith',
62
+ 'Contains',
63
+ 'NotContains',
64
+ ],
65
+ Timeonly: [...FrontendFilterableUtils.baseOperators, 'GreaterThan', 'LessThan'],
66
+ Uuid: FrontendFilterableUtils.baseOperators,
67
+ };
68
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsdGVyYWJsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy91dGlscy9mb3Jlc3Qtc2NoZW1hL2ZpbHRlcmFibGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQSxNQUFxQix1QkFBdUI7SUEwQzFDOzs7Ozs7T0FNRztJQUNILE1BQU0sQ0FBQyxZQUFZLENBQUMsSUFBZ0IsRUFBRSxTQUF5QjtRQUM3RCxNQUFNLGVBQWUsR0FBRyx1QkFBdUIsQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMzRSxNQUFNLGtCQUFrQixHQUFHLFNBQVMsSUFBSSxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBRWxELE9BQU8sT0FBTyxDQUFDLGVBQWUsSUFBSSxlQUFlLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsa0JBQWtCLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM3RixDQUFDO0lBRUQsTUFBTSxDQUFDLG9CQUFvQixDQUFDLElBQWdCO1FBQzFDLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUSxJQUFJLHVCQUF1QixDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUM1RSxPQUFPLHVCQUF1QixDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUNyRDtRQUVELHFGQUFxRjtRQUNyRiw0RkFBNEY7UUFDNUYsd0RBQXdEO1FBQ3hELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUN2QixPQUFPLENBQUMsYUFBYSxDQUFDLENBQUM7U0FDeEI7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7O0FBckVILDBDQXNFQztBQXJFeUIscUNBQWEsR0FBZSxDQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0FBRXRFLHFDQUFhLEdBQWU7SUFDbEQsR0FBRyx1QkFBdUIsQ0FBQyxhQUFhO0lBQ3hDLFVBQVU7SUFDVixhQUFhO0lBQ2IsT0FBTztJQUNQLFdBQVc7SUFDWCxlQUFlO0lBQ2YsY0FBYztJQUNkLGlCQUFpQjtJQUNqQixjQUFjO0lBQ2QscUJBQXFCO0lBQ3JCLG9CQUFvQjtJQUNwQixxQkFBcUI7SUFDckIsdUJBQXVCO0lBQ3ZCLG9CQUFvQjtJQUNwQixNQUFNO0lBQ04sUUFBUTtJQUNSLGlCQUFpQjtJQUNqQixnQkFBZ0I7Q0FDakIsQ0FBQztBQUVzQixzQ0FBYyxHQUFnRDtJQUNwRixPQUFPLEVBQUUsdUJBQXVCLENBQUMsYUFBYTtJQUM5QyxJQUFJLEVBQUUsdUJBQXVCLENBQUMsYUFBYTtJQUMzQyxRQUFRLEVBQUUsdUJBQXVCLENBQUMsYUFBYTtJQUMvQyxJQUFJLEVBQUUsQ0FBQyxHQUFHLHVCQUF1QixDQUFDLGFBQWEsRUFBRSxJQUFJLENBQUM7SUFDdEQsTUFBTSxFQUFFLENBQUMsR0FBRyx1QkFBdUIsQ0FBQyxhQUFhLEVBQUUsSUFBSSxFQUFFLGFBQWEsRUFBRSxVQUFVLENBQUM7SUFDbkYsTUFBTSxFQUFFO1FBQ04sR0FBRyx1QkFBdUIsQ0FBQyxhQUFhO1FBQ3hDLElBQUk7UUFDSixZQUFZO1FBQ1osVUFBVTtRQUNWLFVBQVU7UUFDVixhQUFhO0tBQ2Q7SUFDRCxRQUFRLEVBQUUsQ0FBQyxHQUFHLHVCQUF1QixDQUFDLGFBQWEsRUFBRSxhQUFhLEVBQUUsVUFBVSxDQUFDO0lBQy9FLElBQUksRUFBRSx1QkFBdUIsQ0FBQyxhQUFhO0NBQzVDLENBQUMifQ==
@@ -0,0 +1,14 @@
1
+ import { ActionField, Collection, DataSource } from '@forestadmin/datasource-toolkit';
2
+ import { ForestServerAction, ForestServerActionField } from './types';
3
+ export default class SchemaGeneratorActions {
4
+ /**
5
+ * 'fields' sent to forestadmin-server when we want to generate the form on demand.
6
+ * This works around a bug in frontend which won't call the server if no fields are defined.
7
+ */
8
+ static defaultFields: ForestServerActionField[];
9
+ static buildSchema(collection: Collection, name: string): Promise<ForestServerAction>;
10
+ /** Build schema for given field */
11
+ static buildFieldSchema(dataSource: DataSource, field: ActionField): ForestServerActionField;
12
+ private static buildFields;
13
+ }
14
+ //# sourceMappingURL=generator-actions.d.ts.map