ObjectStack Standard System Library
The runtime package provides the Standard Library for the ObjectStack Operating System. It bridges the pure ObjectKernel (from @objectstack/core) with the Data Engine (@objectstack/objectql) and provides essential infrastructure adapters.
- Standard Library: Contains essential plugins (
AppPlugin,DriverPlugin) - Core Integration: Re-exports
ObjectKernelfor convenience - Capability Contracts: Abstract interfaces for HTTP server and data persistence
npm install @objectstack/runtimeimport { ObjectKernel } from '@objectstack/core';
import { DriverPlugin, AppPlugin } from '@objectstack/runtime';
import { ObjectQLPlugin } from '@objectstack/objectql';
import { InMemoryDriver } from '@objectstack/driver-memory';
const kernel = new ObjectKernel();
kernel
// Register ObjectQL engine
.use(new ObjectQLPlugin())
// Add database driver
.use(new DriverPlugin(new InMemoryDriver(), 'memory'))
// Add your app configurations
// .use(new AppPlugin(appConfig));
await kernel.bootstrap();If you have a separate ObjectQL implementation or need custom configuration:
import { ObjectKernel, DriverPlugin } from '@objectstack/runtime';
import { ObjectQLPlugin, ObjectQL } from '@objectstack/objectql';
// Create custom ObjectQL instance
const customQL = new ObjectQL({
env: 'production',
customConfig: true
});
// Pre-configure with custom hooks
customQL.registerHook('beforeInsert', async (ctx) => {
console.log(`Inserting into ${ctx.object}`);
});
const kernel = new ObjectKernel();
kernel
// Use your custom ObjectQL instance
.use(new ObjectQLPlugin(customQL))
// Add driver
.use(new DriverPlugin(new InMemoryDriver(), 'memory'));
await kernel.bootstrap();
// Access ObjectQL via service registry
const objectql = kernel.getService('objectql');The kernel provides:
- Plugin Lifecycle Management: init → start → destroy phases
- Service Registry: Dependency injection container
- Event/Hook System: Inter-plugin communication
- Dependency Resolution: Topological sort for plugin dependencies
Registers the ObjectQL data engine as a service.
new ObjectQLPlugin() // Default instance
new ObjectQLPlugin(customQL) // Custom instance
new ObjectQLPlugin(undefined, { env: 'prod' }) // With contextServices: 'objectql'
Registers a data driver with ObjectQL.
new DriverPlugin(driver, 'driver-name')Dependencies: ['com.objectstack.engine.objectql']
Wraps ObjectStack app manifests (objectstack.config.ts) as plugins.
new AppPlugin(appConfig)Services: 'app.{id}'
Abstract interface for HTTP server capabilities. Allows plugins to work with any HTTP framework (Express, Fastify, Hono, etc.) without tight coupling.
import { IHttpServer, IHttpRequest, IHttpResponse } from '@objectstack/runtime';
// In your HTTP server plugin
class MyHttpServerPlugin implements Plugin {
name = 'http-server';
async init(ctx: PluginContext) {
const server: IHttpServer = createMyServer(); // Express, Hono, etc.
ctx.registerService('http-server', server);
}
}
// In your API plugin
class MyApiPlugin implements Plugin {
name = 'api';
dependencies = ['http-server'];
async start(ctx: PluginContext) {
const server = ctx.getService<IHttpServer>('http-server');
// Register routes - works with any HTTP framework
server.get('/api/users', async (req, res) => {
res.json({ users: [] });
});
}
}Interface Methods:
get(path, handler)- Register GET routepost(path, handler)- Register POST routeput(path, handler)- Register PUT routedelete(path, handler)- Register DELETE routepatch(path, handler)- Register PATCH routeuse(path, handler?)- Register middlewarelisten(port)- Start serverclose()- Stop server (optional)
Abstract interface for data persistence. Allows plugins to work with any data layer (ObjectQL, Prisma, TypeORM, etc.) without tight coupling.
import { IDataEngine } from '@objectstack/runtime';
// In your data plugin
class MyDataPlugin implements Plugin {
name = 'data';
async init(ctx: PluginContext) {
const engine: IDataEngine = createMyDataEngine(); // ObjectQL, Prisma, etc.
ctx.registerService('data-engine', engine);
}
}
// In your business logic plugin
class MyBusinessPlugin implements Plugin {
name = 'business';
dependencies = ['data'];
async start(ctx: PluginContext) {
const engine = ctx.getService<IDataEngine>('data-engine');
// CRUD operations - works with any data layer
const user = await engine.insert('user', { name: 'John' });
const users = await engine.find('user', { filter: { active: true } });
await engine.update('user', user.id, { name: 'Jane' });
await engine.delete('user', user.id);
}
}Interface Methods:
insert(objectName, data)- Create a recordfind(objectName, query?)- Query recordsupdate(objectName, id, data)- Update a recorddelete(objectName, id)- Delete a record
use(plugin: Plugin): Register a pluginbootstrap(): Initialize and start all pluginsshutdown(): Stop all plugins in reverse ordergetService<T>(name: string): Get a service from registryisRunning(): Check if kernel is runninggetState(): Get current kernel state
interface Plugin {
name: string; // Unique identifier
version?: string; // Plugin version
dependencies?: string[]; // Required plugin names
init(ctx: PluginContext): Promise<void>; // Register services
start?(ctx: PluginContext): Promise<void>; // Execute business logic
destroy?(): Promise<void>; // Cleanup
}interface PluginContext {
registerService(name: string, service: any): void;
getService<T>(name: string): T;
hook(name: string, handler: Function): void;
trigger(name: string, ...args: any[]): Promise<void>;
logger: Console;
getKernel?(): any;
}See the examples/ directory for complete examples:
examples/host/- Full server setup with Honoexamples/msw-react-crud/- Browser-based setup with MSWtest-mini-kernel.ts- Comprehensive kernel test suite- `packages/runtime/src/
- True Modularity: Each plugin is independent and reusable
- Capability Contracts: Plugins depend on interfaces, not implementations
- Testability: Mock services easily in tests
- Flexibility: Load plugins conditionally, swap implementations
- Extensibility: Add new plugins without modifying kernel
- Clear Dependencies: Explicit dependency declarations
- Better Architecture: Separation of concerns with Dependency Inversion
- Keep plugins focused: One responsibility per plugin
- Use services: Share functionality via service registry
- Declare dependencies: Make plugin requirements explicit
- Use hooks: Decouple plugins with event system
- Handle errors: Implement proper error handling in lifecycle methods
- MiniKernel Guide - Complete API documentation and patterns
- MiniKernel Architecture - Architecture diagrams and flows
- MiniKernel Implementation - Implementation details
Apache-2.0