@objectql/core 4.0.6 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +19 -0
  3. package/dist/ai/index.d.ts +8 -0
  4. package/dist/ai/index.js +25 -0
  5. package/dist/ai/index.js.map +1 -0
  6. package/dist/ai/registry.d.ts +23 -0
  7. package/dist/ai/registry.js +78 -0
  8. package/dist/ai/registry.js.map +1 -0
  9. package/dist/app.d.ts +2 -1
  10. package/dist/app.js +41 -20
  11. package/dist/app.js.map +1 -1
  12. package/dist/gateway.d.ts +3 -2
  13. package/dist/gateway.js +6 -2
  14. package/dist/gateway.js.map +1 -1
  15. package/dist/index.d.ts +11 -4
  16. package/dist/index.js +11 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/optimizations/CompiledHookManager.d.ts +1 -0
  19. package/dist/optimizations/CompiledHookManager.js +7 -1
  20. package/dist/optimizations/CompiledHookManager.js.map +1 -1
  21. package/dist/plugin.d.ts +3 -2
  22. package/dist/plugin.js +77 -33
  23. package/dist/plugin.js.map +1 -1
  24. package/dist/protocol.d.ts +11 -0
  25. package/dist/protocol.js +12 -0
  26. package/dist/protocol.js.map +1 -1
  27. package/dist/query/filter-translator.d.ts +1 -4
  28. package/dist/query/filter-translator.js.map +1 -1
  29. package/dist/query/query-analyzer.d.ts +1 -3
  30. package/dist/query/query-analyzer.js.map +1 -1
  31. package/dist/query/query-builder.d.ts +1 -9
  32. package/dist/query/query-builder.js +8 -0
  33. package/dist/query/query-builder.js.map +1 -1
  34. package/dist/query/query-service.d.ts +2 -3
  35. package/dist/query/query-service.js +5 -1
  36. package/dist/query/query-service.js.map +1 -1
  37. package/dist/repository.d.ts +0 -28
  38. package/dist/repository.js +18 -173
  39. package/dist/repository.js.map +1 -1
  40. package/package.json +16 -9
  41. package/src/ai/index.ts +9 -0
  42. package/src/ai/registry.ts +81 -0
  43. package/src/app.ts +47 -20
  44. package/src/gateway.ts +7 -3
  45. package/src/index.ts +24 -7
  46. package/src/optimizations/CompiledHookManager.ts +9 -1
  47. package/src/plugin.ts +90 -36
  48. package/src/protocol.ts +13 -0
  49. package/src/query/filter-translator.ts +3 -3
  50. package/src/query/query-analyzer.ts +1 -2
  51. package/src/query/query-builder.ts +8 -8
  52. package/src/query/query-service.ts +7 -3
  53. package/src/repository.ts +20 -223
  54. package/test/ai-registry.test.ts +42 -0
  55. package/test/app.test.ts +6 -6
  56. package/test/optimizations.test.ts +1 -1
  57. package/test/plugin-integration.test.ts +3 -2
  58. package/tsconfig.tsbuildinfo +1 -1
  59. package/jest.config.js +0 -29
package/src/gateway.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
 
9
- import { ApiRequest, ApiResponse, GatewayProtocol } from '@objectql/types';
9
+ import { ApiRequest, ApiResponse, GatewayProtocol, Logger, ConsoleLogger } from '@objectql/types';
10
10
 
11
11
  export type RequestTransformer = (request: ApiRequest) => Promise<ApiRequest>;
12
12
  export type ResponseTransformer = (response: ApiResponse) => Promise<ApiResponse>;
@@ -19,9 +19,11 @@ export class ObjectGateway {
19
19
  private protocols: GatewayProtocol[] = [];
20
20
  private requestTransforms: RequestTransformer[] = [];
21
21
  private responseTransforms: ResponseTransformer[] = [];
22
+ private logger: Logger;
22
23
 
23
- constructor(protocols: GatewayProtocol[] = []) {
24
+ constructor(protocols: GatewayProtocol[] = [], logger?: Logger) {
24
25
  this.protocols = protocols;
26
+ this.logger = logger ?? new ConsoleLogger({ name: '@objectql/gateway', level: 'info' });
25
27
  }
26
28
 
27
29
  /**
@@ -78,7 +80,9 @@ export class ObjectGateway {
78
80
  try {
79
81
  response = await protocol.handle(req);
80
82
  } catch (error: any) {
81
- console.error(`[ObjectGateway] Error in ${protocol.name}:`, error);
83
+ this.logger.error(`Error in ${protocol.name}`, error as Error, {
84
+ protocol: protocol.name,
85
+ });
82
86
  response = {
83
87
  status: 500,
84
88
  headers: { 'Content-Type': 'application/json' },
package/src/index.ts CHANGED
@@ -9,15 +9,29 @@
9
9
  // Re-export types from @objectstack packages for API compatibility
10
10
  export type { ObjectKernel } from '@objectstack/runtime';
11
11
  export type { ObjectStackProtocolImplementation } from '@objectstack/objectql';
12
- // Note: @objectstack/objectql types temporarily commented out due to type incompatibilities
13
- // in the published package. Will be re-enabled when package is updated.
14
- // export type { ObjectQL as ObjectQLEngine, SchemaRegistry } from '@objectstack/objectql';
12
+
13
+ // Re-export new @objectstack/objectql 1.1.0 FQN (Fully Qualified Name) utilities
14
+ export {
15
+ computeFQN,
16
+ parseFQN,
17
+ RESERVED_NAMESPACES,
18
+ DEFAULT_OWNER_PRIORITY,
19
+ DEFAULT_EXTENDER_PRIORITY,
20
+ SchemaRegistry,
21
+ } from '@objectstack/objectql';
22
+ export type { ObjectContributor } from '@objectstack/objectql';
15
23
 
16
24
  // Export ObjectStack spec types for driver development
17
- import { Data, System } from '@objectstack/spec';
18
- export type QueryAST = Data.QueryAST;
19
- export type DriverInterface = Data.DriverInterface;
20
- export type DriverOptions = Data.DriverOptions;
25
+ import { Data, System, Automation } from '@objectstack/spec';
26
+ import { z } from 'zod';
27
+ export { QueryAST } from '@objectql/types';
28
+ export type DriverInterface = z.infer<typeof Data.DriverInterfaceSchema>;
29
+ export type DriverOptions = z.infer<typeof Data.DriverOptionsSchema>;
30
+
31
+ // Re-export new @objectstack/spec 1.1.0 types
32
+ export type StateMachineConfig = z.infer<typeof Automation.StateMachineSchema>;
33
+ export type ObjectOwnership = z.infer<typeof Data.ObjectOwnershipEnum>;
34
+ export type ObjectExtension = z.infer<typeof Data.ObjectExtensionSchema>;
21
35
 
22
36
  export * from './gateway';
23
37
 
@@ -34,3 +48,6 @@ export * from './util';
34
48
 
35
49
  // Export kernel optimizations
36
50
  export * from './optimizations';
51
+
52
+ // Export AI runtime
53
+ export * from './ai';
@@ -6,6 +6,8 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
 
9
+ import { Logger, ConsoleLogger } from '@objectql/types';
10
+
9
11
  /**
10
12
  * Hook definition
11
13
  */
@@ -30,6 +32,9 @@ export class CompiledHookManager {
30
32
 
31
33
  // Keep track of all registered hooks for management
32
34
  private allHooks = new Map<string, Hook>();
35
+
36
+ // Structured logger
37
+ private logger: Logger = new ConsoleLogger({ name: '@objectql/hook-manager', level: 'warn' });
33
38
 
34
39
  /**
35
40
  * Expand a pattern like "before*" to all matching events
@@ -135,7 +140,10 @@ export class CompiledHookManager {
135
140
  try {
136
141
  return Promise.resolve(hook.handler(context));
137
142
  } catch (error) {
138
- console.error(`Hook execution failed for ${event}:${objectName}`, error);
143
+ this.logger.error(`Hook execution failed for ${event}:${objectName}`, error as Error, {
144
+ event,
145
+ objectName,
146
+ });
139
147
  return Promise.resolve();
140
148
  }
141
149
  }));
package/src/plugin.ts CHANGED
@@ -7,12 +7,15 @@
7
7
  */
8
8
 
9
9
  import type { RuntimePlugin, RuntimeContext } from '@objectql/types';
10
+ import { ConsoleLogger } from '@objectql/types';
11
+ import type { Logger } from '@objectql/types';
10
12
  import { ValidatorPlugin, ValidatorPluginConfig } from '@objectql/plugin-validator';
11
13
  import { FormulaPlugin, FormulaPluginConfig } from '@objectql/plugin-formula';
12
14
  import { QueryService } from './query/query-service';
13
15
  import { QueryAnalyzer } from './query/query-analyzer';
14
16
  import { ObjectStackProtocolImplementation } from './protocol';
15
17
  import type { Driver } from '@objectql/types';
18
+ import { createDefaultAiRegistry } from './ai';
16
19
 
17
20
  /**
18
21
  * Extended kernel with ObjectQL services
@@ -93,6 +96,7 @@ export interface ObjectQLPluginConfig {
93
96
  export class ObjectQLPlugin implements RuntimePlugin {
94
97
  name = '@objectql/core';
95
98
  version = '4.0.2';
99
+ private logger: Logger;
96
100
 
97
101
  constructor(private config: ObjectQLPluginConfig = {}, ql?: any) {
98
102
  // Set defaults
@@ -104,6 +108,7 @@ export class ObjectQLPlugin implements RuntimePlugin {
104
108
  enableQueryService: true,
105
109
  ...config
106
110
  };
111
+ this.logger = new ConsoleLogger({ name: '@objectql/core/plugin', level: 'info' });
107
112
  }
108
113
 
109
114
  /**
@@ -111,7 +116,7 @@ export class ObjectQLPlugin implements RuntimePlugin {
111
116
  * This is called during kernel initialization
112
117
  */
113
118
  async install(ctx: RuntimeContext): Promise<void> {
114
- console.log(`[${this.name}] Installing plugin...`);
119
+ this.logger.info('Installing plugin...');
115
120
 
116
121
  const kernel = ctx.engine as ExtendedKernel;
117
122
 
@@ -127,9 +132,11 @@ export class ObjectQLPlugin implements RuntimePlugin {
127
132
  const driverName = driver.name || (index === 0 ? 'default' : `driver_${index + 1}`);
128
133
  datasources![driverName] = driver;
129
134
  });
130
- console.log(`[${this.name}] Using drivers from kernel:`, Object.keys(datasources));
135
+ this.logger.info('Using drivers from kernel', {
136
+ drivers: Object.keys(datasources),
137
+ });
131
138
  } else {
132
- console.warn(`[${this.name}] No datasources configured and no drivers found in kernel. Repository and QueryService will not be available.`);
139
+ this.logger.warn('No datasources configured and no drivers found in kernel. Repository and QueryService will not be available.');
133
140
  }
134
141
  }
135
142
 
@@ -147,7 +154,7 @@ export class ObjectQLPlugin implements RuntimePlugin {
147
154
  );
148
155
  kernel.queryAnalyzer = queryAnalyzer;
149
156
 
150
- console.log(`[${this.name}] QueryService and QueryAnalyzer registered`);
157
+ this.logger.info('QueryService and QueryAnalyzer registered');
151
158
  }
152
159
 
153
160
  // Register components based on configuration
@@ -171,7 +178,23 @@ export class ObjectQLPlugin implements RuntimePlugin {
171
178
  await this.registerAI(kernel);
172
179
  }
173
180
 
174
- console.log(`[${this.name}] Plugin installed successfully`);
181
+ // Register system service aliases
182
+ if (typeof (ctx as any).registerService === 'function') {
183
+ const registerService = (ctx as any).registerService.bind(ctx);
184
+
185
+ // 1. Metadata service
186
+ if (kernel.metadata) {
187
+ registerService('metadata', kernel.metadata);
188
+ this.logger.debug('Registered metadata service alias');
189
+ }
190
+
191
+ // 2. Data service (prefer QueryService, fallback to kernel)
192
+ const dataService = kernel.queryService || kernel;
193
+ registerService('data', dataService);
194
+ this.logger.debug('Registered data service alias');
195
+ }
196
+
197
+ this.logger.info('Plugin installed successfully');
175
198
  }
176
199
 
177
200
  /**
@@ -179,37 +202,11 @@ export class ObjectQLPlugin implements RuntimePlugin {
179
202
  * This is the initialization phase
180
203
  */
181
204
  async onStart(ctx: RuntimeContext): Promise<void> {
182
- console.log(`[${this.name}] Starting plugin...`);
205
+ this.logger.debug('Starting plugin...');
183
206
  // Additional startup logic can be added here
184
207
  }
185
208
 
186
209
  // --- Adapter for @objectstack/core compatibility ---
187
- async init(kernel: any): Promise<void> {
188
- // The new core passes the kernel instance directly
189
- // We wrap it to match the old RuntimeContext interface
190
- const ctx = {
191
- engine: kernel,
192
- getKernel: () => kernel
193
- };
194
-
195
- // Register Protocol Service
196
- // If kernel supports service registration (PluginContext or ExtendedKernel with custom registry)
197
- if (kernel && typeof kernel.registerService === 'function') {
198
- console.log(`[${this.name}] Registering protocol service...`);
199
- const protocolShim = new ObjectStackProtocolImplementation(kernel as any);
200
- kernel.registerService('protocol', protocolShim);
201
- }
202
-
203
- return this.install(ctx);
204
- }
205
-
206
- async start(kernel: any): Promise<void> {
207
- const ctx = {
208
- engine: kernel,
209
- getKernel: () => kernel
210
- };
211
- return this.onStart(ctx);
212
- }
213
210
  // ---------------------------------------------------
214
211
 
215
212
  /**
@@ -246,6 +243,16 @@ export class ObjectQLPlugin implements RuntimePlugin {
246
243
  };
247
244
 
248
245
  kernel.find = async (objectName: string, query: any): Promise<{ value: any[]; count: number }> => {
246
+ // Use QueryService if available for advanced query processing (AST, optimizations)
247
+ if ((kernel as any).queryService) {
248
+ const result = await (kernel as any).queryService.find(objectName, query);
249
+ return {
250
+ value: result.value,
251
+ count: result.count !== undefined ? result.count : result.value.length
252
+ };
253
+ }
254
+
255
+ // Fallback to direct driver call
249
256
  const driver = getDriver(objectName);
250
257
  const value = await driver.find(objectName, query);
251
258
  const count = value.length;
@@ -253,16 +260,30 @@ export class ObjectQLPlugin implements RuntimePlugin {
253
260
  };
254
261
 
255
262
  kernel.get = async (objectName: string, id: string): Promise<any> => {
263
+ // Use QueryService if available
264
+ if ((kernel as any).queryService) {
265
+ const result = await (kernel as any).queryService.findOne(objectName, id);
266
+ return result.value;
267
+ }
268
+
256
269
  const driver = getDriver(objectName);
257
270
  return await driver.findOne(objectName, id);
258
271
  };
259
272
 
260
273
  kernel.count = async (objectName: string, filters?: any): Promise<number> => {
274
+ // Use QueryService if available
275
+ if ((kernel as any).queryService) {
276
+ // QueryService.count expects a UnifiedQuery filter or just filter object?
277
+ // Looking at QueryService.count signature: count(objectName: string, where?: Filter, options?: QueryOptions)
278
+ const result = await (kernel as any).queryService.count(objectName, filters);
279
+ return result.value;
280
+ }
281
+
261
282
  const driver = getDriver(objectName);
262
283
  return await driver.count(objectName, filters || {}, {});
263
284
  };
264
285
 
265
- console.log(`[${this.name}] Repository pattern registered`);
286
+ this.logger.info('Repository pattern registered');
266
287
  }
267
288
 
268
289
  /**
@@ -270,8 +291,41 @@ export class ObjectQLPlugin implements RuntimePlugin {
270
291
  * @private
271
292
  */
272
293
  private async registerAI(kernel: any): Promise<void> {
273
- // TODO: Implement AI registration
274
- // For now, this is a placeholder to establish the structure
275
- console.log(`[${this.name}] AI integration registered`);
294
+ if (!(kernel as any).ai) {
295
+ (kernel as any).ai = createDefaultAiRegistry();
296
+ }
297
+ this.logger.debug('AI integration registered');
276
298
  }
299
+
300
+ // --- Adapter for @objectstack/core compatibility ---
301
+ init = async (kernel: any): Promise<void> => {
302
+ // The new core passes the kernel instance directly
303
+ // We wrap it to match the old RuntimeContext interface
304
+ const ctx: any = {
305
+ engine: kernel,
306
+ getKernel: () => kernel
307
+ };
308
+
309
+ // Register Protocol Service
310
+ // If kernel supports service registration (PluginContext or ExtendedKernel with custom registry)
311
+ if (kernel && typeof kernel.registerService === 'function') {
312
+ this.logger.info('Registering protocol service...');
313
+ const protocolShim = new ObjectStackProtocolImplementation(kernel);
314
+ kernel.registerService('protocol', protocolShim);
315
+
316
+ // Register 'objectql' service for AppPlugin compatibility
317
+ kernel.registerService('objectql', this);
318
+ this.logger.debug('Registered objectql service');
319
+ }
320
+
321
+ return this.install(ctx);
322
+ }
323
+
324
+ start = async (kernel: any): Promise<void> => {
325
+ const ctx: any = {
326
+ engine: kernel,
327
+ getKernel: () => kernel
328
+ };
329
+ return this.onStart(ctx);
330
+ }
277
331
  }
package/src/protocol.ts CHANGED
@@ -72,6 +72,19 @@ export class ObjectStackProtocolImplementation implements ObjectStackProtocol {
72
72
  return this.getMetaItem(args);
73
73
  }
74
74
 
75
+ /**
76
+ * Save Metadata Item
77
+ */
78
+ async saveMetaItem(args: { type: string; name: string; item?: any }): Promise<{ success: boolean; message?: string }> {
79
+ const { type, name, item } = args;
80
+ if (this.engine.metadata && typeof this.engine.metadata.register === 'function') {
81
+ const data = { ...(item || {}), name }; // Ensure name is in data
82
+ this.engine.metadata.register(type, data);
83
+ return { success: true };
84
+ }
85
+ throw new Error('Engine does not support saving metadata');
86
+ }
87
+
75
88
  /**
76
89
  * Get UI View
77
90
  */
@@ -8,7 +8,7 @@
8
8
 
9
9
  import type { Filter } from '@objectql/types';
10
10
  import { Data } from '@objectstack/spec';
11
- type FilterCondition = Data.FilterCondition;
11
+ import { z } from 'zod';
12
12
  import { ObjectQLError } from '@objectql/types';
13
13
 
14
14
  /**
@@ -25,7 +25,7 @@ export class FilterTranslator {
25
25
  /**
26
26
  * Translate filters from ObjectQL format to ObjectStack FilterCondition format
27
27
  */
28
- translate(filters?: Filter): FilterCondition | undefined {
28
+ translate(filters?: Filter): Filter | undefined {
29
29
  if (!filters) {
30
30
  return undefined;
31
31
  }
@@ -36,6 +36,6 @@ export class FilterTranslator {
36
36
  }
37
37
 
38
38
  // Both ObjectQL Filter and ObjectStack FilterCondition use the same format now
39
- return filters as unknown as FilterCondition;
39
+ return filters;
40
40
  }
41
41
  }
@@ -7,8 +7,7 @@
7
7
  */
8
8
 
9
9
  import type { UnifiedQuery, ObjectConfig, MetadataRegistry } from '@objectql/types';
10
- import { Data } from '@objectstack/spec';
11
- type QueryAST = Data.QueryAST;
10
+ import { QueryAST } from '@objectql/types';
12
11
  import { QueryService, QueryOptions } from './query-service';
13
12
 
14
13
  /**
@@ -6,16 +6,16 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
 
9
- import type { UnifiedQuery } from '@objectql/types';
10
- import { Data } from '@objectstack/spec';
9
+ import type { UnifiedQuery, QueryAST } from '@objectql/types';
10
+ // import { QueryAST } from './types'; (Removed)
11
11
 
12
12
  // Local QueryAST type extension to include all properties we need
13
- interface QueryAST extends Data.QueryAST {
14
- top?: number;
15
- expand?: Record<string, any>;
16
- aggregations?: any[];
17
- having?: any;
18
- }
13
+ // interface QueryAST extends Data.QueryAST {
14
+ // top?: number;
15
+ // expand?: Record<string, any>;
16
+ // aggregations?: any[];
17
+ // having?: any;
18
+ // }
19
19
 
20
20
  import { FilterTranslator } from './filter-translator';
21
21
 
@@ -13,9 +13,9 @@ import type {
13
13
  Filter,
14
14
  MetadataRegistry
15
15
  } from '@objectql/types';
16
- import { Data } from '@objectstack/spec';
17
- type QueryAST = Data.QueryAST;
16
+ import { QueryAST } from '@objectql/types';
18
17
  import { QueryBuilder } from './query-builder';
18
+ import { QueryCompiler } from '../optimizations/QueryCompiler';
19
19
 
20
20
  /**
21
21
  * Options for query execution
@@ -101,12 +101,14 @@ export interface QueryProfile {
101
101
  */
102
102
  export class QueryService {
103
103
  private queryBuilder: QueryBuilder;
104
+ private queryCompiler: QueryCompiler;
104
105
 
105
106
  constructor(
106
107
  private datasources: Record<string, Driver>,
107
108
  private metadata: MetadataRegistry
108
109
  ) {
109
110
  this.queryBuilder = new QueryBuilder();
111
+ this.queryCompiler = new QueryCompiler(1000);
110
112
  }
111
113
 
112
114
  /**
@@ -142,7 +144,9 @@ export class QueryService {
142
144
  * @private
143
145
  */
144
146
  private buildQueryAST(objectName: string, query: UnifiedQuery): QueryAST {
145
- return this.queryBuilder.build(objectName, query);
147
+ const ast = this.queryBuilder.build(objectName, query);
148
+ const compiled = this.queryCompiler.compile(objectName, ast);
149
+ return compiled.ast;
146
150
  }
147
151
 
148
152
  /**