@payloadcms/plugin-cloud-storage 4.0.0-internal.435b2d6 → 4.0.0-internal.442e8b6
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 +77 -21
- 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 +177 -168
- package/dist/plugin.js.map +1 -1
- package/dist/types.d.ts +23 -14
- 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 +19 -11
- package/dist/utilities/getFilePrefix.d.ts.map +1 -1
- package/dist/utilities/getFilePrefix.js +70 -30
- package/dist/utilities/getFilePrefix.js.map +1 -1
- package/dist/utilities/getIncomingFiles.js +2 -2
- package/dist/utilities/getIncomingFiles.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,8 +1,19 @@
|
|
|
1
|
+
import { sanitizePrefix } from '../utilities/sanitizePrefix.js';
|
|
2
|
+
// The object's folder: semantic prefix + `_objectKey` segment.
|
|
3
|
+
const getObjectFolder = (data, originalDoc)=>{
|
|
4
|
+
const source = data ?? originalDoc ?? {};
|
|
5
|
+
const safePrefix = sanitizePrefix(typeof source.prefix === 'string' ? source.prefix : '');
|
|
6
|
+
const safeObjectKey = sanitizePrefix(typeof source._objectKey === 'string' ? source._objectKey : '');
|
|
7
|
+
if (safePrefix && safeObjectKey) {
|
|
8
|
+
return `${safePrefix}/${safeObjectKey}`;
|
|
9
|
+
}
|
|
10
|
+
return safePrefix || safeObjectKey;
|
|
11
|
+
};
|
|
1
12
|
export const getBeforeChangeHook = ({ adapter, collection, disablePayloadAccessControl, generateFileURL, size })=>async ({ data, originalDoc, value })=>{
|
|
2
13
|
const newFilename = size ? data?.sizes?.[size.name]?.filename : data?.filename;
|
|
3
14
|
const originalFilename = size ? originalDoc?.sizes?.[size.name]?.filename : originalDoc?.filename;
|
|
4
15
|
const filename = newFilename || originalFilename;
|
|
5
|
-
const prefix = data
|
|
16
|
+
const prefix = getObjectFolder(data, originalDoc);
|
|
6
17
|
let url = value;
|
|
7
18
|
if (generateFileURL && filename) {
|
|
8
19
|
url = await generateFileURL({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/beforeChange.ts"],"sourcesContent":["import type { CollectionConfig, FieldHook, ImageSize } from 'payload'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n disablePayloadAccessControl?: boolean\n generateFileURL?: GenerateFileURL\n size?: ImageSize\n}\n\nexport const getBeforeChangeHook =\n ({ adapter, collection, disablePayloadAccessControl, generateFileURL, size }: Args): FieldHook =>\n async ({ data, originalDoc, value }) => {\n const newFilename = size ? data?.sizes?.[size.name]?.filename : data?.filename\n const originalFilename = size\n ? originalDoc?.sizes?.[size.name]?.filename\n : originalDoc?.filename\n const filename = newFilename || originalFilename\n const prefix = data
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/beforeChange.ts"],"sourcesContent":["import type { CollectionConfig, FieldHook, ImageSize } from 'payload'\n\nimport type { GeneratedAdapter, GenerateFileURL } from '../types.js'\n\nimport { sanitizePrefix } from '../utilities/sanitizePrefix.js'\n\ninterface Args {\n adapter: GeneratedAdapter\n collection: CollectionConfig\n disablePayloadAccessControl?: boolean\n generateFileURL?: GenerateFileURL\n size?: ImageSize\n}\n\n// The object's folder: semantic prefix + `_objectKey` segment.\nconst getObjectFolder = (data: unknown, originalDoc: unknown): string => {\n const source = (data ?? originalDoc ?? {}) as Record<string, unknown>\n const safePrefix = sanitizePrefix(typeof source.prefix === 'string' ? source.prefix : '')\n const safeObjectKey = sanitizePrefix(\n typeof source._objectKey === 'string' ? source._objectKey : '',\n )\n\n if (safePrefix && safeObjectKey) {\n return `${safePrefix}/${safeObjectKey}`\n }\n\n return safePrefix || safeObjectKey\n}\n\nexport const getBeforeChangeHook =\n ({ adapter, collection, disablePayloadAccessControl, generateFileURL, size }: Args): FieldHook =>\n async ({ data, originalDoc, value }) => {\n const newFilename = size ? data?.sizes?.[size.name]?.filename : data?.filename\n const originalFilename = size\n ? originalDoc?.sizes?.[size.name]?.filename\n : originalDoc?.filename\n const filename = newFilename || originalFilename\n const prefix = getObjectFolder(data, originalDoc)\n let url = value\n\n if (generateFileURL && filename) {\n url = await generateFileURL({\n collection,\n filename,\n prefix,\n size,\n })\n } else if (disablePayloadAccessControl && filename && adapter.generateURL) {\n url = await adapter.generateURL({\n collection,\n data: data || originalDoc,\n filename,\n prefix,\n })\n }\n\n return url\n }\n"],"names":["sanitizePrefix","getObjectFolder","data","originalDoc","source","safePrefix","prefix","safeObjectKey","_objectKey","getBeforeChangeHook","adapter","collection","disablePayloadAccessControl","generateFileURL","size","value","newFilename","sizes","name","filename","originalFilename","url","generateURL"],"mappings":"AAIA,SAASA,cAAc,QAAQ,iCAAgC;AAU/D,+DAA+D;AAC/D,MAAMC,kBAAkB,CAACC,MAAeC;IACtC,MAAMC,SAAUF,QAAQC,eAAe,CAAC;IACxC,MAAME,aAAaL,eAAe,OAAOI,OAAOE,MAAM,KAAK,WAAWF,OAAOE,MAAM,GAAG;IACtF,MAAMC,gBAAgBP,eACpB,OAAOI,OAAOI,UAAU,KAAK,WAAWJ,OAAOI,UAAU,GAAG;IAG9D,IAAIH,cAAcE,eAAe;QAC/B,OAAO,GAAGF,WAAW,CAAC,EAAEE,eAAe;IACzC;IAEA,OAAOF,cAAcE;AACvB;AAEA,OAAO,MAAME,sBACX,CAAC,EAAEC,OAAO,EAAEC,UAAU,EAAEC,2BAA2B,EAAEC,eAAe,EAAEC,IAAI,EAAQ,GAClF,OAAO,EAAEZ,IAAI,EAAEC,WAAW,EAAEY,KAAK,EAAE;QACjC,MAAMC,cAAcF,OAAOZ,MAAMe,OAAO,CAACH,KAAKI,IAAI,CAAC,EAAEC,WAAWjB,MAAMiB;QACtE,MAAMC,mBAAmBN,OACrBX,aAAac,OAAO,CAACH,KAAKI,IAAI,CAAC,EAAEC,WACjChB,aAAagB;QACjB,MAAMA,WAAWH,eAAeI;QAChC,MAAMd,SAASL,gBAAgBC,MAAMC;QACrC,IAAIkB,MAAMN;QAEV,IAAIF,mBAAmBM,UAAU;YAC/BE,MAAM,MAAMR,gBAAgB;gBAC1BF;gBACAQ;gBACAb;gBACAQ;YACF;QACF,OAAO,IAAIF,+BAA+BO,YAAYT,QAAQY,WAAW,EAAE;YACzED,MAAM,MAAMX,QAAQY,WAAW,CAAC;gBAC9BX;gBACAT,MAAMA,QAAQC;gBACdgB;gBACAb;YACF;QACF;QAEA,OAAOe;IACT,EAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CollectionBeforeChangeHook, FieldHook } from 'payload';
|
|
2
|
+
type Args = {
|
|
3
|
+
collectionPrefix?: string;
|
|
4
|
+
useCompositePrefixes?: boolean;
|
|
5
|
+
};
|
|
6
|
+
/** Persist new upload destinations without reinterpreting metadata-only updates. */
|
|
7
|
+
export declare const getNormalizeUploadPrefixHook: ({ collectionPrefix, useCompositePrefixes }: Args) => CollectionBeforeChangeHook;
|
|
8
|
+
/** Run last on the prefix field so user hooks cannot leave stale storage coordinates. */
|
|
9
|
+
export declare const getNormalizeUploadPrefixFieldHook: ({ collectionPrefix, useCompositePrefixes }: Args) => FieldHook;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=normalizeUploadPrefix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalizeUploadPrefix.d.ts","sourceRoot":"","sources":["../../src/hooks/normalizeUploadPrefix.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAIpE,KAAK,IAAI,GAAG;IACV,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,CAAA;AAiBD,oFAAoF;AACpF,eAAO,MAAM,4BAA4B,+CACM,IAAI,KAAG,0BAiBnD,CAAA;AAEH,yFAAyF;AACzF,eAAO,MAAM,iCAAiC,+CACC,IAAI,KAAG,SAenD,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { buildUploadPrefix } from '../utilities/buildStoragePathData.js';
|
|
2
|
+
/**
|
|
3
|
+
* A prefix the caller did not supply, or supplied unchanged, is left as stored so
|
|
4
|
+
* pre-upgrade files keep resolving to their original object keys. Anything the caller
|
|
5
|
+
* chooses is contained, because `prefix` is writable through the REST, GraphQL and
|
|
6
|
+
* Local APIs and the read path trusts whatever is persisted.
|
|
7
|
+
*/ const isPrefixSupplied = ({ storedPrefix, value })=>typeof value === 'string' && value !== (typeof storedPrefix === 'string' ? storedPrefix : '');
|
|
8
|
+
/** Persist new upload destinations without reinterpreting metadata-only updates. */ export const getNormalizeUploadPrefixHook = ({ collectionPrefix, useCompositePrefixes })=>({ data, originalDoc, req })=>{
|
|
9
|
+
if (req.context?.skipCloudStorage) {
|
|
10
|
+
return data;
|
|
11
|
+
}
|
|
12
|
+
if (!req.file && !isPrefixSupplied({
|
|
13
|
+
storedPrefix: originalDoc?.prefix,
|
|
14
|
+
value: data.prefix
|
|
15
|
+
})) {
|
|
16
|
+
return data;
|
|
17
|
+
}
|
|
18
|
+
data.prefix = buildUploadPrefix({
|
|
19
|
+
collectionPrefix,
|
|
20
|
+
docPrefix: typeof data.prefix === 'string' ? data.prefix : '',
|
|
21
|
+
useCompositePrefixes
|
|
22
|
+
}).sanitizedDocPrefix;
|
|
23
|
+
return data;
|
|
24
|
+
};
|
|
25
|
+
/** Run last on the prefix field so user hooks cannot leave stale storage coordinates. */ export const getNormalizeUploadPrefixFieldHook = ({ collectionPrefix, useCompositePrefixes })=>({ previousValue, req, value })=>{
|
|
26
|
+
if (req.context?.skipCloudStorage) {
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
if (!req.file && !isPrefixSupplied({
|
|
30
|
+
storedPrefix: previousValue,
|
|
31
|
+
value
|
|
32
|
+
})) {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
return buildUploadPrefix({
|
|
36
|
+
collectionPrefix,
|
|
37
|
+
docPrefix: typeof value === 'string' ? value : '',
|
|
38
|
+
useCompositePrefixes
|
|
39
|
+
}).sanitizedDocPrefix;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=normalizeUploadPrefix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/normalizeUploadPrefix.ts"],"sourcesContent":["import type { CollectionBeforeChangeHook, FieldHook } from 'payload'\n\nimport { buildUploadPrefix } from '../utilities/buildStoragePathData.js'\n\ntype Args = {\n collectionPrefix?: string\n useCompositePrefixes?: boolean\n}\n\n/**\n * A prefix the caller did not supply, or supplied unchanged, is left as stored so\n * pre-upgrade files keep resolving to their original object keys. Anything the caller\n * chooses is contained, because `prefix` is writable through the REST, GraphQL and\n * Local APIs and the read path trusts whatever is persisted.\n */\nconst isPrefixSupplied = ({\n storedPrefix,\n value,\n}: {\n storedPrefix: unknown\n value: unknown\n}): boolean =>\n typeof value === 'string' && value !== (typeof storedPrefix === 'string' ? storedPrefix : '')\n\n/** Persist new upload destinations without reinterpreting metadata-only updates. */\nexport const getNormalizeUploadPrefixHook =\n ({ collectionPrefix, useCompositePrefixes }: Args): CollectionBeforeChangeHook =>\n ({ data, originalDoc, req }) => {\n if (req.context?.skipCloudStorage) {\n return data\n }\n\n if (!req.file && !isPrefixSupplied({ storedPrefix: originalDoc?.prefix, value: data.prefix })) {\n return data\n }\n\n data.prefix = buildUploadPrefix({\n collectionPrefix,\n docPrefix: typeof data.prefix === 'string' ? data.prefix : '',\n useCompositePrefixes,\n }).sanitizedDocPrefix\n\n return data\n }\n\n/** Run last on the prefix field so user hooks cannot leave stale storage coordinates. */\nexport const getNormalizeUploadPrefixFieldHook =\n ({ collectionPrefix, useCompositePrefixes }: Args): FieldHook =>\n ({ previousValue, req, value }) => {\n if (req.context?.skipCloudStorage) {\n return value\n }\n\n if (!req.file && !isPrefixSupplied({ storedPrefix: previousValue, value })) {\n return value\n }\n\n return buildUploadPrefix({\n collectionPrefix,\n docPrefix: typeof value === 'string' ? value : '',\n useCompositePrefixes,\n }).sanitizedDocPrefix\n }\n"],"names":["buildUploadPrefix","isPrefixSupplied","storedPrefix","value","getNormalizeUploadPrefixHook","collectionPrefix","useCompositePrefixes","data","originalDoc","req","context","skipCloudStorage","file","prefix","docPrefix","sanitizedDocPrefix","getNormalizeUploadPrefixFieldHook","previousValue"],"mappings":"AAEA,SAASA,iBAAiB,QAAQ,uCAAsC;AAOxE;;;;;CAKC,GACD,MAAMC,mBAAmB,CAAC,EACxBC,YAAY,EACZC,KAAK,EAIN,GACC,OAAOA,UAAU,YAAYA,UAAW,CAAA,OAAOD,iBAAiB,WAAWA,eAAe,EAAC;AAE7F,kFAAkF,GAClF,OAAO,MAAME,+BACX,CAAC,EAAEC,gBAAgB,EAAEC,oBAAoB,EAAQ,GACjD,CAAC,EAAEC,IAAI,EAAEC,WAAW,EAAEC,GAAG,EAAE;QACzB,IAAIA,IAAIC,OAAO,EAAEC,kBAAkB;YACjC,OAAOJ;QACT;QAEA,IAAI,CAACE,IAAIG,IAAI,IAAI,CAACX,iBAAiB;YAAEC,cAAcM,aAAaK;YAAQV,OAAOI,KAAKM,MAAM;QAAC,IAAI;YAC7F,OAAON;QACT;QAEAA,KAAKM,MAAM,GAAGb,kBAAkB;YAC9BK;YACAS,WAAW,OAAOP,KAAKM,MAAM,KAAK,WAAWN,KAAKM,MAAM,GAAG;YAC3DP;QACF,GAAGS,kBAAkB;QAErB,OAAOR;IACT,EAAC;AAEH,uFAAuF,GACvF,OAAO,MAAMS,oCACX,CAAC,EAAEX,gBAAgB,EAAEC,oBAAoB,EAAQ,GACjD,CAAC,EAAEW,aAAa,EAAER,GAAG,EAAEN,KAAK,EAAE;QAC5B,IAAIM,IAAIC,OAAO,EAAEC,kBAAkB;YACjC,OAAOR;QACT;QAEA,IAAI,CAACM,IAAIG,IAAI,IAAI,CAACX,iBAAiB;YAAEC,cAAce;YAAed;QAAM,IAAI;YAC1E,OAAOA;QACT;QAEA,OAAOH,kBAAkB;YACvBK;YACAS,WAAW,OAAOX,UAAU,WAAWA,QAAQ;YAC/CG;QACF,GAAGS,kBAAkB;IACvB,EAAC"}
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAErC,OAAO,KAAK,EAAsB,aAAa,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAErC,OAAO,KAAK,EAAsB,aAAa,EAAE,MAAM,YAAY,CAAA;AAiBnE,eAAO,MAAM,kBAAkB,kBACb,aAAa,sBACZ,MAAM,KAAG,MAwOzB,CAAA"}
|
package/dist/plugin.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getFields } from './fields/getFields.js';
|
|
2
2
|
import { getAfterChangeHook } from './hooks/afterChange.js';
|
|
3
3
|
import { getAfterDeleteHook } from './hooks/afterDelete.js';
|
|
4
|
+
import { getNormalizeUploadPrefixHook } from './hooks/normalizeUploadPrefix.js';
|
|
4
5
|
import { getPreserveFileDataHook } from './hooks/preserveFileData.js';
|
|
5
6
|
// This plugin extends all targeted collections by offloading uploaded files
|
|
6
7
|
// to cloud storage instead of solely storing files locally.
|
|
@@ -9,189 +10,197 @@ import { getPreserveFileDataHook } from './hooks/preserveFileData.js';
|
|
|
9
10
|
// 1. handleUpload, 2. handleDelete, 3. generateURL, 4. staticHandler
|
|
10
11
|
// Optionally, the adapter can specify any Webpack config overrides if they are necessary.
|
|
11
12
|
export const cloudStoragePlugin = (pluginOptions)=>(incomingConfig)=>{
|
|
12
|
-
const {
|
|
13
|
+
const { collections: allCollectionOptions, enabled, useCompositePrefixes } = pluginOptions;
|
|
13
14
|
const config = {
|
|
14
15
|
...incomingConfig
|
|
15
16
|
};
|
|
16
|
-
// If disabled
|
|
17
|
+
// If disabled, only insert fields (e.g. prefix) without full plugin functionality,
|
|
18
|
+
// so the collection schema stays consistent across environments.
|
|
17
19
|
if (enabled === false) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
})
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
return config;
|
|
20
|
+
return {
|
|
21
|
+
...config,
|
|
22
|
+
collections: (config.collections || []).map((existingCollection)=>{
|
|
23
|
+
const options = allCollectionOptions[existingCollection.slug];
|
|
24
|
+
if (options) {
|
|
25
|
+
// If adapter is provided, use it to get fields
|
|
26
|
+
const adapter = options.adapter ? options.adapter({
|
|
27
|
+
collection: existingCollection,
|
|
28
|
+
prefix: options.prefix
|
|
29
|
+
}) : undefined;
|
|
30
|
+
const fields = getFields({
|
|
31
|
+
adapter,
|
|
32
|
+
collection: existingCollection,
|
|
33
|
+
disablePayloadAccessControl: options.disablePayloadAccessControl,
|
|
34
|
+
generateFileURL: options.generateFileURL,
|
|
35
|
+
prefix: options.prefix,
|
|
36
|
+
useCompositePrefixes
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
...existingCollection,
|
|
40
|
+
fields
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return existingCollection;
|
|
44
|
+
})
|
|
45
|
+
};
|
|
48
46
|
}
|
|
49
47
|
const initFunctions = [];
|
|
50
48
|
const endpointPaths = new Map();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
49
|
+
const collections = (config.collections || []).map((existingCollection)=>{
|
|
50
|
+
const options = allCollectionOptions[existingCollection.slug];
|
|
51
|
+
if (options?.adapter) {
|
|
52
|
+
const adapter = options.adapter({
|
|
53
|
+
collection: existingCollection,
|
|
54
|
+
prefix: options.prefix
|
|
55
|
+
});
|
|
56
|
+
if (adapter.onInit) {
|
|
57
|
+
initFunctions.push(adapter.onInit);
|
|
58
|
+
}
|
|
59
|
+
let uploadInstructions;
|
|
60
|
+
if (adapter.uploadInstructions) {
|
|
61
|
+
const { adminHandler, enabled, endpoint, ...instructions } = adapter.uploadInstructions;
|
|
62
|
+
let endpointPath = endpointPaths.get(options.adapter);
|
|
63
|
+
if (enabled && endpoint && !endpointPath) {
|
|
64
|
+
const endpointCount = config.endpoints?.filter(({ path })=>path?.startsWith(endpoint.path)).length || 0;
|
|
65
|
+
endpointPath = endpointCount ? `${endpoint.path}-${endpointCount}` : endpoint.path;
|
|
66
|
+
config.endpoints ??= [];
|
|
67
|
+
config.endpoints.push({
|
|
68
|
+
handler: endpoint.handler,
|
|
69
|
+
method: 'post',
|
|
70
|
+
path: endpointPath
|
|
71
|
+
});
|
|
72
|
+
endpointPaths.set(options.adapter, endpointPath);
|
|
62
73
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (adminHandler) {
|
|
79
|
-
config.admin ??= {};
|
|
80
|
-
config.admin.components ??= {};
|
|
81
|
-
config.admin.components.providers ??= [];
|
|
82
|
-
config.admin.components.providers.push({
|
|
83
|
-
clientProps: {
|
|
84
|
-
collectionSlug: existingCollection.slug,
|
|
85
|
-
endpointPath,
|
|
86
|
-
prefix: options.prefix,
|
|
87
|
-
props: adminHandler.props || {}
|
|
88
|
-
},
|
|
89
|
-
path: adminHandler.path
|
|
90
|
-
});
|
|
91
|
-
}
|
|
74
|
+
if (enabled && adminHandler) {
|
|
75
|
+
config.admin ??= {};
|
|
76
|
+
config.admin.components ??= {};
|
|
77
|
+
config.admin.components.providers ??= [];
|
|
78
|
+
config.admin.components.providers.push({
|
|
79
|
+
clientProps: {
|
|
80
|
+
collectionSlug: existingCollection.slug,
|
|
81
|
+
endpointPath,
|
|
82
|
+
prefix: options.prefix,
|
|
83
|
+
props: adminHandler.props || {}
|
|
84
|
+
},
|
|
85
|
+
path: adminHandler.path
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (enabled) {
|
|
92
89
|
uploadInstructions = instructions;
|
|
90
|
+
} else if (adminHandler) {
|
|
91
|
+
/** Avoid importMap.js differences when client uploads vary between dev and production. */ config.admin ??= {};
|
|
92
|
+
config.admin.dependencies ??= {};
|
|
93
|
+
config.admin.dependencies[adminHandler.path] = {
|
|
94
|
+
type: 'component',
|
|
95
|
+
path: adminHandler.path
|
|
96
|
+
};
|
|
93
97
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
}
|
|
99
|
+
const fields = getFields({
|
|
100
|
+
adapter,
|
|
101
|
+
collection: existingCollection,
|
|
102
|
+
disablePayloadAccessControl: options.disablePayloadAccessControl,
|
|
103
|
+
generateFileURL: options.generateFileURL,
|
|
104
|
+
prefix: options.prefix,
|
|
105
|
+
useCompositePrefixes
|
|
106
|
+
});
|
|
107
|
+
const handlers = [
|
|
108
|
+
...typeof existingCollection.upload === 'object' && Array.isArray(existingCollection.upload.handlers) ? existingCollection.upload.handlers : []
|
|
109
|
+
];
|
|
110
|
+
if (!options.disablePayloadAccessControl) {
|
|
111
|
+
handlers.push(adapter.staticHandler);
|
|
112
|
+
// Else if disablePayloadAccessControl: true and upload instructions are used
|
|
113
|
+
// Build the "proxied" handler that responds only when addDataAndFileToRequest fetches the uploaded file
|
|
114
|
+
} else if (uploadInstructions) {
|
|
115
|
+
handlers.push((req, args)=>{
|
|
116
|
+
if ('uploadReference' in args.params) {
|
|
117
|
+
return adapter.staticHandler(req, args);
|
|
118
|
+
}
|
|
101
119
|
});
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
120
|
+
}
|
|
121
|
+
const getSkipSafeFetchSetting = ()=>{
|
|
122
|
+
const isBooleanTrueSkipSafeFetch = typeof existingCollection.upload === 'object' && existingCollection.upload.skipSafeFetch === true;
|
|
123
|
+
const isAllowListSkipSafeFetch = typeof existingCollection.upload === 'object' && Array.isArray(existingCollection.upload.skipSafeFetch);
|
|
124
|
+
if (isBooleanTrueSkipSafeFetch) {
|
|
125
|
+
return true;
|
|
126
|
+
} else if (isAllowListSkipSafeFetch) {
|
|
127
|
+
const existingSkipSafeFetch = typeof existingCollection.upload === 'object' && Array.isArray(existingCollection.upload.skipSafeFetch) ? existingCollection.upload.skipSafeFetch : [];
|
|
128
|
+
const hasExactLocalhostMatch = existingSkipSafeFetch.some((entry)=>{
|
|
129
|
+
const entryKeys = Object.keys(entry);
|
|
130
|
+
return entryKeys.length === 1 && entry.hostname === 'localhost';
|
|
114
131
|
});
|
|
132
|
+
const localhostEntry = process.env.NODE_ENV !== 'production' && !hasExactLocalhostMatch ? [
|
|
133
|
+
{
|
|
134
|
+
hostname: 'localhost'
|
|
135
|
+
}
|
|
136
|
+
] : [];
|
|
137
|
+
return [
|
|
138
|
+
...existingSkipSafeFetch,
|
|
139
|
+
...localhostEntry
|
|
140
|
+
];
|
|
115
141
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
...existingCollection.hooks?.afterDelete || [],
|
|
163
|
-
getAfterDeleteHook({
|
|
164
|
-
adapter,
|
|
165
|
-
collection: existingCollection
|
|
166
|
-
})
|
|
167
|
-
],
|
|
168
|
-
beforeChange: [
|
|
169
|
-
...existingCollection.hooks?.beforeChange || [],
|
|
170
|
-
getPreserveFileDataHook()
|
|
171
|
-
]
|
|
142
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
143
|
+
return [
|
|
144
|
+
{
|
|
145
|
+
hostname: 'localhost'
|
|
146
|
+
}
|
|
147
|
+
];
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
};
|
|
151
|
+
return {
|
|
152
|
+
...existingCollection,
|
|
153
|
+
fields,
|
|
154
|
+
hooks: {
|
|
155
|
+
...existingCollection.hooks || {},
|
|
156
|
+
afterChange: [
|
|
157
|
+
...existingCollection.hooks?.afterChange || [],
|
|
158
|
+
getAfterChangeHook({
|
|
159
|
+
adapter,
|
|
160
|
+
collection: existingCollection,
|
|
161
|
+
collectionPrefix: options.prefix,
|
|
162
|
+
useCompositePrefixes
|
|
163
|
+
})
|
|
164
|
+
],
|
|
165
|
+
afterDelete: [
|
|
166
|
+
...existingCollection.hooks?.afterDelete || [],
|
|
167
|
+
getAfterDeleteHook({
|
|
168
|
+
adapter,
|
|
169
|
+
collection: existingCollection,
|
|
170
|
+
collectionPrefix: options.prefix,
|
|
171
|
+
useCompositePrefixes
|
|
172
|
+
})
|
|
173
|
+
],
|
|
174
|
+
beforeChange: [
|
|
175
|
+
...existingCollection.hooks?.beforeChange || [],
|
|
176
|
+
getNormalizeUploadPrefixHook({
|
|
177
|
+
collectionPrefix: options.prefix,
|
|
178
|
+
useCompositePrefixes
|
|
179
|
+
}),
|
|
180
|
+
getPreserveFileDataHook()
|
|
181
|
+
]
|
|
182
|
+
},
|
|
183
|
+
upload: {
|
|
184
|
+
...typeof existingCollection.upload === 'object' ? existingCollection.upload : {},
|
|
185
|
+
adapter: adapter.name,
|
|
186
|
+
...uploadInstructions && {
|
|
187
|
+
uploadInstructions
|
|
172
188
|
},
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
return existingCollection;
|
|
186
|
-
}),
|
|
187
|
-
...config.admin && {
|
|
188
|
-
admin: config.admin
|
|
189
|
-
},
|
|
190
|
-
...config.endpoints && {
|
|
191
|
-
endpoints: config.endpoints
|
|
192
|
-
},
|
|
189
|
+
disableLocalStorage: typeof options.disableLocalStorage === 'boolean' ? options.disableLocalStorage : true,
|
|
190
|
+
handlers,
|
|
191
|
+
skipSafeFetch: getSkipSafeFetchSetting()
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
return existingCollection;
|
|
196
|
+
});
|
|
197
|
+
return {
|
|
198
|
+
...config,
|
|
199
|
+
collections,
|
|
193
200
|
onInit: async (payload)=>{
|
|
194
|
-
|
|
201
|
+
// Await each init so a provisioning failure fails Payload startup
|
|
202
|
+
// instead of becoming an unhandled rejection.
|
|
203
|
+
await Promise.all(initFunctions.map((fn)=>fn()));
|
|
195
204
|
if (config.onInit) {
|
|
196
205
|
await config.onInit(payload);
|
|
197
206
|
}
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Config } from 'payload'\n\nimport type { Adapter, AllowList, PluginOptions } from './types.js'\n\nimport { getFields } from './fields/getFields.js'\nimport { getAfterChangeHook } from './hooks/afterChange.js'\nimport { getAfterDeleteHook } from './hooks/afterDelete.js'\nimport { getPreserveFileDataHook } from './hooks/preserveFileData.js'\n\n// This plugin extends all targeted collections by offloading uploaded files\n// to cloud storage instead of solely storing files locally.\n\n// It is based on an adapter approach, where adapters can be written for any cloud provider.\n// Adapters are responsible for providing four actions that this plugin will use:\n// 1. handleUpload, 2. handleDelete, 3. generateURL, 4. staticHandler\n\n// Optionally, the adapter can specify any Webpack config overrides if they are necessary.\n\nexport const cloudStoragePlugin =\n (pluginOptions: PluginOptions) =>\n (incomingConfig: Config): Config => {\n const {\n alwaysInsertFields,\n collections: allCollectionOptions,\n enabled,\n useCompositePrefixes,\n } = pluginOptions\n const config = { ...incomingConfig }\n\n // If disabled but alwaysInsertFields is true, only insert fields without full plugin functionality\n if (enabled === false) {\n if (alwaysInsertFields) {\n return {\n ...config,\n collections: (config.collections || []).map((existingCollection) => {\n const options = allCollectionOptions[existingCollection.slug]\n\n if (options) {\n // If adapter is provided, use it to get fields\n const adapter = options.adapter\n ? options.adapter({\n collection: existingCollection,\n prefix: options.prefix,\n })\n : undefined\n\n const fields = getFields({\n adapter,\n alwaysInsertFields: true,\n collection: existingCollection,\n disablePayloadAccessControl: options.disablePayloadAccessControl,\n generateFileURL: options.generateFileURL,\n prefix: options.prefix,\n useCompositePrefixes,\n })\n\n return {\n ...existingCollection,\n fields,\n }\n }\n\n return existingCollection\n }),\n }\n }\n\n return config\n }\n\n const initFunctions: Array<() => void> = []\n const endpointPaths = new Map<Adapter, string>()\n\n return {\n ...config,\n collections: (config.collections || []).map((existingCollection) => {\n const options = allCollectionOptions[existingCollection.slug]\n\n if (options?.adapter) {\n const adapter = options.adapter({\n collection: existingCollection,\n prefix: options.prefix,\n })\n\n if (adapter.onInit) {\n initFunctions.push(adapter.onInit)\n }\n\n let uploadInstructions\n\n if (adapter.uploadInstructions) {\n const { adminHandler, endpoint, ...instructions } = adapter.uploadInstructions\n let endpointPath = endpointPaths.get(options.adapter)\n\n if (endpoint && !endpointPath) {\n const endpointCount =\n config.endpoints?.filter(({ path }) => path?.startsWith(endpoint.path)).length || 0\n\n endpointPath = endpointCount ? `${endpoint.path}-${endpointCount}` : endpoint.path\n config.endpoints ??= []\n config.endpoints.push({\n handler: endpoint.handler,\n method: 'post',\n path: endpointPath,\n })\n endpointPaths.set(options.adapter, endpointPath)\n }\n\n if (adminHandler) {\n config.admin ??= {}\n config.admin.components ??= {}\n config.admin.components.providers ??= []\n config.admin.components.providers.push({\n clientProps: {\n collectionSlug: existingCollection.slug,\n endpointPath,\n prefix: options.prefix,\n props: adminHandler.props || {},\n },\n path: adminHandler.path,\n })\n }\n\n uploadInstructions = instructions\n }\n\n const fields = getFields({\n adapter,\n collection: existingCollection,\n disablePayloadAccessControl: options.disablePayloadAccessControl,\n generateFileURL: options.generateFileURL,\n prefix: options.prefix,\n useCompositePrefixes,\n })\n\n const handlers = [\n ...(typeof existingCollection.upload === 'object' &&\n Array.isArray(existingCollection.upload.handlers)\n ? existingCollection.upload.handlers\n : []),\n ]\n\n if (!options.disablePayloadAccessControl) {\n handlers.push(adapter.staticHandler)\n // Else if disablePayloadAccessControl: true and upload instructions are used\n // Build the \"proxied\" handler that responds only when addDataAndFileToRequest fetches the uploaded file\n } else if (adapter.uploadInstructions) {\n handlers.push((req, args) => {\n if ('directUpload' in args.params) {\n return adapter.staticHandler(req, args)\n }\n })\n }\n\n const getSkipSafeFetchSetting = (): AllowList | boolean => {\n if (options.disablePayloadAccessControl) {\n return true\n }\n const isBooleanTrueSkipSafeFetch =\n typeof existingCollection.upload === 'object' &&\n existingCollection.upload.skipSafeFetch === true\n\n const isAllowListSkipSafeFetch =\n typeof existingCollection.upload === 'object' &&\n Array.isArray(existingCollection.upload.skipSafeFetch)\n\n if (isBooleanTrueSkipSafeFetch) {\n return true\n } else if (isAllowListSkipSafeFetch) {\n const existingSkipSafeFetch =\n typeof existingCollection.upload === 'object' &&\n Array.isArray(existingCollection.upload.skipSafeFetch)\n ? existingCollection.upload.skipSafeFetch\n : []\n\n const hasExactLocalhostMatch = existingSkipSafeFetch.some((entry) => {\n const entryKeys = Object.keys(entry)\n return entryKeys.length === 1 && entry.hostname === 'localhost'\n })\n\n const localhostEntry =\n process.env.NODE_ENV !== 'production' && !hasExactLocalhostMatch\n ? [{ hostname: 'localhost' }]\n : []\n\n return [...existingSkipSafeFetch, ...localhostEntry]\n }\n\n if (process.env.NODE_ENV !== 'production') {\n return [{ hostname: 'localhost' }]\n }\n\n return false\n }\n\n return {\n ...existingCollection,\n fields,\n hooks: {\n ...(existingCollection.hooks || {}),\n afterChange: [\n ...(existingCollection.hooks?.afterChange || []),\n getAfterChangeHook({ adapter, collection: existingCollection }),\n ],\n afterDelete: [\n ...(existingCollection.hooks?.afterDelete || []),\n getAfterDeleteHook({ adapter, collection: existingCollection }),\n ],\n beforeChange: [\n ...(existingCollection.hooks?.beforeChange || []),\n getPreserveFileDataHook(),\n ],\n },\n upload: {\n ...(typeof existingCollection.upload === 'object' ? existingCollection.upload : {}),\n adapter: adapter.name,\n ...(uploadInstructions && {\n uploadInstructions,\n }),\n disableLocalStorage:\n typeof options.disableLocalStorage === 'boolean'\n ? options.disableLocalStorage\n : true,\n handlers,\n skipSafeFetch: getSkipSafeFetchSetting(),\n },\n }\n }\n\n return existingCollection\n }),\n ...(config.admin && { admin: config.admin }),\n ...(config.endpoints && { endpoints: config.endpoints }),\n onInit: async (payload) => {\n initFunctions.forEach((fn) => fn())\n if (config.onInit) {\n await config.onInit(payload)\n }\n },\n }\n }\n"],"names":["getFields","getAfterChangeHook","getAfterDeleteHook","getPreserveFileDataHook","cloudStoragePlugin","pluginOptions","incomingConfig","alwaysInsertFields","collections","allCollectionOptions","enabled","useCompositePrefixes","config","map","existingCollection","options","slug","adapter","collection","prefix","undefined","fields","disablePayloadAccessControl","generateFileURL","initFunctions","endpointPaths","Map","onInit","push","uploadInstructions","adminHandler","endpoint","instructions","endpointPath","get","endpointCount","endpoints","filter","path","startsWith","length","handler","method","set","admin","components","providers","clientProps","collectionSlug","props","handlers","upload","Array","isArray","staticHandler","req","args","params","getSkipSafeFetchSetting","isBooleanTrueSkipSafeFetch","skipSafeFetch","isAllowListSkipSafeFetch","existingSkipSafeFetch","hasExactLocalhostMatch","some","entry","entryKeys","Object","keys","hostname","localhostEntry","process","env","NODE_ENV","hooks","afterChange","afterDelete","beforeChange","name","disableLocalStorage","payload","forEach","fn"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Config } from 'payload'\n\nimport type { Adapter, AllowList, PluginOptions } from './types.js'\n\nimport { getFields } from './fields/getFields.js'\nimport { getAfterChangeHook } from './hooks/afterChange.js'\nimport { getAfterDeleteHook } from './hooks/afterDelete.js'\nimport { getNormalizeUploadPrefixHook } from './hooks/normalizeUploadPrefix.js'\nimport { getPreserveFileDataHook } from './hooks/preserveFileData.js'\n\n// This plugin extends all targeted collections by offloading uploaded files\n// to cloud storage instead of solely storing files locally.\n\n// It is based on an adapter approach, where adapters can be written for any cloud provider.\n// Adapters are responsible for providing four actions that this plugin will use:\n// 1. handleUpload, 2. handleDelete, 3. generateURL, 4. staticHandler\n\n// Optionally, the adapter can specify any Webpack config overrides if they are necessary.\n\nexport const cloudStoragePlugin =\n (pluginOptions: PluginOptions) =>\n (incomingConfig: Config): Config => {\n const { collections: allCollectionOptions, enabled, useCompositePrefixes } = pluginOptions\n const config = { ...incomingConfig }\n\n // If disabled, only insert fields (e.g. prefix) without full plugin functionality,\n // so the collection schema stays consistent across environments.\n if (enabled === false) {\n return {\n ...config,\n collections: (config.collections || []).map((existingCollection) => {\n const options = allCollectionOptions[existingCollection.slug]\n\n if (options) {\n // If adapter is provided, use it to get fields\n const adapter = options.adapter\n ? options.adapter({\n collection: existingCollection,\n prefix: options.prefix,\n })\n : undefined\n\n const fields = getFields({\n adapter,\n collection: existingCollection,\n disablePayloadAccessControl: options.disablePayloadAccessControl,\n generateFileURL: options.generateFileURL,\n prefix: options.prefix,\n useCompositePrefixes,\n })\n\n return {\n ...existingCollection,\n fields,\n }\n }\n\n return existingCollection\n }),\n }\n }\n\n const initFunctions: Array<() => Promise<void> | void> = []\n const endpointPaths = new Map<Adapter, string>()\n\n const collections = (config.collections || []).map((existingCollection) => {\n const options = allCollectionOptions[existingCollection.slug]\n\n if (options?.adapter) {\n const adapter = options.adapter({\n collection: existingCollection,\n prefix: options.prefix,\n })\n\n if (adapter.onInit) {\n initFunctions.push(adapter.onInit)\n }\n\n let uploadInstructions\n\n if (adapter.uploadInstructions) {\n const { adminHandler, enabled, endpoint, ...instructions } = adapter.uploadInstructions\n let endpointPath = endpointPaths.get(options.adapter)\n\n if (enabled && endpoint && !endpointPath) {\n const endpointCount =\n config.endpoints?.filter(({ path }) => path?.startsWith(endpoint.path)).length || 0\n\n endpointPath = endpointCount ? `${endpoint.path}-${endpointCount}` : endpoint.path\n config.endpoints ??= []\n config.endpoints.push({\n handler: endpoint.handler,\n method: 'post',\n path: endpointPath,\n })\n endpointPaths.set(options.adapter, endpointPath)\n }\n\n if (enabled && adminHandler) {\n config.admin ??= {}\n config.admin.components ??= {}\n config.admin.components.providers ??= []\n config.admin.components.providers.push({\n clientProps: {\n collectionSlug: existingCollection.slug,\n endpointPath,\n prefix: options.prefix,\n props: adminHandler.props || {},\n },\n path: adminHandler.path,\n })\n }\n\n if (enabled) {\n uploadInstructions = instructions\n } else if (adminHandler) {\n /** Avoid importMap.js differences when client uploads vary between dev and production. */\n config.admin ??= {}\n config.admin.dependencies ??= {}\n config.admin.dependencies[adminHandler.path] = {\n type: 'component',\n path: adminHandler.path,\n }\n }\n }\n\n const fields = getFields({\n adapter,\n collection: existingCollection,\n disablePayloadAccessControl: options.disablePayloadAccessControl,\n generateFileURL: options.generateFileURL,\n prefix: options.prefix,\n useCompositePrefixes,\n })\n\n const handlers = [\n ...(typeof existingCollection.upload === 'object' &&\n Array.isArray(existingCollection.upload.handlers)\n ? existingCollection.upload.handlers\n : []),\n ]\n\n if (!options.disablePayloadAccessControl) {\n handlers.push(adapter.staticHandler)\n // Else if disablePayloadAccessControl: true and upload instructions are used\n // Build the \"proxied\" handler that responds only when addDataAndFileToRequest fetches the uploaded file\n } else if (uploadInstructions) {\n handlers.push((req, args) => {\n if ('uploadReference' in args.params) {\n return adapter.staticHandler(req, args)\n }\n })\n }\n\n const getSkipSafeFetchSetting = (): AllowList | boolean => {\n const isBooleanTrueSkipSafeFetch =\n typeof existingCollection.upload === 'object' &&\n existingCollection.upload.skipSafeFetch === true\n\n const isAllowListSkipSafeFetch =\n typeof existingCollection.upload === 'object' &&\n Array.isArray(existingCollection.upload.skipSafeFetch)\n\n if (isBooleanTrueSkipSafeFetch) {\n return true\n } else if (isAllowListSkipSafeFetch) {\n const existingSkipSafeFetch =\n typeof existingCollection.upload === 'object' &&\n Array.isArray(existingCollection.upload.skipSafeFetch)\n ? existingCollection.upload.skipSafeFetch\n : []\n\n const hasExactLocalhostMatch = existingSkipSafeFetch.some((entry) => {\n const entryKeys = Object.keys(entry)\n return entryKeys.length === 1 && entry.hostname === 'localhost'\n })\n\n const localhostEntry =\n process.env.NODE_ENV !== 'production' && !hasExactLocalhostMatch\n ? [{ hostname: 'localhost' }]\n : []\n\n return [...existingSkipSafeFetch, ...localhostEntry]\n }\n\n if (process.env.NODE_ENV !== 'production') {\n return [{ hostname: 'localhost' }]\n }\n\n return false\n }\n\n return {\n ...existingCollection,\n fields,\n hooks: {\n ...(existingCollection.hooks || {}),\n afterChange: [\n ...(existingCollection.hooks?.afterChange || []),\n getAfterChangeHook({\n adapter,\n collection: existingCollection,\n collectionPrefix: options.prefix,\n useCompositePrefixes,\n }),\n ],\n afterDelete: [\n ...(existingCollection.hooks?.afterDelete || []),\n getAfterDeleteHook({\n adapter,\n collection: existingCollection,\n collectionPrefix: options.prefix,\n useCompositePrefixes,\n }),\n ],\n beforeChange: [\n ...(existingCollection.hooks?.beforeChange || []),\n getNormalizeUploadPrefixHook({\n collectionPrefix: options.prefix,\n useCompositePrefixes,\n }),\n getPreserveFileDataHook(),\n ],\n },\n upload: {\n ...(typeof existingCollection.upload === 'object' ? existingCollection.upload : {}),\n adapter: adapter.name,\n ...(uploadInstructions && {\n uploadInstructions,\n }),\n disableLocalStorage:\n typeof options.disableLocalStorage === 'boolean' ? options.disableLocalStorage : true,\n handlers,\n skipSafeFetch: getSkipSafeFetchSetting(),\n },\n }\n }\n\n return existingCollection\n })\n\n return {\n ...config,\n collections,\n onInit: async (payload) => {\n // Await each init so a provisioning failure fails Payload startup\n // instead of becoming an unhandled rejection.\n await Promise.all(initFunctions.map((fn) => fn()))\n if (config.onInit) {\n await config.onInit(payload)\n }\n },\n }\n }\n"],"names":["getFields","getAfterChangeHook","getAfterDeleteHook","getNormalizeUploadPrefixHook","getPreserveFileDataHook","cloudStoragePlugin","pluginOptions","incomingConfig","collections","allCollectionOptions","enabled","useCompositePrefixes","config","map","existingCollection","options","slug","adapter","collection","prefix","undefined","fields","disablePayloadAccessControl","generateFileURL","initFunctions","endpointPaths","Map","onInit","push","uploadInstructions","adminHandler","endpoint","instructions","endpointPath","get","endpointCount","endpoints","filter","path","startsWith","length","handler","method","set","admin","components","providers","clientProps","collectionSlug","props","dependencies","type","handlers","upload","Array","isArray","staticHandler","req","args","params","getSkipSafeFetchSetting","isBooleanTrueSkipSafeFetch","skipSafeFetch","isAllowListSkipSafeFetch","existingSkipSafeFetch","hasExactLocalhostMatch","some","entry","entryKeys","Object","keys","hostname","localhostEntry","process","env","NODE_ENV","hooks","afterChange","collectionPrefix","afterDelete","beforeChange","name","disableLocalStorage","payload","Promise","all","fn"],"mappings":"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"}
|