Skip to content

Commit d8e6268

Browse files
Copilothuangyiirene
andcommitted
refactor: Remove backward compatibility layer per user request
Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com>
1 parent 201b814 commit d8e6268

4 files changed

Lines changed: 71 additions & 147 deletions

File tree

packages/foundation/core/RUNTIME_INTEGRATION.md

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,11 @@ app.registerDriver('mydb', new MyCustomDriver(), false);
247247
- Initialization process now calls `kernel.start()` which installs and starts all plugins
248248
- Dependencies updated to `@objectstack/*@0.2.0`
249249
- New `getKernel()` method provides access to the underlying kernel
250+
- **Removed legacy plugin support** - all plugins must now implement the `RuntimePlugin` interface
250251

251252
**Migration Guide:**
252253

253-
Your existing code should continue to work without changes:
254+
The ObjectQL API remains the same:
254255
```typescript
255256
import { ObjectQL } from '@objectql/core';
256257
import { MyDriver } from './my-driver';
@@ -261,13 +262,43 @@ const app = new ObjectQL({
261262
}
262263
});
263264

264-
await app.init(); // Now calls kernel.start() internally
265+
await app.init(); // Calls kernel.start() internally
265266
```
266267

267-
If you need kernel access:
268+
Access the kernel for advanced use cases:
268269
```typescript
269-
const kernel = app.getKernel();
270-
// Use kernel methods if needed
270+
const kernel = app.getKernel(); // Must call after init()
271+
```
272+
273+
**Plugin Migration:**
274+
275+
Old plugins with `onEnable` hook are no longer supported. Migrate to `RuntimePlugin`:
276+
277+
```typescript
278+
// Old (no longer supported)
279+
const plugin = {
280+
id: 'my-plugin',
281+
onEnable: async (context) => {
282+
// initialization logic
283+
}
284+
};
285+
286+
// New (required)
287+
import type { RuntimePlugin, RuntimeContext } from '@objectstack/runtime';
288+
289+
class MyPlugin implements RuntimePlugin {
290+
name = 'my-plugin';
291+
292+
async install(ctx: RuntimeContext): Promise<void> {
293+
// installation logic
294+
}
295+
296+
async onStart(ctx: RuntimeContext): Promise<void> {
297+
// startup logic
298+
}
299+
}
300+
301+
const plugin = new MyPlugin();
271302
```
272303

273304
### v3.0.1: Native DriverInterface Adoption

packages/foundation/core/src/app.ts

Lines changed: 10 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,15 @@ import { convertIntrospectedSchemaToObjects } from './util';
3636
/**
3737
* ObjectQL
3838
*
39-
* Enhanced ObjectQL implementation that wraps ObjectStackKernel
40-
* to provide the plugin architecture while maintaining backward compatibility.
41-
*
42-
* This class acts as a compatibility layer, proxying operations to the kernel
43-
* while preserving the existing API surface.
39+
* ObjectQL implementation that wraps ObjectStackKernel
40+
* to provide the plugin architecture.
4441
*/
4542
export class ObjectQL implements IObjectQL {
4643
public metadata: MetadataRegistry;
4744
private datasources: Record<string, Driver> = {};
4845
private remotes: string[] = [];
4946
private hooks: Record<string, HookEntry[]> = {};
5047
private actions: Record<string, ActionEntry> = {};
51-
private pluginsList: PluginDefinition[] = [];
5248

5349
// ObjectStack Kernel Integration
5450
private kernel: ObjectStackKernel | null = null;
@@ -70,7 +66,7 @@ export class ObjectQL implements IObjectQL {
7066
// Add the ObjectQL plugin to provide enhanced features
7167
this.kernelPlugins.push(new ObjectQLPlugin());
7268

73-
// Initialize Plugin List (but don't setup yet)
69+
// Add runtime plugins from config
7470
if (config.plugins) {
7571
for (const plugin of config.plugins) {
7672
if (typeof plugin === 'string') {
@@ -81,10 +77,9 @@ export class ObjectQL implements IObjectQL {
8177
}
8278
}
8379
}
84-
use(plugin: PluginDefinition) {
85-
this.pluginsList.push(plugin);
86-
// Only add to kernelPlugins, not both lists
87-
// The kernel will handle RuntimePlugins, legacy plugins stay in pluginsList
80+
81+
use(plugin: any) {
82+
this.kernelPlugins.push(plugin);
8883
}
8984

9085
removePackage(name: string) {
@@ -250,132 +245,16 @@ export class ObjectQL implements IObjectQL {
250245
}
251246
}
252247

253-
/**
254-
* Create a PluginContext from the current IObjectQL instance.
255-
* This adapts the IObjectQL interface to the PluginContext expected by @objectstack/spec plugins.
256-
*
257-
* **Current Implementation Status:**
258-
* - ✅ ql.object() - Fully functional, provides repository interface for data access
259-
* - ❌ ql.query() - Not implemented, throws error with guidance
260-
* - ❌ os.getCurrentUser() - Stub, returns null
261-
* - ❌ os.getConfig() - Stub, returns null
262-
* - ✅ logger - Functional, logs to console with [Plugin] prefix
263-
* - ❌ storage - Stub, no persistence implemented
264-
* - ✅ i18n - Basic fallback implementation
265-
* - ✅ metadata - Direct access to MetadataRegistry
266-
* - ❌ events - Empty object, event bus not implemented
267-
* - ❌ app.router - Stub methods, no actual routing
268-
* - ❌ app.scheduler - Not implemented (optional in spec)
269-
*
270-
* @private
271-
* @returns Minimal PluginContext adapter for current plugin system capabilities
272-
*/
273-
private createPluginContext(): import('@objectstack/spec').PluginContextData {
274-
// TODO: Implement full PluginContext conversion
275-
// For now, provide a minimal adapter that maps IObjectQL to PluginContext
276-
return {
277-
ql: {
278-
object: (name: string) => {
279-
// Return a repository-like interface
280-
// Cast to ObjectQL to access createContext
281-
return (this as ObjectQL).createContext({}).object(name);
282-
},
283-
query: async (soql: string) => {
284-
// TODO: Implement SOQL query execution
285-
// This requires implementing a SOQL parser and converter
286-
// For now, throw a descriptive error to guide users
287-
throw new Error(
288-
'SOQL queries are not yet supported in plugin context adapter. ' +
289-
'Please use context.ql.object(name).find() instead for data access.'
290-
);
291-
}
292-
},
293-
os: {
294-
getCurrentUser: async () => {
295-
// TODO: Get from context
296-
return null;
297-
},
298-
getConfig: async (key: string) => {
299-
// TODO: Implement config access
300-
return null;
301-
}
302-
},
303-
logger: {
304-
debug: (...args: any[]) => console.debug('[Plugin]', ...args),
305-
info: (...args: any[]) => console.info('[Plugin]', ...args),
306-
warn: (...args: any[]) => console.warn('[Plugin]', ...args),
307-
error: (...args: any[]) => console.error('[Plugin]', ...args),
308-
},
309-
storage: {
310-
get: async (key: string) => {
311-
// TODO: Implement plugin storage
312-
return null;
313-
},
314-
set: async (key: string, value: any) => {
315-
// TODO: Implement plugin storage
316-
},
317-
delete: async (key: string) => {
318-
// TODO: Implement plugin storage
319-
}
320-
},
321-
i18n: {
322-
t: (key: string, params?: any) => key, // Fallback: return key
323-
getLocale: () => 'en'
324-
},
325-
metadata: this.metadata,
326-
events: {
327-
// TODO: Implement event bus
328-
},
329-
app: {
330-
router: {
331-
get: (path: string, handler: (...args: unknown[]) => unknown, ...args: unknown[]) => {
332-
// TODO: Implement router registration
333-
},
334-
post: (path: string, handler: (...args: unknown[]) => unknown, ...args: unknown[]) => {
335-
// TODO: Implement router registration
336-
},
337-
use: (path: string | undefined, handler: (...args: unknown[]) => unknown, ...args: unknown[]) => {
338-
// TODO: Implement middleware registration
339-
}
340-
},
341-
scheduler: undefined // Optional in spec
342-
}
343-
};
344-
}
345-
346248
async init() {
347249
console.log('[ObjectQL] Initializing with ObjectStackKernel...');
348250

349251
// Create the kernel instance with all collected plugins
350-
// This must be done here, not in constructor, to allow use() to be called after construction
351252
this.kernel = new ObjectStackKernel(this.kernelPlugins);
352253

353-
// Start the kernel first - this will install and start all plugins
254+
// Start the kernel - this will install and start all plugins
354255
await this.kernel.start();
355-
356-
// 0. Init Legacy Plugins (for backwards compatibility)
357-
// Only process plugins that are in pluginsList but NOT runtime plugins
358-
// Runtime plugins are already handled by kernel.start()
359-
for (const plugin of this.pluginsList) {
360-
// Skip if this is a RuntimePlugin (has install or onStart methods)
361-
if ('install' in plugin || 'onStart' in plugin) {
362-
continue; // Already handled by kernel
363-
}
364-
365-
const pluginId = plugin.id || 'unknown';
366-
console.log(`Initializing legacy plugin '${pluginId}'...`);
367-
368-
// Call onEnable hook if it exists (legacy plugin pattern)
369-
if (plugin.onEnable) {
370-
const context = this.createPluginContext();
371-
await plugin.onEnable(context);
372-
}
373-
}
374256

375-
// Packages, Presets, Source, Objects loading logic removed from Core.
376-
// Use @objectql/platform-node's ObjectLoader or platform-specific loaders.
377-
378-
// 3. Load In-Memory Objects (Dynamic Layer)
257+
// Load In-Memory Objects (Dynamic Layer)
379258
if (this.config.objects) {
380259
for (const [key, obj] of Object.entries(this.config.objects)) {
381260
this.registerObject(obj);
@@ -384,7 +263,7 @@ export class ObjectQL implements IObjectQL {
384263

385264
const objects = this.metadata.list<ObjectConfig>('object');
386265

387-
// 5. Init Datasources
266+
// Init Datasources
388267
// Let's pass all objects to all configured drivers.
389268
for (const [name, driver] of Object.entries(this.datasources)) {
390269
if (driver.init) {
@@ -393,7 +272,7 @@ export class ObjectQL implements IObjectQL {
393272
}
394273
}
395274

396-
// 6. Process Initial Data
275+
// Process Initial Data
397276
await this.processInitialData();
398277

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

packages/foundation/core/test/__mocks__/@objectstack/runtime.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,24 @@
66

77
export class ObjectStackKernel {
88
public ql: any = null;
9+
private plugins: any[] = [];
910

1011
constructor(plugins: any[] = []) {
11-
// Mock implementation
12+
this.plugins = plugins;
1213
}
1314

1415
async start(): Promise<void> {
15-
// Mock implementation
16+
// Mock implementation that calls plugin lifecycle methods
17+
for (const plugin of this.plugins) {
18+
if (plugin.install) {
19+
await plugin.install({ engine: this });
20+
}
21+
}
22+
for (const plugin of this.plugins) {
23+
if (plugin.onStart) {
24+
await plugin.onStart({ engine: this });
25+
}
26+
}
1627
}
1728

1829
async seed(): Promise<void> {

packages/foundation/core/test/app.test.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -291,11 +291,13 @@ describe('ObjectQL App', () => {
291291
});
292292

293293
describe('Plugin System', () => {
294-
it('should initialize plugins on init', async () => {
295-
const onEnableFn = jest.fn();
296-
const mockPlugin: PluginDefinition = {
297-
id: 'test-plugin',
298-
onEnable: onEnableFn
294+
it('should initialize runtime plugins on init', async () => {
295+
const installFn = jest.fn();
296+
const onStartFn = jest.fn();
297+
const mockPlugin = {
298+
name: 'test-plugin',
299+
install: installFn,
300+
onStart: onStartFn
299301
};
300302

301303
const app = new ObjectQL({
@@ -304,13 +306,14 @@ describe('ObjectQL App', () => {
304306
});
305307

306308
await app.init();
307-
expect(onEnableFn).toHaveBeenCalled();
309+
expect(installFn).toHaveBeenCalled();
310+
expect(onStartFn).toHaveBeenCalled();
308311
});
309312

310313
it('should use plugin method', () => {
311-
const mockPlugin: PluginDefinition = {
312-
id: 'test-plugin',
313-
onEnable: jest.fn()
314+
const mockPlugin = {
315+
name: 'test-plugin',
316+
install: jest.fn()
314317
};
315318

316319
const app = new ObjectQL({ datasources: {} });

0 commit comments

Comments
 (0)