@fjall/payload 0.87.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +135 -0
- package/dist/adapters/postgres.d.ts +64 -0
- package/dist/adapters/postgres.d.ts.map +1 -0
- package/dist/adapters/postgres.js +89 -0
- package/dist/adapters/postgres.js.map +1 -0
- package/dist/adapters/secrets.d.ts +21 -0
- package/dist/adapters/secrets.d.ts.map +1 -0
- package/dist/adapters/secrets.js +53 -0
- package/dist/adapters/secrets.js.map +1 -0
- package/dist/config/defaults.d.ts +69 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +79 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/storage/s3.d.ts +52 -0
- package/dist/storage/s3.d.ts.map +1 -0
- package/dist/storage/s3.js +45 -0
- package/dist/storage/s3.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# @fjall/payload
|
|
2
|
+
|
|
3
|
+
AWS Lambda adapters for Payload CMS. This package provides drop-in replacements for Payload's database and storage adapters, optimized for serverless deployments on AWS.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @fjall/payload @payloadcms/storage-s3
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **`fjallPostgresAdapter`** - PostgreSQL adapter with AWS Secrets Manager integration
|
|
14
|
+
- **`awsS3Storage`** - S3 storage plugin for media uploads
|
|
15
|
+
- **`fjallDefaults`** - Sensible CORS/CSRF defaults for Lambda
|
|
16
|
+
- **`isProduction`** / **`isLambda`** - Environment detection helpers
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Database Adapter
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
// payload.config.ts
|
|
24
|
+
import { buildConfig } from "payload";
|
|
25
|
+
import { fjallPostgresAdapter, fjallDefaults } from "@fjall/payload";
|
|
26
|
+
import { migrations } from "./migrations";
|
|
27
|
+
|
|
28
|
+
export default buildConfig({
|
|
29
|
+
...fjallDefaults(),
|
|
30
|
+
db: await fjallPostgresAdapter({
|
|
31
|
+
migrationDir: "./src/migrations",
|
|
32
|
+
prodMigrations: migrations,
|
|
33
|
+
}),
|
|
34
|
+
// ... rest of config
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The adapter automatically:
|
|
39
|
+
|
|
40
|
+
- Fetches database credentials from AWS Secrets Manager in Lambda
|
|
41
|
+
- Falls back to `DATABASE_URL` for local development
|
|
42
|
+
- Configures SSL for Aurora PostgreSQL
|
|
43
|
+
|
|
44
|
+
### S3 Storage Plugin
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// plugins/index.ts
|
|
48
|
+
import { awsS3Storage } from "@fjall/payload";
|
|
49
|
+
import { Plugin } from "payload";
|
|
50
|
+
|
|
51
|
+
export const plugins: Plugin[] = [awsS3Storage()];
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The plugin automatically:
|
|
55
|
+
|
|
56
|
+
- Uses `MEDIA_BUCKET_NAME` environment variable set by Fjall infrastructure
|
|
57
|
+
- Handles presigned URLs for uploads
|
|
58
|
+
- Falls back to local filesystem in development
|
|
59
|
+
|
|
60
|
+
### Environment Detection
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { isProduction, isLambda } from "@fjall/payload";
|
|
64
|
+
|
|
65
|
+
// Conditional logic based on environment
|
|
66
|
+
if (isProduction()) {
|
|
67
|
+
// Running in AWS with Fjall infrastructure
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (isLambda()) {
|
|
71
|
+
// Running in AWS Lambda runtime
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Conditional Static Directory
|
|
76
|
+
|
|
77
|
+
For Media collections that need local uploads in dev but S3 in production:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { isProduction } from "@fjall/payload";
|
|
81
|
+
import path from "path";
|
|
82
|
+
|
|
83
|
+
export const Media: CollectionConfig = {
|
|
84
|
+
slug: "media",
|
|
85
|
+
upload: {
|
|
86
|
+
...(isProduction()
|
|
87
|
+
? {}
|
|
88
|
+
: {
|
|
89
|
+
staticDir: path.resolve(__dirname, "../../public/media"),
|
|
90
|
+
}),
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Environment Variables
|
|
96
|
+
|
|
97
|
+
### Production (Lambda)
|
|
98
|
+
|
|
99
|
+
Set automatically by Fjall infrastructure:
|
|
100
|
+
|
|
101
|
+
| Variable | Description |
|
|
102
|
+
| ------------------- | ----------------------------- |
|
|
103
|
+
| `DATABASE_HOST` | Aurora PostgreSQL endpoint |
|
|
104
|
+
| `DATABASE_PORT` | Database port (default: 5432) |
|
|
105
|
+
| `DATABASE_NAME` | Database name |
|
|
106
|
+
| `DATABASE_SSL` | Enable SSL (`true`) |
|
|
107
|
+
| `MEDIA_BUCKET_NAME` | S3 bucket for uploads |
|
|
108
|
+
|
|
109
|
+
Credentials fetched from Secrets Manager:
|
|
110
|
+
|
|
111
|
+
- `DATABASE_USERNAME`
|
|
112
|
+
- `DATABASE_PASSWORD`
|
|
113
|
+
|
|
114
|
+
### Development
|
|
115
|
+
|
|
116
|
+
| Variable | Description |
|
|
117
|
+
| -------------- | --------------------------------- |
|
|
118
|
+
| `DATABASE_URL` | Full PostgreSQL connection string |
|
|
119
|
+
|
|
120
|
+
## Auto-Configuration
|
|
121
|
+
|
|
122
|
+
When you run `fjall deploy` on a Payload project, the CLI automatically:
|
|
123
|
+
|
|
124
|
+
1. Detects the Payload pattern
|
|
125
|
+
2. Installs `@fjall/payload` and `@payloadcms/storage-s3`
|
|
126
|
+
3. Patches `payload.config.ts` to use `fjallPostgresAdapter`
|
|
127
|
+
4. Patches or creates `plugins/index.ts` with S3 storage
|
|
128
|
+
5. Configures `next.config.js` for Lambda (standalone output)
|
|
129
|
+
6. Generates `open-next.config.ts` for OpenNext
|
|
130
|
+
|
|
131
|
+
No manual configuration required - just run `fjall deploy`.
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
MIT
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fjall PostgreSQL adapter for Payload CMS.
|
|
3
|
+
*
|
|
4
|
+
* Wraps @payloadcms/db-postgres with AWS-specific features:
|
|
5
|
+
* - Fetches database credentials from AWS Secrets Manager via Lambda Extension
|
|
6
|
+
* - Constructs connection string from Fjall environment variables
|
|
7
|
+
* - Handles SSL configuration for Aurora PostgreSQL
|
|
8
|
+
* - Falls back to DATABASE_URL for local development
|
|
9
|
+
*/
|
|
10
|
+
import { postgresAdapter } from "@payloadcms/db-postgres";
|
|
11
|
+
/** The return type of postgresAdapter */
|
|
12
|
+
type PostgresAdapterResult = ReturnType<typeof postgresAdapter>;
|
|
13
|
+
/**
|
|
14
|
+
* Options for the Fjall PostgreSQL adapter.
|
|
15
|
+
*/
|
|
16
|
+
export interface FjallPostgresAdapterOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Path to migrations directory (relative to project root).
|
|
19
|
+
* @default './src/migrations'
|
|
20
|
+
*/
|
|
21
|
+
migrationDir?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Pre-compiled migrations for production.
|
|
24
|
+
* Required for Lambda deployments where filesystem migrations aren't available.
|
|
25
|
+
*/
|
|
26
|
+
prodMigrations?: Array<{
|
|
27
|
+
up: (args: {
|
|
28
|
+
db: unknown;
|
|
29
|
+
payload: unknown;
|
|
30
|
+
req: unknown;
|
|
31
|
+
}) => Promise<void>;
|
|
32
|
+
down: (args: {
|
|
33
|
+
db: unknown;
|
|
34
|
+
payload: unknown;
|
|
35
|
+
req: unknown;
|
|
36
|
+
}) => Promise<void>;
|
|
37
|
+
name: string;
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create a Fjall-configured PostgreSQL adapter for Payload CMS.
|
|
42
|
+
*
|
|
43
|
+
* This is an async function because it needs to fetch credentials from
|
|
44
|
+
* Secrets Manager. Call it with top-level await in your payload.config.ts.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* import { fjallPostgresAdapter } from '@fjall/payload'
|
|
49
|
+
* import { migrations } from './migrations'
|
|
50
|
+
*
|
|
51
|
+
* const db = await fjallPostgresAdapter({
|
|
52
|
+
* migrationDir: './src/migrations',
|
|
53
|
+
* prodMigrations: migrations,
|
|
54
|
+
* })
|
|
55
|
+
*
|
|
56
|
+
* export default buildConfig({
|
|
57
|
+
* db,
|
|
58
|
+
* // ...
|
|
59
|
+
* })
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function fjallPostgresAdapter(options?: FjallPostgresAdapterOptions): Promise<PostgresAdapterResult>;
|
|
63
|
+
export {};
|
|
64
|
+
//# sourceMappingURL=postgres.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/adapters/postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG1D,yCAAyC;AACzC,KAAK,qBAAqB,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAmDhE;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC;QACrB,EAAE,EAAE,CAAC,IAAI,EAAE;YACT,EAAE,EAAE,OAAO,CAAC;YACZ,OAAO,EAAE,OAAO,CAAC;YACjB,GAAG,EAAE,OAAO,CAAC;SACd,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACpB,IAAI,EAAE,CAAC,IAAI,EAAE;YACX,EAAE,EAAE,OAAO,CAAC;YACZ,OAAO,EAAE,OAAO,CAAC;YACjB,GAAG,EAAE,OAAO,CAAC;SACd,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;CACJ;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,qBAAqB,CAAC,CAahC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fjall PostgreSQL adapter for Payload CMS.
|
|
3
|
+
*
|
|
4
|
+
* Wraps @payloadcms/db-postgres with AWS-specific features:
|
|
5
|
+
* - Fetches database credentials from AWS Secrets Manager via Lambda Extension
|
|
6
|
+
* - Constructs connection string from Fjall environment variables
|
|
7
|
+
* - Handles SSL configuration for Aurora PostgreSQL
|
|
8
|
+
* - Falls back to DATABASE_URL for local development
|
|
9
|
+
*/
|
|
10
|
+
import { postgresAdapter } from "@payloadcms/db-postgres";
|
|
11
|
+
import { fetchSecretField } from "./secrets.js";
|
|
12
|
+
// Cache for resolved database URL (resolved once at Lambda cold start).
|
|
13
|
+
// Module-level state is intentional here: Lambda reuses the module across
|
|
14
|
+
// invocations, so caching avoids repeated Secrets Manager calls.
|
|
15
|
+
let cachedDbUrl = null;
|
|
16
|
+
/**
|
|
17
|
+
* Build the database connection URL from Fjall environment variables.
|
|
18
|
+
*
|
|
19
|
+
* In production (Lambda), uses:
|
|
20
|
+
* - DATABASE_HOST, DATABASE_PORT, DATABASE_NAME from environment
|
|
21
|
+
* - DATABASE_USERNAME/PASSWORD from Secrets Manager via Lambda Extension
|
|
22
|
+
*
|
|
23
|
+
* In development, falls back to DATABASE_URL environment variable.
|
|
24
|
+
*/
|
|
25
|
+
async function getDatabaseUrl() {
|
|
26
|
+
// Return cached URL if already resolved
|
|
27
|
+
if (cachedDbUrl)
|
|
28
|
+
return cachedDbUrl;
|
|
29
|
+
// If Fjall env vars are present (production Lambda environment)
|
|
30
|
+
if (process.env.DATABASE_HOST) {
|
|
31
|
+
const host = process.env.DATABASE_HOST;
|
|
32
|
+
const port = process.env.DATABASE_PORT || "5432";
|
|
33
|
+
const name = process.env.DATABASE_NAME;
|
|
34
|
+
// Fetch credentials from Lambda Extension
|
|
35
|
+
const user = (await fetchSecretField("DATABASE_USERNAME")) || "postgres";
|
|
36
|
+
const pass = (await fetchSecretField("DATABASE_PASSWORD")) || "";
|
|
37
|
+
cachedDbUrl = `postgresql://${user}:${encodeURIComponent(pass)}@${host}:${port}/${name}`;
|
|
38
|
+
return cachedDbUrl;
|
|
39
|
+
}
|
|
40
|
+
// Fallback to DATABASE_URL for local development
|
|
41
|
+
cachedDbUrl = process.env.DATABASE_URL || "";
|
|
42
|
+
return cachedDbUrl;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Get SSL configuration for Aurora PostgreSQL.
|
|
46
|
+
*
|
|
47
|
+
* In production (DATABASE_SSL=true), enables SSL but skips certificate
|
|
48
|
+
* verification since Aurora uses Amazon's internal CA.
|
|
49
|
+
*/
|
|
50
|
+
function getSslConfig() {
|
|
51
|
+
return process.env.DATABASE_SSL === "true"
|
|
52
|
+
? { rejectUnauthorized: false }
|
|
53
|
+
: false;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Create a Fjall-configured PostgreSQL adapter for Payload CMS.
|
|
57
|
+
*
|
|
58
|
+
* This is an async function because it needs to fetch credentials from
|
|
59
|
+
* Secrets Manager. Call it with top-level await in your payload.config.ts.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* import { fjallPostgresAdapter } from '@fjall/payload'
|
|
64
|
+
* import { migrations } from './migrations'
|
|
65
|
+
*
|
|
66
|
+
* const db = await fjallPostgresAdapter({
|
|
67
|
+
* migrationDir: './src/migrations',
|
|
68
|
+
* prodMigrations: migrations,
|
|
69
|
+
* })
|
|
70
|
+
*
|
|
71
|
+
* export default buildConfig({
|
|
72
|
+
* db,
|
|
73
|
+
* // ...
|
|
74
|
+
* })
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export async function fjallPostgresAdapter(options = {}) {
|
|
78
|
+
const { migrationDir = "./src/migrations", prodMigrations } = options;
|
|
79
|
+
const databaseUrl = await getDatabaseUrl();
|
|
80
|
+
return postgresAdapter({
|
|
81
|
+
pool: {
|
|
82
|
+
connectionString: databaseUrl,
|
|
83
|
+
ssl: getSslConfig(),
|
|
84
|
+
},
|
|
85
|
+
migrationDir,
|
|
86
|
+
prodMigrations,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=postgres.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/adapters/postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAKhD,wEAAwE;AACxE,0EAA0E;AAC1E,iEAAiE;AACjE,IAAI,WAAW,GAAkB,IAAI,CAAC;AAEtC;;;;;;;;GAQG;AACH,KAAK,UAAU,cAAc;IAC3B,wCAAwC;IACxC,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IAEpC,gEAAgE;IAChE,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;QACvC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,MAAM,CAAC;QACjD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;QAEvC,0CAA0C;QAC1C,MAAM,IAAI,GAAG,CAAC,MAAM,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,IAAI,UAAU,CAAC;QACzE,MAAM,IAAI,GAAG,CAAC,MAAM,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,IAAI,EAAE,CAAC;QAEjE,WAAW,GAAG,gBAAgB,IAAI,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;QACzF,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,iDAAiD;IACjD,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;IAC7C,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY;IACnB,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,MAAM;QACxC,CAAC,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE;QAC/B,CAAC,CAAC,KAAK,CAAC;AACZ,CAAC;AA+BD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,UAAuC,EAAE;IAEzC,MAAM,EAAE,YAAY,GAAG,kBAAkB,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;IAEtE,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAC;IAE3C,OAAO,eAAe,CAAC;QACrB,IAAI,EAAE;YACJ,gBAAgB,EAAE,WAAW;YAC7B,GAAG,EAAE,YAAY,EAAE;SACpB;QACD,YAAY;QACZ,cAAc;KACf,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Secrets Manager helper for Lambda environments.
|
|
3
|
+
*
|
|
4
|
+
* Fetches secrets via the Lambda Extension which runs on port 2773.
|
|
5
|
+
* The extension caches secrets automatically for performance.
|
|
6
|
+
*
|
|
7
|
+
* @see https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Fetch a specific field from an AWS Secret stored in Secrets Manager.
|
|
11
|
+
*
|
|
12
|
+
* Uses the Lambda Parameters and Secrets Extension for secure, cached access.
|
|
13
|
+
* The extension expects:
|
|
14
|
+
* - `${envKey}_SECRET_ARN` - The ARN of the secret in Secrets Manager
|
|
15
|
+
* - `${envKey}_SECRET_FIELD` - (Optional) The field name within the JSON secret
|
|
16
|
+
*
|
|
17
|
+
* @param envKey - The environment variable prefix (e.g., 'DATABASE_USERNAME')
|
|
18
|
+
* @returns The secret value, or undefined if not available
|
|
19
|
+
*/
|
|
20
|
+
export declare function fetchSecretField(envKey: string): Promise<string | undefined>;
|
|
21
|
+
//# sourceMappingURL=secrets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../src/adapters/secrets.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAqC7B"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Secrets Manager helper for Lambda environments.
|
|
3
|
+
*
|
|
4
|
+
* Fetches secrets via the Lambda Extension which runs on port 2773.
|
|
5
|
+
* The extension caches secrets automatically for performance.
|
|
6
|
+
*
|
|
7
|
+
* @see https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Fetch a specific field from an AWS Secret stored in Secrets Manager.
|
|
11
|
+
*
|
|
12
|
+
* Uses the Lambda Parameters and Secrets Extension for secure, cached access.
|
|
13
|
+
* The extension expects:
|
|
14
|
+
* - `${envKey}_SECRET_ARN` - The ARN of the secret in Secrets Manager
|
|
15
|
+
* - `${envKey}_SECRET_FIELD` - (Optional) The field name within the JSON secret
|
|
16
|
+
*
|
|
17
|
+
* @param envKey - The environment variable prefix (e.g., 'DATABASE_USERNAME')
|
|
18
|
+
* @returns The secret value, or undefined if not available
|
|
19
|
+
*/
|
|
20
|
+
export async function fetchSecretField(envKey) {
|
|
21
|
+
const secretArn = process.env[`${envKey}_SECRET_ARN`];
|
|
22
|
+
const secretField = process.env[`${envKey}_SECRET_FIELD`];
|
|
23
|
+
if (!secretArn)
|
|
24
|
+
return undefined;
|
|
25
|
+
const sessionToken = process.env.AWS_SESSION_TOKEN;
|
|
26
|
+
if (!sessionToken) {
|
|
27
|
+
// AWS_SESSION_TOKEN is set by Lambda runtime - if missing, we're not in Lambda
|
|
28
|
+
console.error(`fetchSecretField: AWS_SESSION_TOKEN not set (not running in Lambda?)`);
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const url = `http://localhost:2773/secretsmanager/get?secretId=${encodeURIComponent(secretArn)}`;
|
|
33
|
+
const response = await fetch(url, {
|
|
34
|
+
headers: {
|
|
35
|
+
"X-Aws-Parameters-Secrets-Token": sessionToken,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
console.error(`Failed to fetch secret ${envKey}: ${response.status}`);
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
const data = (await response.json());
|
|
43
|
+
if (!data.SecretString)
|
|
44
|
+
return undefined;
|
|
45
|
+
const parsed = JSON.parse(data.SecretString);
|
|
46
|
+
return secretField ? parsed[secretField] : data.SecretString;
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error(`Error fetching secret ${envKey}:`, err);
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/adapters/secrets.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAc;IAEd,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,aAAa,CAAC,CAAC;IACtD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,eAAe,CAAC,CAAC;IAE1D,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IAEjC,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACnD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,+EAA+E;QAC/E,OAAO,CAAC,KAAK,CACX,sEAAsE,CACvE,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,qDAAqD,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;QACjG,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,OAAO,EAAE;gBACP,gCAAgC,EAAE,YAAY;aAC/C;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,0BAA0B,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YACtE,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA8B,CAAC;QAClE,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO,SAAS,CAAC;QAEzC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7C,OAAO,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;IAC/D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,MAAM,GAAG,EAAE,GAAG,CAAC,CAAC;QACvD,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fjall default configuration helpers for Payload CMS.
|
|
3
|
+
*
|
|
4
|
+
* Provides sensible defaults for AWS Lambda deployments:
|
|
5
|
+
* - CORS configuration based on environment
|
|
6
|
+
* - CSRF configuration for security
|
|
7
|
+
* - Environment detection helpers
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Check if running in a production AWS environment.
|
|
11
|
+
*
|
|
12
|
+
* Detection is based on the presence of MEDIA_BUCKET_NAME which is set
|
|
13
|
+
* by Fjall infrastructure in Lambda environments.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isProduction(): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Check if running in AWS Lambda.
|
|
18
|
+
*
|
|
19
|
+
* Uses AWS_LAMBDA_FUNCTION_NAME which is set by the Lambda runtime.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isLambda(): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Fjall default configuration spread for Payload buildConfig.
|
|
24
|
+
*
|
|
25
|
+
* Provides:
|
|
26
|
+
* - CORS: Locked to NEXT_PUBLIC_SERVER_URL in production, permissive otherwise
|
|
27
|
+
* - CSRF: Enabled in production with NEXT_PUBLIC_SERVER_URL
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { fjallDefaults } from '@fjall/payload'
|
|
32
|
+
*
|
|
33
|
+
* export default buildConfig({
|
|
34
|
+
* ...fjallDefaults(),
|
|
35
|
+
* // your config...
|
|
36
|
+
* })
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function fjallDefaults(): {
|
|
40
|
+
cors: string[];
|
|
41
|
+
csrf: string[];
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Get the conditional staticDir configuration for Media collections.
|
|
45
|
+
*
|
|
46
|
+
* In production (Lambda), S3 storage is used and staticDir should be omitted.
|
|
47
|
+
* In local development, uploads go to the local filesystem.
|
|
48
|
+
*
|
|
49
|
+
* @param localPath - The local path for development (e.g., './public/media')
|
|
50
|
+
* @returns Object with staticDir for local dev, empty object for production
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* import { conditionalStaticDir } from '@fjall/payload'
|
|
55
|
+
* import path from 'path'
|
|
56
|
+
*
|
|
57
|
+
* export const Media: CollectionConfig = {
|
|
58
|
+
* slug: 'media',
|
|
59
|
+
* upload: {
|
|
60
|
+
* ...conditionalStaticDir(path.resolve(__dirname, '../../public/media')),
|
|
61
|
+
* // other upload config...
|
|
62
|
+
* },
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function conditionalStaticDir(localPath: string): {
|
|
67
|
+
staticDir: string;
|
|
68
|
+
} | Record<string, never>;
|
|
69
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAElC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,IAAI;IAC/B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAUA;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,GAChB;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAE/C"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fjall default configuration helpers for Payload CMS.
|
|
3
|
+
*
|
|
4
|
+
* Provides sensible defaults for AWS Lambda deployments:
|
|
5
|
+
* - CORS configuration based on environment
|
|
6
|
+
* - CSRF configuration for security
|
|
7
|
+
* - Environment detection helpers
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Check if running in a production AWS environment.
|
|
11
|
+
*
|
|
12
|
+
* Detection is based on the presence of MEDIA_BUCKET_NAME which is set
|
|
13
|
+
* by Fjall infrastructure in Lambda environments.
|
|
14
|
+
*/
|
|
15
|
+
export function isProduction() {
|
|
16
|
+
return Boolean(process.env.MEDIA_BUCKET_NAME);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Check if running in AWS Lambda.
|
|
20
|
+
*
|
|
21
|
+
* Uses AWS_LAMBDA_FUNCTION_NAME which is set by the Lambda runtime.
|
|
22
|
+
*/
|
|
23
|
+
export function isLambda() {
|
|
24
|
+
return Boolean(process.env.AWS_LAMBDA_FUNCTION_NAME);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Fjall default configuration spread for Payload buildConfig.
|
|
28
|
+
*
|
|
29
|
+
* Provides:
|
|
30
|
+
* - CORS: Locked to NEXT_PUBLIC_SERVER_URL in production, permissive otherwise
|
|
31
|
+
* - CSRF: Enabled in production with NEXT_PUBLIC_SERVER_URL
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* import { fjallDefaults } from '@fjall/payload'
|
|
36
|
+
*
|
|
37
|
+
* export default buildConfig({
|
|
38
|
+
* ...fjallDefaults(),
|
|
39
|
+
* // your config...
|
|
40
|
+
* })
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function fjallDefaults() {
|
|
44
|
+
const serverUrl = process.env.NEXT_PUBLIC_SERVER_URL;
|
|
45
|
+
return {
|
|
46
|
+
// When custom domain is set (via Lambda env), lock CORS to that domain
|
|
47
|
+
// Otherwise permissive for CloudFront deployments
|
|
48
|
+
cors: serverUrl ? [serverUrl] : ["*"],
|
|
49
|
+
// CSRF protection - only enable when we have a known origin
|
|
50
|
+
csrf: serverUrl ? [serverUrl] : [],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get the conditional staticDir configuration for Media collections.
|
|
55
|
+
*
|
|
56
|
+
* In production (Lambda), S3 storage is used and staticDir should be omitted.
|
|
57
|
+
* In local development, uploads go to the local filesystem.
|
|
58
|
+
*
|
|
59
|
+
* @param localPath - The local path for development (e.g., './public/media')
|
|
60
|
+
* @returns Object with staticDir for local dev, empty object for production
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* import { conditionalStaticDir } from '@fjall/payload'
|
|
65
|
+
* import path from 'path'
|
|
66
|
+
*
|
|
67
|
+
* export const Media: CollectionConfig = {
|
|
68
|
+
* slug: 'media',
|
|
69
|
+
* upload: {
|
|
70
|
+
* ...conditionalStaticDir(path.resolve(__dirname, '../../public/media')),
|
|
71
|
+
* // other upload config...
|
|
72
|
+
* },
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export function conditionalStaticDir(localPath) {
|
|
77
|
+
return isProduction() ? {} : { staticDir: localPath };
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ;IACtB,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,aAAa;IAI3B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;IAErD,OAAO;QACL,uEAAuE;QACvE,kDAAkD;QAClD,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACrC,4DAA4D;QAC5D,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;KACnC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,oBAAoB,CAClC,SAAiB;IAEjB,OAAO,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AACxD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fjall/payload - Fjall AWS adapters and utilities for Payload CMS
|
|
3
|
+
*
|
|
4
|
+
* This package provides AWS-specific adapters and helpers for deploying
|
|
5
|
+
* Payload CMS applications to AWS Lambda via Fjall.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* // payload.config.ts
|
|
10
|
+
* import {
|
|
11
|
+
* fjallPostgresAdapter,
|
|
12
|
+
* awsS3Storage,
|
|
13
|
+
* fjallDefaults,
|
|
14
|
+
* isProduction
|
|
15
|
+
* } from '@fjall/payload'
|
|
16
|
+
* import { migrations } from './migrations'
|
|
17
|
+
*
|
|
18
|
+
* const db = await fjallPostgresAdapter({
|
|
19
|
+
* migrationDir: './src/migrations',
|
|
20
|
+
* prodMigrations: migrations,
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* export default buildConfig({
|
|
24
|
+
* ...fjallDefaults(),
|
|
25
|
+
* db,
|
|
26
|
+
* plugins: [
|
|
27
|
+
* awsS3Storage(),
|
|
28
|
+
* // other plugins...
|
|
29
|
+
* ],
|
|
30
|
+
* // your config...
|
|
31
|
+
* })
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export { fjallPostgresAdapter, type FjallPostgresAdapterOptions, } from "./adapters/postgres.js";
|
|
35
|
+
export { fetchSecretField } from "./adapters/secrets.js";
|
|
36
|
+
export { awsS3Storage, type AwsS3StorageOptions } from "./storage/s3.js";
|
|
37
|
+
export { fjallDefaults, isProduction, isLambda, conditionalStaticDir, } from "./config/defaults.js";
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAGH,OAAO,EACL,oBAAoB,EACpB,KAAK,2BAA2B,GACjC,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAGzE,OAAO,EACL,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,oBAAoB,GACrB,MAAM,sBAAsB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fjall/payload - Fjall AWS adapters and utilities for Payload CMS
|
|
3
|
+
*
|
|
4
|
+
* This package provides AWS-specific adapters and helpers for deploying
|
|
5
|
+
* Payload CMS applications to AWS Lambda via Fjall.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* // payload.config.ts
|
|
10
|
+
* import {
|
|
11
|
+
* fjallPostgresAdapter,
|
|
12
|
+
* awsS3Storage,
|
|
13
|
+
* fjallDefaults,
|
|
14
|
+
* isProduction
|
|
15
|
+
* } from '@fjall/payload'
|
|
16
|
+
* import { migrations } from './migrations'
|
|
17
|
+
*
|
|
18
|
+
* const db = await fjallPostgresAdapter({
|
|
19
|
+
* migrationDir: './src/migrations',
|
|
20
|
+
* prodMigrations: migrations,
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* export default buildConfig({
|
|
24
|
+
* ...fjallDefaults(),
|
|
25
|
+
* db,
|
|
26
|
+
* plugins: [
|
|
27
|
+
* awsS3Storage(),
|
|
28
|
+
* // other plugins...
|
|
29
|
+
* ],
|
|
30
|
+
* // your config...
|
|
31
|
+
* })
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
// Database adapter
|
|
35
|
+
export { fjallPostgresAdapter, } from "./adapters/postgres.js";
|
|
36
|
+
// AWS Secrets helper
|
|
37
|
+
export { fetchSecretField } from "./adapters/secrets.js";
|
|
38
|
+
// S3 storage plugin
|
|
39
|
+
export { awsS3Storage } from "./storage/s3.js";
|
|
40
|
+
// Configuration helpers
|
|
41
|
+
export { fjallDefaults, isProduction, isLambda, conditionalStaticDir, } from "./config/defaults.js";
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,mBAAmB;AACnB,OAAO,EACL,oBAAoB,GAErB,MAAM,wBAAwB,CAAC;AAEhC,qBAAqB;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAA4B,MAAM,iBAAiB,CAAC;AAEzE,wBAAwB;AACxB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,oBAAoB,GACrB,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fjall S3 storage configuration for Payload CMS.
|
|
3
|
+
*
|
|
4
|
+
* Wraps @payloadcms/storage-s3 with AWS Lambda-specific defaults:
|
|
5
|
+
* - Uses MEDIA_BUCKET_NAME environment variable from Fjall infrastructure
|
|
6
|
+
* - Enables/disables local storage based on environment
|
|
7
|
+
* - Uses AWS_REGION for automatic region configuration
|
|
8
|
+
*/
|
|
9
|
+
import type { Plugin } from "payload";
|
|
10
|
+
/**
|
|
11
|
+
* Options for the Fjall S3 storage plugin.
|
|
12
|
+
*/
|
|
13
|
+
export interface AwsS3StorageOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Collection slugs to enable S3 storage for.
|
|
16
|
+
* @default ['media']
|
|
17
|
+
*/
|
|
18
|
+
collections?: string[];
|
|
19
|
+
/**
|
|
20
|
+
* S3 key prefix for uploaded files.
|
|
21
|
+
* @default 'media'
|
|
22
|
+
*/
|
|
23
|
+
prefix?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Custom bucket name. If not provided, uses MEDIA_BUCKET_NAME env var.
|
|
26
|
+
*/
|
|
27
|
+
bucket?: string;
|
|
28
|
+
/**
|
|
29
|
+
* AWS region. If not provided, uses AWS_REGION env var.
|
|
30
|
+
* @default 'us-east-1'
|
|
31
|
+
*/
|
|
32
|
+
region?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Create an S3 storage plugin configured for Fjall/AWS Lambda.
|
|
36
|
+
*
|
|
37
|
+
* This plugin is always registered so Payload includes S3 client components
|
|
38
|
+
* in the importMap at build time. In local development (when MEDIA_BUCKET_NAME
|
|
39
|
+
* is not set), uploads fall back to disk storage.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* import { awsS3Storage } from '@fjall/payload'
|
|
44
|
+
*
|
|
45
|
+
* export const plugins: Plugin[] = [
|
|
46
|
+
* awsS3Storage(),
|
|
47
|
+
* // other plugins...
|
|
48
|
+
* ]
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function awsS3Storage(options?: AwsS3StorageOptions): Plugin;
|
|
52
|
+
//# sourceMappingURL=s3.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../src/storage/s3.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAEvB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CA0BtE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fjall S3 storage configuration for Payload CMS.
|
|
3
|
+
*
|
|
4
|
+
* Wraps @payloadcms/storage-s3 with AWS Lambda-specific defaults:
|
|
5
|
+
* - Uses MEDIA_BUCKET_NAME environment variable from Fjall infrastructure
|
|
6
|
+
* - Enables/disables local storage based on environment
|
|
7
|
+
* - Uses AWS_REGION for automatic region configuration
|
|
8
|
+
*/
|
|
9
|
+
import { s3Storage } from "@payloadcms/storage-s3";
|
|
10
|
+
/**
|
|
11
|
+
* Create an S3 storage plugin configured for Fjall/AWS Lambda.
|
|
12
|
+
*
|
|
13
|
+
* This plugin is always registered so Payload includes S3 client components
|
|
14
|
+
* in the importMap at build time. In local development (when MEDIA_BUCKET_NAME
|
|
15
|
+
* is not set), uploads fall back to disk storage.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { awsS3Storage } from '@fjall/payload'
|
|
20
|
+
*
|
|
21
|
+
* export const plugins: Plugin[] = [
|
|
22
|
+
* awsS3Storage(),
|
|
23
|
+
* // other plugins...
|
|
24
|
+
* ]
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function awsS3Storage(options = {}) {
|
|
28
|
+
const { collections = ["media"], prefix = "media", bucket = process.env.MEDIA_BUCKET_NAME, region = process.env.AWS_REGION || "us-east-1", } = options;
|
|
29
|
+
// Build collection config - disable local storage when bucket is configured
|
|
30
|
+
const collectionConfig = Object.fromEntries(collections.map((slug) => [
|
|
31
|
+
slug,
|
|
32
|
+
{ prefix, disableLocalStorage: !!bucket },
|
|
33
|
+
]));
|
|
34
|
+
return s3Storage({
|
|
35
|
+
collections: collectionConfig,
|
|
36
|
+
// Use placeholder bucket for local dev - plugin is registered but won't be used
|
|
37
|
+
bucket: bucket || "placeholder",
|
|
38
|
+
config: {
|
|
39
|
+
// When running in Lambda with IAM role, credentials are automatic
|
|
40
|
+
// For local testing with S3, set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
|
|
41
|
+
region,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=s3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3.js","sourceRoot":"","sources":["../../src/storage/s3.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AA+BnD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,YAAY,CAAC,UAA+B,EAAE;IAC5D,MAAM,EACJ,WAAW,GAAG,CAAC,OAAO,CAAC,EACvB,MAAM,GAAG,OAAO,EAChB,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,EACtC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,WAAW,GAC/C,GAAG,OAAO,CAAC;IAEZ,4EAA4E;IAC5E,MAAM,gBAAgB,GAAG,MAAM,CAAC,WAAW,CACzC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACxB,IAAI;QACJ,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE;KAC1C,CAAC,CACH,CAAC;IAEF,OAAO,SAAS,CAAC;QACf,WAAW,EAAE,gBAAgB;QAC7B,gFAAgF;QAChF,MAAM,EAAE,MAAM,IAAI,aAAa;QAC/B,MAAM,EAAE;YACN,kEAAkE;YAClE,6EAA6E;YAC7E,MAAM;SACP;KACF,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fjall/payload",
|
|
3
|
+
"version": "0.87.4",
|
|
4
|
+
"description": "Fjall AWS adapters and utilities for Payload CMS",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist/"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"clean": "rm -rf ./dist",
|
|
19
|
+
"build": "npm run clean && npx tsc",
|
|
20
|
+
"watch": "npm run build && npx tsc-watch",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
23
|
+
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
24
|
+
"lint": "eslint src/",
|
|
25
|
+
"lint:fix": "eslint src/ --fix"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18.0.0"
|
|
29
|
+
},
|
|
30
|
+
"author": "",
|
|
31
|
+
"license": "ISC",
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@payloadcms/db-postgres": "^3.0.0",
|
|
34
|
+
"@payloadcms/storage-s3": "^3.0.0",
|
|
35
|
+
"payload": "^3.0.0"
|
|
36
|
+
},
|
|
37
|
+
"peerDependenciesMeta": {
|
|
38
|
+
"@payloadcms/db-postgres": {
|
|
39
|
+
"optional": false
|
|
40
|
+
},
|
|
41
|
+
"@payloadcms/storage-s3": {
|
|
42
|
+
"optional": true
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@payloadcms/db-postgres": "^3.73.0",
|
|
47
|
+
"@payloadcms/storage-s3": "^3.73.0",
|
|
48
|
+
"@types/node": "^22.0.0",
|
|
49
|
+
"payload": "^3.73.0",
|
|
50
|
+
"typescript": "^5.8.2"
|
|
51
|
+
},
|
|
52
|
+
"gitHead": "0f9a9509a197b92e469b05719551e63c61b044f3"
|
|
53
|
+
}
|