feat: add missing service contract interfaces for all CoreServiceName services#600
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
… services Add 11 new contract interfaces with co-located tests: - IMetadataService (metadata) - IAuthService (auth) - IAutomationService (automation) - IGraphQLService (graphql) - IAnalyticsService (analytics) - IRealtimeService (realtime) - IJobService (job) - IAIService (ai) - II18nService (i18n) - IUIService (ui) - IWorkflowService (workflow) Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds the remaining missing CoreServiceName service contract interfaces to @objectstack/spec, completing the set of core service contracts so plugins/adapters can depend on stable, centralized interfaces.
Changes:
- Introduces 11 new service contract interfaces under
packages/spec/src/contracts/(metadata/auth/automation/graphql/analytics/realtime/job/ai/i18n/ui/workflow). - Adds co-located Vitest contract tests for each new interface to validate “minimal vs full” implementations.
- Updates the contracts barrel export (
packages/spec/src/contracts/index.ts) to export the new contracts.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/spec/src/contracts/index.ts | Exports the newly added contract modules from the contracts barrel. |
| packages/spec/src/contracts/metadata-service.ts | Defines IMetadataService contract (register/get/list/unregister + object conveniences). |
| packages/spec/src/contracts/metadata-service.test.ts | Contract tests for IMetadataService. |
| packages/spec/src/contracts/auth-service.ts | Defines IAuthService contract and related auth/session types. |
| packages/spec/src/contracts/auth-service.test.ts | Contract tests for IAuthService. |
| packages/spec/src/contracts/automation-service.ts | Defines IAutomationService contract and execution context/result types. |
| packages/spec/src/contracts/automation-service.test.ts | Contract tests for IAutomationService. |
| packages/spec/src/contracts/graphql-service.ts | Defines IGraphQLService contract and GraphQL request/response types. |
| packages/spec/src/contracts/graphql-service.test.ts | Contract tests for IGraphQLService. |
| packages/spec/src/contracts/analytics-service.ts | Defines IAnalyticsService contract and analytics query/result/meta types. |
| packages/spec/src/contracts/analytics-service.test.ts | Contract tests for IAnalyticsService. |
| packages/spec/src/contracts/realtime-service.ts | Defines IRealtimeService pub/sub contract and event/subscription types. |
| packages/spec/src/contracts/realtime-service.test.ts | Contract tests for IRealtimeService. |
| packages/spec/src/contracts/job-service.ts | Defines IJobService contract and job scheduling/execution types. |
| packages/spec/src/contracts/job-service.test.ts | Contract tests for IJobService. |
| packages/spec/src/contracts/ai-service.ts | Defines IAIService contract and chat/completion/options/result types. |
| packages/spec/src/contracts/ai-service.test.ts | Contract tests for IAIService. |
| packages/spec/src/contracts/i18n-service.ts | Defines II18nService translation/locale management contract. |
| packages/spec/src/contracts/i18n-service.test.ts | Contract tests for II18nService. |
| packages/spec/src/contracts/ui-service.ts | Defines IUIService contract for view/dashboard access and optional registration. |
| packages/spec/src/contracts/ui-service.test.ts | Contract tests for IUIService. |
| packages/spec/src/contracts/workflow-service.ts | Defines IWorkflowService contract and workflow transition/status types. |
| packages/spec/src/contracts/workflow-service.test.ts | Contract tests for IWorkflowService. |
| * @param packageName - The package name whose items should be removed | ||
| */ | ||
| unregisterPackage?(packageName: string): void; |
There was a problem hiding this comment.
unregisterPackage’s parameter/documentation calls this a packageName, but the underlying registry/facade APIs treat this value as a package identifier (e.g. com.pkg). Renaming the parameter/docs to packageId (and being explicit about the expected format) would avoid confusing it with a human-readable package name.
| * @param packageName - The package name whose items should be removed | |
| */ | |
| unregisterPackage?(packageName: string): void; | |
| * @param packageId - The package identifier (e.g. 'com.pkg') whose items should be removed | |
| */ | |
| unregisterPackage?(packageId: string): void; |
| export interface JobSchedule { | ||
| /** Schedule type */ | ||
| type: 'cron' | 'interval' | 'once'; | ||
| /** Cron expression (when type is 'cron') */ | ||
| expression?: string; |
There was a problem hiding this comment.
JobSchedule currently allows invalid combinations (e.g. type: 'cron' without expression, or type: 'interval' without intervalMs). Consider changing this to a discriminated union keyed by type so TypeScript enforces the required fields for each schedule kind.
| export interface IUIService { | ||
| /** | ||
| * Get a view definition by name | ||
| * @param name - View name (snake_case) | ||
| * @returns View definition, or undefined if not found | ||
| */ | ||
| getView(name: string): unknown | undefined; | ||
|
|
||
| /** | ||
| * List view definitions, optionally filtered by object | ||
| * @param object - Optional object name to filter views for | ||
| * @returns Array of view definitions | ||
| */ | ||
| listViews(object?: string): unknown[]; | ||
|
|
||
| /** | ||
| * Get a dashboard definition by name | ||
| * @param name - Dashboard name (snake_case) | ||
| * @returns Dashboard definition, or undefined if not found | ||
| */ | ||
| getDashboard?(name: string): unknown | undefined; | ||
|
|
||
| /** | ||
| * List all dashboard definitions | ||
| * @returns Array of dashboard definitions | ||
| */ | ||
| listDashboards?(): unknown[]; | ||
|
|
||
| /** | ||
| * Register a view definition | ||
| * @param name - View name (snake_case) | ||
| * @param definition - View definition object | ||
| */ | ||
| registerView?(name: string, definition: unknown): void; | ||
|
|
||
| /** | ||
| * Register a dashboard definition | ||
| * @param name - Dashboard name (snake_case) | ||
| * @param definition - Dashboard definition object | ||
| */ | ||
| registerDashboard?(name: string, definition: unknown): void; |
There was a problem hiding this comment.
getView/listViews returning unknown loses the type-safety available in @objectstack/spec/ui (e.g. View from ui/view.zod and Dashboard from ui/dashboard.zod). Using those exported types (or a small typed alias) would make the contract more useful for consumers and avoid downstream casting.
| export interface IUIService { | |
| /** | |
| * Get a view definition by name | |
| * @param name - View name (snake_case) | |
| * @returns View definition, or undefined if not found | |
| */ | |
| getView(name: string): unknown | undefined; | |
| /** | |
| * List view definitions, optionally filtered by object | |
| * @param object - Optional object name to filter views for | |
| * @returns Array of view definitions | |
| */ | |
| listViews(object?: string): unknown[]; | |
| /** | |
| * Get a dashboard definition by name | |
| * @param name - Dashboard name (snake_case) | |
| * @returns Dashboard definition, or undefined if not found | |
| */ | |
| getDashboard?(name: string): unknown | undefined; | |
| /** | |
| * List all dashboard definitions | |
| * @returns Array of dashboard definitions | |
| */ | |
| listDashboards?(): unknown[]; | |
| /** | |
| * Register a view definition | |
| * @param name - View name (snake_case) | |
| * @param definition - View definition object | |
| */ | |
| registerView?(name: string, definition: unknown): void; | |
| /** | |
| * Register a dashboard definition | |
| * @param name - Dashboard name (snake_case) | |
| * @param definition - Dashboard definition object | |
| */ | |
| registerDashboard?(name: string, definition: unknown): void; | |
| import type { View } from '../ui/view.zod'; | |
| import type { Dashboard } from '../ui/dashboard.zod'; | |
| export interface IUIService { | |
| /** | |
| * Get a view definition by name | |
| * @param name - View name (snake_case) | |
| * @returns View definition, or undefined if not found | |
| */ | |
| getView(name: string): View | undefined; | |
| /** | |
| * List view definitions, optionally filtered by object | |
| * @param object - Optional object name to filter views for | |
| * @returns Array of view definitions | |
| */ | |
| listViews(object?: string): View[]; | |
| /** | |
| * Get a dashboard definition by name | |
| * @param name - Dashboard name (snake_case) | |
| * @returns Dashboard definition, or undefined if not found | |
| */ | |
| getDashboard?(name: string): Dashboard | undefined; | |
| /** | |
| * List all dashboard definitions | |
| * @returns Array of dashboard definitions | |
| */ | |
| listDashboards?(): Dashboard[]; | |
| /** | |
| * Register a view definition | |
| * @param name - View name (snake_case) | |
| * @param definition - View definition object | |
| */ | |
| registerView?(name: string, definition: View): void; | |
| /** | |
| * Register a dashboard definition | |
| * @param name - Dashboard name (snake_case) | |
| * @param definition - Dashboard definition object | |
| */ | |
| registerDashboard?(name: string, definition: Dashboard): void; |
CoreServiceNamedefines 17 service identifiers but only 6 had contract interfaces. This PR closes the gap by adding the 11 missing contracts.New contracts
IMetadataService— register/get/list/unregister metadata by type, convenience methods for objects (aligned withMetadataFacade)IAuthService—handleRequest(Request),verify(token), optionallogout/getCurrentUserIAutomationService—execute(flowName, context),listFlows(), optional register/unregisterIGraphQLService—execute(GraphQLRequest), optionalhandleRequest/getSchemaIAnalyticsService—query(AnalyticsQuery),getMeta(), optionalgenerateSqldry-runIRealtimeService— pub/sub withpublish(event),subscribe(channel, handler),unsubscribe(id)IJobService—schedule(name, schedule, handler),cancel,trigger, optional execution historyIAIService—chat(messages),complete(prompt), optionalembed/listModelsII18nService—t(key, locale),loadTranslations,getLocales, optional default localeIUIService—getView/listViews, optional dashboard CRUDIWorkflowService—transition(WorkflowTransition),getStatus, optionalgetHistoryCoverage after this change
metadataIMetadataService✅ newdataIDataEngine(existed)authIAuthService✅ newcacheICacheService(existed)searchISearchService(existed)queueIQueueService(existed)file-storageIStorageService(existed)notificationINotificationService(existed)automationIAutomationService✅ newgraphqlIGraphQLService✅ newanalyticsIAnalyticsService✅ newrealtimeIRealtimeService✅ newjobIJobService✅ newaiIAIService✅ newi18nII18nService✅ newuiIUIService✅ newworkflowIWorkflowService✅ newAll contracts follow the established pattern: TypeScript interfaces in
src/contracts/with co-located.test.tsfiles, exported via barrel. 168 test files / 4312 tests pass.💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.