@payloadcms/plugin-cloud-storage 4.0.0-internal.c3ac604 → 4.0.0-internal.c6494b5
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/README.md +2 -0
- package/dist/exports/client.d.ts +1 -1
- package/dist/exports/client.d.ts.map +1 -1
- package/dist/exports/client.js +1 -1
- package/dist/exports/client.js.map +1 -1
- package/dist/exports/utilities.d.ts +1 -1
- package/dist/exports/utilities.d.ts.map +1 -1
- package/dist/exports/utilities.js +1 -1
- package/dist/exports/utilities.js.map +1 -1
- package/dist/fields/getFields.d.ts +1 -5
- package/dist/fields/getFields.d.ts.map +1 -1
- package/dist/fields/getFields.js +118 -24
- package/dist/fields/getFields.js.map +1 -1
- package/dist/hooks/afterChange.d.ts +5 -1
- package/dist/hooks/afterChange.d.ts.map +1 -1
- package/dist/hooks/afterChange.js +137 -23
- package/dist/hooks/afterChange.js.map +1 -1
- package/dist/hooks/afterDelete.d.ts +3 -1
- package/dist/hooks/afterDelete.d.ts.map +1 -1
- package/dist/hooks/afterDelete.js +26 -4
- package/dist/hooks/afterDelete.js.map +1 -1
- package/dist/hooks/afterRead.d.ts +6 -1
- package/dist/hooks/afterRead.d.ts.map +1 -1
- package/dist/hooks/afterRead.js +34 -7
- package/dist/hooks/afterRead.js.map +1 -1
- package/dist/hooks/beforeChange.d.ts +2 -1
- package/dist/hooks/beforeChange.d.ts.map +1 -1
- package/dist/hooks/beforeChange.js +18 -4
- package/dist/hooks/beforeChange.js.map +1 -1
- package/dist/hooks/normalizeUploadPrefix.d.ts +11 -0
- package/dist/hooks/normalizeUploadPrefix.d.ts.map +1 -0
- package/dist/hooks/normalizeUploadPrefix.js +42 -0
- package/dist/hooks/normalizeUploadPrefix.js.map +1 -0
- package/dist/hooks/publicOriginalURL.d.ts +8 -0
- package/dist/hooks/publicOriginalURL.d.ts.map +1 -0
- package/dist/hooks/publicOriginalURL.js +34 -0
- package/dist/hooks/publicOriginalURL.js.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +72 -42
- package/dist/plugin.js.map +1 -1
- package/dist/types.d.ts +45 -12
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities/buildPrefixWithObjectKey.d.ts +8 -0
- package/dist/utilities/buildPrefixWithObjectKey.d.ts.map +1 -0
- package/dist/utilities/buildPrefixWithObjectKey.js +13 -0
- package/dist/utilities/buildPrefixWithObjectKey.js.map +1 -0
- package/dist/utilities/buildStoragePathData.d.ts +49 -0
- package/dist/utilities/buildStoragePathData.d.ts.map +1 -0
- package/dist/utilities/buildStoragePathData.js +67 -0
- package/dist/utilities/buildStoragePathData.js.map +1 -0
- package/dist/utilities/createFileOperations.d.ts +13 -0
- package/dist/utilities/createFileOperations.d.ts.map +1 -0
- package/dist/utilities/createFileOperations.js +258 -0
- package/dist/utilities/createFileOperations.js.map +1 -0
- package/dist/utilities/getFilePrefix.d.ts +15 -10
- package/dist/utilities/getFilePrefix.d.ts.map +1 -1
- package/dist/utilities/getFilePrefix.js +85 -30
- package/dist/utilities/getFilePrefix.js.map +1 -1
- package/dist/utilities/getIncomingFiles.js +2 -2
- package/dist/utilities/getIncomingFiles.js.map +1 -1
- package/dist/utilities/getStorageLocationSelect.d.ts +9 -0
- package/dist/utilities/getStorageLocationSelect.d.ts.map +1 -0
- package/dist/utilities/getStorageLocationSelect.js +54 -0
- package/dist/utilities/getStorageLocationSelect.js.map +1 -0
- package/dist/utilities/resolveSignedURLKey.d.ts +12 -1
- package/dist/utilities/resolveSignedURLKey.d.ts.map +1 -1
- package/dist/utilities/resolveSignedURLKey.js +52 -10
- package/dist/utilities/resolveSignedURLKey.js.map +1 -1
- package/dist/utilities/sanitizePrefix.d.ts +1 -9
- package/dist/utilities/sanitizePrefix.d.ts.map +1 -1
- package/dist/utilities/sanitizePrefix.js +1 -21
- package/dist/utilities/sanitizePrefix.js.map +1 -1
- package/package.json +6 -6
- package/dist/admin/fields/getFields.d.ts +0 -17
- package/dist/admin/fields/getFields.d.ts.map +0 -1
- package/dist/admin/fields/getFields.js +0 -98
- package/dist/admin/fields/getFields.js.map +0 -1
- package/dist/admin/index.d.ts +0 -4
- package/dist/admin/index.d.ts.map +0 -1
- package/dist/admin/index.js +0 -34
- package/dist/admin/index.js.map +0 -1
- package/dist/utilities/getFileKey.d.ts +0 -22
- package/dist/utilities/getFileKey.d.ts.map +0 -1
- package/dist/utilities/getFileKey.js +0 -23
- package/dist/utilities/getFileKey.js.map +0 -1
- package/dist/utilities/getFileKey.spec.js +0 -174
- package/dist/utilities/getFileKey.spec.js.map +0 -1
- package/dist/utilities/getFilePrefix.spec.js +0 -105
- package/dist/utilities/getFilePrefix.spec.js.map +0 -1
package/README.md
CHANGED
|
@@ -98,6 +98,8 @@ Instead, all uploads will still be reached from the default `/:collectionSlug/fi
|
|
|
98
98
|
|
|
99
99
|
If this does not apply to you (your upload collection has `read: () => true` or similar) you can disable this functionality by setting `disablePayloadAccessControl` to `true`. When this setting is in place, this plugin will update your file URLs to point directly to your cloud host.
|
|
100
100
|
|
|
101
|
+
`disablePayloadAccessControl` does not disable safe outbound fetching. If Payload needs to fetch files from a private or internal storage endpoint, configure the upload collection's [`skipSafeFetch`](https://payloadcms.com/docs/upload/overview#skip-safe-fetch) option with an explicit allowlist for the trusted destination. Set `skipSafeFetch: true` only when every URL accepted by the collection is trusted.
|
|
102
|
+
|
|
101
103
|
## Credit
|
|
102
104
|
|
|
103
105
|
This plugin was created with significant help, and code, from [Alex Bechmann](https://github.com/alexbechmann) and [Richard VanBergen](https://github.com/richardvanbergen). Thank you!!
|
package/dist/exports/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { createClientUploadHandler } from '../client/createClientUploadHandler.js';
|
|
2
|
-
export {
|
|
2
|
+
export { buildStoragePathData, buildUploadStoragePathData, } from '../utilities/buildStoragePathData.js';
|
|
3
3
|
export { sanitizePrefix } from '../utilities/sanitizePrefix.js';
|
|
4
4
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/exports/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAA;AAClF,OAAO,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/exports/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAA;AAClF,OAAO,EACL,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA"}
|
package/dist/exports/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createClientUploadHandler } from '../client/createClientUploadHandler.js';
|
|
2
|
-
export {
|
|
2
|
+
export { buildStoragePathData, buildUploadStoragePathData } from '../utilities/buildStoragePathData.js';
|
|
3
3
|
export { sanitizePrefix } from '../utilities/sanitizePrefix.js';
|
|
4
4
|
|
|
5
5
|
//# sourceMappingURL=client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["export { createClientUploadHandler } from '../client/createClientUploadHandler.js'\nexport {
|
|
1
|
+
{"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["export { createClientUploadHandler } from '../client/createClientUploadHandler.js'\nexport {\n buildStoragePathData,\n buildUploadStoragePathData,\n} from '../utilities/buildStoragePathData.js'\nexport { sanitizePrefix } from '../utilities/sanitizePrefix.js'\n"],"names":["createClientUploadHandler","buildStoragePathData","buildUploadStoragePathData","sanitizePrefix"],"mappings":"AAAA,SAASA,yBAAyB,QAAQ,yCAAwC;AAClF,SACEC,oBAAoB,EACpBC,0BAA0B,QACrB,uCAAsC;AAC7C,SAASC,cAAc,QAAQ,iCAAgC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { buildStoragePathData, buildUploadStoragePathData, isStoragePathWithinCollectionPrefix, } from '../utilities/buildStoragePathData.js';
|
|
2
2
|
export { getFilePrefix } from '../utilities/getFilePrefix.js';
|
|
3
3
|
export { resolveSignedURLKey } from '../utilities/resolveSignedURLKey.js';
|
|
4
4
|
export { sanitizePrefix } from '../utilities/sanitizePrefix.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../../src/exports/utilities.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../../src/exports/utilities.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,0BAA0B,EAC1B,mCAAmC,GACpC,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { buildStoragePathData, buildUploadStoragePathData, isStoragePathWithinCollectionPrefix } from '../utilities/buildStoragePathData.js';
|
|
2
2
|
export { getFilePrefix } from '../utilities/getFilePrefix.js';
|
|
3
3
|
export { resolveSignedURLKey } from '../utilities/resolveSignedURLKey.js';
|
|
4
4
|
export { sanitizePrefix } from '../utilities/sanitizePrefix.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/exports/utilities.ts"],"sourcesContent":["export {
|
|
1
|
+
{"version":3,"sources":["../../src/exports/utilities.ts"],"sourcesContent":["export {\n buildStoragePathData,\n buildUploadStoragePathData,\n isStoragePathWithinCollectionPrefix,\n} from '../utilities/buildStoragePathData.js'\nexport { getFilePrefix } from '../utilities/getFilePrefix.js'\nexport { resolveSignedURLKey } from '../utilities/resolveSignedURLKey.js'\nexport { sanitizePrefix } from '../utilities/sanitizePrefix.js'\n"],"names":["buildStoragePathData","buildUploadStoragePathData","isStoragePathWithinCollectionPrefix","getFilePrefix","resolveSignedURLKey","sanitizePrefix"],"mappings":"AAAA,SACEA,oBAAoB,EACpBC,0BAA0B,EAC1BC,mCAAmC,QAC9B,uCAAsC;AAC7C,SAASC,aAAa,QAAQ,gCAA+B;AAC7D,SAASC,mBAAmB,QAAQ,sCAAqC;AACzE,SAASC,cAAc,QAAQ,iCAAgC"}
|
|
@@ -2,10 +2,6 @@ import type { CollectionConfig, Field } from 'payload';
|
|
|
2
2
|
import type { GeneratedAdapter, GenerateFileURL } from '../types.js';
|
|
3
3
|
interface Args {
|
|
4
4
|
adapter?: GeneratedAdapter;
|
|
5
|
-
/**
|
|
6
|
-
* When true, always insert the prefix field regardless of whether a prefix is configured.
|
|
7
|
-
*/
|
|
8
|
-
alwaysInsertFields?: boolean;
|
|
9
5
|
collection: CollectionConfig;
|
|
10
6
|
disablePayloadAccessControl?: true;
|
|
11
7
|
generateFileURL?: GenerateFileURL;
|
|
@@ -16,6 +12,6 @@ interface Args {
|
|
|
16
12
|
*/
|
|
17
13
|
useCompositePrefixes?: boolean;
|
|
18
14
|
}
|
|
19
|
-
export declare const getFields: ({ adapter,
|
|
15
|
+
export declare const getFields: ({ adapter, collection, disablePayloadAccessControl, generateFileURL, prefix, useCompositePrefixes, }: Args) => Field[];
|
|
20
16
|
export {};
|
|
21
17
|
//# sourceMappingURL=getFields.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getFields.d.ts","sourceRoot":"","sources":["../../src/fields/getFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"getFields.d.ts","sourceRoot":"","sources":["../../src/fields/getFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAgD,MAAM,SAAS,CAAA;AAIpG,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAMpE,UAAU,IAAI;IACZ,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAC1B,UAAU,EAAE,gBAAgB,CAAA;IAC5B,2BAA2B,CAAC,EAAE,IAAI,CAAA;IAClC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,eAAO,MAAM,SAAS,yGAOnB,IAAI,KAAG,KAAK,EAgSd,CAAA"}
|
package/dist/fields/getFields.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { getAfterReadHook } from '../hooks/afterRead.js';
|
|
3
3
|
import { getBeforeChangeHook } from '../hooks/beforeChange.js';
|
|
4
|
-
|
|
4
|
+
import { getNormalizeUploadPrefixFieldHook } from '../hooks/normalizeUploadPrefix.js';
|
|
5
|
+
export const getFields = ({ adapter, collection, disablePayloadAccessControl, generateFileURL, prefix, useCompositePrefixes = false })=>{
|
|
5
6
|
const baseURLField = {
|
|
6
7
|
name: 'url',
|
|
7
8
|
type: 'text',
|
|
@@ -15,10 +16,38 @@ export const getFields = ({ adapter, alwaysInsertFields, collection, disablePayl
|
|
|
15
16
|
name: 'prefix',
|
|
16
17
|
type: 'text',
|
|
17
18
|
admin: {
|
|
19
|
+
disabled: {
|
|
20
|
+
bulkEdit: true,
|
|
21
|
+
column: true,
|
|
22
|
+
filter: true,
|
|
23
|
+
groupBy: true
|
|
24
|
+
},
|
|
25
|
+
hidden: true,
|
|
26
|
+
readOnly: true
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
// Server-owned key segment. Field-level `hidden` would remove it before the URL hooks can read it.
|
|
30
|
+
const baseObjectKeyField = {
|
|
31
|
+
name: '_objectKey',
|
|
32
|
+
type: 'text',
|
|
33
|
+
admin: {
|
|
34
|
+
disabled: {
|
|
35
|
+
bulkEdit: true,
|
|
36
|
+
column: true,
|
|
37
|
+
filter: true,
|
|
38
|
+
groupBy: true
|
|
39
|
+
},
|
|
18
40
|
hidden: true,
|
|
19
41
|
readOnly: true
|
|
20
42
|
}
|
|
21
43
|
};
|
|
44
|
+
const storedPrefixField = {
|
|
45
|
+
...basePrefixField,
|
|
46
|
+
admin: {
|
|
47
|
+
...basePrefixField.admin,
|
|
48
|
+
disabled: true
|
|
49
|
+
}
|
|
50
|
+
};
|
|
22
51
|
const fields = [
|
|
23
52
|
...collection.fields,
|
|
24
53
|
...adapter?.fields || []
|
|
@@ -67,10 +96,54 @@ export const getFields = ({ adapter, alwaysInsertFields, collection, disablePayl
|
|
|
67
96
|
...existingURLField || {}
|
|
68
97
|
});
|
|
69
98
|
}
|
|
70
|
-
|
|
99
|
+
let originalField = fields.find((field)=>field.type === 'group' && 'name' in field && field.name === 'original');
|
|
100
|
+
if (adapter && !originalField) {
|
|
101
|
+
originalField = {
|
|
102
|
+
name: 'original',
|
|
103
|
+
type: 'group',
|
|
104
|
+
fields: [
|
|
105
|
+
baseURLField
|
|
106
|
+
]
|
|
107
|
+
};
|
|
108
|
+
fields.push(originalField);
|
|
109
|
+
}
|
|
110
|
+
const originalURLFieldIndex = originalField?.fields.findIndex((field)=>'name' in field && field.name === 'url');
|
|
111
|
+
if (adapter && originalField && originalURLFieldIndex !== undefined && originalURLFieldIndex >= 0) {
|
|
112
|
+
const originalURLField = originalField.fields[originalURLFieldIndex];
|
|
113
|
+
originalField.fields[originalURLFieldIndex] = {
|
|
114
|
+
...baseURLField,
|
|
115
|
+
...originalURLField,
|
|
116
|
+
hooks: {
|
|
117
|
+
afterRead: [
|
|
118
|
+
getAfterReadHook({
|
|
119
|
+
adapter,
|
|
120
|
+
collection,
|
|
121
|
+
disablePayloadAccessControl,
|
|
122
|
+
generateFileURL,
|
|
123
|
+
isOriginal: true
|
|
124
|
+
}),
|
|
125
|
+
...originalURLField.hooks?.afterRead || []
|
|
126
|
+
],
|
|
127
|
+
beforeChange: [
|
|
128
|
+
getBeforeChangeHook({
|
|
129
|
+
adapter,
|
|
130
|
+
collection,
|
|
131
|
+
disablePayloadAccessControl,
|
|
132
|
+
generateFileURL,
|
|
133
|
+
isOriginal: true
|
|
134
|
+
}),
|
|
135
|
+
...originalURLField.hooks?.beforeChange || []
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// Storage adapters add these fields during their `init`, after transformers (e.g. Sharp) have
|
|
141
|
+
// written each collection's image sizes onto its upload config.
|
|
142
|
+
const variants = typeof collection.upload === 'object' ? collection.upload.variants : undefined;
|
|
143
|
+
if (variants) {
|
|
71
144
|
let existingSizesFieldIndex = -1;
|
|
72
145
|
const existingSizesField = fields.find((existingField, i)=>{
|
|
73
|
-
if ('name' in existingField && existingField.name === '
|
|
146
|
+
if ('name' in existingField && existingField.name === 'variants') {
|
|
74
147
|
existingSizesFieldIndex = i;
|
|
75
148
|
return true;
|
|
76
149
|
}
|
|
@@ -81,12 +154,12 @@ export const getFields = ({ adapter, alwaysInsertFields, collection, disablePayl
|
|
|
81
154
|
}
|
|
82
155
|
const sizesField = {
|
|
83
156
|
...existingSizesField || {},
|
|
84
|
-
name: '
|
|
157
|
+
name: 'variants',
|
|
85
158
|
type: 'group',
|
|
86
159
|
admin: {
|
|
87
160
|
hidden: true
|
|
88
161
|
},
|
|
89
|
-
fields:
|
|
162
|
+
fields: variants.map((size)=>{
|
|
90
163
|
const existingSizeField = existingSizesField?.fields.find((existingField)=>'name' in existingField && existingField.name === size.name);
|
|
91
164
|
const existingSizeURLField = existingSizeField?.fields.find((existingField)=>'name' in existingField && existingField.name === 'url');
|
|
92
165
|
// Only add afterRead hook if adapter is provided
|
|
@@ -124,33 +197,54 @@ export const getFields = ({ adapter, alwaysInsertFields, collection, disablePayl
|
|
|
124
197
|
name: size.name,
|
|
125
198
|
type: 'group',
|
|
126
199
|
fields: [
|
|
127
|
-
...adapter?.fields || []
|
|
128
|
-
|
|
200
|
+
...(adapter?.fields || []).filter((field)=>!('name' in field && [
|
|
201
|
+
'_objectKey',
|
|
202
|
+
'prefix'
|
|
203
|
+
].includes(field.name))),
|
|
204
|
+
sizeURLField,
|
|
205
|
+
storedPrefixField,
|
|
206
|
+
baseObjectKeyField
|
|
129
207
|
]
|
|
130
208
|
};
|
|
131
209
|
})
|
|
132
210
|
};
|
|
133
211
|
fields.push(sizesField);
|
|
134
212
|
}
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
return false;
|
|
144
|
-
});
|
|
145
|
-
if (existingPrefixFieldIndex > -1) {
|
|
146
|
-
fields.splice(existingPrefixFieldIndex, 1);
|
|
213
|
+
// Always insert the prefix field so the schema stays consistent regardless of
|
|
214
|
+
// whether the plugin is enabled or a prefix is configured.
|
|
215
|
+
let existingPrefixFieldIndex = -1;
|
|
216
|
+
const existingPrefixField = fields.find((existingField, i)=>{
|
|
217
|
+
if ('name' in existingField && existingField.name === 'prefix') {
|
|
218
|
+
existingPrefixFieldIndex = i;
|
|
219
|
+
return true;
|
|
147
220
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
});
|
|
221
|
+
return false;
|
|
222
|
+
});
|
|
223
|
+
if (existingPrefixFieldIndex > -1) {
|
|
224
|
+
fields.splice(existingPrefixFieldIndex, 1);
|
|
153
225
|
}
|
|
226
|
+
fields.push({
|
|
227
|
+
...basePrefixField,
|
|
228
|
+
...existingPrefixField || {},
|
|
229
|
+
defaultValue: existingPrefixField?.defaultValue ?? (useCompositePrefixes ? '' : prefix ? path.posix.join(prefix) : ''),
|
|
230
|
+
hooks: {
|
|
231
|
+
...existingPrefixField?.hooks,
|
|
232
|
+
beforeChange: [
|
|
233
|
+
...existingPrefixField?.hooks?.beforeChange || [],
|
|
234
|
+
getNormalizeUploadPrefixFieldHook({
|
|
235
|
+
collectionPrefix: prefix,
|
|
236
|
+
useCompositePrefixes
|
|
237
|
+
})
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
const existingObjectKeyFieldIndex = fields.findIndex((existingField)=>'name' in existingField && existingField.name === '_objectKey');
|
|
242
|
+
if (existingObjectKeyFieldIndex > -1) {
|
|
243
|
+
fields.splice(existingObjectKeyFieldIndex, 1);
|
|
244
|
+
}
|
|
245
|
+
fields.push({
|
|
246
|
+
...baseObjectKeyField
|
|
247
|
+
});
|
|
154
248
|
return fields;
|
|
155
249
|
};
|
|
156
250
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/fields/getFields.ts"],"sourcesContent":["import type { CollectionConfig, Field, GroupField, TextField } from 'payload'\n\nimport path from 'path'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport { getAfterReadHook } from '../hooks/afterRead.js'\nimport { getBeforeChangeHook } from '../hooks/beforeChange.js'\n\ninterface Args {\n adapter?: GeneratedAdapter\n /**\n * When true, always insert the prefix field regardless of whether a prefix is configured.\n */\n alwaysInsertFields?: boolean\n collection: CollectionConfig\n disablePayloadAccessControl?: true\n generateFileURL?: GenerateFileURL\n prefix?: string\n /**\n * When true, do not default the `prefix` field to the collection prefix; the\n * document field holds only the document-level segment.\n */\n useCompositePrefixes?: boolean\n}\n\nexport const getFields = ({\n adapter,\n alwaysInsertFields,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n prefix,\n useCompositePrefixes = false,\n}: Args): Field[] => {\n const baseURLField: TextField = {\n name: 'url',\n type: 'text',\n admin: {\n hidden: true,\n readOnly: true,\n },\n label: 'URL',\n }\n\n const basePrefixField: TextField = {\n name: 'prefix',\n type: 'text',\n admin: {\n hidden: true,\n readOnly: true,\n },\n }\n\n const fields = [...collection.fields, ...(adapter?.fields || [])]\n\n // Inject a hook into all URL fields to generate URLs\n\n let existingURLFieldIndex = -1\n\n const existingURLField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'url') {\n existingURLFieldIndex = i\n return true\n }\n return false\n }) as TextField\n\n if (existingURLFieldIndex > -1) {\n fields.splice(existingURLFieldIndex, 1)\n }\n\n // Only add afterRead hook if adapter is provided\n if (adapter) {\n fields.push({\n ...baseURLField,\n ...(existingURLField || {}),\n hooks: {\n afterRead: [\n getAfterReadHook({ adapter, collection, disablePayloadAccessControl, generateFileURL }),\n ...(existingURLField?.hooks?.afterRead || []),\n ],\n beforeChange: [\n getBeforeChangeHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n }),\n ...(existingURLField?.hooks?.beforeChange || []),\n ],\n },\n } as TextField)\n } else {\n fields.push({\n ...baseURLField,\n ...(existingURLField || {}),\n } as TextField)\n }\n\n if (typeof collection.upload === 'object' && collection.upload.imageSizes) {\n let existingSizesFieldIndex = -1\n\n const existingSizesField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'sizes') {\n existingSizesFieldIndex = i\n return true\n }\n\n return false\n }) as GroupField\n\n if (existingSizesFieldIndex > -1) {\n fields.splice(existingSizesFieldIndex, 1)\n }\n\n const sizesField: Field = {\n ...(existingSizesField || {}),\n name: 'sizes',\n type: 'group',\n admin: {\n hidden: true,\n },\n fields: collection.upload.imageSizes.map((size) => {\n const existingSizeField = existingSizesField?.fields.find(\n (existingField) => 'name' in existingField && existingField.name === size.name,\n ) as GroupField\n\n const existingSizeURLField = existingSizeField?.fields.find(\n (existingField) => 'name' in existingField && existingField.name === 'url',\n ) as TextField\n\n // Only add afterRead hook if adapter is provided\n const sizeURLField: TextField = adapter\n ? ({\n ...(existingSizeURLField || {}),\n ...baseURLField,\n hooks: {\n afterRead: [\n getAfterReadHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n size,\n }),\n ...((typeof existingSizeURLField === 'object' &&\n 'hooks' in existingSizeURLField &&\n existingSizeURLField?.hooks?.afterRead) ||\n []),\n ],\n beforeChange: [\n getBeforeChangeHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n size,\n }),\n ...((typeof existingSizeURLField === 'object' &&\n 'hooks' in existingSizeURLField &&\n existingSizeURLField?.hooks?.beforeChange) ||\n []),\n ],\n },\n } as TextField)\n : ({\n ...(existingSizeURLField || {}),\n ...baseURLField,\n } as TextField)\n\n return {\n ...existingSizeField,\n name: size.name,\n type: 'group',\n fields: [...(adapter?.fields || []), sizeURLField],\n } as Field\n }),\n }\n\n fields.push(sizesField)\n }\n\n // If prefix is enabled or alwaysInsertFields is true, save it to db\n if (typeof prefix !== 'undefined' || alwaysInsertFields) {\n let existingPrefixFieldIndex = -1\n\n const existingPrefixField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'prefix') {\n existingPrefixFieldIndex = i\n return true\n }\n return false\n }) as TextField\n\n if (existingPrefixFieldIndex > -1) {\n fields.splice(existingPrefixFieldIndex, 1)\n }\n\n fields.push({\n ...basePrefixField,\n ...(existingPrefixField || {}),\n defaultValue:\n existingPrefixField?.defaultValue ??\n (useCompositePrefixes ? '' : prefix ? path.posix.join(prefix) : ''),\n } as TextField)\n }\n\n return fields\n}\n"],"names":["path","getAfterReadHook","getBeforeChangeHook","getFields","adapter","alwaysInsertFields","collection","disablePayloadAccessControl","generateFileURL","prefix","useCompositePrefixes","baseURLField","name","type","admin","hidden","readOnly","label","basePrefixField","fields","existingURLFieldIndex","existingURLField","find","existingField","i","splice","push","hooks","afterRead","beforeChange","upload","imageSizes","existingSizesFieldIndex","existingSizesField","sizesField","map","size","existingSizeField","existingSizeURLField","sizeURLField","existingPrefixFieldIndex","existingPrefixField","defaultValue","posix","join"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/fields/getFields.ts"],"sourcesContent":["import type { CollectionConfig, Field, GroupField, SanitizedUploadConfig, TextField } from 'payload'\n\nimport path from 'path'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport { getAfterReadHook } from '../hooks/afterRead.js'\nimport { getBeforeChangeHook } from '../hooks/beforeChange.js'\nimport { getNormalizeUploadPrefixFieldHook } from '../hooks/normalizeUploadPrefix.js'\n\ninterface Args {\n adapter?: GeneratedAdapter\n collection: CollectionConfig\n disablePayloadAccessControl?: true\n generateFileURL?: GenerateFileURL\n prefix?: string\n /**\n * When true, do not default the `prefix` field to the collection prefix; the\n * document field holds only the document-level segment.\n */\n useCompositePrefixes?: boolean\n}\n\nexport const getFields = ({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n prefix,\n useCompositePrefixes = false,\n}: Args): Field[] => {\n const baseURLField: TextField = {\n name: 'url',\n type: 'text',\n admin: {\n hidden: true,\n readOnly: true,\n },\n label: 'URL',\n }\n\n const basePrefixField: TextField = {\n name: 'prefix',\n type: 'text',\n admin: {\n disabled: {\n bulkEdit: true,\n column: true,\n filter: true,\n groupBy: true,\n },\n hidden: true,\n readOnly: true,\n },\n }\n\n // Server-owned key segment. Field-level `hidden` would remove it before the URL hooks can read it.\n const baseObjectKeyField: TextField = {\n name: '_objectKey',\n type: 'text',\n admin: {\n disabled: {\n bulkEdit: true,\n column: true,\n filter: true,\n groupBy: true,\n },\n hidden: true,\n readOnly: true,\n },\n }\n\n const storedPrefixField: TextField = {\n ...basePrefixField,\n admin: {\n ...basePrefixField.admin,\n disabled: true,\n },\n }\n\n const fields = [...collection.fields, ...(adapter?.fields || [])]\n\n // Inject a hook into all URL fields to generate URLs\n\n let existingURLFieldIndex = -1\n\n const existingURLField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'url') {\n existingURLFieldIndex = i\n return true\n }\n return false\n }) as TextField\n\n if (existingURLFieldIndex > -1) {\n fields.splice(existingURLFieldIndex, 1)\n }\n\n // Only add afterRead hook if adapter is provided\n if (adapter) {\n fields.push({\n ...baseURLField,\n ...(existingURLField || {}),\n hooks: {\n afterRead: [\n getAfterReadHook({ adapter, collection, disablePayloadAccessControl, generateFileURL }),\n ...(existingURLField?.hooks?.afterRead || []),\n ],\n beforeChange: [\n getBeforeChangeHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n }),\n ...(existingURLField?.hooks?.beforeChange || []),\n ],\n },\n } as TextField)\n } else {\n fields.push({\n ...baseURLField,\n ...(existingURLField || {}),\n } as TextField)\n }\n\n let originalField = fields.find(\n (field): field is GroupField =>\n field.type === 'group' && 'name' in field && field.name === 'original',\n )\n\n if (adapter && !originalField) {\n originalField = {\n name: 'original',\n type: 'group',\n fields: [baseURLField],\n }\n fields.push(originalField)\n }\n\n const originalURLFieldIndex = originalField?.fields.findIndex(\n (field) => 'name' in field && field.name === 'url',\n )\n\n if (\n adapter &&\n originalField &&\n originalURLFieldIndex !== undefined &&\n originalURLFieldIndex >= 0\n ) {\n const originalURLField = originalField.fields[originalURLFieldIndex] as TextField\n\n originalField.fields[originalURLFieldIndex] = {\n ...baseURLField,\n ...originalURLField,\n hooks: {\n afterRead: [\n getAfterReadHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n isOriginal: true,\n }),\n ...(originalURLField.hooks?.afterRead || []),\n ],\n beforeChange: [\n getBeforeChangeHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n isOriginal: true,\n }),\n ...(originalURLField.hooks?.beforeChange || []),\n ],\n },\n } as TextField\n }\n\n // Storage adapters add these fields during their `init`, after transformers (e.g. Sharp) have\n // written each collection's image sizes onto its upload config.\n const variants =\n typeof collection.upload === 'object'\n ? (collection.upload as SanitizedUploadConfig).variants\n : undefined\n\n if (variants) {\n let existingSizesFieldIndex = -1\n\n const existingSizesField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'variants') {\n existingSizesFieldIndex = i\n return true\n }\n\n return false\n }) as GroupField\n\n if (existingSizesFieldIndex > -1) {\n fields.splice(existingSizesFieldIndex, 1)\n }\n\n const sizesField: Field = {\n ...(existingSizesField || {}),\n name: 'variants',\n type: 'group',\n admin: {\n hidden: true,\n },\n fields: variants.map((size) => {\n const existingSizeField = existingSizesField?.fields.find(\n (existingField) => 'name' in existingField && existingField.name === size.name,\n ) as GroupField\n\n const existingSizeURLField = existingSizeField?.fields.find(\n (existingField) => 'name' in existingField && existingField.name === 'url',\n ) as TextField\n\n // Only add afterRead hook if adapter is provided\n const sizeURLField: TextField = adapter\n ? ({\n ...(existingSizeURLField || {}),\n ...baseURLField,\n hooks: {\n afterRead: [\n getAfterReadHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n size,\n }),\n ...((typeof existingSizeURLField === 'object' &&\n 'hooks' in existingSizeURLField &&\n existingSizeURLField?.hooks?.afterRead) ||\n []),\n ],\n beforeChange: [\n getBeforeChangeHook({\n adapter,\n collection,\n disablePayloadAccessControl,\n generateFileURL,\n size,\n }),\n ...((typeof existingSizeURLField === 'object' &&\n 'hooks' in existingSizeURLField &&\n existingSizeURLField?.hooks?.beforeChange) ||\n []),\n ],\n },\n } as TextField)\n : ({\n ...(existingSizeURLField || {}),\n ...baseURLField,\n } as TextField)\n\n return {\n ...existingSizeField,\n name: size.name,\n type: 'group',\n fields: [\n ...(adapter?.fields || []).filter(\n (field) => !('name' in field && ['_objectKey', 'prefix'].includes(field.name)),\n ),\n sizeURLField,\n storedPrefixField,\n baseObjectKeyField,\n ],\n } as Field\n }),\n }\n\n fields.push(sizesField)\n }\n\n // Always insert the prefix field so the schema stays consistent regardless of\n // whether the plugin is enabled or a prefix is configured.\n let existingPrefixFieldIndex = -1\n\n const existingPrefixField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'prefix') {\n existingPrefixFieldIndex = i\n return true\n }\n return false\n }) as TextField\n\n if (existingPrefixFieldIndex > -1) {\n fields.splice(existingPrefixFieldIndex, 1)\n }\n\n fields.push({\n ...basePrefixField,\n ...(existingPrefixField || {}),\n defaultValue:\n existingPrefixField?.defaultValue ??\n (useCompositePrefixes ? '' : prefix ? path.posix.join(prefix) : ''),\n hooks: {\n ...existingPrefixField?.hooks,\n beforeChange: [\n ...(existingPrefixField?.hooks?.beforeChange || []),\n getNormalizeUploadPrefixFieldHook({ collectionPrefix: prefix, useCompositePrefixes }),\n ],\n },\n } as TextField)\n\n const existingObjectKeyFieldIndex = fields.findIndex(\n (existingField) => 'name' in existingField && existingField.name === '_objectKey',\n )\n if (existingObjectKeyFieldIndex > -1) {\n fields.splice(existingObjectKeyFieldIndex, 1)\n }\n\n fields.push({ ...baseObjectKeyField } as TextField)\n\n return fields\n}\n"],"names":["path","getAfterReadHook","getBeforeChangeHook","getNormalizeUploadPrefixFieldHook","getFields","adapter","collection","disablePayloadAccessControl","generateFileURL","prefix","useCompositePrefixes","baseURLField","name","type","admin","hidden","readOnly","label","basePrefixField","disabled","bulkEdit","column","filter","groupBy","baseObjectKeyField","storedPrefixField","fields","existingURLFieldIndex","existingURLField","find","existingField","i","splice","push","hooks","afterRead","beforeChange","originalField","field","originalURLFieldIndex","findIndex","undefined","originalURLField","isOriginal","variants","upload","existingSizesFieldIndex","existingSizesField","sizesField","map","size","existingSizeField","existingSizeURLField","sizeURLField","includes","existingPrefixFieldIndex","existingPrefixField","defaultValue","posix","join","collectionPrefix","existingObjectKeyFieldIndex"],"mappings":"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"}
|
|
@@ -3,7 +3,11 @@ import type { GeneratedAdapter } from '../types.js';
|
|
|
3
3
|
interface Args {
|
|
4
4
|
adapter: GeneratedAdapter;
|
|
5
5
|
collection: CollectionConfig;
|
|
6
|
+
collectionPrefix?: string;
|
|
7
|
+
disablePayloadAccessControl?: boolean;
|
|
8
|
+
hasCustomFileURL?: boolean;
|
|
9
|
+
useCompositePrefixes?: boolean;
|
|
6
10
|
}
|
|
7
|
-
export declare const getAfterChangeHook: ({ adapter, collection }: Args) => CollectionAfterChangeHook<FileData & TypeWithID>;
|
|
11
|
+
export declare const getAfterChangeHook: ({ adapter, collection, collectionPrefix, disablePayloadAccessControl, hasCustomFileURL, useCompositePrefixes, }: Args) => CollectionAfterChangeHook<FileData & TypeWithID>;
|
|
8
12
|
export {};
|
|
9
13
|
//# sourceMappingURL=afterChange.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"afterChange.d.ts","sourceRoot":"","sources":["../../src/hooks/afterChange.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"afterChange.d.ts","sourceRoot":"","sources":["../../src/hooks/afterChange.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAIhG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAUnD,UAAU,IAAI;IACZ,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAQD,eAAO,MAAM,kBAAkB,oHAQ1B,IAAI,KAAG,yBAAyB,CAAC,QAAQ,GAAG,UAAU,CA2OxD,CAAA"}
|
|
@@ -1,27 +1,112 @@
|
|
|
1
|
+
import { deepMergeWithSourceArrays } from 'payload';
|
|
2
|
+
import { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js';
|
|
3
|
+
import { buildStoragePathData, buildUploadStoragePathData } from '../utilities/buildStoragePathData.js';
|
|
1
4
|
import { getIncomingFiles } from '../utilities/getIncomingFiles.js';
|
|
2
|
-
|
|
5
|
+
import { appendProxyPrefix } from './afterRead.js';
|
|
6
|
+
// The object's folder: semantic prefix + `_objectKey` segment.
|
|
7
|
+
const getObjectFolder = (data)=>{
|
|
8
|
+
const record = data ?? {};
|
|
9
|
+
return buildPrefixWithObjectKey({
|
|
10
|
+
objectKey: record._objectKey,
|
|
11
|
+
prefix: record.prefix
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
export const getAfterChangeHook = ({ adapter, collection, collectionPrefix, disablePayloadAccessControl, hasCustomFileURL, useCompositePrefixes })=>async ({ data, doc, operation, previousDoc, req, select })=>{
|
|
3
15
|
// Skip if this is an internal update to prevent infinite loop
|
|
4
16
|
if (req.context?.skipCloudStorage) {
|
|
5
17
|
return doc;
|
|
6
18
|
}
|
|
7
|
-
|
|
19
|
+
// Restore upload metadata removed by select, including partially selected image sizes.
|
|
20
|
+
const uploadData = select ? deepMergeWithSourceArrays(data, doc) : doc;
|
|
21
|
+
const withProxyPrefix = (upload)=>{
|
|
22
|
+
const { prefix } = upload;
|
|
23
|
+
if (disablePayloadAccessControl || hasCustomFileURL || !useCompositePrefixes || !prefix) {
|
|
24
|
+
return upload;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
...upload,
|
|
28
|
+
...upload.url && {
|
|
29
|
+
url: appendProxyPrefix({
|
|
30
|
+
prefix,
|
|
31
|
+
url: upload.url
|
|
32
|
+
})
|
|
33
|
+
},
|
|
34
|
+
...upload.original?.url && {
|
|
35
|
+
original: {
|
|
36
|
+
...upload.original,
|
|
37
|
+
url: appendProxyPrefix({
|
|
38
|
+
prefix,
|
|
39
|
+
url: upload.original.url
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const isDraftSave = uploadData._status === 'draft';
|
|
8
46
|
const isDraftOverPublished = isDraftSave && previousDoc?._status === 'published';
|
|
47
|
+
if (req.context?._payloadManagedCloudStorage) {
|
|
48
|
+
const metadata = req.context._payloadManagedCloudMetadata;
|
|
49
|
+
if (!metadata || Object.keys(metadata).length === 0) {
|
|
50
|
+
return withProxyPrefix(doc);
|
|
51
|
+
}
|
|
52
|
+
req.context.skipCloudStorage = true;
|
|
53
|
+
req.file = undefined;
|
|
54
|
+
req.payloadUploadSizes = undefined;
|
|
55
|
+
const originalQuery = req.query;
|
|
56
|
+
req.query = {
|
|
57
|
+
...req.query
|
|
58
|
+
};
|
|
59
|
+
delete req.query.uploadEdits;
|
|
60
|
+
try {
|
|
61
|
+
const updatedDoc = await req.payload.update({
|
|
62
|
+
id: doc.id,
|
|
63
|
+
collection: collection.slug,
|
|
64
|
+
data: metadata,
|
|
65
|
+
depth: 0,
|
|
66
|
+
draft: isDraftSave,
|
|
67
|
+
overrideAccess: true,
|
|
68
|
+
req,
|
|
69
|
+
select
|
|
70
|
+
});
|
|
71
|
+
return withProxyPrefix({
|
|
72
|
+
...doc,
|
|
73
|
+
...updatedDoc
|
|
74
|
+
});
|
|
75
|
+
} finally{
|
|
76
|
+
req.query = originalQuery;
|
|
77
|
+
delete req.context.skipCloudStorage;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
9
80
|
try {
|
|
10
81
|
const files = getIncomingFiles({
|
|
11
|
-
data:
|
|
82
|
+
data: uploadData,
|
|
12
83
|
req
|
|
13
84
|
});
|
|
14
85
|
if (files.length > 0) {
|
|
86
|
+
// Fold `_objectKey` so generated sizes land in the same folder as the original.
|
|
87
|
+
const dataForUpload = {
|
|
88
|
+
...uploadData,
|
|
89
|
+
prefix: getObjectFolder(uploadData)
|
|
90
|
+
};
|
|
15
91
|
const uploadResults = await Promise.all(files.filter((file)=>!file.uploadReference).map((file)=>adapter.handleUpload({
|
|
16
92
|
collection,
|
|
17
|
-
data:
|
|
93
|
+
data: dataForUpload,
|
|
18
94
|
file,
|
|
19
|
-
req
|
|
95
|
+
req,
|
|
96
|
+
storageFilePath: buildUploadStoragePathData({
|
|
97
|
+
collectionPrefix,
|
|
98
|
+
docPrefix: dataForUpload.prefix,
|
|
99
|
+
filename: file.filename,
|
|
100
|
+
useCompositePrefixes
|
|
101
|
+
}).storageFilePath
|
|
20
102
|
})));
|
|
21
103
|
const uploadMetadata = uploadResults.filter((result)=>result != null && typeof result === 'object').reduce((acc, metadata)=>({
|
|
22
104
|
...acc,
|
|
23
105
|
...metadata
|
|
24
106
|
}), {});
|
|
107
|
+
// Adapters may echo `data` back as metadata; keep the document's own `prefix`/`_objectKey`.
|
|
108
|
+
delete uploadMetadata.prefix;
|
|
109
|
+
delete uploadMetadata._objectKey;
|
|
25
110
|
let docWithMetadata = doc;
|
|
26
111
|
if (Object.keys(uploadMetadata).length > 0) {
|
|
27
112
|
if (!req.context) {
|
|
@@ -32,55 +117,84 @@ export const getAfterChangeHook = ({ adapter, collection })=>async ({ doc, opera
|
|
|
32
117
|
req.file = undefined;
|
|
33
118
|
req.payloadUploadSizes = undefined;
|
|
34
119
|
try {
|
|
35
|
-
await req.payload.update({
|
|
120
|
+
const updatedDoc = await req.payload.update({
|
|
36
121
|
id: doc.id,
|
|
37
122
|
collection: collection.slug,
|
|
38
123
|
data: uploadMetadata,
|
|
39
124
|
depth: 0,
|
|
40
125
|
draft: isDraftSave,
|
|
41
|
-
|
|
126
|
+
overrideAccess: true,
|
|
127
|
+
req,
|
|
128
|
+
select
|
|
42
129
|
});
|
|
130
|
+
// Persist all adapter metadata, but do not add unselected fields to the response.
|
|
131
|
+
docWithMetadata = select ? {
|
|
132
|
+
...doc,
|
|
133
|
+
...updatedDoc
|
|
134
|
+
} : {
|
|
135
|
+
...doc,
|
|
136
|
+
...uploadMetadata
|
|
137
|
+
};
|
|
43
138
|
} finally{
|
|
44
139
|
delete req.context.skipCloudStorage;
|
|
45
140
|
}
|
|
46
|
-
docWithMetadata = {
|
|
47
|
-
...doc,
|
|
48
|
-
...uploadMetadata
|
|
49
|
-
};
|
|
50
141
|
}
|
|
51
142
|
// Delete previous files only after the new upload and metadata
|
|
52
143
|
// persistence have succeeded. Deleting earlier would orphan the
|
|
53
144
|
// record if a later step throws (e.g. a user-defined afterChange
|
|
54
145
|
// hook on the same collection).
|
|
55
|
-
if (previousDoc && operation === 'update' && !isDraftOverPublished) {
|
|
146
|
+
if (previousDoc && operation === 'update' && !isDraftOverPublished && !collection.versions && !previousDoc.original) {
|
|
56
147
|
let filesToDelete = [];
|
|
57
148
|
if (typeof previousDoc?.filename === 'string') {
|
|
58
149
|
filesToDelete.push(previousDoc.filename);
|
|
59
150
|
}
|
|
60
|
-
if (typeof previousDoc.
|
|
61
|
-
filesToDelete = filesToDelete.concat(Object.values(previousDoc?.
|
|
151
|
+
if (typeof previousDoc.variants === 'object') {
|
|
152
|
+
filesToDelete = filesToDelete.concat(Object.values(previousDoc?.variants || []).map((resizedFileData)=>resizedFileData?.filename));
|
|
62
153
|
}
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
|
|
154
|
+
// Compare full locations: a replacement can reuse a filename while moving
|
|
155
|
+
// a legacy object beneath the collection prefix.
|
|
156
|
+
const newFileData = {
|
|
157
|
+
...uploadData,
|
|
158
|
+
...uploadMetadata
|
|
159
|
+
};
|
|
66
160
|
const newFilenames = new Set();
|
|
67
|
-
if (typeof
|
|
68
|
-
newFilenames.add(
|
|
161
|
+
if (typeof newFileData.filename === 'string') {
|
|
162
|
+
newFilenames.add(newFileData.filename);
|
|
69
163
|
}
|
|
70
|
-
if (typeof
|
|
71
|
-
for (const size of Object.values(
|
|
164
|
+
if (typeof newFileData.variants === 'object') {
|
|
165
|
+
for (const size of Object.values(newFileData.variants || {})){
|
|
72
166
|
if (size?.filename && typeof size.filename === 'string') {
|
|
73
167
|
newFilenames.add(size.filename);
|
|
74
168
|
}
|
|
75
169
|
}
|
|
76
170
|
}
|
|
171
|
+
const resolveKey = ({ data, filename })=>buildStoragePathData({
|
|
172
|
+
collectionPrefix,
|
|
173
|
+
docPrefix: getObjectFolder(data),
|
|
174
|
+
filename,
|
|
175
|
+
useCompositePrefixes
|
|
176
|
+
}).storageFilePath;
|
|
177
|
+
const newKeys = new Set([
|
|
178
|
+
...newFilenames
|
|
179
|
+
].map((filename)=>resolveKey({
|
|
180
|
+
data: newFileData,
|
|
181
|
+
filename
|
|
182
|
+
})));
|
|
77
183
|
const deletionPromises = filesToDelete.map(async (filename)=>{
|
|
78
|
-
if (
|
|
184
|
+
if (!filename) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const storageFilePath = resolveKey({
|
|
188
|
+
data: previousDoc,
|
|
189
|
+
filename
|
|
190
|
+
});
|
|
191
|
+
if (!newKeys.has(storageFilePath)) {
|
|
79
192
|
await adapter.handleDelete({
|
|
80
193
|
collection,
|
|
81
194
|
doc: previousDoc,
|
|
82
195
|
filename,
|
|
83
|
-
req
|
|
196
|
+
req,
|
|
197
|
+
storageFilePath
|
|
84
198
|
});
|
|
85
199
|
}
|
|
86
200
|
});
|