@payloadcms/plugin-cloud-storage 4.0.0-internal.8001944 → 4.0.0-internal.8089ef7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/fields/getFields.d.ts.map +1 -1
  2. package/dist/fields/getFields.js +73 -8
  3. package/dist/fields/getFields.js.map +1 -1
  4. package/dist/hooks/afterChange.d.ts +3 -1
  5. package/dist/hooks/afterChange.d.ts.map +1 -1
  6. package/dist/hooks/afterChange.js +64 -6
  7. package/dist/hooks/afterChange.js.map +1 -1
  8. package/dist/hooks/afterDelete.d.ts.map +1 -1
  9. package/dist/hooks/afterDelete.js +10 -2
  10. package/dist/hooks/afterDelete.js.map +1 -1
  11. package/dist/hooks/afterRead.d.ts +6 -1
  12. package/dist/hooks/afterRead.d.ts.map +1 -1
  13. package/dist/hooks/afterRead.js +20 -6
  14. package/dist/hooks/afterRead.js.map +1 -1
  15. package/dist/hooks/beforeChange.d.ts +2 -1
  16. package/dist/hooks/beforeChange.d.ts.map +1 -1
  17. package/dist/hooks/beforeChange.js +7 -4
  18. package/dist/hooks/beforeChange.js.map +1 -1
  19. package/dist/hooks/publicOriginalURL.d.ts +8 -0
  20. package/dist/hooks/publicOriginalURL.d.ts.map +1 -0
  21. package/dist/hooks/publicOriginalURL.js +34 -0
  22. package/dist/hooks/publicOriginalURL.js.map +1 -0
  23. package/dist/plugin.d.ts.map +1 -1
  24. package/dist/plugin.js +29 -4
  25. package/dist/plugin.js.map +1 -1
  26. package/dist/types.d.ts +26 -1
  27. package/dist/types.d.ts.map +1 -1
  28. package/dist/types.js.map +1 -1
  29. package/dist/utilities/createFileOperations.d.ts +13 -0
  30. package/dist/utilities/createFileOperations.d.ts.map +1 -0
  31. package/dist/utilities/createFileOperations.js +258 -0
  32. package/dist/utilities/createFileOperations.js.map +1 -0
  33. package/dist/utilities/getFilePrefix.d.ts +2 -5
  34. package/dist/utilities/getFilePrefix.d.ts.map +1 -1
  35. package/dist/utilities/getFilePrefix.js +25 -10
  36. package/dist/utilities/getFilePrefix.js.map +1 -1
  37. package/dist/utilities/getIncomingFiles.js +2 -2
  38. package/dist/utilities/getIncomingFiles.js.map +1 -1
  39. package/dist/utilities/getStorageLocationSelect.d.ts +9 -0
  40. package/dist/utilities/getStorageLocationSelect.d.ts.map +1 -0
  41. package/dist/utilities/getStorageLocationSelect.js +54 -0
  42. package/dist/utilities/getStorageLocationSelect.js.map +1 -0
  43. package/dist/utilities/resolveSignedURLKey.d.ts.map +1 -1
  44. package/dist/utilities/resolveSignedURLKey.js +15 -7
  45. package/dist/utilities/resolveSignedURLKey.js.map +1 -1
  46. package/package.json +4 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicOriginalURL.d.ts","sourceRoot":"","sources":["../../src/hooks/publicOriginalURL.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,gBAAgB,EAAwB,MAAM,SAAS,CAAA;AAE9F,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAIpE,eAAO,MAAM,wBAAwB,8CAKhC;IACD,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAA;CAClC,KAAG,uBAsBH,CAAA"}
@@ -0,0 +1,34 @@
1
+ import { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js';
2
+ export const getPublicOriginalURLHook = ({ adapter, collection, generateFileURL })=>async ({ doc })=>{
3
+ const upload = doc;
4
+ const filename = upload.original?.filename;
5
+ if (!filename) {
6
+ return doc;
7
+ }
8
+ if (upload.original?.url && !upload.original.url.startsWith('/')) {
9
+ return doc;
10
+ }
11
+ const prefix = buildPrefixWithObjectKey({
12
+ objectKey: upload.original?._objectKey,
13
+ prefix: upload.original?.prefix
14
+ });
15
+ const url = generateFileURL ? await generateFileURL({
16
+ collection,
17
+ filename,
18
+ prefix
19
+ }) : await adapter.generateURL?.({
20
+ collection,
21
+ data: upload,
22
+ filename,
23
+ prefix
24
+ });
25
+ return url ? {
26
+ ...doc,
27
+ original: {
28
+ ...upload.original,
29
+ url
30
+ }
31
+ } : doc;
32
+ };
33
+
34
+ //# sourceMappingURL=publicOriginalURL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hooks/publicOriginalURL.ts"],"sourcesContent":["import type { CollectionAfterReadHook, CollectionConfig, FileData, TypeWithID } from 'payload'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport { buildPrefixWithObjectKey } from '../utilities/buildPrefixWithObjectKey.js'\n\nexport const getPublicOriginalURLHook =\n ({\n adapter,\n collection,\n generateFileURL,\n }: {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n generateFileURL?: GenerateFileURL\n }): CollectionAfterReadHook =>\n async ({ doc }) => {\n const upload = doc as { _objectKey?: string; prefix?: string } & FileData & TypeWithID\n const filename = upload.original?.filename\n\n if (!filename) {\n return doc\n }\n\n if (upload.original?.url && !upload.original.url.startsWith('/')) {\n return doc\n }\n\n const prefix = buildPrefixWithObjectKey({\n objectKey: upload.original?._objectKey,\n prefix: upload.original?.prefix,\n })\n const url = generateFileURL\n ? await generateFileURL({ collection, filename, prefix })\n : await adapter.generateURL?.({ collection, data: upload, filename, prefix })\n\n return url ? { ...doc, original: { ...upload.original, url } } : doc\n }\n"],"names":["buildPrefixWithObjectKey","getPublicOriginalURLHook","adapter","collection","generateFileURL","doc","upload","filename","original","url","startsWith","prefix","objectKey","_objectKey","generateURL","data"],"mappings":"AAIA,SAASA,wBAAwB,QAAQ,2CAA0C;AAEnF,OAAO,MAAMC,2BACX,CAAC,EACCC,OAAO,EACPC,UAAU,EACVC,eAAe,EAKhB,GACD,OAAO,EAAEC,GAAG,EAAE;QACZ,MAAMC,SAASD;QACf,MAAME,WAAWD,OAAOE,QAAQ,EAAED;QAElC,IAAI,CAACA,UAAU;YACb,OAAOF;QACT;QAEA,IAAIC,OAAOE,QAAQ,EAAEC,OAAO,CAACH,OAAOE,QAAQ,CAACC,GAAG,CAACC,UAAU,CAAC,MAAM;YAChE,OAAOL;QACT;QAEA,MAAMM,SAASX,yBAAyB;YACtCY,WAAWN,OAAOE,QAAQ,EAAEK;YAC5BF,QAAQL,OAAOE,QAAQ,EAAEG;QAC3B;QACA,MAAMF,MAAML,kBACR,MAAMA,gBAAgB;YAAED;YAAYI;YAAUI;QAAO,KACrD,MAAMT,QAAQY,WAAW,GAAG;YAAEX;YAAYY,MAAMT;YAAQC;YAAUI;QAAO;QAE7E,OAAOF,MAAM;YAAE,GAAGJ,GAAG;YAAEG,UAAU;gBAAE,GAAGF,OAAOE,QAAQ;gBAAEC;YAAI;QAAE,IAAIJ;IACnE,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAErC,OAAO,KAAK,EAAsB,aAAa,EAAE,MAAM,YAAY,CAAA;AAiBnE,eAAO,MAAM,kBAAkB,kBACb,aAAa,sBACZ,MAAM,KAAG,MAwOzB,CAAA"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAErC,OAAO,KAAK,EAAsB,aAAa,EAAE,MAAM,YAAY,CAAA;AAoBnE,eAAO,MAAM,kBAAkB,kBACb,aAAa,sBACZ,MAAM,KAAG,MA+PzB,CAAA"}
package/dist/plugin.js CHANGED
@@ -3,6 +3,9 @@ import { getAfterChangeHook } from './hooks/afterChange.js';
3
3
  import { getAfterDeleteHook } from './hooks/afterDelete.js';
4
4
  import { getNormalizeUploadPrefixHook } from './hooks/normalizeUploadPrefix.js';
5
5
  import { getPreserveFileDataHook } from './hooks/preserveFileData.js';
6
+ import { getPublicOriginalURLHook } from './hooks/publicOriginalURL.js';
7
+ import { createFileOperations } from './utilities/createFileOperations.js';
8
+ import { getStorageLocationSelect } from './utilities/getStorageLocationSelect.js';
6
9
  // This plugin extends all targeted collections by offloading uploaded files
7
10
  // to cloud storage instead of solely storing files locally.
8
11
  // It is based on an adapter approach, where adapters can be written for any cloud provider.
@@ -109,11 +112,10 @@ export const cloudStoragePlugin = (pluginOptions)=>(incomingConfig)=>{
109
112
  ];
110
113
  if (!options.disablePayloadAccessControl) {
111
114
  handlers.push(adapter.staticHandler);
112
- // Else if disablePayloadAccessControl: true and upload instructions are used
113
- // Build the "proxied" handler that responds only when addDataAndFileToRequest fetches the uploaded file
114
- } else if (uploadInstructions) {
115
+ // Public files still need a server path when Payload reads them for a transform.
116
+ } else {
115
117
  handlers.push((req, args)=>{
116
- if ('uploadReference' in args.params) {
118
+ if ('uploadReference' in args.params || args.params.operation === 'transform') {
117
119
  return adapter.staticHandler(req, args);
118
120
  }
119
121
  });
@@ -159,6 +161,8 @@ export const cloudStoragePlugin = (pluginOptions)=>(incomingConfig)=>{
159
161
  adapter,
160
162
  collection: existingCollection,
161
163
  collectionPrefix: options.prefix,
164
+ disablePayloadAccessControl: options.disablePayloadAccessControl,
165
+ hasCustomFileURL: Boolean(options.generateFileURL),
162
166
  useCompositePrefixes
163
167
  })
164
168
  ],
@@ -171,6 +175,16 @@ export const cloudStoragePlugin = (pluginOptions)=>(incomingConfig)=>{
171
175
  useCompositePrefixes
172
176
  })
173
177
  ],
178
+ afterRead: [
179
+ ...existingCollection.hooks?.afterRead || [],
180
+ ...options.disablePayloadAccessControl && (options.generateFileURL || adapter.generateURL) ? [
181
+ getPublicOriginalURLHook({
182
+ adapter,
183
+ collection: existingCollection,
184
+ generateFileURL: options.generateFileURL
185
+ })
186
+ ] : []
187
+ ],
174
188
  beforeChange: [
175
189
  ...existingCollection.hooks?.beforeChange || [],
176
190
  getNormalizeUploadPrefixHook({
@@ -180,9 +194,20 @@ export const cloudStoragePlugin = (pluginOptions)=>(incomingConfig)=>{
180
194
  getPreserveFileDataHook()
181
195
  ]
182
196
  },
197
+ select: getStorageLocationSelect({
198
+ select: existingCollection.select
199
+ }),
183
200
  upload: {
184
201
  ...typeof existingCollection.upload === 'object' ? existingCollection.upload : {},
185
202
  adapter: adapter.name,
203
+ fileOperations: createFileOperations({
204
+ adapter,
205
+ collection: existingCollection,
206
+ collectionPrefix: options.prefix,
207
+ disablePayloadAccessControl: options.disablePayloadAccessControl,
208
+ generateFileURL: options.generateFileURL,
209
+ useCompositePrefixes
210
+ }),
186
211
  ...uploadInstructions && {
187
212
  uploadInstructions
188
213
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Config } from 'payload'\n\nimport type { Adapter, AllowList, PluginOptions } from './types.js'\n\nimport { getFields } from './fields/getFields.js'\nimport { getAfterChangeHook } from './hooks/afterChange.js'\nimport { getAfterDeleteHook } from './hooks/afterDelete.js'\nimport { getNormalizeUploadPrefixHook } from './hooks/normalizeUploadPrefix.js'\nimport { getPreserveFileDataHook } from './hooks/preserveFileData.js'\n\n// This plugin extends all targeted collections by offloading uploaded files\n// to cloud storage instead of solely storing files locally.\n\n// It is based on an adapter approach, where adapters can be written for any cloud provider.\n// Adapters are responsible for providing four actions that this plugin will use:\n// 1. handleUpload, 2. handleDelete, 3. generateURL, 4. staticHandler\n\n// Optionally, the adapter can specify any Webpack config overrides if they are necessary.\n\nexport const cloudStoragePlugin =\n (pluginOptions: PluginOptions) =>\n (incomingConfig: Config): Config => {\n const { collections: allCollectionOptions, enabled, useCompositePrefixes } = pluginOptions\n const config = { ...incomingConfig }\n\n // If disabled, only insert fields (e.g. prefix) without full plugin functionality,\n // so the collection schema stays consistent across environments.\n if (enabled === false) {\n return {\n ...config,\n collections: (config.collections || []).map((existingCollection) => {\n const options = allCollectionOptions[existingCollection.slug]\n\n if (options) {\n // If adapter is provided, use it to get fields\n const adapter = options.adapter\n ? options.adapter({\n collection: existingCollection,\n prefix: options.prefix,\n })\n : undefined\n\n const fields = getFields({\n adapter,\n collection: existingCollection,\n disablePayloadAccessControl: options.disablePayloadAccessControl,\n generateFileURL: options.generateFileURL,\n prefix: options.prefix,\n useCompositePrefixes,\n })\n\n return {\n ...existingCollection,\n fields,\n }\n }\n\n return existingCollection\n }),\n }\n }\n\n const initFunctions: Array<() => Promise<void> | void> = []\n const endpointPaths = new Map<Adapter, string>()\n\n const collections = (config.collections || []).map((existingCollection) => {\n const options = allCollectionOptions[existingCollection.slug]\n\n if (options?.adapter) {\n const adapter = options.adapter({\n collection: existingCollection,\n prefix: options.prefix,\n })\n\n if (adapter.onInit) {\n initFunctions.push(adapter.onInit)\n }\n\n let uploadInstructions\n\n if (adapter.uploadInstructions) {\n const { adminHandler, enabled, endpoint, ...instructions } = adapter.uploadInstructions\n let endpointPath = endpointPaths.get(options.adapter)\n\n if (enabled && endpoint && !endpointPath) {\n const endpointCount =\n config.endpoints?.filter(({ path }) => path?.startsWith(endpoint.path)).length || 0\n\n endpointPath = endpointCount ? `${endpoint.path}-${endpointCount}` : endpoint.path\n config.endpoints ??= []\n config.endpoints.push({\n handler: endpoint.handler,\n method: 'post',\n path: endpointPath,\n })\n endpointPaths.set(options.adapter, endpointPath)\n }\n\n if (enabled && adminHandler) {\n config.admin ??= {}\n config.admin.components ??= {}\n config.admin.components.providers ??= []\n config.admin.components.providers.push({\n clientProps: {\n collectionSlug: existingCollection.slug,\n endpointPath,\n prefix: options.prefix,\n props: adminHandler.props || {},\n },\n path: adminHandler.path,\n })\n }\n\n if (enabled) {\n uploadInstructions = instructions\n } else if (adminHandler) {\n /** Avoid importMap.js differences when client uploads vary between dev and production. */\n config.admin ??= {}\n config.admin.dependencies ??= {}\n config.admin.dependencies[adminHandler.path] = {\n type: 'component',\n path: adminHandler.path,\n }\n }\n }\n\n const fields = getFields({\n adapter,\n collection: existingCollection,\n disablePayloadAccessControl: options.disablePayloadAccessControl,\n generateFileURL: options.generateFileURL,\n prefix: options.prefix,\n useCompositePrefixes,\n })\n\n const handlers = [\n ...(typeof existingCollection.upload === 'object' &&\n Array.isArray(existingCollection.upload.handlers)\n ? existingCollection.upload.handlers\n : []),\n ]\n\n if (!options.disablePayloadAccessControl) {\n handlers.push(adapter.staticHandler)\n // Else if disablePayloadAccessControl: true and upload instructions are used\n // Build the \"proxied\" handler that responds only when addDataAndFileToRequest fetches the uploaded file\n } else if (uploadInstructions) {\n handlers.push((req, args) => {\n if ('uploadReference' in args.params) {\n return adapter.staticHandler(req, args)\n }\n })\n }\n\n const getSkipSafeFetchSetting = (): AllowList | boolean => {\n const isBooleanTrueSkipSafeFetch =\n typeof existingCollection.upload === 'object' &&\n existingCollection.upload.skipSafeFetch === true\n\n const isAllowListSkipSafeFetch =\n typeof existingCollection.upload === 'object' &&\n Array.isArray(existingCollection.upload.skipSafeFetch)\n\n if (isBooleanTrueSkipSafeFetch) {\n return true\n } else if (isAllowListSkipSafeFetch) {\n const existingSkipSafeFetch =\n typeof existingCollection.upload === 'object' &&\n Array.isArray(existingCollection.upload.skipSafeFetch)\n ? existingCollection.upload.skipSafeFetch\n : []\n\n const hasExactLocalhostMatch = existingSkipSafeFetch.some((entry) => {\n const entryKeys = Object.keys(entry)\n return entryKeys.length === 1 && entry.hostname === 'localhost'\n })\n\n const localhostEntry =\n process.env.NODE_ENV !== 'production' && !hasExactLocalhostMatch\n ? [{ hostname: 'localhost' }]\n : []\n\n return [...existingSkipSafeFetch, ...localhostEntry]\n }\n\n if (process.env.NODE_ENV !== 'production') {\n return [{ hostname: 'localhost' }]\n }\n\n return false\n }\n\n return {\n ...existingCollection,\n fields,\n hooks: {\n ...(existingCollection.hooks || {}),\n afterChange: [\n ...(existingCollection.hooks?.afterChange || []),\n getAfterChangeHook({\n adapter,\n collection: existingCollection,\n collectionPrefix: options.prefix,\n useCompositePrefixes,\n }),\n ],\n afterDelete: [\n ...(existingCollection.hooks?.afterDelete || []),\n getAfterDeleteHook({\n adapter,\n collection: existingCollection,\n collectionPrefix: options.prefix,\n useCompositePrefixes,\n }),\n ],\n beforeChange: [\n ...(existingCollection.hooks?.beforeChange || []),\n getNormalizeUploadPrefixHook({\n collectionPrefix: options.prefix,\n useCompositePrefixes,\n }),\n getPreserveFileDataHook(),\n ],\n },\n upload: {\n ...(typeof existingCollection.upload === 'object' ? existingCollection.upload : {}),\n adapter: adapter.name,\n ...(uploadInstructions && {\n uploadInstructions,\n }),\n disableLocalStorage:\n typeof options.disableLocalStorage === 'boolean' ? options.disableLocalStorage : true,\n handlers,\n skipSafeFetch: getSkipSafeFetchSetting(),\n },\n }\n }\n\n return existingCollection\n })\n\n return {\n ...config,\n collections,\n onInit: async (payload) => {\n // Await each init so a provisioning failure fails Payload startup\n // instead of becoming an unhandled rejection.\n await Promise.all(initFunctions.map((fn) => fn()))\n if (config.onInit) {\n await config.onInit(payload)\n }\n },\n }\n }\n"],"names":["getFields","getAfterChangeHook","getAfterDeleteHook","getNormalizeUploadPrefixHook","getPreserveFileDataHook","cloudStoragePlugin","pluginOptions","incomingConfig","collections","allCollectionOptions","enabled","useCompositePrefixes","config","map","existingCollection","options","slug","adapter","collection","prefix","undefined","fields","disablePayloadAccessControl","generateFileURL","initFunctions","endpointPaths","Map","onInit","push","uploadInstructions","adminHandler","endpoint","instructions","endpointPath","get","endpointCount","endpoints","filter","path","startsWith","length","handler","method","set","admin","components","providers","clientProps","collectionSlug","props","dependencies","type","handlers","upload","Array","isArray","staticHandler","req","args","params","getSkipSafeFetchSetting","isBooleanTrueSkipSafeFetch","skipSafeFetch","isAllowListSkipSafeFetch","existingSkipSafeFetch","hasExactLocalhostMatch","some","entry","entryKeys","Object","keys","hostname","localhostEntry","process","env","NODE_ENV","hooks","afterChange","collectionPrefix","afterDelete","beforeChange","name","disableLocalStorage","payload","Promise","all","fn"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Config } from 'payload'\n\nimport type { Adapter, AllowList, PluginOptions } from './types.js'\n\nimport { getFields } from './fields/getFields.js'\nimport { getAfterChangeHook } from './hooks/afterChange.js'\nimport { getAfterDeleteHook } from './hooks/afterDelete.js'\nimport { getNormalizeUploadPrefixHook } from './hooks/normalizeUploadPrefix.js'\nimport { getPreserveFileDataHook } from './hooks/preserveFileData.js'\nimport { getPublicOriginalURLHook } from './hooks/publicOriginalURL.js'\nimport { createFileOperations } from './utilities/createFileOperations.js'\nimport { getStorageLocationSelect } from './utilities/getStorageLocationSelect.js'\n\n// This plugin extends all targeted collections by offloading uploaded files\n// to cloud storage instead of solely storing files locally.\n\n// It is based on an adapter approach, where adapters can be written for any cloud provider.\n// Adapters are responsible for providing four actions that this plugin will use:\n// 1. handleUpload, 2. handleDelete, 3. generateURL, 4. staticHandler\n\n// Optionally, the adapter can specify any Webpack config overrides if they are necessary.\n\nexport const cloudStoragePlugin =\n (pluginOptions: PluginOptions) =>\n (incomingConfig: Config): Config => {\n const { collections: allCollectionOptions, enabled, useCompositePrefixes } = pluginOptions\n const config = { ...incomingConfig }\n\n // If disabled, only insert fields (e.g. prefix) without full plugin functionality,\n // so the collection schema stays consistent across environments.\n if (enabled === false) {\n return {\n ...config,\n collections: (config.collections || []).map((existingCollection) => {\n const options = allCollectionOptions[existingCollection.slug]\n\n if (options) {\n // If adapter is provided, use it to get fields\n const adapter = options.adapter\n ? options.adapter({\n collection: existingCollection,\n prefix: options.prefix,\n })\n : undefined\n\n const fields = getFields({\n adapter,\n collection: existingCollection,\n disablePayloadAccessControl: options.disablePayloadAccessControl,\n generateFileURL: options.generateFileURL,\n prefix: options.prefix,\n useCompositePrefixes,\n })\n\n return {\n ...existingCollection,\n fields,\n }\n }\n\n return existingCollection\n }),\n }\n }\n\n const initFunctions: Array<() => Promise<void> | void> = []\n const endpointPaths = new Map<Adapter, string>()\n\n const collections = (config.collections || []).map((existingCollection) => {\n const options = allCollectionOptions[existingCollection.slug]\n\n if (options?.adapter) {\n const adapter = options.adapter({\n collection: existingCollection,\n prefix: options.prefix,\n })\n\n if (adapter.onInit) {\n initFunctions.push(adapter.onInit)\n }\n\n let uploadInstructions\n\n if (adapter.uploadInstructions) {\n const { adminHandler, enabled, endpoint, ...instructions } = adapter.uploadInstructions\n let endpointPath = endpointPaths.get(options.adapter)\n\n if (enabled && endpoint && !endpointPath) {\n const endpointCount =\n config.endpoints?.filter(({ path }) => path?.startsWith(endpoint.path)).length || 0\n\n endpointPath = endpointCount ? `${endpoint.path}-${endpointCount}` : endpoint.path\n config.endpoints ??= []\n config.endpoints.push({\n handler: endpoint.handler,\n method: 'post',\n path: endpointPath,\n })\n endpointPaths.set(options.adapter, endpointPath)\n }\n\n if (enabled && adminHandler) {\n config.admin ??= {}\n config.admin.components ??= {}\n config.admin.components.providers ??= []\n config.admin.components.providers.push({\n clientProps: {\n collectionSlug: existingCollection.slug,\n endpointPath,\n prefix: options.prefix,\n props: adminHandler.props || {},\n },\n path: adminHandler.path,\n })\n }\n\n if (enabled) {\n uploadInstructions = instructions\n } else if (adminHandler) {\n /** Avoid importMap.js differences when client uploads vary between dev and production. */\n config.admin ??= {}\n config.admin.dependencies ??= {}\n config.admin.dependencies[adminHandler.path] = {\n type: 'component',\n path: adminHandler.path,\n }\n }\n }\n\n const fields = getFields({\n adapter,\n collection: existingCollection,\n disablePayloadAccessControl: options.disablePayloadAccessControl,\n generateFileURL: options.generateFileURL,\n prefix: options.prefix,\n useCompositePrefixes,\n })\n\n const handlers = [\n ...(typeof existingCollection.upload === 'object' &&\n Array.isArray(existingCollection.upload.handlers)\n ? existingCollection.upload.handlers\n : []),\n ]\n\n if (!options.disablePayloadAccessControl) {\n handlers.push(adapter.staticHandler)\n // Public files still need a server path when Payload reads them for a transform.\n } else {\n handlers.push((req, args) => {\n if ('uploadReference' in args.params || args.params.operation === 'transform') {\n return adapter.staticHandler(req, args)\n }\n })\n }\n\n const getSkipSafeFetchSetting = (): AllowList | boolean => {\n const isBooleanTrueSkipSafeFetch =\n typeof existingCollection.upload === 'object' &&\n existingCollection.upload.skipSafeFetch === true\n\n const isAllowListSkipSafeFetch =\n typeof existingCollection.upload === 'object' &&\n Array.isArray(existingCollection.upload.skipSafeFetch)\n\n if (isBooleanTrueSkipSafeFetch) {\n return true\n } else if (isAllowListSkipSafeFetch) {\n const existingSkipSafeFetch =\n typeof existingCollection.upload === 'object' &&\n Array.isArray(existingCollection.upload.skipSafeFetch)\n ? existingCollection.upload.skipSafeFetch\n : []\n\n const hasExactLocalhostMatch = existingSkipSafeFetch.some((entry) => {\n const entryKeys = Object.keys(entry)\n return entryKeys.length === 1 && entry.hostname === 'localhost'\n })\n\n const localhostEntry =\n process.env.NODE_ENV !== 'production' && !hasExactLocalhostMatch\n ? [{ hostname: 'localhost' }]\n : []\n\n return [...existingSkipSafeFetch, ...localhostEntry]\n }\n\n if (process.env.NODE_ENV !== 'production') {\n return [{ hostname: 'localhost' }]\n }\n\n return false\n }\n\n return {\n ...existingCollection,\n fields,\n hooks: {\n ...(existingCollection.hooks || {}),\n afterChange: [\n ...(existingCollection.hooks?.afterChange || []),\n getAfterChangeHook({\n adapter,\n collection: existingCollection,\n collectionPrefix: options.prefix,\n disablePayloadAccessControl: options.disablePayloadAccessControl,\n hasCustomFileURL: Boolean(options.generateFileURL),\n useCompositePrefixes,\n }),\n ],\n afterDelete: [\n ...(existingCollection.hooks?.afterDelete || []),\n getAfterDeleteHook({\n adapter,\n collection: existingCollection,\n collectionPrefix: options.prefix,\n useCompositePrefixes,\n }),\n ],\n afterRead: [\n ...(existingCollection.hooks?.afterRead || []),\n ...(options.disablePayloadAccessControl &&\n (options.generateFileURL || adapter.generateURL)\n ? [\n getPublicOriginalURLHook({\n adapter,\n collection: existingCollection,\n generateFileURL: options.generateFileURL,\n }),\n ]\n : []),\n ],\n beforeChange: [\n ...(existingCollection.hooks?.beforeChange || []),\n getNormalizeUploadPrefixHook({\n collectionPrefix: options.prefix,\n useCompositePrefixes,\n }),\n getPreserveFileDataHook(),\n ],\n },\n select: getStorageLocationSelect({ select: existingCollection.select }),\n upload: {\n ...(typeof existingCollection.upload === 'object' ? existingCollection.upload : {}),\n adapter: adapter.name,\n fileOperations: createFileOperations({\n adapter,\n collection: existingCollection,\n collectionPrefix: options.prefix,\n disablePayloadAccessControl: options.disablePayloadAccessControl,\n generateFileURL: options.generateFileURL,\n useCompositePrefixes,\n }),\n ...(uploadInstructions && {\n uploadInstructions,\n }),\n disableLocalStorage:\n typeof options.disableLocalStorage === 'boolean' ? options.disableLocalStorage : true,\n handlers,\n skipSafeFetch: getSkipSafeFetchSetting(),\n },\n }\n }\n\n return existingCollection\n })\n\n return {\n ...config,\n collections,\n onInit: async (payload) => {\n // Await each init so a provisioning failure fails Payload startup\n // instead of becoming an unhandled rejection.\n await Promise.all(initFunctions.map((fn) => fn()))\n if (config.onInit) {\n await config.onInit(payload)\n }\n },\n }\n }\n"],"names":["getFields","getAfterChangeHook","getAfterDeleteHook","getNormalizeUploadPrefixHook","getPreserveFileDataHook","getPublicOriginalURLHook","createFileOperations","getStorageLocationSelect","cloudStoragePlugin","pluginOptions","incomingConfig","collections","allCollectionOptions","enabled","useCompositePrefixes","config","map","existingCollection","options","slug","adapter","collection","prefix","undefined","fields","disablePayloadAccessControl","generateFileURL","initFunctions","endpointPaths","Map","onInit","push","uploadInstructions","adminHandler","endpoint","instructions","endpointPath","get","endpointCount","endpoints","filter","path","startsWith","length","handler","method","set","admin","components","providers","clientProps","collectionSlug","props","dependencies","type","handlers","upload","Array","isArray","staticHandler","req","args","params","operation","getSkipSafeFetchSetting","isBooleanTrueSkipSafeFetch","skipSafeFetch","isAllowListSkipSafeFetch","existingSkipSafeFetch","hasExactLocalhostMatch","some","entry","entryKeys","Object","keys","hostname","localhostEntry","process","env","NODE_ENV","hooks","afterChange","collectionPrefix","hasCustomFileURL","Boolean","afterDelete","afterRead","generateURL","beforeChange","select","name","fileOperations","disableLocalStorage","payload","Promise","all","fn"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import type { CollectionConfig, Field, FileData, ImageSize, PayloadHandler, PayloadRequest, TypeWithID, UploadCollectionSlug, UploadInstructionsAccess, UploadInstructionsCapability } from 'payload';
1
+ import type { CollectionConfig, Field, FileData, FileHandlerOperation, ImageSize, PayloadHandler, PayloadRequest, SanitizedCollectionConfig, TypeWithID, UploadCollectionSlug, UploadInstructionsAccess, UploadInstructionsCapability } from 'payload';
2
+ export type { FileHandlerOperation } from 'payload';
2
3
  export interface File {
3
4
  buffer: Buffer;
4
5
  filename: string;
@@ -43,6 +44,23 @@ export type HandleDelete = (args: {
43
44
  */
44
45
  storageFilePath: string;
45
46
  }) => Promise<void> | void;
47
+ /** Deletes a stored object without requiring a saved document. */
48
+ export type DeleteFile = (args: {
49
+ collection: CollectionConfig;
50
+ req: PayloadRequest;
51
+ /** Complete storage path, with prefixes and `_objectKey` already resolved. */
52
+ storageFilePath: string;
53
+ }) => Promise<void> | void;
54
+ /** Complete storage keys are resolved before invoking a provider operation. */
55
+ export type FileOperationArgs = {
56
+ collection: SanitizedCollectionConfig;
57
+ from: string;
58
+ mimeType?: string;
59
+ req: PayloadRequest;
60
+ to: string;
61
+ };
62
+ export type CopyFile = (args: FileOperationArgs) => Promise<void>;
63
+ export type MoveFile = (args: FileOperationArgs) => Promise<void>;
46
64
  export type GenerateURL = (args: {
47
65
  collection: CollectionConfig;
48
66
  data: any;
@@ -55,11 +73,15 @@ export type StaticHandler = (req: PayloadRequest, args: {
55
73
  params: {
56
74
  collection: string;
57
75
  filename: string;
76
+ operation?: FileHandlerOperation;
58
77
  prefix?: string;
59
78
  uploadReference?: unknown;
60
79
  };
61
80
  }) => Promise<Response> | Response;
62
81
  export interface GeneratedAdapter {
82
+ /** Preserve object metadata and fail if `to` already exists. Rename retains `from` for history. */
83
+ copyFile: CopyFile;
84
+ deleteFile: DeleteFile;
63
85
  /**
64
86
  * Additional fields to be injected into the base collection and image sizes
65
87
  */
@@ -70,9 +92,12 @@ export interface GeneratedAdapter {
70
92
  generateURL?: GenerateURL;
71
93
  handleDelete: HandleDelete;
72
94
  handleUpload: HandleUpload;
95
+ moveFile?: MoveFile;
73
96
  name: string;
74
97
  onInit?: () => Promise<void> | void;
75
98
  staticHandler: StaticHandler;
99
+ /** Reads source files by path when staging server-mediated uploads. */
100
+ supportsTempFiles?: boolean;
76
101
  /** Generates upload instructions when supported. */
77
102
  uploadInstructions?: {
78
103
  adminHandler?: {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type {\n CollectionConfig,\n Field,\n FileData,\n ImageSize,\n PayloadHandler,\n PayloadRequest,\n TypeWithID,\n UploadCollectionSlug,\n UploadInstructionsAccess,\n UploadInstructionsCapability,\n} from 'payload'\n\nexport interface File {\n buffer: Buffer\n filename: string\n filesize: number\n mimeType: string\n tempFilePath?: string\n uploadReference?: unknown\n}\n\nexport type ClientUploadsConfig = { access?: UploadInstructionsAccess } | boolean\n\n/**\n * Reference to a client-uploaded object, returned by an upload handler and\n * submitted with the document. Always carries the signed receipt; `prefix`\n * locates the stored object.\n */\nexport type UploadReference = {\n _objectKey?: string\n prefix: string\n signedReceipt: `${string}.${string}`\n}\n\nexport type HandleUpload = (args: {\n collection: CollectionConfig\n data: any\n file: File\n req: PayloadRequest\n /**\n * Pre-resolved storage path (`_objectKey` folded in, contained beneath the collection prefix).\n */\n storageFilePath: string\n}) =>\n | Partial<FileData & TypeWithID>\n | Promise<Partial<FileData & TypeWithID>>\n | Promise<void>\n | void\n\nexport interface TypeWithPrefix {\n prefix?: string\n}\n\nexport type HandleDelete = (args: {\n collection: CollectionConfig\n doc: FileData & TypeWithID & TypeWithPrefix\n filename: string\n req: PayloadRequest\n /**\n * Pre-resolved storage path of the object to delete.\n */\n storageFilePath: string\n}) => Promise<void> | void\n\nexport type GenerateURL = (args: {\n collection: CollectionConfig\n data: any\n filename: string\n prefix?: string\n}) => Promise<string> | string\n\nexport type StaticHandler = (\n req: PayloadRequest,\n args: {\n doc?: TypeWithID\n headers?: Headers\n params: { collection: string; filename: string; prefix?: string; uploadReference?: unknown }\n },\n) => Promise<Response> | Response\n\nexport interface GeneratedAdapter {\n /**\n * Additional fields to be injected into the base collection and image sizes\n */\n fields?: Field[]\n /**\n * Generates the public URL for a file\n */\n generateURL?: GenerateURL\n handleDelete: HandleDelete\n handleUpload: HandleUpload\n name: string\n onInit?: () => Promise<void> | void\n staticHandler: StaticHandler\n /** Generates upload instructions when supported. */\n uploadInstructions?: {\n adminHandler?: {\n path: string\n props?: Record<string, unknown>\n }\n enabled: boolean\n endpoint?: {\n handler: PayloadHandler\n path: `/${string}`\n }\n } & UploadInstructionsCapability\n}\n\nexport type Adapter = (args: { collection: CollectionConfig; prefix?: string }) => GeneratedAdapter\n\nexport type AllowList = Array<{\n hostname: string\n pathname?: string\n port?: string\n protocol?: 'http' | 'https'\n search?: string\n}>\n\nexport type GenerateFileURL = (args: {\n collection: CollectionConfig\n filename: string\n prefix?: string\n size?: ImageSize\n}) => Promise<string> | string\n\nexport interface CollectionOptions {\n adapter: Adapter | null\n disableLocalStorage?: boolean\n disablePayloadAccessControl?: true\n generateFileURL?: GenerateFileURL\n prefix?: string\n}\n\nexport interface PluginOptions {\n collections: Partial<Record<UploadCollectionSlug, CollectionOptions>>\n /**\n * Whether or not to enable the plugin\n *\n * Default: true\n */\n enabled?: boolean\n /**\n * When true (compositional prefixes), the stored `prefix` field is only the\n * document-level segment; the collection prefix comes from plugin options and\n * must not be pre-filled as the field default.\n *\n * Set by storage adapters that support compositional prefixes (e.g. S3, Azure, R2, Vercel Blob, GCS).\n *\n * @default false\n */\n useCompositePrefixes?: boolean\n}\n"],"names":[],"mappings":"AAsIA,WAkBC"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type {\n CollectionConfig,\n Field,\n FileData,\n FileHandlerOperation,\n ImageSize,\n PayloadHandler,\n PayloadRequest,\n SanitizedCollectionConfig,\n TypeWithID,\n UploadCollectionSlug,\n UploadInstructionsAccess,\n UploadInstructionsCapability,\n} from 'payload'\n\nexport type { FileHandlerOperation } from 'payload'\n\nexport interface File {\n buffer: Buffer\n filename: string\n filesize: number\n mimeType: string\n tempFilePath?: string\n uploadReference?: unknown\n}\n\nexport type ClientUploadsConfig = { access?: UploadInstructionsAccess } | boolean\n\n/**\n * Reference to a client-uploaded object, returned by an upload handler and\n * submitted with the document. Always carries the signed receipt; `prefix`\n * locates the stored object.\n */\nexport type UploadReference = {\n _objectKey?: string\n prefix: string\n signedReceipt: `${string}.${string}`\n}\n\nexport type HandleUpload = (args: {\n collection: CollectionConfig\n data: any\n file: File\n req: PayloadRequest\n /**\n * Pre-resolved storage path (`_objectKey` folded in, contained beneath the collection prefix).\n */\n storageFilePath: string\n}) =>\n | Partial<FileData & TypeWithID>\n | Promise<Partial<FileData & TypeWithID>>\n | Promise<void>\n | void\n\nexport interface TypeWithPrefix {\n prefix?: string\n}\n\nexport type HandleDelete = (args: {\n collection: CollectionConfig\n doc: FileData & TypeWithID & TypeWithPrefix\n filename: string\n req: PayloadRequest\n /**\n * Pre-resolved storage path of the object to delete.\n */\n storageFilePath: string\n}) => Promise<void> | void\n\n/** Deletes a stored object without requiring a saved document. */\nexport type DeleteFile = (args: {\n collection: CollectionConfig\n req: PayloadRequest\n /** Complete storage path, with prefixes and `_objectKey` already resolved. */\n storageFilePath: string\n}) => Promise<void> | void\n\n/** Complete storage keys are resolved before invoking a provider operation. */\nexport type FileOperationArgs = {\n collection: SanitizedCollectionConfig\n from: string\n mimeType?: string\n req: PayloadRequest\n to: string\n}\n\nexport type CopyFile = (args: FileOperationArgs) => Promise<void>\nexport type MoveFile = (args: FileOperationArgs) => Promise<void>\n\nexport type GenerateURL = (args: {\n collection: CollectionConfig\n data: any\n filename: string\n prefix?: string\n}) => Promise<string> | string\n\nexport type StaticHandler = (\n req: PayloadRequest,\n args: {\n doc?: TypeWithID\n headers?: Headers\n params: {\n collection: string\n filename: string\n operation?: FileHandlerOperation\n prefix?: string\n uploadReference?: unknown\n }\n },\n) => Promise<Response> | Response\n\nexport interface GeneratedAdapter {\n /** Preserve object metadata and fail if `to` already exists. Rename retains `from` for history. */\n copyFile: CopyFile\n deleteFile: DeleteFile\n /**\n * Additional fields to be injected into the base collection and image sizes\n */\n fields?: Field[]\n /**\n * Generates the public URL for a file\n */\n generateURL?: GenerateURL\n handleDelete: HandleDelete\n handleUpload: HandleUpload\n moveFile?: MoveFile\n name: string\n onInit?: () => Promise<void> | void\n staticHandler: StaticHandler\n /** Reads source files by path when staging server-mediated uploads. */\n supportsTempFiles?: boolean\n /** Generates upload instructions when supported. */\n uploadInstructions?: {\n adminHandler?: {\n path: string\n props?: Record<string, unknown>\n }\n enabled: boolean\n endpoint?: {\n handler: PayloadHandler\n path: `/${string}`\n }\n } & UploadInstructionsCapability\n}\n\nexport type Adapter = (args: { collection: CollectionConfig; prefix?: string }) => GeneratedAdapter\n\nexport type AllowList = Array<{\n hostname: string\n pathname?: string\n port?: string\n protocol?: 'http' | 'https'\n search?: string\n}>\n\nexport type GenerateFileURL = (args: {\n collection: CollectionConfig\n filename: string\n prefix?: string\n size?: ImageSize\n}) => Promise<string> | string\n\nexport interface CollectionOptions {\n adapter: Adapter | null\n disableLocalStorage?: boolean\n disablePayloadAccessControl?: true\n generateFileURL?: GenerateFileURL\n prefix?: string\n}\n\nexport interface PluginOptions {\n collections: Partial<Record<UploadCollectionSlug, CollectionOptions>>\n /**\n * Whether or not to enable the plugin\n *\n * Default: true\n */\n enabled?: boolean\n /**\n * When true (compositional prefixes), the stored `prefix` field is only the\n * document-level segment; the collection prefix comes from plugin options and\n * must not be pre-filled as the field default.\n *\n * Set by storage adapters that support compositional prefixes (e.g. S3, Azure, R2, Vercel Blob, GCS).\n *\n * @default false\n */\n useCompositePrefixes?: boolean\n}\n"],"names":[],"mappings":"AA0KA,WAkBC"}
@@ -0,0 +1,13 @@
1
+ import type { CollectionConfig, UploadConfig } from 'payload';
2
+ import type { GeneratedAdapter, GenerateFileURL } from '../types.js';
3
+ type Args = {
4
+ adapter: GeneratedAdapter;
5
+ collection: CollectionConfig;
6
+ collectionPrefix?: string;
7
+ disablePayloadAccessControl?: boolean;
8
+ generateFileURL?: GenerateFileURL;
9
+ useCompositePrefixes?: boolean;
10
+ };
11
+ export declare const createFileOperations: ({ adapter, collection, collectionPrefix, disablePayloadAccessControl, generateFileURL, useCompositePrefixes, }: Args) => NonNullable<UploadConfig['fileOperations']>;
12
+ export {};
13
+ //# sourceMappingURL=createFileOperations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createFileOperations.d.ts","sourceRoot":"","sources":["../../src/utilities/createFileOperations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAyB,YAAY,EAAE,MAAM,SAAS,CAAA;AAOpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AASpE,KAAK,IAAI,GAAG;IACV,OAAO,EAAE,gBAAgB,CAAA;IACzB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,CAAA;AAED,eAAO,MAAM,oBAAoB,mHAO9B,IAAI,KAAG,WAAW,CAAC,YAAY,CAAC,gBAAgB,CAAC,CA+OnD,CAAA"}
@@ -0,0 +1,258 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { isDeepStrictEqual } from 'node:util';
4
+ import { deepCopyObjectSimple, generatePayloadFileURL } from 'payload';
5
+ import { buildPrefixWithObjectKey } from './buildPrefixWithObjectKey.js';
6
+ import { buildStoragePathData, buildUploadPrefix, buildUploadStoragePathData } from './buildStoragePathData.js';
7
+ export const createFileOperations = ({ adapter, collection, collectionPrefix, disablePayloadAccessControl, generateFileURL, useCompositePrefixes })=>{
8
+ if (typeof adapter.deleteFile !== 'function') {
9
+ throw new Error(`Storage adapter "${adapter.name}" must implement deleteFile for collection "${collection.slug}".`);
10
+ }
11
+ return {
12
+ copy: async ({ from, req, to, trackStagedObject })=>{
13
+ await adapter.copyFile({
14
+ collection: req.payload.collections[collection.slug].config,
15
+ from,
16
+ req,
17
+ to
18
+ });
19
+ trackStagedObject({
20
+ key: to,
21
+ remove: async ()=>{
22
+ await adapter.deleteFile({
23
+ collection,
24
+ req,
25
+ storageFilePath: to
26
+ });
27
+ }
28
+ });
29
+ },
30
+ delete: async ({ key, req })=>{
31
+ await adapter.deleteFile({
32
+ collection,
33
+ req,
34
+ storageFilePath: key
35
+ });
36
+ },
37
+ hasLegacyFile: async ({ doc, req })=>{
38
+ if (typeof doc.filename !== 'string' || typeof doc.url !== 'string') {
39
+ return false;
40
+ }
41
+ const docPrefix = typeof doc.prefix === 'string' ? doc.prefix : undefined;
42
+ const objectFolder = buildPrefixWithObjectKey({
43
+ objectKey: typeof doc._objectKey === 'string' ? doc._objectKey : undefined,
44
+ prefix: docPrefix
45
+ });
46
+ const expectedURL = async ({ filename, size })=>{
47
+ if (generateFileURL) {
48
+ return generateFileURL({
49
+ collection,
50
+ filename,
51
+ prefix: objectFolder,
52
+ size
53
+ });
54
+ }
55
+ if (disablePayloadAccessControl && adapter.generateURL) {
56
+ return adapter.generateURL({
57
+ collection,
58
+ data: doc,
59
+ filename,
60
+ prefix: objectFolder
61
+ });
62
+ }
63
+ return generatePayloadFileURL({
64
+ collectionSlug: collection.slug,
65
+ config: req.payload.config,
66
+ filename,
67
+ relative: true
68
+ });
69
+ };
70
+ if (!isSameFileLocation({
71
+ actual: doc.url,
72
+ expected: await expectedURL({
73
+ filename: doc.filename
74
+ })
75
+ })) {
76
+ return false;
77
+ }
78
+ if (doc.variants && typeof doc.variants === 'object' && !Array.isArray(doc.variants)) {
79
+ for (const [sizeKey, size] of Object.entries(doc.variants)){
80
+ if (size && typeof size === 'object' && 'filename' in size && typeof size.filename === 'string') {
81
+ const imageSize = req.payload.collections[collection.slug]?.config.upload.variants?.find(({ name })=>name === sizeKey);
82
+ if (!('url' in size) || typeof size.url !== 'string' || !isSameFileLocation({
83
+ actual: size.url,
84
+ expected: await expectedURL({
85
+ filename: size.filename,
86
+ size: imageSize
87
+ })
88
+ })) {
89
+ return false;
90
+ }
91
+ }
92
+ }
93
+ }
94
+ return true;
95
+ },
96
+ resolveStorageKey: ({ _objectKey, filename, prefix })=>buildStoragePathData({
97
+ collectionPrefix,
98
+ docPrefix: buildPrefixWithObjectKey({
99
+ objectKey: _objectKey,
100
+ prefix
101
+ }),
102
+ filename,
103
+ useCompositePrefixes
104
+ }).storageFilePath,
105
+ ...adapter.moveFile && {
106
+ move: async ({ from, req, to, trackStagedObject })=>{
107
+ await adapter.moveFile({
108
+ collection: req.payload.collections[collection.slug].config,
109
+ from,
110
+ req,
111
+ to
112
+ });
113
+ trackStagedObject({
114
+ key: to,
115
+ remove: ()=>adapter.moveFile({
116
+ collection: req.payload.collections[collection.slug].config,
117
+ from: to,
118
+ req,
119
+ to: from
120
+ })
121
+ });
122
+ }
123
+ },
124
+ stage: async ({ data, files, req, trackStagedObject })=>{
125
+ const uploadedNames = new Set();
126
+ const metadata = {};
127
+ const verifiedOriginal = req.context?._payloadVerifiedProviderOriginal;
128
+ for (const file of files){
129
+ const filename = path.basename(file.path);
130
+ const representations = [
131
+ data
132
+ ];
133
+ if (data.original && typeof data.original === 'object') {
134
+ representations.push(data.original);
135
+ }
136
+ if (data.variants && typeof data.variants === 'object') {
137
+ representations.push(...Object.values(data.variants).filter((value)=>Boolean(value) && typeof value === 'object'));
138
+ }
139
+ const destinations = representations.filter((value)=>value.filename === filename);
140
+ // Provider-direct uploads already placed the source object at its verified location.
141
+ // A bounded content probe can still appear in files, but it is not a representation
142
+ // Payload should upload again.
143
+ if (!destinations.length && verifiedOriginal) {
144
+ continue;
145
+ }
146
+ if (!destinations.length) {
147
+ throw new Error(`No stored representation describes ${filename}`);
148
+ }
149
+ const prefixLocation = destinations.find((destination)=>typeof destination.prefix === 'string');
150
+ const objectKeyLocation = destinations.find((destination)=>typeof destination._objectKey === 'string');
151
+ const prefix = typeof prefixLocation?.prefix === 'string' ? prefixLocation.prefix : undefined;
152
+ const objectKey = typeof objectKeyLocation?._objectKey === 'string' ? objectKeyLocation._objectKey : undefined;
153
+ const prefixData = buildUploadPrefix({
154
+ collectionPrefix,
155
+ docPrefix: typeof prefix === 'string' ? prefix : undefined,
156
+ useCompositePrefixes
157
+ });
158
+ const uploadPrefix = useCompositePrefixes ? prefixData.sanitizedDocPrefix : prefixData.uploadPrefix;
159
+ for (const destination of destinations){
160
+ destination.prefix = uploadPrefix;
161
+ destination._objectKey = objectKey;
162
+ }
163
+ const docPrefix = buildPrefixWithObjectKey({
164
+ objectKey,
165
+ prefix: uploadPrefix
166
+ });
167
+ const dataForUpload = {
168
+ ...data,
169
+ prefix: docPrefix
170
+ };
171
+ const storageFilePath = buildUploadStoragePathData({
172
+ collectionPrefix,
173
+ docPrefix,
174
+ filename,
175
+ useCompositePrefixes
176
+ }).storageFilePath;
177
+ if (uploadedNames.has(filename)) {
178
+ throw new Error(`Duplicate managed cloud filename: ${filename}`);
179
+ }
180
+ uploadedNames.add(filename);
181
+ const buffer = 'buffer' in file ? file.buffer : adapter.supportsTempFiles ? Buffer.alloc(0) : await fs.readFile(file.sourcePath);
182
+ const uploadFile = {
183
+ buffer,
184
+ filename,
185
+ filesize: 'buffer' in file ? file.buffer.length : (await fs.stat(file.sourcePath)).size,
186
+ mimeType: getMimeType({
187
+ data,
188
+ filename
189
+ }),
190
+ ...'sourcePath' in file ? {
191
+ tempFilePath: file.sourcePath
192
+ } : {}
193
+ };
194
+ // A new object folder is allocated for every server upload, so an interrupted
195
+ // provider write can be removed without touching an earlier revision.
196
+ trackStagedObject({
197
+ key: storageFilePath,
198
+ remove: async ()=>{
199
+ await adapter.deleteFile({
200
+ collection,
201
+ req,
202
+ storageFilePath
203
+ });
204
+ }
205
+ });
206
+ const dataBeforeUpload = deepCopyObjectSimple(dataForUpload);
207
+ const result = await adapter.handleUpload({
208
+ collection,
209
+ data: dataForUpload,
210
+ file: uploadFile,
211
+ req,
212
+ storageFilePath
213
+ });
214
+ if (result && typeof result === 'object') {
215
+ // Adapters may return the entire input document, including fields made stale by this upload.
216
+ for (const [key, value] of Object.entries(result)){
217
+ if (!isDeepStrictEqual(value, dataBeforeUpload[key])) {
218
+ metadata[key] = value;
219
+ }
220
+ }
221
+ }
222
+ }
223
+ delete metadata.prefix;
224
+ delete metadata._objectKey;
225
+ return {
226
+ metadata
227
+ };
228
+ }
229
+ };
230
+ };
231
+ const getMimeType = ({ data, filename })=>{
232
+ if (data.original && typeof data.original === 'object') {
233
+ const original = data.original;
234
+ if (original.filename === filename && original.mimeType) {
235
+ return original.mimeType;
236
+ }
237
+ }
238
+ if (data.variants && typeof data.variants === 'object') {
239
+ for (const size of Object.values(data.variants)){
240
+ const candidate = size;
241
+ if (candidate?.filename === filename && candidate.mimeType) {
242
+ return candidate.mimeType;
243
+ }
244
+ }
245
+ }
246
+ return typeof data.mimeType === 'string' ? data.mimeType : 'application/octet-stream';
247
+ };
248
+ /** Signed and time-limited URLs change their query on every generation, so only the location is compared. */ const isSameFileLocation = ({ actual, expected })=>typeof expected === 'string' && getFileLocation({
249
+ url: actual
250
+ }) === getFileLocation({
251
+ url: expected
252
+ });
253
+ const getFileLocation = ({ url })=>{
254
+ const parsed = new URL(url, 'http://payload.local');
255
+ return url.startsWith('/') ? parsed.pathname : `${parsed.origin}${parsed.pathname}`;
256
+ };
257
+
258
+ //# sourceMappingURL=createFileOperations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/createFileOperations.ts"],"sourcesContent":["import type { CollectionConfig, ImageSize, JsonObject, UploadConfig } from 'payload'\n\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { isDeepStrictEqual } from 'node:util'\nimport { deepCopyObjectSimple, generatePayloadFileURL } from 'payload'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport { buildPrefixWithObjectKey } from './buildPrefixWithObjectKey.js'\nimport {\n buildStoragePathData,\n buildUploadPrefix,\n buildUploadStoragePathData,\n} from './buildStoragePathData.js'\n\ntype Args = {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n collectionPrefix?: string\n disablePayloadAccessControl?: boolean\n generateFileURL?: GenerateFileURL\n useCompositePrefixes?: boolean\n}\n\nexport const createFileOperations = ({\n adapter,\n collection,\n collectionPrefix,\n disablePayloadAccessControl,\n generateFileURL,\n useCompositePrefixes,\n}: Args): NonNullable<UploadConfig['fileOperations']> => {\n if (typeof adapter.deleteFile !== 'function') {\n throw new Error(\n `Storage adapter \"${adapter.name}\" must implement deleteFile for collection \"${collection.slug}\".`,\n )\n }\n\n return {\n copy: async ({ from, req, to, trackStagedObject }) => {\n await adapter.copyFile({\n collection: req.payload.collections[collection.slug]!.config,\n from,\n req,\n to,\n })\n trackStagedObject({\n key: to,\n remove: async () => {\n await adapter.deleteFile({\n collection,\n req,\n storageFilePath: to,\n })\n },\n })\n },\n delete: async ({ key, req }) => {\n await adapter.deleteFile({\n collection,\n req,\n storageFilePath: key,\n })\n },\n hasLegacyFile: async ({ doc, req }) => {\n if (typeof doc.filename !== 'string' || typeof doc.url !== 'string') {\n return false\n }\n\n const docPrefix = typeof doc.prefix === 'string' ? doc.prefix : undefined\n const objectFolder = buildPrefixWithObjectKey({\n objectKey: typeof doc._objectKey === 'string' ? doc._objectKey : undefined,\n prefix: docPrefix,\n })\n const expectedURL = async ({ filename, size }: { filename: string; size?: ImageSize }) => {\n if (generateFileURL) {\n return generateFileURL({ collection, filename, prefix: objectFolder, size })\n }\n if (disablePayloadAccessControl && adapter.generateURL) {\n return adapter.generateURL({ collection, data: doc, filename, prefix: objectFolder })\n }\n return generatePayloadFileURL({\n collectionSlug: collection.slug,\n config: req.payload.config as unknown as Parameters<\n typeof generatePayloadFileURL\n >[0]['config'],\n filename,\n relative: true,\n })\n }\n if (\n !isSameFileLocation({\n actual: doc.url,\n expected: await expectedURL({ filename: doc.filename }),\n })\n ) {\n return false\n }\n if (doc.variants && typeof doc.variants === 'object' && !Array.isArray(doc.variants)) {\n for (const [sizeKey, size] of Object.entries(doc.variants)) {\n if (\n size &&\n typeof size === 'object' &&\n 'filename' in size &&\n typeof size.filename === 'string'\n ) {\n const imageSize = req.payload.collections[\n collection.slug\n ]?.config.upload.variants?.find(({ name }) => name === sizeKey)\n if (\n !('url' in size) ||\n typeof size.url !== 'string' ||\n !isSameFileLocation({\n actual: size.url,\n expected: await expectedURL({ filename: size.filename, size: imageSize }),\n })\n ) {\n return false\n }\n }\n }\n }\n return true\n },\n resolveStorageKey: ({ _objectKey, filename, prefix }) =>\n buildStoragePathData({\n collectionPrefix,\n docPrefix: buildPrefixWithObjectKey({ objectKey: _objectKey, prefix }),\n filename,\n useCompositePrefixes,\n }).storageFilePath,\n ...(adapter.moveFile && {\n move: async ({ from, req, to, trackStagedObject }) => {\n await adapter.moveFile!({\n collection: req.payload.collections[collection.slug]!.config,\n from,\n req,\n to,\n })\n trackStagedObject({\n key: to,\n remove: () =>\n adapter.moveFile!({\n collection: req.payload.collections[collection.slug]!.config,\n from: to,\n req,\n to: from,\n }),\n })\n },\n }),\n stage: async ({ data, files, req, trackStagedObject }) => {\n const uploadedNames = new Set<string>()\n const metadata: Record<string, unknown> = {}\n const verifiedOriginal = req.context?._payloadVerifiedProviderOriginal as\n | { filename: string }\n | undefined\n for (const file of files) {\n const filename = path.basename(file.path)\n const representations: Record<string, unknown>[] = [data]\n if (data.original && typeof data.original === 'object') {\n representations.push(data.original as Record<string, unknown>)\n }\n if (data.variants && typeof data.variants === 'object') {\n representations.push(\n ...Object.values(data.variants).filter(\n (value): value is Record<string, unknown> =>\n Boolean(value) && typeof value === 'object',\n ),\n )\n }\n const destinations = representations.filter((value) => value.filename === filename)\n // Provider-direct uploads already placed the source object at its verified location.\n // A bounded content probe can still appear in files, but it is not a representation\n // Payload should upload again.\n if (!destinations.length && verifiedOriginal) {\n continue\n }\n if (!destinations.length) {\n throw new Error(`No stored representation describes ${filename}`)\n }\n const prefixLocation = destinations.find(\n (destination) => typeof destination.prefix === 'string',\n )\n const objectKeyLocation = destinations.find(\n (destination) => typeof destination._objectKey === 'string',\n )\n const prefix =\n typeof prefixLocation?.prefix === 'string' ? prefixLocation.prefix : undefined\n const objectKey =\n typeof objectKeyLocation?._objectKey === 'string'\n ? objectKeyLocation._objectKey\n : undefined\n const prefixData = buildUploadPrefix({\n collectionPrefix,\n docPrefix: typeof prefix === 'string' ? prefix : undefined,\n useCompositePrefixes,\n })\n const uploadPrefix = useCompositePrefixes\n ? prefixData.sanitizedDocPrefix\n : prefixData.uploadPrefix\n for (const destination of destinations) {\n destination.prefix = uploadPrefix\n destination._objectKey = objectKey\n }\n const docPrefix = buildPrefixWithObjectKey({ objectKey, prefix: uploadPrefix })\n const dataForUpload = { ...data, prefix: docPrefix }\n const storageFilePath = buildUploadStoragePathData({\n collectionPrefix,\n docPrefix,\n filename,\n useCompositePrefixes,\n }).storageFilePath\n\n if (uploadedNames.has(filename)) {\n throw new Error(`Duplicate managed cloud filename: ${filename}`)\n }\n\n uploadedNames.add(filename)\n const buffer =\n 'buffer' in file\n ? file.buffer\n : adapter.supportsTempFiles\n ? Buffer.alloc(0)\n : await fs.readFile(file.sourcePath)\n const uploadFile = {\n buffer,\n filename,\n filesize: 'buffer' in file ? file.buffer.length : (await fs.stat(file.sourcePath)).size,\n mimeType: getMimeType({ data, filename }),\n ...('sourcePath' in file ? { tempFilePath: file.sourcePath } : {}),\n }\n\n // A new object folder is allocated for every server upload, so an interrupted\n // provider write can be removed without touching an earlier revision.\n trackStagedObject({\n key: storageFilePath,\n remove: async () => {\n await adapter.deleteFile({\n collection,\n req,\n storageFilePath,\n })\n },\n })\n\n const dataBeforeUpload = deepCopyObjectSimple(dataForUpload as JsonObject)\n const result = await adapter.handleUpload({\n collection,\n data: dataForUpload,\n file: uploadFile,\n req,\n storageFilePath,\n })\n\n if (result && typeof result === 'object') {\n // Adapters may return the entire input document, including fields made stale by this upload.\n for (const [key, value] of Object.entries(result)) {\n if (!isDeepStrictEqual(value, dataBeforeUpload[key])) {\n metadata[key] = value\n }\n }\n }\n }\n\n delete metadata.prefix\n delete metadata._objectKey\n return { metadata }\n },\n }\n}\n\nconst getMimeType = ({\n data,\n filename,\n}: {\n data: Record<string, unknown>\n filename: string\n}): string => {\n if (data.original && typeof data.original === 'object') {\n const original = data.original as { filename?: string; mimeType?: string }\n if (original.filename === filename && original.mimeType) {\n return original.mimeType\n }\n }\n if (data.variants && typeof data.variants === 'object') {\n for (const size of Object.values(data.variants)) {\n const candidate = size as { filename?: string; mimeType?: string } | null\n if (candidate?.filename === filename && candidate.mimeType) {\n return candidate.mimeType\n }\n }\n }\n return typeof data.mimeType === 'string' ? data.mimeType : 'application/octet-stream'\n}\n\n/** Signed and time-limited URLs change their query on every generation, so only the location is compared. */\nconst isSameFileLocation = ({\n actual,\n expected,\n}: {\n actual: string\n expected: null | string | undefined\n}): boolean =>\n typeof expected === 'string' &&\n getFileLocation({ url: actual }) === getFileLocation({ url: expected })\n\nconst getFileLocation = ({ url }: { url: string }): string => {\n const parsed = new URL(url, 'http://payload.local')\n\n return url.startsWith('/') ? parsed.pathname : `${parsed.origin}${parsed.pathname}`\n}\n"],"names":["fs","path","isDeepStrictEqual","deepCopyObjectSimple","generatePayloadFileURL","buildPrefixWithObjectKey","buildStoragePathData","buildUploadPrefix","buildUploadStoragePathData","createFileOperations","adapter","collection","collectionPrefix","disablePayloadAccessControl","generateFileURL","useCompositePrefixes","deleteFile","Error","name","slug","copy","from","req","to","trackStagedObject","copyFile","payload","collections","config","key","remove","storageFilePath","delete","hasLegacyFile","doc","filename","url","docPrefix","prefix","undefined","objectFolder","objectKey","_objectKey","expectedURL","size","generateURL","data","collectionSlug","relative","isSameFileLocation","actual","expected","variants","Array","isArray","sizeKey","Object","entries","imageSize","upload","find","resolveStorageKey","moveFile","move","stage","files","uploadedNames","Set","metadata","verifiedOriginal","context","_payloadVerifiedProviderOriginal","file","basename","representations","original","push","values","filter","value","Boolean","destinations","length","prefixLocation","destination","objectKeyLocation","prefixData","uploadPrefix","sanitizedDocPrefix","dataForUpload","has","add","buffer","supportsTempFiles","Buffer","alloc","readFile","sourcePath","uploadFile","filesize","stat","mimeType","getMimeType","tempFilePath","dataBeforeUpload","result","handleUpload","candidate","getFileLocation","parsed","URL","startsWith","pathname","origin"],"mappings":"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"}