diff --git a/examples/features/middleware-example.ts b/examples/features/middleware-example.ts index 77d3611d4..77947b501 100644 --- a/examples/features/middleware-example.ts +++ b/examples/features/middleware-example.ts @@ -147,7 +147,7 @@ function applyMiddlewareToServer(server: any, manager: MiddlewareManager) { const chain = manager.getMiddlewareChain(); // Apply each middleware to the server - chain.forEach(middleware => { + chain.forEach((middleware: Middleware) => { server.use(middleware); }); @@ -263,12 +263,14 @@ function setupAdvancedMiddleware() { manager.register({ name: 'cors', type: 'custom', + enabled: true, order: 10, }, corsMiddleware); manager.register({ name: 'logger', type: 'logging', + enabled: true, order: 20, }, loggingMiddleware); @@ -276,6 +278,7 @@ function setupAdvancedMiddleware() { manager.register({ name: 'rate_limit', type: 'custom', + enabled: true, order: 25, config: { windowMs: 60000, @@ -290,6 +293,7 @@ function setupAdvancedMiddleware() { manager.register({ name: 'auth', type: 'authentication', + enabled: true, order: 30, paths: { exclude: ['/health', '/metrics', '/api/v1'] @@ -300,6 +304,7 @@ function setupAdvancedMiddleware() { manager.register({ name: 'cache', type: 'custom', + enabled: true, order: 35, paths: { include: ['/api/v1/meta/*'] // Only cache metadata @@ -309,6 +314,7 @@ function setupAdvancedMiddleware() { manager.register({ name: 'validation', type: 'validation', + enabled: true, order: 40, }, validationMiddleware); diff --git a/examples/features/package.json b/examples/features/package.json index 399c0acff..f463567aa 100644 --- a/examples/features/package.json +++ b/examples/features/package.json @@ -10,7 +10,8 @@ }, "dependencies": { "@objectstack/spec": "workspace:*", - "@objectstack/core": "workspace:*" + "@objectstack/core": "workspace:*", + "@objectstack/runtime": "workspace:*" }, "devDependencies": { "typescript": "^5.0.0", diff --git a/examples/features/registry-example.ts b/examples/features/registry-example.ts index bda68d14e..ba110a976 100644 --- a/examples/features/registry-example.ts +++ b/examples/features/registry-example.ts @@ -287,7 +287,7 @@ console.log('Found', restApis.length, 'REST APIs'); // Discover plugin-registered APIs const pluginApis = registry.apis.filter( - api => api.metadata?.pluginSource !== undefined + api => api.metadata && 'pluginSource' in api.metadata && api.metadata.pluginSource !== undefined ); console.log('Found', pluginApis.length, 'plugin APIs'); diff --git a/examples/features/rest-server-example.ts b/examples/features/rest-server-example.ts index 77e6ee541..d4ed17a00 100644 --- a/examples/features/rest-server-example.ts +++ b/examples/features/rest-server-example.ts @@ -5,8 +5,8 @@ * generate RESTful CRUD endpoints for your ObjectStack application. */ -import { RestServer } from '@objectstack/runtime'; -import type { IProtocolProvider } from '@objectstack/runtime'; +import { RestServer, RouteEntry } from '@objectstack/runtime'; +import type { ObjectStackProtocol } from '@objectstack/spec/api'; /** * Example: Mock Protocol Provider @@ -14,7 +14,7 @@ import type { IProtocolProvider } from '@objectstack/runtime'; * In a real application, this would be provided by your ObjectQL engine * or data layer implementation. */ -class MockProtocolProvider implements IProtocolProvider { +class MockProtocolProvider { private data: Map = new Map(); getDiscovery() { @@ -105,6 +105,35 @@ class MockProtocolProvider implements IProtocolProvider { return { success: true }; } + async getMetaItemCached(request: any) { + return { + type: request.type, + name: request.name, + item: await this.getMetaItem(request.type, request.name), + cached: false + }; + } + + async batchData(request: any) { + const results = []; + for (const op of request.operations || []) { + try { + let result; + if (op.operation === 'create') { + result = await this.createData(op.object, op.data); + } else if (op.operation === 'update') { + result = await this.updateData(op.object, op.id, op.data); + } else if (op.operation === 'delete') { + result = await this.deleteData(op.object, op.id); + } + results.push({ success: true, data: result }); + } catch (error) { + results.push({ success: false, error: (error as Error).message }); + } + } + return { results }; + } + async createManyData(object: string, records: any[]) { const existing = this.data.get(object) || []; const newRecords = records.map(r => ({ id: Date.now().toString(), ...r })); @@ -112,6 +141,32 @@ class MockProtocolProvider implements IProtocolProvider { this.data.set(object, existing); return newRecords; } + + async updateManyData(request: any) { + const results = []; + for (const id of request.ids || []) { + try { + const result = await this.updateData(request.object, id, request.data); + results.push({ success: true, data: result }); + } catch (error) { + results.push({ success: false, error: (error as Error).message }); + } + } + return { results }; + } + + async deleteManyData(request: any) { + const results = []; + for (const id of request.ids || []) { + try { + const result = await this.deleteData(request.object, id); + results.push({ success: true, data: result }); + } catch (error) { + results.push({ success: false, error: (error as Error).message }); + } + } + return { results }; + } } /** @@ -123,7 +178,7 @@ async function setupRestServer() { const httpServer = {} as any; // Placeholder - use actual server in production // 2. Create a protocol provider - const protocol = new MockProtocolProvider(); + const protocol = new MockProtocolProvider() as any as ObjectStackProtocol; // 3. Create REST server with configuration const restServer = new RestServer(httpServer, protocol, { @@ -137,6 +192,7 @@ async function setupRestServer() { }, crud: { dataPrefix: '/data', + objectParamStyle: 'path' as const, operations: { create: true, read: true, @@ -148,10 +204,12 @@ async function setupRestServer() { metadata: { prefix: '/meta', enableCache: true, + cacheTtl: 300, // 5 minutes }, batch: { maxBatchSize: 200, enableBatchEndpoint: true, + defaultAtomic: true, operations: { createMany: true, updateMany: true, @@ -167,7 +225,7 @@ async function setupRestServer() { // 5. Get route information (useful for debugging) const routes = restServer.getRoutes(); console.log(`Registered ${routes.length} routes:`); - routes.forEach(route => { + routes.forEach((route: RouteEntry) => { console.log(` ${route.method} ${route.path}`); }); @@ -214,7 +272,7 @@ async function exampleApiUsage() { email: 'john@example.com' }) }); - const newUser = await createResponse.json(); + const newUser = await createResponse.json() as { id: string; name: string; email: string }; console.log('Created user:', newUser); // List users diff --git a/examples/guide-cli/objectstack.config.ts b/examples/guide-cli/objectstack.config.ts index 9cc03692c..1003b5993 100644 --- a/examples/guide-cli/objectstack.config.ts +++ b/examples/guide-cli/objectstack.config.ts @@ -1,15 +1,19 @@ import { defineStack } from '@objectstack/spec'; import { Project } from './src/project.object.js'; -// @ts-ignore -import CRMPlugin from '../../plugin-advanced-crm/objectstack.config.js'; export default defineStack({ + manifest: { + id: 'com.example.cli-guide', + version: '1.0.0', + type: 'app', + name: 'CLI Usage Guide', + description: 'Example project demonstrating ObjectStack CLI usage' + }, objects: [ Project ], apps: [], plugins: [ - '@objectstack/plugin-bi', - CRMPlugin + '@objectstack/plugin-bi' ] }); diff --git a/examples/plugin-crm/objectstack.config.ts b/examples/plugin-crm/objectstack.config.ts index 54983da1d..a8a72b5c8 100644 --- a/examples/plugin-crm/objectstack.config.ts +++ b/examples/plugin-crm/objectstack.config.ts @@ -1,6 +1,6 @@ import { defineStack } from '@objectstack/spec'; // @ts-ignore -import BiPlugin from '../../plugin-bi/objectstack.config.js'; +import BiPlugin from '../plugin-bi/objectstack.config.js'; /** * Advanced CRM Plugin Example diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index 89b83a3d7..beb3a52e6 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -9,6 +9,7 @@ export { AppPlugin } from './app-plugin.js'; export { HttpServer } from './http-server.js'; export { RestServer } from './rest-server.js'; export { RouteManager, RouteGroupBuilder } from './route-manager.js'; +export type { RouteEntry } from './route-manager.js'; export { MiddlewareManager } from './middleware.js'; // Export Types diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 49b1bd592..059c409cb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -245,6 +245,9 @@ importers: '@objectstack/core': specifier: workspace:* version: link:../../packages/core + '@objectstack/runtime': + specifier: workspace:* + version: link:../../packages/runtime '@objectstack/spec': specifier: workspace:* version: link:../../packages/spec