mirror of
https://github.com/xtr-dev/payload-feature-flags.git
synced 2025-12-08 00:13:23 +00:00
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:
70
README.md
70
README.md
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user