Fix test suite and improve security documentation

- Removed broken test that referenced deleted customEndpointHandler
- Removed unused import for createPayloadRequest
- Added production security best practices to README including API key authentication example
- Added rate limiting example for production use
- Added client-side caching recommendations for performance optimization

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-03 14:24:10 +02:00
parent a6712666af
commit 118f1ee2ed
2 changed files with 71 additions and 18 deletions

View File

@@ -176,6 +176,44 @@ access: {
}
```
**Production Security Best Practices:**
For production environments, consider implementing these additional security measures:
```typescript
// Example: API key authentication for external services
collectionOverrides: {
access: {
read: ({ req }) => {
// Check for API key in headers for service-to-service calls
const apiKey = req.headers['x-api-key']
if (apiKey && apiKey === process.env.FEATURE_FLAGS_API_KEY) {
return true
}
// Fall back to user authentication
return !!req.user
}
}
}
```
**Rate Limiting:** Use Payload's built-in rate limiting or implement middleware:
```typescript
// Example with express-rate-limit
import rateLimit from 'express-rate-limit'
const featureFlagLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per windowMs
standardHeaders: true,
legacyHeaders: false,
})
// Apply to your API routes
app.use('/api/feature-flags', featureFlagLimiter)
```
**Important:** The plugin uses Payload's native REST API for the collection, which respects all access control rules.
## Usage
@@ -448,6 +486,38 @@ if (flag.enabled && flag.variants) {
}
```
## Performance Considerations
### Client-Side Caching
For improved performance, consider implementing client-side caching when fetching feature flags:
```typescript
// Example: Simple cache with TTL
class FeatureFlagCache {
private cache = new Map<string, { data: any; expiry: number }>()
private ttl = 5 * 60 * 1000 // 5 minutes
async get(key: string, fetcher: () => Promise<any>) {
const cached = this.cache.get(key)
if (cached && cached.expiry > Date.now()) {
return cached.data
}
const data = await fetcher()
this.cache.set(key, { data, expiry: Date.now() + this.ttl })
return data
}
}
const flagCache = new FeatureFlagCache()
// Use with the hooks
const flags = await flagCache.get('all-flags', () =>
fetch('/api/feature-flags?limit=1000').then(r => r.json())
)
```
## Migration
### Disabling the Plugin

View File

@@ -1,11 +1,9 @@
import type { Payload } from 'payload'
import config from '@payload-config'
import { createPayloadRequest, getPayload } from 'payload'
import { getPayload } from 'payload'
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
import { customEndpointHandler } from '../src/endpoints/customEndpointHandler.js'
let payload: Payload
afterAll(async () => {
@@ -17,21 +15,6 @@ beforeAll(async () => {
})
describe('Plugin integration tests', () => {
test('should query custom endpoint added by plugin', async () => {
const request = new Request('http://localhost:3000/api/my-plugin-endpoint', {
method: 'GET',
})
const payloadRequest = await createPayloadRequest({ config, request })
const response = await customEndpointHandler(payloadRequest)
expect(response.status).toBe(200)
const data = await response.json()
expect(data).toMatchObject({
message: 'Hello from custom endpoint',
})
})
test('can create post with custom text field added by plugin', async () => {
const post = await payload.create({
collection: 'posts',