@payloadcms/plugin-cloud-storage 3.89.0 → 3.90.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.
- 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 +3 -2
- package/dist/exports/utilities.d.ts.map +1 -1
- package/dist/exports/utilities.js +3 -2
- package/dist/exports/utilities.js.map +1 -1
- package/dist/fields/getFields.d.ts.map +1 -1
- package/dist/fields/getFields.js +28 -1
- package/dist/fields/getFields.js.map +1 -1
- package/dist/hooks/afterChange.d.ts +3 -1
- package/dist/hooks/afterChange.d.ts.map +1 -1
- package/dist/hooks/afterChange.js +56 -9
- package/dist/hooks/afterChange.js.map +1 -1
- package/dist/hooks/afterChange.spec.js +150 -0
- package/dist/hooks/afterChange.spec.js.map +1 -0
- package/dist/hooks/afterDelete.d.ts +3 -1
- package/dist/hooks/afterDelete.d.ts.map +1 -1
- package/dist/hooks/afterDelete.js +16 -2
- package/dist/hooks/afterDelete.js.map +1 -1
- package/dist/hooks/afterRead.d.ts.map +1 -1
- package/dist/hooks/afterRead.js +13 -2
- package/dist/hooks/afterRead.js.map +1 -1
- package/dist/hooks/beforeChange.d.ts.map +1 -1
- package/dist/hooks/beforeChange.js +10 -1
- 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/normalizeUploadPrefix.spec.js +154 -0
- package/dist/hooks/normalizeUploadPrefix.spec.js.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +15 -6
- package/dist/plugin.js.map +1 -1
- package/dist/plugin.spec.js +166 -0
- package/dist/plugin.spec.js.map +1 -0
- package/dist/types.d.ts +23 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities/assertReceiptMatchesFileKey.d.ts +15 -0
- package/dist/utilities/assertReceiptMatchesFileKey.d.ts.map +1 -0
- package/dist/utilities/assertReceiptMatchesFileKey.js +31 -0
- package/dist/utilities/assertReceiptMatchesFileKey.js.map +1 -0
- 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 +55 -0
- package/dist/utilities/buildStoragePathData.d.ts.map +1 -0
- package/dist/utilities/buildStoragePathData.js +69 -0
- package/dist/utilities/buildStoragePathData.js.map +1 -0
- package/dist/utilities/{getFileKey.spec.js → buildStoragePathData.spec.js} +116 -36
- package/dist/utilities/buildStoragePathData.spec.js.map +1 -0
- package/dist/utilities/getFilePrefix.d.ts +27 -11
- package/dist/utilities/getFilePrefix.d.ts.map +1 -1
- package/dist/utilities/getFilePrefix.js +75 -31
- package/dist/utilities/getFilePrefix.js.map +1 -1
- package/dist/utilities/getFilePrefix.spec.js +221 -35
- package/dist/utilities/getFilePrefix.spec.js.map +1 -1
- package/dist/utilities/resolveSignedURLKey.d.ts +11 -0
- package/dist/utilities/resolveSignedURLKey.d.ts.map +1 -1
- package/dist/utilities/resolveSignedURLKey.js +43 -8
- package/dist/utilities/resolveSignedURLKey.js.map +1 -1
- package/dist/utilities/resolveSignedURLKey.spec.js +56 -0
- package/dist/utilities/resolveSignedURLKey.spec.js.map +1 -0
- package/dist/utilities/sanitizePrefix.d.ts +2 -2
- package/dist/utilities/sanitizePrefix.js +4 -4
- package/dist/utilities/sanitizePrefix.js.map +1 -1
- package/dist/utilities/verifyClientUploadReceiptForFileKey.d.ts +20 -0
- package/dist/utilities/verifyClientUploadReceiptForFileKey.d.ts.map +1 -0
- package/dist/utilities/verifyClientUploadReceiptForFileKey.js +24 -0
- package/dist/utilities/verifyClientUploadReceiptForFileKey.js.map +1 -0
- package/dist/utilities/verifyClientUploadReceiptForFileKey.spec.js +108 -0
- package/dist/utilities/verifyClientUploadReceiptForFileKey.spec.js.map +1 -0
- package/package.json +4 -4
- 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.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 { getFileKey } from '../utilities/
|
|
2
|
+
export { buildStoragePathData, buildStoragePathData as getFileKey, 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,oBAAoB,IAAI,UAAU,EAClC,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 { getFileKey } from '../utilities/
|
|
2
|
+
export { buildStoragePathData, buildStoragePathData as getFileKey, 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 { getFileKey
|
|
1
|
+
{"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["export { createClientUploadHandler } from '../client/createClientUploadHandler.js'\nexport {\n buildStoragePathData,\n buildStoragePathData as getFileKey,\n buildUploadStoragePathData,\n} from '../utilities/buildStoragePathData.js'\nexport { sanitizePrefix } from '../utilities/sanitizePrefix.js'\n"],"names":["createClientUploadHandler","buildStoragePathData","getFileKey","buildUploadStoragePathData","sanitizePrefix"],"mappings":"AAAA,SAASA,yBAAyB,QAAQ,yCAAwC;AAClF,SACEC,oBAAoB,EACpBA,wBAAwBC,UAAU,EAClCC,0BAA0B,QACrB,uCAAsC;AAC7C,SAASC,cAAc,QAAQ,iCAAgC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export { getFileKey } from '../utilities/
|
|
2
|
-
export { getFilePrefix } from '../utilities/getFilePrefix.js';
|
|
1
|
+
export { buildStoragePathData as getFileKey, buildStoragePathData, buildUploadStoragePathData, isStoragePathWithinCollectionPrefix, } from '../utilities/buildStoragePathData.js';
|
|
2
|
+
export { getFilePrefix, getStorageFilePath } from '../utilities/getFilePrefix.js';
|
|
3
3
|
export { initClientUploads } from '../utilities/initClientUploads.js';
|
|
4
4
|
export { resolveSignedURLKey } from '../utilities/resolveSignedURLKey.js';
|
|
5
5
|
export { sanitizePrefix } from '../utilities/sanitizePrefix.js';
|
|
6
|
+
export { verifyClientUploadReceiptForFileKey } from '../utilities/verifyClientUploadReceiptForFileKey.js';
|
|
6
7
|
//# sourceMappingURL=utilities.d.ts.map
|
|
@@ -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,IAAI,UAAU,EAClC,oBAAoB,EACpB,0BAA0B,EAC1B,mCAAmC,GACpC,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAA;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAA;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,EAAE,mCAAmC,EAAE,MAAM,qDAAqD,CAAA"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export { getFileKey } from '../utilities/
|
|
2
|
-
export { getFilePrefix } from '../utilities/getFilePrefix.js';
|
|
1
|
+
export { buildStoragePathData as getFileKey, buildStoragePathData, buildUploadStoragePathData, isStoragePathWithinCollectionPrefix } from '../utilities/buildStoragePathData.js';
|
|
2
|
+
export { getFilePrefix, getStorageFilePath } from '../utilities/getFilePrefix.js';
|
|
3
3
|
export { initClientUploads } from '../utilities/initClientUploads.js';
|
|
4
4
|
export { resolveSignedURLKey } from '../utilities/resolveSignedURLKey.js';
|
|
5
5
|
export { sanitizePrefix } from '../utilities/sanitizePrefix.js';
|
|
6
|
+
export { verifyClientUploadReceiptForFileKey } from '../utilities/verifyClientUploadReceiptForFileKey.js';
|
|
6
7
|
|
|
7
8
|
//# sourceMappingURL=utilities.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/exports/utilities.ts"],"sourcesContent":["export { getFileKey
|
|
1
|
+
{"version":3,"sources":["../../src/exports/utilities.ts"],"sourcesContent":["export {\n buildStoragePathData as getFileKey,\n buildStoragePathData,\n buildUploadStoragePathData,\n isStoragePathWithinCollectionPrefix,\n} from '../utilities/buildStoragePathData.js'\nexport { getFilePrefix, getStorageFilePath } from '../utilities/getFilePrefix.js'\nexport { initClientUploads } from '../utilities/initClientUploads.js'\nexport { resolveSignedURLKey } from '../utilities/resolveSignedURLKey.js'\nexport { sanitizePrefix } from '../utilities/sanitizePrefix.js'\nexport { verifyClientUploadReceiptForFileKey } from '../utilities/verifyClientUploadReceiptForFileKey.js'\n"],"names":["buildStoragePathData","getFileKey","buildUploadStoragePathData","isStoragePathWithinCollectionPrefix","getFilePrefix","getStorageFilePath","initClientUploads","resolveSignedURLKey","sanitizePrefix","verifyClientUploadReceiptForFileKey"],"mappings":"AAAA,SACEA,wBAAwBC,UAAU,EAClCD,oBAAoB,EACpBE,0BAA0B,EAC1BC,mCAAmC,QAC9B,uCAAsC;AAC7C,SAASC,aAAa,EAAEC,kBAAkB,QAAQ,gCAA+B;AACjF,SAASC,iBAAiB,QAAQ,oCAAmC;AACrE,SAASC,mBAAmB,QAAQ,sCAAqC;AACzE,SAASC,cAAc,QAAQ,iCAAgC;AAC/D,SAASC,mCAAmC,QAAQ,sDAAqD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getFields.d.ts","sourceRoot":"","sources":["../../src/fields/getFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAyB,MAAM,SAAS,CAAA;AAI7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"getFields.d.ts","sourceRoot":"","sources":["../../src/fields/getFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAyB,MAAM,SAAS,CAAA;AAI7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAMpE,UAAU,IAAI;IACZ,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAC1B;;OAEG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,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,6HAQnB,IAAI,KAAG,KAAK,EAyMd,CAAA"}
|
package/dist/fields/getFields.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { getAfterReadHook } from '../hooks/afterRead.js';
|
|
3
3
|
import { getBeforeChangeHook } from '../hooks/beforeChange.js';
|
|
4
|
+
import { getNormalizeUploadPrefixFieldHook } from '../hooks/normalizeUploadPrefix.js';
|
|
4
5
|
export const getFields = ({ adapter, alwaysInsertFields, collection, disablePayloadAccessControl, generateFileURL, prefix, useCompositePrefixes = false })=>{
|
|
5
6
|
const baseURLField = {
|
|
6
7
|
name: 'url',
|
|
@@ -19,6 +20,15 @@ export const getFields = ({ adapter, alwaysInsertFields, collection, disablePayl
|
|
|
19
20
|
readOnly: true
|
|
20
21
|
}
|
|
21
22
|
};
|
|
23
|
+
// Unique storage object key
|
|
24
|
+
const baseObjectKeyField = {
|
|
25
|
+
name: '_objectKey',
|
|
26
|
+
type: 'text',
|
|
27
|
+
admin: {
|
|
28
|
+
hidden: true,
|
|
29
|
+
readOnly: true
|
|
30
|
+
}
|
|
31
|
+
};
|
|
22
32
|
const fields = [
|
|
23
33
|
...collection.fields,
|
|
24
34
|
...adapter?.fields || []
|
|
@@ -148,9 +158,26 @@ export const getFields = ({ adapter, alwaysInsertFields, collection, disablePayl
|
|
|
148
158
|
fields.push({
|
|
149
159
|
...basePrefixField,
|
|
150
160
|
...existingPrefixField || {},
|
|
151
|
-
defaultValue: existingPrefixField?.defaultValue ?? (useCompositePrefixes ? '' : prefix ? path.posix.join(prefix) : '')
|
|
161
|
+
defaultValue: existingPrefixField?.defaultValue ?? (useCompositePrefixes ? '' : prefix ? path.posix.join(prefix) : ''),
|
|
162
|
+
hooks: {
|
|
163
|
+
...existingPrefixField?.hooks,
|
|
164
|
+
beforeChange: [
|
|
165
|
+
...existingPrefixField?.hooks?.beforeChange || [],
|
|
166
|
+
getNormalizeUploadPrefixFieldHook({
|
|
167
|
+
collectionPrefix: prefix,
|
|
168
|
+
useCompositePrefixes
|
|
169
|
+
})
|
|
170
|
+
]
|
|
171
|
+
}
|
|
152
172
|
});
|
|
153
173
|
}
|
|
174
|
+
const existingObjectKeyFieldIndex = fields.findIndex((existingField)=>'name' in existingField && existingField.name === '_objectKey');
|
|
175
|
+
if (existingObjectKeyFieldIndex > -1) {
|
|
176
|
+
fields.splice(existingObjectKeyFieldIndex, 1);
|
|
177
|
+
}
|
|
178
|
+
fields.push({
|
|
179
|
+
...baseObjectKeyField
|
|
180
|
+
});
|
|
154
181
|
return fields;
|
|
155
182
|
};
|
|
156
183
|
|
|
@@ -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, 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 /**\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 // Unique storage object key\n const baseObjectKeyField: TextField = {\n name: '_objectKey',\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 hooks: {\n ...existingPrefixField?.hooks,\n beforeChange: [\n ...(existingPrefixField?.hooks?.beforeChange || []),\n getNormalizeUploadPrefixFieldHook({ collectionPrefix: prefix, useCompositePrefixes }),\n ],\n },\n } as TextField)\n }\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","alwaysInsertFields","collection","disablePayloadAccessControl","generateFileURL","prefix","useCompositePrefixes","baseURLField","name","type","admin","hidden","readOnly","label","basePrefixField","baseObjectKeyField","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","collectionPrefix","existingObjectKeyFieldIndex","findIndex"],"mappings":"AAEA,OAAOA,UAAU,OAAM;AAIvB,SAASC,gBAAgB,QAAQ,wBAAuB;AACxD,SAASC,mBAAmB,QAAQ,2BAA0B;AAC9D,SAASC,iCAAiC,QAAQ,oCAAmC;AAmBrF,OAAO,MAAMC,YAAY,CAAC,EACxBC,OAAO,EACPC,kBAAkB,EAClBC,UAAU,EACVC,2BAA2B,EAC3BC,eAAe,EACfC,MAAM,EACNC,uBAAuB,KAAK,EACvB;IACL,MAAMC,eAA0B;QAC9BC,MAAM;QACNC,MAAM;QACNC,OAAO;YACLC,QAAQ;YACRC,UAAU;QACZ;QACAC,OAAO;IACT;IAEA,MAAMC,kBAA6B;QACjCN,MAAM;QACNC,MAAM;QACNC,OAAO;YACLC,QAAQ;YACRC,UAAU;QACZ;IACF;IAEA,4BAA4B;IAC5B,MAAMG,qBAAgC;QACpCP,MAAM;QACNC,MAAM;QACNC,OAAO;YACLC,QAAQ;YACRC,UAAU;QACZ;IACF;IAEA,MAAMI,SAAS;WAAId,WAAWc,MAAM;WAAMhB,SAASgB,UAAU,EAAE;KAAE;IAEjE,qDAAqD;IAErD,IAAIC,wBAAwB,CAAC;IAE7B,MAAMC,mBAAmBF,OAAOG,IAAI,CAAC,CAACC,eAAeC;QACnD,IAAI,UAAUD,iBAAiBA,cAAcZ,IAAI,KAAK,OAAO;YAC3DS,wBAAwBI;YACxB,OAAO;QACT;QACA,OAAO;IACT;IAEA,IAAIJ,wBAAwB,CAAC,GAAG;QAC9BD,OAAOM,MAAM,CAACL,uBAAuB;IACvC;IAEA,iDAAiD;IACjD,IAAIjB,SAAS;QACXgB,OAAOO,IAAI,CAAC;YACV,GAAGhB,YAAY;YACf,GAAIW,oBAAoB,CAAC,CAAC;YAC1BM,OAAO;gBACLC,WAAW;oBACT7B,iBAAiB;wBAAEI;wBAASE;wBAAYC;wBAA6BC;oBAAgB;uBACjFc,kBAAkBM,OAAOC,aAAa,EAAE;iBAC7C;gBACDC,cAAc;oBACZ7B,oBAAoB;wBAClBG;wBACAE;wBACAC;wBACAC;oBACF;uBACIc,kBAAkBM,OAAOE,gBAAgB,EAAE;iBAChD;YACH;QACF;IACF,OAAO;QACLV,OAAOO,IAAI,CAAC;YACV,GAAGhB,YAAY;YACf,GAAIW,oBAAoB,CAAC,CAAC;QAC5B;IACF;IAEA,IAAI,OAAOhB,WAAWyB,MAAM,KAAK,YAAYzB,WAAWyB,MAAM,CAACC,UAAU,EAAE;QACzE,IAAIC,0BAA0B,CAAC;QAE/B,MAAMC,qBAAqBd,OAAOG,IAAI,CAAC,CAACC,eAAeC;YACrD,IAAI,UAAUD,iBAAiBA,cAAcZ,IAAI,KAAK,SAAS;gBAC7DqB,0BAA0BR;gBAC1B,OAAO;YACT;YAEA,OAAO;QACT;QAEA,IAAIQ,0BAA0B,CAAC,GAAG;YAChCb,OAAOM,MAAM,CAACO,yBAAyB;QACzC;QAEA,MAAME,aAAoB;YACxB,GAAID,sBAAsB,CAAC,CAAC;YAC5BtB,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,QAAQ;YACV;YACAK,QAAQd,WAAWyB,MAAM,CAACC,UAAU,CAACI,GAAG,CAAC,CAACC;gBACxC,MAAMC,oBAAoBJ,oBAAoBd,OAAOG,KACnD,CAACC,gBAAkB,UAAUA,iBAAiBA,cAAcZ,IAAI,KAAKyB,KAAKzB,IAAI;gBAGhF,MAAM2B,uBAAuBD,mBAAmBlB,OAAOG,KACrD,CAACC,gBAAkB,UAAUA,iBAAiBA,cAAcZ,IAAI,KAAK;gBAGvE,iDAAiD;gBACjD,MAAM4B,eAA0BpC,UAC3B;oBACC,GAAImC,wBAAwB,CAAC,CAAC;oBAC9B,GAAG5B,YAAY;oBACfiB,OAAO;wBACLC,WAAW;4BACT7B,iBAAiB;gCACfI;gCACAE;gCACAC;gCACAC;gCACA6B;4BACF;+BACI,AAAC,OAAOE,yBAAyB,YACnC,WAAWA,wBACXA,sBAAsBX,OAAOC,aAC7B,EAAE;yBACL;wBACDC,cAAc;4BACZ7B,oBAAoB;gCAClBG;gCACAE;gCACAC;gCACAC;gCACA6B;4BACF;+BACI,AAAC,OAAOE,yBAAyB,YACnC,WAAWA,wBACXA,sBAAsBX,OAAOE,gBAC7B,EAAE;yBACL;oBACH;gBACF,IACC;oBACC,GAAIS,wBAAwB,CAAC,CAAC;oBAC9B,GAAG5B,YAAY;gBACjB;gBAEJ,OAAO;oBACL,GAAG2B,iBAAiB;oBACpB1B,MAAMyB,KAAKzB,IAAI;oBACfC,MAAM;oBACNO,QAAQ;2BAAKhB,SAASgB,UAAU,EAAE;wBAAGoB;qBAAa;gBACpD;YACF;QACF;QAEApB,OAAOO,IAAI,CAACQ;IACd;IAEA,oEAAoE;IACpE,IAAI,OAAO1B,WAAW,eAAeJ,oBAAoB;QACvD,IAAIoC,2BAA2B,CAAC;QAEhC,MAAMC,sBAAsBtB,OAAOG,IAAI,CAAC,CAACC,eAAeC;YACtD,IAAI,UAAUD,iBAAiBA,cAAcZ,IAAI,KAAK,UAAU;gBAC9D6B,2BAA2BhB;gBAC3B,OAAO;YACT;YACA,OAAO;QACT;QAEA,IAAIgB,2BAA2B,CAAC,GAAG;YACjCrB,OAAOM,MAAM,CAACe,0BAA0B;QAC1C;QAEArB,OAAOO,IAAI,CAAC;YACV,GAAGT,eAAe;YAClB,GAAIwB,uBAAuB,CAAC,CAAC;YAC7BC,cACED,qBAAqBC,gBACpBjC,CAAAA,uBAAuB,KAAKD,SAASV,KAAK6C,KAAK,CAACC,IAAI,CAACpC,UAAU,EAAC;YACnEmB,OAAO;gBACL,GAAGc,qBAAqBd,KAAK;gBAC7BE,cAAc;uBACRY,qBAAqBd,OAAOE,gBAAgB,EAAE;oBAClD5B,kCAAkC;wBAAE4C,kBAAkBrC;wBAAQC;oBAAqB;iBACpF;YACH;QACF;IACF;IAEA,MAAMqC,8BAA8B3B,OAAO4B,SAAS,CAClD,CAACxB,gBAAkB,UAAUA,iBAAiBA,cAAcZ,IAAI,KAAK;IAEvE,IAAImC,8BAA8B,CAAC,GAAG;QACpC3B,OAAOM,MAAM,CAACqB,6BAA6B;IAC7C;IAEA3B,OAAOO,IAAI,CAAC;QAAE,GAAGR,kBAAkB;IAAC;IAEpC,OAAOC;AACT,EAAC"}
|
|
@@ -3,7 +3,9 @@ import type { GeneratedAdapter } from '../types.js';
|
|
|
3
3
|
interface Args {
|
|
4
4
|
adapter: GeneratedAdapter;
|
|
5
5
|
collection: CollectionConfig;
|
|
6
|
+
collectionPrefix?: string;
|
|
7
|
+
useCompositePrefixes?: boolean;
|
|
6
8
|
}
|
|
7
|
-
export declare const getAfterChangeHook: ({ adapter, collection }: Args) => CollectionAfterChangeHook<FileData & TypeWithID>;
|
|
9
|
+
export declare const getAfterChangeHook: ({ adapter, collection, collectionPrefix, useCompositePrefixes, }: Args) => CollectionAfterChangeHook<FileData & TypeWithID>;
|
|
8
10
|
export {};
|
|
9
11
|
//# 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;AAEhG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,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;AAEhG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AASnD,UAAU,IAAI;IACZ,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAQD,eAAO,MAAM,kBAAkB,qEAM1B,IAAI,KAAG,yBAAyB,CAAC,QAAQ,GAAG,UAAU,CA8KxD,CAAA"}
|
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
import { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js';
|
|
2
|
+
import { buildStoragePathData, buildUploadStoragePathData } from '../utilities/buildStoragePathData.js';
|
|
1
3
|
import { getIncomingFiles } from '../utilities/getIncomingFiles.js';
|
|
2
|
-
|
|
4
|
+
// The object's folder: semantic prefix + `_objectKey` segment.
|
|
5
|
+
const getObjectFolder = (doc)=>{
|
|
6
|
+
const record = doc ?? {};
|
|
7
|
+
return buildPrefixWithObjectKey({
|
|
8
|
+
objectKey: record._objectKey,
|
|
9
|
+
prefix: record.prefix
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
export const getAfterChangeHook = ({ adapter, collection, collectionPrefix, useCompositePrefixes })=>async ({ doc, operation, previousDoc, req })=>{
|
|
3
13
|
// Skip if this is an internal update to prevent infinite loop
|
|
4
14
|
if (req.context?.skipCloudStorage) {
|
|
5
15
|
return doc;
|
|
@@ -12,17 +22,33 @@ export const getAfterChangeHook = ({ adapter, collection })=>async ({ doc, opera
|
|
|
12
22
|
req
|
|
13
23
|
});
|
|
14
24
|
if (files.length > 0) {
|
|
15
|
-
|
|
25
|
+
// Fold `_objectKey` so generated sizes land in the same folder as the original.
|
|
26
|
+
const dataForUpload = {
|
|
27
|
+
...doc,
|
|
28
|
+
prefix: getObjectFolder(doc)
|
|
29
|
+
};
|
|
30
|
+
const uploadResults = await Promise.all(files// Files with a clientUploadContext are already in storage (uploaded
|
|
31
|
+
// directly by the browser), so skip re-uploading them here.
|
|
32
|
+
.filter((file)=>!file.clientUploadContext).map((file)=>adapter.handleUpload({
|
|
16
33
|
clientUploadContext: file.clientUploadContext,
|
|
17
34
|
collection,
|
|
18
|
-
data:
|
|
35
|
+
data: dataForUpload,
|
|
19
36
|
file,
|
|
20
|
-
req
|
|
37
|
+
req,
|
|
38
|
+
storageFilePath: buildUploadStoragePathData({
|
|
39
|
+
collectionPrefix,
|
|
40
|
+
docPrefix: dataForUpload.prefix,
|
|
41
|
+
filename: file.filename,
|
|
42
|
+
useCompositePrefixes
|
|
43
|
+
}).storageFilePath
|
|
21
44
|
})));
|
|
22
45
|
const uploadMetadata = uploadResults.filter((result)=>result != null && typeof result === 'object').reduce((acc, metadata)=>({
|
|
23
46
|
...acc,
|
|
24
47
|
...metadata
|
|
25
48
|
}), {});
|
|
49
|
+
// Adapters may echo `data` back as metadata; keep the document's own `prefix`/`_objectKey`.
|
|
50
|
+
delete uploadMetadata.prefix;
|
|
51
|
+
delete uploadMetadata._objectKey;
|
|
26
52
|
let docWithMetadata = doc;
|
|
27
53
|
if (Object.keys(uploadMetadata).length > 0) {
|
|
28
54
|
if (!req.context) {
|
|
@@ -61,9 +87,8 @@ export const getAfterChangeHook = ({ adapter, collection })=>async ({ doc, opera
|
|
|
61
87
|
if (typeof previousDoc.sizes === 'object') {
|
|
62
88
|
filesToDelete = filesToDelete.concat(Object.values(previousDoc?.sizes || []).map((resizedFileData)=>resizedFileData?.filename));
|
|
63
89
|
}
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
// where Payload overwrites in place).
|
|
90
|
+
// Compare full locations: a replacement can reuse a filename while moving
|
|
91
|
+
// a legacy object beneath the collection prefix.
|
|
67
92
|
const newFilenames = new Set();
|
|
68
93
|
if (typeof docWithMetadata.filename === 'string') {
|
|
69
94
|
newFilenames.add(docWithMetadata.filename);
|
|
@@ -75,13 +100,35 @@ export const getAfterChangeHook = ({ adapter, collection })=>async ({ doc, opera
|
|
|
75
100
|
}
|
|
76
101
|
}
|
|
77
102
|
}
|
|
103
|
+
// Resolve each object's real location, folding `_objectKey` so a client-uploaded
|
|
104
|
+
// original is compared and deleted at `prefix/_objectKey/filename`.
|
|
105
|
+
const resolveKey = ({ data, filename })=>buildStoragePathData({
|
|
106
|
+
collectionPrefix,
|
|
107
|
+
docPrefix: getObjectFolder(data),
|
|
108
|
+
filename,
|
|
109
|
+
useCompositePrefixes
|
|
110
|
+
}).storageFilePath;
|
|
111
|
+
const newKeys = new Set([
|
|
112
|
+
...newFilenames
|
|
113
|
+
].map((filename)=>resolveKey({
|
|
114
|
+
data: docWithMetadata,
|
|
115
|
+
filename
|
|
116
|
+
})));
|
|
78
117
|
const deletionPromises = filesToDelete.map(async (filename)=>{
|
|
79
|
-
if (
|
|
118
|
+
if (!filename) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const storageFilePath = resolveKey({
|
|
122
|
+
data: previousDoc,
|
|
123
|
+
filename
|
|
124
|
+
});
|
|
125
|
+
if (!newKeys.has(storageFilePath)) {
|
|
80
126
|
await adapter.handleDelete({
|
|
81
127
|
collection,
|
|
82
128
|
doc: previousDoc,
|
|
83
129
|
filename,
|
|
84
|
-
req
|
|
130
|
+
req,
|
|
131
|
+
storageFilePath
|
|
85
132
|
});
|
|
86
133
|
}
|
|
87
134
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/afterChange.ts"],"sourcesContent":["import type { CollectionAfterChangeHook, CollectionConfig, FileData, TypeWithID } from 'payload'\n\nimport type { GeneratedAdapter } from '../types.js'\n\nimport { getIncomingFiles } from '../utilities/getIncomingFiles.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n}\n\nexport const getAfterChangeHook =\n ({ adapter, collection }: Args): CollectionAfterChangeHook<FileData & TypeWithID> =>\n async ({ doc, operation, previousDoc, req }) => {\n // Skip if this is an internal update to prevent infinite loop\n if (req.context?.skipCloudStorage) {\n return doc\n }\n\n const isDraftSave = (doc as { _status?: string })._status === 'draft'\n const isDraftOverPublished =\n isDraftSave && (previousDoc as { _status?: string } | undefined)?._status === 'published'\n\n try {\n const files = getIncomingFiles({ data: doc, req })\n\n if (files.length > 0) {\n const uploadResults = await Promise.all(\n files\n .filter((file) => !file.clientUploadContext)\n .map((file) =>\n adapter.handleUpload({\n clientUploadContext: file.clientUploadContext,\n collection,\n data: doc,\n file,\n req,\n }),\n ),\n )\n\n const uploadMetadata = uploadResults\n .filter(\n (result): result is Partial<FileData & TypeWithID> =>\n result != null && typeof result === 'object',\n )\n .reduce(\n (acc, metadata) => ({ ...acc, ...metadata }),\n {} as Partial<FileData & TypeWithID>,\n )\n\n let docWithMetadata = doc\n\n if (Object.keys(uploadMetadata).length > 0) {\n if (!req.context) {\n req.context = {}\n }\n req.context.skipCloudStorage = true\n\n // Clear to prevent re-processing\n req.file = undefined\n req.payloadUploadSizes = undefined\n\n try {\n await req.payload.update({\n id: doc.id,\n collection: collection.slug,\n data: uploadMetadata,\n depth: 0,\n draft: isDraftSave,\n req,\n })\n } finally {\n delete req.context.skipCloudStorage\n }\n\n docWithMetadata = { ...doc, ...uploadMetadata }\n }\n\n // Delete previous files only after the new upload and metadata\n // persistence have succeeded. Deleting earlier would orphan the\n // record if a later step throws (e.g. a user-defined afterChange\n // hook on the same collection).\n if (previousDoc && operation === 'update' && !isDraftOverPublished) {\n let filesToDelete: string[] = []\n\n if (typeof previousDoc?.filename === 'string') {\n filesToDelete.push(previousDoc.filename)\n }\n\n if (typeof previousDoc.sizes === 'object') {\n filesToDelete = filesToDelete.concat(\n Object.values(previousDoc?.sizes || []).map(\n (resizedFileData) => resizedFileData?.filename as string,\n ),\n )\n }\n\n // Collect new filenames (main + sizes) so we don't delete a\n // file that the new upload reused (e.g. same filename on reupload\n // where Payload overwrites in place).\n const newFilenames = new Set<string>()\n if (typeof docWithMetadata.filename === 'string') {\n newFilenames.add(docWithMetadata.filename)\n }\n if (typeof docWithMetadata.sizes === 'object') {\n for (const size of Object.values(docWithMetadata.sizes || {})) {\n if (size?.filename && typeof size.filename === 'string') {\n newFilenames.add(size.filename)\n }\n }\n }\n\n const deletionPromises = filesToDelete.map(async (filename) => {\n if (filename && !newFilenames.has(filename)) {\n await adapter.handleDelete({ collection, doc: previousDoc, filename, req })\n }\n })\n\n await Promise.all(deletionPromises)\n }\n\n if (docWithMetadata !== doc) {\n return docWithMetadata\n }\n }\n } catch (err: unknown) {\n req.payload.logger.error(\n `There was an error while uploading files corresponding to the collection ${collection.slug} with filename ${doc.filename}:`,\n )\n req.payload.logger.error({ err })\n throw err\n }\n return doc\n }\n"],"names":["getIncomingFiles","getAfterChangeHook","adapter","collection","doc","operation","previousDoc","req","context","skipCloudStorage","isDraftSave","_status","isDraftOverPublished","files","data","length","uploadResults","Promise","all","filter","file","clientUploadContext","map","handleUpload","uploadMetadata","result","reduce","acc","metadata","docWithMetadata","Object","keys","undefined","payloadUploadSizes","payload","update","id","slug","depth","draft","filesToDelete","filename","push","sizes","concat","values","resizedFileData","newFilenames","Set","add","size","deletionPromises","has","handleDelete","err","logger","error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/afterChange.ts"],"sourcesContent":["import type { CollectionAfterChangeHook, CollectionConfig, FileData, TypeWithID } from 'payload'\n\nimport type { GeneratedAdapter } from '../types.js'\n\nimport { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js'\nimport {\n buildStoragePathData,\n buildUploadStoragePathData,\n} from '../utilities/buildStoragePathData.js'\nimport { getIncomingFiles } from '../utilities/getIncomingFiles.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n collectionPrefix?: string\n useCompositePrefixes?: boolean\n}\n\n// The object's folder: semantic prefix + `_objectKey` segment.\nconst getObjectFolder = (doc: unknown): string => {\n const record = (doc ?? {}) as { _objectKey?: string; prefix?: string }\n return buildPrefixWithObjectKey({ objectKey: record._objectKey, prefix: record.prefix })\n}\n\nexport const getAfterChangeHook =\n ({\n adapter,\n collection,\n collectionPrefix,\n useCompositePrefixes,\n }: Args): CollectionAfterChangeHook<FileData & TypeWithID> =>\n async ({ doc, operation, previousDoc, req }) => {\n // Skip if this is an internal update to prevent infinite loop\n if (req.context?.skipCloudStorage) {\n return doc\n }\n\n const isDraftSave = (doc as { _status?: string })._status === 'draft'\n const isDraftOverPublished =\n isDraftSave && (previousDoc as { _status?: string } | undefined)?._status === 'published'\n\n try {\n const files = getIncomingFiles({ data: doc, req })\n\n if (files.length > 0) {\n // Fold `_objectKey` so generated sizes land in the same folder as the original.\n const dataForUpload = { ...doc, prefix: getObjectFolder(doc) }\n\n const uploadResults = await Promise.all(\n files\n // Files with a clientUploadContext are already in storage (uploaded\n // directly by the browser), so skip re-uploading them here.\n .filter((file) => !file.clientUploadContext)\n .map((file) =>\n adapter.handleUpload({\n clientUploadContext: file.clientUploadContext,\n collection,\n data: dataForUpload,\n file,\n req,\n storageFilePath: buildUploadStoragePathData({\n collectionPrefix,\n docPrefix: dataForUpload.prefix,\n filename: file.filename,\n useCompositePrefixes,\n }).storageFilePath,\n }),\n ),\n )\n\n const uploadMetadata = uploadResults\n .filter(\n (result): result is Partial<FileData & TypeWithID> =>\n result != null && typeof result === 'object',\n )\n .reduce(\n (acc, metadata) => ({ ...acc, ...metadata }),\n {} as Partial<FileData & TypeWithID>,\n )\n\n // Adapters may echo `data` back as metadata; keep the document's own `prefix`/`_objectKey`.\n delete (uploadMetadata as Record<string, unknown>).prefix\n delete (uploadMetadata as Record<string, unknown>)._objectKey\n\n let docWithMetadata = doc\n\n if (Object.keys(uploadMetadata).length > 0) {\n if (!req.context) {\n req.context = {}\n }\n req.context.skipCloudStorage = true\n\n // Clear to prevent re-processing\n req.file = undefined\n req.payloadUploadSizes = undefined\n\n try {\n await req.payload.update({\n id: doc.id,\n collection: collection.slug,\n data: uploadMetadata,\n depth: 0,\n draft: isDraftSave,\n req,\n })\n } finally {\n delete req.context.skipCloudStorage\n }\n\n docWithMetadata = { ...doc, ...uploadMetadata }\n }\n\n // Delete previous files only after the new upload and metadata\n // persistence have succeeded. Deleting earlier would orphan the\n // record if a later step throws (e.g. a user-defined afterChange\n // hook on the same collection).\n if (previousDoc && operation === 'update' && !isDraftOverPublished) {\n let filesToDelete: string[] = []\n\n if (typeof previousDoc?.filename === 'string') {\n filesToDelete.push(previousDoc.filename)\n }\n\n if (typeof previousDoc.sizes === 'object') {\n filesToDelete = filesToDelete.concat(\n Object.values(previousDoc?.sizes || []).map(\n (resizedFileData) => resizedFileData?.filename as string,\n ),\n )\n }\n\n // Compare full locations: a replacement can reuse a filename while moving\n // a legacy object beneath the collection prefix.\n const newFilenames = new Set<string>()\n if (typeof docWithMetadata.filename === 'string') {\n newFilenames.add(docWithMetadata.filename)\n }\n if (typeof docWithMetadata.sizes === 'object') {\n for (const size of Object.values(docWithMetadata.sizes || {})) {\n if (size?.filename && typeof size.filename === 'string') {\n newFilenames.add(size.filename)\n }\n }\n }\n\n // Resolve each object's real location, folding `_objectKey` so a client-uploaded\n // original is compared and deleted at `prefix/_objectKey/filename`.\n const resolveKey = ({\n data,\n filename,\n }: {\n data: { _objectKey?: string; prefix?: string }\n filename: string\n }) =>\n buildStoragePathData({\n collectionPrefix,\n docPrefix: getObjectFolder(data),\n filename,\n useCompositePrefixes,\n }).storageFilePath\n\n const newKeys = new Set(\n [...newFilenames].map((filename) =>\n resolveKey({\n data: docWithMetadata as { _objectKey?: string; prefix?: string },\n filename,\n }),\n ),\n )\n\n const deletionPromises = filesToDelete.map(async (filename) => {\n if (!filename) {\n return\n }\n const storageFilePath = resolveKey({\n data: previousDoc as { _objectKey?: string; prefix?: string },\n filename,\n })\n if (!newKeys.has(storageFilePath)) {\n await adapter.handleDelete({\n collection,\n doc: previousDoc,\n filename,\n req,\n storageFilePath,\n })\n }\n })\n\n await Promise.all(deletionPromises)\n }\n\n if (docWithMetadata !== doc) {\n return docWithMetadata\n }\n }\n } catch (err: unknown) {\n req.payload.logger.error(\n `There was an error while uploading files corresponding to the collection ${collection.slug} with filename ${doc.filename}:`,\n )\n req.payload.logger.error({ err })\n throw err\n }\n return doc\n }\n"],"names":["buildPrefixWithObjectKey","buildStoragePathData","buildUploadStoragePathData","getIncomingFiles","getObjectFolder","doc","record","objectKey","_objectKey","prefix","getAfterChangeHook","adapter","collection","collectionPrefix","useCompositePrefixes","operation","previousDoc","req","context","skipCloudStorage","isDraftSave","_status","isDraftOverPublished","files","data","length","dataForUpload","uploadResults","Promise","all","filter","file","clientUploadContext","map","handleUpload","storageFilePath","docPrefix","filename","uploadMetadata","result","reduce","acc","metadata","docWithMetadata","Object","keys","undefined","payloadUploadSizes","payload","update","id","slug","depth","draft","filesToDelete","push","sizes","concat","values","resizedFileData","newFilenames","Set","add","size","resolveKey","newKeys","deletionPromises","has","handleDelete","err","logger","error"],"mappings":"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"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { getAfterChangeHook } from './afterChange.js';
|
|
3
|
+
describe('upload replacement cleanup', ()=>{
|
|
4
|
+
it.each([
|
|
5
|
+
[
|
|
6
|
+
'invoices',
|
|
7
|
+
'media/invoices',
|
|
8
|
+
[
|
|
9
|
+
{
|
|
10
|
+
filename: 'file.png',
|
|
11
|
+
prefix: 'invoices'
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
filename: 'thumb.png',
|
|
15
|
+
prefix: 'invoices'
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
],
|
|
19
|
+
[
|
|
20
|
+
'',
|
|
21
|
+
'media',
|
|
22
|
+
[]
|
|
23
|
+
],
|
|
24
|
+
[
|
|
25
|
+
'media/invoices',
|
|
26
|
+
'media/invoices',
|
|
27
|
+
[]
|
|
28
|
+
]
|
|
29
|
+
])('should compare object locations when replacing %s with %s', async (oldPrefix, newPrefix, expectedDeletes)=>{
|
|
30
|
+
const handleDelete = vi.fn();
|
|
31
|
+
const hook = getAfterChangeHook({
|
|
32
|
+
adapter: {
|
|
33
|
+
handleUpload: vi.fn(),
|
|
34
|
+
handleDelete
|
|
35
|
+
},
|
|
36
|
+
collection: {
|
|
37
|
+
slug: 'media'
|
|
38
|
+
},
|
|
39
|
+
collectionPrefix: 'media'
|
|
40
|
+
});
|
|
41
|
+
await hook({
|
|
42
|
+
doc: {
|
|
43
|
+
id: 1,
|
|
44
|
+
filename: 'file.png',
|
|
45
|
+
mimeType: 'image/png',
|
|
46
|
+
sizes: {
|
|
47
|
+
thumbnail: {
|
|
48
|
+
filename: 'thumb.png'
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
prefix: newPrefix
|
|
52
|
+
},
|
|
53
|
+
previousDoc: {
|
|
54
|
+
id: 1,
|
|
55
|
+
filename: 'file.png',
|
|
56
|
+
mimeType: 'image/png',
|
|
57
|
+
sizes: {
|
|
58
|
+
thumbnail: {
|
|
59
|
+
filename: 'thumb.png'
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
prefix: oldPrefix
|
|
63
|
+
},
|
|
64
|
+
operation: 'update',
|
|
65
|
+
req: {
|
|
66
|
+
context: {},
|
|
67
|
+
file: {
|
|
68
|
+
data: Buffer.from('file'),
|
|
69
|
+
size: 4
|
|
70
|
+
},
|
|
71
|
+
payload: {
|
|
72
|
+
logger: {
|
|
73
|
+
error: vi.fn()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
expect(handleDelete.mock.calls.map(([{ doc, filename }])=>({
|
|
79
|
+
filename,
|
|
80
|
+
prefix: doc.prefix
|
|
81
|
+
}))).toEqual(expectedDeletes);
|
|
82
|
+
});
|
|
83
|
+
it('should delete a replaced client upload at its _objectKey folder', async ()=>{
|
|
84
|
+
const handleDelete = vi.fn();
|
|
85
|
+
const hook = getAfterChangeHook({
|
|
86
|
+
adapter: {
|
|
87
|
+
handleUpload: vi.fn(),
|
|
88
|
+
handleDelete
|
|
89
|
+
},
|
|
90
|
+
collection: {
|
|
91
|
+
slug: 'media'
|
|
92
|
+
},
|
|
93
|
+
collectionPrefix: 'media'
|
|
94
|
+
});
|
|
95
|
+
await hook({
|
|
96
|
+
doc: {
|
|
97
|
+
id: 1,
|
|
98
|
+
_objectKey: 'new-key',
|
|
99
|
+
filename: 'file.png',
|
|
100
|
+
mimeType: 'image/png',
|
|
101
|
+
prefix: 'media/invoices',
|
|
102
|
+
sizes: {
|
|
103
|
+
thumbnail: {
|
|
104
|
+
filename: 'thumb.png'
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
previousDoc: {
|
|
109
|
+
id: 1,
|
|
110
|
+
_objectKey: 'old-key',
|
|
111
|
+
filename: 'file.png',
|
|
112
|
+
mimeType: 'image/png',
|
|
113
|
+
prefix: 'media/invoices',
|
|
114
|
+
sizes: {
|
|
115
|
+
thumbnail: {
|
|
116
|
+
filename: 'thumb.png'
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
operation: 'update',
|
|
121
|
+
req: {
|
|
122
|
+
context: {},
|
|
123
|
+
file: {
|
|
124
|
+
data: Buffer.from('file'),
|
|
125
|
+
size: 4
|
|
126
|
+
},
|
|
127
|
+
payload: {
|
|
128
|
+
logger: {
|
|
129
|
+
error: vi.fn()
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
expect(handleDelete.mock.calls.map(([{ filename, storageFilePath }])=>({
|
|
135
|
+
filename,
|
|
136
|
+
storageFilePath
|
|
137
|
+
}))).toEqual([
|
|
138
|
+
{
|
|
139
|
+
filename: 'file.png',
|
|
140
|
+
storageFilePath: 'media/invoices/old-key/file.png'
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
filename: 'thumb.png',
|
|
144
|
+
storageFilePath: 'media/invoices/old-key/thumb.png'
|
|
145
|
+
}
|
|
146
|
+
]);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
//# sourceMappingURL=afterChange.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/afterChange.spec.ts"],"sourcesContent":["import { describe, expect, it, vi } from 'vitest'\n\nimport { getAfterChangeHook } from './afterChange.js'\n\ndescribe('upload replacement cleanup', () => {\n it.each([\n [\n 'invoices',\n 'media/invoices',\n [\n { filename: 'file.png', prefix: 'invoices' },\n { filename: 'thumb.png', prefix: 'invoices' },\n ],\n ],\n ['', 'media', []],\n ['media/invoices', 'media/invoices', []],\n ] as const)(\n 'should compare object locations when replacing %s with %s',\n async (oldPrefix, newPrefix, expectedDeletes) => {\n const handleDelete = vi.fn()\n const hook = getAfterChangeHook({\n adapter: { handleUpload: vi.fn(), handleDelete } as never,\n collection: { slug: 'media' } as never,\n collectionPrefix: 'media',\n })\n\n await hook({\n doc: {\n id: 1,\n filename: 'file.png',\n mimeType: 'image/png',\n sizes: { thumbnail: { filename: 'thumb.png' } },\n prefix: newPrefix,\n },\n previousDoc: {\n id: 1,\n filename: 'file.png',\n mimeType: 'image/png',\n sizes: { thumbnail: { filename: 'thumb.png' } },\n prefix: oldPrefix,\n },\n operation: 'update',\n req: {\n context: {},\n file: { data: Buffer.from('file'), size: 4 },\n payload: { logger: { error: vi.fn() } },\n },\n } as never)\n\n expect(\n handleDelete.mock.calls.map(([{ doc, filename }]) => ({\n filename,\n prefix: doc.prefix,\n })),\n ).toEqual(expectedDeletes)\n },\n )\n\n it('should delete a replaced client upload at its _objectKey folder', async () => {\n const handleDelete = vi.fn()\n const hook = getAfterChangeHook({\n adapter: { handleUpload: vi.fn(), handleDelete } as never,\n collection: { slug: 'media' } as never,\n collectionPrefix: 'media',\n })\n\n await hook({\n doc: {\n id: 1,\n _objectKey: 'new-key',\n filename: 'file.png',\n mimeType: 'image/png',\n prefix: 'media/invoices',\n sizes: { thumbnail: { filename: 'thumb.png' } },\n },\n previousDoc: {\n id: 1,\n _objectKey: 'old-key',\n filename: 'file.png',\n mimeType: 'image/png',\n prefix: 'media/invoices',\n sizes: { thumbnail: { filename: 'thumb.png' } },\n },\n operation: 'update',\n req: {\n context: {},\n file: { data: Buffer.from('file'), size: 4 },\n payload: { logger: { error: vi.fn() } },\n },\n } as never)\n\n expect(\n handleDelete.mock.calls.map(([{ filename, storageFilePath }]) => ({\n filename,\n storageFilePath,\n })),\n ).toEqual([\n { filename: 'file.png', storageFilePath: 'media/invoices/old-key/file.png' },\n { filename: 'thumb.png', storageFilePath: 'media/invoices/old-key/thumb.png' },\n ])\n })\n})\n"],"names":["describe","expect","it","vi","getAfterChangeHook","each","filename","prefix","oldPrefix","newPrefix","expectedDeletes","handleDelete","fn","hook","adapter","handleUpload","collection","slug","collectionPrefix","doc","id","mimeType","sizes","thumbnail","previousDoc","operation","req","context","file","data","Buffer","from","size","payload","logger","error","mock","calls","map","toEqual","_objectKey","storageFilePath"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,SAAQ;AAEjD,SAASC,kBAAkB,QAAQ,mBAAkB;AAErDJ,SAAS,8BAA8B;IACrCE,GAAGG,IAAI,CAAC;QACN;YACE;YACA;YACA;gBACE;oBAAEC,UAAU;oBAAYC,QAAQ;gBAAW;gBAC3C;oBAAED,UAAU;oBAAaC,QAAQ;gBAAW;aAC7C;SACF;QACD;YAAC;YAAI;YAAS,EAAE;SAAC;QACjB;YAAC;YAAkB;YAAkB,EAAE;SAAC;KACzC,EACC,6DACA,OAAOC,WAAWC,WAAWC;QAC3B,MAAMC,eAAeR,GAAGS,EAAE;QAC1B,MAAMC,OAAOT,mBAAmB;YAC9BU,SAAS;gBAAEC,cAAcZ,GAAGS,EAAE;gBAAID;YAAa;YAC/CK,YAAY;gBAAEC,MAAM;YAAQ;YAC5BC,kBAAkB;QACpB;QAEA,MAAML,KAAK;YACTM,KAAK;gBACHC,IAAI;gBACJd,UAAU;gBACVe,UAAU;gBACVC,OAAO;oBAAEC,WAAW;wBAAEjB,UAAU;oBAAY;gBAAE;gBAC9CC,QAAQE;YACV;YACAe,aAAa;gBACXJ,IAAI;gBACJd,UAAU;gBACVe,UAAU;gBACVC,OAAO;oBAAEC,WAAW;wBAAEjB,UAAU;oBAAY;gBAAE;gBAC9CC,QAAQC;YACV;YACAiB,WAAW;YACXC,KAAK;gBACHC,SAAS,CAAC;gBACVC,MAAM;oBAAEC,MAAMC,OAAOC,IAAI,CAAC;oBAASC,MAAM;gBAAE;gBAC3CC,SAAS;oBAAEC,QAAQ;wBAAEC,OAAOhC,GAAGS,EAAE;oBAAG;gBAAE;YACxC;QACF;QAEAX,OACEU,aAAayB,IAAI,CAACC,KAAK,CAACC,GAAG,CAAC,CAAC,CAAC,EAAEnB,GAAG,EAAEb,QAAQ,EAAE,CAAC,GAAM,CAAA;gBACpDA;gBACAC,QAAQY,IAAIZ,MAAM;YACpB,CAAA,IACAgC,OAAO,CAAC7B;IACZ;IAGFR,GAAG,mEAAmE;QACpE,MAAMS,eAAeR,GAAGS,EAAE;QAC1B,MAAMC,OAAOT,mBAAmB;YAC9BU,SAAS;gBAAEC,cAAcZ,GAAGS,EAAE;gBAAID;YAAa;YAC/CK,YAAY;gBAAEC,MAAM;YAAQ;YAC5BC,kBAAkB;QACpB;QAEA,MAAML,KAAK;YACTM,KAAK;gBACHC,IAAI;gBACJoB,YAAY;gBACZlC,UAAU;gBACVe,UAAU;gBACVd,QAAQ;gBACRe,OAAO;oBAAEC,WAAW;wBAAEjB,UAAU;oBAAY;gBAAE;YAChD;YACAkB,aAAa;gBACXJ,IAAI;gBACJoB,YAAY;gBACZlC,UAAU;gBACVe,UAAU;gBACVd,QAAQ;gBACRe,OAAO;oBAAEC,WAAW;wBAAEjB,UAAU;oBAAY;gBAAE;YAChD;YACAmB,WAAW;YACXC,KAAK;gBACHC,SAAS,CAAC;gBACVC,MAAM;oBAAEC,MAAMC,OAAOC,IAAI,CAAC;oBAASC,MAAM;gBAAE;gBAC3CC,SAAS;oBAAEC,QAAQ;wBAAEC,OAAOhC,GAAGS,EAAE;oBAAG;gBAAE;YACxC;QACF;QAEAX,OACEU,aAAayB,IAAI,CAACC,KAAK,CAACC,GAAG,CAAC,CAAC,CAAC,EAAEhC,QAAQ,EAAEmC,eAAe,EAAE,CAAC,GAAM,CAAA;gBAChEnC;gBACAmC;YACF,CAAA,IACAF,OAAO,CAAC;YACR;gBAAEjC,UAAU;gBAAYmC,iBAAiB;YAAkC;YAC3E;gBAAEnC,UAAU;gBAAamC,iBAAiB;YAAmC;SAC9E;IACH;AACF"}
|
|
@@ -3,7 +3,9 @@ import type { GeneratedAdapter, TypeWithPrefix } from '../types.js';
|
|
|
3
3
|
interface Args {
|
|
4
4
|
adapter: GeneratedAdapter;
|
|
5
5
|
collection: CollectionConfig;
|
|
6
|
+
collectionPrefix?: string;
|
|
7
|
+
useCompositePrefixes?: boolean;
|
|
6
8
|
}
|
|
7
|
-
export declare const getAfterDeleteHook: ({ adapter, collection, }: Args) => CollectionAfterDeleteHook<FileData & TypeWithID & TypeWithPrefix>;
|
|
9
|
+
export declare const getAfterDeleteHook: ({ adapter, collection, collectionPrefix, useCompositePrefixes, }: Args) => CollectionAfterDeleteHook<FileData & TypeWithID & TypeWithPrefix>;
|
|
8
10
|
export {};
|
|
9
11
|
//# sourceMappingURL=afterDelete.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"afterDelete.d.ts","sourceRoot":"","sources":["../../src/hooks/afterDelete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEhG,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"afterDelete.d.ts","sourceRoot":"","sources":["../../src/hooks/afterDelete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEhG,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAKnE,UAAU,IAAI;IACZ,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,eAAO,MAAM,kBAAkB,qEAK5B,IAAI,KAAG,yBAAyB,CAAC,QAAQ,GAAG,UAAU,GAAG,cAAc,CAqCzE,CAAA"}
|
|
@@ -1,17 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
import { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js';
|
|
2
|
+
import { buildStoragePathData } from '../utilities/buildStoragePathData.js';
|
|
3
|
+
export const getAfterDeleteHook = ({ adapter, collection, collectionPrefix, useCompositePrefixes })=>{
|
|
2
4
|
return async ({ doc, req })=>{
|
|
3
5
|
try {
|
|
6
|
+
// Fold `_objectKey` so deletes target the real object folder.
|
|
7
|
+
const docPrefix = buildPrefixWithObjectKey({
|
|
8
|
+
objectKey: doc._objectKey,
|
|
9
|
+
prefix: doc.prefix
|
|
10
|
+
});
|
|
4
11
|
const filesToDelete = [
|
|
5
12
|
doc.filename,
|
|
6
13
|
...Object.values(doc?.sizes || []).map((resizedFileData)=>resizedFileData?.filename)
|
|
7
14
|
];
|
|
8
15
|
const promises = filesToDelete.map(async (filename)=>{
|
|
9
16
|
if (filename) {
|
|
17
|
+
const { storageFilePath } = buildStoragePathData({
|
|
18
|
+
collectionPrefix,
|
|
19
|
+
docPrefix,
|
|
20
|
+
filename,
|
|
21
|
+
useCompositePrefixes
|
|
22
|
+
});
|
|
10
23
|
await adapter.handleDelete({
|
|
11
24
|
collection,
|
|
12
25
|
doc,
|
|
13
26
|
filename,
|
|
14
|
-
req
|
|
27
|
+
req,
|
|
28
|
+
storageFilePath
|
|
15
29
|
});
|
|
16
30
|
}
|
|
17
31
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/afterDelete.ts"],"sourcesContent":["import type { CollectionAfterDeleteHook, CollectionConfig, FileData, TypeWithID } from 'payload'\n\nimport type { GeneratedAdapter, TypeWithPrefix } from '../types.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n}\n\nexport const getAfterDeleteHook = ({\n adapter,\n collection,\n}: Args): CollectionAfterDeleteHook<FileData & TypeWithID & TypeWithPrefix> => {\n return async ({ doc, req }) => {\n try {\n const filesToDelete: string[] = [\n doc.filename,\n ...Object.values(doc?.sizes || []).map(\n (resizedFileData) => resizedFileData?.filename as string,\n ),\n ]\n\n const promises = filesToDelete.map(async (filename) => {\n if (filename) {\n await adapter.handleDelete({ collection, doc, filename, req })\n }\n })\n\n await Promise.all(promises)\n } catch (err: unknown) {\n req.payload.logger.error({\n err,\n msg: `There was an error while deleting files corresponding to the ${collection.labels?.singular} with ID ${doc.id}.`,\n })\n }\n return doc\n }\n}\n"],"names":["getAfterDeleteHook","adapter","collection","doc","req","filesToDelete","filename","Object","values","sizes","map","resizedFileData","promises","handleDelete","Promise","all","err","payload","logger","error","msg","labels","singular","id"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/afterDelete.ts"],"sourcesContent":["import type { CollectionAfterDeleteHook, CollectionConfig, FileData, TypeWithID } from 'payload'\n\nimport type { GeneratedAdapter, TypeWithPrefix } from '../types.js'\n\nimport { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js'\nimport { buildStoragePathData } from '../utilities/buildStoragePathData.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n collectionPrefix?: string\n useCompositePrefixes?: boolean\n}\n\nexport const getAfterDeleteHook = ({\n adapter,\n collection,\n collectionPrefix,\n useCompositePrefixes,\n}: Args): CollectionAfterDeleteHook<FileData & TypeWithID & TypeWithPrefix> => {\n return async ({ doc, req }) => {\n try {\n // Fold `_objectKey` so deletes target the real object folder.\n const docPrefix = buildPrefixWithObjectKey({\n objectKey: (doc as { _objectKey?: string })._objectKey,\n prefix: doc.prefix,\n })\n\n const filesToDelete: string[] = [\n doc.filename,\n ...Object.values(doc?.sizes || []).map(\n (resizedFileData) => resizedFileData?.filename as string,\n ),\n ]\n\n const promises = filesToDelete.map(async (filename) => {\n if (filename) {\n const { storageFilePath } = buildStoragePathData({\n collectionPrefix,\n docPrefix,\n filename,\n useCompositePrefixes,\n })\n await adapter.handleDelete({ collection, doc, filename, req, storageFilePath })\n }\n })\n\n await Promise.all(promises)\n } catch (err: unknown) {\n req.payload.logger.error({\n err,\n msg: `There was an error while deleting files corresponding to the ${collection.labels?.singular} with ID ${doc.id}.`,\n })\n }\n return doc\n }\n}\n"],"names":["buildPrefixWithObjectKey","buildStoragePathData","getAfterDeleteHook","adapter","collection","collectionPrefix","useCompositePrefixes","doc","req","docPrefix","objectKey","_objectKey","prefix","filesToDelete","filename","Object","values","sizes","map","resizedFileData","promises","storageFilePath","handleDelete","Promise","all","err","payload","logger","error","msg","labels","singular","id"],"mappings":"AAIA,SAASA,wBAAwB,QAAQ,2CAA0C;AACnF,SAASC,oBAAoB,QAAQ,uCAAsC;AAS3E,OAAO,MAAMC,qBAAqB,CAAC,EACjCC,OAAO,EACPC,UAAU,EACVC,gBAAgB,EAChBC,oBAAoB,EACf;IACL,OAAO,OAAO,EAAEC,GAAG,EAAEC,GAAG,EAAE;QACxB,IAAI;YACF,8DAA8D;YAC9D,MAAMC,YAAYT,yBAAyB;gBACzCU,WAAW,AAACH,IAAgCI,UAAU;gBACtDC,QAAQL,IAAIK,MAAM;YACpB;YAEA,MAAMC,gBAA0B;gBAC9BN,IAAIO,QAAQ;mBACTC,OAAOC,MAAM,CAACT,KAAKU,SAAS,EAAE,EAAEC,GAAG,CACpC,CAACC,kBAAoBA,iBAAiBL;aAEzC;YAED,MAAMM,WAAWP,cAAcK,GAAG,CAAC,OAAOJ;gBACxC,IAAIA,UAAU;oBACZ,MAAM,EAAEO,eAAe,EAAE,GAAGpB,qBAAqB;wBAC/CI;wBACAI;wBACAK;wBACAR;oBACF;oBACA,MAAMH,QAAQmB,YAAY,CAAC;wBAAElB;wBAAYG;wBAAKO;wBAAUN;wBAAKa;oBAAgB;gBAC/E;YACF;YAEA,MAAME,QAAQC,GAAG,CAACJ;QACpB,EAAE,OAAOK,KAAc;YACrBjB,IAAIkB,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;gBACvBH;gBACAI,KAAK,CAAC,6DAA6D,EAAEzB,WAAW0B,MAAM,EAAEC,SAAS,SAAS,EAAExB,IAAIyB,EAAE,CAAC,CAAC,CAAC;YACvH;QACF;QACA,OAAOzB;IACT;AACF,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"afterRead.d.ts","sourceRoot":"","sources":["../../src/hooks/afterRead.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAErE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"afterRead.d.ts","sourceRoot":"","sources":["../../src/hooks/afterRead.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAErE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAIpE,UAAU,IAAI;IACZ,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB;AAQD,eAAO,MAAM,gBAAgB,gFACmD,IAAI,KAAG,SA8BpF,CAAA"}
|