Plugins
Extend Flashcore with middleware, custom indexes, and model extensions.
Flashcore has a plugin system for adding middleware, model extensions, client extensions, and custom index providers.
Defining a Plugin
Use definePlugin from robo.js/flashcore:
import { definePlugin } from 'robo.js/flashcore'
export const auditPlugin = () => definePlugin({
name: 'audit',
setup(ctx) {
ctx.state.log = []
},
middleware: {
async create(params, next) {
const result = await next()
this.state.log.push({ op: 'create', model: params.model, at: Date.now() })
return result
},
async delete(params, next) {
const result = await next()
this.state.log.push({ op: 'delete', model: params.model, at: Date.now() })
return result
}
},
clientExtensions: {
getAuditLog() {
return [...this.state.log]
}
}
})import { definePlugin } from 'robo.js/flashcore'
export const auditPlugin = () => definePlugin({
name: 'audit',
setup(ctx) {
ctx.state.log = []
},
middleware: {
async create(params, next) {
const result = await next()
this.state.log.push({ op: 'create', model: params.model, at: Date.now() })
return result
},
async delete(params, next) {
const result = await next()
this.state.log.push({ op: 'delete', model: params.model, at: Date.now() })
return result
}
},
clientExtensions: {
getAuditLog() {
return [...this.state.log]
}
}
})Middleware
Middleware intercepts CRUD operations. Each middleware receives the operation parameters and a next() function to continue the chain.
Supported operations: create, update, delete, findUnique, findMany, count, createMany, updateMany, deleteMany, upsert.
Built-in Middleware
Flashcore provides utility factories for common patterns:
import {
createLoggingMiddleware,
createValidationMiddleware,
forModels,
forOperations
} from 'robo.js/flashcore'
// Log all operations with the default logger
const logging = createLoggingMiddleware()
// Log with a custom logger function
const customLogging = createLoggingMiddleware((message, ...args) => {
console.log(`[DB] ${message}`, ...args)
})
// Only run middleware for specific models
const modelScoped = forModels(['Warning', 'GuildSettings'], logging)
// Only run middleware for specific operations
const writeOnly = forOperations(['create', 'update', 'delete'], logging)
// Custom validation — receives (operation, args) and should throw on invalid data
const validate = createValidationMiddleware((operation, args) => {
if (operation === 'create' && args?.data?.reason?.length < 3) {
throw new Error('Reason must be at least 3 characters')
}
})import {
createLoggingMiddleware,
createValidationMiddleware,
forModels,
forOperations
} from 'robo.js/flashcore'
// Log all operations with the default logger
const logging = createLoggingMiddleware()
// Log with a custom logger function
const customLogging = createLoggingMiddleware((message, ...args) => {
console.log(`[DB] ${message}`, ...args)
})
// Only run middleware for specific models
const modelScoped = forModels(['Warning', 'GuildSettings'], logging)
// Only run middleware for specific operations
const writeOnly = forOperations(['create', 'update', 'delete'], logging)
// Custom validation — receives (operation, args) and should throw on invalid data
const validate = createValidationMiddleware((operation, args) => {
if (operation === 'create' && args?.data?.reason?.length < 3) {
throw new Error('Reason must be at least 3 characters')
}
})Model Extensions
Add custom methods to all models:
export const softDeletePlugin = () => definePlugin({
name: 'soft-delete',
modelExtensions: {
async softDelete(where) {
return this.update({
where,
data: { deletedAt: new Date() }
})
},
async findActive(args) {
return this.findMany({
...args,
where: { ...args?.where, deletedAt: { equals: undefined } }
})
}
}
})export const softDeletePlugin = () => definePlugin({
name: 'soft-delete',
modelExtensions: {
async softDelete(where) {
return this.update({
where,
data: { deletedAt: new Date() }
})
},
async findActive(args) {
return this.findMany({
...args,
where: { ...args?.where, deletedAt: { equals: undefined } }
})
}
}
})Model extension methods are called with this bound to the model instance.
Client Extensions
Add methods to Flashcore.$:
export const statsPlugin = () => definePlugin({
name: 'stats',
setup(ctx) {
ctx.state.opCount = 0
},
middleware: {
async create(params, next) {
this.state.opCount++
return next()
}
},
clientExtensions: {
getOpCount() {
return this.state.opCount
}
}
})
// Usage: Flashcore.$.stats.getOpCount()export const statsPlugin = () => definePlugin({
name: 'stats',
setup(ctx) {
ctx.state.opCount = 0
},
middleware: {
async create(params, next) {
this.state.opCount++
return next()
}
},
clientExtensions: {
getOpCount() {
return this.state.opCount
}
}
})
// Usage: Flashcore.$.stats.getOpCount()Client extensions are namespaced under the plugin name on the $ API.
Custom Index Providers
Define custom index types for specialized queries:
import { defineIndex, createTrieIndex, createFullTextIndex } from 'robo.js/flashcore'
// Built-in trie index for prefix matching
const trie = createTrieIndex()
// Built-in full-text index
const fullText = createFullTextIndex()
// Custom index
const geoIndex = defineIndex({
create: (options) => new GeoIndex(options),
operators: ['nearby', 'withinRadius']
})import { defineIndex, createTrieIndex, createFullTextIndex } from 'robo.js/flashcore'
// Built-in trie index for prefix matching
const trie = createTrieIndex()
// Built-in full-text index
const fullText = createFullTextIndex()
// Custom index
const geoIndex = defineIndex({
create: (options) => new GeoIndex(options),
operators: ['nearby', 'withinRadius']
})Use custom indexes on fields with .indexedWith():
const schema = {
id: f.id(),
name: f.string().indexedWith('trie'),
description: f.string().indexedWith('fullText')
}System API Reference
The Flashcore.$ object exposes system-level methods:
| Method | Description |
|---|---|
$.init(options) | Initialize Flashcore with adapter and config |
$.registerModel(name, schema, options) | Register a model (called by createModel) |
$.introspect() | Get system state: models, capabilities, metrics |
$.checkIntegrity(model, options) | Check index integrity for a model |
$.repair(model, options) | Repair indexes for a model |
$.rebuildIndexes(model) | Rebuild all indexes for a model |
$.flushIndexes() | Flush all index data to disk |
$.preload(models) | Pre-load catalogs and indexes for specified models |
$.validateSchemas() | Detect schema changes since last validation |
$.transaction(fn, options) | Run operations in a transaction |
Some $ methods (like transaction, validateSchemas, and integrity tools) require @robojs/flashcore-extras to be installed. The core framework defines the interfaces, and the extras plugin provides the implementations.
