@forestadmin/plugin-aws-s3 1.2.5 → 1.3.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.
@@ -2,14 +2,21 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const data_uri_1 = require("../utils/data-uri");
4
4
  function createField(collection, config) {
5
+ const dependencies = config.objectKeyFromRecord?.extraDependencies ?? [];
6
+ if (!dependencies.includes(config.sourcename)) {
7
+ dependencies.push(config.sourcename);
8
+ }
5
9
  collection.addField(config.filename, {
6
10
  columnType: 'String',
7
- dependencies: [config.sourcename],
8
- getValues: records => records.map(async (record) => {
9
- const key = record[config.sourcename];
11
+ dependencies,
12
+ getValues: (records, context) => records.map(async (record) => {
13
+ let key = record[config.sourcename];
10
14
  if (!key) {
11
15
  return null;
12
16
  }
17
+ key = config.objectKeyFromRecord?.mappingFunction
18
+ ? await config.objectKeyFromRecord.mappingFunction(record, context)
19
+ : key;
13
20
  if (config.readMode === 'proxy') {
14
21
  return (0, data_uri_1.encodeDataUri)(await config.client.load(key));
15
22
  }
@@ -21,4 +28,4 @@ function createField(collection, config) {
21
28
  });
22
29
  }
23
30
  exports.default = createField;
24
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLWZpZWxkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ZpZWxkL2NyZWF0ZS1maWVsZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUdBLGdEQUFrRDtBQUVsRCxTQUF3QixXQUFXLENBQUMsVUFBZ0MsRUFBRSxNQUFxQjtJQUN6RixVQUFVLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUU7UUFDbkMsVUFBVSxFQUFFLFFBQVE7UUFDcEIsWUFBWSxFQUFFLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQztRQUNqQyxTQUFTLEVBQUUsT0FBTyxDQUFDLEVBQUUsQ0FDbkIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUMsTUFBTSxFQUFDLEVBQUU7WUFDekIsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUV0QyxJQUFJLENBQUMsR0FBRyxFQUFFO2dCQUNSLE9BQU8sSUFBSSxDQUFDO2FBQ2I7WUFFRCxJQUFJLE1BQU0sQ0FBQyxRQUFRLEtBQUssT0FBTyxFQUFFO2dCQUMvQixPQUFPLElBQUEsd0JBQWEsRUFBQyxNQUFNLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7YUFDckQ7WUFFRCxJQUFJLE1BQU0sQ0FBQyxHQUFHLEtBQUssYUFBYSxJQUFJLE1BQU0sQ0FBQyxHQUFHLEtBQUssbUJBQW1CLEVBQUU7Z0JBQ3RFLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUM7YUFDeEM7WUFFRCxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3pDLENBQUMsQ0FBQztLQUNMLENBQUMsQ0FBQztBQUNMLENBQUM7QUF2QkQsOEJBdUJDIn0=
31
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLWZpZWxkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ZpZWxkL2NyZWF0ZS1maWVsZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUdBLGdEQUFrRDtBQUVsRCxTQUF3QixXQUFXLENBQUMsVUFBZ0MsRUFBRSxNQUFxQjtJQUN6RixNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsbUJBQW1CLEVBQUUsaUJBQWlCLElBQUksRUFBRSxDQUFDO0lBRXpFLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsRUFBRTtRQUM3QyxZQUFZLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztLQUN0QztJQUVELFVBQVUsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRTtRQUNuQyxVQUFVLEVBQUUsUUFBUTtRQUNwQixZQUFZO1FBQ1osU0FBUyxFQUFFLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxFQUFFLENBQzlCLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFDLE1BQU0sRUFBQyxFQUFFO1lBQ3pCLElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7WUFFcEMsSUFBSSxDQUFDLEdBQUcsRUFBRTtnQkFDUixPQUFPLElBQUksQ0FBQzthQUNiO1lBRUQsR0FBRyxHQUFHLE1BQU0sQ0FBQyxtQkFBbUIsRUFBRSxlQUFlO2dCQUMvQyxDQUFDLENBQUMsTUFBTSxNQUFNLENBQUMsbUJBQW1CLENBQUMsZUFBZSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUM7Z0JBQ25FLENBQUMsQ0FBQyxHQUFHLENBQUM7WUFFUixJQUFJLE1BQU0sQ0FBQyxRQUFRLEtBQUssT0FBTyxFQUFFO2dCQUMvQixPQUFPLElBQUEsd0JBQWEsRUFBQyxNQUFNLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7YUFDckQ7WUFFRCxJQUFJLE1BQU0sQ0FBQyxHQUFHLEtBQUssYUFBYSxJQUFJLE1BQU0sQ0FBQyxHQUFHLEtBQUssbUJBQW1CLEVBQUU7Z0JBQ3RFLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUM7YUFDeEM7WUFFRCxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3pDLENBQUMsQ0FBQztLQUNMLENBQUMsQ0FBQztBQUNMLENBQUM7QUFqQ0QsOEJBaUNDIn0=
@@ -1,9 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  async function deleteFiles(config, context) {
4
- const records = await context.collection.list(context.filter, [config.sourcename]);
5
- const keys = [...new Set(records.map(r => r[config.sourcename]).filter(path => !!path))];
6
- await Promise.all(keys.map(k => config.client.delete(k)));
4
+ const projection = config.objectKeyFromRecord?.extraDependencies ?? [];
5
+ if (!projection.includes(config.sourcename)) {
6
+ projection.push(config.sourcename);
7
+ }
8
+ const records = await context.collection.list(context.filter, projection);
9
+ let keys;
10
+ if (config.objectKeyFromRecord?.mappingFunction) {
11
+ keys = await Promise.all(records.map(record => config.objectKeyFromRecord.mappingFunction(record, context)));
12
+ }
13
+ else {
14
+ keys = records.map(record => record[config.sourcename]);
15
+ }
16
+ const uniqueNonNull = [...new Set(keys.filter(path => !!path))];
17
+ if (uniqueNonNull.length > 0) {
18
+ await Promise.all(uniqueNonNull.map(k => config.client.delete(k)));
19
+ }
7
20
  }
8
21
  function makeFieldDeleteable(collection, config) {
9
22
  if (!config.deleteFiles)
@@ -18,4 +31,4 @@ function makeFieldDeleteable(collection, config) {
18
31
  });
19
32
  }
20
33
  exports.default = makeFieldDeleteable;
21
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFrZS1maWVsZC1kZWxldGVhYmxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ZpZWxkL21ha2UtZmllbGQtZGVsZXRlYWJsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQU9BLEtBQUssVUFBVSxXQUFXLENBQ3hCLE1BQXFCLEVBQ3JCLE9BQTBEO0lBRTFELE1BQU0sT0FBTyxHQUFHLE1BQU0sT0FBTyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQ25GLE1BQU0sSUFBSSxHQUFHLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFekYsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDNUQsQ0FBQztBQUVELFNBQXdCLG1CQUFtQixDQUN6QyxVQUFnQyxFQUNoQyxNQUFxQjtJQUVyQixJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVc7UUFBRSxPQUFPO0lBRWhDLFVBQVUsQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUMsT0FBTyxFQUFDLEVBQUU7UUFDckQsSUFBSSxPQUFPLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxJQUFJLEVBQUU7WUFDM0MsV0FBVyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztTQUM5QjtJQUNILENBQUMsQ0FBQyxDQUFDO0lBRUgsVUFBVSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBQyxPQUFPLEVBQUMsRUFBRTtRQUNyRCxXQUFXLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQy9CLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQWZELHNDQWVDIn0=
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFrZS1maWVsZC1kZWxldGVhYmxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ZpZWxkL21ha2UtZmllbGQtZGVsZXRlYWJsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQU9BLEtBQUssVUFBVSxXQUFXLENBQ3hCLE1BQXFCLEVBQ3JCLE9BQTBEO0lBRTFELE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxtQkFBbUIsRUFBRSxpQkFBaUIsSUFBSSxFQUFFLENBQUM7SUFFdkUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxFQUFFO1FBQzNDLFVBQVUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0tBQ3BDO0lBRUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQzFFLElBQUksSUFBYyxDQUFDO0lBRW5CLElBQUksTUFBTSxDQUFDLG1CQUFtQixFQUFFLGVBQWUsRUFBRTtRQUMvQyxJQUFJLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUN0QixPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLG1CQUFtQixDQUFDLGVBQWUsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FDbkYsQ0FBQztLQUNIO1NBQU07UUFDTCxJQUFJLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztLQUN6RDtJQUVELE1BQU0sYUFBYSxHQUFHLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUVoRSxJQUFJLGFBQWEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1FBQzVCLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0tBQ3BFO0FBQ0gsQ0FBQztBQUVELFNBQXdCLG1CQUFtQixDQUN6QyxVQUFnQyxFQUNoQyxNQUFxQjtJQUVyQixJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVc7UUFBRSxPQUFPO0lBRWhDLFVBQVUsQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUMsT0FBTyxFQUFDLEVBQUU7UUFDckQsSUFBSSxPQUFPLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxJQUFJLEVBQUU7WUFDM0MsV0FBVyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztTQUM5QjtJQUNILENBQUMsQ0FBQyxDQUFDO0lBRUgsVUFBVSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBQyxPQUFPLEVBQUMsRUFBRTtRQUNyRCxXQUFXLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQy9CLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQWZELHNDQWVDIn0=
@@ -1,10 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const data_uri_1 = require("../utils/data-uri");
4
- function getRecordId(collection, record) {
4
+ function getPks(collection) {
5
5
  return Object.entries(collection.schema.fields)
6
6
  .filter(([, schema]) => schema.type === 'Column' && schema.isPrimaryKey)
7
- .map(([name]) => record[name]);
7
+ .map(([name]) => name);
8
+ }
9
+ function computeProjection(collection, config) {
10
+ return [
11
+ ...new Set([
12
+ config.sourcename,
13
+ ...getPks(collection),
14
+ ...(config.objectKeyFromRecord?.extraDependencies ?? []), // extra deps
15
+ ]),
16
+ ];
8
17
  }
9
18
  function makeFieldWritable(collection, config) {
10
19
  const schema = collection.schema.fields[config.sourcename];
@@ -13,14 +22,30 @@ function makeFieldWritable(collection, config) {
13
22
  collection.replaceFieldWriting(config.filename, async (value, context) => {
14
23
  const patch = { [config.sourcename]: null };
15
24
  if (value) {
16
- const recordId = getRecordId(collection, context.record).join('|');
17
25
  const file = (0, data_uri_1.parseDataUri)(value);
18
- const key = config.storeAt(recordId, file.name);
19
- await config.client.save(key, file, config.acl);
20
- patch[config.sourcename] = key;
26
+ let record = null;
27
+ let recordId = null;
28
+ if (context.action === 'update') {
29
+ // On updates, we fetch the missing information from the database.
30
+ const pks = getPks(collection);
31
+ const projection = computeProjection(collection, config);
32
+ const records = await context.collection.list(context.filter || {}, projection);
33
+ // context.record is the patch coming from the frontend.
34
+ record = { ...(records?.[0] ?? {}), ...context.record };
35
+ recordId = pks.map(pk => record[pk]).join('|');
36
+ }
37
+ else {
38
+ // context.record is the record coming from the frontend.
39
+ record = { ...context.record };
40
+ }
41
+ patch[config.sourcename] = await config.storeAt(recordId, file.name, context);
42
+ // Update database and s3 bucket
43
+ await config.client.save(config.objectKeyFromRecord?.mappingFunction
44
+ ? await config.objectKeyFromRecord.mappingFunction({ ...record, ...patch }, context)
45
+ : patch[config.sourcename], file, config.acl);
21
46
  }
22
47
  return patch;
23
48
  });
24
49
  }
25
50
  exports.default = makeFieldWritable;
26
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFrZS1maWVsZC13cml0YWJsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9maWVsZC9tYWtlLWZpZWxkLXdyaXRhYmxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBSUEsZ0RBQWlEO0FBRWpELFNBQVMsV0FBVyxDQUFDLFVBQWdDLEVBQUUsTUFBa0I7SUFDdkUsT0FBTyxNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDO1NBQzVDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksTUFBTSxDQUFDLFlBQVksQ0FBQztTQUN2RSxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztBQUNuQyxDQUFDO0FBRUQsU0FBd0IsaUJBQWlCLENBQ3ZDLFVBQWdDLEVBQ2hDLE1BQXFCO0lBRXJCLE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQWlCLENBQUM7SUFDM0UsSUFBSSxNQUFNLENBQUMsVUFBVTtRQUFFLE9BQU87SUFFOUIsVUFBVSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtRQUN2RSxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDO1FBRTVDLElBQUksS0FBSyxFQUFFO1lBQ1QsTUFBTSxRQUFRLEdBQUcsV0FBVyxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ25FLE1BQU0sSUFBSSxHQUFHLElBQUEsdUJBQVksRUFBQyxLQUFLLENBQUMsQ0FBQztZQUNqQyxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFFaEQsTUFBTSxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNoRCxLQUFLLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLEdBQUcsQ0FBQztTQUNoQztRQUVELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBckJELG9DQXFCQyJ9
51
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFrZS1maWVsZC13cml0YWJsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9maWVsZC9tYWtlLWZpZWxkLXdyaXRhYmxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBSUEsZ0RBQWlEO0FBRWpELFNBQVMsTUFBTSxDQUFDLFVBQWdDO0lBQzlDLE9BQU8sTUFBTSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQztTQUM1QyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssUUFBUSxJQUFJLE1BQU0sQ0FBQyxZQUFZLENBQUM7U0FDdkUsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDM0IsQ0FBQztBQUVELFNBQVMsaUJBQWlCLENBQUMsVUFBZ0MsRUFBRSxNQUFxQjtJQUNoRixPQUFPO1FBQ0wsR0FBRyxJQUFJLEdBQUcsQ0FBQztZQUNULE1BQU0sQ0FBQyxVQUFVO1lBQ2pCLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQztZQUNyQixHQUFHLENBQUMsTUFBTSxDQUFDLG1CQUFtQixFQUFFLGlCQUFpQixJQUFJLEVBQUUsQ0FBQyxFQUFFLGFBQWE7U0FDeEUsQ0FBQztLQUNILENBQUM7QUFDSixDQUFDO0FBRUQsU0FBd0IsaUJBQWlCLENBQ3ZDLFVBQWdDLEVBQ2hDLE1BQXFCO0lBRXJCLE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQWlCLENBQUM7SUFDM0UsSUFBSSxNQUFNLENBQUMsVUFBVTtRQUFFLE9BQU87SUFFOUIsVUFBVSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtRQUN2RSxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDO1FBRTVDLElBQUksS0FBSyxFQUFFO1lBQ1QsTUFBTSxJQUFJLEdBQUcsSUFBQSx1QkFBWSxFQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ2pDLElBQUksTUFBTSxHQUFlLElBQUksQ0FBQztZQUM5QixJQUFJLFFBQVEsR0FBVyxJQUFJLENBQUM7WUFFNUIsSUFBSSxPQUFPLENBQUMsTUFBTSxLQUFLLFFBQVEsRUFBRTtnQkFDL0Isa0VBQWtFO2dCQUNsRSxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7Z0JBQy9CLE1BQU0sVUFBVSxHQUFHLGlCQUFpQixDQUFDLFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDekQsTUFBTSxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxJQUFJLEVBQUUsRUFBRSxVQUFVLENBQUMsQ0FBQztnQkFFaEYsd0RBQXdEO2dCQUN4RCxNQUFNLEdBQUcsRUFBRSxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsR0FBRyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ3hELFFBQVEsR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2FBQ2hEO2lCQUFNO2dCQUNMLHlEQUF5RDtnQkFDekQsTUFBTSxHQUFHLEVBQUUsR0FBRyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7YUFDaEM7WUFFRCxLQUFLLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLE1BQU0sTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztZQUU5RSxnQ0FBZ0M7WUFDaEMsTUFBTSxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FDdEIsTUFBTSxDQUFDLG1CQUFtQixFQUFFLGVBQWU7Z0JBQ3pDLENBQUMsQ0FBQyxNQUFNLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxlQUFlLENBQUMsRUFBRSxHQUFHLE1BQU0sRUFBRSxHQUFHLEtBQUssRUFBRSxFQUFFLE9BQU8sQ0FBQztnQkFDcEYsQ0FBQyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEVBQzVCLElBQUksRUFDSixNQUFNLENBQUMsR0FBRyxDQUNYLENBQUM7U0FDSDtRQUVELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBM0NELG9DQTJDQyJ9
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { CollectionCustomizer, DataSourceCustomizer } from '@forestadmin/datasource-customizer';
1
+ import type { TCollectionName, TSchema } from '@forestadmin/datasource-customizer';
2
2
  import { File, Options } from './types';
3
3
  export { Options, File };
4
- export declare function createFileField(dataSource: DataSourceCustomizer, collection: CollectionCustomizer, options?: Options): Promise<void>;
4
+ export declare function createFileField<S extends TSchema = TSchema, N extends TCollectionName<S> = TCollectionName<S>>(dataSource: any, collection: any, options?: Options<S, N>): Promise<void>;
5
5
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -30,6 +30,7 @@ async function createFileField(dataSource, collection, options) {
30
30
  readMode: options?.readMode ?? 'url',
31
31
  acl: options?.acl ?? 'private',
32
32
  storeAt: options?.storeAt ?? ((id, name) => `${collection.name}/${id}/${name}`),
33
+ objectKeyFromRecord: options?.objectKeyFromRecord || null,
33
34
  };
34
35
  (0, create_field_1.default)(collection, config);
35
36
  (0, make_field_writable_1.default)(collection, config);
@@ -40,4 +41,4 @@ async function createFileField(dataSource, collection, options) {
40
41
  (0, replace_field_1.default)(collection, config);
41
42
  }
42
43
  exports.createFileField = createFileField;
43
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBS0Esd0VBQStDO0FBQy9DLDBGQUFnRTtBQUNoRSwwRkFBZ0U7QUFDaEUsc0ZBQTREO0FBQzVELHNGQUE0RDtBQUM1RCxzRkFBNEQ7QUFDNUQsMEVBQWlEO0FBRWpELG9EQUFnQztBQUl6QixLQUFLLFVBQVUsZUFBZSxDQUNuQyxVQUFnQyxFQUNoQyxVQUFnQyxFQUNoQyxPQUFpQjtJQUVqQixJQUFJLENBQUMsVUFBVTtRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsa0RBQWtELENBQUMsQ0FBQztJQUNyRixJQUFJLENBQUMsT0FBTztRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsMkJBQTJCLENBQUMsQ0FBQztJQUUzRCxNQUFNLFlBQVksR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7SUFFakUsSUFBSSxDQUFDLFlBQVksSUFBSSxZQUFZLENBQUMsSUFBSSxLQUFLLFFBQVEsSUFBSSxZQUFZLENBQUMsVUFBVSxLQUFLLFFBQVEsRUFBRTtRQUMzRixNQUFNLEtBQUssR0FBRyxHQUFHLFVBQVUsQ0FBQyxJQUFJLElBQUksT0FBTyxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ3hELE1BQU0sSUFBSSxLQUFLLENBQUMsY0FBYyxLQUFLLHNDQUFzQyxDQUFDLENBQUM7S0FDNUU7SUFFRCxNQUFNLE1BQU0sR0FBRztRQUNiLFVBQVUsRUFBRSxPQUFPLENBQUMsU0FBUztRQUM3QixRQUFRLEVBQUUsR0FBRyxPQUFPLENBQUMsU0FBUyxRQUFRO1FBQ3RDLE1BQU0sRUFBRSxJQUFJLFlBQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDO1FBQy9CLFdBQVcsRUFBRSxPQUFPLEVBQUUsV0FBVyxJQUFJLEtBQUs7UUFDMUMsUUFBUSxFQUFFLE9BQU8sRUFBRSxRQUFRLElBQUksS0FBSztRQUNwQyxHQUFHLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxTQUFTO1FBQzlCLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxJQUFJLENBQUMsQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxJQUFJLElBQUksRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDO0tBQ2hGLENBQUM7SUFFRixJQUFBLHNCQUFXLEVBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ2hDLElBQUEsNkJBQWlCLEVBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ3RDLElBQUEsK0JBQW1CLEVBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ3hDLElBQUEsNkJBQWlCLEVBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ3RDLElBQUEsK0JBQW1CLEVBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ3hDLElBQUEsNkJBQWlCLEVBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ3RDLElBQUEsdUJBQVksRUFBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFDbkMsQ0FBQztBQWhDRCwwQ0FnQ0MifQ==
44
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBRUEsd0VBQStDO0FBQy9DLDBGQUFnRTtBQUNoRSwwRkFBZ0U7QUFDaEUsc0ZBQTREO0FBQzVELHNGQUE0RDtBQUM1RCxzRkFBNEQ7QUFDNUQsMEVBQWlEO0FBRWpELG9EQUFnQztBQUl6QixLQUFLLFVBQVUsZUFBZSxDQUduQyxVQUFVLEVBQUUsVUFBVSxFQUFFLE9BQXVCO0lBQy9DLElBQUksQ0FBQyxVQUFVO1FBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxrREFBa0QsQ0FBQyxDQUFDO0lBQ3JGLElBQUksQ0FBQyxPQUFPO1FBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO0lBRTNELE1BQU0sWUFBWSxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUVqRSxJQUFJLENBQUMsWUFBWSxJQUFJLFlBQVksQ0FBQyxJQUFJLEtBQUssUUFBUSxJQUFJLFlBQVksQ0FBQyxVQUFVLEtBQUssUUFBUSxFQUFFO1FBQzNGLE1BQU0sS0FBSyxHQUFHLEdBQUcsVUFBVSxDQUFDLElBQUksSUFBSSxPQUFPLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDeEQsTUFBTSxJQUFJLEtBQUssQ0FBQyxjQUFjLEtBQUssc0NBQXNDLENBQUMsQ0FBQztLQUM1RTtJQUVELE1BQU0sTUFBTSxHQUFHO1FBQ2IsVUFBVSxFQUFFLE9BQU8sQ0FBQyxTQUFTO1FBQzdCLFFBQVEsRUFBRSxHQUFHLE9BQU8sQ0FBQyxTQUFTLFFBQVE7UUFDdEMsTUFBTSxFQUFFLElBQUksWUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUM7UUFDL0IsV0FBVyxFQUFFLE9BQU8sRUFBRSxXQUFXLElBQUksS0FBSztRQUMxQyxRQUFRLEVBQUUsT0FBTyxFQUFFLFFBQVEsSUFBSSxLQUFLO1FBQ3BDLEdBQUcsRUFBRSxPQUFPLEVBQUUsR0FBRyxJQUFJLFNBQVM7UUFDOUIsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLElBQUksQ0FBQyxDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFBRSxDQUFDLEdBQUcsVUFBVSxDQUFDLElBQUksSUFBSSxFQUFFLElBQUksSUFBSSxFQUFFLENBQUM7UUFDL0UsbUJBQW1CLEVBQUUsT0FBTyxFQUFFLG1CQUFtQixJQUFJLElBQUk7S0FDMUQsQ0FBQztJQUVGLElBQUEsc0JBQVcsRUFBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDaEMsSUFBQSw2QkFBaUIsRUFBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDdEMsSUFBQSwrQkFBbUIsRUFBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDeEMsSUFBQSw2QkFBaUIsRUFBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDdEMsSUFBQSwrQkFBbUIsRUFBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDeEMsSUFBQSw2QkFBaUIsRUFBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDdEMsSUFBQSx1QkFBWSxFQUFDLFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FBQztBQUNuQyxDQUFDO0FBaENELDBDQWdDQyJ9
package/dist/types.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  /// <reference types="node" />
2
+ import type { TCollectionName, TColumnName, TFieldName, TPartialSimpleRow, TSchema } from '@forestadmin/datasource-customizer';
3
+ import type CollectionCustomizationContext from '@forestadmin/datasource-customizer/dist/context/collection-context';
4
+ import type WriteCustomizationContext from '@forestadmin/datasource-customizer/dist/decorators/write/write-replace/context';
2
5
  import { ObjectCannedACL } from '@aws-sdk/client-s3';
3
6
  import Client from './utils/s3';
4
7
  export type File = {
@@ -13,14 +16,44 @@ export type File = {
13
16
  * It can be included in the global agent configuration under the "s3" key and overriden for
14
17
  * specific fields by using the "config" property on `AmazonS3File`.
15
18
  */
16
- export type Options = {
19
+ export type Options<S extends TSchema = TSchema, N extends TCollectionName<S> = TCollectionName<S>> = {
17
20
  /** Name of the field that you want to use as a file-picker on the frontend */
18
- fieldname: string;
21
+ fieldname: TColumnName<S, N>;
19
22
  /**
20
- * Where should the file be stored on S3?
21
- * Defaults to '<collection_name>/<field_name>/`.
23
+ * This function allows customizing the string that will be saved in the database.
24
+ * If the objectKeyFromRecord option is not set, the output of that function will also
25
+ * be used as the object key in S3.
26
+ *
27
+ * Note that the recordId parameter will _not_ be provided when records are created.
28
+ *
29
+ * Defaults to '<collection name>/<id>/<originalFilename>`.
30
+ *
31
+ * @example
32
+ * ```js
33
+ * storeAt: (recordId, originalFilename, context) => {
34
+ * return `${context.collection.name}/${recordId ?? 'new-record'}/${originalFilename}`;
35
+ * }
36
+ * ```
22
37
  */
23
- storeAt?: (recordId: string, originalFilename: string) => string;
38
+ storeAt?: (recordId: string, originalFilename: string, context: WriteCustomizationContext<S, N>) => string | Promise<string>;
39
+ /**
40
+ * This function allows customizing the object key that will be used in S3 without interfering
41
+ * with what is stored in the database.
42
+ *
43
+ * @example
44
+ * ```
45
+ * objectKeyFromRecord: {
46
+ * extraDependencies: ['firstname', 'lastname'],
47
+ * mappingFunction: (record, context) => {
48
+ * return `avatars/${record.firstname}-${record.lastname}.png`;
49
+ * }
50
+ * };
51
+ * ```
52
+ */
53
+ objectKeyFromRecord?: {
54
+ extraDependencies?: TFieldName<S, N>[];
55
+ mappingFunction: (record: TPartialSimpleRow<S, N>, context: CollectionCustomizationContext<S, N>) => string | Promise<string>;
56
+ };
24
57
  /** Either if old files should be deleted when updating or deleting a record. */
25
58
  deleteFiles?: boolean;
26
59
  /**
@@ -56,9 +89,9 @@ export type Options = {
56
89
  endpoint?: string;
57
90
  };
58
91
  };
59
- export type Configuration = Required<Pick<Options, 'acl' | 'deleteFiles' | 'readMode' | 'storeAt'> & {
92
+ export type Configuration<S extends TSchema = TSchema, N extends TCollectionName<S> = TCollectionName<S>> = Required<Pick<Options<S, N>, 'acl' | 'deleteFiles' | 'readMode' | 'storeAt' | 'objectKeyFromRecord'> & {
60
93
  client: Client;
61
- sourcename: string;
62
- filename: string;
94
+ sourcename: TColumnName<S, N>;
95
+ filename: TColumnName<S, N>;
63
96
  }>;
64
97
  //# sourceMappingURL=types.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forestadmin/plugin-aws-s3",
3
- "version": "1.2.5",
3
+ "version": "1.3.1",
4
4
  "main": "dist/index.js",
5
5
  "license": "GPL-3.0",
6
6
  "publishConfig": {
@@ -16,7 +16,7 @@
16
16
  "@aws-sdk/s3-request-presigner": "^3.157.0"
17
17
  },
18
18
  "devDependencies": {
19
- "@forestadmin/datasource-customizer": "1.9.3",
19
+ "@forestadmin/datasource-customizer": "1.10.1",
20
20
  "@forestadmin/datasource-toolkit": "1.5.1"
21
21
  },
22
22
  "files": [