-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcontract.zod.ts
More file actions
231 lines (207 loc) · 8.17 KB
/
contract.zod.ts
File metadata and controls
231 lines (207 loc) · 8.17 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
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
import { z } from 'zod';
import { QuerySchema } from '../data/query.zod';
// ==========================================
// 1. Base Envelopes
// ==========================================
export const ApiErrorSchema = z.object({
code: z.string().describe('Error code (e.g. validation_error)'),
message: z.string().describe('Readable error message'),
category: z.string().optional().describe('Error category (e.g. validation, authorization)'),
details: z.unknown().optional().describe('Additional error context (e.g. field validation errors)'),
requestId: z.string().optional().describe('Request ID for tracking'),
});
export const BaseResponseSchema = z.object({
success: z.boolean().describe('Operation success status'),
error: ApiErrorSchema.optional().describe('Error details if success is false'),
meta: z.object({
timestamp: z.string(),
duration: z.number().optional(),
requestId: z.string().optional(),
traceId: z.string().optional(),
}).optional().describe('Response metadata'),
});
// ==========================================
// 2. Request Payloads (Inputs)
// ==========================================
export const RecordDataSchema = z.record(z.string(), z.unknown()).describe('Key-value map of record data');
/**
* Standard Create Request
*/
export const CreateRequestSchema = z.object({
data: RecordDataSchema.describe('Record data to insert'),
});
/**
* Standard Update Request
*/
export const UpdateRequestSchema = z.object({
data: RecordDataSchema.describe('Partial record data to update'),
});
/**
* Standard Bulk Request
*/
export const BulkRequestSchema = z.object({
records: z.array(RecordDataSchema).describe('Array of records to process'),
allOrNone: z.boolean().default(true).describe('If true, rollback entire transaction on any failure'),
});
/**
* Export Request
*/
export const ExportRequestSchema = z.intersection(
QuerySchema,
z.object({
format: z.enum(['csv', 'json', 'xlsx']).default('csv'),
})
);
// ==========================================
// 3. Response Payloads (Outputs)
// ==========================================
/**
* Single Record Response (Get/Create/Update)
*/
export const SingleRecordResponseSchema = BaseResponseSchema.extend({
data: RecordDataSchema.describe('The requested or modified record'),
});
/**
* List/Query Response
*/
export const ListRecordResponseSchema = BaseResponseSchema.extend({
data: z.array(RecordDataSchema).describe('Array of matching records'),
pagination: z.object({
total: z.number().optional().describe('Total matching records count'),
limit: z.number().optional().describe('Page size'),
offset: z.number().optional().describe('Page offset'),
cursor: z.string().optional().describe('Cursor for next page'),
nextCursor: z.string().optional().describe('Next cursor for pagination'),
hasMore: z.boolean().describe('Are there more pages?'),
}).describe('Pagination info'),
});
/**
* ID Request (Get/Delete)
*/
export const IdRequestSchema = z.object({
id: z.string().describe('Record ID'),
});
/**
* Modification Result (for Batch/Bulk operations)
*/
export const ModificationResultSchema = z.object({
id: z.string().optional().describe('Record ID if processed'),
success: z.boolean(),
errors: z.array(ApiErrorSchema).optional(),
index: z.number().optional().describe('Index in original request'),
data: z.unknown().optional().describe('Result data (e.g. created record)'),
});
/**
* Bulk Operation Response
*/
export const BulkResponseSchema = BaseResponseSchema.extend({
data: z.array(ModificationResultSchema).describe('Results for each item in the batch'),
});
/**
* Delete Response
*/
export const DeleteResponseSchema = BaseResponseSchema.extend({
id: z.string().describe('ID of the deleted record'),
});
// ==========================================
// 4. API Contract Registry
// ==========================================
/**
* Standard API Contracts map
* Used for generating SDKs and Documentation
*/
export const StandardApiContracts = {
create: {
input: CreateRequestSchema,
output: SingleRecordResponseSchema
},
delete: {
input: IdRequestSchema,
output: DeleteResponseSchema
},
get: {
input: IdRequestSchema,
output: SingleRecordResponseSchema
},
update: {
input: UpdateRequestSchema,
output: SingleRecordResponseSchema
},
list: {
input: QuerySchema,
output: ListRecordResponseSchema
},
bulkCreate: {
input: BulkRequestSchema,
output: BulkResponseSchema
},
bulkUpdate: {
input: BulkRequestSchema,
output: BulkResponseSchema
},
bulkUpsert: {
input: BulkRequestSchema,
output: BulkResponseSchema
},
bulkDelete: {
input: z.object({ ids: z.array(z.string()) }),
output: BulkResponseSchema
}
};
// ==========================================
// 5. DataLoader / N+1 Query Prevention
// ==========================================
/**
* DataLoader Configuration Schema
* Batch loading configuration to prevent N+1 query problems
*/
export const DataLoaderConfigSchema = z.object({
maxBatchSize: z.number().int().default(100).describe('Maximum number of keys per batch load'),
batchScheduleFn: z.enum(['microtask', 'timeout', 'manual']).default('microtask')
.describe('Scheduling strategy for collecting batch keys'),
cacheEnabled: z.boolean().default(true).describe('Enable per-request result caching'),
cacheKeyFn: z.string().optional().describe('Name or identifier of the cache key function'),
cacheTtl: z.number().min(0).optional().describe('Cache time-to-live in seconds (0 = no expiration)'),
coalesceRequests: z.boolean().default(true).describe('Deduplicate identical requests within a batch window'),
maxConcurrency: z.number().int().optional().describe('Maximum parallel batch requests'),
});
/**
* Batch Loading Strategy Schema
* Defines how batched data loading is orchestrated
*/
export const BatchLoadingStrategySchema = z.object({
strategy: z.enum(['dataloader', 'windowed', 'prefetch']).describe('Batch loading strategy type'),
windowMs: z.number().optional().describe('Collection window duration in milliseconds (for windowed strategy)'),
prefetchDepth: z.number().int().optional().describe('Depth of relation prefetching (for prefetch strategy)'),
associationLoading: z.enum(['lazy', 'eager', 'batch']).default('batch')
.describe('How to load related associations'),
});
/**
* Query Optimization Configuration Schema
* Top-level configuration for N+1 prevention and query optimization
*/
export const QueryOptimizationConfigSchema = z.object({
preventNPlusOne: z.boolean().describe('Enable N+1 query detection and prevention'),
dataLoader: DataLoaderConfigSchema.optional().describe('DataLoader batch loading configuration'),
batchStrategy: BatchLoadingStrategySchema.optional().describe('Batch loading strategy configuration'),
maxQueryDepth: z.number().int().describe('Maximum depth for nested relation queries'),
queryComplexityLimit: z.number().optional().describe('Maximum allowed query complexity score'),
enableQueryPlan: z.boolean().default(false).describe('Log query execution plans for debugging'),
});
export type ApiError = z.infer<typeof ApiErrorSchema>;
export type BaseResponse = z.infer<typeof BaseResponseSchema>;
export type RecordData = z.infer<typeof RecordDataSchema>;
export type CreateRequest = z.infer<typeof CreateRequestSchema>;
export type UpdateRequest = z.infer<typeof UpdateRequestSchema>;
export type BulkRequest = z.infer<typeof BulkRequestSchema>;
export type ExportRequest = z.infer<typeof ExportRequestSchema>;
export type SingleRecordResponse = z.infer<typeof SingleRecordResponseSchema>;
export type ListRecordResponse = z.infer<typeof ListRecordResponseSchema>;
export type IdRequest = z.infer<typeof IdRequestSchema>;
export type ModificationResult = z.infer<typeof ModificationResultSchema>;
export type BulkResponse = z.infer<typeof BulkResponseSchema>;
export type DeleteResponse = z.infer<typeof DeleteResponseSchema>;
export type DataLoaderConfig = z.infer<typeof DataLoaderConfigSchema>;
export type BatchLoadingStrategy = z.infer<typeof BatchLoadingStrategySchema>;
export type QueryOptimizationConfig = z.infer<typeof QueryOptimizationConfigSchema>;