@payloadcms/plugin-cloud-storage 4.0.0-internal.77191e5 → 4.0.0-internal.7803e2c

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 (52) hide show
  1. package/dist/exports/utilities.d.ts +1 -0
  2. package/dist/exports/utilities.d.ts.map +1 -1
  3. package/dist/exports/utilities.js +1 -0
  4. package/dist/exports/utilities.js.map +1 -1
  5. package/dist/fields/getFields.d.ts.map +1 -1
  6. package/dist/fields/getFields.js +79 -8
  7. package/dist/fields/getFields.js.map +1 -1
  8. package/dist/hooks/afterChange.d.ts +3 -1
  9. package/dist/hooks/afterChange.d.ts.map +1 -1
  10. package/dist/hooks/afterChange.js +139 -17
  11. package/dist/hooks/afterChange.js.map +1 -1
  12. package/dist/hooks/afterDelete.d.ts +7 -1
  13. package/dist/hooks/afterDelete.d.ts.map +1 -1
  14. package/dist/hooks/afterDelete.js +108 -27
  15. package/dist/hooks/afterDelete.js.map +1 -1
  16. package/dist/hooks/afterRead.d.ts +6 -1
  17. package/dist/hooks/afterRead.d.ts.map +1 -1
  18. package/dist/hooks/afterRead.js +20 -6
  19. package/dist/hooks/afterRead.js.map +1 -1
  20. package/dist/hooks/beforeChange.d.ts +2 -1
  21. package/dist/hooks/beforeChange.d.ts.map +1 -1
  22. package/dist/hooks/beforeChange.js +7 -4
  23. package/dist/hooks/beforeChange.js.map +1 -1
  24. package/dist/hooks/publicOriginalURL.d.ts +8 -0
  25. package/dist/hooks/publicOriginalURL.d.ts.map +1 -0
  26. package/dist/hooks/publicOriginalURL.js +34 -0
  27. package/dist/hooks/publicOriginalURL.js.map +1 -0
  28. package/dist/plugin.d.ts.map +1 -1
  29. package/dist/plugin.js +36 -5
  30. package/dist/plugin.js.map +1 -1
  31. package/dist/types.d.ts +30 -1
  32. package/dist/types.d.ts.map +1 -1
  33. package/dist/types.js.map +1 -1
  34. package/dist/utilities/createFileOperations.d.ts +13 -0
  35. package/dist/utilities/createFileOperations.d.ts.map +1 -0
  36. package/dist/utilities/createFileOperations.js +258 -0
  37. package/dist/utilities/createFileOperations.js.map +1 -0
  38. package/dist/utilities/getFilePrefix.d.ts +2 -5
  39. package/dist/utilities/getFilePrefix.d.ts.map +1 -1
  40. package/dist/utilities/getFilePrefix.js +25 -10
  41. package/dist/utilities/getFilePrefix.js.map +1 -1
  42. package/dist/utilities/getIncomingFiles.js +2 -2
  43. package/dist/utilities/getIncomingFiles.js.map +1 -1
  44. package/dist/utilities/getStorageLocationSelect.d.ts +9 -0
  45. package/dist/utilities/getStorageLocationSelect.d.ts.map +1 -0
  46. package/dist/utilities/getStorageLocationSelect.js +54 -0
  47. package/dist/utilities/getStorageLocationSelect.js.map +1 -0
  48. package/dist/utilities/resolveSignedURLKey.d.ts +3 -1
  49. package/dist/utilities/resolveSignedURLKey.d.ts.map +1 -1
  50. package/dist/utilities/resolveSignedURLKey.js +30 -8
  51. package/dist/utilities/resolveSignedURLKey.js.map +1 -1
  52. package/package.json +24 -26
@@ -0,0 +1,54 @@
1
+ import { getSelectMode } from 'payload/shared';
2
+ const locationFieldNames = [
3
+ 'filename',
4
+ 'prefix',
5
+ '_objectKey'
6
+ ];
7
+ /**
8
+ * URL hooks rebuild direct URLs from each representation's stored location, so a positive
9
+ * selection of a URL must also read the fields that location is built from.
10
+ */ export const getStorageLocationSelect = ({ select: existingSelect })=>(args)=>{
11
+ const select = existingSelect?.(args) ?? args.select;
12
+ if (!select || getSelectMode(select) === 'exclude') {
13
+ return select;
14
+ }
15
+ return withLocationFields({
16
+ select
17
+ });
18
+ };
19
+ const withLocationFields = ({ select })=>{
20
+ const result = addLocationFields({
21
+ representation: {
22
+ ...select
23
+ }
24
+ });
25
+ if (isSelectRecord(result.original)) {
26
+ result.original = addLocationFields({
27
+ representation: {
28
+ ...result.original
29
+ }
30
+ });
31
+ }
32
+ if (isSelectRecord(result.variants)) {
33
+ result.variants = Object.fromEntries(Object.entries(result.variants).map(([name, variant])=>[
34
+ name,
35
+ isSelectRecord(variant) ? addLocationFields({
36
+ representation: {
37
+ ...variant
38
+ }
39
+ }) : variant
40
+ ]));
41
+ }
42
+ return result;
43
+ };
44
+ const addLocationFields = ({ representation })=>{
45
+ if (representation.url === true) {
46
+ for (const fieldName of locationFieldNames){
47
+ representation[fieldName] = true;
48
+ }
49
+ }
50
+ return representation;
51
+ };
52
+ const isSelectRecord = (value)=>typeof value === 'object' && value !== null && !Array.isArray(value);
53
+
54
+ //# sourceMappingURL=getStorageLocationSelect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/getStorageLocationSelect.ts"],"sourcesContent":["import type { CollectionConfig, SelectType } from 'payload'\n\nimport { getSelectMode } from 'payload/shared'\n\ntype SelectRecord = Record<string, unknown>\n\nconst locationFieldNames = ['filename', 'prefix', '_objectKey'] as const\n\n/**\n * URL hooks rebuild direct URLs from each representation's stored location, so a positive\n * selection of a URL must also read the fields that location is built from.\n */\nexport const getStorageLocationSelect =\n ({\n select: existingSelect,\n }: {\n select: CollectionConfig['select']\n }): NonNullable<CollectionConfig['select']> =>\n (args) => {\n const select = existingSelect?.(args) ?? args.select\n\n if (!select || getSelectMode(select) === 'exclude') {\n return select\n }\n\n return withLocationFields({ select })\n }\n\nconst withLocationFields = ({ select }: { select: SelectType }): SelectType => {\n const result = addLocationFields({ representation: { ...select } })\n\n if (isSelectRecord(result.original)) {\n result.original = addLocationFields({ representation: { ...result.original } })\n }\n\n if (isSelectRecord(result.variants)) {\n result.variants = Object.fromEntries(\n Object.entries(result.variants).map(([name, variant]) => [\n name,\n isSelectRecord(variant) ? addLocationFields({ representation: { ...variant } }) : variant,\n ]),\n )\n }\n\n return result as SelectType\n}\n\nconst addLocationFields = ({ representation }: { representation: SelectRecord }): SelectRecord => {\n if (representation.url === true) {\n for (const fieldName of locationFieldNames) {\n representation[fieldName] = true\n }\n }\n\n return representation\n}\n\nconst isSelectRecord = (value: unknown): value is SelectRecord =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n"],"names":["getSelectMode","locationFieldNames","getStorageLocationSelect","select","existingSelect","args","withLocationFields","result","addLocationFields","representation","isSelectRecord","original","variants","Object","fromEntries","entries","map","name","variant","url","fieldName","value","Array","isArray"],"mappings":"AAEA,SAASA,aAAa,QAAQ,iBAAgB;AAI9C,MAAMC,qBAAqB;IAAC;IAAY;IAAU;CAAa;AAE/D;;;CAGC,GACD,OAAO,MAAMC,2BACX,CAAC,EACCC,QAAQC,cAAc,EAGvB,GACD,CAACC;QACC,MAAMF,SAASC,iBAAiBC,SAASA,KAAKF,MAAM;QAEpD,IAAI,CAACA,UAAUH,cAAcG,YAAY,WAAW;YAClD,OAAOA;QACT;QAEA,OAAOG,mBAAmB;YAAEH;QAAO;IACrC,EAAC;AAEH,MAAMG,qBAAqB,CAAC,EAAEH,MAAM,EAA0B;IAC5D,MAAMI,SAASC,kBAAkB;QAAEC,gBAAgB;YAAE,GAAGN,MAAM;QAAC;IAAE;IAEjE,IAAIO,eAAeH,OAAOI,QAAQ,GAAG;QACnCJ,OAAOI,QAAQ,GAAGH,kBAAkB;YAAEC,gBAAgB;gBAAE,GAAGF,OAAOI,QAAQ;YAAC;QAAE;IAC/E;IAEA,IAAID,eAAeH,OAAOK,QAAQ,GAAG;QACnCL,OAAOK,QAAQ,GAAGC,OAAOC,WAAW,CAClCD,OAAOE,OAAO,CAACR,OAAOK,QAAQ,EAAEI,GAAG,CAAC,CAAC,CAACC,MAAMC,QAAQ,GAAK;gBACvDD;gBACAP,eAAeQ,WAAWV,kBAAkB;oBAAEC,gBAAgB;wBAAE,GAAGS,OAAO;oBAAC;gBAAE,KAAKA;aACnF;IAEL;IAEA,OAAOX;AACT;AAEA,MAAMC,oBAAoB,CAAC,EAAEC,cAAc,EAAoC;IAC7E,IAAIA,eAAeU,GAAG,KAAK,MAAM;QAC/B,KAAK,MAAMC,aAAanB,mBAAoB;YAC1CQ,cAAc,CAACW,UAAU,GAAG;QAC9B;IACF;IAEA,OAAOX;AACT;AAEA,MAAMC,iBAAiB,CAACW,QACtB,OAAOA,UAAU,YAAYA,UAAU,QAAQ,CAACC,MAAMC,OAAO,CAACF"}
@@ -1,6 +1,8 @@
1
1
  import type { PayloadRequest } from 'payload';
2
2
  import type { UploadReference } from '../types.js';
3
3
  type Args = {
4
+ /** Signed into the receipt and returned to the upload handler as `uploadReference.adapterData`. */
5
+ adapterData?: Record<string, unknown>;
4
6
  collectionPrefix?: string;
5
7
  collectionSlug: string;
6
8
  docPrefix?: string;
@@ -25,7 +27,7 @@ type Args = {
25
27
  * key with {@link buildUploadStoragePathData}, so the receipt only ever signs a key
26
28
  * beneath the configured collection prefix.
27
29
  */
28
- export declare function resolveSignedURLKey({ collectionPrefix, collectionSlug, docPrefix, filename, req, useCompositePrefixes, }: Args): Promise<{
30
+ export declare function resolveSignedURLKey({ adapterData, collectionPrefix, collectionSlug, docPrefix, filename, req, useCompositePrefixes, }: Args): Promise<{
29
31
  sanitizedDocPrefix: string;
30
32
  sanitizedFilename: string;
31
33
  storageFilePath: string;
@@ -1 +1 @@
1
- {"version":3,"file":"resolveSignedURLKey.d.ts","sourceRoot":"","sources":["../../src/utilities/resolveSignedURLKey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAM7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAIlD,KAAK,IAAI,GAAG;IACV,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,cAAc,CAAA;IACnB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,mBAAmB,CAAC,EACxC,gBAAqB,EACrB,cAAc,EACd,SAAS,EACT,QAAQ,EACR,GAAG,EACH,oBAA4B,GAC7B,EAAE,IAAI,GAAG,OAAO,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,iBAAiB,EAAE,MAAM,CAAA;IACzB,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,eAAe,CAAA;CACjC,CAAC,CAyCD"}
1
+ {"version":3,"file":"resolveSignedURLKey.d.ts","sourceRoot":"","sources":["../../src/utilities/resolveSignedURLKey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAY7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAIlD,KAAK,IAAI,GAAG;IACV,mGAAmG;IACnG,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,cAAc,CAAA;IACnB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,mBAAmB,CAAC,EACxC,WAAW,EACX,gBAAqB,EACrB,cAAc,EACd,SAAS,EACT,QAAQ,EACR,GAAG,EACH,oBAA4B,GAC7B,EAAE,IAAI,GAAG,OAAO,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,iBAAiB,EAAE,MAAM,CAAA;IACzB,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,eAAe,CAAA;CACjC,CAAC,CA2DD"}
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { createClientUploadReceipt, getSafeFileName } from 'payload/internal';
2
+ import { createClientUploadReceipt, getOriginalFilename, getSafeFileName, incrementName, truncateFilename } from 'payload/internal';
3
3
  import { getSanitizedUploadFilename } from 'payload/shared';
4
4
  import { buildUploadPrefix, buildUploadStoragePathData } from './buildStoragePathData.js';
5
5
  /**
@@ -18,14 +18,33 @@ import { buildUploadPrefix, buildUploadStoragePathData } from './buildStoragePat
18
18
  * The semantic prefix is resolved with {@link buildUploadPrefix} and the final
19
19
  * key with {@link buildUploadStoragePathData}, so the receipt only ever signs a key
20
20
  * beneath the configured collection prefix.
21
- */ export async function resolveSignedURLKey({ collectionPrefix = '', collectionSlug, docPrefix, filename, req, useCompositePrefixes = false }) {
22
- // Sanitize with the same helper generateFileData uses for the DB filename so the storage key
23
- // and doc.filename stay in sync (#16694).
24
- const sanitizedFilename = await getSafeFileName({
21
+ */ export async function resolveSignedURLKey({ adapterData, collectionPrefix = '', collectionSlug, docPrefix, filename, req, useCompositePrefixes = false }) {
22
+ // The document stores the -original name, so check collisions against that name.
23
+ let sanitizedFilename = truncateFilename({
24
+ filename: getSanitizedUploadFilename(filename),
25
+ maxBytes: 255 - Buffer.byteLength('-original')
26
+ });
27
+ let attempts = 0;
28
+ let originalFilename = getOriginalFilename({
29
+ filename: sanitizedFilename
30
+ });
31
+ while(await getSafeFileName({
25
32
  collectionSlug,
26
- desiredFilename: getSanitizedUploadFilename(filename),
33
+ desiredFilename: originalFilename,
27
34
  req
28
- });
35
+ }) !== originalFilename){
36
+ const nextFilename = truncateFilename({
37
+ filename: incrementName(sanitizedFilename),
38
+ maxBytes: 255 - Buffer.byteLength('-original')
39
+ });
40
+ if (++attempts >= 1000 || nextFilename === sanitizedFilename) {
41
+ throw new Error('Unable to find an available upload filename');
42
+ }
43
+ sanitizedFilename = nextFilename;
44
+ originalFilename = getOriginalFilename({
45
+ filename: sanitizedFilename
46
+ });
47
+ }
29
48
  const rawBaseDocPrefix = useCompositePrefixes ? docPrefix : docPrefix || collectionPrefix;
30
49
  const { sanitizedDocPrefix } = buildUploadPrefix({
31
50
  collectionPrefix,
@@ -38,7 +57,7 @@ import { buildUploadPrefix, buildUploadStoragePathData } from './buildStoragePat
38
57
  const { storageFilePath } = buildUploadStoragePathData({
39
58
  collectionPrefix,
40
59
  docPrefix: keyedDocPrefix,
41
- filename: sanitizedFilename,
60
+ filename: originalFilename,
42
61
  useCompositePrefixes
43
62
  });
44
63
  const uploadReference = {
@@ -46,6 +65,9 @@ import { buildUploadPrefix, buildUploadStoragePathData } from './buildStoragePat
46
65
  prefix: sanitizedDocPrefix,
47
66
  signedReceipt: createClientUploadReceipt({
48
67
  _objectKey,
68
+ ...adapterData !== undefined && {
69
+ adapterData
70
+ },
49
71
  collectionSlug,
50
72
  filename: sanitizedFilename,
51
73
  filePrefix: sanitizedDocPrefix,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/resolveSignedURLKey.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { randomUUID } from 'node:crypto'\nimport { createClientUploadReceipt, getSafeFileName } from 'payload/internal'\nimport { getSanitizedUploadFilename } from 'payload/shared'\n\nimport type { UploadReference } from '../types.js'\n\nimport { buildUploadPrefix, buildUploadStoragePathData } from './buildStoragePathData.js'\n\ntype Args = {\n collectionPrefix?: string\n collectionSlug: string\n docPrefix?: string\n filename: string\n req: PayloadRequest\n useCompositePrefixes?: boolean\n}\n\n/**\n * Resolves the storage key for an upload-instructions request, deduping\n * the filename via {@link getSafeFileName} so a duplicate upload does not\n * overwrite an existing blob.\n *\n * A unique per-upload segment is included in the storage key so each issued\n * key is distinct. The stored `filename` stays clean and the semantic `prefix`\n * stays exactly what the collection configured — the per-upload entropy is\n * persisted separately in `_objectKey`.\n *\n * The resolved `sanitizedFilename` is returned so the browser-side handler\n * can update the form via `updateFilename`.\n *\n * The semantic prefix is resolved with {@link buildUploadPrefix} and the final\n * key with {@link buildUploadStoragePathData}, so the receipt only ever signs a key\n * beneath the configured collection prefix.\n */\nexport async function resolveSignedURLKey({\n collectionPrefix = '',\n collectionSlug,\n docPrefix,\n filename,\n req,\n useCompositePrefixes = false,\n}: Args): Promise<{\n sanitizedDocPrefix: string\n sanitizedFilename: string\n storageFilePath: string\n uploadReference: UploadReference\n}> {\n // Sanitize with the same helper generateFileData uses for the DB filename so the storage key\n // and doc.filename stay in sync (#16694).\n const sanitizedFilename = await getSafeFileName({\n collectionSlug,\n desiredFilename: getSanitizedUploadFilename(filename),\n req,\n })\n\n const rawBaseDocPrefix = useCompositePrefixes ? docPrefix : docPrefix || collectionPrefix\n const { sanitizedDocPrefix } = buildUploadPrefix({\n collectionPrefix,\n docPrefix: rawBaseDocPrefix,\n useCompositePrefixes,\n })\n\n const _objectKey = randomUUID()\n // Per-upload segment lives in the key; it is persisted in `_objectKey`, keeping `prefix` semantic.\n const keyedDocPrefix = sanitizedDocPrefix ? `${sanitizedDocPrefix}/${_objectKey}` : _objectKey\n\n const { storageFilePath } = buildUploadStoragePathData({\n collectionPrefix,\n docPrefix: keyedDocPrefix,\n filename: sanitizedFilename,\n useCompositePrefixes,\n })\n\n const uploadReference = {\n _objectKey,\n prefix: sanitizedDocPrefix,\n signedReceipt: createClientUploadReceipt({\n _objectKey,\n collectionSlug,\n filename: sanitizedFilename,\n filePrefix: sanitizedDocPrefix,\n req,\n storageFilePath,\n }),\n }\n\n return { sanitizedDocPrefix, sanitizedFilename, storageFilePath, uploadReference }\n}\n"],"names":["randomUUID","createClientUploadReceipt","getSafeFileName","getSanitizedUploadFilename","buildUploadPrefix","buildUploadStoragePathData","resolveSignedURLKey","collectionPrefix","collectionSlug","docPrefix","filename","req","useCompositePrefixes","sanitizedFilename","desiredFilename","rawBaseDocPrefix","sanitizedDocPrefix","_objectKey","keyedDocPrefix","storageFilePath","uploadReference","prefix","signedReceipt","filePrefix"],"mappings":"AAEA,SAASA,UAAU,QAAQ,cAAa;AACxC,SAASC,yBAAyB,EAAEC,eAAe,QAAQ,mBAAkB;AAC7E,SAASC,0BAA0B,QAAQ,iBAAgB;AAI3D,SAASC,iBAAiB,EAAEC,0BAA0B,QAAQ,4BAA2B;AAWzF;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,eAAeC,oBAAoB,EACxCC,mBAAmB,EAAE,EACrBC,cAAc,EACdC,SAAS,EACTC,QAAQ,EACRC,GAAG,EACHC,uBAAuB,KAAK,EACvB;IAML,6FAA6F;IAC7F,0CAA0C;IAC1C,MAAMC,oBAAoB,MAAMX,gBAAgB;QAC9CM;QACAM,iBAAiBX,2BAA2BO;QAC5CC;IACF;IAEA,MAAMI,mBAAmBH,uBAAuBH,YAAYA,aAAaF;IACzE,MAAM,EAAES,kBAAkB,EAAE,GAAGZ,kBAAkB;QAC/CG;QACAE,WAAWM;QACXH;IACF;IAEA,MAAMK,aAAajB;IACnB,mGAAmG;IACnG,MAAMkB,iBAAiBF,qBAAqB,GAAGA,mBAAmB,CAAC,EAAEC,YAAY,GAAGA;IAEpF,MAAM,EAAEE,eAAe,EAAE,GAAGd,2BAA2B;QACrDE;QACAE,WAAWS;QACXR,UAAUG;QACVD;IACF;IAEA,MAAMQ,kBAAkB;QACtBH;QACAI,QAAQL;QACRM,eAAerB,0BAA0B;YACvCgB;YACAT;YACAE,UAAUG;YACVU,YAAYP;YACZL;YACAQ;QACF;IACF;IAEA,OAAO;QAAEH;QAAoBH;QAAmBM;QAAiBC;IAAgB;AACnF"}
1
+ {"version":3,"sources":["../../src/utilities/resolveSignedURLKey.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { randomUUID } from 'node:crypto'\nimport {\n createClientUploadReceipt,\n getOriginalFilename,\n getSafeFileName,\n incrementName,\n truncateFilename,\n} from 'payload/internal'\nimport { getSanitizedUploadFilename } from 'payload/shared'\n\nimport type { UploadReference } from '../types.js'\n\nimport { buildUploadPrefix, buildUploadStoragePathData } from './buildStoragePathData.js'\n\ntype Args = {\n /** Signed into the receipt and returned to the upload handler as `uploadReference.adapterData`. */\n adapterData?: Record<string, unknown>\n collectionPrefix?: string\n collectionSlug: string\n docPrefix?: string\n filename: string\n req: PayloadRequest\n useCompositePrefixes?: boolean\n}\n\n/**\n * Resolves the storage key for an upload-instructions request, deduping\n * the filename via {@link getSafeFileName} so a duplicate upload does not\n * overwrite an existing blob.\n *\n * A unique per-upload segment is included in the storage key so each issued\n * key is distinct. The stored `filename` stays clean and the semantic `prefix`\n * stays exactly what the collection configured — the per-upload entropy is\n * persisted separately in `_objectKey`.\n *\n * The resolved `sanitizedFilename` is returned so the browser-side handler\n * can update the form via `updateFilename`.\n *\n * The semantic prefix is resolved with {@link buildUploadPrefix} and the final\n * key with {@link buildUploadStoragePathData}, so the receipt only ever signs a key\n * beneath the configured collection prefix.\n */\nexport async function resolveSignedURLKey({\n adapterData,\n collectionPrefix = '',\n collectionSlug,\n docPrefix,\n filename,\n req,\n useCompositePrefixes = false,\n}: Args): Promise<{\n sanitizedDocPrefix: string\n sanitizedFilename: string\n storageFilePath: string\n uploadReference: UploadReference\n}> {\n // The document stores the -original name, so check collisions against that name.\n let sanitizedFilename = truncateFilename({\n filename: getSanitizedUploadFilename(filename),\n maxBytes: 255 - Buffer.byteLength('-original'),\n })\n let attempts = 0\n let originalFilename = getOriginalFilename({ filename: sanitizedFilename })\n\n while (\n (await getSafeFileName({ collectionSlug, desiredFilename: originalFilename, req })) !==\n originalFilename\n ) {\n const nextFilename = truncateFilename({\n filename: incrementName(sanitizedFilename),\n maxBytes: 255 - Buffer.byteLength('-original'),\n })\n\n if (++attempts >= 1000 || nextFilename === sanitizedFilename) {\n throw new Error('Unable to find an available upload filename')\n }\n\n sanitizedFilename = nextFilename\n originalFilename = getOriginalFilename({ filename: sanitizedFilename })\n }\n\n const rawBaseDocPrefix = useCompositePrefixes ? docPrefix : docPrefix || collectionPrefix\n const { sanitizedDocPrefix } = buildUploadPrefix({\n collectionPrefix,\n docPrefix: rawBaseDocPrefix,\n useCompositePrefixes,\n })\n\n const _objectKey = randomUUID()\n // Per-upload segment lives in the key; it is persisted in `_objectKey`, keeping `prefix` semantic.\n const keyedDocPrefix = sanitizedDocPrefix ? `${sanitizedDocPrefix}/${_objectKey}` : _objectKey\n\n const { storageFilePath } = buildUploadStoragePathData({\n collectionPrefix,\n docPrefix: keyedDocPrefix,\n filename: originalFilename,\n useCompositePrefixes,\n })\n\n const uploadReference = {\n _objectKey,\n prefix: sanitizedDocPrefix,\n signedReceipt: createClientUploadReceipt({\n _objectKey,\n ...(adapterData !== undefined && { adapterData }),\n collectionSlug,\n filename: sanitizedFilename,\n filePrefix: sanitizedDocPrefix,\n req,\n storageFilePath,\n }),\n }\n\n return { sanitizedDocPrefix, sanitizedFilename, storageFilePath, uploadReference }\n}\n"],"names":["randomUUID","createClientUploadReceipt","getOriginalFilename","getSafeFileName","incrementName","truncateFilename","getSanitizedUploadFilename","buildUploadPrefix","buildUploadStoragePathData","resolveSignedURLKey","adapterData","collectionPrefix","collectionSlug","docPrefix","filename","req","useCompositePrefixes","sanitizedFilename","maxBytes","Buffer","byteLength","attempts","originalFilename","desiredFilename","nextFilename","Error","rawBaseDocPrefix","sanitizedDocPrefix","_objectKey","keyedDocPrefix","storageFilePath","uploadReference","prefix","signedReceipt","undefined","filePrefix"],"mappings":"AAEA,SAASA,UAAU,QAAQ,cAAa;AACxC,SACEC,yBAAyB,EACzBC,mBAAmB,EACnBC,eAAe,EACfC,aAAa,EACbC,gBAAgB,QACX,mBAAkB;AACzB,SAASC,0BAA0B,QAAQ,iBAAgB;AAI3D,SAASC,iBAAiB,EAAEC,0BAA0B,QAAQ,4BAA2B;AAazF;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,eAAeC,oBAAoB,EACxCC,WAAW,EACXC,mBAAmB,EAAE,EACrBC,cAAc,EACdC,SAAS,EACTC,QAAQ,EACRC,GAAG,EACHC,uBAAuB,KAAK,EACvB;IAML,iFAAiF;IACjF,IAAIC,oBAAoBZ,iBAAiB;QACvCS,UAAUR,2BAA2BQ;QACrCI,UAAU,MAAMC,OAAOC,UAAU,CAAC;IACpC;IACA,IAAIC,WAAW;IACf,IAAIC,mBAAmBpB,oBAAoB;QAAEY,UAAUG;IAAkB;IAEzE,MACE,AAAC,MAAMd,gBAAgB;QAAES;QAAgBW,iBAAiBD;QAAkBP;IAAI,OAChFO,iBACA;QACA,MAAME,eAAenB,iBAAiB;YACpCS,UAAUV,cAAca;YACxBC,UAAU,MAAMC,OAAOC,UAAU,CAAC;QACpC;QAEA,IAAI,EAAEC,YAAY,QAAQG,iBAAiBP,mBAAmB;YAC5D,MAAM,IAAIQ,MAAM;QAClB;QAEAR,oBAAoBO;QACpBF,mBAAmBpB,oBAAoB;YAAEY,UAAUG;QAAkB;IACvE;IAEA,MAAMS,mBAAmBV,uBAAuBH,YAAYA,aAAaF;IACzE,MAAM,EAAEgB,kBAAkB,EAAE,GAAGpB,kBAAkB;QAC/CI;QACAE,WAAWa;QACXV;IACF;IAEA,MAAMY,aAAa5B;IACnB,mGAAmG;IACnG,MAAM6B,iBAAiBF,qBAAqB,GAAGA,mBAAmB,CAAC,EAAEC,YAAY,GAAGA;IAEpF,MAAM,EAAEE,eAAe,EAAE,GAAGtB,2BAA2B;QACrDG;QACAE,WAAWgB;QACXf,UAAUQ;QACVN;IACF;IAEA,MAAMe,kBAAkB;QACtBH;QACAI,QAAQL;QACRM,eAAehC,0BAA0B;YACvC2B;YACA,GAAIlB,gBAAgBwB,aAAa;gBAAExB;YAAY,CAAC;YAChDE;YACAE,UAAUG;YACVkB,YAAYR;YACZZ;YACAe;QACF;IACF;IAEA,OAAO;QAAEH;QAAoBV;QAAmBa;QAAiBC;IAAgB;AACnF"}
package/package.json CHANGED
@@ -1,13 +1,8 @@
1
1
  {
2
2
  "name": "@payloadcms/plugin-cloud-storage",
3
- "version": "4.0.0-internal.77191e5",
3
+ "version": "4.0.0-internal.7803e2c",
4
4
  "description": "The official cloud storage plugin for Payload CMS",
5
5
  "homepage": "https://payloadcms.com",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/payloadcms/payload.git",
9
- "directory": "packages/plugin-cloud-storage"
10
- },
11
6
  "license": "MIT",
12
7
  "author": "Payload <dev@payloadcms.com> (https://payloadcms.com)",
13
8
  "maintainers": [
@@ -17,8 +12,20 @@
17
12
  "url": "https://payloadcms.com"
18
13
  }
19
14
  ],
20
- "sideEffects": false,
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/payloadcms/payload.git",
18
+ "directory": "packages/plugin-cloud-storage"
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "*.js",
23
+ "*.d.ts"
24
+ ],
21
25
  "type": "module",
26
+ "sideEffects": false,
27
+ "main": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
22
29
  "exports": {
23
30
  ".": {
24
31
  "import": "./dist/index.js",
@@ -41,31 +48,24 @@
41
48
  "default": "./dist/exports/client.js"
42
49
  }
43
50
  },
44
- "main": "./dist/index.js",
45
- "types": "./dist/index.d.ts",
46
- "files": [
47
- "dist",
48
- "*.js",
49
- "*.d.ts"
50
- ],
51
+ "publishConfig": {
52
+ "registry": "https://registry.npmjs.org/"
53
+ },
51
54
  "dependencies": {
55
+ "@payloadcms/ui": "4.0.0-internal.7803e2c",
52
56
  "find-node-modules": "^2.1.3",
53
- "range-parser": "^1.2.1",
54
- "@payloadcms/ui": "4.0.0-internal.77191e5"
57
+ "range-parser": "^1.2.1"
55
58
  },
56
59
  "devDependencies": {
57
60
  "@types/find-node-modules": "^2.1.2",
58
- "@types/react": "19.2.14",
59
- "@types/react-dom": "19.2.3",
60
- "payload": "4.0.0-internal.77191e5"
61
+ "@types/react": "19.3.0",
62
+ "@types/react-dom": "19.3.0",
63
+ "payload": "4.0.0-internal.7803e2c"
61
64
  },
62
65
  "peerDependencies": {
66
+ "payload": "4.0.0-internal.7803e2c",
63
67
  "react": "^19.0.1 || ^19.1.2 || ^19.2.1",
64
- "react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1",
65
- "payload": "4.0.0-internal.77191e5"
66
- },
67
- "publishConfig": {
68
- "registry": "https://registry.npmjs.org/"
68
+ "react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1"
69
69
  },
70
70
  "scripts": {
71
71
  "build": "pnpm build:types && pnpm build:swc ",
@@ -73,8 +73,6 @@
73
73
  "build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
74
74
  "build:types": "tsc --emitDeclarationOnly --outDir dist",
75
75
  "clean": "rimraf -g {dist,*.tsbuildinfo}",
76
- "lint": "eslint .",
77
- "lint:fix": "eslint . --fix",
78
76
  "test": "echo \"No tests available.\""
79
77
  }
80
78
  }