Context and services
Use the services provided to your plugin's register function.
Context overview
The loader creates a context for each installed plugin and passes it to register(ctx).
| Property | Purpose |
|---|---|
name, version | Installed package identity |
db | Shared Drizzle database instance |
coreSchema | Selected core table definitions |
id(prefix) | Generate an ID using the kernel helper |
hooks.on() | Subscribe to lifecycle events |
settings | Read and write settings |
audit.log() | Record audit data |
jobs | Enqueue jobs and inspect queued work |
storage | Invoice/media upload and download helpers |
scheduler.every() | Register an in-process periodic task |
logger | Plugin-prefixed debug, info, warning, and error logging |
errors | HTTP error helpers |
auth | Password hashing and verification helpers |
inventory | Inventory service helpers |
csv | CSV parsing and serialization |
Read settings and log an event
const label = (await ctx.settings.get('hello.label')) ?? 'Hello'
ctx.logger.info('Plugin registered', { label, version: ctx.version })
Namespace your keys explicitly. The shared settings service does not automatically prepend your package name.
Schedule periodic work
ctx.scheduler.every(60_000, async () => {
ctx.logger.debug('Periodic task running')
}, { label: 'heartbeat' })
The scheduler manages intervals and clears them when the plugin is unloaded. It logs exceptions from individual ticks. Work can overlap if a callback takes longer than the interval; coordinate long-running or non-repeatable operations accordingly.
For durable tasks, ctx.jobs.enqueue(type, payload, options) uses the core job queue. A corresponding job handler must be registered by the runtime integration. The context does not expose a method for registering arbitrary handler types.
Database and storage
ctx.db is the shared database instance, not an automatically tenant-filtered or plugin-schema-scoped client. Use explicit table/schema definitions and preserve tenant ownership in queries.
Storage helpers derive their tenant context from the installed plugin record. The context provides uploadInvoicePdf, uploadMedia, and getPresignedDownloadUrl.
Current limitations
ctx.inventory.getStock() is currently a stub that returns 0; it must not be used as an actual stock reading. The factory provides inventory.move and inventory.defaultWarehouseId separately.
There is no Fastify instance, HTTP route registrar, or UI extension registrar on the current context. Plan those integrations against explicit runtime support rather than adding undeclared context methods.
Found something unclear? Let us know