@payloadcms/plugin-cloud-storage 3.89.0-internal.95c9cba → 3.90.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/exports/client.d.ts +1 -1
- package/dist/exports/client.d.ts.map +1 -1
- package/dist/exports/client.js +1 -1
- package/dist/exports/client.js.map +1 -1
- package/dist/exports/utilities.d.ts +3 -2
- package/dist/exports/utilities.d.ts.map +1 -1
- package/dist/exports/utilities.js +3 -2
- package/dist/exports/utilities.js.map +1 -1
- package/dist/fields/getFields.d.ts.map +1 -1
- package/dist/fields/getFields.js +28 -1
- package/dist/fields/getFields.js.map +1 -1
- package/dist/hooks/afterChange.d.ts +3 -1
- package/dist/hooks/afterChange.d.ts.map +1 -1
- package/dist/hooks/afterChange.js +56 -9
- package/dist/hooks/afterChange.js.map +1 -1
- package/dist/hooks/afterChange.spec.js +150 -0
- package/dist/hooks/afterChange.spec.js.map +1 -0
- package/dist/hooks/afterDelete.d.ts +3 -1
- package/dist/hooks/afterDelete.d.ts.map +1 -1
- package/dist/hooks/afterDelete.js +16 -2
- package/dist/hooks/afterDelete.js.map +1 -1
- package/dist/hooks/afterRead.d.ts.map +1 -1
- package/dist/hooks/afterRead.js +13 -2
- package/dist/hooks/afterRead.js.map +1 -1
- package/dist/hooks/beforeChange.d.ts.map +1 -1
- package/dist/hooks/beforeChange.js +10 -1
- package/dist/hooks/beforeChange.js.map +1 -1
- package/dist/hooks/normalizeUploadPrefix.d.ts +11 -0
- package/dist/hooks/normalizeUploadPrefix.d.ts.map +1 -0
- package/dist/hooks/normalizeUploadPrefix.js +42 -0
- package/dist/hooks/normalizeUploadPrefix.js.map +1 -0
- package/dist/hooks/normalizeUploadPrefix.spec.js +154 -0
- package/dist/hooks/normalizeUploadPrefix.spec.js.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +15 -6
- package/dist/plugin.js.map +1 -1
- package/dist/plugin.spec.js +166 -0
- package/dist/plugin.spec.js.map +1 -0
- package/dist/types.d.ts +23 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities/assertReceiptMatchesFileKey.d.ts +15 -0
- package/dist/utilities/assertReceiptMatchesFileKey.d.ts.map +1 -0
- package/dist/utilities/assertReceiptMatchesFileKey.js +31 -0
- package/dist/utilities/assertReceiptMatchesFileKey.js.map +1 -0
- package/dist/utilities/buildPrefixWithObjectKey.d.ts +8 -0
- package/dist/utilities/buildPrefixWithObjectKey.d.ts.map +1 -0
- package/dist/utilities/buildPrefixWithObjectKey.js +13 -0
- package/dist/utilities/buildPrefixWithObjectKey.js.map +1 -0
- package/dist/utilities/buildStoragePathData.d.ts +55 -0
- package/dist/utilities/buildStoragePathData.d.ts.map +1 -0
- package/dist/utilities/buildStoragePathData.js +69 -0
- package/dist/utilities/buildStoragePathData.js.map +1 -0
- package/dist/utilities/buildStoragePathData.spec.js +254 -0
- package/dist/utilities/buildStoragePathData.spec.js.map +1 -0
- package/dist/utilities/getFilePrefix.d.ts +27 -11
- package/dist/utilities/getFilePrefix.d.ts.map +1 -1
- package/dist/utilities/getFilePrefix.js +75 -31
- package/dist/utilities/getFilePrefix.js.map +1 -1
- package/dist/utilities/getFilePrefix.spec.js +221 -35
- package/dist/utilities/getFilePrefix.spec.js.map +1 -1
- package/dist/utilities/resolveSignedURLKey.d.ts +11 -0
- package/dist/utilities/resolveSignedURLKey.d.ts.map +1 -1
- package/dist/utilities/resolveSignedURLKey.js +43 -8
- package/dist/utilities/resolveSignedURLKey.js.map +1 -1
- package/dist/utilities/resolveSignedURLKey.spec.js +56 -0
- package/dist/utilities/resolveSignedURLKey.spec.js.map +1 -0
- package/dist/utilities/sanitizePrefix.d.ts +2 -2
- package/dist/utilities/sanitizePrefix.js +4 -4
- package/dist/utilities/sanitizePrefix.js.map +1 -1
- package/dist/utilities/verifyClientUploadReceiptForFileKey.d.ts +20 -0
- package/dist/utilities/verifyClientUploadReceiptForFileKey.d.ts.map +1 -0
- package/dist/utilities/verifyClientUploadReceiptForFileKey.js +24 -0
- package/dist/utilities/verifyClientUploadReceiptForFileKey.js.map +1 -0
- package/dist/utilities/verifyClientUploadReceiptForFileKey.spec.js +108 -0
- package/dist/utilities/verifyClientUploadReceiptForFileKey.spec.js.map +1 -0
- package/package.json +4 -4
|
@@ -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,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
|
|
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,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAItD,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;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,mBAAmB,CAAC,EACxC,gBAAqB,EACrB,cAAc,EACd,SAAS,EACT,QAAQ,EACR,GAAG,EACH,oBAA4B,GAC7B,EAAE,IAAI;;;;;;;GAiDN"}
|
|
@@ -1,29 +1,64 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { createClientUploadReceipt, getSafeFileName } from 'payload/internal';
|
|
3
|
+
import { getSanitizedUploadFilename } from 'payload/shared';
|
|
4
|
+
import { buildUploadPrefix, buildUploadStoragePathData } from './buildStoragePathData.js';
|
|
3
5
|
/**
|
|
4
6
|
* Resolves the storage key for a clientUploads signed-URL request, deduping
|
|
5
7
|
* the filename via {@link getSafeFileName} so a duplicate upload does not
|
|
6
8
|
* overwrite an existing blob.
|
|
7
9
|
*
|
|
10
|
+
* A per-upload segment is persisted in `_objectKey` (not `prefix`), so the stored `prefix`
|
|
11
|
+
* and `filename` stay clean.
|
|
12
|
+
*
|
|
8
13
|
* The resolved `sanitizedFilename` is returned so the browser-side handler
|
|
9
14
|
* can update the form via `updateFilename`.
|
|
15
|
+
*
|
|
16
|
+
* The semantic prefix is resolved with {@link buildUploadPrefix} and the final key with
|
|
17
|
+
* {@link buildUploadStoragePathData}, so the receipt only ever signs a key beneath the configured
|
|
18
|
+
* collection prefix.
|
|
10
19
|
*/ export async function resolveSignedURLKey({ collectionPrefix = '', collectionSlug, docPrefix, filename, req, useCompositePrefixes = false }) {
|
|
20
|
+
// Sanitize with the same helper generateFileData uses for the DB filename so the storage key
|
|
21
|
+
// and doc.filename stay in sync (#16694).
|
|
11
22
|
const sanitizedFilename = await getSafeFileName({
|
|
12
23
|
collectionSlug,
|
|
13
|
-
desiredFilename: filename,
|
|
14
|
-
prefix: docPrefix,
|
|
24
|
+
desiredFilename: getSanitizedUploadFilename(filename),
|
|
15
25
|
req
|
|
16
26
|
});
|
|
17
|
-
const
|
|
27
|
+
const rawBaseDocPrefix = useCompositePrefixes ? docPrefix : docPrefix || collectionPrefix;
|
|
28
|
+
const { sanitizedDocPrefix } = buildUploadPrefix({
|
|
18
29
|
collectionPrefix,
|
|
19
|
-
docPrefix,
|
|
30
|
+
docPrefix: rawBaseDocPrefix,
|
|
31
|
+
useCompositePrefixes
|
|
32
|
+
});
|
|
33
|
+
const _objectKey = randomUUID();
|
|
34
|
+
// Persisted in `_objectKey`, keeping `prefix` semantic.
|
|
35
|
+
const keyedDocPrefix = sanitizedDocPrefix ? `${sanitizedDocPrefix}/${_objectKey}` : _objectKey;
|
|
36
|
+
const { storageFilePath } = buildUploadStoragePathData({
|
|
37
|
+
collectionPrefix,
|
|
38
|
+
docPrefix: keyedDocPrefix,
|
|
20
39
|
filename: sanitizedFilename,
|
|
21
40
|
useCompositePrefixes
|
|
22
41
|
});
|
|
42
|
+
const context = {
|
|
43
|
+
_objectKey,
|
|
44
|
+
prefix: sanitizedDocPrefix
|
|
45
|
+
};
|
|
46
|
+
const clientUploadContext = {
|
|
47
|
+
...context,
|
|
48
|
+
signedReceipt: createClientUploadReceipt({
|
|
49
|
+
collectionSlug,
|
|
50
|
+
context,
|
|
51
|
+
filename: sanitizedFilename,
|
|
52
|
+
req
|
|
53
|
+
})
|
|
54
|
+
};
|
|
23
55
|
return {
|
|
24
|
-
|
|
56
|
+
_objectKey,
|
|
57
|
+
clientUploadContext,
|
|
58
|
+
fileKey: storageFilePath,
|
|
25
59
|
sanitizedDocPrefix,
|
|
26
|
-
sanitizedFilename
|
|
60
|
+
sanitizedFilename,
|
|
61
|
+
storageFilePath
|
|
27
62
|
};
|
|
28
63
|
}
|
|
29
64
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/resolveSignedURLKey.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { getSafeFileName } from 'payload/internal'\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/resolveSignedURLKey.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { randomUUID } from 'crypto'\nimport { createClientUploadReceipt, getSafeFileName } from 'payload/internal'\nimport { getSanitizedUploadFilename } from 'payload/shared'\n\nimport type { ClientUploadContext } 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 a clientUploads signed-URL request, deduping\n * the filename via {@link getSafeFileName} so a duplicate upload does not\n * overwrite an existing blob.\n *\n * A per-upload segment is persisted in `_objectKey` (not `prefix`), so the stored `prefix`\n * and `filename` stay clean.\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 key with\n * {@link buildUploadStoragePathData}, so the receipt only ever signs a key beneath the configured\n * collection prefix.\n */\nexport async function resolveSignedURLKey({\n collectionPrefix = '',\n collectionSlug,\n docPrefix,\n filename,\n req,\n useCompositePrefixes = false,\n}: Args) {\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 // 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 context = {\n _objectKey,\n prefix: sanitizedDocPrefix,\n }\n const clientUploadContext: ClientUploadContext = {\n ...context,\n signedReceipt: createClientUploadReceipt({\n collectionSlug,\n context,\n filename: sanitizedFilename,\n req,\n }),\n }\n\n return {\n _objectKey,\n clientUploadContext,\n fileKey: storageFilePath,\n sanitizedDocPrefix,\n sanitizedFilename,\n storageFilePath,\n }\n}\n"],"names":["randomUUID","createClientUploadReceipt","getSafeFileName","getSanitizedUploadFilename","buildUploadPrefix","buildUploadStoragePathData","resolveSignedURLKey","collectionPrefix","collectionSlug","docPrefix","filename","req","useCompositePrefixes","sanitizedFilename","desiredFilename","rawBaseDocPrefix","sanitizedDocPrefix","_objectKey","keyedDocPrefix","storageFilePath","context","prefix","clientUploadContext","signedReceipt","fileKey"],"mappings":"AAEA,SAASA,UAAU,QAAQ,SAAQ;AACnC,SAASC,yBAAyB,EAAEC,eAAe,QAAQ,mBAAkB;AAC7E,SAASC,0BAA0B,QAAQ,iBAAgB;AAI3D,SAASC,iBAAiB,EAAEC,0BAA0B,QAAQ,4BAA2B;AAWzF;;;;;;;;;;;;;;CAcC,GACD,OAAO,eAAeC,oBAAoB,EACxCC,mBAAmB,EAAE,EACrBC,cAAc,EACdC,SAAS,EACTC,QAAQ,EACRC,GAAG,EACHC,uBAAuB,KAAK,EACvB;IACL,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,wDAAwD;IACxD,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,UAAU;QACdH;QACAI,QAAQL;IACV;IACA,MAAMM,sBAA2C;QAC/C,GAAGF,OAAO;QACVG,eAAetB,0BAA0B;YACvCO;YACAY;YACAV,UAAUG;YACVF;QACF;IACF;IAEA,OAAO;QACLM;QACAK;QACAE,SAASL;QACTH;QACAH;QACAM;IACF;AACF"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { createClientUploadReceipt, getSafeFileName } from 'payload/internal';
|
|
3
|
+
import { resolveSignedURLKey } from './resolveSignedURLKey.js';
|
|
4
|
+
vi.mock('payload/internal', ()=>({
|
|
5
|
+
createClientUploadReceipt: vi.fn(()=>'receipt'),
|
|
6
|
+
getSafeFileName: vi.fn()
|
|
7
|
+
}));
|
|
8
|
+
describe('resolveSignedURLKey', ()=>{
|
|
9
|
+
beforeEach(()=>{
|
|
10
|
+
vi.clearAllMocks();
|
|
11
|
+
});
|
|
12
|
+
it('should deduplicate within the resolved document prefix', async ()=>{
|
|
13
|
+
vi.mocked(getSafeFileName).mockImplementation(async ({ desiredFilename })=>{
|
|
14
|
+
expect(desiredFilename).toBe('photo.jpg');
|
|
15
|
+
return 'photo-1.jpg';
|
|
16
|
+
});
|
|
17
|
+
const result = await resolveSignedURLKey({
|
|
18
|
+
collectionPrefix: 'media',
|
|
19
|
+
collectionSlug: 'media',
|
|
20
|
+
docPrefix: 'media-archive',
|
|
21
|
+
filename: 'photo.jpg',
|
|
22
|
+
req: {}
|
|
23
|
+
});
|
|
24
|
+
expect(result.sanitizedDocPrefix).toBe('media/media-archive');
|
|
25
|
+
expect(result.fileKey).toMatch(/^media\/media-archive\/[0-9a-f-]+\/photo-1\.jpg$/);
|
|
26
|
+
expect(result.sanitizedFilename).toBe('photo-1.jpg');
|
|
27
|
+
expect(result._objectKey).toMatch(/^[0-9a-f-]+$/);
|
|
28
|
+
expect(result.clientUploadContext).toMatchObject({
|
|
29
|
+
_objectKey: result._objectKey,
|
|
30
|
+
prefix: 'media/media-archive',
|
|
31
|
+
signedReceipt: 'receipt'
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
it('should mint the receipt for a prefix contained by the collection prefix', async ()=>{
|
|
35
|
+
vi.mocked(getSafeFileName).mockResolvedValue('photo-1.jpg');
|
|
36
|
+
const { _objectKey, sanitizedDocPrefix } = await resolveSignedURLKey({
|
|
37
|
+
collectionPrefix: 'media',
|
|
38
|
+
collectionSlug: 'media',
|
|
39
|
+
docPrefix: 'media-archive',
|
|
40
|
+
filename: 'photo.jpg',
|
|
41
|
+
req: {}
|
|
42
|
+
});
|
|
43
|
+
expect(sanitizedDocPrefix).toBe('media/media-archive');
|
|
44
|
+
expect(createClientUploadReceipt).toHaveBeenCalledWith({
|
|
45
|
+
collectionSlug: 'media',
|
|
46
|
+
context: {
|
|
47
|
+
_objectKey,
|
|
48
|
+
prefix: sanitizedDocPrefix
|
|
49
|
+
},
|
|
50
|
+
filename: 'photo-1.jpg',
|
|
51
|
+
req: {}
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=resolveSignedURLKey.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/resolveSignedURLKey.spec.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest'\n\nimport { createClientUploadReceipt, getSafeFileName } from 'payload/internal'\n\nimport { resolveSignedURLKey } from './resolveSignedURLKey.js'\n\nvi.mock('payload/internal', () => ({\n createClientUploadReceipt: vi.fn(() => 'receipt'),\n getSafeFileName: vi.fn(),\n}))\n\ndescribe('resolveSignedURLKey', () => {\n beforeEach(() => {\n vi.clearAllMocks()\n })\n\n it('should deduplicate within the resolved document prefix', async () => {\n vi.mocked(getSafeFileName).mockImplementation(async ({ desiredFilename }) => {\n expect(desiredFilename).toBe('photo.jpg')\n return 'photo-1.jpg'\n })\n\n const result = await resolveSignedURLKey({\n collectionPrefix: 'media',\n collectionSlug: 'media',\n docPrefix: 'media-archive',\n filename: 'photo.jpg',\n req: {} as PayloadRequest,\n })\n\n expect(result.sanitizedDocPrefix).toBe('media/media-archive')\n expect(result.fileKey).toMatch(/^media\\/media-archive\\/[0-9a-f-]+\\/photo-1\\.jpg$/)\n expect(result.sanitizedFilename).toBe('photo-1.jpg')\n expect(result._objectKey).toMatch(/^[0-9a-f-]+$/)\n expect(result.clientUploadContext).toMatchObject({\n _objectKey: result._objectKey,\n prefix: 'media/media-archive',\n signedReceipt: 'receipt',\n })\n })\n\n it('should mint the receipt for a prefix contained by the collection prefix', async () => {\n vi.mocked(getSafeFileName).mockResolvedValue('photo-1.jpg')\n\n const { _objectKey, sanitizedDocPrefix } = await resolveSignedURLKey({\n collectionPrefix: 'media',\n collectionSlug: 'media',\n docPrefix: 'media-archive',\n filename: 'photo.jpg',\n req: {} as PayloadRequest,\n })\n\n expect(sanitizedDocPrefix).toBe('media/media-archive')\n expect(createClientUploadReceipt).toHaveBeenCalledWith({\n collectionSlug: 'media',\n context: { _objectKey, prefix: sanitizedDocPrefix },\n filename: 'photo-1.jpg',\n req: {},\n })\n })\n})\n"],"names":["beforeEach","describe","expect","it","vi","createClientUploadReceipt","getSafeFileName","resolveSignedURLKey","mock","fn","clearAllMocks","mocked","mockImplementation","desiredFilename","toBe","result","collectionPrefix","collectionSlug","docPrefix","filename","req","sanitizedDocPrefix","fileKey","toMatch","sanitizedFilename","_objectKey","clientUploadContext","toMatchObject","prefix","signedReceipt","mockResolvedValue","toHaveBeenCalledWith","context"],"mappings":"AAEA,SAASA,UAAU,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,SAAQ;AAE7D,SAASC,yBAAyB,EAAEC,eAAe,QAAQ,mBAAkB;AAE7E,SAASC,mBAAmB,QAAQ,2BAA0B;AAE9DH,GAAGI,IAAI,CAAC,oBAAoB,IAAO,CAAA;QACjCH,2BAA2BD,GAAGK,EAAE,CAAC,IAAM;QACvCH,iBAAiBF,GAAGK,EAAE;IACxB,CAAA;AAEAR,SAAS,uBAAuB;IAC9BD,WAAW;QACTI,GAAGM,aAAa;IAClB;IAEAP,GAAG,0DAA0D;QAC3DC,GAAGO,MAAM,CAACL,iBAAiBM,kBAAkB,CAAC,OAAO,EAAEC,eAAe,EAAE;YACtEX,OAAOW,iBAAiBC,IAAI,CAAC;YAC7B,OAAO;QACT;QAEA,MAAMC,SAAS,MAAMR,oBAAoB;YACvCS,kBAAkB;YAClBC,gBAAgB;YAChBC,WAAW;YACXC,UAAU;YACVC,KAAK,CAAC;QACR;QAEAlB,OAAOa,OAAOM,kBAAkB,EAAEP,IAAI,CAAC;QACvCZ,OAAOa,OAAOO,OAAO,EAAEC,OAAO,CAAC;QAC/BrB,OAAOa,OAAOS,iBAAiB,EAAEV,IAAI,CAAC;QACtCZ,OAAOa,OAAOU,UAAU,EAAEF,OAAO,CAAC;QAClCrB,OAAOa,OAAOW,mBAAmB,EAAEC,aAAa,CAAC;YAC/CF,YAAYV,OAAOU,UAAU;YAC7BG,QAAQ;YACRC,eAAe;QACjB;IACF;IAEA1B,GAAG,2EAA2E;QAC5EC,GAAGO,MAAM,CAACL,iBAAiBwB,iBAAiB,CAAC;QAE7C,MAAM,EAAEL,UAAU,EAAEJ,kBAAkB,EAAE,GAAG,MAAMd,oBAAoB;YACnES,kBAAkB;YAClBC,gBAAgB;YAChBC,WAAW;YACXC,UAAU;YACVC,KAAK,CAAC;QACR;QAEAlB,OAAOmB,oBAAoBP,IAAI,CAAC;QAChCZ,OAAOG,2BAA2B0B,oBAAoB,CAAC;YACrDd,gBAAgB;YAChBe,SAAS;gBAAEP;gBAAYG,QAAQP;YAAmB;YAClDF,UAAU;YACVC,KAAK,CAAC;QACR;IACF;AACF"}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Decodes URI components once (so query-style `%2F` becomes `/`), rejects
|
|
5
5
|
* values that still contain percent-encodings after decoding (e.g. `%252f`),
|
|
6
|
-
* then normalizes slashes, drops `.` / `..` segments,
|
|
7
|
-
* and
|
|
6
|
+
* then removes control characters, normalizes slashes, drops `.` / `..` segments,
|
|
7
|
+
* and strips leading slashes.
|
|
8
8
|
*/
|
|
9
9
|
export declare function sanitizePrefix(prefix: string): string;
|
|
10
10
|
//# sourceMappingURL=sanitizePrefix.d.ts.map
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Decodes URI components once (so query-style `%2F` becomes `/`), rejects
|
|
5
5
|
* values that still contain percent-encodings after decoding (e.g. `%252f`),
|
|
6
|
-
* then normalizes slashes, drops `.` / `..` segments,
|
|
7
|
-
* and
|
|
6
|
+
* then removes control characters, normalizes slashes, drops `.` / `..` segments,
|
|
7
|
+
* and strips leading slashes.
|
|
8
8
|
*/ export function sanitizePrefix(prefix) {
|
|
9
9
|
let decodedPrefix;
|
|
10
10
|
try {
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
if (/%[0-9a-f]{2}/i.test(decodedPrefix)) {
|
|
17
17
|
return '';
|
|
18
18
|
}
|
|
19
|
-
return decodedPrefix
|
|
20
|
-
.replace(/[\x00-\x1f\x80-\x9f]/g, '');
|
|
19
|
+
return decodedPrefix// eslint-disable-next-line no-control-regex
|
|
20
|
+
.replace(/[\x00-\x1f\x80-\x9f]/g, '').replace(/\\/g, '/').split('/').filter((segment)=>segment && segment !== '..' && segment !== '.').join('/').replace(/^\/+/, '');
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
//# sourceMappingURL=sanitizePrefix.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/sanitizePrefix.ts"],"sourcesContent":["/**\n * Normalizes a storage prefix for use in object keys and URLs.\n *\n * Decodes URI components once (so query-style `%2F` becomes `/`), rejects\n * values that still contain percent-encodings after decoding (e.g. `%252f`),\n * then normalizes slashes, drops `.` / `..` segments
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/sanitizePrefix.ts"],"sourcesContent":["/**\n * Normalizes a storage prefix for use in object keys and URLs.\n *\n * Decodes URI components once (so query-style `%2F` becomes `/`), rejects\n * values that still contain percent-encodings after decoding (e.g. `%252f`),\n * then removes control characters, normalizes slashes, drops `.` / `..` segments,\n * and strips leading slashes.\n */\nexport function sanitizePrefix(prefix: string): string {\n let decodedPrefix: string\n\n try {\n decodedPrefix = decodeURIComponent(prefix)\n } catch {\n return ''\n }\n\n // Reject multi-encoded values (e.g. `%252f`) by allowing only a single decode pass.\n if (/%[0-9a-f]{2}/i.test(decodedPrefix)) {\n return ''\n }\n\n return (\n decodedPrefix\n // eslint-disable-next-line no-control-regex\n .replace(/[\\x00-\\x1f\\x80-\\x9f]/g, '')\n .replace(/\\\\/g, '/')\n .split('/')\n .filter((segment) => segment && segment !== '..' && segment !== '.')\n .join('/')\n .replace(/^\\/+/, '')\n )\n}\n"],"names":["sanitizePrefix","prefix","decodedPrefix","decodeURIComponent","test","replace","split","filter","segment","join"],"mappings":"AAAA;;;;;;;CAOC,GACD,OAAO,SAASA,eAAeC,MAAc;IAC3C,IAAIC;IAEJ,IAAI;QACFA,gBAAgBC,mBAAmBF;IACrC,EAAE,OAAM;QACN,OAAO;IACT;IAEA,oFAAoF;IACpF,IAAI,gBAAgBG,IAAI,CAACF,gBAAgB;QACvC,OAAO;IACT;IAEA,OACEA,aACE,4CAA4C;KAC3CG,OAAO,CAAC,yBAAyB,IACjCA,OAAO,CAAC,OAAO,KACfC,KAAK,CAAC,KACNC,MAAM,CAAC,CAACC,UAAYA,WAAWA,YAAY,QAAQA,YAAY,KAC/DC,IAAI,CAAC,KACLJ,OAAO,CAAC,QAAQ;AAEvB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PayloadRequest } from 'payload';
|
|
2
|
+
import type { ClientUploadReceipt } from 'payload/internal';
|
|
3
|
+
type Args = {
|
|
4
|
+
collectionPrefix?: string;
|
|
5
|
+
collectionSlug: string;
|
|
6
|
+
expectedFileKey: string;
|
|
7
|
+
req: PayloadRequest;
|
|
8
|
+
signedReceipt: string;
|
|
9
|
+
useCompositePrefixes?: boolean;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Authenticates a client-upload receipt and asserts it authorizes writing to
|
|
13
|
+
* `expectedFileKey`, returning the verified receipt. Combines
|
|
14
|
+
* {@link verifyClientUploadReceipt} (authentication + collection binding) with
|
|
15
|
+
* {@link assertReceiptMatchesFileKey} (storage-key binding) so an adapter binds
|
|
16
|
+
* the receipt to its request in a single call.
|
|
17
|
+
*/
|
|
18
|
+
export declare function verifyClientUploadReceiptForFileKey({ collectionPrefix, collectionSlug, expectedFileKey, req, signedReceipt, useCompositePrefixes, }: Args): ClientUploadReceipt;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=verifyClientUploadReceiptForFileKey.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifyClientUploadReceiptForFileKey.d.ts","sourceRoot":"","sources":["../../src/utilities/verifyClientUploadReceiptForFileKey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAM3D,KAAK,IAAI,GAAG;IACV,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,GAAG,EAAE,cAAc,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;IACrB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,mCAAmC,CAAC,EAClD,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,GAAG,EACH,aAAa,EACb,oBAAoB,GACrB,EAAE,IAAI,GAAG,mBAAmB,CAM5B"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { verifyClientUploadReceipt } from 'payload/internal';
|
|
2
|
+
import { assertReceiptMatchesFileKey } from './assertReceiptMatchesFileKey.js';
|
|
3
|
+
/**
|
|
4
|
+
* Authenticates a client-upload receipt and asserts it authorizes writing to
|
|
5
|
+
* `expectedFileKey`, returning the verified receipt. Combines
|
|
6
|
+
* {@link verifyClientUploadReceipt} (authentication + collection binding) with
|
|
7
|
+
* {@link assertReceiptMatchesFileKey} (storage-key binding) so an adapter binds
|
|
8
|
+
* the receipt to its request in a single call.
|
|
9
|
+
*/ export function verifyClientUploadReceiptForFileKey({ collectionPrefix, collectionSlug, expectedFileKey, req, signedReceipt, useCompositePrefixes }) {
|
|
10
|
+
const receipt = verifyClientUploadReceipt({
|
|
11
|
+
collectionSlug,
|
|
12
|
+
req,
|
|
13
|
+
signedReceipt
|
|
14
|
+
});
|
|
15
|
+
assertReceiptMatchesFileKey({
|
|
16
|
+
collectionPrefix,
|
|
17
|
+
expectedFileKey,
|
|
18
|
+
receipt,
|
|
19
|
+
useCompositePrefixes
|
|
20
|
+
});
|
|
21
|
+
return receipt;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=verifyClientUploadReceiptForFileKey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/verifyClientUploadReceiptForFileKey.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\nimport type { ClientUploadReceipt } from 'payload/internal'\n\nimport { verifyClientUploadReceipt } from 'payload/internal'\n\nimport { assertReceiptMatchesFileKey } from './assertReceiptMatchesFileKey.js'\n\ntype Args = {\n collectionPrefix?: string\n collectionSlug: string\n expectedFileKey: string\n req: PayloadRequest\n signedReceipt: string\n useCompositePrefixes?: boolean\n}\n\n/**\n * Authenticates a client-upload receipt and asserts it authorizes writing to\n * `expectedFileKey`, returning the verified receipt. Combines\n * {@link verifyClientUploadReceipt} (authentication + collection binding) with\n * {@link assertReceiptMatchesFileKey} (storage-key binding) so an adapter binds\n * the receipt to its request in a single call.\n */\nexport function verifyClientUploadReceiptForFileKey({\n collectionPrefix,\n collectionSlug,\n expectedFileKey,\n req,\n signedReceipt,\n useCompositePrefixes,\n}: Args): ClientUploadReceipt {\n const receipt = verifyClientUploadReceipt({ collectionSlug, req, signedReceipt })\n\n assertReceiptMatchesFileKey({ collectionPrefix, expectedFileKey, receipt, useCompositePrefixes })\n\n return receipt\n}\n"],"names":["verifyClientUploadReceipt","assertReceiptMatchesFileKey","verifyClientUploadReceiptForFileKey","collectionPrefix","collectionSlug","expectedFileKey","req","signedReceipt","useCompositePrefixes","receipt"],"mappings":"AAGA,SAASA,yBAAyB,QAAQ,mBAAkB;AAE5D,SAASC,2BAA2B,QAAQ,mCAAkC;AAW9E;;;;;;CAMC,GACD,OAAO,SAASC,oCAAoC,EAClDC,gBAAgB,EAChBC,cAAc,EACdC,eAAe,EACfC,GAAG,EACHC,aAAa,EACbC,oBAAoB,EACf;IACL,MAAMC,UAAUT,0BAA0B;QAAEI;QAAgBE;QAAKC;IAAc;IAE/EN,4BAA4B;QAAEE;QAAkBE;QAAiBI;QAASD;IAAqB;IAE/F,OAAOC;AACT"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { createClientUploadReceipt } from 'payload/internal';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { verifyClientUploadReceiptForFileKey } from './verifyClientUploadReceiptForFileKey.js';
|
|
4
|
+
const req = {
|
|
5
|
+
payload: {
|
|
6
|
+
secret: 'test-secret'
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
const issueReceipt = ({ collectionSlug = 'media', filename = 'photo.png', prefix })=>createClientUploadReceipt({
|
|
10
|
+
collectionSlug,
|
|
11
|
+
context: {
|
|
12
|
+
prefix
|
|
13
|
+
},
|
|
14
|
+
filename,
|
|
15
|
+
req
|
|
16
|
+
});
|
|
17
|
+
const verify = ({ expectedFileKey, signedReceipt, useCompositePrefixes })=>verifyClientUploadReceiptForFileKey({
|
|
18
|
+
collectionPrefix: 'media',
|
|
19
|
+
collectionSlug: 'media',
|
|
20
|
+
expectedFileKey,
|
|
21
|
+
req,
|
|
22
|
+
signedReceipt,
|
|
23
|
+
useCompositePrefixes
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* This guard is what lets adapters accept a caller-supplied storage key: the key is
|
|
27
|
+
* recomputed from the signed prefix and filename, so a receipt issued for one location
|
|
28
|
+
* cannot be replayed against another.
|
|
29
|
+
*/ describe('verifyClientUploadReceiptForFileKey', ()=>{
|
|
30
|
+
it('should accept the key the receipt was issued for', ()=>{
|
|
31
|
+
const signedReceipt = issueReceipt({
|
|
32
|
+
prefix: 'media/documents'
|
|
33
|
+
});
|
|
34
|
+
expect(verify({
|
|
35
|
+
expectedFileKey: 'media/documents/photo.png',
|
|
36
|
+
signedReceipt
|
|
37
|
+
}).filename).toBe('photo.png');
|
|
38
|
+
});
|
|
39
|
+
it.each([
|
|
40
|
+
[
|
|
41
|
+
'a sibling of the collection prefix',
|
|
42
|
+
'media-archive/photo.png'
|
|
43
|
+
],
|
|
44
|
+
[
|
|
45
|
+
'another collection',
|
|
46
|
+
'invoices/photo.png'
|
|
47
|
+
],
|
|
48
|
+
[
|
|
49
|
+
'another document prefix in the same collection',
|
|
50
|
+
'media/other-doc/photo.png'
|
|
51
|
+
],
|
|
52
|
+
[
|
|
53
|
+
'another filename under the issued prefix',
|
|
54
|
+
'media/documents/payroll.pdf'
|
|
55
|
+
]
|
|
56
|
+
])('should reject %s', (_case, expectedFileKey)=>{
|
|
57
|
+
const signedReceipt = issueReceipt({
|
|
58
|
+
prefix: 'media/documents'
|
|
59
|
+
});
|
|
60
|
+
expect(()=>verify({
|
|
61
|
+
expectedFileKey,
|
|
62
|
+
signedReceipt
|
|
63
|
+
})).toThrow('Client upload reference does not match this request.');
|
|
64
|
+
});
|
|
65
|
+
it('should reject a receipt issued for another collection', ()=>{
|
|
66
|
+
const signedReceipt = issueReceipt({
|
|
67
|
+
collectionSlug: 'invoices',
|
|
68
|
+
prefix: 'media/documents'
|
|
69
|
+
});
|
|
70
|
+
expect(()=>verify({
|
|
71
|
+
expectedFileKey: 'media/documents/photo.png',
|
|
72
|
+
signedReceipt
|
|
73
|
+
})).toThrow('Invalid or expired client upload reference.');
|
|
74
|
+
});
|
|
75
|
+
it('should reject a receipt whose prefix is not a string', ()=>{
|
|
76
|
+
const signedReceipt = issueReceipt({
|
|
77
|
+
prefix: {
|
|
78
|
+
nested: true
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
expect(()=>verify({
|
|
82
|
+
expectedFileKey: 'media/photo.png',
|
|
83
|
+
signedReceipt
|
|
84
|
+
})).toThrow('Client upload reference does not match this request.');
|
|
85
|
+
});
|
|
86
|
+
it('should reject a tampered signature', ()=>{
|
|
87
|
+
const signedReceipt = issueReceipt({
|
|
88
|
+
prefix: 'media/documents'
|
|
89
|
+
});
|
|
90
|
+
const [encodedReceipt] = signedReceipt.split('.');
|
|
91
|
+
expect(()=>verify({
|
|
92
|
+
expectedFileKey: 'media/documents/photo.png',
|
|
93
|
+
signedReceipt: `${encodedReceipt}.not-the-signature`
|
|
94
|
+
})).toThrow();
|
|
95
|
+
});
|
|
96
|
+
it('should recompute the key in composite mode', ()=>{
|
|
97
|
+
const signedReceipt = issueReceipt({
|
|
98
|
+
prefix: 'documents'
|
|
99
|
+
});
|
|
100
|
+
expect(verify({
|
|
101
|
+
expectedFileKey: 'media/documents/photo.png',
|
|
102
|
+
signedReceipt,
|
|
103
|
+
useCompositePrefixes: true
|
|
104
|
+
}).filename).toBe('photo.png');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
//# sourceMappingURL=verifyClientUploadReceiptForFileKey.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/verifyClientUploadReceiptForFileKey.spec.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { createClientUploadReceipt } from 'payload/internal'\nimport { describe, expect, it } from 'vitest'\n\nimport { verifyClientUploadReceiptForFileKey } from './verifyClientUploadReceiptForFileKey.js'\n\nconst req = { payload: { secret: 'test-secret' } } as unknown as PayloadRequest\n\nconst issueReceipt = ({\n collectionSlug = 'media',\n filename = 'photo.png',\n prefix,\n}: {\n collectionSlug?: string\n filename?: string\n prefix: unknown\n}) =>\n createClientUploadReceipt({\n collectionSlug,\n context: { prefix },\n filename,\n req,\n })\n\nconst verify = ({\n expectedFileKey,\n signedReceipt,\n useCompositePrefixes,\n}: {\n expectedFileKey: string\n signedReceipt: string\n useCompositePrefixes?: boolean\n}) =>\n verifyClientUploadReceiptForFileKey({\n collectionPrefix: 'media',\n collectionSlug: 'media',\n expectedFileKey,\n req,\n signedReceipt,\n useCompositePrefixes,\n })\n\n/**\n * This guard is what lets adapters accept a caller-supplied storage key: the key is\n * recomputed from the signed prefix and filename, so a receipt issued for one location\n * cannot be replayed against another.\n */\ndescribe('verifyClientUploadReceiptForFileKey', () => {\n it('should accept the key the receipt was issued for', () => {\n const signedReceipt = issueReceipt({ prefix: 'media/documents' })\n\n expect(verify({ expectedFileKey: 'media/documents/photo.png', signedReceipt }).filename).toBe(\n 'photo.png',\n )\n })\n\n it.each([\n ['a sibling of the collection prefix', 'media-archive/photo.png'],\n ['another collection', 'invoices/photo.png'],\n ['another document prefix in the same collection', 'media/other-doc/photo.png'],\n ['another filename under the issued prefix', 'media/documents/payroll.pdf'],\n ])('should reject %s', (_case, expectedFileKey) => {\n const signedReceipt = issueReceipt({ prefix: 'media/documents' })\n\n expect(() => verify({ expectedFileKey, signedReceipt })).toThrow(\n 'Client upload reference does not match this request.',\n )\n })\n\n it('should reject a receipt issued for another collection', () => {\n const signedReceipt = issueReceipt({ collectionSlug: 'invoices', prefix: 'media/documents' })\n\n expect(() => verify({ expectedFileKey: 'media/documents/photo.png', signedReceipt })).toThrow(\n 'Invalid or expired client upload reference.',\n )\n })\n\n it('should reject a receipt whose prefix is not a string', () => {\n const signedReceipt = issueReceipt({ prefix: { nested: true } })\n\n expect(() => verify({ expectedFileKey: 'media/photo.png', signedReceipt })).toThrow(\n 'Client upload reference does not match this request.',\n )\n })\n\n it('should reject a tampered signature', () => {\n const signedReceipt = issueReceipt({ prefix: 'media/documents' })\n const [encodedReceipt] = signedReceipt.split('.')\n\n expect(() =>\n verify({\n expectedFileKey: 'media/documents/photo.png',\n signedReceipt: `${encodedReceipt}.not-the-signature`,\n }),\n ).toThrow()\n })\n\n it('should recompute the key in composite mode', () => {\n const signedReceipt = issueReceipt({ prefix: 'documents' })\n\n expect(\n verify({\n expectedFileKey: 'media/documents/photo.png',\n signedReceipt,\n useCompositePrefixes: true,\n }).filename,\n ).toBe('photo.png')\n })\n})\n"],"names":["createClientUploadReceipt","describe","expect","it","verifyClientUploadReceiptForFileKey","req","payload","secret","issueReceipt","collectionSlug","filename","prefix","context","verify","expectedFileKey","signedReceipt","useCompositePrefixes","collectionPrefix","toBe","each","_case","toThrow","nested","encodedReceipt","split"],"mappings":"AAEA,SAASA,yBAAyB,QAAQ,mBAAkB;AAC5D,SAASC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7C,SAASC,mCAAmC,QAAQ,2CAA0C;AAE9F,MAAMC,MAAM;IAAEC,SAAS;QAAEC,QAAQ;IAAc;AAAE;AAEjD,MAAMC,eAAe,CAAC,EACpBC,iBAAiB,OAAO,EACxBC,WAAW,WAAW,EACtBC,MAAM,EAKP,GACCX,0BAA0B;QACxBS;QACAG,SAAS;YAAED;QAAO;QAClBD;QACAL;IACF;AAEF,MAAMQ,SAAS,CAAC,EACdC,eAAe,EACfC,aAAa,EACbC,oBAAoB,EAKrB,GACCZ,oCAAoC;QAClCa,kBAAkB;QAClBR,gBAAgB;QAChBK;QACAT;QACAU;QACAC;IACF;AAEF;;;;CAIC,GACDf,SAAS,uCAAuC;IAC9CE,GAAG,oDAAoD;QACrD,MAAMY,gBAAgBP,aAAa;YAAEG,QAAQ;QAAkB;QAE/DT,OAAOW,OAAO;YAAEC,iBAAiB;YAA6BC;QAAc,GAAGL,QAAQ,EAAEQ,IAAI,CAC3F;IAEJ;IAEAf,GAAGgB,IAAI,CAAC;QACN;YAAC;YAAsC;SAA0B;QACjE;YAAC;YAAsB;SAAqB;QAC5C;YAAC;YAAkD;SAA4B;QAC/E;YAAC;YAA4C;SAA8B;KAC5E,EAAE,oBAAoB,CAACC,OAAON;QAC7B,MAAMC,gBAAgBP,aAAa;YAAEG,QAAQ;QAAkB;QAE/DT,OAAO,IAAMW,OAAO;gBAAEC;gBAAiBC;YAAc,IAAIM,OAAO,CAC9D;IAEJ;IAEAlB,GAAG,yDAAyD;QAC1D,MAAMY,gBAAgBP,aAAa;YAAEC,gBAAgB;YAAYE,QAAQ;QAAkB;QAE3FT,OAAO,IAAMW,OAAO;gBAAEC,iBAAiB;gBAA6BC;YAAc,IAAIM,OAAO,CAC3F;IAEJ;IAEAlB,GAAG,wDAAwD;QACzD,MAAMY,gBAAgBP,aAAa;YAAEG,QAAQ;gBAAEW,QAAQ;YAAK;QAAE;QAE9DpB,OAAO,IAAMW,OAAO;gBAAEC,iBAAiB;gBAAmBC;YAAc,IAAIM,OAAO,CACjF;IAEJ;IAEAlB,GAAG,sCAAsC;QACvC,MAAMY,gBAAgBP,aAAa;YAAEG,QAAQ;QAAkB;QAC/D,MAAM,CAACY,eAAe,GAAGR,cAAcS,KAAK,CAAC;QAE7CtB,OAAO,IACLW,OAAO;gBACLC,iBAAiB;gBACjBC,eAAe,GAAGQ,eAAe,kBAAkB,CAAC;YACtD,IACAF,OAAO;IACX;IAEAlB,GAAG,8CAA8C;QAC/C,MAAMY,gBAAgBP,aAAa;YAAEG,QAAQ;QAAY;QAEzDT,OACEW,OAAO;YACLC,iBAAiB;YACjBC;YACAC,sBAAsB;QACxB,GAAGN,QAAQ,EACXQ,IAAI,CAAC;IACT;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payloadcms/plugin-cloud-storage",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.90.0",
|
|
4
4
|
"description": "The official cloud storage plugin for Payload CMS",
|
|
5
5
|
"homepage": "https://payloadcms.com",
|
|
6
6
|
"repository": {
|
|
@@ -51,18 +51,18 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"find-node-modules": "^2.1.3",
|
|
53
53
|
"range-parser": "^1.2.1",
|
|
54
|
-
"@payloadcms/ui": "3.
|
|
54
|
+
"@payloadcms/ui": "3.90.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/find-node-modules": "^2.1.2",
|
|
58
58
|
"@types/react": "19.2.14",
|
|
59
59
|
"@types/react-dom": "19.2.3",
|
|
60
|
-
"payload": "3.
|
|
60
|
+
"payload": "3.90.0"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
63
|
"react": "^19.0.1 || ^19.1.2 || ^19.2.1",
|
|
64
64
|
"react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1",
|
|
65
|
-
"payload": "3.
|
|
65
|
+
"payload": "3.90.0"
|
|
66
66
|
},
|
|
67
67
|
"publishConfig": {
|
|
68
68
|
"registry": "https://registry.npmjs.org/"
|