@payloadcms/plugin-cloud-storage 4.0.0-internal.f05c47f → 4.0.0-internal.f15737c

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 (76) hide show
  1. package/README.md +2 -0
  2. package/dist/exports/client.d.ts +1 -1
  3. package/dist/exports/client.d.ts.map +1 -1
  4. package/dist/exports/client.js +1 -1
  5. package/dist/exports/client.js.map +1 -1
  6. package/dist/exports/utilities.d.ts +1 -1
  7. package/dist/exports/utilities.d.ts.map +1 -1
  8. package/dist/exports/utilities.js +1 -1
  9. package/dist/exports/utilities.js.map +1 -1
  10. package/dist/fields/getFields.d.ts +1 -5
  11. package/dist/fields/getFields.d.ts.map +1 -1
  12. package/dist/fields/getFields.js +54 -22
  13. package/dist/fields/getFields.js.map +1 -1
  14. package/dist/hooks/afterChange.d.ts +3 -1
  15. package/dist/hooks/afterChange.d.ts.map +1 -1
  16. package/dist/hooks/afterChange.js +78 -22
  17. package/dist/hooks/afterChange.js.map +1 -1
  18. package/dist/hooks/afterDelete.d.ts +3 -1
  19. package/dist/hooks/afterDelete.d.ts.map +1 -1
  20. package/dist/hooks/afterDelete.js +17 -3
  21. package/dist/hooks/afterDelete.js.map +1 -1
  22. package/dist/hooks/afterRead.d.ts.map +1 -1
  23. package/dist/hooks/afterRead.js +16 -3
  24. package/dist/hooks/afterRead.js.map +1 -1
  25. package/dist/hooks/beforeChange.d.ts.map +1 -1
  26. package/dist/hooks/beforeChange.js +14 -3
  27. package/dist/hooks/beforeChange.js.map +1 -1
  28. package/dist/hooks/normalizeUploadPrefix.d.ts +11 -0
  29. package/dist/hooks/normalizeUploadPrefix.d.ts.map +1 -0
  30. package/dist/hooks/normalizeUploadPrefix.js +42 -0
  31. package/dist/hooks/normalizeUploadPrefix.js.map +1 -0
  32. package/dist/plugin.d.ts.map +1 -1
  33. package/dist/plugin.js +43 -38
  34. package/dist/plugin.js.map +1 -1
  35. package/dist/types.d.ts +22 -12
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/types.js.map +1 -1
  38. package/dist/utilities/buildPrefixWithObjectKey.d.ts +8 -0
  39. package/dist/utilities/buildPrefixWithObjectKey.d.ts.map +1 -0
  40. package/dist/utilities/buildPrefixWithObjectKey.js +13 -0
  41. package/dist/utilities/buildPrefixWithObjectKey.js.map +1 -0
  42. package/dist/utilities/buildStoragePathData.d.ts +49 -0
  43. package/dist/utilities/buildStoragePathData.d.ts.map +1 -0
  44. package/dist/utilities/buildStoragePathData.js +67 -0
  45. package/dist/utilities/buildStoragePathData.js.map +1 -0
  46. package/dist/utilities/getFilePrefix.d.ts +18 -10
  47. package/dist/utilities/getFilePrefix.d.ts.map +1 -1
  48. package/dist/utilities/getFilePrefix.js +70 -30
  49. package/dist/utilities/getFilePrefix.js.map +1 -1
  50. package/dist/utilities/getIncomingFiles.js +2 -2
  51. package/dist/utilities/getIncomingFiles.js.map +1 -1
  52. package/dist/utilities/resolveSignedURLKey.d.ts +12 -1
  53. package/dist/utilities/resolveSignedURLKey.d.ts.map +1 -1
  54. package/dist/utilities/resolveSignedURLKey.js +42 -8
  55. package/dist/utilities/resolveSignedURLKey.js.map +1 -1
  56. package/dist/utilities/sanitizePrefix.d.ts +1 -9
  57. package/dist/utilities/sanitizePrefix.d.ts.map +1 -1
  58. package/dist/utilities/sanitizePrefix.js +1 -21
  59. package/dist/utilities/sanitizePrefix.js.map +1 -1
  60. package/package.json +6 -6
  61. package/dist/admin/fields/getFields.d.ts +0 -17
  62. package/dist/admin/fields/getFields.d.ts.map +0 -1
  63. package/dist/admin/fields/getFields.js +0 -98
  64. package/dist/admin/fields/getFields.js.map +0 -1
  65. package/dist/admin/index.d.ts +0 -4
  66. package/dist/admin/index.d.ts.map +0 -1
  67. package/dist/admin/index.js +0 -34
  68. package/dist/admin/index.js.map +0 -1
  69. package/dist/utilities/getFileKey.d.ts +0 -22
  70. package/dist/utilities/getFileKey.d.ts.map +0 -1
  71. package/dist/utilities/getFileKey.js +0 -23
  72. package/dist/utilities/getFileKey.js.map +0 -1
  73. package/dist/utilities/getFileKey.spec.js +0 -174
  74. package/dist/utilities/getFileKey.spec.js.map +0 -1
  75. package/dist/utilities/getFilePrefix.spec.js +0 -105
  76. package/dist/utilities/getFilePrefix.spec.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/afterRead.ts"],"sourcesContent":["import type { CollectionConfig, FieldHook, ImageSize } from 'payload'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n disablePayloadAccessControl?: boolean\n generateFileURL?: GenerateFileURL\n size?: ImageSize\n}\n\nexport const getAfterReadHook =\n ({ adapter, collection, disablePayloadAccessControl, generateFileURL, size }: Args): FieldHook =>\n async ({ data, value }) => {\n const filename = size ? data?.sizes?.[size.name]?.filename : data?.filename\n const prefix = data?.prefix\n let url = value\n\n if (filename) {\n if (generateFileURL) {\n url = await generateFileURL({\n collection,\n filename,\n prefix,\n size,\n })\n } else if (disablePayloadAccessControl && adapter.generateURL) {\n url = await adapter.generateURL({\n collection,\n data,\n filename,\n prefix,\n })\n } else if (url && prefix) {\n const separator = url.includes('?') ? '&' : '?'\n url = `${url}${separator}prefix=${encodeURIComponent(prefix)}`\n }\n }\n\n return url\n }\n"],"names":["getAfterReadHook","adapter","collection","disablePayloadAccessControl","generateFileURL","size","data","value","filename","sizes","name","prefix","url","generateURL","separator","includes","encodeURIComponent"],"mappings":"AAYA,OAAO,MAAMA,mBACX,CAAC,EAAEC,OAAO,EAAEC,UAAU,EAAEC,2BAA2B,EAAEC,eAAe,EAAEC,IAAI,EAAQ,GAClF,OAAO,EAAEC,IAAI,EAAEC,KAAK,EAAE;QACpB,MAAMC,WAAWH,OAAOC,MAAMG,OAAO,CAACJ,KAAKK,IAAI,CAAC,EAAEF,WAAWF,MAAME;QACnE,MAAMG,SAASL,MAAMK;QACrB,IAAIC,MAAML;QAEV,IAAIC,UAAU;YACZ,IAAIJ,iBAAiB;gBACnBQ,MAAM,MAAMR,gBAAgB;oBAC1BF;oBACAM;oBACAG;oBACAN;gBACF;YACF,OAAO,IAAIF,+BAA+BF,QAAQY,WAAW,EAAE;gBAC7DD,MAAM,MAAMX,QAAQY,WAAW,CAAC;oBAC9BX;oBACAI;oBACAE;oBACAG;gBACF;YACF,OAAO,IAAIC,OAAOD,QAAQ;gBACxB,MAAMG,YAAYF,IAAIG,QAAQ,CAAC,OAAO,MAAM;gBAC5CH,MAAM,GAAGA,MAAME,UAAU,OAAO,EAAEE,mBAAmBL,SAAS;YAChE;QACF;QAEA,OAAOC;IACT,EAAC"}
1
+ {"version":3,"sources":["../../src/hooks/afterRead.ts"],"sourcesContent":["import type { CollectionConfig, FieldHook, ImageSize } from 'payload'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport { sanitizePrefix } from '../utilities/sanitizePrefix.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n disablePayloadAccessControl?: boolean\n generateFileURL?: GenerateFileURL\n size?: ImageSize\n}\n\n// The object's folder: semantic prefix + `_objectKey` segment.\nconst getObjectFolder = (data: unknown): string => {\n const record = (data ?? {}) as Record<string, unknown>\n const safePrefix = sanitizePrefix(typeof record.prefix === 'string' ? record.prefix : '')\n const safeObjectKey = sanitizePrefix(\n typeof record._objectKey === 'string' ? record._objectKey : '',\n )\n\n if (safePrefix && safeObjectKey) {\n return `${safePrefix}/${safeObjectKey}`\n }\n\n return safePrefix || safeObjectKey\n}\n\nexport const getAfterReadHook =\n ({ adapter, collection, disablePayloadAccessControl, generateFileURL, size }: Args): FieldHook =>\n async ({ data, value }) => {\n const filename = size ? data?.variants?.[size.name]?.filename : data?.filename\n const prefix = data?.prefix\n // Direct-serve URLs encode the full location; the proxy resolves `_objectKey` server-side.\n const objectFolder = getObjectFolder(data)\n let url = value\n\n if (filename) {\n if (generateFileURL) {\n url = await generateFileURL({\n collection,\n filename,\n prefix: objectFolder,\n size,\n })\n } else if (disablePayloadAccessControl && adapter.generateURL) {\n url = await adapter.generateURL({\n collection,\n data,\n filename,\n prefix: objectFolder,\n })\n } else if (url && prefix) {\n const separator = url.includes('?') ? '&' : '?'\n url = `${url}${separator}prefix=${encodeURIComponent(prefix)}`\n }\n }\n\n return url\n }\n"],"names":["sanitizePrefix","getObjectFolder","data","record","safePrefix","prefix","safeObjectKey","_objectKey","getAfterReadHook","adapter","collection","disablePayloadAccessControl","generateFileURL","size","value","filename","variants","name","objectFolder","url","generateURL","separator","includes","encodeURIComponent"],"mappings":"AAIA,SAASA,cAAc,QAAQ,iCAAgC;AAU/D,+DAA+D;AAC/D,MAAMC,kBAAkB,CAACC;IACvB,MAAMC,SAAUD,QAAQ,CAAC;IACzB,MAAME,aAAaJ,eAAe,OAAOG,OAAOE,MAAM,KAAK,WAAWF,OAAOE,MAAM,GAAG;IACtF,MAAMC,gBAAgBN,eACpB,OAAOG,OAAOI,UAAU,KAAK,WAAWJ,OAAOI,UAAU,GAAG;IAG9D,IAAIH,cAAcE,eAAe;QAC/B,OAAO,GAAGF,WAAW,CAAC,EAAEE,eAAe;IACzC;IAEA,OAAOF,cAAcE;AACvB;AAEA,OAAO,MAAME,mBACX,CAAC,EAAEC,OAAO,EAAEC,UAAU,EAAEC,2BAA2B,EAAEC,eAAe,EAAEC,IAAI,EAAQ,GAClF,OAAO,EAAEX,IAAI,EAAEY,KAAK,EAAE;QACpB,MAAMC,WAAWF,OAAOX,MAAMc,UAAU,CAACH,KAAKI,IAAI,CAAC,EAAEF,WAAWb,MAAMa;QACtE,MAAMV,SAASH,MAAMG;QACrB,2FAA2F;QAC3F,MAAMa,eAAejB,gBAAgBC;QACrC,IAAIiB,MAAML;QAEV,IAAIC,UAAU;YACZ,IAAIH,iBAAiB;gBACnBO,MAAM,MAAMP,gBAAgB;oBAC1BF;oBACAK;oBACAV,QAAQa;oBACRL;gBACF;YACF,OAAO,IAAIF,+BAA+BF,QAAQW,WAAW,EAAE;gBAC7DD,MAAM,MAAMV,QAAQW,WAAW,CAAC;oBAC9BV;oBACAR;oBACAa;oBACAV,QAAQa;gBACV;YACF,OAAO,IAAIC,OAAOd,QAAQ;gBACxB,MAAMgB,YAAYF,IAAIG,QAAQ,CAAC,OAAO,MAAM;gBAC5CH,MAAM,GAAGA,MAAME,UAAU,OAAO,EAAEE,mBAAmBlB,SAAS;YAChE;QACF;QAEA,OAAOc;IACT,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"beforeChange.d.ts","sourceRoot":"","sources":["../../src/hooks/beforeChange.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;AAEpE,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;AAED,eAAO,MAAM,mBAAmB,gFACgD,IAAI,KAAG,SA2BpF,CAAA"}
1
+ {"version":3,"file":"beforeChange.d.ts","sourceRoot":"","sources":["../../src/hooks/beforeChange.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;AAiBD,eAAO,MAAM,mBAAmB,gFACgD,IAAI,KAAG,SA2BpF,CAAA"}
@@ -1,8 +1,19 @@
1
+ import { sanitizePrefix } from '../utilities/sanitizePrefix.js';
2
+ // The object's folder: semantic prefix + `_objectKey` segment.
3
+ const getObjectFolder = (data, originalDoc)=>{
4
+ const source = data ?? originalDoc ?? {};
5
+ const safePrefix = sanitizePrefix(typeof source.prefix === 'string' ? source.prefix : '');
6
+ const safeObjectKey = sanitizePrefix(typeof source._objectKey === 'string' ? source._objectKey : '');
7
+ if (safePrefix && safeObjectKey) {
8
+ return `${safePrefix}/${safeObjectKey}`;
9
+ }
10
+ return safePrefix || safeObjectKey;
11
+ };
1
12
  export const getBeforeChangeHook = ({ adapter, collection, disablePayloadAccessControl, generateFileURL, size })=>async ({ data, originalDoc, value })=>{
2
- const newFilename = size ? data?.sizes?.[size.name]?.filename : data?.filename;
3
- const originalFilename = size ? originalDoc?.sizes?.[size.name]?.filename : originalDoc?.filename;
13
+ const newFilename = size ? data?.variants?.[size.name]?.filename : data?.filename;
14
+ const originalFilename = size ? originalDoc?.variants?.[size.name]?.filename : originalDoc?.filename;
4
15
  const filename = newFilename || originalFilename;
5
- const prefix = data?.prefix;
16
+ const prefix = getObjectFolder(data, originalDoc);
6
17
  let url = value;
7
18
  if (generateFileURL && filename) {
8
19
  url = await generateFileURL({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/beforeChange.ts"],"sourcesContent":["import type { CollectionConfig, FieldHook, ImageSize } from 'payload'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n disablePayloadAccessControl?: boolean\n generateFileURL?: GenerateFileURL\n size?: ImageSize\n}\n\nexport const getBeforeChangeHook =\n ({ adapter, collection, disablePayloadAccessControl, generateFileURL, size }: Args): FieldHook =>\n async ({ data, originalDoc, value }) => {\n const newFilename = size ? data?.sizes?.[size.name]?.filename : data?.filename\n const originalFilename = size\n ? originalDoc?.sizes?.[size.name]?.filename\n : originalDoc?.filename\n const filename = newFilename || originalFilename\n const prefix = data?.prefix\n let url = value\n\n if (generateFileURL && filename) {\n url = await generateFileURL({\n collection,\n filename,\n prefix,\n size,\n })\n } else if (disablePayloadAccessControl && filename && adapter.generateURL) {\n url = await adapter.generateURL({\n collection,\n data: data || originalDoc,\n filename,\n prefix,\n })\n }\n\n return url\n }\n"],"names":["getBeforeChangeHook","adapter","collection","disablePayloadAccessControl","generateFileURL","size","data","originalDoc","value","newFilename","sizes","name","filename","originalFilename","prefix","url","generateURL"],"mappings":"AAYA,OAAO,MAAMA,sBACX,CAAC,EAAEC,OAAO,EAAEC,UAAU,EAAEC,2BAA2B,EAAEC,eAAe,EAAEC,IAAI,EAAQ,GAClF,OAAO,EAAEC,IAAI,EAAEC,WAAW,EAAEC,KAAK,EAAE;QACjC,MAAMC,cAAcJ,OAAOC,MAAMI,OAAO,CAACL,KAAKM,IAAI,CAAC,EAAEC,WAAWN,MAAMM;QACtE,MAAMC,mBAAmBR,OACrBE,aAAaG,OAAO,CAACL,KAAKM,IAAI,CAAC,EAAEC,WACjCL,aAAaK;QACjB,MAAMA,WAAWH,eAAeI;QAChC,MAAMC,SAASR,MAAMQ;QACrB,IAAIC,MAAMP;QAEV,IAAIJ,mBAAmBQ,UAAU;YAC/BG,MAAM,MAAMX,gBAAgB;gBAC1BF;gBACAU;gBACAE;gBACAT;YACF;QACF,OAAO,IAAIF,+BAA+BS,YAAYX,QAAQe,WAAW,EAAE;YACzED,MAAM,MAAMd,QAAQe,WAAW,CAAC;gBAC9Bd;gBACAI,MAAMA,QAAQC;gBACdK;gBACAE;YACF;QACF;QAEA,OAAOC;IACT,EAAC"}
1
+ {"version":3,"sources":["../../src/hooks/beforeChange.ts"],"sourcesContent":["import type { CollectionConfig, FieldHook, ImageSize } from 'payload'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport { sanitizePrefix } from '../utilities/sanitizePrefix.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n disablePayloadAccessControl?: boolean\n generateFileURL?: GenerateFileURL\n size?: ImageSize\n}\n\n// The object's folder: semantic prefix + `_objectKey` segment.\nconst getObjectFolder = (data: unknown, originalDoc: unknown): string => {\n const source = (data ?? originalDoc ?? {}) as Record<string, unknown>\n const safePrefix = sanitizePrefix(typeof source.prefix === 'string' ? source.prefix : '')\n const safeObjectKey = sanitizePrefix(\n typeof source._objectKey === 'string' ? source._objectKey : '',\n )\n\n if (safePrefix && safeObjectKey) {\n return `${safePrefix}/${safeObjectKey}`\n }\n\n return safePrefix || safeObjectKey\n}\n\nexport const getBeforeChangeHook =\n ({ adapter, collection, disablePayloadAccessControl, generateFileURL, size }: Args): FieldHook =>\n async ({ data, originalDoc, value }) => {\n const newFilename = size ? data?.variants?.[size.name]?.filename : data?.filename\n const originalFilename = size\n ? originalDoc?.variants?.[size.name]?.filename\n : originalDoc?.filename\n const filename = newFilename || originalFilename\n const prefix = getObjectFolder(data, originalDoc)\n let url = value\n\n if (generateFileURL && filename) {\n url = await generateFileURL({\n collection,\n filename,\n prefix,\n size,\n })\n } else if (disablePayloadAccessControl && filename && adapter.generateURL) {\n url = await adapter.generateURL({\n collection,\n data: data || originalDoc,\n filename,\n prefix,\n })\n }\n\n return url\n }\n"],"names":["sanitizePrefix","getObjectFolder","data","originalDoc","source","safePrefix","prefix","safeObjectKey","_objectKey","getBeforeChangeHook","adapter","collection","disablePayloadAccessControl","generateFileURL","size","value","newFilename","variants","name","filename","originalFilename","url","generateURL"],"mappings":"AAIA,SAASA,cAAc,QAAQ,iCAAgC;AAU/D,+DAA+D;AAC/D,MAAMC,kBAAkB,CAACC,MAAeC;IACtC,MAAMC,SAAUF,QAAQC,eAAe,CAAC;IACxC,MAAME,aAAaL,eAAe,OAAOI,OAAOE,MAAM,KAAK,WAAWF,OAAOE,MAAM,GAAG;IACtF,MAAMC,gBAAgBP,eACpB,OAAOI,OAAOI,UAAU,KAAK,WAAWJ,OAAOI,UAAU,GAAG;IAG9D,IAAIH,cAAcE,eAAe;QAC/B,OAAO,GAAGF,WAAW,CAAC,EAAEE,eAAe;IACzC;IAEA,OAAOF,cAAcE;AACvB;AAEA,OAAO,MAAME,sBACX,CAAC,EAAEC,OAAO,EAAEC,UAAU,EAAEC,2BAA2B,EAAEC,eAAe,EAAEC,IAAI,EAAQ,GAClF,OAAO,EAAEZ,IAAI,EAAEC,WAAW,EAAEY,KAAK,EAAE;QACjC,MAAMC,cAAcF,OAAOZ,MAAMe,UAAU,CAACH,KAAKI,IAAI,CAAC,EAAEC,WAAWjB,MAAMiB;QACzE,MAAMC,mBAAmBN,OACrBX,aAAac,UAAU,CAACH,KAAKI,IAAI,CAAC,EAAEC,WACpChB,aAAagB;QACjB,MAAMA,WAAWH,eAAeI;QAChC,MAAMd,SAASL,gBAAgBC,MAAMC;QACrC,IAAIkB,MAAMN;QAEV,IAAIF,mBAAmBM,UAAU;YAC/BE,MAAM,MAAMR,gBAAgB;gBAC1BF;gBACAQ;gBACAb;gBACAQ;YACF;QACF,OAAO,IAAIF,+BAA+BO,YAAYT,QAAQY,WAAW,EAAE;YACzED,MAAM,MAAMX,QAAQY,WAAW,CAAC;gBAC9BX;gBACAT,MAAMA,QAAQC;gBACdgB;gBACAb;YACF;QACF;QAEA,OAAOe;IACT,EAAC"}
@@ -0,0 +1,11 @@
1
+ import type { CollectionBeforeChangeHook, FieldHook } from 'payload';
2
+ type Args = {
3
+ collectionPrefix?: string;
4
+ useCompositePrefixes?: boolean;
5
+ };
6
+ /** Persist new upload destinations without reinterpreting metadata-only updates. */
7
+ export declare const getNormalizeUploadPrefixHook: ({ collectionPrefix, useCompositePrefixes }: Args) => CollectionBeforeChangeHook;
8
+ /** Run last on the prefix field so user hooks cannot leave stale storage coordinates. */
9
+ export declare const getNormalizeUploadPrefixFieldHook: ({ collectionPrefix, useCompositePrefixes }: Args) => FieldHook;
10
+ export {};
11
+ //# sourceMappingURL=normalizeUploadPrefix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalizeUploadPrefix.d.ts","sourceRoot":"","sources":["../../src/hooks/normalizeUploadPrefix.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAIpE,KAAK,IAAI,GAAG;IACV,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,CAAA;AAiBD,oFAAoF;AACpF,eAAO,MAAM,4BAA4B,+CACM,IAAI,KAAG,0BAiBnD,CAAA;AAEH,yFAAyF;AACzF,eAAO,MAAM,iCAAiC,+CACC,IAAI,KAAG,SAenD,CAAA"}
@@ -0,0 +1,42 @@
1
+ import { buildUploadPrefix } from '../utilities/buildStoragePathData.js';
2
+ /**
3
+ * A prefix the caller did not supply, or supplied unchanged, is left as stored so
4
+ * pre-upgrade files keep resolving to their original object keys. Anything the caller
5
+ * chooses is contained, because `prefix` is writable through the REST, GraphQL and
6
+ * Local APIs and the read path trusts whatever is persisted.
7
+ */ const isPrefixSupplied = ({ storedPrefix, value })=>typeof value === 'string' && value !== (typeof storedPrefix === 'string' ? storedPrefix : '');
8
+ /** Persist new upload destinations without reinterpreting metadata-only updates. */ export const getNormalizeUploadPrefixHook = ({ collectionPrefix, useCompositePrefixes })=>({ data, originalDoc, req })=>{
9
+ if (req.context?.skipCloudStorage) {
10
+ return data;
11
+ }
12
+ if (!req.file && !isPrefixSupplied({
13
+ storedPrefix: originalDoc?.prefix,
14
+ value: data.prefix
15
+ })) {
16
+ return data;
17
+ }
18
+ data.prefix = buildUploadPrefix({
19
+ collectionPrefix,
20
+ docPrefix: typeof data.prefix === 'string' ? data.prefix : '',
21
+ useCompositePrefixes
22
+ }).sanitizedDocPrefix;
23
+ return data;
24
+ };
25
+ /** Run last on the prefix field so user hooks cannot leave stale storage coordinates. */ export const getNormalizeUploadPrefixFieldHook = ({ collectionPrefix, useCompositePrefixes })=>({ previousValue, req, value })=>{
26
+ if (req.context?.skipCloudStorage) {
27
+ return value;
28
+ }
29
+ if (!req.file && !isPrefixSupplied({
30
+ storedPrefix: previousValue,
31
+ value
32
+ })) {
33
+ return value;
34
+ }
35
+ return buildUploadPrefix({
36
+ collectionPrefix,
37
+ docPrefix: typeof value === 'string' ? value : '',
38
+ useCompositePrefixes
39
+ }).sanitizedDocPrefix;
40
+ };
41
+
42
+ //# sourceMappingURL=normalizeUploadPrefix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hooks/normalizeUploadPrefix.ts"],"sourcesContent":["import type { CollectionBeforeChangeHook, FieldHook } from 'payload'\n\nimport { buildUploadPrefix } from '../utilities/buildStoragePathData.js'\n\ntype Args = {\n collectionPrefix?: string\n useCompositePrefixes?: boolean\n}\n\n/**\n * A prefix the caller did not supply, or supplied unchanged, is left as stored so\n * pre-upgrade files keep resolving to their original object keys. Anything the caller\n * chooses is contained, because `prefix` is writable through the REST, GraphQL and\n * Local APIs and the read path trusts whatever is persisted.\n */\nconst isPrefixSupplied = ({\n storedPrefix,\n value,\n}: {\n storedPrefix: unknown\n value: unknown\n}): boolean =>\n typeof value === 'string' && value !== (typeof storedPrefix === 'string' ? storedPrefix : '')\n\n/** Persist new upload destinations without reinterpreting metadata-only updates. */\nexport const getNormalizeUploadPrefixHook =\n ({ collectionPrefix, useCompositePrefixes }: Args): CollectionBeforeChangeHook =>\n ({ data, originalDoc, req }) => {\n if (req.context?.skipCloudStorage) {\n return data\n }\n\n if (!req.file && !isPrefixSupplied({ storedPrefix: originalDoc?.prefix, value: data.prefix })) {\n return data\n }\n\n data.prefix = buildUploadPrefix({\n collectionPrefix,\n docPrefix: typeof data.prefix === 'string' ? data.prefix : '',\n useCompositePrefixes,\n }).sanitizedDocPrefix\n\n return data\n }\n\n/** Run last on the prefix field so user hooks cannot leave stale storage coordinates. */\nexport const getNormalizeUploadPrefixFieldHook =\n ({ collectionPrefix, useCompositePrefixes }: Args): FieldHook =>\n ({ previousValue, req, value }) => {\n if (req.context?.skipCloudStorage) {\n return value\n }\n\n if (!req.file && !isPrefixSupplied({ storedPrefix: previousValue, value })) {\n return value\n }\n\n return buildUploadPrefix({\n collectionPrefix,\n docPrefix: typeof value === 'string' ? value : '',\n useCompositePrefixes,\n }).sanitizedDocPrefix\n }\n"],"names":["buildUploadPrefix","isPrefixSupplied","storedPrefix","value","getNormalizeUploadPrefixHook","collectionPrefix","useCompositePrefixes","data","originalDoc","req","context","skipCloudStorage","file","prefix","docPrefix","sanitizedDocPrefix","getNormalizeUploadPrefixFieldHook","previousValue"],"mappings":"AAEA,SAASA,iBAAiB,QAAQ,uCAAsC;AAOxE;;;;;CAKC,GACD,MAAMC,mBAAmB,CAAC,EACxBC,YAAY,EACZC,KAAK,EAIN,GACC,OAAOA,UAAU,YAAYA,UAAW,CAAA,OAAOD,iBAAiB,WAAWA,eAAe,EAAC;AAE7F,kFAAkF,GAClF,OAAO,MAAME,+BACX,CAAC,EAAEC,gBAAgB,EAAEC,oBAAoB,EAAQ,GACjD,CAAC,EAAEC,IAAI,EAAEC,WAAW,EAAEC,GAAG,EAAE;QACzB,IAAIA,IAAIC,OAAO,EAAEC,kBAAkB;YACjC,OAAOJ;QACT;QAEA,IAAI,CAACE,IAAIG,IAAI,IAAI,CAACX,iBAAiB;YAAEC,cAAcM,aAAaK;YAAQV,OAAOI,KAAKM,MAAM;QAAC,IAAI;YAC7F,OAAON;QACT;QAEAA,KAAKM,MAAM,GAAGb,kBAAkB;YAC9BK;YACAS,WAAW,OAAOP,KAAKM,MAAM,KAAK,WAAWN,KAAKM,MAAM,GAAG;YAC3DP;QACF,GAAGS,kBAAkB;QAErB,OAAOR;IACT,EAAC;AAEH,uFAAuF,GACvF,OAAO,MAAMS,oCACX,CAAC,EAAEX,gBAAgB,EAAEC,oBAAoB,EAAQ,GACjD,CAAC,EAAEW,aAAa,EAAER,GAAG,EAAEN,KAAK,EAAE;QAC5B,IAAIM,IAAIC,OAAO,EAAEC,kBAAkB;YACjC,OAAOR;QACT;QAEA,IAAI,CAACM,IAAIG,IAAI,IAAI,CAACX,iBAAiB;YAAEC,cAAce;YAAed;QAAM,IAAI;YAC1E,OAAOA;QACT;QAEA,OAAOH,kBAAkB;YACvBK;YACAS,WAAW,OAAOX,UAAU,WAAWA,QAAQ;YAC/CG;QACF,GAAGS,kBAAkB;IACvB,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;AAgBnE,eAAO,MAAM,kBAAkB,kBACb,aAAa,sBACZ,MAAM,KAAG,MAoOzB,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;AAiBnE,eAAO,MAAM,kBAAkB,kBACb,aAAa,sBACZ,MAAM,KAAG,MAwOzB,CAAA"}
package/dist/plugin.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { getFields } from './fields/getFields.js';
2
2
  import { getAfterChangeHook } from './hooks/afterChange.js';
3
3
  import { getAfterDeleteHook } from './hooks/afterDelete.js';
4
+ import { getNormalizeUploadPrefixHook } from './hooks/normalizeUploadPrefix.js';
4
5
  import { getPreserveFileDataHook } from './hooks/preserveFileData.js';
5
6
  // This plugin extends all targeted collections by offloading uploaded files
6
7
  // to cloud storage instead of solely storing files locally.
@@ -9,42 +10,39 @@ import { getPreserveFileDataHook } from './hooks/preserveFileData.js';
9
10
  // 1. handleUpload, 2. handleDelete, 3. generateURL, 4. staticHandler
10
11
  // Optionally, the adapter can specify any Webpack config overrides if they are necessary.
11
12
  export const cloudStoragePlugin = (pluginOptions)=>(incomingConfig)=>{
12
- const { alwaysInsertFields, collections: allCollectionOptions, enabled, useCompositePrefixes } = pluginOptions;
13
+ const { collections: allCollectionOptions, enabled, useCompositePrefixes } = pluginOptions;
13
14
  const config = {
14
15
  ...incomingConfig
15
16
  };
16
- // If disabled but alwaysInsertFields is true, only insert fields without full plugin functionality
17
+ // If disabled, only insert fields (e.g. prefix) without full plugin functionality,
18
+ // so the collection schema stays consistent across environments.
17
19
  if (enabled === false) {
18
- if (alwaysInsertFields) {
19
- return {
20
- ...config,
21
- collections: (config.collections || []).map((existingCollection)=>{
22
- const options = allCollectionOptions[existingCollection.slug];
23
- if (options) {
24
- // If adapter is provided, use it to get fields
25
- const adapter = options.adapter ? options.adapter({
26
- collection: existingCollection,
27
- prefix: options.prefix
28
- }) : undefined;
29
- const fields = getFields({
30
- adapter,
31
- alwaysInsertFields: true,
32
- collection: existingCollection,
33
- disablePayloadAccessControl: options.disablePayloadAccessControl,
34
- generateFileURL: options.generateFileURL,
35
- prefix: options.prefix,
36
- useCompositePrefixes
37
- });
38
- return {
39
- ...existingCollection,
40
- fields
41
- };
42
- }
43
- return existingCollection;
44
- })
45
- };
46
- }
47
- return config;
20
+ return {
21
+ ...config,
22
+ collections: (config.collections || []).map((existingCollection)=>{
23
+ const options = allCollectionOptions[existingCollection.slug];
24
+ if (options) {
25
+ // If adapter is provided, use it to get fields
26
+ const adapter = options.adapter ? options.adapter({
27
+ collection: existingCollection,
28
+ prefix: options.prefix
29
+ }) : undefined;
30
+ const fields = getFields({
31
+ adapter,
32
+ collection: existingCollection,
33
+ disablePayloadAccessControl: options.disablePayloadAccessControl,
34
+ generateFileURL: options.generateFileURL,
35
+ prefix: options.prefix,
36
+ useCompositePrefixes
37
+ });
38
+ return {
39
+ ...existingCollection,
40
+ fields
41
+ };
42
+ }
43
+ return existingCollection;
44
+ })
45
+ };
48
46
  }
49
47
  const initFunctions = [];
50
48
  const endpointPaths = new Map();
@@ -121,9 +119,6 @@ export const cloudStoragePlugin = (pluginOptions)=>(incomingConfig)=>{
121
119
  });
122
120
  }
123
121
  const getSkipSafeFetchSetting = ()=>{
124
- if (options.disablePayloadAccessControl) {
125
- return true;
126
- }
127
122
  const isBooleanTrueSkipSafeFetch = typeof existingCollection.upload === 'object' && existingCollection.upload.skipSafeFetch === true;
128
123
  const isAllowListSkipSafeFetch = typeof existingCollection.upload === 'object' && Array.isArray(existingCollection.upload.skipSafeFetch);
129
124
  if (isBooleanTrueSkipSafeFetch) {
@@ -162,18 +157,26 @@ export const cloudStoragePlugin = (pluginOptions)=>(incomingConfig)=>{
162
157
  ...existingCollection.hooks?.afterChange || [],
163
158
  getAfterChangeHook({
164
159
  adapter,
165
- collection: existingCollection
160
+ collection: existingCollection,
161
+ collectionPrefix: options.prefix,
162
+ useCompositePrefixes
166
163
  })
167
164
  ],
168
165
  afterDelete: [
169
166
  ...existingCollection.hooks?.afterDelete || [],
170
167
  getAfterDeleteHook({
171
168
  adapter,
172
- collection: existingCollection
169
+ collection: existingCollection,
170
+ collectionPrefix: options.prefix,
171
+ useCompositePrefixes
173
172
  })
174
173
  ],
175
174
  beforeChange: [
176
175
  ...existingCollection.hooks?.beforeChange || [],
176
+ getNormalizeUploadPrefixHook({
177
+ collectionPrefix: options.prefix,
178
+ useCompositePrefixes
179
+ }),
177
180
  getPreserveFileDataHook()
178
181
  ]
179
182
  },
@@ -195,7 +198,9 @@ export const cloudStoragePlugin = (pluginOptions)=>(incomingConfig)=>{
195
198
  ...config,
196
199
  collections,
197
200
  onInit: async (payload)=>{
198
- initFunctions.forEach((fn)=>fn());
201
+ // Await each init so a provisioning failure fails Payload startup
202
+ // instead of becoming an unhandled rejection.
203
+ await Promise.all(initFunctions.map((fn)=>fn()));
199
204
  if (config.onInit) {
200
205
  await config.onInit(payload);
201
206
  }
@@ -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 { 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 {\n alwaysInsertFields,\n collections: allCollectionOptions,\n enabled,\n useCompositePrefixes,\n } = pluginOptions\n const config = { ...incomingConfig }\n\n // If disabled but alwaysInsertFields is true, only insert fields without full plugin functionality\n if (enabled === false) {\n if (alwaysInsertFields) {\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 alwaysInsertFields: true,\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 return config\n }\n\n const initFunctions: Array<() => 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 if (options.disablePayloadAccessControl) {\n return true\n }\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({ adapter, collection: existingCollection }),\n ],\n afterDelete: [\n ...(existingCollection.hooks?.afterDelete || []),\n getAfterDeleteHook({ adapter, collection: existingCollection }),\n ],\n beforeChange: [\n ...(existingCollection.hooks?.beforeChange || []),\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 initFunctions.forEach((fn) => fn())\n if (config.onInit) {\n await config.onInit(payload)\n }\n },\n }\n }\n"],"names":["getFields","getAfterChangeHook","getAfterDeleteHook","getPreserveFileDataHook","cloudStoragePlugin","pluginOptions","incomingConfig","alwaysInsertFields","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","afterDelete","beforeChange","name","disableLocalStorage","payload","forEach","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'\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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"}
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, 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;
@@ -10,11 +11,25 @@ export interface File {
10
11
  export type ClientUploadsConfig = {
11
12
  access?: UploadInstructionsAccess;
12
13
  } | boolean;
14
+ /**
15
+ * Reference to a client-uploaded object, returned by an upload handler and
16
+ * submitted with the document. Always carries the signed receipt; `prefix`
17
+ * locates the stored object.
18
+ */
19
+ export type UploadReference = {
20
+ _objectKey?: string;
21
+ prefix: string;
22
+ signedReceipt: `${string}.${string}`;
23
+ };
13
24
  export type HandleUpload = (args: {
14
25
  collection: CollectionConfig;
15
26
  data: any;
16
27
  file: File;
17
28
  req: PayloadRequest;
29
+ /**
30
+ * Pre-resolved storage path (`_objectKey` folded in, contained beneath the collection prefix).
31
+ */
32
+ storageFilePath: string;
18
33
  }) => Partial<FileData & TypeWithID> | Promise<Partial<FileData & TypeWithID>> | Promise<void> | void;
19
34
  export interface TypeWithPrefix {
20
35
  prefix?: string;
@@ -24,6 +39,10 @@ export type HandleDelete = (args: {
24
39
  doc: FileData & TypeWithID & TypeWithPrefix;
25
40
  filename: string;
26
41
  req: PayloadRequest;
42
+ /**
43
+ * Pre-resolved storage path of the object to delete.
44
+ */
45
+ storageFilePath: string;
27
46
  }) => Promise<void> | void;
28
47
  export type GenerateURL = (args: {
29
48
  collection: CollectionConfig;
@@ -37,6 +56,7 @@ export type StaticHandler = (req: PayloadRequest, args: {
37
56
  params: {
38
57
  collection: string;
39
58
  filename: string;
59
+ operation?: FileHandlerOperation;
40
60
  prefix?: string;
41
61
  uploadReference?: unknown;
42
62
  };
@@ -53,7 +73,7 @@ export interface GeneratedAdapter {
53
73
  handleDelete: HandleDelete;
54
74
  handleUpload: HandleUpload;
55
75
  name: string;
56
- onInit?: () => void;
76
+ onInit?: () => Promise<void> | void;
57
77
  staticHandler: StaticHandler;
58
78
  /** Generates upload instructions when supported. */
59
79
  uploadInstructions?: {
@@ -93,16 +113,6 @@ export interface CollectionOptions {
93
113
  prefix?: string;
94
114
  }
95
115
  export interface PluginOptions {
96
- /**
97
- * When enabled, fields (like the prefix field) will always be inserted into
98
- * the collection schema regardless of whether the plugin is enabled. This
99
- * ensures a consistent schema across all environments.
100
- *
101
- * This will be enabled by default in Payload v4.
102
- *
103
- * @default false
104
- */
105
- alwaysInsertFields?: boolean;
106
116
  collections: Partial<Record<UploadCollectionSlug, CollectionOptions>>;
107
117
  /**
108
118
  * Whether or not to enable the plugin
@@ -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\nexport type HandleUpload = (args: {\n collection: CollectionConfig\n data: any\n file: File\n req: PayloadRequest\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}) => 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?: () => 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 /**\n * When enabled, fields (like the prefix field) will always be inserted into\n * the collection schema regardless of whether the plugin is enabled. This\n * ensures a consistent schema across all environments.\n *\n * This will be enabled by default in Payload v4.\n *\n * @default false\n */\n alwaysInsertFields?: boolean\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":"AAmHA,WA4BC"}
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 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\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 /**\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":"AA+IA,WAkBC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Joins the semantic prefix and the `_objectKey` segment into the object's folder; either may be empty.
3
+ */
4
+ export declare const buildPrefixWithObjectKey: ({ objectKey, prefix, }: {
5
+ objectKey?: string;
6
+ prefix?: string;
7
+ }) => string;
8
+ //# sourceMappingURL=buildPrefixWithObjectKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildPrefixWithObjectKey.d.ts","sourceRoot":"","sources":["../../src/utilities/buildPrefixWithObjectKey.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,wBAAwB,2BAGlC;IACD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,KAAG,MASH,CAAA"}
@@ -0,0 +1,13 @@
1
+ import { sanitizePrefix } from './sanitizePrefix.js';
2
+ /**
3
+ * Joins the semantic prefix and the `_objectKey` segment into the object's folder; either may be empty.
4
+ */ export const buildPrefixWithObjectKey = ({ objectKey, prefix })=>{
5
+ const safePrefix = sanitizePrefix(prefix ?? '');
6
+ const safeObjectKey = sanitizePrefix(objectKey ?? '');
7
+ if (safePrefix && safeObjectKey) {
8
+ return `${safePrefix}/${safeObjectKey}`;
9
+ }
10
+ return safePrefix || safeObjectKey;
11
+ };
12
+
13
+ //# sourceMappingURL=buildPrefixWithObjectKey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/buildPrefixWithObjectKey.ts"],"sourcesContent":["import { sanitizePrefix } from './sanitizePrefix.js'\n\n/**\n * Joins the semantic prefix and the `_objectKey` segment into the object's folder; either may be empty.\n */\nexport const buildPrefixWithObjectKey = ({\n objectKey,\n prefix,\n}: {\n objectKey?: string\n prefix?: string\n}): string => {\n const safePrefix = sanitizePrefix(prefix ?? '')\n const safeObjectKey = sanitizePrefix(objectKey ?? '')\n\n if (safePrefix && safeObjectKey) {\n return `${safePrefix}/${safeObjectKey}`\n }\n\n return safePrefix || safeObjectKey\n}\n"],"names":["sanitizePrefix","buildPrefixWithObjectKey","objectKey","prefix","safePrefix","safeObjectKey"],"mappings":"AAAA,SAASA,cAAc,QAAQ,sBAAqB;AAEpD;;CAEC,GACD,OAAO,MAAMC,2BAA2B,CAAC,EACvCC,SAAS,EACTC,MAAM,EAIP;IACC,MAAMC,aAAaJ,eAAeG,UAAU;IAC5C,MAAME,gBAAgBL,eAAeE,aAAa;IAElD,IAAIE,cAAcC,eAAe;QAC/B,OAAO,GAAGD,WAAW,CAAC,EAAEC,eAAe;IACzC;IAEA,OAAOD,cAAcC;AACvB,EAAC"}
@@ -0,0 +1,49 @@
1
+ type BuildFilePathDataArgs = {
2
+ collectionPrefix?: string;
3
+ docPrefix?: string;
4
+ filename: string;
5
+ useCompositePrefixes?: boolean;
6
+ };
7
+ type BuildFilePathDataResult = {
8
+ sanitizedCollectionPrefix: string;
9
+ sanitizedDocPrefix: string;
10
+ sanitizedFilename: string;
11
+ /**
12
+ * The full path to the file within the storage backend.
13
+ */
14
+ storageFilePath: string;
15
+ };
16
+ export declare function isStoragePathWithinCollectionPrefix({ collectionPrefix, docPrefix, }: {
17
+ collectionPrefix?: string;
18
+ docPrefix: string;
19
+ }): boolean;
20
+ /**
21
+ * Resolves where a new upload must be stored, without needing a filename.
22
+ *
23
+ * In non-composite mode (useCompositePrefixes: false), docPrefix is treated as a complete prefix
24
+ * when it is already within collectionPrefix and is otherwise nested beneath collectionPrefix.
25
+ * In composite mode (useCompositePrefixes: true), the collection prefix is joined when the key is
26
+ * built, so the persisted document prefix stays relative to it.
27
+ *
28
+ * Prefix-only callers (such as the upload prefix hooks) use this directly; use
29
+ * {@link buildUploadStoragePathData} when a full object key is needed.
30
+ */
31
+ export declare function buildUploadPrefix({ collectionPrefix, docPrefix, useCompositePrefixes, }: Omit<BuildFilePathDataArgs, 'filename'>): {
32
+ sanitizedCollectionPrefix: string;
33
+ sanitizedDocPrefix: string;
34
+ uploadPrefix: string;
35
+ };
36
+ /**
37
+ * Resolves a new upload destination beneath the configured collection prefix.
38
+ * Both prefixes are passed through {@link sanitizePrefix} so keys stay normalized.
39
+ */
40
+ export declare function buildUploadStoragePathData({ collectionPrefix, docPrefix, filename, useCompositePrefixes, }: BuildFilePathDataArgs): BuildFilePathDataResult;
41
+ /**
42
+ * Resolves the exact location represented by persisted upload metadata.
43
+ * Non-composite document prefixes historically override the collection prefix;
44
+ * keep that behavior for reads, URLs, and cleanup of pre-upgrade files.
45
+ * New writes must use buildUploadStoragePathData instead.
46
+ */
47
+ export declare function buildStoragePathData({ collectionPrefix, docPrefix, filename, useCompositePrefixes, }: BuildFilePathDataArgs): BuildFilePathDataResult;
48
+ export {};
49
+ //# sourceMappingURL=buildStoragePathData.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildStoragePathData.d.ts","sourceRoot":"","sources":["../../src/utilities/buildStoragePathData.ts"],"names":[],"mappings":"AAKA,KAAK,qBAAqB,GAAG;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,CAAA;AAED,KAAK,uBAAuB,GAAG;IAC7B,yBAAyB,EAAE,MAAM,CAAA;IACjC,kBAAkB,EAAE,MAAM,CAAA;IAC1B,iBAAiB,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,eAAe,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,wBAAgB,mCAAmC,CAAC,EAClD,gBAAgB,EAChB,SAAS,GACV,EAAE;IACD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,SAAS,EAAE,MAAM,CAAA;CAClB,GAAG,OAAO,CAQV;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,gBAAgB,EAChB,SAAS,EACT,oBAA4B,GAC7B,EAAE,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAC,GAAG;IAC3C,yBAAyB,EAAE,MAAM,CAAA;IACjC,kBAAkB,EAAE,MAAM,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAA;CACrB,CAiBA;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,gBAAgB,EAChB,SAAS,EACT,QAAQ,EACR,oBAA4B,GAC7B,EAAE,qBAAqB,GAAG,uBAAuB,CAkBjD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,gBAAgB,EAChB,SAAS,EACT,QAAQ,EACR,oBAA4B,GAC7B,EAAE,qBAAqB,GAAG,uBAAuB,CAcjD"}