Plugin Development
Create custom plugins to extend AutoDeployBase with your own functionality.
Quick Start
Create a Plugin
npx autodeploybase plugin create my-plugin
This generates:
plugins/my-plugin/
├── manifest.json # Plugin metadata
├── generator.js # Generation logic
├── templates/ # Template files
│ └── .gitkeep
└── README.md
Plugin Structure
manifest.json
The plugin manifest defines metadata and configuration:
manifest.json
{
"name": "my-plugin",
"version": "1.0.0",
"description": "My awesome plugin",
"author": "Your Name",
"license": "MIT",
"category": "feature",
"tier": "public",
"frameworks": ["next", "nuxt", "sveltekit"],
"databases": ["postgresql", "mongodb"],
"dependencies": {
"axios": "^1.6.0",
"zod": "^3.22.0"
},
"settings": {
"schema": {
"apiUrl": {
"type": "string",
"label": "API URL",
"default": "https://api.example.com",
"required": true
},
"apiKey": {
"type": "string",
"label": "API Key",
"secret": true
}
}
},
"adminMenu": {
"label": "My Plugin",
"icon": "Plug",
"href": "/admin/my-plugin"
}
}
generator.js
The generator runs during project generation:
generator.js
import { sdk } from 'autodeploybase';
export default async function generate(context) {
const { projectPath, framework, settings } = context;
// Copy templates
await sdk.copyTemplates({
source: './templates',
destination: projectPath,
framework,
variables: {
apiUrl: settings.apiUrl
}
});
// Register API routes
await sdk.registerAPIRoutes({
routes: [{ path: '/api/my-plugin', handler: 'my-plugin/api' }]
});
// Register admin menu
await sdk.registerAdminMenu({
id: 'my-plugin',
label: 'My Plugin',
icon: 'Plug',
href: '/admin/my-plugin'
});
// Add Prisma schema
await sdk.registerPrismaSchema(`
model MyPluginData {
id String @id @default(cuid())
name String
createdAt DateTime @default(now())
}
`);
// Register settings
await sdk.registerSettings({
pluginId: 'my-plugin',
schema: {
apiUrl: { type: 'string', label: 'API URL' }
}
});
}
SDK Functions
copyTemplates
Copy template files to the project:
await sdk.copyTemplates({
source: './templates',
destination: context.projectPath,
framework: context.framework,
variables: {
pluginName: 'my-plugin',
version: '1.0.0'
},
ignore: ['*.test.ts']
});
registerAPIRoutes
Register API endpoints:
await sdk.registerAPIRoutes({
routes: [
{
path: '/api/my-plugin',
handler: 'plugins/my-plugin/api/route',
methods: ['GET', 'POST']
},
{
path: '/api/my-plugin/:id',
handler: 'plugins/my-plugin/api/[id]/route',
methods: ['GET', 'PUT', 'DELETE']
}
]
});
registerAdminMenu
Add admin sidebar items:
await sdk.registerAdminMenu({
id: 'my-plugin',
label: 'My Plugin',
icon: 'Plug',
href: '/admin/my-plugin',
children: [
{ id: 'settings', label: 'Settings', href: '/admin/my-plugin/settings' },
{ id: 'logs', label: 'Logs', href: '/admin/my-plugin/logs' }
]
});
registerPrismaSchema
Add database models:
await sdk.registerPrismaSchema(`
model Notification {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id])
message String
read Boolean @default(false)
createdAt DateTime @default(now())
}
`);
registerSettings
Define plugin settings:
await sdk.registerSettings({
pluginId: 'my-plugin',
schema: {
enabled: {
type: 'boolean',
label: 'Enable Plugin',
default: true
},
webhookUrl: {
type: 'string',
label: 'Webhook URL',
validation: 'url'
},
maxRetries: {
type: 'number',
label: 'Max Retries',
default: 3,
min: 1,
max: 10
}
}
});
registerProvider
Register React context providers:
await sdk.registerProvider({
name: 'MyPluginProvider',
import: '@/plugins/my-plugin/provider',
order: 10
});
registerCSS
Add CSS variables:
await sdk.registerCSS({
variables: {
'--my-plugin-primary': '#007bff',
'--my-plugin-secondary': '#6c757d'
}
});
Template Files
Directory Structure
templates/
├── next/ # Next.js specific
│ └── app/
│ └── admin/
│ └── my-plugin/
│ └── page.tsx
├── nuxt/ # Nuxt specific
│ └── pages/
│ └── admin/
│ └── my-plugin.vue
├── shared/ # All frameworks
│ └── lib/
│ └── my-plugin.ts
└── prisma/
└── schema.prisma # Database schema
Template Variables
Use Handlebars syntax:
templates/shared/lib/my-plugin.ts
// {{pluginName}} v{{version}}
const API_URL = '{{apiUrl}}';
export async function fetchData() {
const response = await fetch(API_URL);
return response.json();
}
Conditional Content
{{#if settings.enableLogging}}
import { logger } from '@/lib/logger';
{{/if}}
export function doSomething() {
{{#if settings.enableLogging}}
logger.info('Doing something');
{{/if}}
// ...
}
Framework Detection
Handle framework differences:
export default async function generate(context) {
const { framework } = context;
if (framework === 'next') {
await sdk.copyTemplates({
source: './templates/next',
destination: context.projectPath
});
} else if (framework === 'nuxt') {
await sdk.copyTemplates({
source: './templates/nuxt',
destination: context.projectPath
});
}
// Shared files
await sdk.copyTemplates({
source: './templates/shared',
destination: context.projectPath
});
}
Testing Plugins
Unit Tests
tests/generator.test.js
import { describe, it, expect } from 'vitest';
import generate from '../generator.js';
describe('my-plugin', () => {
it('should generate files', async () => {
const context = {
projectPath: '/tmp/test-project',
framework: 'next',
settings: { apiUrl: 'https://api.test.com' }
};
await generate(context);
// Assert files were created
expect(fs.existsSync('/tmp/test-project/lib/my-plugin.ts')).toBe(true);
});
});
Integration Tests
# Create test project
npx autodeploybase init test-project --plugins ./plugins/my-plugin
# Verify generation
cd test-project
npm run typecheck
npm run test
Publishing
To npm
cd plugins/my-plugin
npm publish
To AutoDeployBase Registry
npx autodeploybase plugin publish
As Premium Plugin
Contact us for premium plugin distribution.
Best Practices
- Keep it focused - One plugin, one purpose
- Support multiple frameworks - Use framework detection
- Validate settings - Check required configuration
- Document everything - Include README and examples
- Test thoroughly - Unit and integration tests
- Version properly - Follow semver
Example: Notifications Plugin
Complete example:
generator.js
import { sdk } from 'autodeploybase';
export default async function generate(context) {
const { projectPath, framework, settings } = context;
// Copy template files
await sdk.copyTemplates({
source: `./templates/${framework}`,
destination: projectPath,
variables: settings
});
await sdk.copyTemplates({
source: './templates/shared',
destination: projectPath,
variables: settings
});
// Register database schema
await sdk.registerPrismaSchema(`
model Notification {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id])
type String
message String
data Json?
read Boolean @default(false)
createdAt DateTime @default(now())
}
`);
// Register API routes
await sdk.registerAPIRoutes({
routes: [
{ path: '/api/notifications', methods: ['GET', 'POST'] },
{ path: '/api/notifications/:id', methods: ['PATCH', 'DELETE'] },
{ path: '/api/notifications/mark-read', methods: ['POST'] }
]
});
// Add admin menu
await sdk.registerAdminMenu({
id: 'notifications',
label: 'Notifications',
icon: 'Bell',
href: '/admin/notifications'
});
// Register settings
await sdk.registerSettings({
pluginId: 'notifications',
schema: {
enabled: { type: 'boolean', default: true },
maxPerUser: { type: 'number', default: 100 },
retentionDays: { type: 'number', default: 30 }
}
});
// Register provider for real-time
if (settings.realtime) {
await sdk.registerProvider({
name: 'NotificationProvider',
import: '@/plugins/notifications/provider'
});
}
}