Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/foundation/core/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,15 @@ module.exports = {
isolatedModules: true,
}],
},
transformIgnorePatterns: [
'node_modules/(?!(@objectstack))',
],
globals: {
'ts-jest': {
tsconfig: {
esModuleInterop: true,
allowSyntheticDefaultImports: true,
}
}
}
};
4 changes: 2 additions & 2 deletions packages/foundation/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
"dependencies": {
"@objectql/types": "workspace:*",
"@objectstack/spec": "^0.2.0",
"@objectstack/runtime": "^0.1.1",
"@objectstack/objectql": "^0.1.1",
"@objectstack/runtime": "^0.2.0",
"@objectstack/objectql": "^0.2.0",
"js-yaml": "^4.1.0",
"openai": "^4.28.0"
},
Expand Down
49 changes: 48 additions & 1 deletion packages/foundation/core/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import {
LoaderPlugin
} from '@objectql/types';
import type { PluginDefinition } from '@objectstack/spec';
import { ObjectStackKernel } from '@objectstack/runtime';
import { ObjectRepository } from './repository';
import { ObjectQLPlugin } from './plugin';
// import { createDriverFromConnection } from './driver'; // REMOVE THIS

// import { loadRemoteFromUrl } from './remote';
Expand All @@ -31,6 +33,15 @@ import { registerHookHelper, triggerHookHelper, HookEntry } from './hook';
import { registerObjectHelper, getConfigsHelper } from './object';
import { convertIntrospectedSchemaToObjects } from './util';

/**
* ObjectQL
*
* Enhanced ObjectQL implementation that wraps ObjectStackKernel
* to provide the plugin architecture while maintaining backward compatibility.
*
* This class acts as a compatibility layer, proxying operations to the kernel
* while preserving the existing API surface.
*/
export class ObjectQL implements IObjectQL {
public metadata: MetadataRegistry;
private datasources: Record<string, Driver> = {};
Expand All @@ -39,6 +50,10 @@ export class ObjectQL implements IObjectQL {
private actions: Record<string, ActionEntry> = {};
private pluginsList: PluginDefinition[] = [];

// ObjectStack Kernel Integration
private kernel: ObjectStackKernel;
private kernelPlugins: any[] = [];

// Store config for lazy loading in init()
private config: ObjectQLConfig;

Expand All @@ -52,6 +67,13 @@ export class ObjectQL implements IObjectQL {
throw new Error("Connection strings are not supported in core directly. Use @objectql/platform-node's createDriverFromConnection or pass a driver instance to 'datasources'.");
}

// Initialize ObjectStackKernel with plugins
// The kernel will be used for lifecycle management and plugin orchestration
this.kernelPlugins = [];

// Add the ObjectQL plugin to provide enhanced features
this.kernelPlugins.push(new ObjectQLPlugin());

// Initialize Plugin List (but don't setup yet)
if (config.plugins) {
for (const plugin of config.plugins) {
Expand All @@ -62,9 +84,14 @@ export class ObjectQL implements IObjectQL {
}
}
}

// Create the kernel instance
// Note: The kernel expects plugins in its constructor
this.kernel = new ObjectStackKernel(this.kernelPlugins);
}
use(plugin: PluginDefinition) {
this.pluginsList.push(plugin);
this.kernelPlugins.push(plugin);
}

removePackage(name: string) {
Expand Down Expand Up @@ -143,6 +170,18 @@ export class ObjectQL implements IObjectQL {
return ctx;
}

/**
* Get the underlying ObjectStackKernel instance
*
* This provides access to the kernel for advanced usage scenarios
* where you need direct access to the plugin architecture.
*
* @returns The ObjectStackKernel instance
*/
getKernel(): ObjectStackKernel {
return this.kernel;
}

registerObject(object: ObjectConfig) {
registerObjectHelper(this.metadata, object);
}
Expand Down Expand Up @@ -308,11 +347,17 @@ export class ObjectQL implements IObjectQL {
}

async init() {
console.log('[ObjectQL] Initializing with ObjectStackKernel...');

// Start the kernel first - this will install and start all plugins
await this.kernel.start();

// 0. Init Plugins (This allows plugins to register custom loaders)
// Legacy plugin support - for plugins not registered with the kernel
for (const plugin of this.pluginsList) {
const pluginId = plugin.id || 'unknown';

console.log(`Initializing plugin '${pluginId}'...`);
console.log(`Initializing legacy plugin '${pluginId}'...`);

// Call onEnable hook if it exists
if (plugin.onEnable) {
Expand Down Expand Up @@ -344,6 +389,8 @@ export class ObjectQL implements IObjectQL {

// 6. Process Initial Data
await this.processInitialData();

console.log('[ObjectQL] Initialization complete');
}

private async processInitialData() {
Expand Down
1 change: 1 addition & 0 deletions packages/foundation/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type { DriverInterface, DriverOptions, QueryAST } from '@objectstack/spec
// Export our enhanced runtime components (actual implementations)
export * from './repository';
export * from './app';
export * from './plugin';

export * from './action';
export * from './hook';
Expand Down
138 changes: 138 additions & 0 deletions packages/foundation/core/src/plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/**
* ObjectQL Plugin
* Copyright (c) 2026-present ObjectStack Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import type { RuntimePlugin, RuntimeContext } from '@objectstack/runtime';
import type { ObjectStackKernel } from '@objectstack/runtime';

/**
* Configuration for the ObjectQL Plugin
*/
export interface ObjectQLPluginConfig {
/**
* Enable repository pattern for data access
* @default true
*/
enableRepository?: boolean;

/**
* Enable validation engine
* @default true
*/
enableValidator?: boolean;

/**
* Enable formula engine
* @default true
*/
enableFormulas?: boolean;

/**
* Enable AI integration
* @default true
*/
enableAI?: boolean;
}

/**
* ObjectQL Plugin
*
* Implements the RuntimePlugin interface from @objectstack/runtime
* to provide ObjectQL's enhanced features (Repository, Validator, Formula, AI)
* on top of the ObjectStack kernel.
*/
export class ObjectQLPlugin implements RuntimePlugin {
name = '@objectql/core';
version = '4.0.0';

constructor(private config: ObjectQLPluginConfig = {}) {
// Set defaults
this.config = {
enableRepository: true,
enableValidator: true,
enableFormulas: true,
enableAI: true,
...config
};
}

/**
* Install the plugin into the kernel
* This is called during kernel initialization
*/
async install(ctx: RuntimeContext): Promise<void> {
console.log(`[${this.name}] Installing plugin...`);

// Register components based on configuration
if (this.config.enableRepository !== false) {
await this.registerRepository(ctx.engine);
}

if (this.config.enableValidator !== false) {
await this.registerValidator(ctx.engine);
}

if (this.config.enableFormulas !== false) {
await this.registerFormulas(ctx.engine);
}

if (this.config.enableAI !== false) {
await this.registerAI(ctx.engine);
}

console.log(`[${this.name}] Plugin installed successfully`);
}

/**
* Called when the kernel starts
* This is the initialization phase
*/
async onStart(ctx: RuntimeContext): Promise<void> {
console.log(`[${this.name}] Starting plugin...`);
// Additional startup logic can be added here
}

/**
* Register the Repository pattern
* @private
*/
private async registerRepository(kernel: ObjectStackKernel): Promise<void> {
// TODO: Implement repository registration
// For now, this is a placeholder to establish the structure
console.log(`[${this.name}] Repository pattern registered`);
}

/**
* Register the Validator engine
* @private
*/
private async registerValidator(kernel: ObjectStackKernel): Promise<void> {
// TODO: Implement validator registration
// For now, this is a placeholder to establish the structure
console.log(`[${this.name}] Validator engine registered`);
}

/**
* Register the Formula engine
* @private
*/
private async registerFormulas(kernel: ObjectStackKernel): Promise<void> {
// TODO: Implement formula registration
// For now, this is a placeholder to establish the structure
console.log(`[${this.name}] Formula engine registered`);
}

/**
* Register AI integration
* @private
*/
private async registerAI(kernel: ObjectStackKernel): Promise<void> {
// TODO: Implement AI registration
// For now, this is a placeholder to establish the structure
console.log(`[${this.name}] AI integration registered`);
}
}
18 changes: 18 additions & 0 deletions packages/foundation/core/test/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@
* LICENSE file in the root directory of this source tree.
*/

// Mock the ObjectStackKernel before importing ObjectQL
jest.mock('@objectstack/runtime', () => {
return {
ObjectStackKernel: jest.fn().mockImplementation(() => ({
ql: null,
start: jest.fn().mockResolvedValue(undefined),
seed: jest.fn().mockResolvedValue(undefined),
find: jest.fn().mockResolvedValue({ value: [], count: 0 }),
get: jest.fn().mockResolvedValue({}),
create: jest.fn().mockResolvedValue({}),
update: jest.fn().mockResolvedValue({}),
delete: jest.fn().mockResolvedValue(true),
getMetadata: jest.fn().mockReturnValue({}),
getView: jest.fn().mockReturnValue(null),
})),
};
});

import { ObjectQL } from '../src/app';
import { MockDriver } from './mock-driver';
import { ObjectConfig, HookContext, ActionContext, Metadata } from '@objectql/types';
Expand Down
44 changes: 18 additions & 26 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.