# @fjall/payload

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.

## Installation

```bash
pnpm add @fjall/payload @payloadcms/storage-s3
```

## Features

- **`fjallPostgresAdapter`** - PostgreSQL adapter with AWS Secrets Manager integration
- **`awsS3Storage`** - S3 storage plugin for media uploads
- **`fjallDefaults`** - Sensible CORS/CSRF defaults for Lambda
- **`isProduction`** / **`isLambda`** - Environment detection helpers

## Usage

### Database Adapter

```typescript
// payload.config.ts
import { buildConfig } from "payload";
import { fjallPostgresAdapter, fjallDefaults } from "@fjall/payload";
import { migrations } from "./migrations";

export default buildConfig({
  ...fjallDefaults(),
  db: await fjallPostgresAdapter({
    migrationDir: "./src/migrations",
    prodMigrations: migrations,
  }),
  // ... rest of config
});
```

The adapter automatically:

- Fetches database credentials from AWS Secrets Manager in Lambda
- Falls back to `DATABASE_URL` for local development
- Configures SSL for Aurora PostgreSQL

### S3 Storage Plugin

```typescript
// plugins/index.ts
import { awsS3Storage } from "@fjall/payload";
import { Plugin } from "payload";

export const plugins: Plugin[] = [awsS3Storage()];
```

The plugin automatically:

- Uses `MEDIA_BUCKET_NAME` environment variable set by Fjall infrastructure
- Handles presigned URLs for uploads
- Falls back to local filesystem in development

### Environment Detection

```typescript
import { isProduction, isLambda } from "@fjall/payload";

// Conditional logic based on environment
if (isProduction()) {
  // Running in AWS with Fjall infrastructure
}

if (isLambda()) {
  // Running in AWS Lambda runtime
}
```

### Conditional Static Directory

For Media collections that need local uploads in dev but S3 in production:

```typescript
import { isProduction } from "@fjall/payload";
import path from "path";

export const Media: CollectionConfig = {
  slug: "media",
  upload: {
    ...(isProduction()
      ? {}
      : {
          staticDir: path.resolve(__dirname, "../../public/media"),
        }),
  },
};
```

## Environment Variables

### Production (Lambda)

Set automatically by Fjall infrastructure:

| Variable            | Description                   |
| ------------------- | ----------------------------- |
| `DATABASE_HOST`     | Aurora PostgreSQL endpoint    |
| `DATABASE_PORT`     | Database port (default: 5432) |
| `DATABASE_NAME`     | Database name                 |
| `DATABASE_SSL`      | Enable SSL (`true`)           |
| `MEDIA_BUCKET_NAME` | S3 bucket for uploads         |

Credentials fetched from Secrets Manager:

- `DATABASE_USERNAME`
- `DATABASE_PASSWORD`

### Development

| Variable       | Description                       |
| -------------- | --------------------------------- |
| `DATABASE_URL` | Full PostgreSQL connection string |

## Auto-Configuration

When you run `fjall deploy` on a Payload project, the CLI automatically:

1. Detects the Payload pattern
2. Installs `@fjall/payload` and `@payloadcms/storage-s3`
3. Patches `payload.config.ts` to use `fjallPostgresAdapter`
4. Patches or creates `plugins/index.ts` with S3 storage
5. Configures `next.config.js` for Lambda (standalone output)
6. Generates `open-next.config.ts` for OpenNext

No manual configuration required - just run `fjall deploy`.

## Licence

Proprietary — see [LICENSE](./LICENSE).
