This directory contains protocol plugin implementations for the ObjectStack ecosystem. Each protocol plugin implements the RuntimePlugin interface defined in @objectql/types.
- Plugin Interface: All protocols implement
RuntimePluginfrom@objectql/types - Direct Engine Access: Plugins access the kernel/engine directly through the RuntimeContext
- No Direct DB Access: All data operations go through kernel methods (find, create, update, delete)
- Lifecycle Management: Plugins follow install → onStart → onStop lifecycle
import type { RuntimePlugin, RuntimeContext } from '@objectql/types';
export class MyProtocolPlugin implements RuntimePlugin {
name = '@objectql/protocol-my-protocol';
version = '1.0.0';
private engine?: any;
async install(ctx: RuntimeContext): Promise<void> {
// Store engine reference for later use
this.engine = ctx.engine;
// Initialize plugin resources
console.log('Plugin installed');
}
async onStart(ctx: RuntimeContext): Promise<void> {
// Start your protocol server
// Use this.engine.find(), this.engine.create(), etc.
console.log('Plugin started');
}
async onStop(ctx: RuntimeContext): Promise<void> {
// Cleanup resources
console.log('Plugin stopped');
}
}Full OData V4 protocol implementation with automatic metadata generation.
Features:
- Service document (/)
- Metadata document ($metadata)
- Entity queries with $filter, $select, $orderby, $top, $skip
- CRUD operations
- EDMX schema generation
Usage:
import { ObjectKernel } from '@objectstack/runtime';
import { ODataV4Plugin } from '@objectql/protocol-odata-v4';
const kernel = new ObjectKernel([
new ODataV4Plugin({
port: 8080,
basePath: '/odata',
namespace: 'MyApp'
})
]);
await kernel.start();
// Access at: http://localhost:8080/odata
// Metadata: http://localhost:8080/odata/$metadata
// Query: http://localhost:8080/odata/users?$top=10&$orderby=nameFull JSON-RPC 2.0 specification compliant implementation.
Features:
- Batch requests
- Notification support
- Built-in introspection (system.listMethods, system.describe)
- CRUD and metadata methods
- Error handling with JSON-RPC error codes
Usage:
import { ObjectKernel } from '@objectstack/runtime';
import { JSONRPCPlugin } from '@objectql/protocol-json-rpc';
const kernel = new ObjectKernel([
new JSONRPCPlugin({
port: 9000,
basePath: '/rpc',
enableIntrospection: true
})
]);
await kernel.start();
// Client request:
// POST http://localhost:9000/rpc
// {
// "jsonrpc": "2.0",
// "method": "object.find",
// "params": ["users", {"where": {"active": true}}],
// "id": 1
// }Full GraphQL implementation with automatic schema generation and Apollo Server integration.
Features:
- Automatic GraphQL schema generation from metadata
- Query and mutation resolvers
- Apollo Server v4+ with Apollo Sandbox
- Introspection support
- Type-safe resolvers
Usage:
import { ObjectKernel } from '@objectstack/runtime';
import { GraphQLPlugin } from '@objectql/protocol-graphql';
const kernel = new ObjectKernel([
new GraphQLPlugin({
port: 4000,
introspection: true
})
]);
await kernel.start();
// Access Apollo Sandbox: http://localhost:4000/
// Query example:
// query {
// usersList(limit: 10) {
// id
// name
// email
// }
// }All protocol plugins implement the RuntimePlugin interface from @objectql/types:
object.find(objectName, query)- Find recordsobject.get(objectName, id)- Get single recordobject.create(objectName, data)- Create recordobject.update(objectName, id, data)- Update recordobject.delete(objectName, id)- Delete recordobject.count(objectName, filters)- Count recordsmetadata.list()- List all objectsmetadata.get(objectName)- Get object metadataaction.execute(actionName, params)- Execute actionsystem.listMethods()- List available methodssystem.describe(method)- Get method signature
All protocol plugins implement the RuntimePlugin interface from @objectql/types:
export interface RuntimePlugin {
/** Unique plugin identifier */
name: string;
/** Plugin version (optional) */
version?: string;
/** Install hook - called during kernel initialization */
install?(ctx: RuntimeContext): void | Promise<void>;
/** Start hook - called when kernel starts */
onStart?(ctx: RuntimeContext): void | Promise<void>;
/** Stop hook - called when kernel stops */
onStop?(ctx: RuntimeContext): void | Promise<void>;
}The RuntimeContext provides access to the kernel/engine:
export interface RuntimeContext {
/** The ObjectStack kernel/engine instance */
engine: any;
}The engine provides the following methods for protocol plugins:
Metadata Operations:
engine.metadata.getTypes()- Get list of registered typesengine.metadata.list(type)- Get items of a specific typeengine.metadata.get(type, name)- Get a specific metadata item
CRUD Operations:
engine.find(objectName, query)- Find recordsengine.get(objectName, id)- Get single recordengine.create(objectName, data)- Create recordengine.update(objectName, id, data)- Update recordengine.delete(objectName, id)- Delete record
The bridge layer provides these methods for protocol implementations:
getMetaTypes(): string[]- Get all registered object typesgetMetaItem(objectName): unknown- Get object metadatagetAllMetaItems(metaType): Map- Get all metadata of typehasObject(objectName): boolean- Check if object exists
findData(objectName, query?): Promise<{value, count}>- Find recordsgetData(objectName, id): Promise<any>- Get single recordcountData(objectName, filters?): Promise<number>- Count records
createData(objectName, data): Promise<any>- Create recordupdateData(objectName, id, data): Promise<any>- Update recorddeleteData(objectName, id): Promise<boolean>- Delete record
getViewConfig(objectName, viewType?): unknown- Get view configexecuteAction(actionName, params?): Promise<any>- Execute actiongetActions(): string[]- List actions
getKernel(): ObjectKernel- Get kernel (advanced use only)
packages/protocols/my-protocol/
├── src/
│ └── index.ts
├── package.json
└── tsconfig.jsonimport type { RuntimePlugin, RuntimeContext, ObjectStackRuntimeProtocol } from '@objectstack/runtime';
export class MyProtocolPlugin implements RuntimePlugin {
name = '@objectql/protocol-my-protocol';
version = '0.1.0';
private protocol?: ObjectStackRuntimeProtocol;
constructor(private config: MyProtocolConfig = {}) {}
async install(ctx: RuntimeContext): Promise<void> {
const { ObjectStackRuntimeProtocol } = await import('@objectstack/runtime');
this.protocol = new ObjectStackRuntimeProtocol(ctx.engine);
}
async onStart(ctx: RuntimeContext): Promise<void> {
// Initialize your protocol server here
// Use this.protocol methods for all data operations
}
async onStop(ctx: RuntimeContext): Promise<void> {
// Cleanup resources
}
}// Get metadata
const objects = this.protocol.getMetaTypes();
const userMeta = this.protocol.getMetaItem('users');
// Query data
const result = await this.protocol.findData('users', {
where: { active: true },
orderBy: [{ field: 'name', order: 'asc' }],
limit: 10
});
// Create data
const newUser = await this.protocol.createData('users', {
name: 'John Doe',
email: 'john@example.com'
});
// Update data
const updated = await this.protocol.updateData('users', '123', {
name: 'Jane Doe'
});
// Delete data
await this.protocol.deleteData('users', '123');- Never access database directly - Always use
ObjectStackRuntimeProtocolmethods - Initialize in install hook - Create the protocol bridge in
install() - Start server in onStart - Launch your protocol server in
onStart() - Cleanup in onStop - Close connections and release resources in
onStop() - Handle errors gracefully - Provide meaningful error messages in protocol format
- Type safety - Use TypeScript strict mode and proper typing
- Configuration - Make plugins configurable through constructor options
- Documentation - Document available endpoints and methods
Each protocol plugin should include:
- Unit tests for request parsing and response formatting
- Integration tests with a mock kernel
- End-to-end tests with real HTTP requests
When adding a new protocol plugin:
- Follow the architectural pattern shown in existing plugins
- Implement all three lifecycle hooks (install, onStart, onStop)
- Use the protocol bridge for all kernel interactions
- Add comprehensive documentation
- Include tests
- Update this README
MIT