@websolutespa/payload-plugin-storage 2.0.1-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @websolutespa/payload-plugin-storage
2
+
3
+ ## 2.0.1-next.0
4
+
5
+ ### Major Changes
6
+
7
+ - e74b305: Release: Payload 3.7.0
package/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # @websolutespa/payload-plugin-storage
2
+
3
+ [![npm version](https://badge.fury.io/js/%40websolutespa%2Fpayload-plugin-storage.svg)](https://badge.fury.io/js/%40websolutespa%2Fpayload-plugin-storage)
4
+
5
+ [![status alpha](https://img.shields.io/badge/status-alpha-red.svg)](https://shields.io/)
6
+
7
+ Storage plugin for PayloadCms.
8
+
9
+ # Payload Storage Plugin
10
+
11
+ A plugin for [Payload CMS](https://github.com/payloadcms/payload) that handle multiple storage adapters.
12
+
13
+ ### Requirements:
14
+
15
+ - Payload version 3.48.0 or higher is required.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm i @websolutespa/payload-plugin-storage
21
+ ```
22
+
23
+ ---
24
+
25
+ ##### *this library is for internal usage and not production ready*
@@ -0,0 +1,40 @@
1
+ import { AzureStorageOptions } from "@payloadcms/storage-azure";
2
+ import { GcsStorageOptions } from "@payloadcms/storage-gcs";
3
+ import { S3StorageOptions } from "@payloadcms/storage-s3";
4
+ import { FSStorageOptions } from "@websolutespa/payload-plugin-cloud-storage-fs";
5
+ import * as payload0 from "payload";
6
+ import { Plugin, UploadCollectionSlug } from "payload";
7
+
8
+ //#region src/types.d.ts
9
+ type StorageFsOptions = {
10
+ adapter: 'fs';
11
+ collections?: UploadCollectionSlug[];
12
+ } & Partial<FSStorageOptions>;
13
+ type StorageAzureOptions = {
14
+ adapter: 'azure';
15
+ collections?: AzureStorageOptions['collections'] | string[] | string;
16
+ } & Omit<Partial<AzureStorageOptions>, 'collections'>;
17
+ type StorageGcsOptions = {
18
+ adapter: 'gcs';
19
+ collections?: GcsStorageOptions['collections'] | string[] | string;
20
+ } & Partial<GcsStorageOptions>;
21
+ type StorageS3Options = {
22
+ adapter: 's3';
23
+ collections?: S3StorageOptions['collections'] | string[] | string;
24
+ } & Partial<S3StorageOptions>;
25
+ type StorageOptions = StorageFsOptions | StorageAzureOptions | StorageGcsOptions | StorageS3Options;
26
+ //# sourceMappingURL=types.d.ts.map
27
+ //#endregion
28
+ //#region src/plugin.d.ts
29
+ declare const storage: (options: StorageOptions & {
30
+ enabled?: boolean;
31
+ }) => Plugin;
32
+ //# sourceMappingURL=plugin.d.ts.map
33
+ //#endregion
34
+ //#region src/index.d.ts
35
+ declare const storagePlugin: (options: StorageOptions & {
36
+ enabled?: boolean;
37
+ }) => payload0.Plugin;
38
+ //#endregion
39
+ export { StorageAzureOptions, StorageFsOptions, StorageGcsOptions, StorageOptions, StorageS3Options, storage as default, storagePlugin };
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/types.ts","../../src/plugin.ts","../../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;KAMY,gBAAA;;gBAEI;AAFhB,CAAA,GAGI,OAHQ,CAGA,gBAHgB,CAAA;AAAA,KAKhB,mBAAA,GALgB;EAAA,OAEZ,EAAA,OAAA;EAAoB,WACxB,CAAA,EAII,mBAJJ,CAAA,aAAA,CAAA,GAAA,MAAA,EAAA,GAAA,MAAA;CAAgB,GAKxB,IALA,CAKK,OALL,CAKa,mBALb,CAAA,EAAA,aAAA,CAAA;AAAO,KAOC,iBAAA,GAPD;EAEC,OAAA,EAAA,KAAA;EAAmB,WAAA,CAAA,EAOf,iBAPe,CAAA,aAAA,CAAA,GAAA,MAAA,EAAA,GAAA,MAAA;CAAA,GAQ3B,OANY,CAMJ,iBANI,CAAA;AACC,KAOL,gBAAA,GAPK;EAAmB,OAA3B,EAAA,IAAA;EAAO,WAAZ,CAAA,EASY,gBATZ,CAAA,aAAA,CAAA,GAAA,MAAA,EAAA,GAAA,MAAA;AAAI,CAAA,GAUJ,OAVI,CAUI,gBAVJ,CAAA;AAEI,KAUA,cAAA,GAAiB,gBAVA,GAUmB,mBAVnB,GAUyC,iBAVzC,GAU6D,gBAV7D;;;;cCNhB,mBAAoB;;MAAyC;;;;cCN7D,yBAAuB,cAAA;;MAAV,QAAA,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './types';
2
+ import { storage } from './plugin';
3
+ export const storagePlugin = storage;
4
+ export default storage;
5
+
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './types';\r\n\r\nimport { storage } from './plugin';\r\n\r\nexport const storagePlugin = storage;\r\n\r\nexport default storage;\r\n"],"names":["storage","storagePlugin"],"mappings":"AAAA,cAAc,UAAU;AAExB,SAASA,OAAO,QAAQ,WAAW;AAEnC,OAAO,MAAMC,gBAAgBD,QAAQ;AAErC,eAAeA,QAAQ"}
package/dist/plugin.js ADDED
@@ -0,0 +1,155 @@
1
+ import { cloudStoragePlugin } from '@payloadcms/plugin-cloud-storage';
2
+ import { azureStorage } from '@payloadcms/storage-azure';
3
+ import { gcsStorage } from '@payloadcms/storage-gcs';
4
+ import { s3Storage } from '@payloadcms/storage-s3';
5
+ import { fsStorageAdapter } from '@websolutespa/payload-plugin-cloud-storage-fs';
6
+ import payload from 'payload';
7
+ export const storage = (options)=>async (sourceConfig)=>{
8
+ if (options.enabled === false) {
9
+ return sourceConfig;
10
+ }
11
+ options.adapter = options.adapter || 'fs';
12
+ const targetConfig = {
13
+ ...sourceConfig,
14
+ admin: {
15
+ ...sourceConfig.admin,
16
+ dependencies: {
17
+ ...sourceConfig.admin?.dependencies,
18
+ azureComponent: {
19
+ path: '@payloadcms/storage-azure/client#AzureClientUploadHandler',
20
+ type: 'function'
21
+ },
22
+ cgsComponent: {
23
+ path: '@payloadcms/storage-gcs/client#GcsClientUploadHandler',
24
+ type: 'function'
25
+ },
26
+ s3Component: {
27
+ path: '@payloadcms/storage-s3/client#S3ClientUploadHandler',
28
+ type: 'function'
29
+ }
30
+ }
31
+ },
32
+ onInit: async (payload)=>{
33
+ if (typeof sourceConfig.onInit === 'function') {
34
+ await sourceConfig.onInit(payload);
35
+ }
36
+ console.log('@websolutespa/payload-plugin-localization.onInit');
37
+ }
38
+ };
39
+ const storage = getStoragePlugin(options);
40
+ return await storage(targetConfig);
41
+ };
42
+ function getStoragePlugin(options) {
43
+ switch(options.adapter){
44
+ case 'azure':
45
+ {
46
+ const collections = getCollections(options.collections);
47
+ const connectionString = getEnv('AZURE_STORAGE_CONNECTION_STRING');
48
+ const containerName = getEnv('AZURE_STORAGE_CONTAINER_NAME');
49
+ const allowContainerCreate = getEnvBool('AZURE_STORAGE_ALLOW_CONTAINER_CREATE');
50
+ const baseURL = getEnv('AZURE_STORAGE_ACCOUNT_BASEURL');
51
+ return azureStorage({
52
+ connectionString,
53
+ containerName,
54
+ allowContainerCreate,
55
+ baseURL,
56
+ collections
57
+ });
58
+ }
59
+ case 's3':
60
+ {
61
+ const collections = getCollections(options.collections);
62
+ const bucket = getEnv('S3_STORAGE_BUCKET');
63
+ const region = getEnv('S3_STORAGE_REGION');
64
+ const accessKeyId = getEnv('S3_STORAGE_ACCESS_KEY_ID');
65
+ const secretAccessKey = getEnv('S3_STORAGE_SECRET_ACCESS_KEY');
66
+ const endpoint = getEnv('S3_STORAGE_ENDPOINT') || undefined;
67
+ return s3Storage({
68
+ bucket,
69
+ config: {
70
+ region,
71
+ credentials: {
72
+ accessKeyId,
73
+ secretAccessKey
74
+ },
75
+ endpoint
76
+ },
77
+ collections
78
+ });
79
+ }
80
+ case 'gcs':
81
+ {
82
+ const collections = getCollections(options.collections);
83
+ const bucket = getEnv('GCS_STORAGE_BUCKET');
84
+ const credentials = getEnvJson('GCS_STORAGE_JSON_CREDENTIALS') || undefined;
85
+ return gcsStorage({
86
+ bucket,
87
+ options: {
88
+ credentials
89
+ },
90
+ collections
91
+ });
92
+ }
93
+ default:
94
+ {
95
+ const keys = options.collections || [
96
+ 'media'
97
+ ];
98
+ const baseDir = getEnv('FS_STORAGE_BASEDIR');
99
+ const baseURL = getEnv('FS_STORAGE_BASEURL');
100
+ const disablePayloadAccessControl = getEnvBool('FS_STORAGE_DISABLE_PAYLOAD_ACCESS_CONTROL') || undefined;
101
+ const generateFileURLEnabled = getEnvBool('FS_STORAGE_ENABLE_GENERATE_FILE_URL');
102
+ const baseUrl = getEnv('FS_STORAGE_BASEURL');
103
+ const collections = Object.fromEntries(keys.map((k)=>[
104
+ k,
105
+ {
106
+ adapter: fsStorageAdapter({
107
+ baseDir,
108
+ baseURL
109
+ }),
110
+ disablePayloadAccessControl,
111
+ generateFileURL: generateFileURLEnabled ? ({ filename })=>`${baseUrl}/${filename}` : undefined
112
+ }
113
+ ]));
114
+ return cloudStoragePlugin({
115
+ collections
116
+ });
117
+ }
118
+ }
119
+ }
120
+ function getCollections(options) {
121
+ if (!options) {
122
+ return {
123
+ media: true
124
+ };
125
+ }
126
+ if (typeof options === 'string') {
127
+ return {
128
+ [options]: true
129
+ };
130
+ }
131
+ if (Array.isArray(options)) {
132
+ return Object.fromEntries(options.map((k)=>[
133
+ k,
134
+ true
135
+ ]));
136
+ }
137
+ return options;
138
+ }
139
+ function getEnv(key) {
140
+ const value = (process.env[key] || '').trim();
141
+ if (!value) {
142
+ const logger = payload.logger || console;
143
+ logger.error(`[Storage] missing env var [${key}]`);
144
+ }
145
+ return value;
146
+ }
147
+ function getEnvBool(key) {
148
+ return (process.env[key] || '').trim() === 'true';
149
+ }
150
+ function getEnvJson(key) {
151
+ const value = getEnv(key);
152
+ return JSON.parse(value);
153
+ }
154
+
155
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import { cloudStoragePlugin } from '@payloadcms/plugin-cloud-storage';\r\nimport type { CollectionOptions } from '@payloadcms/plugin-cloud-storage/types';\r\nimport { azureStorage } from '@payloadcms/storage-azure';\r\nimport { gcsStorage } from '@payloadcms/storage-gcs';\r\nimport { s3Storage } from '@payloadcms/storage-s3';\r\nimport { fsStorageAdapter } from '@websolutespa/payload-plugin-cloud-storage-fs';\r\nimport type { CollectionConfig, Config, Plugin, UploadCollectionSlug } from 'payload';\r\nimport payload, { ImageSize, Payload } from 'payload';\r\nimport { StorageOptions } from './types';\r\n\r\nexport const storage = (options: StorageOptions & { enabled?: boolean }): Plugin => async (sourceConfig: Config): Promise<Config> => {\r\n if (options.enabled === false) {\r\n return sourceConfig;\r\n }\r\n options.adapter = options.adapter || 'fs';\r\n const targetConfig: Config = {\r\n ...sourceConfig,\r\n admin: {\r\n ...sourceConfig.admin,\r\n dependencies: {\r\n ...sourceConfig.admin?.dependencies,\r\n azureComponent: {\r\n path: '@payloadcms/storage-azure/client#AzureClientUploadHandler',\r\n type: 'function',\r\n },\r\n cgsComponent: {\r\n path: '@payloadcms/storage-gcs/client#GcsClientUploadHandler',\r\n type: 'function',\r\n },\r\n s3Component: {\r\n path: '@payloadcms/storage-s3/client#S3ClientUploadHandler',\r\n type: 'function',\r\n },\r\n },\r\n },\r\n onInit: async (payload: Payload) => {\r\n if (typeof sourceConfig.onInit === 'function') {\r\n await sourceConfig.onInit(payload);\r\n }\r\n console.log('@websolutespa/payload-plugin-localization.onInit');\r\n },\r\n };\r\n const storage = getStoragePlugin(options);\r\n return await storage(targetConfig);\r\n};\r\n\r\nfunction getStoragePlugin(options: StorageOptions) {\r\n\r\n switch (options.adapter) {\r\n case 'azure': {\r\n const collections = getCollections(options.collections);\r\n const connectionString = getEnv('AZURE_STORAGE_CONNECTION_STRING');\r\n const containerName = getEnv('AZURE_STORAGE_CONTAINER_NAME');\r\n const allowContainerCreate = getEnvBool('AZURE_STORAGE_ALLOW_CONTAINER_CREATE');\r\n const baseURL = getEnv('AZURE_STORAGE_ACCOUNT_BASEURL');\r\n\r\n return azureStorage({\r\n connectionString,\r\n containerName,\r\n allowContainerCreate,\r\n baseURL,\r\n collections,\r\n });\r\n }\r\n case 's3': {\r\n const collections = getCollections(options.collections);\r\n const bucket = getEnv('S3_STORAGE_BUCKET');\r\n const region = getEnv('S3_STORAGE_REGION');\r\n const accessKeyId = getEnv('S3_STORAGE_ACCESS_KEY_ID');\r\n const secretAccessKey = getEnv('S3_STORAGE_SECRET_ACCESS_KEY');\r\n const endpoint = getEnv('S3_STORAGE_ENDPOINT') || undefined;\r\n\r\n return s3Storage({\r\n bucket,\r\n config: {\r\n region,\r\n credentials: {\r\n accessKeyId,\r\n secretAccessKey,\r\n },\r\n endpoint,\r\n },\r\n collections,\r\n });\r\n }\r\n case 'gcs': {\r\n const collections = getCollections(options.collections);\r\n const bucket = getEnv('GCS_STORAGE_BUCKET');\r\n const credentials = getEnvJson('GCS_STORAGE_JSON_CREDENTIALS') || undefined;\r\n\r\n return gcsStorage({\r\n bucket,\r\n options: {\r\n credentials,\r\n },\r\n collections,\r\n });\r\n }\r\n default: {\r\n const keys = options.collections || ['media'];\r\n const baseDir = getEnv('FS_STORAGE_BASEDIR');\r\n const baseURL = getEnv('FS_STORAGE_BASEURL');\r\n const disablePayloadAccessControl = getEnvBool('FS_STORAGE_DISABLE_PAYLOAD_ACCESS_CONTROL') || undefined;\r\n const generateFileURLEnabled = getEnvBool('FS_STORAGE_ENABLE_GENERATE_FILE_URL');\r\n const baseUrl = getEnv('FS_STORAGE_BASEURL');\r\n\r\n const collections: Record<string, CollectionOptions> = Object.fromEntries(\r\n keys.map(k => [k, {\r\n adapter: fsStorageAdapter({\r\n baseDir,\r\n baseURL,\r\n }),\r\n disablePayloadAccessControl,\r\n generateFileURL: generateFileURLEnabled ? ({\r\n filename,\r\n }: {\r\n collection: CollectionConfig;\r\n filename: string;\r\n prefix?: string;\r\n size?: ImageSize;\r\n }) => `${baseUrl}/${filename}` : undefined,\r\n }]\r\n )\r\n );\r\n\r\n return cloudStoragePlugin({\r\n collections,\r\n });\r\n }\r\n }\r\n}\r\n\r\nfunction getCollections(options: StorageOptions['collections']): Partial<Record<UploadCollectionSlug, Omit<CollectionOptions, 'adapter'> | true>> {\r\n if (!options) {\r\n return {\r\n media: true,\r\n };\r\n }\r\n if (typeof options === 'string') {\r\n return {\r\n [options]: true,\r\n };\r\n }\r\n if (Array.isArray(options)) {\r\n return Object.fromEntries(options.map(k => [k, true]));\r\n }\r\n return options;\r\n}\r\n\r\nfunction getEnv(key: string) {\r\n const value = (process.env[key] || '').trim();\r\n if (!value) {\r\n const logger = payload.logger || console;\r\n logger.error(`[Storage] missing env var [${key}]`);\r\n }\r\n return value;\r\n}\r\n\r\nfunction getEnvBool(key: string) {\r\n return (process.env[key] || '').trim() === 'true';\r\n}\r\n\r\nfunction getEnvJson(key: string) {\r\n const value = getEnv(key);\r\n return JSON.parse(value);\r\n}\r\n"],"names":["cloudStoragePlugin","azureStorage","gcsStorage","s3Storage","fsStorageAdapter","payload","storage","options","sourceConfig","enabled","adapter","targetConfig","admin","dependencies","azureComponent","path","type","cgsComponent","s3Component","onInit","console","log","getStoragePlugin","collections","getCollections","connectionString","getEnv","containerName","allowContainerCreate","getEnvBool","baseURL","bucket","region","accessKeyId","secretAccessKey","endpoint","undefined","config","credentials","getEnvJson","keys","baseDir","disablePayloadAccessControl","generateFileURLEnabled","baseUrl","Object","fromEntries","map","k","generateFileURL","filename","media","Array","isArray","key","value","process","env","trim","logger","error","JSON","parse"],"mappings":"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"}