-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathprotocol.zod.ts
More file actions
1433 lines (1255 loc) · 56.5 KB
/
protocol.zod.ts
File metadata and controls
1433 lines (1255 loc) · 56.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
import { z } from 'zod';
import { ViewSchema } from '../ui/view.zod';
import { DiscoverySchema } from './discovery.zod';
import { BatchUpdateRequestSchema, BatchUpdateResponseSchema, BatchOptionsSchema } from './batch.zod';
import { MetadataCacheRequestSchema, MetadataCacheResponseSchema } from './http-cache.zod';
import { QuerySchema } from '../data/query.zod';
import {
AnalyticsQueryRequestSchema,
AnalyticsResultResponseSchema,
GetAnalyticsMetaRequestSchema,
AnalyticsMetadataResponseSchema
} from './analytics.zod';
import { RealtimePresenceSchema, TransportProtocol } from './realtime.zod';
import { ObjectPermissionSchema, FieldPermissionSchema } from '../security/permission.zod';
import { WorkflowRuleSchema } from '../automation/workflow.zod';
import { TranslationDataSchema } from '../system/translation.zod';
import type {
GetFeedRequest,
GetFeedResponse,
CreateFeedItemRequest,
CreateFeedItemResponse,
UpdateFeedItemRequest,
UpdateFeedItemResponse,
DeleteFeedItemRequest,
DeleteFeedItemResponse,
AddReactionRequest,
AddReactionResponse,
RemoveReactionRequest,
RemoveReactionResponse,
PinFeedItemRequest,
PinFeedItemResponse,
UnpinFeedItemRequest,
UnpinFeedItemResponse,
StarFeedItemRequest,
StarFeedItemResponse,
UnstarFeedItemRequest,
UnstarFeedItemResponse,
SearchFeedRequest,
SearchFeedResponse,
GetChangelogRequest,
GetChangelogResponse,
SubscribeRequest,
SubscribeResponse,
FeedUnsubscribeRequest,
UnsubscribeResponse,
} from './feed-api.zod';
import {
ListPackagesRequestSchema,
ListPackagesResponseSchema,
GetPackageRequestSchema,
GetPackageResponseSchema,
InstallPackageRequestSchema,
InstallPackageResponseSchema,
UninstallPackageRequestSchema,
UninstallPackageResponseSchema,
EnablePackageRequestSchema,
EnablePackageResponseSchema,
DisablePackageRequestSchema,
DisablePackageResponseSchema,
} from '../kernel/package-registry.zod';
import type {
ListPackagesRequest,
ListPackagesResponse,
GetPackageRequest,
GetPackageResponse,
InstallPackageRequest,
InstallPackageResponse,
UninstallPackageRequest,
UninstallPackageResponse,
EnablePackageRequest,
EnablePackageResponse,
DisablePackageRequest,
DisablePackageResponse,
InstalledPackage,
PackageStatus,
} from '../kernel/package-registry.zod';
export const AutomationTriggerRequestSchema = z.object({
trigger: z.string(),
payload: z.record(z.string(), z.unknown())
});
export const AutomationTriggerResponseSchema = z.object({
success: z.boolean(),
jobId: z.string().optional(),
result: z.unknown().optional()
});
/**
* ObjectStack Protocol - Zod Schema Definitions
*
* Defines the runtime-validated contract for interacting with ObjectStack metadata and data.
* Used by API adapters (HTTP, WebSocket, gRPC) to fetch data/metadata without knowing engine internals.
*
* This protocol enables:
* - Runtime request/response validation at API gateway level
* - Automatic API documentation generation
* - Type-safe RPC communication between microservices
* - Client SDK generation from schemas
*
* Architecture Alignment:
* - Salesforce: REST API Request/Response schemas
* - Kubernetes: API Resource schemas with runtime validation
* - GraphQL: Schema-first API design
*/
// ==========================================
// Discovery & Metadata Operations
// ==========================================
/**
* Get API Discovery Request
* No parameters needed
*/
export const GetDiscoveryRequestSchema = z.object({});
/**
* Get API Discovery Response
* Derived from DiscoverySchema (single source of truth) for protocol-level use.
*
* All fields from DiscoverySchema are available but made optional (except `version`)
* to support progressive disclosure and backward compatibility with existing clients.
*
* - `routes` provides a flat endpoint map for client routing.
* - `services` is the single source of truth for service availability.
* - `apiName` is kept as an optional alias for `name` for backward compatibility.
*
* @see DiscoverySchema in ./discovery.zod.ts — the canonical definition.
*/
export const GetDiscoveryResponseSchema = DiscoverySchema
.partial()
.required({ version: true })
.extend({
/** @deprecated Use `name` instead. Kept for backward compatibility. */
apiName: z.string().optional().describe('API name (deprecated — use name)'),
});
/**
* Get Metadata Types Request
*/
export const GetMetaTypesRequestSchema = z.object({});
/**
* Get Metadata Types Response
*/
export const GetMetaTypesResponseSchema = z.object({
types: z.array(z.string()).describe('Available metadata type names (e.g., "object", "plugin", "view")'),
});
/**
* Get Metadata Items Request
* Get all items of a specific metadata type
*/
export const GetMetaItemsRequestSchema = z.object({
type: z.string().describe('Metadata type name (e.g., "object", "plugin")'),
packageId: z.string().optional().describe('Optional package ID to filter items by'),
});
/**
* Get Metadata Items Response
*/
export const GetMetaItemsResponseSchema = z.object({
type: z.string().describe('Metadata type name'),
items: z.array(z.unknown()).describe('Array of metadata items'),
});
/**
* Get Metadata Item Request
* Get a specific metadata item by type and name
*/
export const GetMetaItemRequestSchema = z.object({
type: z.string().describe('Metadata type name'),
name: z.string().describe('Item name (snake_case identifier)'),
packageId: z.string().optional().describe('Optional package ID to filter items by'),
});
/**
* Get Metadata Item Response
*/
export const GetMetaItemResponseSchema = z.object({
type: z.string().describe('Metadata type name'),
name: z.string().describe('Item name'),
item: z.unknown().describe('Metadata item definition'),
});
/**
* Save Metadata Item Request
* Create or update a metadata item
*/
export const SaveMetaItemRequestSchema = z.object({
type: z.string().describe('Metadata type name'),
name: z.string().describe('Item name'),
item: z.unknown().describe('Metadata item definition'),
});
/**
* Save Metadata Item Response
*/
export const SaveMetaItemResponseSchema = z.object({
success: z.boolean(),
message: z.string().optional(),
});
/**
* Get Metadata Item with Cache Request
* Get a specific metadata item with HTTP cache validation support
*/
export const GetMetaItemCachedRequestSchema = z.object({
type: z.string().describe('Metadata type name'),
name: z.string().describe('Item name'),
cacheRequest: MetadataCacheRequestSchema.optional().describe('Cache validation parameters'),
});
/**
* Get Metadata Item with Cache Response
* Uses MetadataCacheResponse from http-cache.zod.ts
*/
export const GetMetaItemCachedResponseSchema = MetadataCacheResponseSchema;
/**
* Get UI View Request
* Resolves the appropriate UI view for an object based on context.
* Unlike getMetaItem, this does not require a specific View ID.
*/
export const GetUiViewRequestSchema = z.object({
object: z.string().describe('Object name (snake_case)'),
type: z.enum(['list', 'form']).describe('View type'),
});
/**
* Get UI View Response
*/
export const GetUiViewResponseSchema = ViewSchema;
// ==========================================
// Data Operations
// ==========================================
/**
* Find Data Request
* Defines a query to retrieve records from a specific object.
* Supports filtering, sorting, pagination, and field selection.
*
* @example
* {
* "object": "customers",
* "query": {
* "where": { "status": "active", "revenue": { "$gt": 10000 } },
* "orderBy": [{ "field": "name", "order": "desc" }],
* "limit": 10
* }
* }
*/
export const FindDataRequestSchema = z.object({
object: z.string().describe('The unique machine name of the object to query (e.g. "account").'),
query: QuerySchema.optional().describe('Structured query definition (filter, sort, select, pagination).'),
});
/**
* Find Data Response
* Returns a list of records matching the query criteria.
*/
export const FindDataResponseSchema = z.object({
object: z.string().describe('The object name for the returned records.'),
records: z.array(z.record(z.string(), z.unknown())).describe('The list of matching records.'),
total: z.number().optional().describe('Total number of records matching the filter (if requested).'),
nextCursor: z.string().optional().describe('Cursor for the next page of results (cursor-based pagination).'),
hasMore: z.boolean().optional().describe('True if there are more records available (pagination).'),
});
/**
* HTTP Find Query Parameters
*
* Canonical HTTP query parameter names for GET /data/:object list endpoints.
* The canonical filter parameter is `filter` (singular). The plural `filters` is
* accepted for backward compatibility but `filter` is the standard going forward.
*
* This schema defines the allowlisted query parameters for HTTP GET list requests.
* Server-side parsers (protocol.ts) should accept both `filter` and `filters` and
* normalize to `filter` (singular) internally.
*
* @example
* GET /api/v1/data/contacts?filter={"status":"active"}&select=name,email&top=10&sort=name
*/
export const HttpFindQueryParamsSchema = z.object({
/** @canonical Singular form — the standard going forward. JSON string of filter expression or AST. */
filter: z.string().optional().describe('JSON-encoded filter expression (canonical, singular).'),
/** @deprecated Use `filter` (singular). Accepted for backward compatibility. */
filters: z.string().optional().describe('JSON-encoded filter expression (deprecated plural alias).'),
select: z.string().optional().describe('Comma-separated list of fields to retrieve.'),
sort: z.string().optional().describe('Sort expression (e.g. "name asc,created_at desc" or "-created_at").'),
orderBy: z.string().optional().describe('Alias for sort (OData compatibility).'),
top: z.coerce.number().optional().describe('Max records to return (limit).'),
skip: z.coerce.number().optional().describe('Records to skip (offset).'),
expand: z.string().optional().describe(
'Comma-separated list of lookup/master_detail field names to expand. '
+ 'Resolved to populate array and passed to the engine for batch $in expansion.'
),
search: z.string().optional().describe('Full-text search query.'),
distinct: z.coerce.boolean().optional().describe('SELECT DISTINCT flag.'),
count: z.coerce.boolean().optional().describe('Include total count in response.'),
});
/**
* Get Data Request
* Retrieval of a single record by its unique identifier.
* Only `select` and `expand` are permitted as additional query parameters.
* All other query parameters should be discarded to prevent parameter pollution.
*
* @example
* {
* "object": "contracts",
* "id": "cnt_123456",
* "select": ["name", "status", "amount"],
* "expand": ["owner", "account"]
* }
*/
export const GetDataRequestSchema = z.object({
object: z.string().describe('The object name.'),
id: z.string().describe('The unique record identifier (primary key).'),
select: z.array(z.string()).optional().describe('Fields to include in the response (allowlisted query param).'),
expand: z.array(z.string()).optional().describe(
'Lookup/master_detail field names to expand. '
+ 'The engine resolves these via batch $in queries, replacing foreign key IDs with full objects.'
),
});
/**
* Get Data Response
*/
export const GetDataResponseSchema = z.object({
object: z.string().describe('The object name.'),
id: z.string().describe('The record ID.'),
record: z.record(z.string(), z.unknown()).describe('The complete record data.'),
});
/**
* Create Data Request
* Creation of a new record.
*
* @example
* {
* "object": "leads",
* "data": {
* "first_name": "John",
* "last_name": "Doe",
* "company": "Acme Inc"
* }
* }
*/
export const CreateDataRequestSchema = z.object({
object: z.string().describe('The object name.'),
data: z.record(z.string(), z.unknown()).describe('The dictionary of field values to insert.'),
});
/**
* Create Data Response
*/
export const CreateDataResponseSchema = z.object({
object: z.string().describe('The object name.'),
id: z.string().describe('The ID of the newly created record.'),
record: z.record(z.string(), z.unknown()).describe('The created record, including server-generated fields (created_at, owner).'),
});
/**
* Update Data Request
* Modification of an existing record.
*
* @example
* {
* "object": "tasks",
* "id": "tsk_001",
* "data": {
* "status": "completed",
* "percent_complete": 100
* }
* }
*/
export const UpdateDataRequestSchema = z.object({
object: z.string().describe('The object name.'),
id: z.string().describe('The ID of the record to update.'),
data: z.record(z.string(), z.unknown()).describe('The fields to update (partial update).'),
});
/**
* Update Data Response
*/
export const UpdateDataResponseSchema = z.object({
object: z.string().describe('Object name'),
id: z.string().describe('Updated record ID'),
record: z.record(z.string(), z.unknown()).describe('Updated record'),
});
/**
* Delete Data Request
*/
export const DeleteDataRequestSchema = z.object({
object: z.string().describe('Object name'),
id: z.string().describe('Record ID to delete'),
});
/**
* Delete Data Response
*/
export const DeleteDataResponseSchema = z.object({
object: z.string().describe('Object name'),
id: z.string().describe('Deleted record ID'),
success: z.boolean().describe('Whether deletion succeeded'),
});
// ==========================================
// Batch Operations
// ==========================================
/**
* Batch Data Request
*/
export const BatchDataRequestSchema = z.object({
object: z.string().describe('Object name'),
request: BatchUpdateRequestSchema.describe('Batch operation request'),
});
/**
* Batch Data Response
* Uses BatchUpdateResponse from batch.zod.ts
*/
export const BatchDataResponseSchema = BatchUpdateResponseSchema;
/**
* Create Many Data Request
*/
export const CreateManyDataRequestSchema = z.object({
object: z.string().describe('Object name'),
records: z.array(z.record(z.string(), z.unknown())).describe('Array of records to create'),
});
/**
* Create Many Data Response
*/
export const CreateManyDataResponseSchema = z.object({
object: z.string().describe('Object name'),
records: z.array(z.record(z.string(), z.unknown())).describe('Created records'),
count: z.number().describe('Number of records created'),
});
/**
* Update Many Data Request
*/
export const UpdateManyDataRequestSchema = z.object({
object: z.string().describe('Object name'),
records: z.array(z.object({
id: z.string().describe('Record ID'),
data: z.record(z.string(), z.unknown()).describe('Fields to update'),
})).describe('Array of updates'),
options: BatchOptionsSchema.optional().describe('Update options'),
});
/**
* Update Many Data Response
* Uses BatchUpdateResponse for consistency
*/
export const UpdateManyDataResponseSchema = BatchUpdateResponseSchema;
/**
* Delete Many Data Request
*/
export const DeleteManyDataRequestSchema = z.object({
object: z.string().describe('Object name'),
ids: z.array(z.string()).describe('Array of record IDs to delete'),
options: BatchOptionsSchema.optional().describe('Delete options'),
});
/**
* Delete Many Data Response
*/
export const DeleteManyDataResponseSchema = BatchUpdateResponseSchema;
// ==========================================
// Package Management Operations
// ==========================================
/**
* Re-export Package Management Request/Response schemas from kernel.
* These define the contract for package lifecycle management:
* - List installed packages (with filters)
* - Get a specific package by ID
* - Install a new package (from manifest)
* - Uninstall a package
* - Enable/Disable a package
*
* Key distinction: Package (ManifestSchema) is the unit of installation.
* An App (AppSchema) is a UI navigation entity within a package.
* A package may contain 0, 1, or many apps.
*/
export {
ListPackagesRequestSchema,
ListPackagesResponseSchema,
GetPackageRequestSchema,
GetPackageResponseSchema,
InstallPackageRequestSchema,
InstallPackageResponseSchema,
UninstallPackageRequestSchema,
UninstallPackageResponseSchema,
EnablePackageRequestSchema,
EnablePackageResponseSchema,
DisablePackageRequestSchema,
DisablePackageResponseSchema,
};
// ==========================================
// View Management Operations
// ==========================================
export const ListViewsRequestSchema = z.object({
object: z.string().describe('Object name (snake_case)'),
type: z.enum(['list', 'form']).optional().describe('Filter by view type'),
});
export const ListViewsResponseSchema = z.object({
object: z.string().describe('Object name'),
views: z.array(ViewSchema).describe('Array of view definitions'),
});
export const GetViewRequestSchema = z.object({
object: z.string().describe('Object name (snake_case)'),
viewId: z.string().describe('View identifier'),
});
export const GetViewResponseSchema = z.object({
object: z.string().describe('Object name'),
view: ViewSchema.describe('View definition'),
});
export const CreateViewRequestSchema = z.object({
object: z.string().describe('Object name (snake_case)'),
data: ViewSchema.describe('View definition to create'),
});
export const CreateViewResponseSchema = z.object({
object: z.string().describe('Object name'),
viewId: z.string().describe('Created view identifier'),
view: ViewSchema.describe('Created view definition'),
});
export const UpdateViewRequestSchema = z.object({
object: z.string().describe('Object name (snake_case)'),
viewId: z.string().describe('View identifier'),
data: ViewSchema.partial().describe('Partial view data to update'),
});
export const UpdateViewResponseSchema = z.object({
object: z.string().describe('Object name'),
viewId: z.string().describe('Updated view identifier'),
view: ViewSchema.describe('Updated view definition'),
});
export const DeleteViewRequestSchema = z.object({
object: z.string().describe('Object name (snake_case)'),
viewId: z.string().describe('View identifier to delete'),
});
export const DeleteViewResponseSchema = z.object({
object: z.string().describe('Object name'),
viewId: z.string().describe('Deleted view identifier'),
success: z.boolean().describe('Whether deletion succeeded'),
});
// ==========================================
// Permission Operations
// ==========================================
export const CheckPermissionRequestSchema = z.object({
object: z.string().describe('Object name to check permissions for'),
action: z.enum(['create', 'read', 'edit', 'delete', 'transfer', 'restore', 'purge']).describe('Action to check'),
recordId: z.string().optional().describe('Specific record ID (for record-level checks)'),
field: z.string().optional().describe('Specific field name (for field-level checks)'),
});
export const CheckPermissionResponseSchema = z.object({
allowed: z.boolean().describe('Whether the action is permitted'),
reason: z.string().optional().describe('Reason if denied'),
});
export const GetObjectPermissionsRequestSchema = z.object({
object: z.string().describe('Object name to get permissions for'),
});
export const GetObjectPermissionsResponseSchema = z.object({
object: z.string().describe('Object name'),
permissions: ObjectPermissionSchema.describe('Object-level permissions'),
fieldPermissions: z.record(z.string(), FieldPermissionSchema).optional().describe('Field-level permissions keyed by field name'),
});
export const GetEffectivePermissionsRequestSchema = z.object({});
export const GetEffectivePermissionsResponseSchema = z.object({
objects: z.record(z.string(), ObjectPermissionSchema).describe('Effective object permissions keyed by object name'),
systemPermissions: z.array(z.string()).describe('Effective system-level permissions'),
});
// ==========================================
// Workflow Operations
// ==========================================
export const GetWorkflowConfigRequestSchema = z.object({
object: z.string().describe('Object name to get workflow config for'),
});
export const GetWorkflowConfigResponseSchema = z.object({
object: z.string().describe('Object name'),
workflows: z.array(WorkflowRuleSchema).describe('Active workflow rules for this object'),
});
export const WorkflowStateSchema = z.object({
currentState: z.string().describe('Current workflow state name'),
availableTransitions: z.array(z.object({
name: z.string().describe('Transition name'),
targetState: z.string().describe('Target state after transition'),
label: z.string().optional().describe('Display label'),
requiresApproval: z.boolean().default(false).describe('Whether transition requires approval'),
})).describe('Available transitions from current state'),
history: z.array(z.object({
fromState: z.string().describe('Previous state'),
toState: z.string().describe('New state'),
action: z.string().describe('Action that triggered the transition'),
userId: z.string().describe('User who performed the action'),
timestamp: z.string().datetime().describe('When the transition occurred'),
comment: z.string().optional().describe('Optional comment'),
})).optional().describe('State transition history'),
});
export const GetWorkflowStateRequestSchema = z.object({
object: z.string().describe('Object name'),
recordId: z.string().describe('Record ID to get workflow state for'),
});
export const GetWorkflowStateResponseSchema = z.object({
object: z.string().describe('Object name'),
recordId: z.string().describe('Record ID'),
state: WorkflowStateSchema.describe('Current workflow state and available transitions'),
});
export const WorkflowTransitionRequestSchema = z.object({
object: z.string().describe('Object name'),
recordId: z.string().describe('Record ID'),
transition: z.string().describe('Transition name to execute'),
comment: z.string().optional().describe('Optional comment for the transition'),
data: z.record(z.string(), z.unknown()).optional().describe('Additional data for the transition'),
});
export const WorkflowTransitionResponseSchema = z.object({
object: z.string().describe('Object name'),
recordId: z.string().describe('Record ID'),
success: z.boolean().describe('Whether the transition succeeded'),
state: WorkflowStateSchema.describe('New workflow state after transition'),
});
export const WorkflowApproveRequestSchema = z.object({
object: z.string().describe('Object name'),
recordId: z.string().describe('Record ID'),
comment: z.string().optional().describe('Approval comment'),
data: z.record(z.string(), z.unknown()).optional().describe('Additional data'),
});
export const WorkflowApproveResponseSchema = z.object({
object: z.string().describe('Object name'),
recordId: z.string().describe('Record ID'),
success: z.boolean().describe('Whether the approval succeeded'),
state: WorkflowStateSchema.describe('New workflow state after approval'),
});
export const WorkflowRejectRequestSchema = z.object({
object: z.string().describe('Object name'),
recordId: z.string().describe('Record ID'),
reason: z.string().describe('Rejection reason'),
comment: z.string().optional().describe('Additional comment'),
});
export const WorkflowRejectResponseSchema = z.object({
object: z.string().describe('Object name'),
recordId: z.string().describe('Record ID'),
success: z.boolean().describe('Whether the rejection succeeded'),
state: WorkflowStateSchema.describe('New workflow state after rejection'),
});
// ==========================================
// Realtime Operations
// ==========================================
export const RealtimeConnectRequestSchema = z.object({
transport: TransportProtocol.optional().describe('Preferred transport protocol'),
channels: z.array(z.string()).optional().describe('Channels to subscribe to on connect'),
token: z.string().optional().describe('Authentication token'),
});
export const RealtimeConnectResponseSchema = z.object({
connectionId: z.string().describe('Unique connection identifier'),
transport: TransportProtocol.describe('Negotiated transport protocol'),
url: z.string().optional().describe('WebSocket/SSE endpoint URL'),
});
export const RealtimeDisconnectRequestSchema = z.object({
connectionId: z.string().optional().describe('Connection ID to disconnect'),
});
export const RealtimeDisconnectResponseSchema = z.object({
success: z.boolean().describe('Whether disconnection succeeded'),
});
export const RealtimeSubscribeRequestSchema = z.object({
channel: z.string().describe('Channel name to subscribe to'),
events: z.array(z.string()).optional().describe('Specific event types to listen for'),
filter: z.record(z.string(), z.unknown()).optional().describe('Event filter criteria'),
});
export const RealtimeSubscribeResponseSchema = z.object({
subscriptionId: z.string().describe('Unique subscription identifier'),
channel: z.string().describe('Subscribed channel name'),
});
export const RealtimeUnsubscribeRequestSchema = z.object({
subscriptionId: z.string().describe('Subscription ID to cancel'),
});
export const RealtimeUnsubscribeResponseSchema = z.object({
success: z.boolean().describe('Whether unsubscription succeeded'),
});
export const SetPresenceRequestSchema = z.object({
channel: z.string().describe('Channel to set presence in'),
state: RealtimePresenceSchema.describe('Presence state to set'),
});
export const SetPresenceResponseSchema = z.object({
success: z.boolean().describe('Whether presence was set'),
});
export const GetPresenceRequestSchema = z.object({
channel: z.string().describe('Channel to get presence for'),
});
export const GetPresenceResponseSchema = z.object({
channel: z.string().describe('Channel name'),
members: z.array(RealtimePresenceSchema).describe('Active members and their presence state'),
});
// ==========================================
// Notification Operations
// ==========================================
export const RegisterDeviceRequestSchema = z.object({
token: z.string().describe('Device push notification token'),
platform: z.enum(['ios', 'android', 'web']).describe('Device platform'),
deviceId: z.string().optional().describe('Unique device identifier'),
name: z.string().optional().describe('Device friendly name'),
});
export const RegisterDeviceResponseSchema = z.object({
deviceId: z.string().describe('Registered device ID'),
success: z.boolean().describe('Whether registration succeeded'),
});
export const UnregisterDeviceRequestSchema = z.object({
deviceId: z.string().describe('Device ID to unregister'),
});
export const UnregisterDeviceResponseSchema = z.object({
success: z.boolean().describe('Whether unregistration succeeded'),
});
export const NotificationPreferencesSchema = z.object({
email: z.boolean().default(true).describe('Receive email notifications'),
push: z.boolean().default(true).describe('Receive push notifications'),
inApp: z.boolean().default(true).describe('Receive in-app notifications'),
digest: z.enum(['none', 'daily', 'weekly']).default('none').describe('Email digest frequency'),
channels: z.record(z.string(), z.object({
enabled: z.boolean().default(true).describe('Whether this channel is enabled'),
email: z.boolean().optional().describe('Override email setting'),
push: z.boolean().optional().describe('Override push setting'),
})).optional().describe('Per-channel notification preferences'),
});
export const GetNotificationPreferencesRequestSchema = z.object({});
export const GetNotificationPreferencesResponseSchema = z.object({
preferences: NotificationPreferencesSchema.describe('Current notification preferences'),
});
export const UpdateNotificationPreferencesRequestSchema = z.object({
preferences: NotificationPreferencesSchema.partial().describe('Preferences to update'),
});
export const UpdateNotificationPreferencesResponseSchema = z.object({
preferences: NotificationPreferencesSchema.describe('Updated notification preferences'),
});
export const NotificationSchema = z.object({
id: z.string().describe('Notification ID'),
type: z.string().describe('Notification type'),
title: z.string().describe('Notification title'),
body: z.string().describe('Notification body text'),
read: z.boolean().default(false).describe('Whether notification has been read'),
data: z.record(z.string(), z.unknown()).optional().describe('Additional notification data'),
actionUrl: z.string().optional().describe('URL to navigate to when clicked'),
createdAt: z.string().datetime().describe('When notification was created'),
});
export const ListNotificationsRequestSchema = z.object({
read: z.boolean().optional().describe('Filter by read status'),
type: z.string().optional().describe('Filter by notification type'),
limit: z.number().default(20).describe('Maximum number of notifications to return'),
cursor: z.string().optional().describe('Pagination cursor'),
});
export const ListNotificationsResponseSchema = z.object({
notifications: z.array(NotificationSchema).describe('List of notifications'),
unreadCount: z.number().describe('Total number of unread notifications'),
cursor: z.string().optional().describe('Next page cursor'),
});
export const MarkNotificationsReadRequestSchema = z.object({
ids: z.array(z.string()).describe('Notification IDs to mark as read'),
});
export const MarkNotificationsReadResponseSchema = z.object({
success: z.boolean().describe('Whether the operation succeeded'),
readCount: z.number().describe('Number of notifications marked as read'),
});
export const MarkAllNotificationsReadRequestSchema = z.object({});
export const MarkAllNotificationsReadResponseSchema = z.object({
success: z.boolean().describe('Whether the operation succeeded'),
readCount: z.number().describe('Number of notifications marked as read'),
});
// ==========================================
// AI Operations
// ==========================================
export const AiNlqRequestSchema = z.object({
query: z.string().describe('Natural language query string'),
object: z.string().optional().describe('Target object context'),
conversationId: z.string().optional().describe('Conversation ID for multi-turn queries'),
});
export const AiNlqResponseSchema = z.object({
query: z.unknown().describe('Generated structured query (AST)'),
explanation: z.string().optional().describe('Human-readable explanation of the query'),
confidence: z.number().min(0).max(1).optional().describe('Confidence score (0-1)'),
suggestions: z.array(z.string()).optional().describe('Suggested follow-up queries'),
});
// AiChatRequestSchema and AiChatResponseSchema have been removed.
// The AI chat wire protocol is now fully aligned with the Vercel AI SDK (`ai`).
// Frontend consumers should use `@ai-sdk/react/useChat` directly.
// See: https://ai-sdk.dev/docs
export const AiSuggestRequestSchema = z.object({
object: z.string().describe('Object name for context'),
field: z.string().optional().describe('Field to suggest values for'),
recordId: z.string().optional().describe('Record ID for context'),
partial: z.string().optional().describe('Partial input for completion'),
});
export const AiSuggestResponseSchema = z.object({
suggestions: z.array(z.object({
value: z.unknown().describe('Suggested value'),
label: z.string().describe('Display label'),
confidence: z.number().min(0).max(1).optional().describe('Confidence score (0-1)'),
reason: z.string().optional().describe('Reason for this suggestion'),
})).describe('Suggested values'),
});
export const AiInsightsRequestSchema = z.object({
object: z.string().describe('Object name to analyze'),
recordId: z.string().optional().describe('Specific record to analyze'),
type: z.enum(['summary', 'trends', 'anomalies', 'recommendations']).optional().describe('Type of insight'),
});
export const AiInsightsResponseSchema = z.object({
insights: z.array(z.object({
type: z.string().describe('Insight type'),
title: z.string().describe('Insight title'),
description: z.string().describe('Detailed description'),
confidence: z.number().min(0).max(1).optional().describe('Confidence score (0-1)'),
data: z.record(z.string(), z.unknown()).optional().describe('Supporting data'),
})).describe('Generated insights'),
});
// ==========================================
// i18n Operations
// ==========================================
export const GetLocalesRequestSchema = z.object({});
export const GetLocalesResponseSchema = z.object({
locales: z.array(z.object({
code: z.string().describe('BCP-47 locale code (e.g., en-US, zh-CN)'),
label: z.string().describe('Display name of the locale'),
isDefault: z.boolean().default(false).describe('Whether this is the default locale'),
})).describe('Available locales'),
});
export const GetTranslationsRequestSchema = z.object({
locale: z.string().describe('BCP-47 locale code'),
namespace: z.string().optional().describe('Translation namespace (e.g., objects, apps, messages)'),
keys: z.array(z.string()).optional().describe('Specific translation keys to fetch'),
});
export const GetTranslationsResponseSchema = z.object({
locale: z.string().describe('Locale code'),
translations: TranslationDataSchema.describe('Translation data'),
});
export const GetFieldLabelsRequestSchema = z.object({
object: z.string().describe('Object name'),
locale: z.string().describe('BCP-47 locale code'),
});
export const GetFieldLabelsResponseSchema = z.object({
object: z.string().describe('Object name'),
locale: z.string().describe('Locale code'),
labels: z.record(z.string(), z.object({
label: z.string().describe('Translated field label'),
help: z.string().optional().describe('Translated help text'),
options: z.record(z.string(), z.string()).optional().describe('Translated option labels'),
})).describe('Field labels keyed by field name'),
});
// ==========================================
// Protocol Interface Schema
// ==========================================
/**
* ObjectStack Protocol Contract
*
* This schema defines the complete API contract as a Zod schema.
* Unlike the old TypeScript interface, this provides runtime validation
* and can be used for:
* - API Gateway validation
* - RPC call validation
* - Client SDK generation
* - API documentation generation
*
* Each method is defined with its request and response schemas.
*/
export const ObjectStackProtocolSchema = z.object({
// Discovery & Metadata
getDiscovery: z.function()
.describe('Get API discovery information'),
getMetaTypes: z.function()
.describe('Get available metadata types'),
getMetaItems: z.function()
.describe('Get all items of a metadata type'),
getMetaItem: z.function()
.describe('Get a specific metadata item'),
saveMetaItem: z.function()
.describe('Save metadata item'),
getMetaItemCached: z.function()
.describe('Get a metadata item with cache validation'),
getUiView: z.function()
.describe('Get UI view definition'),
// Analytics Operations
analyticsQuery: z.function()
.describe('Execute analytics query'),
getAnalyticsMeta: z.function()
.describe('Get analytics metadata (cubes)'),
// Automation Operations
triggerAutomation: z.function()
.describe('Trigger an automation flow or script'),
// Package Management Operations
listPackages: z.function()
.describe('List installed packages with optional filters'),
getPackage: z.function()
.describe('Get a specific installed package by ID'),
installPackage: z.function()
.describe('Install a new package from manifest'),
uninstallPackage: z.function()
.describe('Uninstall a package by ID'),
enablePackage: z.function()
.describe('Enable a disabled package'),
disablePackage: z.function()
.describe('Disable an installed package'),