mirror of
https://github.com/xtr-dev/payload-feature-flags.git
synced 2025-12-08 00:13:23 +00:00
Bump version to 0.0.5
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -47,3 +47,4 @@ yarn-error.log*
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
/dev.db
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { mongooseAdapter } from '@payloadcms/db-mongodb'
|
||||
|
||||
import { lexicalEditor } from '@payloadcms/richtext-lexical'
|
||||
import { MongoMemoryReplSet } from 'mongodb-memory-server'
|
||||
import path from 'path'
|
||||
import { buildConfig } from 'payload'
|
||||
import { payloadFeatureFlags } from '../src/index.js'
|
||||
@@ -9,6 +8,7 @@ import { fileURLToPath } from 'url'
|
||||
|
||||
import { testEmailAdapter } from './helpers/testEmailAdapter.js'
|
||||
import { seed } from './seed.js'
|
||||
import {sqliteAdapter} from "@payloadcms/db-sqlite"
|
||||
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
@@ -17,221 +17,203 @@ if (!process.env.ROOT_DIR) {
|
||||
process.env.ROOT_DIR = dirname
|
||||
}
|
||||
|
||||
const buildConfigWithMemoryDB = async () => {
|
||||
// Use in-memory MongoDB for both test and development
|
||||
if (process.env.NODE_ENV === 'test' || process.env.NODE_ENV !== 'production') {
|
||||
console.log('🗃️ Starting MongoDB Memory Server...')
|
||||
const memoryDB = await MongoMemoryReplSet.create({
|
||||
replSet: {
|
||||
count: 1,
|
||||
dbName: 'payload-feature-flags-dev',
|
||||
export default buildConfig({
|
||||
admin: {
|
||||
importMap: {
|
||||
baseDir: path.resolve(dirname),
|
||||
},
|
||||
},
|
||||
collections: [
|
||||
{
|
||||
slug: 'posts',
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
},
|
||||
})
|
||||
|
||||
const uri = memoryDB.getUri()
|
||||
process.env.DATABASE_URI = `${uri}&retryWrites=true`
|
||||
console.log('✅ MongoDB Memory Server started successfully')
|
||||
}
|
||||
|
||||
return buildConfig({
|
||||
admin: {
|
||||
importMap: {
|
||||
baseDir: path.resolve(dirname),
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
type: 'select',
|
||||
options: ['draft', 'published'],
|
||||
defaultValue: 'draft',
|
||||
},
|
||||
{
|
||||
name: 'publishedAt',
|
||||
type: 'date',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'pages',
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
type: 'text',
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
},
|
||||
{
|
||||
name: 'layout',
|
||||
type: 'select',
|
||||
options: ['default', 'landing', 'sidebar'],
|
||||
defaultValue: 'default',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'users',
|
||||
admin: {
|
||||
useAsTitle: 'email',
|
||||
},
|
||||
auth: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'role',
|
||||
type: 'select',
|
||||
options: ['admin', 'editor', 'user'],
|
||||
defaultValue: 'user',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'media',
|
||||
fields: [
|
||||
{
|
||||
name: 'alt',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
upload: {
|
||||
staticDir: path.resolve(dirname, 'media'),
|
||||
},
|
||||
},
|
||||
collections: [
|
||||
{
|
||||
slug: 'posts',
|
||||
],
|
||||
db: sqliteAdapter({
|
||||
client: {
|
||||
url: process.env.DATABASE_URI || 'file:./dev.db',
|
||||
},
|
||||
}),
|
||||
editor: lexicalEditor(),
|
||||
email: testEmailAdapter,
|
||||
onInit: async (payload) => {
|
||||
await seed(payload)
|
||||
},
|
||||
plugins: [
|
||||
payloadFeatureFlags({
|
||||
// Enable all features
|
||||
enableRollouts: true,
|
||||
enableVariants: true,
|
||||
enableApi: true,
|
||||
defaultValue: false,
|
||||
|
||||
// Custom collection configuration
|
||||
collectionOverrides: {
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
useAsTitle: 'name',
|
||||
group: 'Configuration',
|
||||
description: 'Manage feature flags for the development environment',
|
||||
},
|
||||
fields: [
|
||||
access: {
|
||||
// Only authenticated users can read/manage feature flags
|
||||
read: ({ req: { user } }) => !!user,
|
||||
create: ({ req: { user } }) => !!user,
|
||||
update: ({ req: { user } }) => user?.role === 'admin',
|
||||
delete: ({ req: { user } }) => user?.role === 'admin',
|
||||
},
|
||||
fields: ({ defaultFields }) => [
|
||||
...defaultFields,
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
name: 'environment',
|
||||
type: 'select',
|
||||
options: ['draft', 'published'],
|
||||
defaultValue: 'draft',
|
||||
options: [
|
||||
{ label: 'Development', value: 'development' },
|
||||
{ label: 'Staging', value: 'staging' },
|
||||
{ label: 'Production', value: 'production' },
|
||||
],
|
||||
required: true,
|
||||
defaultValue: 'development',
|
||||
admin: {
|
||||
description: 'Which environment this flag applies to',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'publishedAt',
|
||||
name: 'owner',
|
||||
type: 'relationship',
|
||||
relationTo: 'users',
|
||||
admin: {
|
||||
description: 'Team member responsible for this feature flag',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'expiresAt',
|
||||
type: 'date',
|
||||
admin: {
|
||||
description: 'Optional expiration date for temporary flags',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'jiraTicket',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Related JIRA ticket or issue number',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'pages',
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
type: 'text',
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
},
|
||||
{
|
||||
name: 'layout',
|
||||
type: 'select',
|
||||
options: ['default', 'landing', 'sidebar'],
|
||||
defaultValue: 'default',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'users',
|
||||
admin: {
|
||||
useAsTitle: 'email',
|
||||
},
|
||||
auth: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'role',
|
||||
type: 'select',
|
||||
options: ['admin', 'editor', 'user'],
|
||||
defaultValue: 'user',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'media',
|
||||
fields: [
|
||||
{
|
||||
name: 'alt',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
upload: {
|
||||
staticDir: path.resolve(dirname, 'media'),
|
||||
},
|
||||
},
|
||||
],
|
||||
db: mongooseAdapter({
|
||||
ensureIndexes: true,
|
||||
url: process.env.DATABASE_URI || 'mongodb://localhost/payload-feature-flags-dev',
|
||||
}),
|
||||
editor: lexicalEditor(),
|
||||
email: testEmailAdapter,
|
||||
onInit: async (payload) => {
|
||||
await seed(payload)
|
||||
},
|
||||
plugins: [
|
||||
payloadFeatureFlags({
|
||||
// Enable all features
|
||||
enableRollouts: true,
|
||||
enableVariants: true,
|
||||
enableApi: true,
|
||||
defaultValue: false,
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
async ({ data, req, operation }) => {
|
||||
// Auto-assign current user as owner for new flags
|
||||
if (operation === 'create' && !data.owner && req.user) {
|
||||
data.owner = req.user.id
|
||||
}
|
||||
|
||||
// Custom collection configuration
|
||||
collectionOverrides: {
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
group: 'Configuration',
|
||||
description: 'Manage feature flags for the development environment',
|
||||
},
|
||||
access: {
|
||||
// Only authenticated users can read/manage feature flags
|
||||
read: ({ req: { user } }) => !!user,
|
||||
create: ({ req: { user } }) => !!user,
|
||||
update: ({ req: { user } }) => user?.role === 'admin',
|
||||
delete: ({ req: { user } }) => user?.role === 'admin',
|
||||
},
|
||||
fields: ({ defaultFields }) => [
|
||||
...defaultFields,
|
||||
{
|
||||
name: 'environment',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: 'Development', value: 'development' },
|
||||
{ label: 'Staging', value: 'staging' },
|
||||
{ label: 'Production', value: 'production' },
|
||||
],
|
||||
required: true,
|
||||
defaultValue: 'development',
|
||||
admin: {
|
||||
description: 'Which environment this flag applies to',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'owner',
|
||||
type: 'relationship',
|
||||
relationTo: 'users',
|
||||
admin: {
|
||||
description: 'Team member responsible for this feature flag',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'expiresAt',
|
||||
type: 'date',
|
||||
admin: {
|
||||
description: 'Optional expiration date for temporary flags',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'jiraTicket',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Related JIRA ticket or issue number',
|
||||
},
|
||||
// Log flag changes for audit trail
|
||||
if (req.user) {
|
||||
console.log(`Feature flag "${data.name}" ${operation} by ${req.user.email}`)
|
||||
}
|
||||
|
||||
return data
|
||||
},
|
||||
],
|
||||
afterChange: [
|
||||
async ({ doc, req, operation }) => {
|
||||
// Send notification for critical flag changes
|
||||
if (doc.environment === 'production' && req.user) {
|
||||
console.log(`🚨 Production feature flag "${doc.name}" was ${operation === 'create' ? 'created' : 'modified'} by ${req.user.email}`)
|
||||
}
|
||||
},
|
||||
],
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
async ({ data, req, operation }) => {
|
||||
// Auto-assign current user as owner for new flags
|
||||
if (operation === 'create' && !data.owner && req.user) {
|
||||
data.owner = req.user.id
|
||||
}
|
||||
|
||||
// Log flag changes for audit trail
|
||||
if (req.user) {
|
||||
console.log(`Feature flag "${data.name}" ${operation} by ${req.user.email}`)
|
||||
}
|
||||
|
||||
return data
|
||||
},
|
||||
],
|
||||
afterChange: [
|
||||
async ({ doc, req, operation }) => {
|
||||
// Send notification for critical flag changes
|
||||
if (doc.environment === 'production' && req.user) {
|
||||
console.log(`🚨 Production feature flag "${doc.name}" was ${operation === 'create' ? 'created' : 'modified'} by ${req.user.email}`)
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
secret: process.env.PAYLOAD_SECRET || 'dev-secret-key-change-in-production',
|
||||
sharp,
|
||||
typescript: {
|
||||
outputFile: path.resolve(dirname, 'payload-types.ts'),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export default buildConfigWithMemoryDB()
|
||||
},
|
||||
}),
|
||||
],
|
||||
secret: process.env.PAYLOAD_SECRET || 'dev-secret-key-change-in-production',
|
||||
sharp,
|
||||
typescript: {
|
||||
outputFile: path.resolve(dirname, 'payload-types.ts'),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@xtr-dev/payload-feature-flags",
|
||||
"version": "0.0.4",
|
||||
"version": "0.0.5",
|
||||
"description": "Feature flags plugin for Payload CMS - manage feature toggles, A/B tests, and gradual rollouts",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
||||
Reference in New Issue
Block a user