Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…otocol, hook, widget, core-services schemas Reduces z.any() count from 62 to 9 (remaining 8 are legitimate filter operators in data/filter.zod.ts) Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
… update DEVELOPMENT_PLAN.md - Deduplicate Presence status enum (websocket imports from realtime) - Add 'busy' status to RealtimePresenceStatus - Add missing WidgetSource type export - Update all Phase 1-3 checklist items to completed status Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Refactors the @objectstack/spec Zod definitions based on the schema audit: reducing z.any() usage, deduplicating presence enums across realtime/websocket protocols, and updating the internal development plan to reflect completion status.
Changes:
- Replace many
z.any()occurrences withz.function()/z.unknown()and add missing inferred type exports. - Deduplicate Presence status schemas by re-exporting
RealtimePresenceStatusfrom the WebSocket protocol and extending the canonical enum withbusy. - Update
DEVELOPMENT_PLAN.mdmetrics and phase checklists to reflect current audit results.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/spec/src/ui/widget.zod.ts | Exports WidgetSource type; changes widget callback arg schema from z.any() to z.unknown(). |
| packages/spec/src/system/core-services.zod.ts | Uses z.unknown() for service instances in the kernel service map. |
| packages/spec/src/kernel/plugin.zod.ts | Replaces service method z.any() fields with z.function() and adds hook .describe() annotations. |
| packages/spec/src/data/hook.zod.ts | Changes hook context ql reference from z.any() to z.unknown(). |
| packages/spec/src/api/websocket.zod.ts | Re-exports presence status enum from realtime protocol instead of duplicating it. |
| packages/spec/src/api/realtime.zod.ts | Adds busy to the canonical presence status enum. |
| packages/spec/src/api/realtime.test.ts | Updates tests to accept busy as a valid presence status. |
| packages/spec/src/api/protocol.zod.ts | Replaces protocol method z.any() definitions with z.function(). |
| packages/spec/DEVELOPMENT_PLAN.md | Updates audit metrics table and marks phases/tasks as completed. |
| export const ObjectStackProtocolSchema = z.object({ | ||
| // Discovery & Metadata | ||
| getDiscovery: z.any() | ||
| getDiscovery: z.function() | ||
| .describe('Get API discovery information'), | ||
|
|
||
| getMetaTypes: z.any() | ||
| getMetaTypes: z.function() | ||
| .describe('Get available metadata types'), | ||
|
|
||
| getMetaItems: z.any() | ||
| getMetaItems: z.function() | ||
| .describe('Get all items of a metadata type'), | ||
|
|
||
| getMetaItem: z.any() | ||
| getMetaItem: z.function() | ||
| .describe('Get a specific metadata item'), | ||
| saveMetaItem: z.any() | ||
| saveMetaItem: z.function() | ||
| .describe('Save metadata item'), | ||
| getMetaItemCached: z.any() | ||
| getMetaItemCached: z.function() | ||
| .describe('Get a metadata item with cache validation'), | ||
|
|
||
| getUiView: z.any() | ||
| getUiView: z.function() | ||
| .describe('Get UI view definition'), | ||
|
|
||
| // Analytics Operations | ||
| analyticsQuery: z.any() | ||
| analyticsQuery: z.function() | ||
| .describe('Execute analytics query'), | ||
|
|
||
| getAnalyticsMeta: z.any() | ||
| getAnalyticsMeta: z.function() | ||
| .describe('Get analytics metadata (cubes)'), | ||
|
|
||
| // Automation Operations | ||
| triggerAutomation: z.any() | ||
| triggerAutomation: z.function() | ||
| .describe('Trigger an automation flow or script'), | ||
|
|
||
| // Hub Operations | ||
| listSpaces: z.any() | ||
| listSpaces: z.function() | ||
| .describe('List Hub Spaces'), | ||
|
|
||
| createSpace: z.any() | ||
| createSpace: z.function() | ||
| .describe('Create Hub Space'), | ||
|
|
||
| installPlugin: z.any() | ||
| installPlugin: z.function() | ||
| .describe('Install Plugin into Space'), | ||
|
|
||
| // Package Management Operations | ||
| listPackages: z.any() | ||
| listPackages: z.function() | ||
| .describe('List installed packages with optional filters'), | ||
|
|
||
| getPackage: z.any() | ||
| getPackage: z.function() | ||
| .describe('Get a specific installed package by ID'), | ||
|
|
||
| installPackage: z.any() | ||
| installPackage: z.function() | ||
| .describe('Install a new package from manifest'), | ||
|
|
||
| uninstallPackage: z.any() | ||
| uninstallPackage: z.function() | ||
| .describe('Uninstall a package by ID'), | ||
|
|
||
| enablePackage: z.any() | ||
| enablePackage: z.function() | ||
| .describe('Enable a disabled package'), | ||
|
|
||
| disablePackage: z.any() | ||
| disablePackage: z.function() | ||
| .describe('Disable an installed package'), | ||
|
|
||
| // Data Operations | ||
| findData: z.any() | ||
| findData: z.function() | ||
| .describe('Find data records'), | ||
|
|
||
| getData: z.any() | ||
| getData: z.function() | ||
| .describe('Get single data record'), | ||
|
|
||
| createData: z.any() | ||
| createData: z.function() | ||
| .describe('Create a data record'), | ||
|
|
||
| updateData: z.any() | ||
| updateData: z.function() | ||
| .describe('Update a data record'), | ||
|
|
||
| deleteData: z.any() | ||
| deleteData: z.function() | ||
| .describe('Delete a data record'), | ||
|
|
||
| // Batch Operations | ||
| batchData: z.any() | ||
| batchData: z.function() | ||
| .describe('Perform batch operations'), | ||
|
|
||
| createManyData: z.any() | ||
| createManyData: z.function() | ||
| .describe('Create multiple records'), | ||
|
|
||
| updateManyData: z.any() | ||
| updateManyData: z.function() | ||
| .describe('Update multiple records'), | ||
|
|
||
| deleteManyData: z.any() | ||
| deleteManyData: z.function() | ||
| .describe('Delete multiple records'), | ||
| }); |
There was a problem hiding this comment.
ObjectStackProtocolSchema methods were switched from z.any() to z.function() but none of them define .args(RequestSchema) / .returns(ResponseSchema) (or z.promise(...)). This conflicts with the docstring (“Each method is defined with its request and response schemas”) and will infer the protocol type as no-arg functions, breaking client/server typing. Please wire each function to its corresponding request/response schemas via .args(...) and .returns(...).
| export const PluginContextSchema = z.object({ | ||
| ql: z.object({ | ||
| object: z.any(), // Return any to allow method chaining | ||
| query: z.any(), | ||
| object: z.function().describe('Get object handle for method chaining'), | ||
| query: z.function().describe('Execute a query'), | ||
| }).passthrough().describe('ObjectQL Engine Interface'), | ||
|
|
||
| os: z.object({ | ||
| getCurrentUser: z.any(), | ||
| getConfig: z.any(), | ||
| getCurrentUser: z.function().describe('Get the current authenticated user'), | ||
| getConfig: z.function().describe('Get platform configuration'), | ||
| }).passthrough().describe('ObjectStack Kernel Interface'), | ||
|
|
||
| logger: z.object({ | ||
| debug: z.any(), | ||
| info: z.any(), | ||
| warn: z.any(), | ||
| error: z.any(), | ||
| debug: z.function().describe('Log debug message'), | ||
| info: z.function().describe('Log info message'), | ||
| warn: z.function().describe('Log warning message'), | ||
| error: z.function().describe('Log error message'), | ||
| }).passthrough().describe('Logger Interface'), | ||
|
|
||
| storage: z.object({ | ||
| get: z.any(), | ||
| set: z.any(), | ||
| delete: z.any(), | ||
| get: z.function().describe('Get a value from storage'), | ||
| set: z.function().describe('Set a value in storage'), | ||
| delete: z.function().describe('Delete a value from storage'), | ||
| }).passthrough().describe('Storage Interface'), | ||
|
|
||
| i18n: z.object({ | ||
| t: z.any(), | ||
| getLocale: z.any(), | ||
| t: z.function().describe('Translate a key'), | ||
| getLocale: z.function().describe('Get current locale'), | ||
| }).passthrough().describe('Internationalization Interface'), | ||
|
|
||
| metadata: z.record(z.string(), z.unknown()), | ||
| events: z.record(z.string(), z.unknown()), | ||
|
|
||
| app: z.object({ | ||
| router: z.object({ | ||
| get: z.any(), | ||
| post: z.any(), | ||
| use: z.any(), | ||
| get: z.function().describe('Register GET route handler'), | ||
| post: z.function().describe('Register POST route handler'), | ||
| use: z.function().describe('Register middleware'), | ||
| }).passthrough() | ||
| }).passthrough().describe('App Framework Interface'), | ||
|
|
||
| drivers: z.object({ | ||
| register: z.any(), | ||
| register: z.function().describe('Register a driver'), | ||
| }).passthrough().describe('Driver Registry'), | ||
| }); |
There was a problem hiding this comment.
z.function() is used without .args(...) / .returns(...) for the PluginContext methods. In Zod, omitting these typically infers a () => unknown signature, which prevents consumers from calling e.g. ctx.ql.object('account') or ctx.os.getConfig('key') in TypeScript. Please define minimal call signatures (even if using z.unknown() for params/return), similar to the patterns in data/driver.zod.ts / data/data-engine.zod.ts where every function specifies args/returns.
| export const PluginLifecycleSchema = z.object({ | ||
| onInstall: z.any().optional(), | ||
| onInstall: z.function().optional().describe('Called when plugin is installed'), | ||
|
|
||
| onEnable: z.any().optional(), | ||
| onEnable: z.function().optional().describe('Called when plugin is enabled'), | ||
|
|
||
| onDisable: z.any().optional(), | ||
| onDisable: z.function().optional().describe('Called when plugin is disabled'), | ||
|
|
||
| onUninstall: z.any().optional(), | ||
| onUninstall: z.function().optional().describe('Called when plugin is uninstalled'), | ||
|
|
||
| onUpgrade: z.any().optional(), | ||
| onUpgrade: z.function().optional().describe('Called when plugin is upgraded'), | ||
| }); |
There was a problem hiding this comment.
Lifecycle hooks are now z.function() without .args(...) / .returns(...). This will infer as a no-arg function type, but the hooks are used with parameters (e.g., onInstall(context), onUpgrade(context, fromVersion, toVersion) in plugin.test.ts). Please specify the expected args/returns for each hook (at least (context: PluginContextData) => Promise<void> | void, and for onUpgrade include version args).
Implements findings from
ZOD_SCHEMA_AUDIT_REPORT.md. Reducesz.any()from 62 → 8 (remaining are legitimate filter operators), deduplicates Presence schemas, and updatesDEVELOPMENT_PLAN.mdto reflect actual completion state of all phases.z.any() → z.function() / z.unknown()
logger,storage,i18n,ql,os,router,drivers) and lifecycle hooks now usez.function()with.describe()annotationsObjectStackProtocolSchemamethod definitions converted fromz.any()toz.function()z.unknown()Presence schema deduplication
WebSocketPresenceStatusnow re-exportsRealtimePresenceStatusinstead of defining a duplicate enum. Addedbusyto the canonical enum inrealtime.zod.ts.Missing type exports
Added
WidgetSourcetype export inui/widget.zod.ts.DEVELOPMENT_PLAN.md
Updated all Phase 1–3 checklists to ✅ with actual metrics. Key metrics table now reflects current state (
z.any(): 8,z.unknown(): 340). Phase 4 items remain as future work.💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.