@forestadmin/agent 1.0.0-beta.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 (109) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +0 -0
  3. package/dist/agent/forestadmin-http-driver.d.ts +34 -0
  4. package/dist/agent/forestadmin-http-driver.js +73 -0
  5. package/dist/agent/routes/access/chart.d.ts +17 -0
  6. package/dist/agent/routes/access/chart.js +125 -0
  7. package/dist/agent/routes/access/count-related.d.ts +9 -0
  8. package/dist/agent/routes/access/count-related.js +24 -0
  9. package/dist/agent/routes/access/count.d.ts +9 -0
  10. package/dist/agent/routes/access/count.js +24 -0
  11. package/dist/agent/routes/access/csv-related.d.ts +9 -0
  12. package/dist/agent/routes/access/csv-related.js +33 -0
  13. package/dist/agent/routes/access/csv.d.ts +9 -0
  14. package/dist/agent/routes/access/csv.js +30 -0
  15. package/dist/agent/routes/access/get.d.ts +9 -0
  16. package/dist/agent/routes/access/get.js +28 -0
  17. package/dist/agent/routes/access/list-related.d.ts +9 -0
  18. package/dist/agent/routes/access/list-related.js +26 -0
  19. package/dist/agent/routes/access/list.d.ts +9 -0
  20. package/dist/agent/routes/access/list.js +23 -0
  21. package/dist/agent/routes/base-route.d.ts +14 -0
  22. package/dist/agent/routes/base-route.js +16 -0
  23. package/dist/agent/routes/collection-route.d.ts +12 -0
  24. package/dist/agent/routes/collection-route.js +20 -0
  25. package/dist/agent/routes/index.d.ts +30 -0
  26. package/dist/agent/routes/index.js +90 -0
  27. package/dist/agent/routes/modification/action.d.ts +17 -0
  28. package/dist/agent/routes/modification/action.js +103 -0
  29. package/dist/agent/routes/modification/associate-related.d.ts +12 -0
  30. package/dist/agent/routes/modification/associate-related.js +49 -0
  31. package/dist/agent/routes/modification/create.d.ts +14 -0
  32. package/dist/agent/routes/modification/create.js +81 -0
  33. package/dist/agent/routes/modification/delete.d.ts +11 -0
  34. package/dist/agent/routes/modification/delete.js +40 -0
  35. package/dist/agent/routes/modification/dissociate-delete-related.d.ts +20 -0
  36. package/dist/agent/routes/modification/dissociate-delete-related.js +88 -0
  37. package/dist/agent/routes/modification/update-relation.d.ts +11 -0
  38. package/dist/agent/routes/modification/update-relation.js +53 -0
  39. package/dist/agent/routes/modification/update.d.ts +9 -0
  40. package/dist/agent/routes/modification/update.js +29 -0
  41. package/dist/agent/routes/relation-route.d.ts +10 -0
  42. package/dist/agent/routes/relation-route.js +18 -0
  43. package/dist/agent/routes/security/authentication.d.ts +17 -0
  44. package/dist/agent/routes/security/authentication.js +86 -0
  45. package/dist/agent/routes/security/ip-whitelist.d.ts +14 -0
  46. package/dist/agent/routes/security/ip-whitelist.js +35 -0
  47. package/dist/agent/routes/security/scope-invalidation.d.ts +11 -0
  48. package/dist/agent/routes/security/scope-invalidation.js +28 -0
  49. package/dist/agent/routes/system/error-handling.d.ts +11 -0
  50. package/dist/agent/routes/system/error-handling.js +56 -0
  51. package/dist/agent/routes/system/healthcheck.d.ts +11 -0
  52. package/dist/agent/routes/system/healthcheck.js +22 -0
  53. package/dist/agent/routes/system/logger.d.ts +10 -0
  54. package/dist/agent/routes/system/logger.js +36 -0
  55. package/dist/agent/services/index.d.ts +10 -0
  56. package/dist/agent/services/index.js +12 -0
  57. package/dist/agent/services/permissions.d.ts +19 -0
  58. package/dist/agent/services/permissions.js +79 -0
  59. package/dist/agent/services/serializer.d.ts +17 -0
  60. package/dist/agent/services/serializer.js +120 -0
  61. package/dist/agent/types.d.ts +23 -0
  62. package/dist/agent/types.js +22 -0
  63. package/dist/agent/utils/body-parser.d.ts +7 -0
  64. package/dist/agent/utils/body-parser.js +18 -0
  65. package/dist/agent/utils/context-filter-factory.d.ts +7 -0
  66. package/dist/agent/utils/context-filter-factory.js +29 -0
  67. package/dist/agent/utils/csv-generator.d.ts +12 -0
  68. package/dist/agent/utils/csv-generator.js +39 -0
  69. package/dist/agent/utils/csv-route-context.d.ts +5 -0
  70. package/dist/agent/utils/csv-route-context.js +14 -0
  71. package/dist/agent/utils/forest-http-api.d.ts +63 -0
  72. package/dist/agent/utils/forest-http-api.js +173 -0
  73. package/dist/agent/utils/forest-schema/action-values.d.ts +34 -0
  74. package/dist/agent/utils/forest-schema/action-values.js +144 -0
  75. package/dist/agent/utils/forest-schema/emitter.d.ts +20 -0
  76. package/dist/agent/utils/forest-schema/emitter.js +70 -0
  77. package/dist/agent/utils/forest-schema/filterable.d.ts +16 -0
  78. package/dist/agent/utils/forest-schema/filterable.js +68 -0
  79. package/dist/agent/utils/forest-schema/generator-actions.d.ts +14 -0
  80. package/dist/agent/utils/forest-schema/generator-actions.js +99 -0
  81. package/dist/agent/utils/forest-schema/generator-collection.d.ts +7 -0
  82. package/dist/agent/utils/forest-schema/generator-collection.js +31 -0
  83. package/dist/agent/utils/forest-schema/generator-fields.d.ts +13 -0
  84. package/dist/agent/utils/forest-schema/generator-fields.js +131 -0
  85. package/dist/agent/utils/forest-schema/generator-segments.d.ts +6 -0
  86. package/dist/agent/utils/forest-schema/generator-segments.js +9 -0
  87. package/dist/agent/utils/forest-schema/types.d.ts +79 -0
  88. package/dist/agent/utils/forest-schema/types.js +16 -0
  89. package/dist/agent/utils/forest-schema/validation.d.ts +10 -0
  90. package/dist/agent/utils/forest-schema/validation.js +26 -0
  91. package/dist/agent/utils/http-driver-options.d.ts +13 -0
  92. package/dist/agent/utils/http-driver-options.js +86 -0
  93. package/dist/agent/utils/id.d.ts +8 -0
  94. package/dist/agent/utils/id.js +43 -0
  95. package/dist/agent/utils/query-string.d.ts +14 -0
  96. package/dist/agent/utils/query-string.js +130 -0
  97. package/dist/builder/agent.d.ts +81 -0
  98. package/dist/builder/agent.js +113 -0
  99. package/dist/builder/collection.d.ts +148 -0
  100. package/dist/builder/collection.js +226 -0
  101. package/dist/builder/types.d.ts +5 -0
  102. package/dist/builder/types.js +3 -0
  103. package/dist/index.d.ts +5 -0
  104. package/dist/index.js +22 -0
  105. package/dist/types.d.ts +22 -0
  106. package/dist/types.js +11 -0
  107. package/dist/utils/csv-generator.d.ts +12 -0
  108. package/dist/utils/csv-generator.js +39 -0
  109. package/package.json +55 -0
@@ -0,0 +1,226 @@
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 datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
7
+ const filterable_1 = __importDefault(require("../agent/utils/forest-schema/filterable"));
8
+ class CollectionBuilder {
9
+ constructor(agentBuilder, name) {
10
+ this.agentBuilder = agentBuilder;
11
+ this.name = name;
12
+ }
13
+ /**
14
+ * Import a field from a many to one or one to one relation.
15
+ *
16
+ * @param name the name of the field that will be created on the collection
17
+ * @param options options to import the field
18
+ * @example
19
+ * .importField('authorName', { path: 'author:fullName' })
20
+ */
21
+ importField(name, options) {
22
+ const collection = this.agentBuilder.lateComputed.getCollection(this.name);
23
+ const schema = datasource_toolkit_1.CollectionUtils.getFieldSchema(collection, options.path);
24
+ this.addField(name, {
25
+ beforeRelations: options.beforeRelations,
26
+ columnType: schema.columnType,
27
+ defaultValue: schema.defaultValue,
28
+ dependencies: [options.path],
29
+ getValues: records => records.map(r => datasource_toolkit_1.RecordUtils.getFieldValue(r, options.path)),
30
+ enumValues: schema.enumValues,
31
+ });
32
+ for (const operator of schema.filterOperators) {
33
+ const handler = (value) => ({ field: options.path, operator, value });
34
+ this.replaceFieldOperator(name, operator, handler);
35
+ }
36
+ if (schema.isSortable) {
37
+ this.replaceFieldSorting(name, [{ field: options.path, ascending: true }]);
38
+ }
39
+ return this;
40
+ }
41
+ /**
42
+ * Allow to rename a field of a given collection.
43
+ * @param {string} oldName the current name of the field in a given collection
44
+ * @param {string} newName the new name of the field
45
+ * @example
46
+ * .renameField('theCurrentNameOfTheField', 'theNewNameOfTheField');
47
+ */
48
+ renameField(oldName, newName) {
49
+ this.agentBuilder.rename.getCollection(this.name).renameField(oldName, newName);
50
+ return this;
51
+ }
52
+ /**
53
+ * Remove field by setting its visibility to false.
54
+ * @param {...string[]} names the fields to remove
55
+ * @example
56
+ * .removeField('aFieldToRemove', 'anOtherFieldToRemove');
57
+ */
58
+ removeField(...names) {
59
+ const collection = this.agentBuilder.publication.getCollection(this.name);
60
+ for (const name of names)
61
+ collection.changeFieldVisibility(name, false);
62
+ return this;
63
+ }
64
+ /**
65
+ * Add a new action on the collection.
66
+ * @param {string} name the name of the action
67
+ * @param {ActionDefinition} definition the definition of the action
68
+ * @example
69
+ * .addAction('is live', {
70
+ * scope: 'Single',
71
+ * execute: async (context, responseBuilder) => {
72
+ * return responseBuilder.success(`Is live!`);
73
+ * },
74
+ * })
75
+ */
76
+ addAction(name, definition) {
77
+ this.agentBuilder.action.getCollection(this.name).addAction(name, definition);
78
+ return this;
79
+ }
80
+ /**
81
+ * Add a new field on the collection.
82
+ * @param {string} name the name of the field
83
+ * @param {FieldDefinition} definition The definition of the field
84
+ * @example
85
+ * .addField('fullName', {
86
+ * columnType: 'String',
87
+ * dependencies: ['firstName', 'lastName'],
88
+ * getValues: (records) => records.map(record => `${record.lastName} ${record.firstName}`),
89
+ * });
90
+ */
91
+ addField(name, definition) {
92
+ const { beforeRelations, ...computedDefinition } = definition;
93
+ const collection = definition.beforeRelations
94
+ ? this.agentBuilder.earlyComputed.getCollection(this.name)
95
+ : this.agentBuilder.lateComputed.getCollection(this.name);
96
+ collection.registerComputed(name, computedDefinition);
97
+ return this;
98
+ }
99
+ /**
100
+ * Add a relation between two collections.
101
+ * @param name name of the new relation
102
+ * @param definition definition of the new relation
103
+ * @example
104
+ * .addRelation('author', {
105
+ * type: 'ManyToOne',
106
+ * foreignCollection: 'persons',
107
+ * foreignKey: 'authorId'
108
+ * });
109
+ */
110
+ addRelation(name, definition) {
111
+ this.agentBuilder.relation.getCollection(this.name).addRelation(name, definition);
112
+ return this;
113
+ }
114
+ /**
115
+ * Add a new segment on the collection.
116
+ * @param {string} name the name of the segment
117
+ * @param {SegmentDefinition} definition a function used to generate a condition tree
118
+ * or a condition tree
119
+ * @example
120
+ * .addSegment(
121
+ * 'Wrote more than 2 books',
122
+ * new ConditionTreeLeaf('booksCount', 'GreaterThan', 2),
123
+ * );
124
+ */
125
+ addSegment(name, definition) {
126
+ this.agentBuilder.segment.getCollection(this.name).addSegment(name, definition);
127
+ return this;
128
+ }
129
+ /**
130
+ * Enable sorting on a specific field using emulation.
131
+ * As for all the emulation method, the field sorting will be done in-memory.
132
+ * @param {string} name the name of the field to enable emulation on
133
+ * @example
134
+ * .emulateFieldSorting('fullName');
135
+ */
136
+ emulateFieldSorting(name) {
137
+ this.agentBuilder.sortEmulate.getCollection(this.name).emulateFieldSorting(name);
138
+ return this;
139
+ }
140
+ /**
141
+ * Replace an implementation for the sorting.
142
+ * The field sorting will be done by the datasource.
143
+ * @param {string} name the name of the field to enable sort
144
+ * @param {SortClause[]} equivalentSort the sort equivalent
145
+ * @example
146
+ * .replaceFieldSorting(
147
+ * 'fullName',
148
+ * [
149
+ * { field: 'firstName', ascending: true },
150
+ * { field: 'lastName', ascending: true },
151
+ * ]
152
+ * )
153
+ */
154
+ replaceFieldSorting(name, equivalentSort) {
155
+ this.agentBuilder.sortEmulate
156
+ .getCollection(this.name)
157
+ .replaceFieldSorting(name, equivalentSort);
158
+ return this;
159
+ }
160
+ /**
161
+ * Enable filtering on a specific field using emulation.
162
+ * As for all the emulation method, the field filtering will be done in-memory.
163
+ * @param name the name of the field to enable emulation on
164
+ * @example
165
+ * .emulateFieldFiltering('aField');
166
+ */
167
+ emulateFieldFiltering(name) {
168
+ const collection = this.agentBuilder.lateOpEmulate.getCollection(this.name);
169
+ const field = collection.schema.fields[name];
170
+ for (const operator of filterable_1.default.getRequiredOperators(field.columnType)) {
171
+ if (!field.filterOperators.has(operator)) {
172
+ this.emulateFieldOperator(name, operator);
173
+ }
174
+ }
175
+ return this;
176
+ }
177
+ /**
178
+ * Enable filtering on a specific field with a specific operator using emulation.
179
+ * As for all the emulation method, the field filtering will be done in-memory.
180
+ * @param {string} name the name of the field to enable emulation on
181
+ * @param {Operator} operator the operator to emulate
182
+ * @example
183
+ * .emulateFieldOperator('aField', 'In');
184
+ */
185
+ emulateFieldOperator(name, operator) {
186
+ const collection = this.agentBuilder.earlyOpEmulate.getCollection(this.name).schema.fields[name]
187
+ ? this.agentBuilder.earlyOpEmulate.getCollection(this.name)
188
+ : this.agentBuilder.lateOpEmulate.getCollection(this.name);
189
+ collection.emulateFieldOperator(name, operator);
190
+ return this;
191
+ }
192
+ /**
193
+ * Replace an implementation for a specific operator on a specific field.
194
+ * The operator replacement will be done by the datasource.
195
+ * @param {string} name the name of the field to filter on
196
+ * @param {Operator} operator the operator to replace
197
+ * @param {OperatorReplacer} replacer the proposed implementation
198
+ * @example
199
+ * .replaceFieldOperator('booksCount', 'Equal', ({ value }) => new ConditionTreeNot(
200
+ * new ConditionTreeLeaf('booksCount', 'Equal', value),
201
+ * ));
202
+ */
203
+ replaceFieldOperator(name, operator, replacer) {
204
+ const collection = this.agentBuilder.earlyOpEmulate.getCollection(this.name).schema.fields[name]
205
+ ? this.agentBuilder.earlyOpEmulate.getCollection(this.name)
206
+ : this.agentBuilder.lateOpEmulate.getCollection(this.name);
207
+ collection.replaceFieldOperator(name, operator, replacer);
208
+ return this;
209
+ }
210
+ /**
211
+ * Replace the write behavior of a field.
212
+ * @param {string} name the name of the field
213
+ * @param {WriteDefinition} definition the function or a value to represent the write behavior
214
+ * @example
215
+ * .replaceFieldWriting('fullName', ({ patch: fullName }) => {
216
+ * const [firstName, lastName] = fullName.split(' ');
217
+ * return { firstName, lastName };
218
+ * });
219
+ */
220
+ replaceFieldWriting(name, definition) {
221
+ this.agentBuilder.write.getCollection(this.name).replaceFieldWriting(name, definition);
222
+ return this;
223
+ }
224
+ }
225
+ exports.default = CollectionBuilder;
226
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29sbGVjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9idWlsZGVyL2NvbGxlY3Rpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSx3RUFXeUM7QUFHekMseUZBQThFO0FBRTlFLE1BQXFCLGlCQUFpQjtJQUlwQyxZQUFZLFlBQTBCLEVBQUUsSUFBWTtRQUNsRCxJQUFJLENBQUMsWUFBWSxHQUFHLFlBQVksQ0FBQztRQUNqQyxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztJQUNuQixDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILFdBQVcsQ0FBQyxJQUFZLEVBQUUsT0FBb0Q7UUFDNUUsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMzRSxNQUFNLE1BQU0sR0FBRyxvQ0FBZSxDQUFDLGNBQWMsQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBaUIsQ0FBQztRQUV4RixJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRTtZQUNsQixlQUFlLEVBQUUsT0FBTyxDQUFDLGVBQWU7WUFDeEMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVO1lBQzdCLFlBQVksRUFBRSxNQUFNLENBQUMsWUFBWTtZQUNqQyxZQUFZLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDO1lBQzVCLFNBQVMsRUFBRSxPQUFPLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxnQ0FBVyxDQUFDLGFBQWEsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2xGLFVBQVUsRUFBRSxNQUFNLENBQUMsVUFBVTtTQUM5QixDQUFDLENBQUM7UUFFSCxLQUFLLE1BQU0sUUFBUSxJQUFJLE1BQU0sQ0FBQyxlQUFlLEVBQUU7WUFDN0MsTUFBTSxPQUFP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
@@ -0,0 +1,5 @@
1
+ import { ComputedDefinition } from '@forestadmin/datasource-toolkit';
2
+ export declare type FieldDefinition = ComputedDefinition & {
3
+ beforeRelations?: boolean;
4
+ };
5
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYnVpbGRlci90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
@@ -0,0 +1,5 @@
1
+ import Agent from './builder/agent';
2
+ export * from './types';
3
+ export { default as Collection } from './builder/collection';
4
+ export default Agent;
5
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ var __importDefault = (this && this.__importDefault) || function (mod) {
13
+ return (mod && mod.__esModule) ? mod : { "default": mod };
14
+ };
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.Collection = void 0;
17
+ const agent_1 = __importDefault(require("./builder/agent"));
18
+ __exportStar(require("./types"), exports);
19
+ var collection_1 = require("./builder/collection");
20
+ Object.defineProperty(exports, "Collection", { enumerable: true, get: function () { return __importDefault(collection_1).default; } });
21
+ exports.default = agent_1.default;
22
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDREQUFvQztBQUVwQywwQ0FBd0I7QUFDeEIsbURBQTZEO0FBQXBELHlIQUFBLE9BQU8sT0FBYztBQUU5QixrQkFBZSxlQUFLLENBQUMifQ==
@@ -0,0 +1,22 @@
1
+ /** Logger Level */
2
+ export declare enum LoggerLevel {
3
+ Info = "info",
4
+ Warn = "warn",
5
+ Error = "error"
6
+ }
7
+ /** Logger */
8
+ export declare type Logger = (level: LoggerLevel, message: unknown) => void;
9
+ /** Options to configure behavior of an agent's forestadmin driver */
10
+ export declare type AgentOptions = {
11
+ agentUrl: string;
12
+ authSecret: string;
13
+ clientId?: string;
14
+ envSecret: string;
15
+ forestServerUrl?: string;
16
+ logger?: Logger;
17
+ prefix?: string;
18
+ isProduction: boolean;
19
+ schemaPath?: string;
20
+ permissionsCacheDurationInSeconds?: number;
21
+ };
22
+ //# sourceMappingURL=types.d.ts.map
package/dist/types.js ADDED
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoggerLevel = void 0;
4
+ /** Logger Level */
5
+ var LoggerLevel;
6
+ (function (LoggerLevel) {
7
+ LoggerLevel["Info"] = "info";
8
+ LoggerLevel["Warn"] = "warn";
9
+ LoggerLevel["Error"] = "error";
10
+ })(LoggerLevel = exports.LoggerLevel || (exports.LoggerLevel = {}));
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbUJBQW1CO0FBQ25CLElBQVksV0FJWDtBQUpELFdBQVksV0FBVztJQUNyQiw0QkFBYSxDQUFBO0lBQ2IsNEJBQWEsQ0FBQTtJQUNiLDhCQUFlLENBQUE7QUFDakIsQ0FBQyxFQUpXLFdBQVcsR0FBWCxtQkFBVyxLQUFYLG1CQUFXLFFBSXRCIn0=
@@ -0,0 +1,12 @@
1
+ import { Collection, PaginatedFilter, Projection } from '@forestadmin/datasource-toolkit';
2
+ export declare const CHUNK_SIZE = 1000;
3
+ export default class CsvGenerator {
4
+ /**
5
+ * Use an async generator to ensure that
6
+ * - backpressure is properly applied without needing to extend Readable (for slow clients)
7
+ * - we stop making queries to the database if the client closes the connection.
8
+ */
9
+ static generate(projection: Projection, header: string, filter: PaginatedFilter, collection: Collection, list: Collection['list']): AsyncGenerator<string>;
10
+ private static convert;
11
+ }
12
+ //# sourceMappingURL=csv-generator.d.ts.map
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CHUNK_SIZE = void 0;
4
+ const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
5
+ const format_1 = require("@fast-csv/format");
6
+ exports.CHUNK_SIZE = 1000;
7
+ class CsvGenerator {
8
+ /**
9
+ * Use an async generator to ensure that
10
+ * - backpressure is properly applied without needing to extend Readable (for slow clients)
11
+ * - we stop making queries to the database if the client closes the connection.
12
+ */
13
+ static async *generate(projection, header, filter, collection, list) {
14
+ yield (0, format_1.writeToString)([header.split(',')], { headers: true, includeEndRowDelimiter: true });
15
+ const limit = filter.page?.limit;
16
+ let skip = filter.page?.skip || 0;
17
+ let areAllRecordsFetched = false;
18
+ const copiedFilter = { ...filter };
19
+ while (!areAllRecordsFetched) {
20
+ let currentPageSize = exports.CHUNK_SIZE;
21
+ if (limit < skip)
22
+ currentPageSize = skip - limit;
23
+ copiedFilter.page = new datasource_toolkit_1.Page(skip, currentPageSize);
24
+ if (!copiedFilter.sort || copiedFilter.sort.length === 0) {
25
+ copiedFilter.sort = datasource_toolkit_1.SortFactory.byPrimaryKeys(collection);
26
+ }
27
+ // eslint-disable-next-line no-await-in-loop
28
+ const records = await list(new datasource_toolkit_1.PaginatedFilter(copiedFilter), projection);
29
+ yield CsvGenerator.convert(records, projection);
30
+ areAllRecordsFetched = records.length < exports.CHUNK_SIZE;
31
+ skip += currentPageSize;
32
+ }
33
+ }
34
+ static convert(records, projection) {
35
+ return (0, format_1.writeToString)(records.map(record => projection.map(field => datasource_toolkit_1.RecordUtils.getFieldValue(record, field))));
36
+ }
37
+ }
38
+ exports.default = CsvGenerator;
39
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3N2LWdlbmVyYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9jc3YtZ2VuZXJhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHdFQVF5QztBQUN6Qyw2Q0FBaUQ7QUFFcEMsUUFBQSxVQUFVLEdBQUcsSUFBSSxDQUFDO0FBRS9CLE1BQXFCLFlBQVk7SUFDL0I7Ozs7T0FJRztJQUNILE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxRQUFRLENBQ3BCLFVBQXNCLEVBQ3RCLE1BQWMsRUFDZCxNQUF1QixFQUN2QixVQUFzQixFQUN0QixJQUF3QjtRQUV4QixNQUFNLElBQUEsc0JBQWEsRUFBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsc0JBQXNCLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUUxRixNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQztRQUNqQyxJQUFJLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLElBQUksSUFBSSxDQUFDLENBQUM7UUFFbEMsSUFBSSxvQkFBb0IsR0FBRyxLQUFLLENBQUM7UUFDakMsTUFBTSxZQUFZLEdBQUcsRUFBRSxHQUFHLE1BQU0sRUFBRSxDQUFDO1FBRW5DLE9BQU8sQ0FBQyxvQkFBb0IsRUFBRTtZQUM1QixJQUFJLGVBQWUsR0FBRyxrQkFBVSxDQUFDO1lBQ2pDLElBQUksS0FBSyxHQUFHLElBQUk7Z0JBQUUsZUFBZSxHQUFHLElBQUksR0FBRyxLQUFLLENBQUM7WUFFakQsWUFBWSxDQUFDLElBQUksR0FBRyxJQUFJLHlCQUFJLENBQUMsSUFBSSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1lBRXBELElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxJQUFJLFlBQVksQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtnQkFDeEQsWUFBWSxDQUFDLElBQUksR0FBRyxnQ0FBVyxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUMsQ0FBQzthQUMzRDtZQUVELDRDQUE0QztZQUM1QyxNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxJQUFJLG9DQUFlLENBQUMsWUFBWSxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFFMUUsTUFBTSxZQUFZLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsQ0FBQztZQUVoRCxvQkFBb0IsR0FBRyxPQUFPLENBQUMsTUFBTSxHQUFHLGtCQUFVLENBQUM7WUFDbkQsSUFBSSxJQUFJLGVBQWUsQ0FBQztTQUN6QjtJQUNILENBQUM7SUFFTyxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQXFCLEVBQUUsVUFBc0I7UUFDbEUsT0FBTyxJQUFBLHNCQUFhLEVBQ2xCLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsZ0NBQVcsQ0FBQyxhQUFhLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FDekYsQ0FBQztJQUNKLENBQUM7Q0FDRjtBQTlDRCwrQkE4Q0MifQ==
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@forestadmin/agent",
3
+ "version": "1.0.0-beta.1",
4
+ "main": "dist/index.js",
5
+ "license": "GPL-3.0",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/ForestAdmin/agent-nodejs.git",
12
+ "directory": "packages/agent"
13
+ },
14
+ "dependencies": {
15
+ "@fast-csv/format": "^4.3.5",
16
+ "@forestadmin/datasource-toolkit": "^1.0.0-beta.1",
17
+ "@koa/cors": "^3.1.0",
18
+ "@koa/router": "^10.1.1",
19
+ "forest-ip-utils": "^1.0.1",
20
+ "json-api-serializer": "^2.6.6",
21
+ "json-stringify-pretty-compact": "^3.0.0",
22
+ "jsonwebtoken": "^8.5.1",
23
+ "koa": "^2.13.4",
24
+ "koa-bodyparser": "^4.3.0",
25
+ "koa-jwt": "^4.0.3",
26
+ "lru-cache": "^7.3.1",
27
+ "luxon": "^2.3.0",
28
+ "object-hash": "^2.2.0",
29
+ "openid-client": "5.1.3",
30
+ "superagent": "^7.0.1",
31
+ "uuid": "^8.3.2"
32
+ },
33
+ "files": [
34
+ "dist/**/*.js",
35
+ "dist/**/*.d.ts"
36
+ ],
37
+ "scripts": {
38
+ "build": "tsc",
39
+ "build:watch": "tsc --watch",
40
+ "clean": "rm -rf coverage dist",
41
+ "lint": "eslint src test",
42
+ "test": "jest"
43
+ },
44
+ "devDependencies": {
45
+ "@shopify/jest-koa-mocks": "^3.1.0",
46
+ "@types/json-api-serializer": "2.6.3",
47
+ "@types/jsonwebtoken": "^8.5.8",
48
+ "@types/koa": "^2.13.4",
49
+ "@types/koa-bodyparser": "^4.3.5",
50
+ "@types/koa__cors": "^3.1.1",
51
+ "@types/koa__router": "^8.0.11",
52
+ "@types/superagent": "^4.1.15",
53
+ "fishery": "^2.1.0"
54
+ }
55
+ }