@@ -12,7 +12,59 @@ import {
1212 BatchDataRequestSchema ,
1313 CreateManyDataResponseSchema ,
1414 UpdateManyDataRequestSchema ,
15- DeleteManyDataRequestSchema
15+ DeleteManyDataRequestSchema ,
16+ // Views
17+ ListViewsRequestSchema ,
18+ ListViewsResponseSchema ,
19+ GetViewRequestSchema ,
20+ CreateViewRequestSchema ,
21+ UpdateViewRequestSchema ,
22+ DeleteViewRequestSchema ,
23+ DeleteViewResponseSchema ,
24+ // Permissions
25+ CheckPermissionRequestSchema ,
26+ CheckPermissionResponseSchema ,
27+ GetObjectPermissionsRequestSchema ,
28+ GetObjectPermissionsResponseSchema ,
29+ GetEffectivePermissionsResponseSchema ,
30+ // Workflows
31+ GetWorkflowConfigRequestSchema ,
32+ WorkflowStateSchema ,
33+ GetWorkflowStateRequestSchema ,
34+ WorkflowTransitionRequestSchema ,
35+ WorkflowTransitionResponseSchema ,
36+ WorkflowApproveRequestSchema ,
37+ WorkflowRejectRequestSchema ,
38+ // Realtime
39+ RealtimeConnectRequestSchema ,
40+ RealtimeConnectResponseSchema ,
41+ RealtimeSubscribeRequestSchema ,
42+ RealtimeSubscribeResponseSchema ,
43+ SetPresenceRequestSchema ,
44+ GetPresenceResponseSchema ,
45+ // Notifications
46+ RegisterDeviceRequestSchema ,
47+ RegisterDeviceResponseSchema ,
48+ NotificationPreferencesSchema ,
49+ NotificationSchema ,
50+ ListNotificationsRequestSchema ,
51+ ListNotificationsResponseSchema ,
52+ MarkNotificationsReadRequestSchema ,
53+ // AI
54+ AiNlqRequestSchema ,
55+ AiNlqResponseSchema ,
56+ AiChatRequestSchema ,
57+ AiChatResponseSchema ,
58+ AiSuggestRequestSchema ,
59+ AiSuggestResponseSchema ,
60+ AiInsightsRequestSchema ,
61+ AiInsightsResponseSchema ,
62+ // i18n
63+ GetLocalesResponseSchema ,
64+ GetTranslationsRequestSchema ,
65+ GetTranslationsResponseSchema ,
66+ GetFieldLabelsRequestSchema ,
67+ GetFieldLabelsResponseSchema ,
1668} from './protocol.zod' ;
1769
1870describe ( 'ObjectStack Protocol' , ( ) => {
@@ -115,4 +167,155 @@ describe('ObjectStack Protocol', () => {
115167 expect ( DeleteManyDataRequestSchema . safeParse ( deleteManyReq ) . success ) . toBe ( true ) ;
116168 } ) ;
117169
170+ it ( 'validates Views operations' , ( ) => {
171+ expect ( ListViewsRequestSchema . safeParse ( { object : 'project' , type : 'list' } ) . success ) . toBe ( true ) ;
172+ expect ( ListViewsResponseSchema . safeParse ( {
173+ object : 'project' ,
174+ views : [ { list : { columns : [ ] } } ] ,
175+ } ) . success ) . toBe ( true ) ;
176+ expect ( GetViewRequestSchema . safeParse ( { object : 'project' , viewId : 'v1' } ) . success ) . toBe ( true ) ;
177+ expect ( CreateViewRequestSchema . safeParse ( {
178+ object : 'project' ,
179+ data : { list : { columns : [ ] } } ,
180+ } ) . success ) . toBe ( true ) ;
181+ expect ( UpdateViewRequestSchema . safeParse ( {
182+ object : 'project' ,
183+ viewId : 'v1' ,
184+ data : { list : { columns : [ ] } } ,
185+ } ) . success ) . toBe ( true ) ;
186+ expect ( DeleteViewRequestSchema . safeParse ( { object : 'project' , viewId : 'v1' } ) . success ) . toBe ( true ) ;
187+ expect ( DeleteViewResponseSchema . safeParse ( { object : 'project' , viewId : 'v1' , success : true } ) . success ) . toBe ( true ) ;
188+ } ) ;
189+
190+ it ( 'validates Permissions operations' , ( ) => {
191+ expect ( CheckPermissionRequestSchema . safeParse ( {
192+ object : 'account' ,
193+ action : 'edit' ,
194+ recordId : 'a1' ,
195+ } ) . success ) . toBe ( true ) ;
196+ expect ( CheckPermissionResponseSchema . safeParse ( { allowed : false , reason : 'Insufficient privileges' } ) . success ) . toBe ( true ) ;
197+ expect ( GetObjectPermissionsRequestSchema . safeParse ( { object : 'account' } ) . success ) . toBe ( true ) ;
198+ expect ( GetObjectPermissionsResponseSchema . safeParse ( {
199+ object : 'account' ,
200+ permissions : { allowCreate : true , allowRead : true , allowEdit : false , allowDelete : false } ,
201+ fieldPermissions : { email : { readable : true , editable : false } } ,
202+ } ) . success ) . toBe ( true ) ;
203+ expect ( GetEffectivePermissionsResponseSchema . safeParse ( {
204+ objects : { account : { allowRead : true } } ,
205+ systemPermissions : [ 'manage_users' , 'view_reports' ] ,
206+ } ) . success ) . toBe ( true ) ;
207+ } ) ;
208+
209+ it ( 'validates Workflow operations' , ( ) => {
210+ expect ( GetWorkflowConfigRequestSchema . safeParse ( { object : 'lead' } ) . success ) . toBe ( true ) ;
211+ const state = {
212+ currentState : 'open' ,
213+ availableTransitions : [
214+ { name : 'approve' , targetState : 'approved' , label : 'Approve' , requiresApproval : true } ,
215+ ] ,
216+ history : [ {
217+ fromState : 'draft' , toState : 'open' , action : 'submit' ,
218+ userId : 'u1' , timestamp : '2024-01-15T10:00:00Z' ,
219+ } ] ,
220+ } ;
221+ expect ( WorkflowStateSchema . safeParse ( state ) . success ) . toBe ( true ) ;
222+ expect ( GetWorkflowStateRequestSchema . safeParse ( { object : 'lead' , recordId : 'l1' } ) . success ) . toBe ( true ) ;
223+ expect ( WorkflowTransitionRequestSchema . safeParse ( {
224+ object : 'lead' , recordId : 'l1' , transition : 'approve' , comment : 'Looks good' ,
225+ } ) . success ) . toBe ( true ) ;
226+ expect ( WorkflowTransitionResponseSchema . safeParse ( {
227+ object : 'lead' , recordId : 'l1' , success : true , state,
228+ } ) . success ) . toBe ( true ) ;
229+ expect ( WorkflowApproveRequestSchema . safeParse ( {
230+ object : 'lead' , recordId : 'l1' , comment : 'Approved' ,
231+ } ) . success ) . toBe ( true ) ;
232+ expect ( WorkflowRejectRequestSchema . safeParse ( {
233+ object : 'lead' , recordId : 'l1' , reason : 'Missing info' ,
234+ } ) . success ) . toBe ( true ) ;
235+ } ) ;
236+
237+ it ( 'validates Realtime operations' , ( ) => {
238+ expect ( RealtimeConnectRequestSchema . safeParse ( {
239+ transport : 'websocket' , channels : [ 'project.updates' ] , token : 'tok_abc' ,
240+ } ) . success ) . toBe ( true ) ;
241+ expect ( RealtimeConnectResponseSchema . safeParse ( {
242+ connectionId : 'conn_1' , transport : 'websocket' , url : 'wss://rt.example.com' ,
243+ } ) . success ) . toBe ( true ) ;
244+ expect ( RealtimeSubscribeRequestSchema . safeParse ( {
245+ channel : 'project.updates' , events : [ 'record.created' , 'record.updated' ] ,
246+ } ) . success ) . toBe ( true ) ;
247+ expect ( RealtimeSubscribeResponseSchema . safeParse ( {
248+ subscriptionId : 'sub_1' , channel : 'project.updates' ,
249+ } ) . success ) . toBe ( true ) ;
250+ expect ( SetPresenceRequestSchema . safeParse ( {
251+ channel : 'project.updates' ,
252+ state : { userId : 'u1' , status : 'online' , lastSeen : '2024-01-15T10:00:00Z' } ,
253+ } ) . success ) . toBe ( true ) ;
254+ expect ( GetPresenceResponseSchema . safeParse ( {
255+ channel : 'project.updates' ,
256+ members : [ { userId : 'u1' , status : 'online' , lastSeen : '2024-01-15T10:00:00Z' } ] ,
257+ } ) . success ) . toBe ( true ) ;
258+ } ) ;
259+
260+ it ( 'validates Notification operations' , ( ) => {
261+ expect ( RegisterDeviceRequestSchema . safeParse ( {
262+ token : 'fcm_token_xyz' , platform : 'android' , deviceId : 'dev_1' , name : 'Pixel 8' ,
263+ } ) . success ) . toBe ( true ) ;
264+ expect ( RegisterDeviceResponseSchema . safeParse ( { deviceId : 'dev_1' , success : true } ) . success ) . toBe ( true ) ;
265+ expect ( NotificationPreferencesSchema . safeParse ( {
266+ email : true , push : true , inApp : true , digest : 'daily' ,
267+ channels : { alerts : { enabled : true , push : false } } ,
268+ } ) . success ) . toBe ( true ) ;
269+ expect ( NotificationSchema . safeParse ( {
270+ id : 'n1' , type : 'task_assigned' , title : 'New Task' , body : 'You were assigned a task' ,
271+ read : false , actionUrl : '/tasks/t1' , createdAt : '2024-01-15T10:00:00Z' ,
272+ } ) . success ) . toBe ( true ) ;
273+ expect ( ListNotificationsRequestSchema . safeParse ( { read : false , limit : 10 } ) . success ) . toBe ( true ) ;
274+ expect ( ListNotificationsResponseSchema . safeParse ( {
275+ notifications : [ { id : 'n1' , type : 'info' , title : 'Hi' , body : 'Hello' , read : false , createdAt : '2024-01-15T10:00:00Z' } ] ,
276+ unreadCount : 1 ,
277+ } ) . success ) . toBe ( true ) ;
278+ expect ( MarkNotificationsReadRequestSchema . safeParse ( { ids : [ 'n1' , 'n2' ] } ) . success ) . toBe ( true ) ;
279+ } ) ;
280+
281+ it ( 'validates AI operations' , ( ) => {
282+ expect ( AiNlqRequestSchema . safeParse ( { query : 'show me all open tasks' , object : 'task' } ) . success ) . toBe ( true ) ;
283+ expect ( AiNlqResponseSchema . safeParse ( {
284+ query : { object : 'task' , where : { status : 'open' } } ,
285+ explanation : 'Find all tasks with open status' , confidence : 0.92 ,
286+ } ) . success ) . toBe ( true ) ;
287+ expect ( AiChatRequestSchema . safeParse ( { message : 'How many tasks are overdue?' , conversationId : 'c1' } ) . success ) . toBe ( true ) ;
288+ expect ( AiChatResponseSchema . safeParse ( {
289+ message : 'There are 5 overdue tasks.' , conversationId : 'c1' ,
290+ actions : [ { type : 'navigate' , label : 'View overdue tasks' } ] ,
291+ } ) . success ) . toBe ( true ) ;
292+ expect ( AiSuggestRequestSchema . safeParse ( { object : 'task' , field : 'priority' , partial : 'hi' } ) . success ) . toBe ( true ) ;
293+ expect ( AiSuggestResponseSchema . safeParse ( {
294+ suggestions : [ { value : 'high' , label : 'High' , confidence : 0.95 , reason : 'Matches partial input' } ] ,
295+ } ) . success ) . toBe ( true ) ;
296+ expect ( AiInsightsRequestSchema . safeParse ( { object : 'task' , type : 'trends' } ) . success ) . toBe ( true ) ;
297+ expect ( AiInsightsResponseSchema . safeParse ( {
298+ insights : [ { type : 'trends' , title : 'Task Completion Rate' , description : 'Completion rate increased by 15% this month' , confidence : 0.88 } ] ,
299+ } ) . success ) . toBe ( true ) ;
300+ } ) ;
301+
302+ it ( 'validates i18n operations' , ( ) => {
303+ expect ( GetLocalesResponseSchema . safeParse ( {
304+ locales : [
305+ { code : 'en-US' , label : 'English (US)' , isDefault : true } ,
306+ { code : 'es-ES' , label : 'Spanish (Spain)' } ,
307+ ] ,
308+ } ) . success ) . toBe ( true ) ;
309+ expect ( GetTranslationsRequestSchema . safeParse ( { locale : 'en-US' , namespace : 'objects' } ) . success ) . toBe ( true ) ;
310+ expect ( GetTranslationsResponseSchema . safeParse ( {
311+ locale : 'en-US' ,
312+ translations : { objects : { task : { label : 'Task' , pluralLabel : 'Tasks' } } , messages : { save : 'Save' } } ,
313+ } ) . success ) . toBe ( true ) ;
314+ expect ( GetFieldLabelsRequestSchema . safeParse ( { object : 'task' , locale : 'en-US' } ) . success ) . toBe ( true ) ;
315+ expect ( GetFieldLabelsResponseSchema . safeParse ( {
316+ object : 'task' , locale : 'en-US' ,
317+ labels : { status : { label : 'Status' , help : 'Current task status' , options : { open : 'Open' , closed : 'Closed' } } } ,
318+ } ) . success ) . toBe ( true ) ;
319+ } ) ;
320+
118321} ) ;
0 commit comments