chore(plugin-cloud-storage): eslint fix
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ext": "ts",
|
||||
"exec": "node --trace-warnings -r ts-node/register -r ./src/server.ts",
|
||||
"ext": "ts",
|
||||
"watch": [
|
||||
"src/**/*.ts",
|
||||
"../src/**/*.ts"
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import path from 'path'
|
||||
|
||||
import type { GenerateURL } from '../../types'
|
||||
|
||||
interface Args {
|
||||
containerName: string
|
||||
baseURL: string
|
||||
containerName: string
|
||||
}
|
||||
|
||||
export const getGenerateURL =
|
||||
({ containerName, baseURL }: Args): GenerateURL =>
|
||||
({ baseURL, containerName }: Args): GenerateURL =>
|
||||
({ filename, prefix = '' }) => {
|
||||
return `${baseURL}/${containerName}/${path.posix.join(prefix, filename)}`
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import path from 'path'
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
import type { ContainerClient } from '@azure/storage-blob'
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
import type { HandleDelete } from '../../types'
|
||||
|
||||
interface Args {
|
||||
@@ -9,7 +11,7 @@ interface Args {
|
||||
}
|
||||
|
||||
export const getHandleDelete = ({ getStorageClient }: Args): HandleDelete => {
|
||||
return async ({ filename, doc: { prefix = '' } }) => {
|
||||
return async ({ doc: { prefix = '' }, filename }) => {
|
||||
const blockBlobClient = getStorageClient().getBlockBlobClient(path.posix.join(prefix, filename))
|
||||
await blockBlobClient.deleteIfExists()
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import { Readable } from 'stream'
|
||||
import type { ContainerClient } from '@azure/storage-blob'
|
||||
import { AbortController } from '@azure/abort-controller'
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
import { AbortController } from '@azure/abort-controller'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { Readable } from 'stream'
|
||||
|
||||
import type { HandleUpload } from '../../types'
|
||||
|
||||
interface Args {
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
import type { ContainerClient } from '@azure/storage-blob'
|
||||
|
||||
import { BlobServiceClient } from '@azure/storage-blob'
|
||||
|
||||
import type { Adapter, GeneratedAdapter } from '../../types'
|
||||
import { getHandler } from './staticHandler'
|
||||
|
||||
import { getGenerateURL } from './generateURL'
|
||||
import { getHandleDelete } from './handleDelete'
|
||||
import { getHandleUpload } from './handleUpload'
|
||||
import { getHandler } from './staticHandler'
|
||||
import { extendWebpackConfig } from './webpack'
|
||||
|
||||
export interface Args {
|
||||
allowContainerCreate: boolean
|
||||
baseURL: string
|
||||
connectionString: string
|
||||
containerName: string
|
||||
baseURL: string
|
||||
allowContainerCreate: boolean
|
||||
}
|
||||
|
||||
export const azureBlobStorageAdapter = ({
|
||||
connectionString,
|
||||
allowContainerCreate,
|
||||
containerName,
|
||||
baseURL,
|
||||
connectionString,
|
||||
containerName,
|
||||
}: Args): Adapter => {
|
||||
let storageClient: ContainerClient | null = null
|
||||
const getStorageClient = () => {
|
||||
@@ -33,14 +36,14 @@ export const azureBlobStorageAdapter = ({
|
||||
|
||||
return ({ collection, prefix }): GeneratedAdapter => {
|
||||
return {
|
||||
generateURL: getGenerateURL({ baseURL, containerName }),
|
||||
handleDelete: getHandleDelete({ collection, getStorageClient }),
|
||||
handleUpload: getHandleUpload({
|
||||
collection,
|
||||
getStorageClient,
|
||||
prefix,
|
||||
}),
|
||||
handleDelete: getHandleDelete({ collection, getStorageClient }),
|
||||
generateURL: getGenerateURL({ containerName, baseURL }),
|
||||
staticHandler: getHandler({ getStorageClient, collection }),
|
||||
staticHandler: getHandler({ collection, getStorageClient }),
|
||||
webpack: extendWebpackConfig,
|
||||
...(allowContainerCreate && { onInit: createContainerIfNotExists }),
|
||||
}
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
import type { ContainerClient } from '@azure/storage-blob'
|
||||
import path from 'path'
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
import type { StaticHandler } from '../../types'
|
||||
|
||||
import { getFilePrefix } from '../../utilities/getFilePrefix'
|
||||
import getRangeFromHeader from '../../utilities/getRangeFromHeader'
|
||||
|
||||
interface Args {
|
||||
getStorageClient: () => ContainerClient
|
||||
collection: CollectionConfig
|
||||
getStorageClient: () => ContainerClient
|
||||
}
|
||||
|
||||
export const getHandler = ({ getStorageClient, collection }: Args): StaticHandler => {
|
||||
export const getHandler = ({ collection, getStorageClient }: Args): StaticHandler => {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
const prefix = await getFilePrefix({ req, collection })
|
||||
const prefix = await getFilePrefix({ collection, req })
|
||||
const blockBlobClient = getStorageClient().getBlockBlobClient(
|
||||
path.posix.join(prefix, req.params.filename),
|
||||
)
|
||||
|
||||
const { start, end } = await getRangeFromHeader(blockBlobClient, req.headers.range)
|
||||
const { end, start } = await getRangeFromHeader(blockBlobClient, req.headers.range)
|
||||
|
||||
const blob = await blockBlobClient.download(start, end)
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Configuration as WebpackConfig } from 'webpack'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
export const extendWebpackConfig = (existingWebpackConfig: WebpackConfig): WebpackConfig => {
|
||||
@@ -6,14 +7,14 @@ export const extendWebpackConfig = (existingWebpackConfig: WebpackConfig): Webpa
|
||||
...existingWebpackConfig,
|
||||
resolve: {
|
||||
...(existingWebpackConfig.resolve || {}),
|
||||
fallback: {
|
||||
...(existingWebpackConfig.resolve?.fallback ? existingWebpackConfig.resolve.fallback : {}),
|
||||
stream: false,
|
||||
},
|
||||
alias: {
|
||||
...(existingWebpackConfig.resolve?.alias ? existingWebpackConfig.resolve.alias : {}),
|
||||
'@payloadcms/plugin-cloud-storage/azure': path.resolve(__dirname, './mock.js'),
|
||||
},
|
||||
fallback: {
|
||||
...(existingWebpackConfig.resolve?.fallback ? existingWebpackConfig.resolve.fallback : {}),
|
||||
stream: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import type { Storage } from '@google-cloud/storage'
|
||||
|
||||
import path from 'path'
|
||||
import { Storage } from '@google-cloud/storage'
|
||||
|
||||
import type { GenerateURL } from '../../types'
|
||||
|
||||
interface Args {
|
||||
getStorageClient: () => Storage
|
||||
bucket: string
|
||||
getStorageClient: () => Storage
|
||||
}
|
||||
|
||||
export const getGenerateURL =
|
||||
({ getStorageClient, bucket }: Args): GenerateURL =>
|
||||
({ bucket, getStorageClient }: Args): GenerateURL =>
|
||||
({ filename, prefix = '' }) => {
|
||||
return decodeURIComponent(
|
||||
getStorageClient().bucket(bucket).file(path.posix.join(prefix, filename)).publicUrl(),
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import type { Storage } from '@google-cloud/storage'
|
||||
|
||||
import path from 'path'
|
||||
import { Storage } from '@google-cloud/storage'
|
||||
|
||||
import type { HandleDelete } from '../../types'
|
||||
|
||||
interface Args {
|
||||
getStorageClient: () => Storage
|
||||
bucket: string
|
||||
getStorageClient: () => Storage
|
||||
}
|
||||
|
||||
export const getHandleDelete = ({ getStorageClient, bucket }: Args): HandleDelete => {
|
||||
return async ({ filename, doc: { prefix = '' } }) => {
|
||||
export const getHandleDelete = ({ bucket, getStorageClient }: Args): HandleDelete => {
|
||||
return async ({ doc: { prefix = '' }, filename }) => {
|
||||
await getStorageClient().bucket(bucket).file(path.posix.join(prefix, filename)).delete({
|
||||
ignoreNotFound: true,
|
||||
})
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import path from 'path'
|
||||
import type { Storage } from '@google-cloud/storage'
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
import type { HandleUpload } from '../../types'
|
||||
|
||||
interface Args {
|
||||
collection: CollectionConfig
|
||||
bucket: string
|
||||
acl?: 'Private' | 'Public'
|
||||
prefix?: string
|
||||
bucket: string
|
||||
collection: CollectionConfig
|
||||
getStorageClient: () => Storage
|
||||
prefix?: string
|
||||
}
|
||||
|
||||
export const getHandleUpload = ({
|
||||
getStorageClient,
|
||||
bucket,
|
||||
acl,
|
||||
bucket,
|
||||
getStorageClient,
|
||||
prefix = '',
|
||||
}: Args): HandleUpload => {
|
||||
return async ({ data, file }) => {
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import type { StorageOptions } from '@google-cloud/storage'
|
||||
|
||||
import { Storage } from '@google-cloud/storage'
|
||||
|
||||
import type { Adapter, GeneratedAdapter } from '../../types'
|
||||
|
||||
import { getGenerateURL } from './generateURL'
|
||||
import { getHandler } from './staticHandler'
|
||||
import { getHandleDelete } from './handleDelete'
|
||||
import { getHandleUpload } from './handleUpload'
|
||||
import { getHandler } from './staticHandler'
|
||||
import { extendWebpackConfig } from './webpack'
|
||||
|
||||
export interface Args {
|
||||
options: StorageOptions
|
||||
bucket: string
|
||||
acl?: 'Private' | 'Public'
|
||||
bucket: string
|
||||
options: StorageOptions
|
||||
}
|
||||
|
||||
export const gcsAdapter =
|
||||
({ options, bucket, acl }: Args): Adapter =>
|
||||
({ acl, bucket, options }: Args): Adapter =>
|
||||
({ collection, prefix }): GeneratedAdapter => {
|
||||
let storageClient: Storage | null = null
|
||||
|
||||
@@ -25,16 +28,16 @@ export const gcsAdapter =
|
||||
}
|
||||
|
||||
return {
|
||||
generateURL: getGenerateURL({ bucket, getStorageClient }),
|
||||
handleDelete: getHandleDelete({ bucket, getStorageClient }),
|
||||
handleUpload: getHandleUpload({
|
||||
acl,
|
||||
bucket,
|
||||
collection,
|
||||
getStorageClient,
|
||||
bucket,
|
||||
acl,
|
||||
prefix,
|
||||
}),
|
||||
handleDelete: getHandleDelete({ getStorageClient, bucket }),
|
||||
generateURL: getGenerateURL({ getStorageClient, bucket }),
|
||||
staticHandler: getHandler({ getStorageClient, bucket, collection }),
|
||||
staticHandler: getHandler({ bucket, collection, getStorageClient }),
|
||||
webpack: extendWebpackConfig,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import path from 'path'
|
||||
import type { Storage } from '@google-cloud/storage'
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
import type { StaticHandler } from '../../types'
|
||||
|
||||
import { getFilePrefix } from '../../utilities/getFilePrefix'
|
||||
|
||||
interface Args {
|
||||
getStorageClient: () => Storage
|
||||
bucket: string
|
||||
collection: CollectionConfig
|
||||
getStorageClient: () => Storage
|
||||
}
|
||||
|
||||
export const getHandler = ({ getStorageClient, bucket, collection }: Args): StaticHandler => {
|
||||
export const getHandler = ({ bucket, collection, getStorageClient }: Args): StaticHandler => {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
const prefix = await getFilePrefix({ req, collection })
|
||||
const prefix = await getFilePrefix({ collection, req })
|
||||
const file = getStorageClient()
|
||||
.bucket(bucket)
|
||||
.file(path.posix.join(prefix, req.params.filename))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Configuration as WebpackConfig } from 'webpack'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
export const extendWebpackConfig = (existingWebpackConfig: WebpackConfig): WebpackConfig => {
|
||||
@@ -6,14 +7,14 @@ export const extendWebpackConfig = (existingWebpackConfig: WebpackConfig): Webpa
|
||||
...existingWebpackConfig,
|
||||
resolve: {
|
||||
...(existingWebpackConfig.resolve || {}),
|
||||
fallback: {
|
||||
...(existingWebpackConfig.resolve?.fallback ? existingWebpackConfig.resolve.fallback : {}),
|
||||
stream: false,
|
||||
},
|
||||
alias: {
|
||||
...(existingWebpackConfig.resolve?.alias ? existingWebpackConfig.resolve.alias : {}),
|
||||
'@google-cloud/storage': path.resolve(__dirname, './mock.js'),
|
||||
},
|
||||
fallback: {
|
||||
...(existingWebpackConfig.resolve?.fallback ? existingWebpackConfig.resolve.fallback : {}),
|
||||
stream: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import path from 'path'
|
||||
import type * as AWS from '@aws-sdk/client-s3'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
import type { GenerateURL } from '../../types'
|
||||
|
||||
interface Args {
|
||||
config: AWS.S3ClientConfig
|
||||
bucket: string
|
||||
config: AWS.S3ClientConfig
|
||||
}
|
||||
|
||||
export const getGenerateURL =
|
||||
({ config: { endpoint }, bucket }: Args): GenerateURL =>
|
||||
({ bucket, config: { endpoint } }: Args): GenerateURL =>
|
||||
({ filename, prefix = '' }) => {
|
||||
return `${endpoint}/${bucket}/${path.posix.join(prefix, filename)}`
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import path from 'path'
|
||||
import type * as AWS from '@aws-sdk/client-s3'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
import type { HandleDelete } from '../../types'
|
||||
|
||||
interface Args {
|
||||
getStorageClient: () => AWS.S3
|
||||
bucket: string
|
||||
getStorageClient: () => AWS.S3
|
||||
}
|
||||
|
||||
export const getHandleDelete = ({ getStorageClient, bucket }: Args): HandleDelete => {
|
||||
return async ({ filename, doc: { prefix = '' } }) => {
|
||||
export const getHandleDelete = ({ bucket, getStorageClient }: Args): HandleDelete => {
|
||||
return async ({ doc: { prefix = '' }, filename }) => {
|
||||
await getStorageClient().deleteObject({
|
||||
Bucket: bucket,
|
||||
Key: path.posix.join(prefix, filename),
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import type * as AWS from '@aws-sdk/client-s3'
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
import type stream from 'stream'
|
||||
|
||||
import { Upload } from '@aws-sdk/lib-storage'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
import type { HandleUpload } from '../../types'
|
||||
|
||||
interface Args {
|
||||
collection: CollectionConfig
|
||||
bucket: string
|
||||
acl?: 'private' | 'public-read'
|
||||
prefix?: string
|
||||
bucket: string
|
||||
collection: CollectionConfig
|
||||
getStorageClient: () => AWS.S3
|
||||
prefix?: string
|
||||
}
|
||||
|
||||
const multipartThreshold = 1024 * 1024 * 50 // 50MB
|
||||
|
||||
export const getHandleUpload = ({
|
||||
getStorageClient,
|
||||
bucket,
|
||||
acl,
|
||||
bucket,
|
||||
getStorageClient,
|
||||
prefix = '',
|
||||
}: Args): HandleUpload => {
|
||||
return async ({ data, file }) => {
|
||||
@@ -32,11 +33,11 @@ export const getHandleUpload = ({
|
||||
|
||||
if (file.buffer.length > 0 && file.buffer.length < multipartThreshold) {
|
||||
await getStorageClient().putObject({
|
||||
Bucket: bucket,
|
||||
Key: fileKey,
|
||||
Body: fileBufferOrStream,
|
||||
ACL: acl,
|
||||
Body: fileBufferOrStream,
|
||||
Bucket: bucket,
|
||||
ContentType: file.mimeType,
|
||||
Key: fileKey,
|
||||
})
|
||||
|
||||
return data
|
||||
@@ -45,14 +46,14 @@ export const getHandleUpload = ({
|
||||
const parallelUploadS3 = new Upload({
|
||||
client: getStorageClient(),
|
||||
params: {
|
||||
Bucket: bucket,
|
||||
Key: fileKey,
|
||||
Body: fileBufferOrStream,
|
||||
ACL: acl,
|
||||
Body: fileBufferOrStream,
|
||||
Bucket: bucket,
|
||||
ContentType: file.mimeType,
|
||||
Key: fileKey,
|
||||
},
|
||||
queueSize: 4,
|
||||
partSize: multipartThreshold,
|
||||
queueSize: 4,
|
||||
})
|
||||
|
||||
await parallelUploadS3.done()
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
import * as AWS from '@aws-sdk/client-s3'
|
||||
|
||||
import type { Adapter, GeneratedAdapter } from '../../types'
|
||||
|
||||
import { getGenerateURL } from './generateURL'
|
||||
import { getHandler } from './staticHandler'
|
||||
import { getHandleDelete } from './handleDelete'
|
||||
import { getHandleUpload } from './handleUpload'
|
||||
import { getHandler } from './staticHandler'
|
||||
import { extendWebpackConfig } from './webpack'
|
||||
|
||||
export interface Args {
|
||||
/**
|
||||
* AWS S3 client configuration. Highly dependent on your AWS setup.
|
||||
*
|
||||
* [AWS.S3ClientConfig Docs](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-s3/interfaces/s3clientconfig.html)
|
||||
*/
|
||||
config: AWS.S3ClientConfig
|
||||
acl?: 'private' | 'public-read'
|
||||
/**
|
||||
* Bucket name to upload files to.
|
||||
*
|
||||
* Must follow [AWS S3 bucket naming conventions](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html).
|
||||
*/
|
||||
bucket: string
|
||||
acl?: 'private' | 'public-read'
|
||||
/**
|
||||
* AWS S3 client configuration. Highly dependent on your AWS setup.
|
||||
*
|
||||
* [AWS.S3ClientConfig Docs](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-s3/interfaces/s3clientconfig.html)
|
||||
*/
|
||||
config: AWS.S3ClientConfig
|
||||
}
|
||||
|
||||
export const s3Adapter =
|
||||
({ config = {}, bucket, acl }: Args): Adapter =>
|
||||
({ acl, bucket, config = {} }: Args): Adapter =>
|
||||
({ collection, prefix }): GeneratedAdapter => {
|
||||
let storageClient: AWS.S3 | null = null
|
||||
const getStorageClient: () => AWS.S3 = () => {
|
||||
@@ -33,16 +35,16 @@ export const s3Adapter =
|
||||
}
|
||||
|
||||
return {
|
||||
generateURL: getGenerateURL({ bucket, config }),
|
||||
handleDelete: getHandleDelete({ bucket, getStorageClient }),
|
||||
handleUpload: getHandleUpload({
|
||||
acl,
|
||||
bucket,
|
||||
collection,
|
||||
getStorageClient,
|
||||
bucket,
|
||||
acl,
|
||||
prefix,
|
||||
}),
|
||||
handleDelete: getHandleDelete({ getStorageClient, bucket }),
|
||||
generateURL: getGenerateURL({ bucket, config }),
|
||||
staticHandler: getHandler({ bucket, getStorageClient, collection }),
|
||||
staticHandler: getHandler({ bucket, collection, getStorageClient }),
|
||||
webpack: extendWebpackConfig,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import path from 'path'
|
||||
import type { Readable } from 'stream'
|
||||
import type * as AWS from '@aws-sdk/client-s3'
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
import type { Readable } from 'stream'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
import type { StaticHandler } from '../../types'
|
||||
|
||||
import { getFilePrefix } from '../../utilities/getFilePrefix'
|
||||
|
||||
interface Args {
|
||||
getStorageClient: () => AWS.S3
|
||||
bucket: string
|
||||
collection: CollectionConfig
|
||||
getStorageClient: () => AWS.S3
|
||||
}
|
||||
|
||||
export const getHandler = ({ getStorageClient, bucket, collection }: Args): StaticHandler => {
|
||||
export const getHandler = ({ bucket, collection, getStorageClient }: Args): StaticHandler => {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
const prefix = await getFilePrefix({ req, collection })
|
||||
const prefix = await getFilePrefix({ collection, req })
|
||||
|
||||
const object = await getStorageClient().getObject({
|
||||
Bucket: bucket,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Configuration as WebpackConfig } from 'webpack'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
export const extendWebpackConfig = (existingWebpackConfig: WebpackConfig): WebpackConfig => {
|
||||
@@ -6,14 +7,14 @@ export const extendWebpackConfig = (existingWebpackConfig: WebpackConfig): Webpa
|
||||
...existingWebpackConfig,
|
||||
resolve: {
|
||||
...(existingWebpackConfig.resolve || {}),
|
||||
fallback: {
|
||||
...(existingWebpackConfig.resolve?.fallback ? existingWebpackConfig.resolve.fallback : {}),
|
||||
stream: false,
|
||||
},
|
||||
alias: {
|
||||
...(existingWebpackConfig.resolve?.alias ? existingWebpackConfig.resolve.alias : {}),
|
||||
'@payloadcms/plugin-cloud-storage/s3': path.resolve(__dirname, './mock.js'),
|
||||
},
|
||||
fallback: {
|
||||
...(existingWebpackConfig.resolve?.fallback ? existingWebpackConfig.resolve.fallback : {}),
|
||||
stream: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import path from 'path'
|
||||
import type { GroupField, TextField } from 'payload/dist/fields/config/types'
|
||||
import type { CollectionConfig, Field } from 'payload/types'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
interface Args {
|
||||
collection: CollectionConfig
|
||||
prefix?: string
|
||||
@@ -10,21 +11,21 @@ interface Args {
|
||||
export const getFields = ({ collection, prefix }: Args): Field[] => {
|
||||
const baseURLField: Field = {
|
||||
name: 'url',
|
||||
admin: {
|
||||
hidden: true,
|
||||
readOnly: true,
|
||||
},
|
||||
label: 'URL',
|
||||
type: 'text',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
hidden: true,
|
||||
},
|
||||
}
|
||||
|
||||
const basePrefixField: Field = {
|
||||
name: 'prefix',
|
||||
type: 'text',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
hidden: true,
|
||||
readOnly: true,
|
||||
},
|
||||
type: 'text',
|
||||
}
|
||||
|
||||
const fields = [...collection.fields]
|
||||
@@ -69,31 +70,31 @@ export const getFields = ({ collection, prefix }: Args): Field[] => {
|
||||
const sizesField: Field = {
|
||||
...(existingSizesField || {}),
|
||||
name: 'sizes',
|
||||
type: 'group',
|
||||
admin: {
|
||||
hidden: true,
|
||||
},
|
||||
fields: collection.upload.imageSizes.map(size => {
|
||||
fields: collection.upload.imageSizes.map((size) => {
|
||||
const existingSizeField = existingSizesField?.fields.find(
|
||||
existingField => 'name' in existingField && existingField.name === size.name,
|
||||
(existingField) => 'name' in existingField && existingField.name === size.name,
|
||||
) as GroupField
|
||||
|
||||
const existingSizeURLField = existingSizeField?.fields.find(
|
||||
existingField => 'name' in existingField && existingField.name === 'url',
|
||||
(existingField) => 'name' in existingField && existingField.name === 'url',
|
||||
) as GroupField
|
||||
|
||||
return {
|
||||
...existingSizeField,
|
||||
name: size.name,
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
...(existingSizeURLField || {}),
|
||||
...baseURLField,
|
||||
},
|
||||
],
|
||||
type: 'group',
|
||||
}
|
||||
}),
|
||||
type: 'group',
|
||||
}
|
||||
|
||||
fields.push(sizesField)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { Config } from 'payload/config'
|
||||
|
||||
import type { PluginOptions } from '../types'
|
||||
|
||||
import { getFields } from './fields/getFields'
|
||||
|
||||
// This is the admin plugin cloud-storage stubfile.
|
||||
@@ -18,7 +20,7 @@ export const cloudStorage =
|
||||
|
||||
return {
|
||||
...config,
|
||||
collections: (config.collections || []).map(existingCollection => {
|
||||
collections: (config.collections || []).map((existingCollection) => {
|
||||
const options = allCollectionOptions[existingCollection.slug]
|
||||
|
||||
if (options?.adapter) {
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import path from 'path'
|
||||
import type { GroupField, TextField } from 'payload/dist/fields/config/types'
|
||||
import type { CollectionConfig, Field } from 'payload/types'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
import type { GenerateFileURL, GeneratedAdapter } from '../types'
|
||||
|
||||
import { getAfterReadHook } from '../hooks/afterRead'
|
||||
import type { GeneratedAdapter, GenerateFileURL } from '../types'
|
||||
|
||||
interface Args {
|
||||
adapter: GeneratedAdapter
|
||||
collection: CollectionConfig
|
||||
disablePayloadAccessControl?: true
|
||||
generateFileURL?: GenerateFileURL
|
||||
prefix?: string
|
||||
adapter: GeneratedAdapter
|
||||
}
|
||||
|
||||
export const getFields = ({
|
||||
@@ -21,21 +24,21 @@ export const getFields = ({
|
||||
}: Args): Field[] => {
|
||||
const baseURLField: Field = {
|
||||
name: 'url',
|
||||
admin: {
|
||||
hidden: true,
|
||||
readOnly: true,
|
||||
},
|
||||
label: 'URL',
|
||||
type: 'text',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
hidden: true,
|
||||
},
|
||||
}
|
||||
|
||||
const basePrefixField: Field = {
|
||||
name: 'prefix',
|
||||
type: 'text',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
hidden: true,
|
||||
readOnly: true,
|
||||
},
|
||||
type: 'text',
|
||||
}
|
||||
|
||||
const fields = [...collection.fields]
|
||||
@@ -86,23 +89,21 @@ export const getFields = ({
|
||||
const sizesField: Field = {
|
||||
...(existingSizesField || {}),
|
||||
name: 'sizes',
|
||||
type: 'group',
|
||||
admin: {
|
||||
hidden: true,
|
||||
},
|
||||
fields: collection.upload.imageSizes.map(size => {
|
||||
fields: collection.upload.imageSizes.map((size) => {
|
||||
const existingSizeField = existingSizesField?.fields.find(
|
||||
existingField => 'name' in existingField && existingField.name === size.name,
|
||||
(existingField) => 'name' in existingField && existingField.name === size.name,
|
||||
) as GroupField
|
||||
|
||||
const existingSizeURLField = existingSizeField?.fields.find(
|
||||
existingField => 'name' in existingField && existingField.name === 'url',
|
||||
(existingField) => 'name' in existingField && existingField.name === 'url',
|
||||
) as GroupField
|
||||
|
||||
return {
|
||||
...existingSizeField,
|
||||
name: size.name,
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
...(existingSizeURLField || {}),
|
||||
@@ -112,17 +113,19 @@ export const getFields = ({
|
||||
getAfterReadHook({
|
||||
adapter,
|
||||
collection,
|
||||
size,
|
||||
disablePayloadAccessControl,
|
||||
generateFileURL,
|
||||
size,
|
||||
}),
|
||||
...(existingSizeURLField?.hooks?.afterRead || []),
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'group',
|
||||
}
|
||||
}),
|
||||
type: 'group',
|
||||
}
|
||||
|
||||
fields.push(sizesField)
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
import type { TypeWithID } from 'payload/dist/globals/config/types'
|
||||
import type { FileData } from 'payload/dist/uploads/types'
|
||||
import type { CollectionAfterDeleteHook, CollectionConfig } from 'payload/types'
|
||||
|
||||
import type { GeneratedAdapter, TypeWithPrefix } from '../types'
|
||||
|
||||
interface Args {
|
||||
collection: CollectionConfig
|
||||
adapter: GeneratedAdapter
|
||||
collection: CollectionConfig
|
||||
}
|
||||
|
||||
export const getAfterDeleteHook = ({
|
||||
collection,
|
||||
adapter,
|
||||
collection,
|
||||
}: Args): CollectionAfterDeleteHook<FileData & TypeWithID & TypeWithPrefix> => {
|
||||
return async ({ req, doc }) => {
|
||||
return async ({ doc, req }) => {
|
||||
try {
|
||||
const filesToDelete: string[] = [
|
||||
doc.filename,
|
||||
...Object.values(doc?.sizes || []).map(resizedFileData => resizedFileData?.filename),
|
||||
...Object.values(doc?.sizes || []).map((resizedFileData) => resizedFileData?.filename),
|
||||
]
|
||||
|
||||
const promises = filesToDelete.map(async filename => {
|
||||
if (filename) await adapter.handleDelete({ collection, doc, req, filename })
|
||||
const promises = filesToDelete.map(async (filename) => {
|
||||
if (filename) await adapter.handleDelete({ collection, doc, filename, req })
|
||||
})
|
||||
|
||||
await Promise.all(promises)
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import type { ImageSize } from 'payload/dist/uploads/types'
|
||||
import type { CollectionConfig, FieldHook } from 'payload/types'
|
||||
import type { GeneratedAdapter, GenerateFileURL } from '../types'
|
||||
|
||||
import type { GenerateFileURL, GeneratedAdapter } from '../types'
|
||||
|
||||
interface Args {
|
||||
collection: CollectionConfig
|
||||
adapter: GeneratedAdapter
|
||||
collection: CollectionConfig
|
||||
disablePayloadAccessControl?: boolean
|
||||
size?: ImageSize
|
||||
generateFileURL?: GenerateFileURL
|
||||
size?: ImageSize
|
||||
}
|
||||
|
||||
export const getAfterReadHook =
|
||||
({ collection, adapter, size, disablePayloadAccessControl, generateFileURL }: Args): FieldHook =>
|
||||
({ adapter, collection, disablePayloadAccessControl, generateFileURL, size }: Args): FieldHook =>
|
||||
async ({ data, value }) => {
|
||||
const filename = size ? data?.sizes?.[size.name]?.filename : data?.filename
|
||||
const prefix = data?.prefix
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import type { TypeWithID } from 'payload/dist/collections/config/types'
|
||||
import type { FileData } from 'payload/dist/uploads/types'
|
||||
import type { CollectionBeforeChangeHook, CollectionConfig } from 'payload/types'
|
||||
|
||||
import type { GeneratedAdapter } from '../types'
|
||||
|
||||
import { getIncomingFiles } from '../utilities/getIncomingFiles'
|
||||
|
||||
interface Args {
|
||||
collection: CollectionConfig
|
||||
adapter: GeneratedAdapter
|
||||
collection: CollectionConfig
|
||||
}
|
||||
|
||||
export const getBeforeChangeHook =
|
||||
({ collection, adapter }: Args): CollectionBeforeChangeHook<FileData & TypeWithID> =>
|
||||
async ({ req, data, originalDoc }) => {
|
||||
({ adapter, collection }: Args): CollectionBeforeChangeHook<FileData & TypeWithID> =>
|
||||
async ({ data, originalDoc, req }) => {
|
||||
try {
|
||||
const files = getIncomingFiles({ req, data })
|
||||
const files = getIncomingFiles({ data, req })
|
||||
|
||||
if (files.length > 0) {
|
||||
// If there is an original doc,
|
||||
@@ -29,22 +31,22 @@ export const getBeforeChangeHook =
|
||||
if (typeof originalDoc.sizes === 'object') {
|
||||
filesToDelete = filesToDelete.concat(
|
||||
Object.values(originalDoc?.sizes || []).map(
|
||||
resizedFileData => resizedFileData?.filename,
|
||||
(resizedFileData) => resizedFileData?.filename,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
const deletionPromises = filesToDelete.map(async filename => {
|
||||
const deletionPromises = filesToDelete.map(async (filename) => {
|
||||
if (filename) {
|
||||
await adapter.handleDelete({ collection, doc: originalDoc, req, filename })
|
||||
await adapter.handleDelete({ collection, doc: originalDoc, filename, req })
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.all(deletionPromises)
|
||||
}
|
||||
|
||||
const promises = files.map(async file => {
|
||||
await adapter.handleUpload({ collection, data, req, file })
|
||||
const promises = files.map(async (file) => {
|
||||
await adapter.handleUpload({ collection, data, file, req })
|
||||
})
|
||||
|
||||
await Promise.all(promises)
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import type { Config } from 'payload/config'
|
||||
import { extendWebpackConfig } from './webpack'
|
||||
|
||||
import type { PluginOptions } from './types'
|
||||
import { getBeforeChangeHook } from './hooks/beforeChange'
|
||||
import { getAfterDeleteHook } from './hooks/afterDelete'
|
||||
|
||||
import { getFields } from './fields/getFields'
|
||||
import { getAfterDeleteHook } from './hooks/afterDelete'
|
||||
import { getBeforeChangeHook } from './hooks/beforeChange'
|
||||
import { extendWebpackConfig } from './webpack'
|
||||
|
||||
// This plugin extends all targeted collections by offloading uploaded files
|
||||
// to cloud storage instead of solely storing files locally.
|
||||
@@ -20,7 +22,7 @@ export const cloudStorage =
|
||||
const { collections: allCollectionOptions, enabled } = pluginOptions
|
||||
const config = { ...incomingConfig }
|
||||
|
||||
const webpack = extendWebpackConfig({ options: pluginOptions, config: incomingConfig })
|
||||
const webpack = extendWebpackConfig({ config: incomingConfig, options: pluginOptions })
|
||||
|
||||
config.admin = {
|
||||
...(config.admin || {}),
|
||||
@@ -36,7 +38,7 @@ export const cloudStorage =
|
||||
|
||||
return {
|
||||
...config,
|
||||
collections: (config.collections || []).map(existingCollection => {
|
||||
collections: (config.collections || []).map((existingCollection) => {
|
||||
const options = allCollectionOptions[existingCollection.slug]
|
||||
|
||||
if (options?.adapter) {
|
||||
@@ -48,11 +50,11 @@ export const cloudStorage =
|
||||
if (adapter.onInit) initFunctions.push(adapter.onInit)
|
||||
|
||||
const fields = getFields({
|
||||
adapter,
|
||||
collection: existingCollection,
|
||||
disablePayloadAccessControl: options.disablePayloadAccessControl,
|
||||
generateFileURL: options.generateFileURL,
|
||||
prefix: options.prefix,
|
||||
adapter,
|
||||
})
|
||||
|
||||
const handlers = [
|
||||
@@ -68,33 +70,33 @@ export const cloudStorage =
|
||||
|
||||
return {
|
||||
...existingCollection,
|
||||
upload: {
|
||||
...(typeof existingCollection.upload === 'object' ? existingCollection.upload : {}),
|
||||
handlers,
|
||||
disableLocalStorage:
|
||||
typeof options.disableLocalStorage === 'boolean'
|
||||
? options.disableLocalStorage
|
||||
: true,
|
||||
},
|
||||
fields,
|
||||
hooks: {
|
||||
...(existingCollection.hooks || {}),
|
||||
beforeChange: [
|
||||
...(existingCollection.hooks?.beforeChange || []),
|
||||
getBeforeChangeHook({ adapter, collection: existingCollection }),
|
||||
],
|
||||
afterDelete: [
|
||||
...(existingCollection.hooks?.afterDelete || []),
|
||||
getAfterDeleteHook({ adapter, collection: existingCollection }),
|
||||
],
|
||||
beforeChange: [
|
||||
...(existingCollection.hooks?.beforeChange || []),
|
||||
getBeforeChangeHook({ adapter, collection: existingCollection }),
|
||||
],
|
||||
},
|
||||
upload: {
|
||||
...(typeof existingCollection.upload === 'object' ? existingCollection.upload : {}),
|
||||
disableLocalStorage:
|
||||
typeof options.disableLocalStorage === 'boolean'
|
||||
? options.disableLocalStorage
|
||||
: true,
|
||||
handlers,
|
||||
},
|
||||
fields,
|
||||
}
|
||||
}
|
||||
|
||||
return existingCollection
|
||||
}),
|
||||
onInit: async payload => {
|
||||
initFunctions.forEach(fn => fn())
|
||||
onInit: async (payload) => {
|
||||
initFunctions.forEach((fn) => fn())
|
||||
if (config.onInit) await config.onInit(payload)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ export interface File {
|
||||
|
||||
export type HandleUpload = (args: {
|
||||
collection: CollectionConfig
|
||||
req: PayloadRequest
|
||||
data: any
|
||||
file: File
|
||||
req: PayloadRequest
|
||||
}) => Promise<void> | void
|
||||
|
||||
export interface TypeWithPrefix {
|
||||
@@ -25,16 +25,16 @@ export interface TypeWithPrefix {
|
||||
|
||||
export type HandleDelete = (args: {
|
||||
collection: CollectionConfig
|
||||
req: PayloadRequest
|
||||
doc: TypeWithID & FileData & TypeWithPrefix
|
||||
filename: string
|
||||
req: PayloadRequest
|
||||
}) => Promise<void> | void
|
||||
|
||||
export type GenerateURL = (args: {
|
||||
filename: string
|
||||
collection: CollectionConfig
|
||||
filename: string
|
||||
prefix?: string
|
||||
}) => string | Promise<string>
|
||||
}) => Promise<string> | string
|
||||
|
||||
export type StaticHandler = (
|
||||
req: PayloadRequest,
|
||||
@@ -43,12 +43,12 @@ export type StaticHandler = (
|
||||
) => Promise<unknown> | unknown
|
||||
|
||||
export interface GeneratedAdapter {
|
||||
handleUpload: HandleUpload
|
||||
handleDelete: HandleDelete
|
||||
generateURL: GenerateURL
|
||||
handleDelete: HandleDelete
|
||||
handleUpload: HandleUpload
|
||||
onInit?: () => void
|
||||
staticHandler: StaticHandler
|
||||
webpack?: (config: WebpackConfig) => WebpackConfig
|
||||
onInit?: () => void
|
||||
}
|
||||
|
||||
export type Adapter = (args: { collection: CollectionConfig; prefix?: string }) => GeneratedAdapter
|
||||
@@ -61,19 +61,19 @@ export type GenerateFileURL = (args: {
|
||||
}) => Promise<string> | string
|
||||
|
||||
export interface CollectionOptions {
|
||||
adapter: Adapter | null
|
||||
disableLocalStorage?: boolean
|
||||
disablePayloadAccessControl?: true
|
||||
generateFileURL?: GenerateFileURL
|
||||
prefix?: string
|
||||
adapter: Adapter | null
|
||||
}
|
||||
|
||||
export interface PluginOptions {
|
||||
collections: Record<string, CollectionOptions>
|
||||
/**
|
||||
* Whether or not to enable the plugin
|
||||
*
|
||||
* Default: true
|
||||
*/
|
||||
enabled?: boolean
|
||||
collections: Record<string, CollectionOptions>
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { IncomingUploadType } from 'payload/dist/uploads/types'
|
||||
import type { CollectionConfig, PayloadRequest } from 'payload/types'
|
||||
import { IncomingUploadType } from 'payload/dist/uploads/types'
|
||||
|
||||
export async function getFilePrefix({
|
||||
req,
|
||||
collection,
|
||||
req,
|
||||
}: {
|
||||
req: PayloadRequest
|
||||
collection: CollectionConfig
|
||||
req: PayloadRequest
|
||||
}): Promise<string> {
|
||||
const imageSizes = (collection?.upload as IncomingUploadType)?.imageSizes || []
|
||||
const files = await req.payload.find({
|
||||
@@ -16,7 +16,7 @@ export async function getFilePrefix({
|
||||
{
|
||||
filename: { equals: req.params.filename },
|
||||
},
|
||||
...imageSizes.map(imageSize => ({
|
||||
...imageSizes.map((imageSize) => ({
|
||||
[`sizes.${imageSize.name}.filename`]: { equals: req.params.filename },
|
||||
})),
|
||||
],
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { FileData } from 'payload/dist/uploads/types'
|
||||
import type { PayloadRequest } from 'payload/types'
|
||||
|
||||
import type { File } from '../types'
|
||||
|
||||
export function getIncomingFiles({
|
||||
req,
|
||||
data,
|
||||
req,
|
||||
}: {
|
||||
data: Partial<FileData>
|
||||
req: PayloadRequest
|
||||
@@ -15,11 +16,11 @@ export function getIncomingFiles({
|
||||
|
||||
if (file && data.filename && data.mimeType) {
|
||||
const mainFile: File = {
|
||||
filename: data.filename,
|
||||
mimeType: data.mimeType,
|
||||
buffer: file.data,
|
||||
tempFilePath: file.tempFilePath,
|
||||
filename: data.filename,
|
||||
filesize: file.size,
|
||||
mimeType: data.mimeType,
|
||||
tempFilePath: file.tempFilePath,
|
||||
}
|
||||
|
||||
files = [mainFile]
|
||||
@@ -29,10 +30,10 @@ export function getIncomingFiles({
|
||||
if (req.payloadUploadSizes?.[key] && data.mimeType) {
|
||||
files = files.concat([
|
||||
{
|
||||
filename: `${resizedFileData.filename}`,
|
||||
mimeType: data.mimeType,
|
||||
buffer: req.payloadUploadSizes[key],
|
||||
filename: `${resizedFileData.filename}`,
|
||||
filesize: req.payloadUploadSizes[key].length,
|
||||
mimeType: data.mimeType,
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import type { BlockBlobClient } from '@azure/storage-blob'
|
||||
|
||||
import parseRange from 'range-parser'
|
||||
|
||||
const getRangeFromHeader = async (
|
||||
blockBlobClient: BlockBlobClient,
|
||||
rangeHeader?: string,
|
||||
): Promise<{ start: number; end: number | undefined }> => {
|
||||
const fullRange = { start: 0, end: undefined }
|
||||
): Promise<{ end: number | undefined; start: number }> => {
|
||||
const fullRange = { end: undefined, start: 0 }
|
||||
|
||||
if (!rangeHeader) {
|
||||
return fullRange
|
||||
}
|
||||
|
||||
const size = await blockBlobClient.getProperties().then(props => props.contentLength)
|
||||
const size = await blockBlobClient.getProperties().then((props) => props.contentLength)
|
||||
if (size === undefined) {
|
||||
return fullRange
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import path from 'path'
|
||||
import type { Config } from 'payload/config'
|
||||
import type { Configuration as WebpackConfig } from 'webpack'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
import type { GeneratedAdapter, PluginOptions } from './types'
|
||||
|
||||
interface Args {
|
||||
@@ -10,7 +12,7 @@ interface Args {
|
||||
|
||||
export const extendWebpackConfig =
|
||||
({ config, options }: Args): ((webpackConfig: WebpackConfig) => WebpackConfig) =>
|
||||
webpackConfig => {
|
||||
(webpackConfig) => {
|
||||
const existingWebpackConfig =
|
||||
typeof config.admin?.webpack === 'function'
|
||||
? config.admin.webpack(webpackConfig)
|
||||
@@ -29,7 +31,7 @@ export const extendWebpackConfig =
|
||||
|
||||
return Object.entries(options.collections).reduce(
|
||||
(resultingWebpackConfig, [slug, collectionOptions]) => {
|
||||
const matchedCollection = config.collections?.find(coll => coll.slug === slug)
|
||||
const matchedCollection = config.collections?.find((coll) => coll.slug === slug)
|
||||
|
||||
if (matchedCollection && typeof collectionOptions.adapter === 'function') {
|
||||
const adapter: GeneratedAdapter = collectionOptions.adapter({
|
||||
|
||||
Reference in New Issue
Block a user