Skip to main content

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

  1. Keep it focused - One plugin, one purpose
  2. Support multiple frameworks - Use framework detection
  3. Validate settings - Check required configuration
  4. Document everything - Include README and examples
  5. Test thoroughly - Unit and integration tests
  6. 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'
});
}
}