@payloadcms/payload-cloud 3.0.0-alpha.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/LICENSE.md +22 -0
- package/README.md +93 -0
- package/dist/email.d.ts +6 -0
- package/dist/email.d.ts.map +1 -0
- package/dist/email.js +48 -0
- package/dist/email.js.map +1 -0
- package/dist/email.spec.d.ts +2 -0
- package/dist/email.spec.d.ts.map +1 -0
- package/dist/hooks/afterDelete.d.ts +8 -0
- package/dist/hooks/afterDelete.d.ts.map +1 -0
- package/dist/hooks/afterDelete.js +30 -0
- package/dist/hooks/afterDelete.js.map +1 -0
- package/dist/hooks/beforeChange.d.ts +7 -0
- package/dist/hooks/beforeChange.d.ts.map +1 -0
- package/dist/hooks/beforeChange.js +73 -0
- package/dist/hooks/beforeChange.js.map +1 -0
- package/dist/hooks/uploadCache.d.ts +8 -0
- package/dist/hooks/uploadCache.d.ts.map +1 -0
- package/dist/hooks/uploadCache.js +87 -0
- package/dist/hooks/uploadCache.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +88 -0
- package/dist/plugin.js.map +1 -0
- package/dist/plugin.spec.d.ts +2 -0
- package/dist/plugin.spec.d.ts.map +1 -0
- package/dist/staticHandler.d.ts +9 -0
- package/dist/staticHandler.d.ts.map +1 -0
- package/dist/staticHandler.js +65 -0
- package/dist/staticHandler.js.map +1 -0
- package/dist/types.d.ts +103 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utilities/authAsCognitoUser.d.ts +3 -0
- package/dist/utilities/authAsCognitoUser.d.ts.map +1 -0
- package/dist/utilities/authAsCognitoUser.js +34 -0
- package/dist/utilities/authAsCognitoUser.js.map +1 -0
- package/dist/utilities/createKey.d.ts +8 -0
- package/dist/utilities/createKey.d.ts.map +1 -0
- package/dist/utilities/createKey.js +3 -0
- package/dist/utilities/createKey.js.map +1 -0
- package/dist/utilities/getIncomingFiles.d.ts +7 -0
- package/dist/utilities/getIncomingFiles.d.ts.map +1 -0
- package/dist/utilities/getIncomingFiles.js +33 -0
- package/dist/utilities/getIncomingFiles.js.map +1 -0
- package/dist/utilities/getStorageClient.d.ts +7 -0
- package/dist/utilities/getStorageClient.d.ts.map +1 -0
- package/dist/utilities/getStorageClient.js +40 -0
- package/dist/utilities/getStorageClient.js.map +1 -0
- package/package.json +53 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
(The MIT License)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018-2022 Payload CMS, LLC <info@payloadcms.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
'Software'), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Payload Cloud Plugin
|
|
2
|
+
|
|
3
|
+
This is the official Payload Cloud plugin that connects your Payload instance to the resources that Payload Cloud provides.
|
|
4
|
+
|
|
5
|
+
## File storage
|
|
6
|
+
|
|
7
|
+
Payload Cloud gives you S3 file storage backed by Cloudflare as a CDN, and this plugin extends Payload so that all of your media will be stored in S3 rather than locally.
|
|
8
|
+
|
|
9
|
+
## Email delivery
|
|
10
|
+
|
|
11
|
+
Payload Cloud provides an email delivery service out-of-the-box for all Payload Cloud customers. Powered by [Resend](https://resend.com).
|
|
12
|
+
|
|
13
|
+
## Upload caching
|
|
14
|
+
|
|
15
|
+
Payload Cloud provides a caching for all upload collections by default through Cloudflare's CDN.
|
|
16
|
+
|
|
17
|
+
## How to use
|
|
18
|
+
|
|
19
|
+
Add the plugin to your Payload config
|
|
20
|
+
|
|
21
|
+
`yarn add @payloadcms/payload-cloud`
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { payloadCloud } from '@payloadcms/payload-cloud'
|
|
25
|
+
import { buildConfig } from 'payload'
|
|
26
|
+
|
|
27
|
+
export default buildConfig({
|
|
28
|
+
plugins: [payloadCloud()],
|
|
29
|
+
// rest of config
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
NOTE: If your Payload config already has an email with transport, this will take precedence over Payload Cloud's email service.
|
|
34
|
+
|
|
35
|
+
### From Domain
|
|
36
|
+
|
|
37
|
+
After configuring, ensure that the `from` email address is from a domain you have access to. Payload Cloud will automatically give you permissions to use your deployed domain with the value available in `process.env.PAYLOAD_CLOUD_DEFAULT_DOMAIN`. If you have custom domains, your custom domains will also be whitelisted. Attempting to send from a domain you do not have access to will not succeed.
|
|
38
|
+
|
|
39
|
+
### Optional configuration
|
|
40
|
+
|
|
41
|
+
If you wish to opt-out of any Payload cloud features, the plugin also accepts options to do so.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
payloadCloud({
|
|
45
|
+
storage: false, // Disable file storage
|
|
46
|
+
email: false, // Disable email delivery
|
|
47
|
+
uploadCaching: false, // Disable upload caching
|
|
48
|
+
})
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
#### Upload Caching Configuration
|
|
52
|
+
|
|
53
|
+
If you wish to configure upload caching on a per-collection basis, you can do so by passing in a keyed object of collection names. By default, all collections will be cached for 24 hours (86400 seconds). The cache is invalidated when an item is updated or deleted.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
payloadCloud({
|
|
57
|
+
uploadCaching: {
|
|
58
|
+
maxAge: 604800, // Override default maxAge for all collections
|
|
59
|
+
collection1Slug: {
|
|
60
|
+
maxAge: 10, // Collection-specific maxAge, takes precedence over others
|
|
61
|
+
},
|
|
62
|
+
collection2Slug: {
|
|
63
|
+
enabled: false, // Disable caching for this collection
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Accessing File Storage from Local Environment
|
|
70
|
+
|
|
71
|
+
This plugin works off of a specific set of environment variables in order to access your file resources. The following values must be set in your local environment in order to access your file resources:
|
|
72
|
+
|
|
73
|
+
```txt
|
|
74
|
+
PAYLOAD_CLOUD=true
|
|
75
|
+
PAYLOAD_CLOUD_ENVIRONMENT=prod
|
|
76
|
+
PAYLOAD_CLOUD_COGNITO_USER_POOL_CLIENT_ID=
|
|
77
|
+
PAYLOAD_CLOUD_COGNITO_USER_POOL_ID=
|
|
78
|
+
PAYLOAD_CLOUD_COGNITO_IDENTITY_POOL_ID=
|
|
79
|
+
PAYLOAD_CLOUD_PROJECT_ID=
|
|
80
|
+
PAYLOAD_CLOUD_BUCKET=
|
|
81
|
+
PAYLOAD_CLOUD_BUCKET_REGION=
|
|
82
|
+
PAYLOAD_CLOUD_COGNITO_PASSWORD=
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Future enhancements
|
|
86
|
+
|
|
87
|
+
### API CDN
|
|
88
|
+
|
|
89
|
+
In the future, this plugin will also ship with a way to dynamically cache API requests as well as purge them whenever a resource is updated.
|
|
90
|
+
|
|
91
|
+
## When it executes
|
|
92
|
+
|
|
93
|
+
This plugin will only execute if the required environment variables set by Payload Cloud are in place. If they are not, the plugin will not execute and your Payload instance will behave as normal.
|
package/dist/email.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { nodemailerAdapter } from '@payloadcms/email-nodemailer';
|
|
2
|
+
import type { PayloadCloudEmailOptions } from './types.js';
|
|
3
|
+
type NodemailerAdapter = ReturnType<typeof nodemailerAdapter>;
|
|
4
|
+
export declare const payloadCloudEmail: (args: PayloadCloudEmailOptions) => Promise<NodemailerAdapter> | undefined;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=email.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../src/email.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAGhE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAE1D,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAE7D,eAAO,MAAM,iBAAiB,SACtB,wBAAwB,KAC7B,OAAO,CAAC,iBAAiB,CAAC,GAAG,SAyD/B,CAAA"}
|
package/dist/email.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { nodemailerAdapter } from '@payloadcms/email-nodemailer';
|
|
2
|
+
import nodemailer from 'nodemailer';
|
|
3
|
+
export const payloadCloudEmail = async (args)=>{
|
|
4
|
+
if (process.env.PAYLOAD_CLOUD !== 'true' || !args) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
if (!args.apiKey) {
|
|
8
|
+
throw new Error('apiKey must be provided to use Payload Cloud Email');
|
|
9
|
+
}
|
|
10
|
+
if (!args.defaultDomain) {
|
|
11
|
+
throw new Error('defaultDomain must be provided to use Payload Cloud Email');
|
|
12
|
+
}
|
|
13
|
+
// Check if already has email configuration
|
|
14
|
+
if (args.config.email) {
|
|
15
|
+
// eslint-disable-next-line no-console
|
|
16
|
+
console.log('Payload Cloud Email is enabled but email configuration is already provided in Payload config. If this is intentional, set `email: false` in the Payload Cloud plugin options.');
|
|
17
|
+
return args.config.email;
|
|
18
|
+
}
|
|
19
|
+
const { apiKey, defaultDomain, skipVerify } = args;
|
|
20
|
+
const customDomainEnvs = Object.keys(process.env).filter((e)=>e.startsWith('PAYLOAD_CLOUD_EMAIL_DOMAIN_') && !e.endsWith('API_KEY'));
|
|
21
|
+
const customDomains = customDomainEnvs.map((e)=>process.env[e]).filter(Boolean);
|
|
22
|
+
if (customDomains.length) {
|
|
23
|
+
// eslint-disable-next-line no-console
|
|
24
|
+
console.log(`Configuring Payload Cloud Email for ${[
|
|
25
|
+
defaultDomain,
|
|
26
|
+
...customDomains || []
|
|
27
|
+
].join(', ')}`);
|
|
28
|
+
}
|
|
29
|
+
const defaultFromName = args.defaultFromName || 'Payload CMS';
|
|
30
|
+
const defaultFromAddress = args.defaultFromAddress || `cms@${customDomains.length ? customDomains[0] : defaultDomain}`;
|
|
31
|
+
const emailAdapter = await nodemailerAdapter({
|
|
32
|
+
defaultFromAddress,
|
|
33
|
+
defaultFromName,
|
|
34
|
+
skipVerify,
|
|
35
|
+
transport: nodemailer.createTransport({
|
|
36
|
+
auth: {
|
|
37
|
+
pass: apiKey,
|
|
38
|
+
user: 'resend'
|
|
39
|
+
},
|
|
40
|
+
host: 'smtp.resend.com',
|
|
41
|
+
port: 465,
|
|
42
|
+
secure: true
|
|
43
|
+
})
|
|
44
|
+
});
|
|
45
|
+
return emailAdapter;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=email.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/email.ts"],"sourcesContent":["import { nodemailerAdapter } from '@payloadcms/email-nodemailer'\nimport nodemailer from 'nodemailer'\n\nimport type { PayloadCloudEmailOptions } from './types.js'\n\ntype NodemailerAdapter = ReturnType<typeof nodemailerAdapter>\n\nexport const payloadCloudEmail = async (\n args: PayloadCloudEmailOptions,\n): Promise<NodemailerAdapter> | undefined => {\n if (process.env.PAYLOAD_CLOUD !== 'true' || !args) {\n return undefined\n }\n\n if (!args.apiKey) {\n throw new Error('apiKey must be provided to use Payload Cloud Email')\n }\n if (!args.defaultDomain) {\n throw new Error('defaultDomain must be provided to use Payload Cloud Email')\n }\n\n // Check if already has email configuration\n\n if (args.config.email) {\n // eslint-disable-next-line no-console\n console.log(\n 'Payload Cloud Email is enabled but email configuration is already provided in Payload config. If this is intentional, set `email: false` in the Payload Cloud plugin options.',\n )\n return args.config.email\n }\n\n const { apiKey, defaultDomain, skipVerify } = args\n\n const customDomainEnvs = Object.keys(process.env).filter(\n (e) => e.startsWith('PAYLOAD_CLOUD_EMAIL_DOMAIN_') && !e.endsWith('API_KEY'),\n )\n\n const customDomains = customDomainEnvs.map((e) => process.env[e]).filter(Boolean)\n\n if (customDomains.length) {\n // eslint-disable-next-line no-console\n console.log(\n `Configuring Payload Cloud Email for ${[defaultDomain, ...(customDomains || [])].join(', ')}`,\n )\n }\n\n const defaultFromName = args.defaultFromName || 'Payload CMS'\n const defaultFromAddress =\n args.defaultFromAddress || `cms@${customDomains.length ? customDomains[0] : defaultDomain}`\n\n const emailAdapter = await nodemailerAdapter({\n defaultFromAddress,\n defaultFromName,\n skipVerify,\n transport: nodemailer.createTransport({\n auth: {\n pass: apiKey,\n user: 'resend',\n },\n host: 'smtp.resend.com',\n port: 465,\n secure: true,\n }),\n })\n\n return emailAdapter\n}\n"],"names":["nodemailerAdapter","nodemailer","payloadCloudEmail","args","process","env","PAYLOAD_CLOUD","undefined","apiKey","Error","defaultDomain","config","email","console","log","skipVerify","customDomainEnvs","Object","keys","filter","e","startsWith","endsWith","customDomains","map","Boolean","length","join","defaultFromName","defaultFromAddress","emailAdapter","transport","createTransport","auth","pass","user","host","port","secure"],"mappings":"AAAA,SAASA,iBAAiB,QAAQ,+BAA8B;AAChE,OAAOC,gBAAgB,aAAY;AAMnC,OAAO,MAAMC,oBAAoB,OAC/BC;IAEA,IAAIC,QAAQC,GAAG,CAACC,aAAa,KAAK,UAAU,CAACH,MAAM;QACjD,OAAOI;IACT;IAEA,IAAI,CAACJ,KAAKK,MAAM,EAAE;QAChB,MAAM,IAAIC,MAAM;IAClB;IACA,IAAI,CAACN,KAAKO,aAAa,EAAE;QACvB,MAAM,IAAID,MAAM;IAClB;IAEA,2CAA2C;IAE3C,IAAIN,KAAKQ,MAAM,CAACC,KAAK,EAAE;QACrB,sCAAsC;QACtCC,QAAQC,GAAG,CACT;QAEF,OAAOX,KAAKQ,MAAM,CAACC,KAAK;IAC1B;IAEA,MAAM,EAAEJ,MAAM,EAAEE,aAAa,EAAEK,UAAU,EAAE,GAAGZ;IAE9C,MAAMa,mBAAmBC,OAAOC,IAAI,CAACd,QAAQC,GAAG,EAAEc,MAAM,CACtD,CAACC,IAAMA,EAAEC,UAAU,CAAC,kCAAkC,CAACD,EAAEE,QAAQ,CAAC;IAGpE,MAAMC,gBAAgBP,iBAAiBQ,GAAG,CAAC,CAACJ,IAAMhB,QAAQC,GAAG,CAACe,EAAE,EAAED,MAAM,CAACM;IAEzE,IAAIF,cAAcG,MAAM,EAAE;QACxB,sCAAsC;QACtCb,QAAQC,GAAG,CACT,CAAC,oCAAoC,EAAE;YAACJ;eAAmBa,iBAAiB,EAAE;SAAE,CAACI,IAAI,CAAC,MAAM,CAAC;IAEjG;IAEA,MAAMC,kBAAkBzB,KAAKyB,eAAe,IAAI;IAChD,MAAMC,qBACJ1B,KAAK0B,kBAAkB,IAAI,CAAC,IAAI,EAAEN,cAAcG,MAAM,GAAGH,aAAa,CAAC,EAAE,GAAGb,cAAc,CAAC;IAE7F,MAAMoB,eAAe,MAAM9B,kBAAkB;QAC3C6B;QACAD;QACAb;QACAgB,WAAW9B,WAAW+B,eAAe,CAAC;YACpCC,MAAM;gBACJC,MAAM1B;gBACN2B,MAAM;YACR;YACAC,MAAM;YACNC,MAAM;YACNC,QAAQ;QACV;IACF;IAEA,OAAOR;AACT,EAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email.spec.d.ts","sourceRoot":"","sources":["../src/email.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CollectionAfterDeleteHook, CollectionConfig, FileData, TypeWithID } from 'payload';
|
|
2
|
+
import type { TypeWithPrefix } from '../types.js';
|
|
3
|
+
interface Args {
|
|
4
|
+
collection: CollectionConfig;
|
|
5
|
+
}
|
|
6
|
+
export declare const getAfterDeleteHook: ({ collection, }: Args) => CollectionAfterDeleteHook<FileData & TypeWithID & TypeWithPrefix>;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=afterDelete.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"afterDelete.d.ts","sourceRoot":"","sources":["../../src/hooks/afterDelete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEhG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAKjD,UAAU,IAAI;IACZ,UAAU,EAAE,gBAAgB,CAAA;CAC7B;AAED,eAAO,MAAM,kBAAkB,oBAE5B,IAAI,KAAG,yBAAyB,CAAC,QAAQ,GAAG,UAAU,GAAG,cAAc,CA0BzE,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createKey } from '../utilities/createKey.js';
|
|
2
|
+
import { getStorageClient } from '../utilities/getStorageClient.js';
|
|
3
|
+
export const getAfterDeleteHook = ({ collection })=>{
|
|
4
|
+
return async ({ doc, req })=>{
|
|
5
|
+
try {
|
|
6
|
+
const { identityID, storageClient } = await getStorageClient();
|
|
7
|
+
const filesToDelete = [
|
|
8
|
+
doc.filename,
|
|
9
|
+
...Object.values(doc?.sizes || []).map((resizedFileData)=>resizedFileData?.filename)
|
|
10
|
+
];
|
|
11
|
+
const promises = filesToDelete.map(async (filename)=>{
|
|
12
|
+
await storageClient.deleteObject({
|
|
13
|
+
Bucket: process.env.PAYLOAD_CLOUD_BUCKET,
|
|
14
|
+
Key: createKey({
|
|
15
|
+
collection: collection.slug,
|
|
16
|
+
filename,
|
|
17
|
+
identityID
|
|
18
|
+
})
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
await Promise.all(promises);
|
|
22
|
+
} catch (err) {
|
|
23
|
+
req.payload.logger.error(`There was an error while deleting files corresponding to the ${collection.labels?.singular} with ID ${doc.id}:`);
|
|
24
|
+
req.payload.logger.error(err);
|
|
25
|
+
}
|
|
26
|
+
return doc;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=afterDelete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/afterDelete.ts"],"sourcesContent":["import type { CollectionAfterDeleteHook, CollectionConfig, FileData, TypeWithID } from 'payload'\n\nimport type { TypeWithPrefix } from '../types.js'\n\nimport { createKey } from '../utilities/createKey.js'\nimport { getStorageClient } from '../utilities/getStorageClient.js'\n\ninterface Args {\n collection: CollectionConfig\n}\n\nexport const getAfterDeleteHook = ({\n collection,\n}: Args): CollectionAfterDeleteHook<FileData & TypeWithID & TypeWithPrefix> => {\n return async ({ doc, req }) => {\n try {\n const { identityID, storageClient } = await getStorageClient()\n\n const filesToDelete: string[] = [\n doc.filename,\n ...Object.values(doc?.sizes || []).map((resizedFileData) => resizedFileData?.filename),\n ]\n\n const promises = filesToDelete.map(async (filename) => {\n await storageClient.deleteObject({\n Bucket: process.env.PAYLOAD_CLOUD_BUCKET,\n Key: createKey({ collection: collection.slug, filename, identityID }),\n })\n })\n\n await Promise.all(promises)\n } catch (err: unknown) {\n req.payload.logger.error(\n `There was an error while deleting files corresponding to the ${collection.labels?.singular} with ID ${doc.id}:`,\n )\n req.payload.logger.error(err)\n }\n return doc\n }\n}\n"],"names":["createKey","getStorageClient","getAfterDeleteHook","collection","doc","req","identityID","storageClient","filesToDelete","filename","Object","values","sizes","map","resizedFileData","promises","deleteObject","Bucket","process","env","PAYLOAD_CLOUD_BUCKET","Key","slug","Promise","all","err","payload","logger","error","labels","singular","id"],"mappings":"AAIA,SAASA,SAAS,QAAQ,4BAA2B;AACrD,SAASC,gBAAgB,QAAQ,mCAAkC;AAMnE,OAAO,MAAMC,qBAAqB,CAAC,EACjCC,UAAU,EACL;IACL,OAAO,OAAO,EAAEC,GAAG,EAAEC,GAAG,EAAE;QACxB,IAAI;YACF,MAAM,EAAEC,UAAU,EAAEC,aAAa,EAAE,GAAG,MAAMN;YAE5C,MAAMO,gBAA0B;gBAC9BJ,IAAIK,QAAQ;mBACTC,OAAOC,MAAM,CAACP,KAAKQ,SAAS,EAAE,EAAEC,GAAG,CAAC,CAACC,kBAAoBA,iBAAiBL;aAC9E;YAED,MAAMM,WAAWP,cAAcK,GAAG,CAAC,OAAOJ;gBACxC,MAAMF,cAAcS,YAAY,CAAC;oBAC/BC,QAAQC,QAAQC,GAAG,CAACC,oBAAoB;oBACxCC,KAAKrB,UAAU;wBAAEG,YAAYA,WAAWmB,IAAI;wBAAEb;wBAAUH;oBAAW;gBACrE;YACF;YAEA,MAAMiB,QAAQC,GAAG,CAACT;QACpB,EAAE,OAAOU,KAAc;YACrBpB,IAAIqB,OAAO,CAACC,MAAM,CAACC,KAAK,CACtB,CAAC,6DAA6D,EAAEzB,WAAW0B,MAAM,EAAEC,SAAS,SAAS,EAAE1B,IAAI2B,EAAE,CAAC,CAAC,CAAC;YAElH1B,IAAIqB,OAAO,CAACC,MAAM,CAACC,KAAK,CAACH;QAC3B;QACA,OAAOrB;IACT;AACF,EAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CollectionBeforeChangeHook, CollectionConfig, FileData, TypeWithID } from 'payload';
|
|
2
|
+
interface Args {
|
|
3
|
+
collection: CollectionConfig;
|
|
4
|
+
}
|
|
5
|
+
export declare const getBeforeChangeHook: ({ collection }: Args) => CollectionBeforeChangeHook<FileData & TypeWithID>;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=beforeChange.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beforeChange.d.ts","sourceRoot":"","sources":["../../src/hooks/beforeChange.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAUjG,UAAU,IAAI;IACZ,UAAU,EAAE,gBAAgB,CAAA;CAC7B;AAID,eAAO,MAAM,mBAAmB,mBACb,IAAI,KAAG,0BAA0B,CAAC,QAAQ,GAAG,UAAU,CAuEvE,CAAA"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Upload } from '@aws-sdk/lib-storage';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { createKey } from '../utilities/createKey.js';
|
|
4
|
+
import { getIncomingFiles } from '../utilities/getIncomingFiles.js';
|
|
5
|
+
import { getStorageClient } from '../utilities/getStorageClient.js';
|
|
6
|
+
const MB = 1024 * 1024;
|
|
7
|
+
export const getBeforeChangeHook = ({ collection })=>async ({ data, req })=>{
|
|
8
|
+
try {
|
|
9
|
+
const files = getIncomingFiles({
|
|
10
|
+
data,
|
|
11
|
+
req
|
|
12
|
+
});
|
|
13
|
+
req.payload.logger.debug({
|
|
14
|
+
msg: `Preparing to upload ${files.length} files`
|
|
15
|
+
});
|
|
16
|
+
const { identityID, storageClient } = await getStorageClient();
|
|
17
|
+
const promises = files.map(async (file)=>{
|
|
18
|
+
const fileKey = file.filename;
|
|
19
|
+
req.payload.logger.debug({
|
|
20
|
+
fileKey,
|
|
21
|
+
msg: `File buffer length: ${file.buffer.length / MB}MB`,
|
|
22
|
+
tempFilePath: file.tempFilePath ?? 'undefined'
|
|
23
|
+
});
|
|
24
|
+
const fileBufferOrStream = file.tempFilePath ? fs.createReadStream(file.tempFilePath) : file.buffer;
|
|
25
|
+
if (file.buffer.length > 0) {
|
|
26
|
+
req.payload.logger.debug({
|
|
27
|
+
fileKey,
|
|
28
|
+
msg: `Uploading ${fileKey} from buffer. Size: ${file.buffer.length / MB}MB`
|
|
29
|
+
});
|
|
30
|
+
await storageClient.putObject({
|
|
31
|
+
Body: fileBufferOrStream,
|
|
32
|
+
Bucket: process.env.PAYLOAD_CLOUD_BUCKET,
|
|
33
|
+
ContentType: file.mimeType,
|
|
34
|
+
Key: createKey({
|
|
35
|
+
collection: collection.slug,
|
|
36
|
+
filename: fileKey,
|
|
37
|
+
identityID
|
|
38
|
+
})
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
// This will buffer at max 4 * 5MB = 20MB. Default queueSize is 4 and default partSize is 5MB.
|
|
42
|
+
const parallelUploadS3 = new Upload({
|
|
43
|
+
client: storageClient,
|
|
44
|
+
params: {
|
|
45
|
+
Body: fileBufferOrStream,
|
|
46
|
+
Bucket: process.env.PAYLOAD_CLOUD_BUCKET,
|
|
47
|
+
ContentType: file.mimeType,
|
|
48
|
+
Key: createKey({
|
|
49
|
+
collection: collection.slug,
|
|
50
|
+
filename: fileKey,
|
|
51
|
+
identityID
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
parallelUploadS3.on('httpUploadProgress', (progress)=>{
|
|
56
|
+
if (progress.total) {
|
|
57
|
+
req.payload.logger.debug({
|
|
58
|
+
fileKey,
|
|
59
|
+
msg: `Uploaded part ${progress.part} - ${(progress.loaded || 0) / MB}MB out of ${(progress.total || 0) / MB}MB`
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
await parallelUploadS3.done();
|
|
64
|
+
});
|
|
65
|
+
await Promise.all(promises);
|
|
66
|
+
} catch (err) {
|
|
67
|
+
req.payload.logger.error(`There was an error while uploading files corresponding to the collection ${collection.slug} with filename ${data.filename}:`);
|
|
68
|
+
req.payload.logger.error(err);
|
|
69
|
+
}
|
|
70
|
+
return data;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
//# sourceMappingURL=beforeChange.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/beforeChange.ts"],"sourcesContent":["import type { CollectionBeforeChangeHook, CollectionConfig, FileData, TypeWithID } from 'payload'\nimport type stream from 'stream'\n\nimport { Upload } from '@aws-sdk/lib-storage'\nimport fs from 'fs'\n\nimport { createKey } from '../utilities/createKey.js'\nimport { getIncomingFiles } from '../utilities/getIncomingFiles.js'\nimport { getStorageClient } from '../utilities/getStorageClient.js'\n\ninterface Args {\n collection: CollectionConfig\n}\n\nconst MB = 1024 * 1024\n\nexport const getBeforeChangeHook =\n ({ collection }: Args): CollectionBeforeChangeHook<FileData & TypeWithID> =>\n async ({ data, req }) => {\n try {\n const files = getIncomingFiles({ data, req })\n\n req.payload.logger.debug({\n msg: `Preparing to upload ${files.length} files`,\n })\n\n const { identityID, storageClient } = await getStorageClient()\n\n const promises = files.map(async (file) => {\n const fileKey = file.filename\n\n req.payload.logger.debug({\n fileKey,\n msg: `File buffer length: ${file.buffer.length / MB}MB`,\n tempFilePath: file.tempFilePath ?? 'undefined',\n })\n\n const fileBufferOrStream: Buffer | stream.Readable = file.tempFilePath\n ? fs.createReadStream(file.tempFilePath)\n : file.buffer\n\n if (file.buffer.length > 0) {\n req.payload.logger.debug({\n fileKey,\n msg: `Uploading ${fileKey} from buffer. Size: ${file.buffer.length / MB}MB`,\n })\n\n await storageClient.putObject({\n Body: fileBufferOrStream,\n Bucket: process.env.PAYLOAD_CLOUD_BUCKET,\n ContentType: file.mimeType,\n Key: createKey({ collection: collection.slug, filename: fileKey, identityID }),\n })\n }\n\n // This will buffer at max 4 * 5MB = 20MB. Default queueSize is 4 and default partSize is 5MB.\n const parallelUploadS3 = new Upload({\n client: storageClient,\n params: {\n Body: fileBufferOrStream,\n Bucket: process.env.PAYLOAD_CLOUD_BUCKET,\n ContentType: file.mimeType,\n Key: createKey({ collection: collection.slug, filename: fileKey, identityID }),\n },\n })\n\n parallelUploadS3.on('httpUploadProgress', (progress) => {\n if (progress.total) {\n req.payload.logger.debug({\n fileKey,\n msg: `Uploaded part ${progress.part} - ${(progress.loaded || 0) / MB}MB out of ${\n (progress.total || 0) / MB\n }MB`,\n })\n }\n })\n\n await parallelUploadS3.done()\n })\n\n await Promise.all(promises)\n } catch (err: unknown) {\n req.payload.logger.error(\n `There was an error while uploading files corresponding to the collection ${collection.slug} with filename ${data.filename}:`,\n )\n req.payload.logger.error(err)\n }\n return data\n }\n"],"names":["Upload","fs","createKey","getIncomingFiles","getStorageClient","MB","getBeforeChangeHook","collection","data","req","files","payload","logger","debug","msg","length","identityID","storageClient","promises","map","file","fileKey","filename","buffer","tempFilePath","fileBufferOrStream","createReadStream","putObject","Body","Bucket","process","env","PAYLOAD_CLOUD_BUCKET","ContentType","mimeType","Key","slug","parallelUploadS3","client","params","on","progress","total","part","loaded","done","Promise","all","err","error"],"mappings":"AAGA,SAASA,MAAM,QAAQ,uBAAsB;AAC7C,OAAOC,QAAQ,KAAI;AAEnB,SAASC,SAAS,QAAQ,4BAA2B;AACrD,SAASC,gBAAgB,QAAQ,mCAAkC;AACnE,SAASC,gBAAgB,QAAQ,mCAAkC;AAMnE,MAAMC,KAAK,OAAO;AAElB,OAAO,MAAMC,sBACX,CAAC,EAAEC,UAAU,EAAQ,GACrB,OAAO,EAAEC,IAAI,EAAEC,GAAG,EAAE;QAClB,IAAI;YACF,MAAMC,QAAQP,iBAAiB;gBAAEK;gBAAMC;YAAI;YAE3CA,IAAIE,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;gBACvBC,KAAK,CAAC,oBAAoB,EAAEJ,MAAMK,MAAM,CAAC,MAAM,CAAC;YAClD;YAEA,MAAM,EAAEC,UAAU,EAAEC,aAAa,EAAE,GAAG,MAAMb;YAE5C,MAAMc,WAAWR,MAAMS,GAAG,CAAC,OAAOC;gBAChC,MAAMC,UAAUD,KAAKE,QAAQ;gBAE7Bb,IAAIE,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;oBACvBQ;oBACAP,KAAK,CAAC,oBAAoB,EAAEM,KAAKG,MAAM,CAACR,MAAM,GAAGV,GAAG,EAAE,CAAC;oBACvDmB,cAAcJ,KAAKI,YAAY,IAAI;gBACrC;gBAEA,MAAMC,qBAA+CL,KAAKI,YAAY,GAClEvB,GAAGyB,gBAAgB,CAACN,KAAKI,YAAY,IACrCJ,KAAKG,MAAM;gBAEf,IAAIH,KAAKG,MAAM,CAACR,MAAM,GAAG,GAAG;oBAC1BN,IAAIE,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;wBACvBQ;wBACAP,KAAK,CAAC,UAAU,EAAEO,QAAQ,oBAAoB,EAAED,KAAKG,MAAM,CAACR,MAAM,GAAGV,GAAG,EAAE,CAAC;oBAC7E;oBAEA,MAAMY,cAAcU,SAAS,CAAC;wBAC5BC,MAAMH;wBACNI,QAAQC,QAAQC,GAAG,CAACC,oBAAoB;wBACxCC,aAAab,KAAKc,QAAQ;wBAC1BC,KAAKjC,UAAU;4BAAEK,YAAYA,WAAW6B,IAAI;4BAAEd,UAAUD;4BAASL;wBAAW;oBAC9E;gBACF;gBAEA,8FAA8F;gBAC9F,MAAMqB,mBAAmB,IAAIrC,OAAO;oBAClCsC,QAAQrB;oBACRsB,QAAQ;wBACNX,MAAMH;wBACNI,QAAQC,QAAQC,GAAG,CAACC,oBAAoB;wBACxCC,aAAab,KAAKc,QAAQ;wBAC1BC,KAAKjC,UAAU;4BAAEK,YAAYA,WAAW6B,IAAI;4BAAEd,UAAUD;4BAASL;wBAAW;oBAC9E;gBACF;gBAEAqB,iBAAiBG,EAAE,CAAC,sBAAsB,CAACC;oBACzC,IAAIA,SAASC,KAAK,EAAE;wBAClBjC,IAAIE,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;4BACvBQ;4BACAP,KAAK,CAAC,cAAc,EAAE2B,SAASE,IAAI,CAAC,GAAG,EAAE,AAACF,CAAAA,SAASG,MAAM,IAAI,CAAA,IAAKvC,GAAG,UAAU,EAC7E,AAACoC,CAAAA,SAASC,KAAK,IAAI,CAAA,IAAKrC,GACzB,EAAE,CAAC;wBACN;oBACF;gBACF;gBAEA,MAAMgC,iBAAiBQ,IAAI;YAC7B;YAEA,MAAMC,QAAQC,GAAG,CAAC7B;QACpB,EAAE,OAAO8B,KAAc;YACrBvC,IAAIE,OAAO,CAACC,MAAM,CAACqC,KAAK,CACtB,CAAC,yEAAyE,EAAE1C,WAAW6B,IAAI,CAAC,eAAe,EAAE5B,KAAKc,QAAQ,CAAC,CAAC,CAAC;YAE/Hb,IAAIE,OAAO,CAACC,MAAM,CAACqC,KAAK,CAACD;QAC3B;QACA,OAAOxC;IACT,EAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CollectionAfterChangeHook, CollectionAfterDeleteHook } from 'payload';
|
|
2
|
+
interface Args {
|
|
3
|
+
endpoint: string;
|
|
4
|
+
}
|
|
5
|
+
export declare const getCacheUploadsAfterChangeHook: ({ endpoint }: Args) => CollectionAfterChangeHook;
|
|
6
|
+
export declare const getCacheUploadsAfterDeleteHook: ({ endpoint }: Args) => CollectionAfterDeleteHook;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=uploadCache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploadCache.d.ts","sourceRoot":"","sources":["../../src/hooks/uploadCache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,yBAAyB,EAAkB,MAAM,SAAS,CAAA;AAEnG,UAAU,IAAI;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,eAAO,MAAM,8BAA8B,iBAC1B,IAAI,KAAG,yBAgBrB,CAAA;AAEH,eAAO,MAAM,8BAA8B,iBAC1B,IAAI,KAAG,yBAerB,CAAA"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export const getCacheUploadsAfterChangeHook = ({ endpoint })=>({ doc, operation, req })=>{
|
|
2
|
+
if (!req || !process.env.PAYLOAD_CLOUD_CACHE_KEY) {
|
|
3
|
+
return doc;
|
|
4
|
+
}
|
|
5
|
+
// WARNING:
|
|
6
|
+
// TODO: Test this for 3.0
|
|
7
|
+
const { payloadAPI } = req;
|
|
8
|
+
if (payloadAPI !== 'local') {
|
|
9
|
+
if (operation === 'update') {
|
|
10
|
+
// Unawaited promise
|
|
11
|
+
void purge({
|
|
12
|
+
doc,
|
|
13
|
+
endpoint,
|
|
14
|
+
operation,
|
|
15
|
+
req
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return doc;
|
|
20
|
+
};
|
|
21
|
+
export const getCacheUploadsAfterDeleteHook = ({ endpoint })=>({ doc, req })=>{
|
|
22
|
+
if (!req || !process.env.PAYLOAD_CLOUD_CACHE_KEY) {
|
|
23
|
+
return doc;
|
|
24
|
+
}
|
|
25
|
+
const { payloadAPI } = req;
|
|
26
|
+
// WARNING:
|
|
27
|
+
// TODO: Test this for 3.0
|
|
28
|
+
if (payloadAPI !== 'local') {
|
|
29
|
+
// Unawaited promise
|
|
30
|
+
void purge({
|
|
31
|
+
doc,
|
|
32
|
+
endpoint,
|
|
33
|
+
operation: 'delete',
|
|
34
|
+
req
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return doc;
|
|
38
|
+
};
|
|
39
|
+
async function purge({ doc, endpoint, operation, req }) {
|
|
40
|
+
const filePath = doc.url;
|
|
41
|
+
if (!filePath) {
|
|
42
|
+
req.payload.logger.error({
|
|
43
|
+
msg: 'No url found on doc',
|
|
44
|
+
project: {
|
|
45
|
+
id: process.env.PAYLOAD_CLOUD_PROJECT_ID
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const body = {
|
|
51
|
+
cacheKey: process.env.PAYLOAD_CLOUD_CACHE_KEY,
|
|
52
|
+
filepath: doc.url,
|
|
53
|
+
projectID: process.env.PAYLOAD_CLOUD_PROJECT_ID
|
|
54
|
+
};
|
|
55
|
+
req.payload.logger.debug({
|
|
56
|
+
filepath: doc.url,
|
|
57
|
+
msg: 'Attempting to purge cache',
|
|
58
|
+
operation,
|
|
59
|
+
project: {
|
|
60
|
+
id: process.env.PAYLOAD_CLOUD_PROJECT_ID
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
try {
|
|
64
|
+
const purgeRes = await fetch(`${endpoint}/api/purge-cache`, {
|
|
65
|
+
body: JSON.stringify({
|
|
66
|
+
...body
|
|
67
|
+
}),
|
|
68
|
+
headers: {
|
|
69
|
+
'Content-Type': 'application/json'
|
|
70
|
+
},
|
|
71
|
+
method: 'POST'
|
|
72
|
+
});
|
|
73
|
+
req.payload.logger.debug({
|
|
74
|
+
msg: 'Purge cache result',
|
|
75
|
+
operation,
|
|
76
|
+
statusCode: purgeRes.status
|
|
77
|
+
});
|
|
78
|
+
} catch (err) {
|
|
79
|
+
req.payload.logger.error({
|
|
80
|
+
body,
|
|
81
|
+
err,
|
|
82
|
+
msg: '/purge-cache call failed'
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//# sourceMappingURL=uploadCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/uploadCache.ts"],"sourcesContent":["import type { CollectionAfterChangeHook, CollectionAfterDeleteHook, PayloadRequest } from 'payload'\n\ninterface Args {\n endpoint: string\n}\n\nexport const getCacheUploadsAfterChangeHook =\n ({ endpoint }: Args): CollectionAfterChangeHook =>\n ({ doc, operation, req }) => {\n if (!req || !process.env.PAYLOAD_CLOUD_CACHE_KEY) {\n return doc\n }\n\n // WARNING:\n // TODO: Test this for 3.0\n const { payloadAPI } = req\n if (payloadAPI !== 'local') {\n if (operation === 'update') {\n // Unawaited promise\n void purge({ doc, endpoint, operation, req })\n }\n }\n return doc\n }\n\nexport const getCacheUploadsAfterDeleteHook =\n ({ endpoint }: Args): CollectionAfterDeleteHook =>\n ({ doc, req }) => {\n if (!req || !process.env.PAYLOAD_CLOUD_CACHE_KEY) {\n return doc\n }\n\n const { payloadAPI } = req\n\n // WARNING:\n // TODO: Test this for 3.0\n if (payloadAPI !== 'local') {\n // Unawaited promise\n void purge({ doc, endpoint, operation: 'delete', req })\n }\n return doc\n }\n\ntype PurgeRequest = {\n doc: any\n endpoint: string\n operation: string\n req: PayloadRequest\n}\n\nasync function purge({ doc, endpoint, operation, req }: PurgeRequest) {\n const filePath = doc.url\n\n if (!filePath) {\n req.payload.logger.error({\n msg: 'No url found on doc',\n project: {\n id: process.env.PAYLOAD_CLOUD_PROJECT_ID,\n },\n })\n return\n }\n\n const body = {\n cacheKey: process.env.PAYLOAD_CLOUD_CACHE_KEY,\n filepath: doc.url,\n projectID: process.env.PAYLOAD_CLOUD_PROJECT_ID,\n }\n req.payload.logger.debug({\n filepath: doc.url,\n msg: 'Attempting to purge cache',\n operation,\n project: {\n id: process.env.PAYLOAD_CLOUD_PROJECT_ID,\n },\n })\n\n try {\n const purgeRes = await fetch(`${endpoint}/api/purge-cache`, {\n body: JSON.stringify({\n ...body,\n }),\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n req.payload.logger.debug({\n msg: 'Purge cache result',\n operation,\n statusCode: purgeRes.status,\n })\n } catch (err: unknown) {\n req.payload.logger.error({ body, err, msg: '/purge-cache call failed' })\n }\n}\n"],"names":["getCacheUploadsAfterChangeHook","endpoint","doc","operation","req","process","env","PAYLOAD_CLOUD_CACHE_KEY","payloadAPI","purge","getCacheUploadsAfterDeleteHook","filePath","url","payload","logger","error","msg","project","id","PAYLOAD_CLOUD_PROJECT_ID","body","cacheKey","filepath","projectID","debug","purgeRes","fetch","JSON","stringify","headers","method","statusCode","status","err"],"mappings":"AAMA,OAAO,MAAMA,iCACX,CAAC,EAAEC,QAAQ,EAAQ,GACnB,CAAC,EAAEC,GAAG,EAAEC,SAAS,EAAEC,GAAG,EAAE;QACtB,IAAI,CAACA,OAAO,CAACC,QAAQC,GAAG,CAACC,uBAAuB,EAAE;YAChD,OAAOL;QACT;QAEA,WAAW;QACX,0BAA0B;QAC1B,MAAM,EAAEM,UAAU,EAAE,GAAGJ;QACvB,IAAII,eAAe,SAAS;YAC1B,IAAIL,cAAc,UAAU;gBAC1B,oBAAoB;gBACpB,KAAKM,MAAM;oBAAEP;oBAAKD;oBAAUE;oBAAWC;gBAAI;YAC7C;QACF;QACA,OAAOF;IACT,EAAC;AAEH,OAAO,MAAMQ,iCACX,CAAC,EAAET,QAAQ,EAAQ,GACnB,CAAC,EAAEC,GAAG,EAAEE,GAAG,EAAE;QACX,IAAI,CAACA,OAAO,CAACC,QAAQC,GAAG,CAACC,uBAAuB,EAAE;YAChD,OAAOL;QACT;QAEA,MAAM,EAAEM,UAAU,EAAE,GAAGJ;QAEvB,WAAW;QACX,0BAA0B;QAC1B,IAAII,eAAe,SAAS;YAC1B,oBAAoB;YACpB,KAAKC,MAAM;gBAAEP;gBAAKD;gBAAUE,WAAW;gBAAUC;YAAI;QACvD;QACA,OAAOF;IACT,EAAC;AASH,eAAeO,MAAM,EAAEP,GAAG,EAAED,QAAQ,EAAEE,SAAS,EAAEC,GAAG,EAAgB;IAClE,MAAMO,WAAWT,IAAIU,GAAG;IAExB,IAAI,CAACD,UAAU;QACbP,IAAIS,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;YACvBC,KAAK;YACLC,SAAS;gBACPC,IAAIb,QAAQC,GAAG,CAACa,wBAAwB;YAC1C;QACF;QACA;IACF;IAEA,MAAMC,OAAO;QACXC,UAAUhB,QAAQC,GAAG,CAACC,uBAAuB;QAC7Ce,UAAUpB,IAAIU,GAAG;QACjBW,WAAWlB,QAAQC,GAAG,CAACa,wBAAwB;IACjD;IACAf,IAAIS,OAAO,CAACC,MAAM,CAACU,KAAK,CAAC;QACvBF,UAAUpB,IAAIU,GAAG;QACjBI,KAAK;QACLb;QACAc,SAAS;YACPC,IAAIb,QAAQC,GAAG,CAACa,wBAAwB;QAC1C;IACF;IAEA,IAAI;QACF,MAAMM,WAAW,MAAMC,MAAM,CAAC,EAAEzB,SAAS,gBAAgB,CAAC,EAAE;YAC1DmB,MAAMO,KAAKC,SAAS,CAAC;gBACnB,GAAGR,IAAI;YACT;YACAS,SAAS;gBACP,gBAAgB;YAClB;YACAC,QAAQ;QACV;QAEA1B,IAAIS,OAAO,CAACC,MAAM,CAACU,KAAK,CAAC;YACvBR,KAAK;YACLb;YACA4B,YAAYN,SAASO,MAAM;QAC7B;IACF,EAAE,OAAOC,KAAc;QACrB7B,IAAIS,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;YAAEK;YAAMa;YAAKjB,KAAK;QAA2B;IACxE;AACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { payloadCloudPlugin } from './plugin.js'\nexport { createKey } from './utilities/createKey.js'\nexport { getStorageClient } from './utilities/getStorageClient.js'\n"],"names":["payloadCloudPlugin","createKey","getStorageClient"],"mappings":"AAAA,SAASA,kBAAkB,QAAQ,cAAa;AAChD,SAASC,SAAS,QAAQ,2BAA0B;AACpD,SAASC,gBAAgB,QAAQ,kCAAiC"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +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,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAW/C,eAAO,MAAM,kBAAkB,mBACZ,aAAa,sBACP,MAAM,KAAG,OAAO,CAAC,MAAM,CAiF7C,CAAA"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { payloadCloudEmail } from './email.js';
|
|
2
|
+
import { getAfterDeleteHook } from './hooks/afterDelete.js';
|
|
3
|
+
import { getBeforeChangeHook } from './hooks/beforeChange.js';
|
|
4
|
+
import { getCacheUploadsAfterChangeHook, getCacheUploadsAfterDeleteHook } from './hooks/uploadCache.js';
|
|
5
|
+
import { getStaticHandler } from './staticHandler.js';
|
|
6
|
+
export const payloadCloudPlugin = (pluginOptions)=>async (incomingConfig)=>{
|
|
7
|
+
let config = {
|
|
8
|
+
...incomingConfig
|
|
9
|
+
};
|
|
10
|
+
if (process.env.PAYLOAD_CLOUD !== 'true') {
|
|
11
|
+
return config;
|
|
12
|
+
}
|
|
13
|
+
const cachingEnabled = pluginOptions?.uploadCaching !== false && !!process.env.PAYLOAD_CLOUD_CACHE_KEY;
|
|
14
|
+
const apiEndpoint = pluginOptions?.endpoint || 'https://cloud-api.payloadcms.com';
|
|
15
|
+
// Configure cloud storage
|
|
16
|
+
if (pluginOptions?.storage !== false) {
|
|
17
|
+
config = {
|
|
18
|
+
...config,
|
|
19
|
+
collections: (config.collections || []).map((collection)=>{
|
|
20
|
+
if (collection.upload) {
|
|
21
|
+
return {
|
|
22
|
+
...collection,
|
|
23
|
+
hooks: {
|
|
24
|
+
...collection.hooks || {},
|
|
25
|
+
afterChange: [
|
|
26
|
+
...collection.hooks?.afterChange || [],
|
|
27
|
+
...cachingEnabled ? [
|
|
28
|
+
getCacheUploadsAfterChangeHook({
|
|
29
|
+
endpoint: apiEndpoint
|
|
30
|
+
})
|
|
31
|
+
] : []
|
|
32
|
+
],
|
|
33
|
+
afterDelete: [
|
|
34
|
+
...collection.hooks?.afterDelete || [],
|
|
35
|
+
getAfterDeleteHook({
|
|
36
|
+
collection
|
|
37
|
+
}),
|
|
38
|
+
...cachingEnabled ? [
|
|
39
|
+
getCacheUploadsAfterDeleteHook({
|
|
40
|
+
endpoint: apiEndpoint
|
|
41
|
+
})
|
|
42
|
+
] : []
|
|
43
|
+
],
|
|
44
|
+
beforeChange: [
|
|
45
|
+
...collection.hooks?.beforeChange || [],
|
|
46
|
+
getBeforeChangeHook({
|
|
47
|
+
collection
|
|
48
|
+
})
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
upload: {
|
|
52
|
+
...typeof collection.upload === 'object' ? collection.upload : {},
|
|
53
|
+
disableLocalStorage: true,
|
|
54
|
+
handlers: [
|
|
55
|
+
...typeof collection.upload === 'object' && Array.isArray(collection.upload.handlers) ? collection.upload.handlers : [],
|
|
56
|
+
getStaticHandler({
|
|
57
|
+
cachingOptions: pluginOptions?.uploadCaching,
|
|
58
|
+
collection
|
|
59
|
+
})
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return collection;
|
|
65
|
+
}),
|
|
66
|
+
upload: {
|
|
67
|
+
...config.upload || {},
|
|
68
|
+
useTempFiles: true
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
// Configure cloud email
|
|
73
|
+
const apiKey = process.env.PAYLOAD_CLOUD_EMAIL_API_KEY;
|
|
74
|
+
const defaultDomain = process.env.PAYLOAD_CLOUD_DEFAULT_DOMAIN;
|
|
75
|
+
if (pluginOptions?.email !== false && apiKey && defaultDomain) {
|
|
76
|
+
config.email = await payloadCloudEmail({
|
|
77
|
+
apiKey,
|
|
78
|
+
config,
|
|
79
|
+
defaultDomain,
|
|
80
|
+
defaultFromAddress: pluginOptions?.email?.defaultFromAddress,
|
|
81
|
+
defaultFromName: pluginOptions?.email?.defaultFromName,
|
|
82
|
+
skipVerify: pluginOptions?.email?.skipVerify
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return config;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Config } from 'payload'\n\nimport type { PluginOptions } from './types.js'\n\nimport { payloadCloudEmail } from './email.js'\nimport { getAfterDeleteHook } from './hooks/afterDelete.js'\nimport { getBeforeChangeHook } from './hooks/beforeChange.js'\nimport {\n getCacheUploadsAfterChangeHook,\n getCacheUploadsAfterDeleteHook,\n} from './hooks/uploadCache.js'\nimport { getStaticHandler } from './staticHandler.js'\n\nexport const payloadCloudPlugin =\n (pluginOptions?: PluginOptions) =>\n async (incomingConfig: Config): Promise<Config> => {\n let config = { ...incomingConfig }\n\n if (process.env.PAYLOAD_CLOUD !== 'true') {\n return config\n }\n\n const cachingEnabled =\n pluginOptions?.uploadCaching !== false && !!process.env.PAYLOAD_CLOUD_CACHE_KEY\n\n const apiEndpoint = pluginOptions?.endpoint || 'https://cloud-api.payloadcms.com'\n\n // Configure cloud storage\n if (pluginOptions?.storage !== false) {\n config = {\n ...config,\n collections: (config.collections || []).map((collection) => {\n if (collection.upload) {\n return {\n ...collection,\n hooks: {\n ...(collection.hooks || {}),\n afterChange: [\n ...(collection.hooks?.afterChange || []),\n ...(cachingEnabled\n ? [getCacheUploadsAfterChangeHook({ endpoint: apiEndpoint })]\n : []),\n ],\n afterDelete: [\n ...(collection.hooks?.afterDelete || []),\n getAfterDeleteHook({ collection }),\n ...(cachingEnabled\n ? [getCacheUploadsAfterDeleteHook({ endpoint: apiEndpoint })]\n : []),\n ],\n beforeChange: [\n ...(collection.hooks?.beforeChange || []),\n getBeforeChangeHook({ collection }),\n ],\n },\n upload: {\n ...(typeof collection.upload === 'object' ? collection.upload : {}),\n disableLocalStorage: true,\n handlers: [\n ...(typeof collection.upload === 'object' &&\n Array.isArray(collection.upload.handlers)\n ? collection.upload.handlers\n : []),\n getStaticHandler({\n cachingOptions: pluginOptions?.uploadCaching,\n collection,\n }),\n ],\n },\n }\n }\n\n return collection\n }),\n upload: {\n ...(config.upload || {}),\n useTempFiles: true,\n },\n }\n }\n\n // Configure cloud email\n const apiKey = process.env.PAYLOAD_CLOUD_EMAIL_API_KEY\n const defaultDomain = process.env.PAYLOAD_CLOUD_DEFAULT_DOMAIN\n if (pluginOptions?.email !== false && apiKey && defaultDomain) {\n config.email = await payloadCloudEmail({\n apiKey,\n config,\n defaultDomain,\n defaultFromAddress: pluginOptions?.email?.defaultFromAddress,\n defaultFromName: pluginOptions?.email?.defaultFromName,\n skipVerify: pluginOptions?.email?.skipVerify,\n })\n }\n\n return config\n }\n"],"names":["payloadCloudEmail","getAfterDeleteHook","getBeforeChangeHook","getCacheUploadsAfterChangeHook","getCacheUploadsAfterDeleteHook","getStaticHandler","payloadCloudPlugin","pluginOptions","incomingConfig","config","process","env","PAYLOAD_CLOUD","cachingEnabled","uploadCaching","PAYLOAD_CLOUD_CACHE_KEY","apiEndpoint","endpoint","storage","collections","map","collection","upload","hooks","afterChange","afterDelete","beforeChange","disableLocalStorage","handlers","Array","isArray","cachingOptions","useTempFiles","apiKey","PAYLOAD_CLOUD_EMAIL_API_KEY","defaultDomain","PAYLOAD_CLOUD_DEFAULT_DOMAIN","email","defaultFromAddress","defaultFromName","skipVerify"],"mappings":"AAIA,SAASA,iBAAiB,QAAQ,aAAY;AAC9C,SAASC,kBAAkB,QAAQ,yBAAwB;AAC3D,SAASC,mBAAmB,QAAQ,0BAAyB;AAC7D,SACEC,8BAA8B,EAC9BC,8BAA8B,QACzB,yBAAwB;AAC/B,SAASC,gBAAgB,QAAQ,qBAAoB;AAErD,OAAO,MAAMC,qBACX,CAACC,gBACD,OAAOC;QACL,IAAIC,SAAS;YAAE,GAAGD,cAAc;QAAC;QAEjC,IAAIE,QAAQC,GAAG,CAACC,aAAa,KAAK,QAAQ;YACxC,OAAOH;QACT;QAEA,MAAMI,iBACJN,eAAeO,kBAAkB,SAAS,CAAC,CAACJ,QAAQC,GAAG,CAACI,uBAAuB;QAEjF,MAAMC,cAAcT,eAAeU,YAAY;QAE/C,0BAA0B;QAC1B,IAAIV,eAAeW,YAAY,OAAO;YACpCT,SAAS;gBACP,GAAGA,MAAM;gBACTU,aAAa,AAACV,CAAAA,OAAOU,WAAW,IAAI,EAAE,AAAD,EAAGC,GAAG,CAAC,CAACC;oBAC3C,IAAIA,WAAWC,MAAM,EAAE;wBACrB,OAAO;4BACL,GAAGD,UAAU;4BACbE,OAAO;gCACL,GAAIF,WAAWE,KAAK,IAAI,CAAC,CAAC;gCAC1BC,aAAa;uCACPH,WAAWE,KAAK,EAAEC,eAAe,EAAE;uCACnCX,iBACA;wCAACV,+BAA+B;4CAAEc,UAAUD;wCAAY;qCAAG,GAC3D,EAAE;iCACP;gCACDS,aAAa;uCACPJ,WAAWE,KAAK,EAAEE,eAAe,EAAE;oCACvCxB,mBAAmB;wCAAEoB;oCAAW;uCAC5BR,iBACA;wCAACT,+BAA+B;4CAAEa,UAAUD;wCAAY;qCAAG,GAC3D,EAAE;iCACP;gCACDU,cAAc;uCACRL,WAAWE,KAAK,EAAEG,gBAAgB,EAAE;oCACxCxB,oBAAoB;wCAAEmB;oCAAW;iCAClC;4BACH;4BACAC,QAAQ;gCACN,GAAI,OAAOD,WAAWC,MAAM,KAAK,WAAWD,WAAWC,MAAM,GAAG,CAAC,CAAC;gCAClEK,qBAAqB;gCACrBC,UAAU;uCACJ,OAAOP,WAAWC,MAAM,KAAK,YACjCO,MAAMC,OAAO,CAACT,WAAWC,MAAM,CAACM,QAAQ,IACpCP,WAAWC,MAAM,CAACM,QAAQ,GAC1B,EAAE;oCACNvB,iBAAiB;wCACf0B,gBAAgBxB,eAAeO;wCAC/BO;oCACF;iCACD;4BACH;wBACF;oBACF;oBAEA,OAAOA;gBACT;gBACAC,QAAQ;oBACN,GAAIb,OAAOa,MAAM,IAAI,CAAC,CAAC;oBACvBU,cAAc;gBAChB;YACF;QACF;QAEA,wBAAwB;QACxB,MAAMC,SAASvB,QAAQC,GAAG,CAACuB,2BAA2B;QACtD,MAAMC,gBAAgBzB,QAAQC,GAAG,CAACyB,4BAA4B;QAC9D,IAAI7B,eAAe8B,UAAU,SAASJ,UAAUE,eAAe;YAC7D1B,OAAO4B,KAAK,GAAG,MAAMrC,kBAAkB;gBACrCiC;gBACAxB;gBACA0B;gBACAG,oBAAoB/B,eAAe8B,OAAOC;gBAC1CC,iBAAiBhC,eAAe8B,OAAOE;gBACvCC,YAAYjC,eAAe8B,OAAOG;YACpC;QACF;QAEA,OAAO/B;IACT,EAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.spec.d.ts","sourceRoot":"","sources":["../src/plugin.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CollectionConfig } from 'payload';
|
|
2
|
+
import type { PluginOptions, StaticHandler } from './types.js';
|
|
3
|
+
interface Args {
|
|
4
|
+
cachingOptions?: PluginOptions['uploadCaching'];
|
|
5
|
+
collection: CollectionConfig;
|
|
6
|
+
}
|
|
7
|
+
export declare const getStaticHandler: ({ cachingOptions, collection }: Args) => StaticHandler;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=staticHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staticHandler.d.ts","sourceRoot":"","sources":["../src/staticHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE/C,OAAO,KAAK,EAA2B,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAKvF,UAAU,IAAI;IACZ,cAAc,CAAC,EAAE,aAAa,CAAC,eAAe,CAAC,CAAA;IAC/C,UAAU,EAAE,gBAAgB,CAAA;CAC7B;AAWD,eAAO,MAAM,gBAAgB,mCAAoC,IAAI,KAAG,aAoDvE,CAAA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createKey } from './utilities/createKey.js';
|
|
2
|
+
import { getStorageClient } from './utilities/getStorageClient.js';
|
|
3
|
+
// Convert a stream into a promise that resolves with a Buffer
|
|
4
|
+
const streamToBuffer = async (readableStream)=>{
|
|
5
|
+
const chunks = [];
|
|
6
|
+
for await (const chunk of readableStream){
|
|
7
|
+
chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
|
|
8
|
+
}
|
|
9
|
+
return Buffer.concat(chunks);
|
|
10
|
+
};
|
|
11
|
+
export const getStaticHandler = ({ cachingOptions, collection })=>{
|
|
12
|
+
let maxAge = 86400 // 24 hours default
|
|
13
|
+
;
|
|
14
|
+
let collCacheConfig;
|
|
15
|
+
if (cachingOptions !== false) {
|
|
16
|
+
// Set custom maxAge for all collections
|
|
17
|
+
maxAge = cachingOptions?.maxAge || maxAge;
|
|
18
|
+
collCacheConfig = cachingOptions?.collections?.[collection.slug] || {};
|
|
19
|
+
}
|
|
20
|
+
// Set maxAge using collection-specific override
|
|
21
|
+
maxAge = collCacheConfig?.maxAge || maxAge;
|
|
22
|
+
const cachingEnabled = cachingOptions !== false && !!process.env.PAYLOAD_CLOUD_CACHE_KEY && collCacheConfig?.enabled !== false;
|
|
23
|
+
return async (req, { params })=>{
|
|
24
|
+
try {
|
|
25
|
+
const { identityID, storageClient } = await getStorageClient();
|
|
26
|
+
const Key = createKey({
|
|
27
|
+
collection: collection.slug,
|
|
28
|
+
filename: params.filename,
|
|
29
|
+
identityID
|
|
30
|
+
});
|
|
31
|
+
const object = await storageClient.getObject({
|
|
32
|
+
Bucket: process.env.PAYLOAD_CLOUD_BUCKET,
|
|
33
|
+
Key
|
|
34
|
+
});
|
|
35
|
+
if (!object.Body) {
|
|
36
|
+
return new Response(null, {
|
|
37
|
+
status: 404,
|
|
38
|
+
statusText: 'Not Found'
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const bodyBuffer = await streamToBuffer(object.Body);
|
|
42
|
+
return new Response(bodyBuffer, {
|
|
43
|
+
headers: new Headers({
|
|
44
|
+
'Content-Length': String(object.ContentLength),
|
|
45
|
+
'Content-Type': object.ContentType,
|
|
46
|
+
...cachingEnabled && {
|
|
47
|
+
'Cache-Control': `public, max-age=${maxAge}`
|
|
48
|
+
},
|
|
49
|
+
ETag: object.ETag
|
|
50
|
+
}),
|
|
51
|
+
status: 200
|
|
52
|
+
});
|
|
53
|
+
} catch (err) {
|
|
54
|
+
req.payload.logger.error({
|
|
55
|
+
err,
|
|
56
|
+
msg: 'Error getting file from cloud storage'
|
|
57
|
+
});
|
|
58
|
+
return new Response('Internal Server Error', {
|
|
59
|
+
status: 500
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=staticHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/staticHandler.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\nimport type { CollectionCachingConfig, PluginOptions, StaticHandler } from './types.js'\n\nimport { createKey } from './utilities/createKey.js'\nimport { getStorageClient } from './utilities/getStorageClient.js'\n\ninterface Args {\n cachingOptions?: PluginOptions['uploadCaching']\n collection: CollectionConfig\n}\n\n// Convert a stream into a promise that resolves with a Buffer\nconst streamToBuffer = async (readableStream) => {\n const chunks = []\n for await (const chunk of readableStream) {\n chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk)\n }\n return Buffer.concat(chunks)\n}\n\nexport const getStaticHandler = ({ cachingOptions, collection }: Args): StaticHandler => {\n let maxAge = 86400 // 24 hours default\n let collCacheConfig: CollectionCachingConfig | undefined\n if (cachingOptions !== false) {\n // Set custom maxAge for all collections\n maxAge = cachingOptions?.maxAge || maxAge\n collCacheConfig = cachingOptions?.collections?.[collection.slug] || {}\n }\n\n // Set maxAge using collection-specific override\n maxAge = collCacheConfig?.maxAge || maxAge\n\n const cachingEnabled =\n cachingOptions !== false &&\n !!process.env.PAYLOAD_CLOUD_CACHE_KEY &&\n collCacheConfig?.enabled !== false\n\n return async (req, { params }) => {\n try {\n const { identityID, storageClient } = await getStorageClient()\n\n const Key = createKey({\n collection: collection.slug,\n filename: params.filename,\n identityID,\n })\n\n const object = await storageClient.getObject({\n Bucket: process.env.PAYLOAD_CLOUD_BUCKET,\n Key,\n })\n\n if (!object.Body) {\n return new Response(null, { status: 404, statusText: 'Not Found' })\n }\n\n const bodyBuffer = await streamToBuffer(object.Body)\n\n return new Response(bodyBuffer, {\n headers: new Headers({\n 'Content-Length': String(object.ContentLength),\n 'Content-Type': object.ContentType,\n ...(cachingEnabled && { 'Cache-Control': `public, max-age=${maxAge}` }),\n ETag: object.ETag,\n }),\n status: 200,\n })\n } catch (err: unknown) {\n req.payload.logger.error({ err, msg: 'Error getting file from cloud storage' })\n return new Response('Internal Server Error', { status: 500 })\n }\n }\n}\n"],"names":["createKey","getStorageClient","streamToBuffer","readableStream","chunks","chunk","push","Buffer","from","concat","getStaticHandler","cachingOptions","collection","maxAge","collCacheConfig","collections","slug","cachingEnabled","process","env","PAYLOAD_CLOUD_CACHE_KEY","enabled","req","params","identityID","storageClient","Key","filename","object","getObject","Bucket","PAYLOAD_CLOUD_BUCKET","Body","Response","status","statusText","bodyBuffer","headers","Headers","String","ContentLength","ContentType","ETag","err","payload","logger","error","msg"],"mappings":"AAIA,SAASA,SAAS,QAAQ,2BAA0B;AACpD,SAASC,gBAAgB,QAAQ,kCAAiC;AAOlE,8DAA8D;AAC9D,MAAMC,iBAAiB,OAAOC;IAC5B,MAAMC,SAAS,EAAE;IACjB,WAAW,MAAMC,SAASF,eAAgB;QACxCC,OAAOE,IAAI,CAAC,OAAOD,UAAU,WAAWE,OAAOC,IAAI,CAACH,SAASA;IAC/D;IACA,OAAOE,OAAOE,MAAM,CAACL;AACvB;AAEA,OAAO,MAAMM,mBAAmB,CAAC,EAAEC,cAAc,EAAEC,UAAU,EAAQ;IACnE,IAAIC,SAAS,MAAM,mBAAmB;;IACtC,IAAIC;IACJ,IAAIH,mBAAmB,OAAO;QAC5B,wCAAwC;QACxCE,SAASF,gBAAgBE,UAAUA;QACnCC,kBAAkBH,gBAAgBI,aAAa,CAACH,WAAWI,IAAI,CAAC,IAAI,CAAC;IACvE;IAEA,gDAAgD;IAChDH,SAASC,iBAAiBD,UAAUA;IAEpC,MAAMI,iBACJN,mBAAmB,SACnB,CAAC,CAACO,QAAQC,GAAG,CAACC,uBAAuB,IACrCN,iBAAiBO,YAAY;IAE/B,OAAO,OAAOC,KAAK,EAAEC,MAAM,EAAE;QAC3B,IAAI;YACF,MAAM,EAAEC,UAAU,EAAEC,aAAa,EAAE,GAAG,MAAMxB;YAE5C,MAAMyB,MAAM1B,UAAU;gBACpBY,YAAYA,WAAWI,IAAI;gBAC3BW,UAAUJ,OAAOI,QAAQ;gBACzBH;YACF;YAEA,MAAMI,SAAS,MAAMH,cAAcI,SAAS,CAAC;gBAC3CC,QAAQZ,QAAQC,GAAG,CAACY,oBAAoB;gBACxCL;YACF;YAEA,IAAI,CAACE,OAAOI,IAAI,EAAE;gBAChB,OAAO,IAAIC,SAAS,MAAM;oBAAEC,QAAQ;oBAAKC,YAAY;gBAAY;YACnE;YAEA,MAAMC,aAAa,MAAMlC,eAAe0B,OAAOI,IAAI;YAEnD,OAAO,IAAIC,SAASG,YAAY;gBAC9BC,SAAS,IAAIC,QAAQ;oBACnB,kBAAkBC,OAAOX,OAAOY,aAAa;oBAC7C,gBAAgBZ,OAAOa,WAAW;oBAClC,GAAIxB,kBAAkB;wBAAE,iBAAiB,CAAC,gBAAgB,EAAEJ,OAAO,CAAC;oBAAC,CAAC;oBACtE6B,MAAMd,OAAOc,IAAI;gBACnB;gBACAR,QAAQ;YACV;QACF,EAAE,OAAOS,KAAc;YACrBrB,IAAIsB,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;gBAAEH;gBAAKI,KAAK;YAAwC;YAC7E,OAAO,IAAId,SAAS,yBAAyB;gBAAEC,QAAQ;YAAI;QAC7D;IACF;AACF,EAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { CollectionConfig, Config, FileData, PayloadRequest, TypeWithID } from 'payload';
|
|
2
|
+
export interface File {
|
|
3
|
+
buffer: Buffer;
|
|
4
|
+
filename: string;
|
|
5
|
+
filesize: number;
|
|
6
|
+
mimeType: string;
|
|
7
|
+
tempFilePath?: string;
|
|
8
|
+
}
|
|
9
|
+
export type HandleUpload = (args: {
|
|
10
|
+
collection: CollectionConfig;
|
|
11
|
+
data: any;
|
|
12
|
+
file: File;
|
|
13
|
+
req: PayloadRequest;
|
|
14
|
+
}) => Promise<void> | void;
|
|
15
|
+
export interface TypeWithPrefix {
|
|
16
|
+
prefix?: string;
|
|
17
|
+
}
|
|
18
|
+
export type HandleDelete = (args: {
|
|
19
|
+
collection: CollectionConfig;
|
|
20
|
+
doc: FileData & TypeWithID & TypeWithPrefix;
|
|
21
|
+
filename: string;
|
|
22
|
+
req: PayloadRequest;
|
|
23
|
+
}) => Promise<void> | void;
|
|
24
|
+
export type GenerateURL = (args: {
|
|
25
|
+
collection: CollectionConfig;
|
|
26
|
+
filename: string;
|
|
27
|
+
prefix?: string;
|
|
28
|
+
}) => Promise<string> | string;
|
|
29
|
+
export type StaticHandler = (req: PayloadRequest, args: {
|
|
30
|
+
params: {
|
|
31
|
+
collection: string;
|
|
32
|
+
filename: string;
|
|
33
|
+
};
|
|
34
|
+
}) => Promise<Response> | Promise<void> | Response | void;
|
|
35
|
+
export interface PayloadCloudEmailOptions {
|
|
36
|
+
apiKey: string;
|
|
37
|
+
config: Config;
|
|
38
|
+
defaultDomain: string;
|
|
39
|
+
defaultFromAddress?: string;
|
|
40
|
+
defaultFromName?: string;
|
|
41
|
+
skipVerify?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export interface PluginOptions {
|
|
44
|
+
/** Payload Cloud Email
|
|
45
|
+
* @default true
|
|
46
|
+
*/
|
|
47
|
+
email?: {
|
|
48
|
+
defaultFromAddress: string;
|
|
49
|
+
defaultFromName: string;
|
|
50
|
+
skipVerify?: boolean;
|
|
51
|
+
} | false;
|
|
52
|
+
/**
|
|
53
|
+
* Payload Cloud API endpoint
|
|
54
|
+
*
|
|
55
|
+
* @internal Endpoint override for developement
|
|
56
|
+
*/
|
|
57
|
+
endpoint?: string;
|
|
58
|
+
/** Payload Cloud Storage
|
|
59
|
+
* @default true
|
|
60
|
+
*/
|
|
61
|
+
storage?: false;
|
|
62
|
+
/**
|
|
63
|
+
* Upload caching. Defaults to 24 hours for all collections.
|
|
64
|
+
*
|
|
65
|
+
* Optionally configure caching per collection
|
|
66
|
+
*
|
|
67
|
+
* ```ts
|
|
68
|
+
* {
|
|
69
|
+
* collSlug1: {
|
|
70
|
+
* maxAge: 3600 // Custom value in seconds
|
|
71
|
+
* },
|
|
72
|
+
* collSlug2: {
|
|
73
|
+
* enabled: false // Disable caching for this collection
|
|
74
|
+
* }
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @default true
|
|
79
|
+
*/
|
|
80
|
+
uploadCaching?: {
|
|
81
|
+
/**
|
|
82
|
+
* Caching configuration per-collection
|
|
83
|
+
*/
|
|
84
|
+
collections?: Record<string, CollectionCachingConfig>;
|
|
85
|
+
/** Caching in seconds override for all collections
|
|
86
|
+
* @default 86400 (24 hours)
|
|
87
|
+
*/
|
|
88
|
+
maxAge?: number;
|
|
89
|
+
} | false;
|
|
90
|
+
}
|
|
91
|
+
export type CollectionCachingConfig = {
|
|
92
|
+
/**
|
|
93
|
+
* Enable/disable caching for this collection
|
|
94
|
+
*
|
|
95
|
+
* @default true
|
|
96
|
+
*/
|
|
97
|
+
enabled?: boolean;
|
|
98
|
+
/** Caching in seconds override for this collection
|
|
99
|
+
* @default 86400 (24 hours)
|
|
100
|
+
*/
|
|
101
|
+
maxAge?: number;
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAE7F,MAAM,WAAW,IAAI;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE;IAChC,UAAU,EAAE,gBAAgB,CAAA;IAC5B,IAAI,EAAE,GAAG,CAAA;IACT,IAAI,EAAE,IAAI,CAAA;IACV,GAAG,EAAE,cAAc,CAAA;CACpB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;AAE1B,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE;IAChC,UAAU,EAAE,gBAAgB,CAAA;IAC5B,GAAG,EAAE,QAAQ,GAAG,UAAU,GAAG,cAAc,CAAA;IAC3C,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,cAAc,CAAA;CACpB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;AAE1B,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE;IAC/B,UAAU,EAAE,gBAAgB,CAAA;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAA;AAE9B,MAAM,MAAM,aAAa,GAAG,CAC1B,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE;IAAE,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,KACvD,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,GAAG,IAAI,CAAA;AAExD,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,KAAK,CAAC,EACF;QACE,kBAAkB,EAAE,MAAM,CAAA;QAC1B,eAAe,EAAE,MAAM,CAAA;QACvB,UAAU,CAAC,EAAE,OAAO,CAAA;KACrB,GACD,KAAK,CAAA;IAET;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;OAEG;IACH,OAAO,CAAC,EAAE,KAAK,CAAA;IAEf;;;;;;;;;;;;;;;;;OAiBG;IAEH,aAAa,CAAC,EACV;QACE;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAA;QACrD;;WAEG;QACH,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,GACD,KAAK,CAAA;CACV;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { CollectionConfig, Config, FileData, PayloadRequest, TypeWithID } from 'payload'\n\nexport interface File {\n buffer: Buffer\n filename: string\n filesize: number\n mimeType: string\n tempFilePath?: string\n}\n\nexport type HandleUpload = (args: {\n collection: CollectionConfig\n data: any\n file: File\n req: PayloadRequest\n}) => Promise<void> | void\n\nexport interface TypeWithPrefix {\n prefix?: string\n}\n\nexport type HandleDelete = (args: {\n collection: CollectionConfig\n doc: FileData & TypeWithID & TypeWithPrefix\n filename: string\n req: PayloadRequest\n}) => Promise<void> | void\n\nexport type GenerateURL = (args: {\n collection: CollectionConfig\n filename: string\n prefix?: string\n}) => Promise<string> | string\n\nexport type StaticHandler = (\n req: PayloadRequest,\n args: { params: { collection: string; filename: string } },\n) => Promise<Response> | Promise<void> | Response | void\n\nexport interface PayloadCloudEmailOptions {\n apiKey: string\n config: Config\n defaultDomain: string\n defaultFromAddress?: string\n defaultFromName?: string\n skipVerify?: boolean\n}\n\nexport interface PluginOptions {\n /** Payload Cloud Email\n * @default true\n */\n email?:\n | {\n defaultFromAddress: string\n defaultFromName: string\n skipVerify?: boolean\n }\n | false\n\n /**\n * Payload Cloud API endpoint\n *\n * @internal Endpoint override for developement\n */\n endpoint?: string\n\n /** Payload Cloud Storage\n * @default true\n */\n storage?: false\n\n /**\n * Upload caching. Defaults to 24 hours for all collections.\n *\n * Optionally configure caching per collection\n *\n * ```ts\n * {\n * collSlug1: {\n * maxAge: 3600 // Custom value in seconds\n * },\n * collSlug2: {\n * enabled: false // Disable caching for this collection\n * }\n * }\n * ```\n *\n * @default true\n */\n\n uploadCaching?:\n | {\n /**\n * Caching configuration per-collection\n */\n collections?: Record<string, CollectionCachingConfig>\n /** Caching in seconds override for all collections\n * @default 86400 (24 hours)\n */\n maxAge?: number\n }\n | false\n}\n\nexport type CollectionCachingConfig = {\n /**\n * Enable/disable caching for this collection\n *\n * @default true\n */\n enabled?: boolean\n /** Caching in seconds override for this collection\n * @default 86400 (24 hours)\n */\n maxAge?: number\n}\n"],"names":[],"mappings":"AAyGA,WAWC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authAsCognitoUser.d.ts","sourceRoot":"","sources":["../../src/utilities/authAsCognitoUser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAMpE,eAAO,MAAM,iBAAiB,aAClB,MAAM,YACN,MAAM,KACf,OAAO,CAAC,kBAAkB,CAmC5B,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { AuthenticationDetails, CognitoUser, CognitoUserPool } from 'amazon-cognito-identity-js';
|
|
2
|
+
let sessionAndToken = null;
|
|
3
|
+
export const authAsCognitoUser = async (username, password)=>{
|
|
4
|
+
// TODO: Check that isValid evaluates expiration
|
|
5
|
+
if (sessionAndToken?.isValid()) {
|
|
6
|
+
return sessionAndToken;
|
|
7
|
+
}
|
|
8
|
+
const userPool = new CognitoUserPool({
|
|
9
|
+
ClientId: process.env.PAYLOAD_CLOUD_COGNITO_USER_POOL_CLIENT_ID,
|
|
10
|
+
UserPoolId: process.env.PAYLOAD_CLOUD_COGNITO_USER_POOL_ID
|
|
11
|
+
});
|
|
12
|
+
const authenticationDetails = new AuthenticationDetails({
|
|
13
|
+
Password: password,
|
|
14
|
+
Username: username
|
|
15
|
+
});
|
|
16
|
+
const cognitoUser = new CognitoUser({
|
|
17
|
+
Pool: userPool,
|
|
18
|
+
Username: username
|
|
19
|
+
});
|
|
20
|
+
const result = await new Promise((resolve, reject)=>{
|
|
21
|
+
cognitoUser.authenticateUser(authenticationDetails, {
|
|
22
|
+
onFailure: (err)=>{
|
|
23
|
+
reject(err);
|
|
24
|
+
},
|
|
25
|
+
onSuccess: (res)=>{
|
|
26
|
+
resolve(res);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
sessionAndToken = result;
|
|
31
|
+
return sessionAndToken;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=authAsCognitoUser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/authAsCognitoUser.ts"],"sourcesContent":["import type { CognitoUserSession } from 'amazon-cognito-identity-js'\n\nimport { AuthenticationDetails, CognitoUser, CognitoUserPool } from 'amazon-cognito-identity-js'\n\nlet sessionAndToken: CognitoUserSession | null = null\n\nexport const authAsCognitoUser = async (\n username: string,\n password: string,\n): Promise<CognitoUserSession> => {\n // TODO: Check that isValid evaluates expiration\n if (sessionAndToken?.isValid()) {\n return sessionAndToken\n }\n\n const userPool = new CognitoUserPool({\n ClientId: process.env.PAYLOAD_CLOUD_COGNITO_USER_POOL_CLIENT_ID,\n UserPoolId: process.env.PAYLOAD_CLOUD_COGNITO_USER_POOL_ID,\n })\n\n const authenticationDetails = new AuthenticationDetails({\n Password: password,\n Username: username,\n })\n\n const cognitoUser = new CognitoUser({\n Pool: userPool,\n Username: username,\n })\n\n const result: CognitoUserSession = await new Promise((resolve, reject) => {\n cognitoUser.authenticateUser(authenticationDetails, {\n onFailure: (err: Error) => {\n reject(err)\n },\n onSuccess: (res) => {\n resolve(res)\n },\n })\n })\n\n sessionAndToken = result\n\n return sessionAndToken\n}\n"],"names":["AuthenticationDetails","CognitoUser","CognitoUserPool","sessionAndToken","authAsCognitoUser","username","password","isValid","userPool","ClientId","process","env","PAYLOAD_CLOUD_COGNITO_USER_POOL_CLIENT_ID","UserPoolId","PAYLOAD_CLOUD_COGNITO_USER_POOL_ID","authenticationDetails","Password","Username","cognitoUser","Pool","result","Promise","resolve","reject","authenticateUser","onFailure","err","onSuccess","res"],"mappings":"AAEA,SAASA,qBAAqB,EAAEC,WAAW,EAAEC,eAAe,QAAQ,6BAA4B;AAEhG,IAAIC,kBAA6C;AAEjD,OAAO,MAAMC,oBAAoB,OAC/BC,UACAC;IAEA,gDAAgD;IAChD,IAAIH,iBAAiBI,WAAW;QAC9B,OAAOJ;IACT;IAEA,MAAMK,WAAW,IAAIN,gBAAgB;QACnCO,UAAUC,QAAQC,GAAG,CAACC,yCAAyC;QAC/DC,YAAYH,QAAQC,GAAG,CAACG,kCAAkC;IAC5D;IAEA,MAAMC,wBAAwB,IAAIf,sBAAsB;QACtDgB,UAAUV;QACVW,UAAUZ;IACZ;IAEA,MAAMa,cAAc,IAAIjB,YAAY;QAClCkB,MAAMX;QACNS,UAAUZ;IACZ;IAEA,MAAMe,SAA6B,MAAM,IAAIC,QAAQ,CAACC,SAASC;QAC7DL,YAAYM,gBAAgB,CAACT,uBAAuB;YAClDU,WAAW,CAACC;gBACVH,OAAOG;YACT;YACAC,WAAW,CAACC;gBACVN,QAAQM;YACV;QACF;IACF;IAEAzB,kBAAkBiB;IAElB,OAAOjB;AACT,EAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createKey.d.ts","sourceRoot":"","sources":["../../src/utilities/createKey.ts"],"names":[],"mappings":"AAAA,UAAU,IAAI;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,SAAS,yCAA0C,IAAI,KAAG,MACa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/createKey.ts"],"sourcesContent":["interface Args {\n collection: string\n filename: string\n identityID: string\n}\n\nexport const createKey = ({ collection, filename, identityID }: Args): string =>\n `${identityID}/${process.env.PAYLOAD_CLOUD_ENVIRONMENT}/${collection}/${filename}`\n"],"names":["createKey","collection","filename","identityID","process","env","PAYLOAD_CLOUD_ENVIRONMENT"],"mappings":"AAMA,OAAO,MAAMA,YAAY,CAAC,EAAEC,UAAU,EAAEC,QAAQ,EAAEC,UAAU,EAAQ,GAClE,CAAC,EAAEA,WAAW,CAAC,EAAEC,QAAQC,GAAG,CAACC,yBAAyB,CAAC,CAAC,EAAEL,WAAW,CAAC,EAAEC,SAAS,CAAC,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FileData, PayloadRequest } from 'payload';
|
|
2
|
+
import type { File } from '../types.js';
|
|
3
|
+
export declare function getIncomingFiles({ data, req, }: {
|
|
4
|
+
data: Partial<FileData>;
|
|
5
|
+
req: PayloadRequest;
|
|
6
|
+
}): File[];
|
|
7
|
+
//# sourceMappingURL=getIncomingFiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getIncomingFiles.d.ts","sourceRoot":"","sources":["../../src/utilities/getIncomingFiles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAEvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAEvC,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,GAAG,GACJ,EAAE;IACD,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IACvB,GAAG,EAAE,cAAc,CAAA;CACpB,GAAG,IAAI,EAAE,CAiCT"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function getIncomingFiles({ data, req }) {
|
|
2
|
+
const file = req.file;
|
|
3
|
+
let files = [];
|
|
4
|
+
if (file && data.filename && data.mimeType) {
|
|
5
|
+
const mainFile = {
|
|
6
|
+
buffer: file.data,
|
|
7
|
+
filename: data.filename,
|
|
8
|
+
filesize: file.size,
|
|
9
|
+
mimeType: data.mimeType,
|
|
10
|
+
tempFilePath: file.tempFilePath
|
|
11
|
+
};
|
|
12
|
+
files = [
|
|
13
|
+
mainFile
|
|
14
|
+
];
|
|
15
|
+
if (data?.sizes) {
|
|
16
|
+
Object.entries(data.sizes).forEach(([key, resizedFileData])=>{
|
|
17
|
+
if (req.payloadUploadSizes?.[key] && data.mimeType) {
|
|
18
|
+
files = files.concat([
|
|
19
|
+
{
|
|
20
|
+
buffer: req.payloadUploadSizes[key],
|
|
21
|
+
filename: `${resizedFileData.filename}`,
|
|
22
|
+
filesize: req.payloadUploadSizes[key].length,
|
|
23
|
+
mimeType: data.mimeType
|
|
24
|
+
}
|
|
25
|
+
]);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return files;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=getIncomingFiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/getIncomingFiles.ts"],"sourcesContent":["import type { FileData, PayloadRequest } from 'payload'\n\nimport type { File } from '../types.js'\n\nexport function getIncomingFiles({\n data,\n req,\n}: {\n data: Partial<FileData>\n req: PayloadRequest\n}): File[] {\n const file = req.file\n\n let files: File[] = []\n\n if (file && data.filename && data.mimeType) {\n const mainFile: File = {\n buffer: file.data,\n filename: data.filename,\n filesize: file.size,\n mimeType: data.mimeType,\n tempFilePath: file.tempFilePath,\n }\n\n files = [mainFile]\n\n if (data?.sizes) {\n Object.entries(data.sizes).forEach(([key, resizedFileData]) => {\n if (req.payloadUploadSizes?.[key] && data.mimeType) {\n files = files.concat([\n {\n buffer: req.payloadUploadSizes[key],\n filename: `${resizedFileData.filename}`,\n filesize: req.payloadUploadSizes[key].length,\n mimeType: data.mimeType,\n },\n ])\n }\n })\n }\n }\n\n return files\n}\n"],"names":["getIncomingFiles","data","req","file","files","filename","mimeType","mainFile","buffer","filesize","size","tempFilePath","sizes","Object","entries","forEach","key","resizedFileData","payloadUploadSizes","concat","length"],"mappings":"AAIA,OAAO,SAASA,iBAAiB,EAC/BC,IAAI,EACJC,GAAG,EAIJ;IACC,MAAMC,OAAOD,IAAIC,IAAI;IAErB,IAAIC,QAAgB,EAAE;IAEtB,IAAID,QAAQF,KAAKI,QAAQ,IAAIJ,KAAKK,QAAQ,EAAE;QAC1C,MAAMC,WAAiB;YACrBC,QAAQL,KAAKF,IAAI;YACjBI,UAAUJ,KAAKI,QAAQ;YACvBI,UAAUN,KAAKO,IAAI;YACnBJ,UAAUL,KAAKK,QAAQ;YACvBK,cAAcR,KAAKQ,YAAY;QACjC;QAEAP,QAAQ;YAACG;SAAS;QAElB,IAAIN,MAAMW,OAAO;YACfC,OAAOC,OAAO,CAACb,KAAKW,KAAK,EAAEG,OAAO,CAAC,CAAC,CAACC,KAAKC,gBAAgB;gBACxD,IAAIf,IAAIgB,kBAAkB,EAAE,CAACF,IAAI,IAAIf,KAAKK,QAAQ,EAAE;oBAClDF,QAAQA,MAAMe,MAAM,CAAC;wBACnB;4BACEX,QAAQN,IAAIgB,kBAAkB,CAACF,IAAI;4BACnCX,UAAU,CAAC,EAAEY,gBAAgBZ,QAAQ,CAAC,CAAC;4BACvCI,UAAUP,IAAIgB,kBAAkB,CAACF,IAAI,CAACI,MAAM;4BAC5Cd,UAAUL,KAAKK,QAAQ;wBACzB;qBACD;gBACH;YACF;QACF;IACF;IAEA,OAAOF;AACT"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getStorageClient.d.ts","sourceRoot":"","sources":["../../src/utilities/getStorageClient.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,GAAG,MAAM,oBAAoB,CAAA;AAKzC,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC;IAC3C,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,GAAG,CAAC,EAAE,CAAA;CACtB,CAAC,CAAA;AAMF,eAAO,MAAM,gBAAgB,EAAE,gBAwC9B,CAAA"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { CognitoIdentityClient } from '@aws-sdk/client-cognito-identity';
|
|
2
|
+
import * as AWS from '@aws-sdk/client-s3';
|
|
3
|
+
import { fromCognitoIdentityPool } from '@aws-sdk/credential-providers';
|
|
4
|
+
import { authAsCognitoUser } from './authAsCognitoUser.js';
|
|
5
|
+
let storageClient = null;
|
|
6
|
+
let session = null;
|
|
7
|
+
let identityID;
|
|
8
|
+
export const getStorageClient = async ()=>{
|
|
9
|
+
if (storageClient && session?.isValid()) {
|
|
10
|
+
return {
|
|
11
|
+
identityID,
|
|
12
|
+
storageClient
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
session = await authAsCognitoUser(process.env.PAYLOAD_CLOUD_PROJECT_ID, process.env.PAYLOAD_CLOUD_COGNITO_PASSWORD);
|
|
16
|
+
const cognitoIdentity = new CognitoIdentityClient({
|
|
17
|
+
credentials: fromCognitoIdentityPool({
|
|
18
|
+
clientConfig: {
|
|
19
|
+
region: 'us-east-1'
|
|
20
|
+
},
|
|
21
|
+
identityPoolId: process.env.PAYLOAD_CLOUD_COGNITO_IDENTITY_POOL_ID,
|
|
22
|
+
logins: {
|
|
23
|
+
[`cognito-idp.us-east-1.amazonaws.com/${process.env.PAYLOAD_CLOUD_COGNITO_USER_POOL_ID}`]: session.getIdToken().getJwtToken()
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
});
|
|
27
|
+
const credentials = await cognitoIdentity.config.credentials();
|
|
28
|
+
// @ts-expect-error - Incorrect AWS types
|
|
29
|
+
identityID = credentials.identityId;
|
|
30
|
+
storageClient = new AWS.S3({
|
|
31
|
+
credentials,
|
|
32
|
+
region: process.env.PAYLOAD_CLOUD_BUCKET_REGION
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
identityID,
|
|
36
|
+
storageClient
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=getStorageClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/getStorageClient.ts"],"sourcesContent":["import type { CognitoUserSession } from 'amazon-cognito-identity-js'\n\nimport { CognitoIdentityClient } from '@aws-sdk/client-cognito-identity'\nimport * as AWS from '@aws-sdk/client-s3'\nimport { fromCognitoIdentityPool } from '@aws-sdk/credential-providers'\n\nimport { authAsCognitoUser } from './authAsCognitoUser.js'\n\nexport type GetStorageClient = () => Promise<{\n identityID: string\n storageClient: AWS.S3\n}>\n\nlet storageClient: AWS.S3 | null = null\nlet session: CognitoUserSession | null = null\nlet identityID: string\n\nexport const getStorageClient: GetStorageClient = async () => {\n if (storageClient && session?.isValid()) {\n return {\n identityID,\n storageClient,\n }\n }\n\n session = await authAsCognitoUser(\n process.env.PAYLOAD_CLOUD_PROJECT_ID,\n process.env.PAYLOAD_CLOUD_COGNITO_PASSWORD,\n )\n\n const cognitoIdentity = new CognitoIdentityClient({\n credentials: fromCognitoIdentityPool({\n clientConfig: {\n region: 'us-east-1',\n },\n identityPoolId: process.env.PAYLOAD_CLOUD_COGNITO_IDENTITY_POOL_ID,\n logins: {\n [`cognito-idp.us-east-1.amazonaws.com/${process.env.PAYLOAD_CLOUD_COGNITO_USER_POOL_ID}`]:\n session.getIdToken().getJwtToken(),\n },\n }),\n })\n\n const credentials = await cognitoIdentity.config.credentials()\n\n // @ts-expect-error - Incorrect AWS types\n identityID = credentials.identityId\n\n storageClient = new AWS.S3({\n credentials,\n region: process.env.PAYLOAD_CLOUD_BUCKET_REGION,\n })\n\n return {\n identityID,\n storageClient,\n }\n}\n"],"names":["CognitoIdentityClient","AWS","fromCognitoIdentityPool","authAsCognitoUser","storageClient","session","identityID","getStorageClient","isValid","process","env","PAYLOAD_CLOUD_PROJECT_ID","PAYLOAD_CLOUD_COGNITO_PASSWORD","cognitoIdentity","credentials","clientConfig","region","identityPoolId","PAYLOAD_CLOUD_COGNITO_IDENTITY_POOL_ID","logins","PAYLOAD_CLOUD_COGNITO_USER_POOL_ID","getIdToken","getJwtToken","config","identityId","S3","PAYLOAD_CLOUD_BUCKET_REGION"],"mappings":"AAEA,SAASA,qBAAqB,QAAQ,mCAAkC;AACxE,YAAYC,SAAS,qBAAoB;AACzC,SAASC,uBAAuB,QAAQ,gCAA+B;AAEvE,SAASC,iBAAiB,QAAQ,yBAAwB;AAO1D,IAAIC,gBAA+B;AACnC,IAAIC,UAAqC;AACzC,IAAIC;AAEJ,OAAO,MAAMC,mBAAqC;IAChD,IAAIH,iBAAiBC,SAASG,WAAW;QACvC,OAAO;YACLF;YACAF;QACF;IACF;IAEAC,UAAU,MAAMF,kBACdM,QAAQC,GAAG,CAACC,wBAAwB,EACpCF,QAAQC,GAAG,CAACE,8BAA8B;IAG5C,MAAMC,kBAAkB,IAAIb,sBAAsB;QAChDc,aAAaZ,wBAAwB;YACnCa,cAAc;gBACZC,QAAQ;YACV;YACAC,gBAAgBR,QAAQC,GAAG,CAACQ,sCAAsC;YAClEC,QAAQ;gBACN,CAAC,CAAC,oCAAoC,EAAEV,QAAQC,GAAG,CAACU,kCAAkC,CAAC,CAAC,CAAC,EACvFf,QAAQgB,UAAU,GAAGC,WAAW;YACpC;QACF;IACF;IAEA,MAAMR,cAAc,MAAMD,gBAAgBU,MAAM,CAACT,WAAW;IAE5D,yCAAyC;IACzCR,aAAaQ,YAAYU,UAAU;IAEnCpB,gBAAgB,IAAIH,IAAIwB,EAAE,CAAC;QACzBX;QACAE,QAAQP,QAAQC,GAAG,CAACgB,2BAA2B;IACjD;IAEA,OAAO;QACLpB;QACAF;IACF;AACF,EAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@payloadcms/payload-cloud",
|
|
3
|
+
"version": "3.0.0-alpha.0",
|
|
4
|
+
"description": "The official Payload Cloud plugin",
|
|
5
|
+
"homepage": "https://payloadcms.com",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/payloadcms/payload.git",
|
|
9
|
+
"directory": "packages/payload-cloud"
|
|
10
|
+
},
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.js",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@aws-sdk/client-cognito-identity": "^3.614.0",
|
|
27
|
+
"@aws-sdk/client-s3": "^3.614.0",
|
|
28
|
+
"@aws-sdk/credential-providers": "^3.614.0",
|
|
29
|
+
"@aws-sdk/lib-storage": "^3.614.0",
|
|
30
|
+
"amazon-cognito-identity-js": "^6.1.2",
|
|
31
|
+
"nodemailer": "6.9.10",
|
|
32
|
+
"resend": "^0.17.2",
|
|
33
|
+
"@payloadcms/email-nodemailer": "3.0.0-beta.117"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/jest": "29.5.12",
|
|
37
|
+
"@types/nodemailer": "6.4.14",
|
|
38
|
+
"ts-jest": "^29.1.0",
|
|
39
|
+
"payload": "3.0.0-beta.117"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"payload": "3.0.0-beta.117"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "pnpm build:types && pnpm build:swc",
|
|
46
|
+
"build:swc": "swc ./src -d ./dist --config-file .swcrc-build --strip-leading-paths",
|
|
47
|
+
"build:types": "tsc --emitDeclarationOnly --outDir dist",
|
|
48
|
+
"clean": "rimraf {dist,*.tsbuildinfo}",
|
|
49
|
+
"lint": "eslint .",
|
|
50
|
+
"lint:fix": "eslint . --fix",
|
|
51
|
+
"test": "jest"
|
|
52
|
+
}
|
|
53
|
+
}
|