@payloadcms/plugin-cloud-storage 1.0.17 → 1.0.19
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 +5 -3
- package/dist/adapters/azure/handleUpload.js +3 -2
- package/dist/adapters/azure/handleUpload.js.map +1 -1
- package/dist/adapters/gcs/handleUpload.js +3 -2
- package/dist/adapters/gcs/handleUpload.js.map +1 -1
- package/dist/adapters/s3/handleUpload.js +1 -1
- package/dist/adapters/s3/handleUpload.js.map +1 -1
- package/dist/adapters/s3/index.d.ts +10 -0
- package/dist/adapters/s3/index.js +1 -1
- package/dist/adapters/s3/index.js.map +1 -1
- package/dist/fields/getFields.js +1 -1
- package/dist/fields/getFields.js.map +1 -1
- package/package.json +1 -1
- package/.editorconfig +0 -10
- package/.gitignore +0 -248
- package/.prettierignore +0 -1
- package/.prettierrc.js +0 -8
- package/.vscode/launch.json +0 -40
- package/.vscode/settings.json +0 -9
- package/dev/.env +0 -21
- package/dev/.env.example +0 -21
- package/dev/dist/dev/src/collections/Media.js +0 -56
- package/dev/dist/dev/src/collections/Media.js.map +0 -1
- package/dev/dist/dev/src/collections/Users.js +0 -23
- package/dev/dist/dev/src/collections/Users.js.map +0 -1
- package/dev/dist/dev/src/payload.config.js +0 -153
- package/dev/dist/dev/src/payload.config.js.map +0 -1
- package/dev/dist/dev/src/server.js +0 -26
- package/dev/dist/dev/src/server.js.map +0 -1
- package/dev/dist/src/adapters/azure/generateURL.js +0 -16
- package/dev/dist/src/adapters/azure/generateURL.js.map +0 -1
- package/dev/dist/src/adapters/azure/handleDelete.js +0 -64
- package/dev/dist/src/adapters/azure/handleDelete.js.map +0 -1
- package/dev/dist/src/adapters/azure/handleUpload.js +0 -81
- package/dev/dist/src/adapters/azure/handleUpload.js.map +0 -1
- package/dev/dist/src/adapters/azure/index.js +0 -43
- package/dev/dist/src/adapters/azure/index.js.map +0 -1
- package/dev/dist/src/adapters/azure/staticHandler.js +0 -82
- package/dev/dist/src/adapters/azure/staticHandler.js.map +0 -1
- package/dev/dist/src/adapters/azure/webpack.js +0 -25
- package/dev/dist/src/adapters/azure/webpack.js.map +0 -1
- package/dev/dist/src/adapters/gcs/generateURL.js +0 -16
- package/dev/dist/src/adapters/gcs/generateURL.js.map +0 -1
- package/dev/dist/src/adapters/gcs/handleDelete.js +0 -63
- package/dev/dist/src/adapters/gcs/handleDelete.js.map +0 -1
- package/dev/dist/src/adapters/gcs/handleUpload.js +0 -73
- package/dev/dist/src/adapters/gcs/handleUpload.js.map +0 -1
- package/dev/dist/src/adapters/gcs/index.js +0 -36
- package/dev/dist/src/adapters/gcs/index.js.map +0 -1
- package/dev/dist/src/adapters/gcs/staticHandler.js +0 -77
- package/dev/dist/src/adapters/gcs/staticHandler.js.map +0 -1
- package/dev/dist/src/adapters/gcs/webpack.js +0 -25
- package/dev/dist/src/adapters/gcs/webpack.js.map +0 -1
- package/dev/dist/src/adapters/s3/generateURL.js +0 -16
- package/dev/dist/src/adapters/s3/generateURL.js.map +0 -1
- package/dev/dist/src/adapters/s3/handleDelete.js +0 -64
- package/dev/dist/src/adapters/s3/handleDelete.js.map +0 -1
- package/dev/dist/src/adapters/s3/handleUpload.js +0 -94
- package/dev/dist/src/adapters/s3/handleUpload.js.map +0 -1
- package/dev/dist/src/adapters/s3/index.js +0 -60
- package/dev/dist/src/adapters/s3/index.js.map +0 -1
- package/dev/dist/src/adapters/s3/staticHandler.js +0 -82
- package/dev/dist/src/adapters/s3/staticHandler.js.map +0 -1
- package/dev/dist/src/adapters/s3/webpack.js +0 -25
- package/dev/dist/src/adapters/s3/webpack.js.map +0 -1
- package/dev/dist/src/fields/getFields.js +0 -119
- package/dev/dist/src/fields/getFields.js.map +0 -1
- package/dev/dist/src/hooks/afterDelete.js +0 -92
- package/dev/dist/src/hooks/afterDelete.js.map +0 -1
- package/dev/dist/src/hooks/afterRead.js +0 -80
- package/dev/dist/src/hooks/afterRead.js.map +0 -1
- package/dev/dist/src/hooks/beforeChange.js +0 -106
- package/dev/dist/src/hooks/beforeChange.js.map +0 -1
- package/dev/dist/src/index.js +0 -6
- package/dev/dist/src/index.js.map +0 -1
- package/dev/dist/src/plugin.js +0 -131
- package/dev/dist/src/plugin.js.map +0 -1
- package/dev/dist/src/types.js +0 -3
- package/dev/dist/src/types.js.map +0 -1
- package/dev/dist/src/utilities/getFilePrefix.js +0 -81
- package/dev/dist/src/utilities/getFilePrefix.js.map +0 -1
- package/dev/dist/src/utilities/getIncomingFiles.js +0 -38
- package/dev/dist/src/utilities/getIncomingFiles.js.map +0 -1
- package/dev/dist/src/utilities/getRangeFromHeader.js +0 -67
- package/dev/dist/src/utilities/getRangeFromHeader.js.map +0 -1
- package/dev/dist/src/webpack.js +0 -40
- package/dev/dist/src/webpack.js.map +0 -1
- package/dev/nodemon.json +0 -8
- package/dev/package.json +0 -34
- package/dev/src/collections/Media.ts +0 -56
- package/dev/src/collections/Users.ts +0 -23
- package/dev/src/mocks/fsMock.js +0 -1
- package/dev/src/mocks/promisifyMock.js +0 -1
- package/dev/src/payload.config.ts +0 -111
- package/dev/src/server.ts +0 -26
- package/dev/tsconfig.json +0 -20
- package/docs/local-dev.md +0 -47
- package/eslint-config/index.js +0 -15
- package/eslint-config/rules/import.js +0 -38
- package/eslint-config/rules/prettier.js +0 -7
- package/eslint-config/rules/style.js +0 -21
- package/eslint-config/rules/typescript.js +0 -628
- package/src/adapters/azure/emulator/docker-compose.yml +0 -16
- package/src/adapters/azure/fileStub.js +0 -1
- package/src/adapters/azure/generateURL.ts +0 -13
- package/src/adapters/azure/handleDelete.ts +0 -16
- package/src/adapters/azure/handleUpload.ts +0 -41
- package/src/adapters/azure/index.ts +0 -48
- package/src/adapters/azure/mock.js +0 -13
- package/src/adapters/azure/staticHandler.ts +0 -38
- package/src/adapters/azure/webpack.ts +0 -24
- package/src/adapters/gcs/emulator/docker-compose.yml +0 -15
- package/src/adapters/gcs/generateURL.ts +0 -16
- package/src/adapters/gcs/handleDelete.ts +0 -16
- package/src/adapters/gcs/handleUpload.ts +0 -34
- package/src/adapters/gcs/index.ts +0 -37
- package/src/adapters/gcs/mock.js +0 -3
- package/src/adapters/gcs/staticHandler.ts +0 -34
- package/src/adapters/gcs/webpack.ts +0 -21
- package/src/adapters/s3/emulator/.localstack/cache/machine.json +0 -1
- package/src/adapters/s3/emulator/.localstack/cache/server.test.pem +0 -127
- package/src/adapters/s3/emulator/.localstack/cache/server.test.pem.crt +0 -99
- package/src/adapters/s3/emulator/.localstack/cache/server.test.pem.key +0 -28
- package/src/adapters/s3/emulator/.localstack/cache/service-catalog-2_1_1_dev-1_29_149.pickle +0 -0
- package/src/adapters/s3/emulator/docker-compose.yml +0 -15
- package/src/adapters/s3/fileStub.js +0 -1
- package/src/adapters/s3/fsMock.js +0 -1
- package/src/adapters/s3/generateURL.ts +0 -14
- package/src/adapters/s3/handleDelete.ts +0 -17
- package/src/adapters/s3/handleUpload.ts +0 -62
- package/src/adapters/s3/index.ts +0 -38
- package/src/adapters/s3/mock.js +0 -9
- package/src/adapters/s3/staticHandler.ts +0 -41
- package/src/adapters/s3/webpack.ts +0 -23
- package/src/fields/getFields.ts +0 -155
- package/src/hooks/afterDelete.ts +0 -35
- package/src/hooks/afterRead.ts +0 -38
- package/src/hooks/beforeChange.ts +0 -59
- package/src/index.ts +0 -1
- package/src/plugin.ts +0 -101
- package/src/types.ts +0 -79
- package/src/utilities/getFilePrefix.ts +0 -26
- package/src/utilities/getIncomingFiles.ts +0 -44
- package/src/utilities/getRangeFromHeader.ts +0 -27
- package/src/webpack.ts +0 -46
- package/tsconfig.json +0 -23
- package/yarn-error.log +0 -8163
- package/yarn.lock +0 -8062
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
version: '3.2'
|
|
2
|
-
services:
|
|
3
|
-
localstack:
|
|
4
|
-
image: localstack/localstack:latest
|
|
5
|
-
container_name: localstack_demo
|
|
6
|
-
ports:
|
|
7
|
-
- '4563-4599:4563-4599'
|
|
8
|
-
- '8055:8080'
|
|
9
|
-
environment:
|
|
10
|
-
- SERVICES=s3
|
|
11
|
-
- DEBUG=1
|
|
12
|
-
- DATA_DIR=/tmp/localstack/data
|
|
13
|
-
volumes:
|
|
14
|
-
- './.localstack:/var/lib/localstack'
|
|
15
|
-
- '/var/run/docker.sock:/var/run/docker.sock'
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default 'file-stub'
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = { fs: { createReadStream: () => null } }
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import type * as AWS from '@aws-sdk/client-s3'
|
|
3
|
-
import type { GenerateURL } from '../../types'
|
|
4
|
-
|
|
5
|
-
interface Args {
|
|
6
|
-
config: AWS.S3ClientConfig
|
|
7
|
-
bucket: string
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const getGenerateURL =
|
|
11
|
-
({ config: { endpoint }, bucket }: Args): GenerateURL =>
|
|
12
|
-
({ filename, prefix = '' }) => {
|
|
13
|
-
return `${endpoint}/${bucket}/${path.posix.join(prefix, filename)}`
|
|
14
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import type * as AWS from '@aws-sdk/client-s3'
|
|
3
|
-
import type { HandleDelete } from '../../types'
|
|
4
|
-
|
|
5
|
-
interface Args {
|
|
6
|
-
getStorageClient: () => AWS.S3
|
|
7
|
-
bucket: string
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const getHandleDelete = ({ getStorageClient, bucket }: Args): HandleDelete => {
|
|
11
|
-
return async ({ filename, doc: { prefix = '' } }) => {
|
|
12
|
-
await getStorageClient().deleteObject({
|
|
13
|
-
Bucket: bucket,
|
|
14
|
-
Key: path.posix.join(prefix, filename),
|
|
15
|
-
})
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import type * as AWS from '@aws-sdk/client-s3'
|
|
4
|
-
import type { CollectionConfig } from 'payload/types'
|
|
5
|
-
import type stream from 'stream'
|
|
6
|
-
|
|
7
|
-
import { Upload } from '@aws-sdk/lib-storage'
|
|
8
|
-
import type { HandleUpload } from '../../types'
|
|
9
|
-
|
|
10
|
-
interface Args {
|
|
11
|
-
collection: CollectionConfig
|
|
12
|
-
bucket: string
|
|
13
|
-
acl?: 'private' | 'public-read'
|
|
14
|
-
prefix?: string
|
|
15
|
-
getStorageClient: () => AWS.S3
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const multipartThreshold = 1024 * 1024 * 50 // 50MB
|
|
19
|
-
|
|
20
|
-
export const getHandleUpload = ({
|
|
21
|
-
getStorageClient,
|
|
22
|
-
bucket,
|
|
23
|
-
acl,
|
|
24
|
-
prefix = '',
|
|
25
|
-
}: Args): HandleUpload => {
|
|
26
|
-
return async ({ data, file }) => {
|
|
27
|
-
const fileKey = path.posix.join(prefix, file.filename)
|
|
28
|
-
|
|
29
|
-
const fileBufferOrStream: Buffer | stream.Readable = file.tempFilePath
|
|
30
|
-
? fs.createReadStream(file.tempFilePath)
|
|
31
|
-
: file.buffer
|
|
32
|
-
|
|
33
|
-
if (file.buffer.length > 0 && file.buffer.length < multipartThreshold) {
|
|
34
|
-
await getStorageClient().putObject({
|
|
35
|
-
Bucket: bucket,
|
|
36
|
-
Key: fileKey,
|
|
37
|
-
Body: fileBufferOrStream,
|
|
38
|
-
ACL: acl,
|
|
39
|
-
ContentType: file.mimeType,
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
return data
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const parallelUploadS3 = new Upload({
|
|
46
|
-
client: getStorageClient(),
|
|
47
|
-
params: {
|
|
48
|
-
Bucket: bucket,
|
|
49
|
-
Key: fileKey,
|
|
50
|
-
Body: fileBufferOrStream,
|
|
51
|
-
ACL: acl,
|
|
52
|
-
ContentType: file.mimeType,
|
|
53
|
-
},
|
|
54
|
-
queueSize: 4,
|
|
55
|
-
partSize: multipartThreshold,
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
await parallelUploadS3.done()
|
|
59
|
-
|
|
60
|
-
return data
|
|
61
|
-
}
|
|
62
|
-
}
|
package/src/adapters/s3/index.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import * as AWS from '@aws-sdk/client-s3'
|
|
2
|
-
import type { Adapter, GeneratedAdapter } from '../../types'
|
|
3
|
-
import { getGenerateURL } from './generateURL'
|
|
4
|
-
import { getHandler } from './staticHandler'
|
|
5
|
-
import { getHandleDelete } from './handleDelete'
|
|
6
|
-
import { getHandleUpload } from './handleUpload'
|
|
7
|
-
import { extendWebpackConfig } from './webpack'
|
|
8
|
-
|
|
9
|
-
export interface Args {
|
|
10
|
-
config: AWS.S3ClientConfig
|
|
11
|
-
bucket: string
|
|
12
|
-
acl?: 'private' | 'public-read'
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const s3Adapter =
|
|
16
|
-
({ config, bucket, acl }: Args): Adapter =>
|
|
17
|
-
({ collection, prefix }): GeneratedAdapter => {
|
|
18
|
-
let storageClient: AWS.S3 | null = null
|
|
19
|
-
const getStorageClient: () => AWS.S3 = () => {
|
|
20
|
-
if (storageClient) return storageClient
|
|
21
|
-
storageClient = new AWS.S3(config)
|
|
22
|
-
return storageClient
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return {
|
|
26
|
-
handleUpload: getHandleUpload({
|
|
27
|
-
collection,
|
|
28
|
-
getStorageClient,
|
|
29
|
-
bucket,
|
|
30
|
-
acl,
|
|
31
|
-
prefix,
|
|
32
|
-
}),
|
|
33
|
-
handleDelete: getHandleDelete({ getStorageClient, bucket }),
|
|
34
|
-
generateURL: getGenerateURL({ bucket, config }),
|
|
35
|
-
staticHandler: getHandler({ bucket, getStorageClient, collection }),
|
|
36
|
-
webpack: extendWebpackConfig,
|
|
37
|
-
}
|
|
38
|
-
}
|
package/src/adapters/s3/mock.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
exports.S3 = () => null
|
|
2
|
-
exports.Upload = () => null
|
|
3
|
-
|
|
4
|
-
exports.HeadObjectCommand = () => null
|
|
5
|
-
exports.PutObjectCommand = () => null
|
|
6
|
-
exports.UploadPartCommand = () => null
|
|
7
|
-
exports.CreateMultipartUploadCommand = () => null
|
|
8
|
-
exports.CompleteMultipartUploadCommand = () => null
|
|
9
|
-
exports.PutObjectTaggingCommand = () => null
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import type { Readable } from 'stream'
|
|
3
|
-
import type * as AWS from '@aws-sdk/client-s3'
|
|
4
|
-
import type { CollectionConfig } from 'payload/types'
|
|
5
|
-
import type { StaticHandler } from '../../types'
|
|
6
|
-
import { getFilePrefix } from '../../utilities/getFilePrefix'
|
|
7
|
-
|
|
8
|
-
interface Args {
|
|
9
|
-
getStorageClient: () => AWS.S3
|
|
10
|
-
bucket: string
|
|
11
|
-
collection: CollectionConfig
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const getHandler = ({ getStorageClient, bucket, collection }: Args): StaticHandler => {
|
|
15
|
-
return async (req, res, next) => {
|
|
16
|
-
try {
|
|
17
|
-
const prefix = await getFilePrefix({ req, collection })
|
|
18
|
-
|
|
19
|
-
const object = await getStorageClient().getObject({
|
|
20
|
-
Bucket: bucket,
|
|
21
|
-
Key: path.posix.join(prefix, req.params.filename),
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
res.set({
|
|
25
|
-
'Accept-Ranges': object.AcceptRanges,
|
|
26
|
-
'Content-Length': object.ContentLength,
|
|
27
|
-
'Content-Type': object.ContentType,
|
|
28
|
-
ETag: object.ETag,
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
if (object?.Body) {
|
|
32
|
-
return (object.Body as Readable).pipe(res)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return next()
|
|
36
|
-
} catch (err: unknown) {
|
|
37
|
-
req.payload.logger.error(err)
|
|
38
|
-
return next()
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { Configuration as WebpackConfig } from 'webpack'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
|
|
4
|
-
export const extendWebpackConfig = (existingWebpackConfig: WebpackConfig): WebpackConfig => {
|
|
5
|
-
const newConfig: WebpackConfig = {
|
|
6
|
-
...existingWebpackConfig,
|
|
7
|
-
resolve: {
|
|
8
|
-
...(existingWebpackConfig.resolve || {}),
|
|
9
|
-
fallback: {
|
|
10
|
-
...(existingWebpackConfig.resolve?.fallback ? existingWebpackConfig.resolve.fallback : {}),
|
|
11
|
-
stream: false,
|
|
12
|
-
},
|
|
13
|
-
alias: {
|
|
14
|
-
...(existingWebpackConfig.resolve?.alias ? existingWebpackConfig.resolve.alias : {}),
|
|
15
|
-
'@aws-sdk/client-s3': path.resolve(__dirname, './mock.js'),
|
|
16
|
-
'@aws-sdk/lib-storage': path.resolve(__dirname, './mock.js'),
|
|
17
|
-
fs: path.resolve(__dirname, './fsMock.js'),
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return newConfig
|
|
23
|
-
}
|
package/src/fields/getFields.ts
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import type { GroupField, TextField } from 'payload/dist/fields/config/types'
|
|
3
|
-
import type { CollectionConfig, Field } from 'payload/types'
|
|
4
|
-
import { getAfterReadHook } from '../hooks/afterRead'
|
|
5
|
-
import type { GeneratedAdapter, GenerateFileURL } from '../types'
|
|
6
|
-
|
|
7
|
-
interface Args {
|
|
8
|
-
collection: CollectionConfig
|
|
9
|
-
disablePayloadAccessControl?: true
|
|
10
|
-
generateFileURL?: GenerateFileURL
|
|
11
|
-
prefix?: string
|
|
12
|
-
adapter: GeneratedAdapter
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const getFields = ({
|
|
16
|
-
adapter,
|
|
17
|
-
collection,
|
|
18
|
-
disablePayloadAccessControl,
|
|
19
|
-
generateFileURL,
|
|
20
|
-
prefix,
|
|
21
|
-
}: Args): Field[] => {
|
|
22
|
-
const baseURLField: Field = {
|
|
23
|
-
name: 'url',
|
|
24
|
-
label: 'URL',
|
|
25
|
-
type: 'text',
|
|
26
|
-
admin: {
|
|
27
|
-
readOnly: true,
|
|
28
|
-
hidden: true,
|
|
29
|
-
},
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const basePrefixField: Field = {
|
|
33
|
-
name: 'prefix',
|
|
34
|
-
type: 'text',
|
|
35
|
-
admin: {
|
|
36
|
-
readOnly: true,
|
|
37
|
-
hidden: true,
|
|
38
|
-
},
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const fields = [...collection.fields]
|
|
42
|
-
|
|
43
|
-
// Inject a hook into all URL fields to generate URLs
|
|
44
|
-
|
|
45
|
-
let existingURLFieldIndex = -1
|
|
46
|
-
|
|
47
|
-
const existingURLField = fields.find((existingField, i) => {
|
|
48
|
-
if ('name' in existingField && existingField.name === 'url') {
|
|
49
|
-
existingURLFieldIndex = i
|
|
50
|
-
return true
|
|
51
|
-
}
|
|
52
|
-
return false
|
|
53
|
-
}) as TextField
|
|
54
|
-
|
|
55
|
-
if (existingURLFieldIndex > -1) {
|
|
56
|
-
fields.splice(existingURLFieldIndex, 1)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
fields.push({
|
|
60
|
-
...baseURLField,
|
|
61
|
-
...(existingURLField || {}),
|
|
62
|
-
hooks: {
|
|
63
|
-
afterRead: [
|
|
64
|
-
getAfterReadHook({ adapter, collection, disablePayloadAccessControl, generateFileURL }),
|
|
65
|
-
...(existingURLField?.hooks?.afterRead || []),
|
|
66
|
-
],
|
|
67
|
-
},
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
if (typeof collection.upload === 'object' && collection.upload.imageSizes) {
|
|
71
|
-
let existingSizesFieldIndex = -1
|
|
72
|
-
|
|
73
|
-
const existingSizesField = fields.find((existingField, i) => {
|
|
74
|
-
if ('name' in existingField && existingField.name === 'sizes') {
|
|
75
|
-
existingSizesFieldIndex = i
|
|
76
|
-
return true
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return false
|
|
80
|
-
}) as GroupField
|
|
81
|
-
|
|
82
|
-
if (existingSizesFieldIndex > -1) {
|
|
83
|
-
fields.splice(existingSizesFieldIndex, 1)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const sizesField: Field = {
|
|
87
|
-
...(existingSizesField || {}),
|
|
88
|
-
name: 'sizes',
|
|
89
|
-
type: 'group',
|
|
90
|
-
admin: {
|
|
91
|
-
hidden: true,
|
|
92
|
-
},
|
|
93
|
-
fields: collection.upload.imageSizes.map(size => {
|
|
94
|
-
const existingSizeField = existingSizesField?.fields.find(
|
|
95
|
-
existingField => 'name' in existingField && existingField.name === size.name,
|
|
96
|
-
) as GroupField
|
|
97
|
-
|
|
98
|
-
const existingSizeURLField = existingSizeField?.fields.find(
|
|
99
|
-
existingField => 'name' in existingField && existingField.name === 'url',
|
|
100
|
-
) as GroupField
|
|
101
|
-
|
|
102
|
-
return {
|
|
103
|
-
...existingSizeField,
|
|
104
|
-
name: size.name,
|
|
105
|
-
type: 'group',
|
|
106
|
-
fields: [
|
|
107
|
-
{
|
|
108
|
-
...(existingSizeURLField || {}),
|
|
109
|
-
...baseURLField,
|
|
110
|
-
hooks: {
|
|
111
|
-
afterRead: [
|
|
112
|
-
getAfterReadHook({
|
|
113
|
-
adapter,
|
|
114
|
-
collection,
|
|
115
|
-
size,
|
|
116
|
-
disablePayloadAccessControl,
|
|
117
|
-
generateFileURL,
|
|
118
|
-
}),
|
|
119
|
-
...(existingSizeURLField?.hooks?.afterRead || []),
|
|
120
|
-
],
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
],
|
|
124
|
-
}
|
|
125
|
-
}),
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
fields.push(sizesField)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// If prefix is enabled, save it to db
|
|
132
|
-
if (prefix) {
|
|
133
|
-
let existingPrefixFieldIndex = -1
|
|
134
|
-
|
|
135
|
-
const existingPrefixField = fields.find((existingField, i) => {
|
|
136
|
-
if ('name' in existingField && existingField.name === 'prefix') {
|
|
137
|
-
existingPrefixFieldIndex = i
|
|
138
|
-
return true
|
|
139
|
-
}
|
|
140
|
-
return false
|
|
141
|
-
}) as TextField
|
|
142
|
-
|
|
143
|
-
if (existingPrefixFieldIndex > -1) {
|
|
144
|
-
fields.splice(existingPrefixFieldIndex, 1)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
fields.push({
|
|
148
|
-
...basePrefixField,
|
|
149
|
-
...(existingPrefixField || {}),
|
|
150
|
-
defaultValue: path.posix.join(prefix),
|
|
151
|
-
})
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return fields
|
|
155
|
-
}
|
package/src/hooks/afterDelete.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { TypeWithID } from 'payload/dist/globals/config/types'
|
|
2
|
-
import type { FileData } from 'payload/dist/uploads/types'
|
|
3
|
-
import type { CollectionAfterDeleteHook, CollectionConfig } from 'payload/types'
|
|
4
|
-
import type { GeneratedAdapter, TypeWithPrefix } from '../types'
|
|
5
|
-
|
|
6
|
-
interface Args {
|
|
7
|
-
collection: CollectionConfig
|
|
8
|
-
adapter: GeneratedAdapter
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const getAfterDeleteHook = ({
|
|
12
|
-
collection,
|
|
13
|
-
adapter,
|
|
14
|
-
}: Args): CollectionAfterDeleteHook<FileData & TypeWithID & TypeWithPrefix> => {
|
|
15
|
-
return async ({ req, doc }) => {
|
|
16
|
-
try {
|
|
17
|
-
const filesToDelete: string[] = [
|
|
18
|
-
doc.filename,
|
|
19
|
-
...Object.values(doc?.sizes || []).map(resizedFileData => resizedFileData?.filename),
|
|
20
|
-
]
|
|
21
|
-
|
|
22
|
-
const promises = filesToDelete.map(async filename => {
|
|
23
|
-
if (filename) await adapter.handleDelete({ collection, doc, req, filename })
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
await Promise.all(promises)
|
|
27
|
-
} catch (err: unknown) {
|
|
28
|
-
req.payload.logger.error(
|
|
29
|
-
`There was an error while deleting files corresponding to the ${collection.labels?.singular} with ID ${doc.id}:`,
|
|
30
|
-
)
|
|
31
|
-
req.payload.logger.error(err)
|
|
32
|
-
}
|
|
33
|
-
return doc
|
|
34
|
-
}
|
|
35
|
-
}
|
package/src/hooks/afterRead.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { ImageSize } from 'payload/dist/uploads/types'
|
|
2
|
-
import type { CollectionConfig, FieldHook } from 'payload/types'
|
|
3
|
-
import type { GeneratedAdapter, GenerateFileURL } from '../types'
|
|
4
|
-
|
|
5
|
-
interface Args {
|
|
6
|
-
collection: CollectionConfig
|
|
7
|
-
adapter: GeneratedAdapter
|
|
8
|
-
disablePayloadAccessControl?: boolean
|
|
9
|
-
size?: ImageSize
|
|
10
|
-
generateFileURL?: GenerateFileURL
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const getAfterReadHook =
|
|
14
|
-
({ collection, adapter, size, disablePayloadAccessControl, generateFileURL }: Args): FieldHook =>
|
|
15
|
-
async ({ data, value }) => {
|
|
16
|
-
const filename = size ? data?.sizes?.[size.name]?.filename : data?.filename
|
|
17
|
-
const prefix = data?.prefix
|
|
18
|
-
let url = value
|
|
19
|
-
|
|
20
|
-
if (disablePayloadAccessControl && filename) {
|
|
21
|
-
url = await adapter.generateURL({
|
|
22
|
-
collection,
|
|
23
|
-
filename,
|
|
24
|
-
prefix,
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (generateFileURL) {
|
|
29
|
-
url = await generateFileURL({
|
|
30
|
-
collection,
|
|
31
|
-
filename,
|
|
32
|
-
prefix,
|
|
33
|
-
size,
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return url
|
|
38
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { TypeWithID } from 'payload/dist/collections/config/types'
|
|
2
|
-
import type { FileData } from 'payload/dist/uploads/types'
|
|
3
|
-
import type { CollectionBeforeChangeHook, CollectionConfig } from 'payload/types'
|
|
4
|
-
import type { GeneratedAdapter } from '../types'
|
|
5
|
-
import { getIncomingFiles } from '../utilities/getIncomingFiles'
|
|
6
|
-
|
|
7
|
-
interface Args {
|
|
8
|
-
collection: CollectionConfig
|
|
9
|
-
adapter: GeneratedAdapter
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const getBeforeChangeHook =
|
|
13
|
-
({ collection, adapter }: Args): CollectionBeforeChangeHook<FileData & TypeWithID> =>
|
|
14
|
-
async ({ req, data, originalDoc }) => {
|
|
15
|
-
try {
|
|
16
|
-
const files = getIncomingFiles({ req, data })
|
|
17
|
-
|
|
18
|
-
if (files.length > 0) {
|
|
19
|
-
// If there is an original doc,
|
|
20
|
-
// And we have new files,
|
|
21
|
-
// We need to delete the old files before uploading new
|
|
22
|
-
if (originalDoc) {
|
|
23
|
-
let filesToDelete: string[] = []
|
|
24
|
-
|
|
25
|
-
if (typeof originalDoc?.filename === 'string') {
|
|
26
|
-
filesToDelete.push(originalDoc.filename)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (typeof originalDoc.sizes === 'object') {
|
|
30
|
-
filesToDelete = filesToDelete.concat(
|
|
31
|
-
Object.values(originalDoc?.sizes || []).map(
|
|
32
|
-
resizedFileData => resizedFileData?.filename,
|
|
33
|
-
),
|
|
34
|
-
)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const deletionPromises = filesToDelete.map(async filename => {
|
|
38
|
-
if (filename) {
|
|
39
|
-
await adapter.handleDelete({ collection, doc: originalDoc, req, filename })
|
|
40
|
-
}
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
await Promise.all(deletionPromises)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const promises = files.map(async file => {
|
|
47
|
-
await adapter.handleUpload({ collection, data, req, file })
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
await Promise.all(promises)
|
|
51
|
-
}
|
|
52
|
-
} catch (err: unknown) {
|
|
53
|
-
req.payload.logger.error(
|
|
54
|
-
`There was an error while uploading files corresponding to the collection ${collection.slug} with filename ${data.filename}:`,
|
|
55
|
-
)
|
|
56
|
-
req.payload.logger.error(err)
|
|
57
|
-
}
|
|
58
|
-
return data
|
|
59
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { cloudStorage } from './plugin'
|
package/src/plugin.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import type { Config } from 'payload/config'
|
|
2
|
-
import { extendWebpackConfig } from './webpack'
|
|
3
|
-
import type { PluginOptions } from './types'
|
|
4
|
-
import { getBeforeChangeHook } from './hooks/beforeChange'
|
|
5
|
-
import { getAfterDeleteHook } from './hooks/afterDelete'
|
|
6
|
-
import { getFields } from './fields/getFields'
|
|
7
|
-
|
|
8
|
-
// This plugin extends all targeted collections by offloading uploaded files
|
|
9
|
-
// to cloud storage instead of solely storing files locally.
|
|
10
|
-
|
|
11
|
-
// It is based on an adapter approach, where adapters can be written for any cloud provider.
|
|
12
|
-
// Adapters are responsible for providing four actions that this plugin will use:
|
|
13
|
-
// 1. handleUpload, 2. handleDelete, 3. generateURL, 4. staticHandler
|
|
14
|
-
|
|
15
|
-
// Optionally, the adapter can specify any Webpack config overrides if they are necessary.
|
|
16
|
-
|
|
17
|
-
export const cloudStorage =
|
|
18
|
-
(pluginOptions: PluginOptions) =>
|
|
19
|
-
(incomingConfig: Config): Config => {
|
|
20
|
-
const { collections: allCollectionOptions, enabled } = pluginOptions
|
|
21
|
-
const config = { ...incomingConfig }
|
|
22
|
-
|
|
23
|
-
const webpack = extendWebpackConfig({ options: pluginOptions, config: incomingConfig })
|
|
24
|
-
|
|
25
|
-
config.admin = {
|
|
26
|
-
...(config.admin || {}),
|
|
27
|
-
webpack,
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Return early if disabled. Only webpack config mods are applied.
|
|
31
|
-
if (enabled === false) {
|
|
32
|
-
return config
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const initFunctions: Array<() => void> = []
|
|
36
|
-
|
|
37
|
-
return {
|
|
38
|
-
...config,
|
|
39
|
-
collections: (config.collections || []).map(existingCollection => {
|
|
40
|
-
const options = allCollectionOptions[existingCollection.slug]
|
|
41
|
-
|
|
42
|
-
if (options?.adapter) {
|
|
43
|
-
const adapter = options.adapter({
|
|
44
|
-
collection: existingCollection,
|
|
45
|
-
prefix: options.prefix,
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
if (adapter.onInit) initFunctions.push(adapter.onInit)
|
|
49
|
-
|
|
50
|
-
const fields = getFields({
|
|
51
|
-
collection: existingCollection,
|
|
52
|
-
disablePayloadAccessControl: options.disablePayloadAccessControl,
|
|
53
|
-
generateFileURL: options.generateFileURL,
|
|
54
|
-
prefix: options.prefix,
|
|
55
|
-
adapter,
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
const handlers = [
|
|
59
|
-
...(typeof existingCollection.upload === 'object' &&
|
|
60
|
-
Array.isArray(existingCollection.upload.handlers)
|
|
61
|
-
? existingCollection.upload.handlers
|
|
62
|
-
: []),
|
|
63
|
-
]
|
|
64
|
-
|
|
65
|
-
if (!options.disablePayloadAccessControl) {
|
|
66
|
-
handlers.push(adapter.staticHandler)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return {
|
|
70
|
-
...existingCollection,
|
|
71
|
-
upload: {
|
|
72
|
-
...(typeof existingCollection.upload === 'object' ? existingCollection.upload : {}),
|
|
73
|
-
handlers,
|
|
74
|
-
disableLocalStorage:
|
|
75
|
-
typeof options.disableLocalStorage === 'boolean'
|
|
76
|
-
? options.disableLocalStorage
|
|
77
|
-
: true,
|
|
78
|
-
},
|
|
79
|
-
hooks: {
|
|
80
|
-
...(existingCollection.hooks || {}),
|
|
81
|
-
beforeChange: [
|
|
82
|
-
...(existingCollection.hooks?.beforeChange || []),
|
|
83
|
-
getBeforeChangeHook({ adapter, collection: existingCollection }),
|
|
84
|
-
],
|
|
85
|
-
afterDelete: [
|
|
86
|
-
...(existingCollection.hooks?.afterDelete || []),
|
|
87
|
-
getAfterDeleteHook({ adapter, collection: existingCollection }),
|
|
88
|
-
],
|
|
89
|
-
},
|
|
90
|
-
fields,
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return existingCollection
|
|
95
|
-
}),
|
|
96
|
-
onInit: async payload => {
|
|
97
|
-
initFunctions.forEach(fn => fn())
|
|
98
|
-
if (config.onInit) await config.onInit(payload)
|
|
99
|
-
},
|
|
100
|
-
}
|
|
101
|
-
}
|