@payloadcms/plugin-cloud-storage 4.0.0-internal.7e57eed → 4.0.0-internal.8001944
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 +1 -1
- package/dist/exports/utilities.d.ts.map +1 -1
- package/dist/exports/utilities.js +1 -1
- package/dist/exports/utilities.js.map +1 -1
- package/dist/fields/getFields.d.ts +1 -5
- package/dist/fields/getFields.d.ts.map +1 -1
- package/dist/fields/getFields.js +47 -18
- 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 +76 -20
- package/dist/hooks/afterChange.js.map +1 -1
- 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 +15 -2
- package/dist/hooks/afterRead.js.map +1 -1
- package/dist/hooks/beforeChange.d.ts.map +1 -1
- package/dist/hooks/beforeChange.js +12 -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/plugin.d.ts.map +1 -1
- package/dist/plugin.js +43 -38
- package/dist/plugin.js.map +1 -1
- package/dist/types.d.ts +19 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- 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 +49 -0
- package/dist/utilities/buildStoragePathData.d.ts.map +1 -0
- package/dist/utilities/buildStoragePathData.js +67 -0
- package/dist/utilities/buildStoragePathData.js.map +1 -0
- package/dist/utilities/getFilePrefix.d.ts +18 -10
- package/dist/utilities/getFilePrefix.d.ts.map +1 -1
- package/dist/utilities/getFilePrefix.js +69 -29
- package/dist/utilities/getFilePrefix.js.map +1 -1
- package/dist/utilities/resolveSignedURLKey.d.ts +12 -1
- package/dist/utilities/resolveSignedURLKey.d.ts.map +1 -1
- package/dist/utilities/resolveSignedURLKey.js +42 -8
- package/dist/utilities/resolveSignedURLKey.js.map +1 -1
- package/dist/utilities/sanitizePrefix.d.ts +1 -9
- package/dist/utilities/sanitizePrefix.d.ts.map +1 -1
- package/dist/utilities/sanitizePrefix.js +1 -21
- package/dist/utilities/sanitizePrefix.js.map +1 -1
- package/package.json +6 -6
- package/dist/admin/fields/getFields.d.ts +0 -17
- package/dist/admin/fields/getFields.d.ts.map +0 -1
- package/dist/admin/fields/getFields.js +0 -98
- package/dist/admin/fields/getFields.js.map +0 -1
- package/dist/admin/index.d.ts +0 -4
- package/dist/admin/index.d.ts.map +0 -1
- package/dist/admin/index.js +0 -34
- package/dist/admin/index.js.map +0 -1
- package/dist/utilities/getFileKey.d.ts +0 -22
- package/dist/utilities/getFileKey.d.ts.map +0 -1
- package/dist/utilities/getFileKey.js +0 -23
- package/dist/utilities/getFileKey.js.map +0 -1
- package/dist/utilities/getFileKey.spec.js +0 -174
- package/dist/utilities/getFileKey.spec.js.map +0 -1
- package/dist/utilities/getFilePrefix.spec.js +0 -105
- package/dist/utilities/getFilePrefix.spec.js.map +0 -1
|
@@ -1,20 +1,28 @@
|
|
|
1
|
-
import type { CollectionConfig, PayloadRequest } from 'payload';
|
|
1
|
+
import type { CollectionConfig, PayloadRequest, TypeWithID } from 'payload';
|
|
2
2
|
/**
|
|
3
|
-
* Resolves the
|
|
4
|
-
* always returns a sanitized value.
|
|
3
|
+
* Resolves the folder a stored object lives under (semantic `prefix` plus `_objectKey`).
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* Resolved values are passed through `sanitizePrefix`.
|
|
5
|
+
* An already-authorized `doc` wins outright. Otherwise an `uploadReference` is used (its
|
|
6
|
+
* `prefix` re-contained with {@link buildUploadStoragePathData}, since it hasn't been verified against
|
|
7
|
+
* a signed receipt by every adapter). Otherwise the document is resolved with
|
|
8
|
+
* `overrideAccess: false`, any query-param prefix only narrows that lookup, and `_objectKey`
|
|
9
|
+
* is read from the resolved document via `showHiddenFields`.
|
|
12
10
|
*/
|
|
13
|
-
export declare function getFilePrefix({ collection, filename, prefixQueryParam, req, uploadReference, }: {
|
|
11
|
+
export declare function getFilePrefix({ collection, collectionPrefix, doc, filename, prefixQueryParam, req, uploadReference, useCompositePrefixes, }: {
|
|
14
12
|
collection: CollectionConfig;
|
|
13
|
+
collectionPrefix?: string;
|
|
14
|
+
doc?: {
|
|
15
|
+
_objectKey?: string;
|
|
16
|
+
prefix?: string;
|
|
17
|
+
} & TypeWithID;
|
|
15
18
|
filename: string;
|
|
19
|
+
/**
|
|
20
|
+
* Only narrows the access-controlled fallback lookup below; never trusted or
|
|
21
|
+
* returned directly. Prefer passing the access-checked document as `doc` instead.
|
|
22
|
+
*/
|
|
16
23
|
prefixQueryParam?: string;
|
|
17
24
|
req: PayloadRequest;
|
|
18
25
|
uploadReference?: unknown;
|
|
26
|
+
useCompositePrefixes?: boolean;
|
|
19
27
|
}): Promise<string>;
|
|
20
28
|
//# sourceMappingURL=getFilePrefix.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getFilePrefix.d.ts","sourceRoot":"","sources":["../../src/utilities/getFilePrefix.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAgB,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"getFilePrefix.d.ts","sourceRoot":"","sources":["../../src/utilities/getFilePrefix.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAgB,MAAM,SAAS,CAAA;AAMzF;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,EAClC,UAAU,EACV,gBAAgB,EAChB,GAAG,EACH,QAAQ,EACR,gBAAgB,EAChB,GAAG,EACH,eAAe,EACf,oBAA4B,GAC7B,EAAE;IACD,UAAU,EAAE,gBAAgB,CAAA;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,GAAG,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU,CAAA;IAC3D,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,GAAG,EAAE,cAAc,CAAA;IACnB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,GAAG,OAAO,CAAC,MAAM,CAAC,CAqElB"}
|
|
@@ -1,46 +1,86 @@
|
|
|
1
|
+
import { buildPrefixWithObjectKey } from './buildPrefixWithObjectKey.js';
|
|
2
|
+
import { buildUploadStoragePathData } from './buildStoragePathData.js';
|
|
1
3
|
import { sanitizePrefix } from './sanitizePrefix.js';
|
|
2
4
|
/**
|
|
3
|
-
* Resolves the
|
|
4
|
-
* always returns a sanitized value.
|
|
5
|
+
* Resolves the folder a stored object lives under (semantic `prefix` plus `_objectKey`).
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
* An already-authorized `doc` wins outright. Otherwise an `uploadReference` is used (its
|
|
8
|
+
* `prefix` re-contained with {@link buildUploadStoragePathData}, since it hasn't been verified against
|
|
9
|
+
* a signed receipt by every adapter). Otherwise the document is resolved with
|
|
10
|
+
* `overrideAccess: false`, any query-param prefix only narrows that lookup, and `_objectKey`
|
|
11
|
+
* is read from the resolved document via `showHiddenFields`.
|
|
12
|
+
*/ export async function getFilePrefix({ collection, collectionPrefix, doc, filename, prefixQueryParam, req, uploadReference, useCompositePrefixes = false }) {
|
|
13
|
+
// The serve path already loaded and authorized this document — trust it over any
|
|
14
|
+
// client-supplied upload reference or query prefix.
|
|
15
|
+
if (doc) {
|
|
16
|
+
return buildPrefixWithObjectKey({
|
|
17
|
+
objectKey: doc._objectKey,
|
|
18
|
+
prefix: doc.prefix
|
|
19
|
+
});
|
|
15
20
|
}
|
|
16
|
-
//
|
|
21
|
+
// Upload instructions call handlers without a document yet. Re-contain the claimed
|
|
22
|
+
// prefix — it hasn't been verified against a signed receipt by every adapter.
|
|
17
23
|
if (uploadReference && typeof uploadReference === 'object' && 'prefix' in uploadReference && typeof uploadReference.prefix === 'string') {
|
|
18
|
-
|
|
24
|
+
const referenceObjectKey = '_objectKey' in uploadReference ? uploadReference._objectKey : undefined;
|
|
25
|
+
const containedPrefix = buildUploadStoragePathData({
|
|
26
|
+
collectionPrefix,
|
|
27
|
+
docPrefix: uploadReference.prefix,
|
|
28
|
+
filename,
|
|
29
|
+
useCompositePrefixes
|
|
30
|
+
}).sanitizedDocPrefix;
|
|
31
|
+
return buildPrefixWithObjectKey({
|
|
32
|
+
objectKey: referenceObjectKey,
|
|
33
|
+
prefix: containedPrefix
|
|
34
|
+
});
|
|
19
35
|
}
|
|
36
|
+
// Reads without a query prefix or read-access constraints skip the endpoint's document lookup.
|
|
20
37
|
const imageSizes = collection?.upload?.imageSizes || [];
|
|
38
|
+
const filenameClause = {
|
|
39
|
+
or: [
|
|
40
|
+
{
|
|
41
|
+
filename: {
|
|
42
|
+
equals: filename
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
...imageSizes.map((imageSize)=>({
|
|
46
|
+
[`sizes.${imageSize.name}.filename`]: {
|
|
47
|
+
equals: filename
|
|
48
|
+
}
|
|
49
|
+
}))
|
|
50
|
+
]
|
|
51
|
+
};
|
|
52
|
+
// Only filter by prefix when the collection persists a `prefix` field (querying a missing field throws).
|
|
53
|
+
const hasPrefixField = collection.fields?.some((field)=>'name' in field && field.name === 'prefix');
|
|
54
|
+
const where = typeof prefixQueryParam === 'string' && hasPrefixField ? {
|
|
55
|
+
and: [
|
|
56
|
+
filenameClause,
|
|
57
|
+
{
|
|
58
|
+
prefix: {
|
|
59
|
+
equals: sanitizePrefix(prefixQueryParam)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
} : filenameClause;
|
|
21
64
|
const files = await req.payload.find({
|
|
22
65
|
collection: collection.slug,
|
|
23
66
|
depth: 0,
|
|
24
67
|
draft: true,
|
|
25
68
|
limit: 1,
|
|
69
|
+
overrideAccess: false,
|
|
26
70
|
pagination: false,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
]
|
|
40
|
-
}
|
|
71
|
+
req,
|
|
72
|
+
select: {
|
|
73
|
+
_objectKey: true,
|
|
74
|
+
prefix: true
|
|
75
|
+
},
|
|
76
|
+
showHiddenFields: true,
|
|
77
|
+
where
|
|
78
|
+
});
|
|
79
|
+
const found = files?.docs?.[0];
|
|
80
|
+
return buildPrefixWithObjectKey({
|
|
81
|
+
objectKey: found?._objectKey,
|
|
82
|
+
prefix: found?.prefix
|
|
41
83
|
});
|
|
42
|
-
const prefix = files?.docs?.[0]?.prefix;
|
|
43
|
-
return prefix ? sanitizePrefix(prefix) : '';
|
|
44
84
|
}
|
|
45
85
|
|
|
46
86
|
//# sourceMappingURL=getFilePrefix.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/getFilePrefix.ts"],"sourcesContent":["import type { CollectionConfig, PayloadRequest, UploadConfig } from 'payload'\n\nimport { sanitizePrefix } from './sanitizePrefix.js'\n\n/**\n * Resolves the
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/getFilePrefix.ts"],"sourcesContent":["import type { CollectionConfig, PayloadRequest, TypeWithID, UploadConfig } from 'payload'\n\nimport { buildPrefixWithObjectKey } from './buildPrefixWithObjectKey.js'\nimport { buildUploadStoragePathData } from './buildStoragePathData.js'\nimport { sanitizePrefix } from './sanitizePrefix.js'\n\n/**\n * Resolves the folder a stored object lives under (semantic `prefix` plus `_objectKey`).\n *\n * An already-authorized `doc` wins outright. Otherwise an `uploadReference` is used (its\n * `prefix` re-contained with {@link buildUploadStoragePathData}, since it hasn't been verified against\n * a signed receipt by every adapter). Otherwise the document is resolved with\n * `overrideAccess: false`, any query-param prefix only narrows that lookup, and `_objectKey`\n * is read from the resolved document via `showHiddenFields`.\n */\nexport async function getFilePrefix({\n collection,\n collectionPrefix,\n doc,\n filename,\n prefixQueryParam,\n req,\n uploadReference,\n useCompositePrefixes = false,\n}: {\n collection: CollectionConfig\n collectionPrefix?: string\n doc?: { _objectKey?: string; prefix?: string } & TypeWithID\n filename: string\n /**\n * Only narrows the access-controlled fallback lookup below; never trusted or\n * returned directly. Prefer passing the access-checked document as `doc` instead.\n */\n prefixQueryParam?: string\n req: PayloadRequest\n uploadReference?: unknown\n useCompositePrefixes?: boolean\n}): Promise<string> {\n // The serve path already loaded and authorized this document — trust it over any\n // client-supplied upload reference or query prefix.\n if (doc) {\n return buildPrefixWithObjectKey({ objectKey: doc._objectKey, prefix: doc.prefix })\n }\n\n // Upload instructions call handlers without a document yet. Re-contain the claimed\n // prefix — it hasn't been verified against a signed receipt by every adapter.\n if (\n uploadReference &&\n typeof uploadReference === 'object' &&\n 'prefix' in uploadReference &&\n typeof uploadReference.prefix === 'string'\n ) {\n const referenceObjectKey =\n '_objectKey' in uploadReference\n ? (uploadReference as { _objectKey?: string })._objectKey\n : undefined\n const containedPrefix = buildUploadStoragePathData({\n collectionPrefix,\n docPrefix: uploadReference.prefix,\n filename,\n useCompositePrefixes,\n }).sanitizedDocPrefix\n return buildPrefixWithObjectKey({ objectKey: referenceObjectKey, prefix: containedPrefix })\n }\n\n // Reads without a query prefix or read-access constraints skip the endpoint's document lookup.\n const imageSizes = (collection?.upload as UploadConfig)?.imageSizes || []\n\n const filenameClause = {\n or: [\n {\n filename: { equals: filename },\n },\n ...imageSizes.map((imageSize) => ({\n [`sizes.${imageSize.name}.filename`]: { equals: filename },\n })),\n ],\n }\n\n // Only filter by prefix when the collection persists a `prefix` field (querying a missing field throws).\n const hasPrefixField = collection.fields?.some(\n (field) => 'name' in field && field.name === 'prefix',\n )\n const where =\n typeof prefixQueryParam === 'string' && hasPrefixField\n ? { and: [filenameClause, { prefix: { equals: sanitizePrefix(prefixQueryParam) } }] }\n : filenameClause\n\n const files = await req.payload.find({\n collection: collection.slug,\n depth: 0,\n draft: true,\n limit: 1,\n overrideAccess: false,\n pagination: false,\n req,\n select: {\n _objectKey: true,\n prefix: true,\n },\n showHiddenFields: true,\n where,\n })\n\n const found = files?.docs?.[0] as { _objectKey?: string; prefix?: string } | undefined\n return buildPrefixWithObjectKey({ objectKey: found?._objectKey, prefix: found?.prefix })\n}\n"],"names":["buildPrefixWithObjectKey","buildUploadStoragePathData","sanitizePrefix","getFilePrefix","collection","collectionPrefix","doc","filename","prefixQueryParam","req","uploadReference","useCompositePrefixes","objectKey","_objectKey","prefix","referenceObjectKey","undefined","containedPrefix","docPrefix","sanitizedDocPrefix","imageSizes","upload","filenameClause","or","equals","map","imageSize","name","hasPrefixField","fields","some","field","where","and","files","payload","find","slug","depth","draft","limit","overrideAccess","pagination","select","showHiddenFields","found","docs"],"mappings":"AAEA,SAASA,wBAAwB,QAAQ,gCAA+B;AACxE,SAASC,0BAA0B,QAAQ,4BAA2B;AACtE,SAASC,cAAc,QAAQ,sBAAqB;AAEpD;;;;;;;;CAQC,GACD,OAAO,eAAeC,cAAc,EAClCC,UAAU,EACVC,gBAAgB,EAChBC,GAAG,EACHC,QAAQ,EACRC,gBAAgB,EAChBC,GAAG,EACHC,eAAe,EACfC,uBAAuB,KAAK,EAc7B;IACC,iFAAiF;IACjF,oDAAoD;IACpD,IAAIL,KAAK;QACP,OAAON,yBAAyB;YAAEY,WAAWN,IAAIO,UAAU;YAAEC,QAAQR,IAAIQ,MAAM;QAAC;IAClF;IAEA,mFAAmF;IACnF,8EAA8E;IAC9E,IACEJ,mBACA,OAAOA,oBAAoB,YAC3B,YAAYA,mBACZ,OAAOA,gBAAgBI,MAAM,KAAK,UAClC;QACA,MAAMC,qBACJ,gBAAgBL,kBACZ,AAACA,gBAA4CG,UAAU,GACvDG;QACN,MAAMC,kBAAkBhB,2BAA2B;YACjDI;YACAa,WAAWR,gBAAgBI,MAAM;YACjCP;YACAI;QACF,GAAGQ,kBAAkB;QACrB,OAAOnB,yBAAyB;YAAEY,WAAWG;YAAoBD,QAAQG;QAAgB;IAC3F;IAEA,+FAA+F;IAC/F,MAAMG,aAAa,AAAChB,YAAYiB,QAAyBD,cAAc,EAAE;IAEzE,MAAME,iBAAiB;QACrBC,IAAI;YACF;gBACEhB,UAAU;oBAAEiB,QAAQjB;gBAAS;YAC/B;eACGa,WAAWK,GAAG,CAAC,CAACC,YAAe,CAAA;oBAChC,CAAC,CAAC,MAAM,EAAEA,UAAUC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE;wBAAEH,QAAQjB;oBAAS;gBAC3D,CAAA;SACD;IACH;IAEA,yGAAyG;IACzG,MAAMqB,iBAAiBxB,WAAWyB,MAAM,EAAEC,KACxC,CAACC,QAAU,UAAUA,SAASA,MAAMJ,IAAI,KAAK;IAE/C,MAAMK,QACJ,OAAOxB,qBAAqB,YAAYoB,iBACpC;QAAEK,KAAK;YAACX;YAAgB;gBAAER,QAAQ;oBAAEU,QAAQtB,eAAeM;gBAAkB;YAAE;SAAE;IAAC,IAClFc;IAEN,MAAMY,QAAQ,MAAMzB,IAAI0B,OAAO,CAACC,IAAI,CAAC;QACnChC,YAAYA,WAAWiC,IAAI;QAC3BC,OAAO;QACPC,OAAO;QACPC,OAAO;QACPC,gBAAgB;QAChBC,YAAY;QACZjC;QACAkC,QAAQ;YACN9B,YAAY;YACZC,QAAQ;QACV;QACA8B,kBAAkB;QAClBZ;IACF;IAEA,MAAMa,QAAQX,OAAOY,MAAM,CAAC,EAAE;IAC9B,OAAO9C,yBAAyB;QAAEY,WAAWiC,OAAOhC;QAAYC,QAAQ+B,OAAO/B;IAAO;AACxF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PayloadRequest } from 'payload';
|
|
2
|
+
import type { UploadReference } from '../types.js';
|
|
2
3
|
type Args = {
|
|
3
4
|
collectionPrefix?: string;
|
|
4
5
|
collectionSlug: string;
|
|
@@ -12,13 +13,23 @@ type Args = {
|
|
|
12
13
|
* the filename via {@link getSafeFileName} so a duplicate upload does not
|
|
13
14
|
* overwrite an existing blob.
|
|
14
15
|
*
|
|
16
|
+
* A unique per-upload segment is included in the storage key so each issued
|
|
17
|
+
* key is distinct. The stored `filename` stays clean and the semantic `prefix`
|
|
18
|
+
* stays exactly what the collection configured — the per-upload entropy is
|
|
19
|
+
* persisted separately in `_objectKey`.
|
|
20
|
+
*
|
|
15
21
|
* The resolved `sanitizedFilename` is returned so the browser-side handler
|
|
16
22
|
* can update the form via `updateFilename`.
|
|
23
|
+
*
|
|
24
|
+
* The semantic prefix is resolved with {@link buildUploadPrefix} and the final
|
|
25
|
+
* key with {@link buildUploadStoragePathData}, so the receipt only ever signs a key
|
|
26
|
+
* beneath the configured collection prefix.
|
|
17
27
|
*/
|
|
18
28
|
export declare function resolveSignedURLKey({ collectionPrefix, collectionSlug, docPrefix, filename, req, useCompositePrefixes, }: Args): Promise<{
|
|
19
|
-
fileKey: string;
|
|
20
29
|
sanitizedDocPrefix: string;
|
|
21
30
|
sanitizedFilename: string;
|
|
31
|
+
storageFilePath: string;
|
|
32
|
+
uploadReference: UploadReference;
|
|
22
33
|
}>;
|
|
23
34
|
export {};
|
|
24
35
|
//# sourceMappingURL=resolveSignedURLKey.d.ts.map
|
|
@@ -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,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,29 +1,63 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { randomUUID } from 'node: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 an upload-instructions 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 unique per-upload segment is included in the storage key so each issued
|
|
11
|
+
* key is distinct. The stored `filename` stays clean and the semantic `prefix`
|
|
12
|
+
* stays exactly what the collection configured — the per-upload entropy is
|
|
13
|
+
* persisted separately in `_objectKey`.
|
|
14
|
+
*
|
|
8
15
|
* The resolved `sanitizedFilename` is returned so the browser-side handler
|
|
9
16
|
* can update the form via `updateFilename`.
|
|
17
|
+
*
|
|
18
|
+
* The semantic prefix is resolved with {@link buildUploadPrefix} and the final
|
|
19
|
+
* key with {@link buildUploadStoragePathData}, so the receipt only ever signs a key
|
|
20
|
+
* beneath the configured collection prefix.
|
|
10
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).
|
|
11
24
|
const sanitizedFilename = await getSafeFileName({
|
|
12
25
|
collectionSlug,
|
|
13
|
-
desiredFilename: filename,
|
|
14
|
-
prefix: docPrefix,
|
|
26
|
+
desiredFilename: getSanitizedUploadFilename(filename),
|
|
15
27
|
req
|
|
16
28
|
});
|
|
17
|
-
const
|
|
29
|
+
const rawBaseDocPrefix = useCompositePrefixes ? docPrefix : docPrefix || collectionPrefix;
|
|
30
|
+
const { sanitizedDocPrefix } = buildUploadPrefix({
|
|
31
|
+
collectionPrefix,
|
|
32
|
+
docPrefix: rawBaseDocPrefix,
|
|
33
|
+
useCompositePrefixes
|
|
34
|
+
});
|
|
35
|
+
const _objectKey = randomUUID();
|
|
36
|
+
// Per-upload segment lives in the key; it is persisted in `_objectKey`, keeping `prefix` semantic.
|
|
37
|
+
const keyedDocPrefix = sanitizedDocPrefix ? `${sanitizedDocPrefix}/${_objectKey}` : _objectKey;
|
|
38
|
+
const { storageFilePath } = buildUploadStoragePathData({
|
|
18
39
|
collectionPrefix,
|
|
19
|
-
docPrefix,
|
|
40
|
+
docPrefix: keyedDocPrefix,
|
|
20
41
|
filename: sanitizedFilename,
|
|
21
42
|
useCompositePrefixes
|
|
22
43
|
});
|
|
44
|
+
const uploadReference = {
|
|
45
|
+
_objectKey,
|
|
46
|
+
prefix: sanitizedDocPrefix,
|
|
47
|
+
signedReceipt: createClientUploadReceipt({
|
|
48
|
+
_objectKey,
|
|
49
|
+
collectionSlug,
|
|
50
|
+
filename: sanitizedFilename,
|
|
51
|
+
filePrefix: sanitizedDocPrefix,
|
|
52
|
+
req,
|
|
53
|
+
storageFilePath
|
|
54
|
+
})
|
|
55
|
+
};
|
|
23
56
|
return {
|
|
24
|
-
fileKey,
|
|
25
57
|
sanitizedDocPrefix,
|
|
26
|
-
sanitizedFilename
|
|
58
|
+
sanitizedFilename,
|
|
59
|
+
storageFilePath,
|
|
60
|
+
uploadReference
|
|
27
61
|
};
|
|
28
62
|
}
|
|
29
63
|
|
|
@@ -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 '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,10 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* Normalizes a storage prefix for use in object keys and URLs.
|
|
3
|
-
*
|
|
4
|
-
* Decodes URI components once (so query-style `%2F` becomes `/`), rejects
|
|
5
|
-
* values that still contain percent-encodings after decoding (e.g. `%252f`),
|
|
6
|
-
* then normalizes slashes, drops `.` / `..` segments, strips leading slashes,
|
|
7
|
-
* and removes control characters.
|
|
8
|
-
*/
|
|
9
|
-
export declare function sanitizePrefix(prefix: string): string;
|
|
1
|
+
export { sanitizeUploadPrefix as sanitizePrefix } from 'payload/shared';
|
|
10
2
|
//# sourceMappingURL=sanitizePrefix.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitizePrefix.d.ts","sourceRoot":"","sources":["../../src/utilities/sanitizePrefix.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"sanitizePrefix.d.ts","sourceRoot":"","sources":["../../src/utilities/sanitizePrefix.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,IAAI,cAAc,EAAE,MAAM,gBAAgB,CAAA"}
|
|
@@ -1,23 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
* Normalizes a storage prefix for use in object keys and URLs.
|
|
3
|
-
*
|
|
4
|
-
* Decodes URI components once (so query-style `%2F` becomes `/`), rejects
|
|
5
|
-
* values that still contain percent-encodings after decoding (e.g. `%252f`),
|
|
6
|
-
* then normalizes slashes, drops `.` / `..` segments, strips leading slashes,
|
|
7
|
-
* and removes control characters.
|
|
8
|
-
*/ export function sanitizePrefix(prefix) {
|
|
9
|
-
let decodedPrefix;
|
|
10
|
-
try {
|
|
11
|
-
decodedPrefix = decodeURIComponent(prefix);
|
|
12
|
-
} catch {
|
|
13
|
-
return '';
|
|
14
|
-
}
|
|
15
|
-
// Reject multi-encoded values (e.g. `%252f`) by allowing only a single decode pass.
|
|
16
|
-
if (/%[0-9a-f]{2}/i.test(decodedPrefix)) {
|
|
17
|
-
return '';
|
|
18
|
-
}
|
|
19
|
-
return decodedPrefix.replace(/\\/g, '/').split('/').filter((segment)=>segment !== '..' && segment !== '.').join('/').replace(/^\/+/, '')// eslint-disable-next-line no-control-regex
|
|
20
|
-
.replace(/[\x00-\x1f\x80-\x9f]/g, '');
|
|
21
|
-
}
|
|
1
|
+
export { sanitizeUploadPrefix as sanitizePrefix } from 'payload/shared';
|
|
22
2
|
|
|
23
3
|
//# sourceMappingURL=sanitizePrefix.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/sanitizePrefix.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/sanitizePrefix.ts"],"sourcesContent":["export { sanitizeUploadPrefix as sanitizePrefix } from 'payload/shared'\n"],"names":["sanitizeUploadPrefix","sanitizePrefix"],"mappings":"AAAA,SAASA,wBAAwBC,cAAc,QAAQ,iBAAgB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payloadcms/plugin-cloud-storage",
|
|
3
|
-
"version": "4.0.0-internal.
|
|
3
|
+
"version": "4.0.0-internal.8001944",
|
|
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": "4.0.0-internal.
|
|
54
|
+
"@payloadcms/ui": "4.0.0-internal.8001944"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/find-node-modules": "^2.1.2",
|
|
58
|
-
"@types/react": "19.
|
|
59
|
-
"@types/react-dom": "19.
|
|
60
|
-
"payload": "4.0.0-internal.
|
|
58
|
+
"@types/react": "19.3.0",
|
|
59
|
+
"@types/react-dom": "19.3.0",
|
|
60
|
+
"payload": "4.0.0-internal.8001944"
|
|
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": "4.0.0-internal.
|
|
65
|
+
"payload": "4.0.0-internal.8001944"
|
|
66
66
|
},
|
|
67
67
|
"publishConfig": {
|
|
68
68
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { CollectionConfig, Field } from 'payload';
|
|
2
|
-
interface Args {
|
|
3
|
-
/**
|
|
4
|
-
* When true, always insert the prefix field regardless of whether a prefix is configured.
|
|
5
|
-
*/
|
|
6
|
-
alwaysInsertFields?: boolean;
|
|
7
|
-
collection: CollectionConfig;
|
|
8
|
-
prefix?: string;
|
|
9
|
-
/**
|
|
10
|
-
* When true, do not default the `prefix` field to the collection prefix; the
|
|
11
|
-
* document field holds only the document-level segment.
|
|
12
|
-
*/
|
|
13
|
-
useCompositePrefixes?: boolean;
|
|
14
|
-
}
|
|
15
|
-
export declare const getFields: ({ alwaysInsertFields, collection, prefix, useCompositePrefixes, }: Args) => Field[];
|
|
16
|
-
export {};
|
|
17
|
-
//# sourceMappingURL=getFields.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getFields.d.ts","sourceRoot":"","sources":["../../../src/admin/fields/getFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAyB,MAAM,SAAS,CAAA;AAI7E,UAAU,IAAI;IACZ;;OAEG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,UAAU,EAAE,gBAAgB,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,eAAO,MAAM,SAAS,sEAKnB,IAAI,KAAG,KAAK,EAsHd,CAAA"}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
export const getFields = ({ alwaysInsertFields, collection, prefix, useCompositePrefixes = false })=>{
|
|
3
|
-
const baseURLField = {
|
|
4
|
-
name: 'url',
|
|
5
|
-
type: 'text',
|
|
6
|
-
admin: {
|
|
7
|
-
hidden: true,
|
|
8
|
-
readOnly: true
|
|
9
|
-
},
|
|
10
|
-
label: 'URL'
|
|
11
|
-
};
|
|
12
|
-
const basePrefixField = {
|
|
13
|
-
name: 'prefix',
|
|
14
|
-
type: 'text',
|
|
15
|
-
admin: {
|
|
16
|
-
hidden: true,
|
|
17
|
-
readOnly: true
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
const fields = [
|
|
21
|
-
...collection.fields
|
|
22
|
-
];
|
|
23
|
-
// Inject a hook into all URL fields to generate URLs
|
|
24
|
-
let existingURLFieldIndex = -1;
|
|
25
|
-
const existingURLField = fields.find((existingField, i)=>{
|
|
26
|
-
if ('name' in existingField && existingField.name === 'url') {
|
|
27
|
-
existingURLFieldIndex = i;
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
return false;
|
|
31
|
-
});
|
|
32
|
-
if (existingURLFieldIndex > -1) {
|
|
33
|
-
fields.splice(existingURLFieldIndex, 1);
|
|
34
|
-
}
|
|
35
|
-
fields.push({
|
|
36
|
-
...baseURLField,
|
|
37
|
-
...existingURLField || {}
|
|
38
|
-
});
|
|
39
|
-
if (typeof collection.upload === 'object' && collection.upload.imageSizes) {
|
|
40
|
-
let existingSizesFieldIndex = -1;
|
|
41
|
-
const existingSizesField = fields.find((existingField, i)=>{
|
|
42
|
-
if ('name' in existingField && existingField.name === 'sizes') {
|
|
43
|
-
existingSizesFieldIndex = i;
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
return false;
|
|
47
|
-
});
|
|
48
|
-
if (existingSizesFieldIndex > -1) {
|
|
49
|
-
fields.splice(existingSizesFieldIndex, 1);
|
|
50
|
-
}
|
|
51
|
-
const sizesField = {
|
|
52
|
-
...existingSizesField || {},
|
|
53
|
-
name: 'sizes',
|
|
54
|
-
type: 'group',
|
|
55
|
-
admin: {
|
|
56
|
-
hidden: true
|
|
57
|
-
},
|
|
58
|
-
fields: collection.upload.imageSizes.map((size)=>{
|
|
59
|
-
const existingSizeField = existingSizesField?.fields.find((existingField)=>'name' in existingField && existingField.name === size.name);
|
|
60
|
-
const existingSizeURLField = existingSizeField?.fields.find((existingField)=>'name' in existingField && existingField.name === 'url');
|
|
61
|
-
return {
|
|
62
|
-
...existingSizeField,
|
|
63
|
-
name: size.name,
|
|
64
|
-
type: 'group',
|
|
65
|
-
fields: [
|
|
66
|
-
{
|
|
67
|
-
...existingSizeURLField || {},
|
|
68
|
-
...baseURLField
|
|
69
|
-
}
|
|
70
|
-
]
|
|
71
|
-
};
|
|
72
|
-
})
|
|
73
|
-
};
|
|
74
|
-
fields.push(sizesField);
|
|
75
|
-
}
|
|
76
|
-
// If prefix is enabled or alwaysInsertFields is true, save it to db
|
|
77
|
-
if (typeof prefix !== 'undefined' || alwaysInsertFields) {
|
|
78
|
-
let existingPrefixFieldIndex = -1;
|
|
79
|
-
const existingPrefixField = fields.find((existingField, i)=>{
|
|
80
|
-
if ('name' in existingField && existingField.name === 'prefix') {
|
|
81
|
-
existingPrefixFieldIndex = i;
|
|
82
|
-
return true;
|
|
83
|
-
}
|
|
84
|
-
return false;
|
|
85
|
-
});
|
|
86
|
-
if (existingPrefixFieldIndex > -1) {
|
|
87
|
-
fields.splice(existingPrefixFieldIndex, 1);
|
|
88
|
-
}
|
|
89
|
-
fields.push({
|
|
90
|
-
...basePrefixField,
|
|
91
|
-
...existingPrefixField || {},
|
|
92
|
-
defaultValue: existingPrefixField?.defaultValue ?? (useCompositePrefixes ? '' : prefix ? path.posix.join(prefix) : '')
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
return fields;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
//# sourceMappingURL=getFields.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/fields/getFields.ts"],"sourcesContent":["import type { CollectionConfig, Field, GroupField, TextField } from 'payload'\n\nimport path from 'path'\n\ninterface Args {\n /**\n * When true, always insert the prefix field regardless of whether a prefix is configured.\n */\n alwaysInsertFields?: boolean\n collection: CollectionConfig\n prefix?: string\n /**\n * When true, do not default the `prefix` field to the collection prefix; the\n * document field holds only the document-level segment.\n */\n useCompositePrefixes?: boolean\n}\n\nexport const getFields = ({\n alwaysInsertFields,\n collection,\n prefix,\n useCompositePrefixes = false,\n}: Args): Field[] => {\n const baseURLField: TextField = {\n name: 'url',\n type: 'text',\n admin: {\n hidden: true,\n readOnly: true,\n },\n label: 'URL',\n }\n\n const basePrefixField: TextField = {\n name: 'prefix',\n type: 'text',\n admin: {\n hidden: true,\n readOnly: true,\n },\n }\n\n const fields = [...collection.fields]\n\n // Inject a hook into all URL fields to generate URLs\n\n let existingURLFieldIndex = -1\n\n const existingURLField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'url') {\n existingURLFieldIndex = i\n return true\n }\n return false\n }) as TextField\n\n if (existingURLFieldIndex > -1) {\n fields.splice(existingURLFieldIndex, 1)\n }\n\n fields.push({\n ...baseURLField,\n ...(existingURLField || {}),\n } as TextField)\n\n if (typeof collection.upload === 'object' && collection.upload.imageSizes) {\n let existingSizesFieldIndex = -1\n\n const existingSizesField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'sizes') {\n existingSizesFieldIndex = i\n return true\n }\n\n return false\n }) as GroupField\n\n if (existingSizesFieldIndex > -1) {\n fields.splice(existingSizesFieldIndex, 1)\n }\n\n const sizesField: Field = {\n ...(existingSizesField || {}),\n name: 'sizes',\n type: 'group',\n admin: {\n hidden: true,\n },\n fields: collection.upload.imageSizes.map((size) => {\n const existingSizeField = existingSizesField?.fields.find(\n (existingField) => 'name' in existingField && existingField.name === size.name,\n ) as GroupField\n\n const existingSizeURLField = existingSizeField?.fields.find(\n (existingField) => 'name' in existingField && existingField.name === 'url',\n ) as GroupField\n\n return {\n ...existingSizeField,\n name: size.name,\n type: 'group',\n fields: [\n {\n ...(existingSizeURLField || {}),\n ...baseURLField,\n },\n ],\n } as Field\n }),\n }\n\n fields.push(sizesField)\n }\n\n // If prefix is enabled or alwaysInsertFields is true, save it to db\n if (typeof prefix !== 'undefined' || alwaysInsertFields) {\n let existingPrefixFieldIndex = -1\n\n const existingPrefixField = fields.find((existingField, i) => {\n if ('name' in existingField && existingField.name === 'prefix') {\n existingPrefixFieldIndex = i\n return true\n }\n return false\n }) as TextField\n\n if (existingPrefixFieldIndex > -1) {\n fields.splice(existingPrefixFieldIndex, 1)\n }\n\n fields.push({\n ...basePrefixField,\n ...(existingPrefixField || {}),\n defaultValue:\n existingPrefixField?.defaultValue ??\n (useCompositePrefixes ? '' : prefix ? path.posix.join(prefix) : ''),\n } as TextField)\n }\n\n return fields\n}\n"],"names":["path","getFields","alwaysInsertFields","collection","prefix","useCompositePrefixes","baseURLField","name","type","admin","hidden","readOnly","label","basePrefixField","fields","existingURLFieldIndex","existingURLField","find","existingField","i","splice","push","upload","imageSizes","existingSizesFieldIndex","existingSizesField","sizesField","map","size","existingSizeField","existingSizeURLField","existingPrefixFieldIndex","existingPrefixField","defaultValue","posix","join"],"mappings":"AAEA,OAAOA,UAAU,OAAM;AAgBvB,OAAO,MAAMC,YAAY,CAAC,EACxBC,kBAAkB,EAClBC,UAAU,EACVC,MAAM,EACNC,uBAAuB,KAAK,EACvB;IACL,MAAMC,eAA0B;QAC9BC,MAAM;QACNC,MAAM;QACNC,OAAO;YACLC,QAAQ;YACRC,UAAU;QACZ;QACAC,OAAO;IACT;IAEA,MAAMC,kBAA6B;QACjCN,MAAM;QACNC,MAAM;QACNC,OAAO;YACLC,QAAQ;YACRC,UAAU;QACZ;IACF;IAEA,MAAMG,SAAS;WAAIX,WAAWW,MAAM;KAAC;IAErC,qDAAqD;IAErD,IAAIC,wBAAwB,CAAC;IAE7B,MAAMC,mBAAmBF,OAAOG,IAAI,CAAC,CAACC,eAAeC;QACnD,IAAI,UAAUD,iBAAiBA,cAAcX,IAAI,KAAK,OAAO;YAC3DQ,wBAAwBI;YACxB,OAAO;QACT;QACA,OAAO;IACT;IAEA,IAAIJ,wBAAwB,CAAC,GAAG;QAC9BD,OAAOM,MAAM,CAACL,uBAAuB;IACvC;IAEAD,OAAOO,IAAI,CAAC;QACV,GAAGf,YAAY;QACf,GAAIU,oBAAoB,CAAC,CAAC;IAC5B;IAEA,IAAI,OAAOb,WAAWmB,MAAM,KAAK,YAAYnB,WAAWmB,MAAM,CAACC,UAAU,EAAE;QACzE,IAAIC,0BAA0B,CAAC;QAE/B,MAAMC,qBAAqBX,OAAOG,IAAI,CAAC,CAACC,eAAeC;YACrD,IAAI,UAAUD,iBAAiBA,cAAcX,IAAI,KAAK,SAAS;gBAC7DiB,0BAA0BL;gBAC1B,OAAO;YACT;YAEA,OAAO;QACT;QAEA,IAAIK,0BAA0B,CAAC,GAAG;YAChCV,OAAOM,MAAM,CAACI,yBAAyB;QACzC;QAEA,MAAME,aAAoB;YACxB,GAAID,sBAAsB,CAAC,CAAC;YAC5BlB,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,QAAQ;YACV;YACAI,QAAQX,WAAWmB,MAAM,CAACC,UAAU,CAACI,GAAG,CAAC,CAACC;gBACxC,MAAMC,oBAAoBJ,oBAAoBX,OAAOG,KACnD,CAACC,gBAAkB,UAAUA,iBAAiBA,cAAcX,IAAI,KAAKqB,KAAKrB,IAAI;gBAGhF,MAAMuB,uBAAuBD,mBAAmBf,OAAOG,KACrD,CAACC,gBAAkB,UAAUA,iBAAiBA,cAAcX,IAAI,KAAK;gBAGvE,OAAO;oBACL,GAAGsB,iBAAiB;oBACpBtB,MAAMqB,KAAKrB,IAAI;oBACfC,MAAM;oBACNM,QAAQ;wBACN;4BACE,GAAIgB,wBAAwB,CAAC,CAAC;4BAC9B,GAAGxB,YAAY;wBACjB;qBACD;gBACH;YACF;QACF;QAEAQ,OAAOO,IAAI,CAACK;IACd;IAEA,oEAAoE;IACpE,IAAI,OAAOtB,WAAW,eAAeF,oBAAoB;QACvD,IAAI6B,2BAA2B,CAAC;QAEhC,MAAMC,sBAAsBlB,OAAOG,IAAI,CAAC,CAACC,eAAeC;YACtD,IAAI,UAAUD,iBAAiBA,cAAcX,IAAI,KAAK,UAAU;gBAC9DwB,2BAA2BZ;gBAC3B,OAAO;YACT;YACA,OAAO;QACT;QAEA,IAAIY,2BAA2B,CAAC,GAAG;YACjCjB,OAAOM,MAAM,CAACW,0BAA0B;QAC1C;QAEAjB,OAAOO,IAAI,CAAC;YACV,GAAGR,eAAe;YAClB,GAAImB,uBAAuB,CAAC,CAAC;YAC7BC,cACED,qBAAqBC,gBACpB5B,CAAAA,uBAAuB,KAAKD,SAASJ,KAAKkC,KAAK,CAACC,IAAI,CAAC/B,UAAU,EAAC;QACrE;IACF;IAEA,OAAOU;AACT,EAAC"}
|
package/dist/admin/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAErC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAOhD,eAAO,MAAM,YAAY,kBACP,aAAa,sBACZ,MAAM,KAAG,MA+BzB,CAAA"}
|
package/dist/admin/index.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { getFields } from './fields/getFields.js';
|
|
2
|
-
// This is the admin plugin cloud-storage stubfile.
|
|
3
|
-
// It only extends the config that are required by the admin UI.
|
|
4
|
-
export const cloudStorage = (pluginOptions)=>(incomingConfig)=>{
|
|
5
|
-
const { alwaysInsertFields, collections: allCollectionOptions, enabled } = pluginOptions;
|
|
6
|
-
const config = {
|
|
7
|
-
...incomingConfig
|
|
8
|
-
};
|
|
9
|
-
// If disabled and alwaysInsertFields is not true, skip processing
|
|
10
|
-
if (enabled === false && !alwaysInsertFields) {
|
|
11
|
-
return config;
|
|
12
|
-
}
|
|
13
|
-
return {
|
|
14
|
-
...config,
|
|
15
|
-
collections: (config.collections || []).map((existingCollection)=>{
|
|
16
|
-
const options = allCollectionOptions[existingCollection.slug];
|
|
17
|
-
// Process if adapter exists OR if alwaysInsertFields is true and this collection is configured
|
|
18
|
-
if (options?.adapter || alwaysInsertFields && options) {
|
|
19
|
-
const fields = getFields({
|
|
20
|
-
alwaysInsertFields,
|
|
21
|
-
collection: existingCollection,
|
|
22
|
-
prefix: options.prefix
|
|
23
|
-
});
|
|
24
|
-
return {
|
|
25
|
-
...existingCollection,
|
|
26
|
-
fields
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
return existingCollection;
|
|
30
|
-
})
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
//# sourceMappingURL=index.js.map
|
package/dist/admin/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/index.ts"],"sourcesContent":["import type { Config } from 'payload'\n\nimport type { PluginOptions } from '../types.js'\n\nimport { getFields } from './fields/getFields.js'\n\n// This is the admin plugin cloud-storage stubfile.\n// It only extends the config that are required by the admin UI.\n\nexport const cloudStorage =\n (pluginOptions: PluginOptions) =>\n (incomingConfig: Config): Config => {\n const { alwaysInsertFields, collections: allCollectionOptions, enabled } = pluginOptions\n const config = { ...incomingConfig }\n\n // If disabled and alwaysInsertFields is not true, skip processing\n if (enabled === false && !alwaysInsertFields) {\n return config\n }\n\n return {\n ...config,\n collections: (config.collections || []).map((existingCollection) => {\n const options = allCollectionOptions[existingCollection.slug]\n\n // Process if adapter exists OR if alwaysInsertFields is true and this collection is configured\n if (options?.adapter || (alwaysInsertFields && options)) {\n const fields = getFields({\n alwaysInsertFields,\n collection: existingCollection,\n prefix: options.prefix,\n })\n\n return {\n ...existingCollection,\n fields,\n }\n }\n\n return existingCollection\n }),\n }\n }\n"],"names":["getFields","cloudStorage","pluginOptions","incomingConfig","alwaysInsertFields","collections","allCollectionOptions","enabled","config","map","existingCollection","options","slug","adapter","fields","collection","prefix"],"mappings":"AAIA,SAASA,SAAS,QAAQ,wBAAuB;AAEjD,mDAAmD;AACnD,gEAAgE;AAEhE,OAAO,MAAMC,eACX,CAACC,gBACD,CAACC;QACC,MAAM,EAAEC,kBAAkB,EAAEC,aAAaC,oBAAoB,EAAEC,OAAO,EAAE,GAAGL;QAC3E,MAAMM,SAAS;YAAE,GAAGL,cAAc;QAAC;QAEnC,kEAAkE;QAClE,IAAII,YAAY,SAAS,CAACH,oBAAoB;YAC5C,OAAOI;QACT;QAEA,OAAO;YACL,GAAGA,MAAM;YACTH,aAAa,AAACG,CAAAA,OAAOH,WAAW,IAAI,EAAE,AAAD,EAAGI,GAAG,CAAC,CAACC;gBAC3C,MAAMC,UAAUL,oBAAoB,CAACI,mBAAmBE,IAAI,CAAC;gBAE7D,+FAA+F;gBAC/F,IAAID,SAASE,WAAYT,sBAAsBO,SAAU;oBACvD,MAAMG,SAASd,UAAU;wBACvBI;wBACAW,YAAYL;wBACZM,QAAQL,QAAQK,MAAM;oBACxB;oBAEA,OAAO;wBACL,GAAGN,kBAAkB;wBACrBI;oBACF;gBACF;gBAEA,OAAOJ;YACT;QACF;IACF,EAAC"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
type GetFileKeyArgs = {
|
|
2
|
-
collectionPrefix?: string;
|
|
3
|
-
docPrefix?: string;
|
|
4
|
-
filename: string;
|
|
5
|
-
useCompositePrefixes?: boolean;
|
|
6
|
-
};
|
|
7
|
-
type GetFileKeyResult = {
|
|
8
|
-
fileKey: string;
|
|
9
|
-
sanitizedCollectionPrefix: string;
|
|
10
|
-
sanitizedDocPrefix: string;
|
|
11
|
-
sanitizedFilename: string;
|
|
12
|
-
};
|
|
13
|
-
/**
|
|
14
|
-
* Computes the file key (path) for storage.
|
|
15
|
-
*
|
|
16
|
-
* In non-composite mode (useCompositePrefixes: false), docPrefix overrides collectionPrefix.
|
|
17
|
-
* In composite mode (useCompositePrefixes: true), both are combined.
|
|
18
|
-
* Both prefixes are passed through {@link sanitizePrefix} so keys stay normalized.
|
|
19
|
-
*/
|
|
20
|
-
export declare function getFileKey({ collectionPrefix, docPrefix, filename, useCompositePrefixes, }: GetFileKeyArgs): GetFileKeyResult;
|
|
21
|
-
export {};
|
|
22
|
-
//# sourceMappingURL=getFileKey.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getFileKey.d.ts","sourceRoot":"","sources":["../../src/utilities/getFileKey.ts"],"names":[],"mappings":"AAKA,KAAK,cAAc,GAAG;IACpB,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,gBAAgB,GAAG;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,yBAAyB,EAAE,MAAM,CAAA;IACjC,kBAAkB,EAAE,MAAM,CAAA;IAC1B,iBAAiB,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EACzB,gBAAgB,EAChB,SAAS,EACT,QAAQ,EACR,oBAA4B,GAC7B,EAAE,cAAc,GAAG,gBAAgB,CAenC"}
|