meebly-onboarding-mcp-server 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,724 @@
1
+ import { z } from 'zod';
2
+ import { ApiError } from './errorUtils.js';
3
+ import { HTTP_STATUS } from '../constants/index.js';
4
+ export function requireString(obj, fieldName, customMessage) {
5
+ const value = obj?.[fieldName];
6
+ if (!value || typeof value !== 'string' || value.trim().length === 0) {
7
+ throw new ApiError(customMessage ||
8
+ `${fieldName} is required and must be a non-empty string`, HTTP_STATUS.BAD_REQUEST);
9
+ }
10
+ return value.trim();
11
+ }
12
+ export function optionalString(obj, fieldName, customMessage) {
13
+ const value = obj?.[fieldName];
14
+ if (value === undefined)
15
+ return undefined;
16
+ if (typeof value !== 'string' || value.trim().length === 0) {
17
+ throw new ApiError(customMessage || `${fieldName} must be a non-empty string when provided`, HTTP_STATUS.BAD_REQUEST);
18
+ }
19
+ return value.trim();
20
+ }
21
+ export function optionalBoolean(obj, fieldName, customMessage) {
22
+ const value = obj?.[fieldName];
23
+ if (value === undefined)
24
+ return undefined;
25
+ if (typeof value !== 'boolean') {
26
+ throw new ApiError(customMessage || `${fieldName} must be a boolean when provided`, HTTP_STATUS.BAD_REQUEST);
27
+ }
28
+ return value;
29
+ }
30
+ export function requireArray(obj, fieldName, customMessage) {
31
+ const value = obj?.[fieldName];
32
+ if (!Array.isArray(value)) {
33
+ throw new ApiError(customMessage || `${fieldName} must be an array`, HTTP_STATUS.BAD_REQUEST);
34
+ }
35
+ return value;
36
+ }
37
+ export function requireMessageArray(obj, fieldName = 'messages') {
38
+ const messages = requireArray(obj, fieldName);
39
+ if (messages.some((m) => !m || typeof m.content !== 'string')) {
40
+ throw new ApiError(`${fieldName} must be an array of objects with content property`, HTTP_STATUS.BAD_REQUEST);
41
+ }
42
+ return messages;
43
+ }
44
+ export function requireEnum(obj, fieldName, allowedValues, customMessage) {
45
+ const value = requireString(obj, fieldName);
46
+ if (!allowedValues.includes(value)) {
47
+ throw new ApiError(customMessage ||
48
+ `${fieldName} must be one of: ${allowedValues.join(', ')}`, HTTP_STATUS.BAD_REQUEST);
49
+ }
50
+ return value;
51
+ }
52
+ export function optionalEnum(obj, fieldName, allowedValues, customMessage) {
53
+ const value = obj?.[fieldName];
54
+ if (value === undefined)
55
+ return undefined;
56
+ if (typeof value !== 'string' || !allowedValues.includes(value)) {
57
+ throw new ApiError(customMessage ||
58
+ `${fieldName} must be one of: ${allowedValues.join(', ')} when provided`, HTTP_STATUS.BAD_REQUEST);
59
+ }
60
+ return value;
61
+ }
62
+ export function validateRequiredParams(params, requiredParams) {
63
+ const missing = requiredParams.filter((p) => params?.[p] === undefined || params?.[p] === null || params?.[p] === '');
64
+ if (missing.length > 0) {
65
+ throw new ApiError(`Missing required parameters: ${missing.join(', ')}`, HTTP_STATUS.BAD_REQUEST);
66
+ }
67
+ }
68
+ export function validateUrl(url, paramName = 'url') {
69
+ try {
70
+ new URL(url);
71
+ }
72
+ catch {
73
+ throw new ApiError(`Invalid ${paramName} format`, HTTP_STATUS.BAD_REQUEST);
74
+ }
75
+ }
76
+ export function validateEmail(email) {
77
+ try {
78
+ z.string().email().parse(email);
79
+ }
80
+ catch {
81
+ throw new ApiError('Invalid email format', HTTP_STATUS.BAD_REQUEST);
82
+ }
83
+ }
84
+ const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
85
+ const OBJECT_ID_REGEX = /^[0-9a-fA-F]{24}$/;
86
+ export function validateId(value, { fieldName = 'id', kind = 'string', } = {}) {
87
+ if (typeof value !== 'string' || value.trim() === '') {
88
+ throw new ApiError(`${fieldName} is required and must be a string`, HTTP_STATUS.BAD_REQUEST);
89
+ }
90
+ const v = value.trim();
91
+ if (kind === 'uuid' && !UUID_REGEX.test(v)) {
92
+ throw new ApiError(`Invalid ${fieldName} format. Expected UUID.`, HTTP_STATUS.BAD_REQUEST);
93
+ }
94
+ if (kind === 'objectId' && !OBJECT_ID_REGEX.test(v)) {
95
+ throw new ApiError(`Invalid ${fieldName} format. Expected 24-char hex ObjectId.`, HTTP_STATUS.BAD_REQUEST);
96
+ }
97
+ return v;
98
+ }
99
+ export function validateBody(data, schema) {
100
+ try {
101
+ return schema.parse(data);
102
+ }
103
+ catch (error) {
104
+ if (error instanceof z.ZodError) {
105
+ const errorMessage = error.issues
106
+ .map((err) => `${err.path.join('.')}: ${err.message}`)
107
+ .join(', ');
108
+ throw new ApiError(`Validation error: ${errorMessage}`, HTTP_STATUS.BAD_REQUEST, error.issues);
109
+ }
110
+ throw error;
111
+ }
112
+ }
113
+ export const HttpMethodEnum = z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH']);
114
+ export const InviteStatusEnum = z.enum([
115
+ 'pending',
116
+ 'accepted',
117
+ 'expired',
118
+ 'revoked',
119
+ ]);
120
+ export const OrganizationRoleEnum = z.enum(['Owner', 'Member', 'Admin']);
121
+ /* ------------------------------------ */
122
+ /* Field Validation Schemas */
123
+ /* ------------------------------------ */
124
+ /** Supported field types */
125
+ export const FieldTypeSchema = z.enum([
126
+ 'string',
127
+ 'number',
128
+ 'integer',
129
+ 'boolean',
130
+ 'array',
131
+ 'object',
132
+ 'date',
133
+ 'datetime',
134
+ 'uuid',
135
+ 'email',
136
+ 'url',
137
+ 'file',
138
+ ]);
139
+ /** Field configuration (recursive for nested properties) */
140
+ export const FieldSchema = z.lazy(() => z.object({
141
+ type: FieldTypeSchema,
142
+ requiredByBackend: z.boolean().optional().default(false),
143
+ fieldInstructions: z.string().optional(),
144
+ format: z.string().optional(),
145
+ items: FieldSchema.optional(),
146
+ example: z.any().optional(),
147
+ location: z.enum(['query', 'path', 'body']).optional(),
148
+ properties: z.record(z.string(), FieldSchema).optional(),
149
+ }));
150
+ /** Field collection - supports both simple and complex formats */
151
+ export const FieldsSchema = z.record(z.string(), FieldSchema);
152
+ export const SimpleFieldsSchema = z.record(z.string(), FieldTypeSchema);
153
+ export const FlexibleFieldsSchema = z.union([SimpleFieldsSchema, FieldsSchema]);
154
+ /* ------------------------------------ */
155
+ /* Chat Validation Schemas */
156
+ /* ------------------------------------ */
157
+ /** Uploaded file metadata */
158
+ export const UploadedFileSchema = z.object({
159
+ url: z.string().min(1, 'File url is required'),
160
+ name: z.string().min(1, 'name is required'),
161
+ type: z.string().min(1, 'MIME type is required'),
162
+ });
163
+ /** Uploaded files collection */
164
+ export const UploadedFilesSchema = z
165
+ .record(z.string(), UploadedFileSchema)
166
+ .optional();
167
+ /** Chat message structure */
168
+ export const ChatMessageSchema = z.object({
169
+ agentId: z.string().min(1, 'agentId is required'),
170
+ apiKey: z.string().min(1, 'apiKey is required'),
171
+ environmentId: z.string().min(1, 'environmentId is required'),
172
+ messages: z
173
+ .array(z.object({
174
+ content: z.string().min(1, 'Message content is required'),
175
+ }))
176
+ .min(1, 'At least one message is required'),
177
+ customerId: z.string().optional(),
178
+ customInstructions: z.string().optional(),
179
+ logChannelId: z.string().optional(),
180
+ logToolScore: z.boolean().optional().default(false),
181
+ threadId: z.string().optional(),
182
+ uploadedFiles: UploadedFilesSchema.optional(),
183
+ });
184
+ export const EphemeralChatMessageSchema = z.object({
185
+ apiKey: z.string().min(1, 'apiKey is required'),
186
+ environmentId: z.string().min(1, 'environmentId is required'),
187
+ messages: z
188
+ .array(z.object({
189
+ content: z.string().min(1, 'Message content is required'),
190
+ }))
191
+ .min(1, 'At least one message is required'),
192
+ authToken: z.string().optional(),
193
+ customInstructions: z.string().optional(),
194
+ endpointDefinition: z.any().optional(),
195
+ endpointId: z.string().optional(),
196
+ logChannelId: z.string().optional(),
197
+ threadId: z.string().optional(),
198
+ uploadedFiles: UploadedFilesSchema.optional(),
199
+ mcpToolId: z.string().optional(),
200
+ });
201
+ /** Screen state schema for context from host app */
202
+ export const ScreenStateSchema = z.object({
203
+ route: z.string().min(1, 'route is required'),
204
+ routeName: z.string().optional(),
205
+ entities: z.record(z.string(), z.any()).optional(),
206
+ observedElements: z
207
+ .array(z.object({
208
+ selector: z.string(),
209
+ text: z.string().optional(),
210
+ attributes: z.record(z.string(), z.string()).optional(),
211
+ }))
212
+ .optional(),
213
+ timestamp: z.string(),
214
+ viewportSize: z
215
+ .object({
216
+ width: z.number(),
217
+ height: z.number(),
218
+ })
219
+ .optional(),
220
+ });
221
+ export const EmbedChatMessageSchema = z.object({
222
+ embedToken: z.string().min(1, 'embedToken is required').optional(),
223
+ messages: z
224
+ .array(z.object({
225
+ content: z.string().min(1, 'Message content is required'),
226
+ }))
227
+ .min(1, 'At least one message is required'),
228
+ customerId: z.string().optional(),
229
+ customInstructions: z.string().optional(),
230
+ encryptedBackendToken: z.string().optional(),
231
+ threadId: z.string().optional(),
232
+ uploadedFiles: UploadedFilesSchema.optional(),
233
+ parentDomain: z.string().optional(),
234
+ screenState: ScreenStateSchema.optional(),
235
+ });
236
+ const ToolExecutionFilePartSchema = z.object({
237
+ name: z.string().nullable().optional(),
238
+ type: z.string().nullable().optional(),
239
+ size: z.number().nullable().optional(),
240
+ base64: z.string().nullable().optional(),
241
+ });
242
+ const ToolExecutionPayloadSchema = z.union([
243
+ z.object({
244
+ type: z.literal('none'),
245
+ }),
246
+ z.object({
247
+ type: z.literal('json'),
248
+ body: z.any().optional(),
249
+ }),
250
+ z.object({
251
+ type: z.literal('form-data'),
252
+ fields: z.record(z.string(), z.any()).optional().default({}),
253
+ files: z
254
+ .record(z.string(), z.union([
255
+ ToolExecutionFilePartSchema,
256
+ z.array(ToolExecutionFilePartSchema),
257
+ ]))
258
+ .optional()
259
+ .default({}),
260
+ }),
261
+ ]);
262
+ export const PingMateManualRunSchema = z.object({
263
+ apiKey: z.string().min(1, 'apiKey is required'),
264
+ environmentId: z.string().min(1, 'environmentId is required'),
265
+ method: HttpMethodEnum,
266
+ url: z.string().min(1, 'url is required'),
267
+ headers: z
268
+ .record(z.string(), z.union([z.string(), z.number(), z.boolean()]).nullable())
269
+ .optional(),
270
+ payload: ToolExecutionPayloadSchema.optional(),
271
+ logChannelId: z.string().optional(),
272
+ authToken: z.string().optional(),
273
+ });
274
+ /** HITL tool approval payload - supports both direct API key auth and embed token auth */
275
+ export const HitlToolApprovalSchema = z
276
+ .object({
277
+ runId: z.string().min(1, 'runId is required'),
278
+ // For authenticated agent sandbox users
279
+ apiKey: z.string().optional(),
280
+ environmentId: z.string().optional(),
281
+ // For embedded iframe users
282
+ embedToken: z.string().optional(),
283
+ })
284
+ .refine((data) => {
285
+ // Either embedToken OR (apiKey + environmentId) must be provided
286
+ const hasEmbedToken = !!data.embedToken;
287
+ const hasApiKeyAuth = !!(data.apiKey && data.environmentId);
288
+ return hasEmbedToken || hasApiKeyAuth;
289
+ }, {
290
+ message: 'Either embedToken or both apiKey and environmentId must be provided',
291
+ });
292
+ /* ------------------------------------ */
293
+ /* Log Validation Schemas */
294
+ /* ------------------------------------ */
295
+ /** Log levels */
296
+ export const LogLevelSchema = z.enum(['info', 'debug', 'warn', 'error']);
297
+ /** Log data (flexible structure) */
298
+ export const LogDataSchema = z
299
+ .union([
300
+ z.string(),
301
+ z.number(),
302
+ z.boolean(),
303
+ z.record(z.string(), z.any()),
304
+ z.array(z.any()),
305
+ ])
306
+ .optional();
307
+ /** Complete log entry */
308
+ export const LogEntrySchema = z.object({
309
+ level: LogLevelSchema,
310
+ message: z.string().min(1, 'Log message is required'),
311
+ data: LogDataSchema,
312
+ scope: z.enum(['request', 'tool', 'system']).optional(),
313
+ userFacing: z.literal(true),
314
+ timestamp: z.string().datetime('Invalid timestamp format'),
315
+ text: z.string().optional(),
316
+ correlationId: z.string().uuid('Invalid correlation ID').optional(),
317
+ });
318
+ /** App create/update payload */
319
+ export const AppDataSchema = z.object({
320
+ name: z.string().min(1, 'name is required'),
321
+ environments: z
322
+ .array(z.object({
323
+ name: z.string().min(1, 'Environment name is required'),
324
+ backendUrl: z
325
+ .string()
326
+ .min(1, 'backendUrl is required')
327
+ .refine((u) => {
328
+ try {
329
+ new URL(u);
330
+ return true;
331
+ }
332
+ catch {
333
+ return false;
334
+ }
335
+ }, 'backendUrl must be a valid URL'),
336
+ }))
337
+ .min(1, 'At least one environment is required'),
338
+ });
339
+ /** Environment create payload */
340
+ export const EnvironmentCreateDataSchema = z.object({
341
+ name: z.string().min(1, 'name is required').max(255, 'Name too long'),
342
+ description: z.string().optional(),
343
+ organizationId: z.string().uuid('Invalid organization ID'),
344
+ backendUrl: z
345
+ .string()
346
+ .min(1, 'backendUrl is required')
347
+ .refine((u) => {
348
+ try {
349
+ new URL(u);
350
+ return true;
351
+ }
352
+ catch {
353
+ return false;
354
+ }
355
+ }, 'backendUrl must be a valid URL'),
356
+ });
357
+ /** Environment update payload */
358
+ export const EnvironmentUpdateDataSchema = z.object({
359
+ name: z.string().min(1).max(255).optional(),
360
+ description: z.string().optional(),
361
+ backendUrl: z
362
+ .string()
363
+ .min(1)
364
+ .refine((u) => {
365
+ try {
366
+ new URL(u);
367
+ return true;
368
+ }
369
+ catch {
370
+ return false;
371
+ }
372
+ }, 'backendUrl must be a valid URL')
373
+ .optional(),
374
+ isActive: z.boolean().optional(),
375
+ });
376
+ /** Quick action object for chat interfaces */
377
+ export const QuickActionSchema = z.object({
378
+ label: z.string().min(1, 'label is required'),
379
+ text: z.string().min(1, 'text is required'),
380
+ });
381
+ /** AI model for agents */
382
+ export const AgentModelSchema = z.object({
383
+ name: z.string().min(1, 'name is required'),
384
+ provider: z.string().min(1, 'provider is required'),
385
+ apiKey: z.string().min(1, 'apiKey is required'),
386
+ });
387
+ /** Endpoint create/update payload */
388
+ export const EndpointDataSchema = z.object({
389
+ operationName: z.string().min(1, 'operationName is required'),
390
+ method: HttpMethodEnum,
391
+ path: z.string().min(1, 'path is required'),
392
+ authType: z.string().nullable(),
393
+ // Optional content type
394
+ contentType: z.string().nullable().optional(),
395
+ // Optional for additional instructions
396
+ systemInstructions: z.string().nullable().optional(),
397
+ // Optional override for backend URL (for external endpoints)
398
+ backendUrlOverride: z
399
+ .string()
400
+ .min(1, 'backendUrlOverride cannot be empty when provided')
401
+ .refine((u) => {
402
+ try {
403
+ new URL(u);
404
+ return true;
405
+ }
406
+ catch {
407
+ return false;
408
+ }
409
+ }, 'backendUrlOverride must be a valid URL')
410
+ .nullable()
411
+ .optional(),
412
+ // Optional success URL to return after successful tool execution
413
+ // No validation - accepts any string or null.
414
+ // The reason is that customers might want to use something like '#tab' in order to redirect to a specific section of their app, not necessarily a full URL.
415
+ successUrl: z.string().nullable().optional(),
416
+ // Optional, but when provided must match your flexible schema
417
+ inputFields: FlexibleFieldsSchema.optional(),
418
+ // Optional payload examples to guide AI agents
419
+ payloadExamples: z
420
+ .object({
421
+ required: z.any().optional(),
422
+ full: z.any().optional(),
423
+ custom: z.any().optional(),
424
+ })
425
+ .nullable()
426
+ .optional(),
427
+ // Whether to request human confirmation before executing this tool (HITL)
428
+ requestConfirmation: z.boolean().optional(),
429
+ });
430
+ /** Endpoint create payload */
431
+ export const EndpointCreateDataSchema = z.object({
432
+ name: z.string().min(1, 'name is required').max(255, 'Name too long'),
433
+ description: z.string().optional(),
434
+ environmentId: z.string().uuid('Invalid environment ID'),
435
+ agentId: z.string().uuid('Invalid agent ID'),
436
+ endpointData: EndpointDataSchema,
437
+ });
438
+ /** Endpoint update payload */
439
+ export const EndpointUpdateDataSchema = z.object({
440
+ name: z.string().min(1).max(255).optional(),
441
+ description: z.string().optional(),
442
+ endpointData: EndpointDataSchema.optional(),
443
+ isActive: z.boolean().optional(),
444
+ });
445
+ /** Endpoint execute payload */
446
+ export const EndpointExecuteDataSchema = z.object({
447
+ inputData: z.any(),
448
+ parameters: z.record(z.string(), z.any()).optional(),
449
+ });
450
+ /** MCP Tool create payload */
451
+ export const McpToolDataSchema = z.object({
452
+ name: z.string().min(1, 'name is required'),
453
+ description: z.string().min(1, 'description is required'),
454
+ type: z.string().min(1, 'type is required'),
455
+ serverData: z.any(),
456
+ icon: z.string().optional(),
457
+ });
458
+ /** MCP Tool update payload */
459
+ export const McpToolUpdateDataSchema = McpToolDataSchema.partial();
460
+ /** Agent create/update payload */
461
+ /** Agent type enumeration */
462
+ export const AgentTypeSchema = z.enum(['conversational', 'functional']);
463
+ export const AgentDataSchema = z.object({
464
+ name: z.string().min(1, 'name is required'),
465
+ instructions: z.string().min(1, 'instructions is required'),
466
+ roleName: z.string().optional().default('assistant'),
467
+ toolIds: z.array(z.string()),
468
+ environmentId: z.string(),
469
+ quickActions: z.array(QuickActionSchema).optional(),
470
+ models: z.array(AgentModelSchema).optional(),
471
+ agentType: AgentTypeSchema.optional(),
472
+ outputSchema: z.any().optional(),
473
+ temperature: z.number().min(0).max(1).optional(),
474
+ enableToolSearch: z.boolean().optional(),
475
+ mcpToolIds: z.array(z.string()),
476
+ });
477
+ export const AgentRAGCreateDataSchema = z.object({
478
+ environmentId: z.string().min(1, 'environmentId is required'),
479
+ uploadedFile: UploadedFileSchema,
480
+ });
481
+ export const AgentRAGDeleteDataSchema = z.object({
482
+ environmentId: z.string().min(1, 'environmentId is required'),
483
+ fileName: z.string().min(1, 'fileName is required'),
484
+ });
485
+ /** WorkflowStep create/update payload */
486
+ export const WorkflowStepDataSchema = z.object({
487
+ name: z.string().min(1, 'name is required'),
488
+ description: z.string().optional(),
489
+ stepType: z.enum(['agent', 'code', 'tool']),
490
+ inputSchema: z.any(), // JSON Schema object
491
+ outputSchema: z.any(), // JSON Schema object
492
+ config: z.any(), // Step-specific configuration
493
+ retries: z.number().int().min(0, 'retries must be non-negative').optional(),
494
+ environmentId: z.string().min(1, 'environmentId is required'),
495
+ });
496
+ export const WorkflowStepUpdateDataSchema = WorkflowStepDataSchema.partial().omit({ environmentId: true });
497
+ /** Workflow step reference schema */
498
+ export const WorkflowStepReferenceSchema = z.object({
499
+ stepId: z.string().uuid('Invalid step ID'),
500
+ stepKey: z
501
+ .string()
502
+ .min(1, 'stepKey is required')
503
+ .regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, 'stepKey must be a valid identifier'),
504
+ stepOrder: z
505
+ .number()
506
+ .int('stepOrder must be an integer')
507
+ .min(0, 'stepOrder must be non-negative'),
508
+ branchGroup: z
509
+ .number()
510
+ .int('branchGroup must be an integer')
511
+ .positive('branchGroup must be positive')
512
+ .nullable()
513
+ .optional(),
514
+ branchCondition: z
515
+ .string()
516
+ .min(1, 'branchCondition cannot be empty when provided')
517
+ .nullable()
518
+ .optional(),
519
+ isDefaultBranch: z.boolean().optional(),
520
+ dataMapping: z.record(z.string(), z.string()).nullable().optional(),
521
+ loopType: z.enum(['foreach', 'dowhile', 'dountil']).nullable().optional(),
522
+ loopConfig: z
523
+ .object({
524
+ collectionPath: z.string().optional(),
525
+ concurrency: z.number().int().min(1).max(20).optional(),
526
+ condition: z.string().optional(),
527
+ maxIterations: z.number().int().min(1).max(1000).optional(),
528
+ })
529
+ .nullable()
530
+ .optional(),
531
+ });
532
+ /** Workflow create/update payload */
533
+ export const WorkflowDataSchema = z.object({
534
+ name: z.string().min(1, 'name is required'),
535
+ description: z.string().optional(),
536
+ environmentId: z.string().min(1, 'environmentId is required'),
537
+ steps: z
538
+ .array(WorkflowStepReferenceSchema)
539
+ .min(1, 'At least one step is required'),
540
+ });
541
+ export const WorkflowUpdateDataSchema = WorkflowDataSchema.partial().omit({
542
+ environmentId: true,
543
+ });
544
+ /** Organization create/update payload */
545
+ export const CreateOrganizationDataSchema = z.object({
546
+ name: z.string().min(1, 'name is required'),
547
+ tier: z.enum(['Hobby', 'Professional', 'Scale', 'Enterprise']),
548
+ });
549
+ export const UpdateOrganizationDataSchema = CreateOrganizationDataSchema.partial();
550
+ /** User↔Organization link payload */
551
+ export const UserToOrgDataSchema = z.object({
552
+ userId: z.string().min(1, 'userId is required'),
553
+ organizationId: z.string().min(1, 'organizationId is required'),
554
+ });
555
+ /** Organization invite create payload */
556
+ export const OrganizationInviteCreateDataSchema = z.object({
557
+ email: z.string().email('Invalid email'),
558
+ role: z.enum(['Owner', 'Member', 'Admin']).optional(),
559
+ expiresAt: z
560
+ .string()
561
+ .datetime({ message: 'expiresAt must be an ISO timestamp', offset: true })
562
+ .optional(),
563
+ });
564
+ /** Agent update payload (partial) */
565
+ export const AgentUpdateDataSchema = AgentDataSchema.partial();
566
+ /** Agent configuration patch payload (for Agent Sandbox editing) */
567
+ export const AgentConfigurationPatchDataSchema = z.object({
568
+ instructions: z.string().min(1, 'instructions is required').optional(),
569
+ toolIds: z.array(z.string()).optional(),
570
+ quickActions: z.array(QuickActionSchema).optional(),
571
+ });
572
+ /** Embed Token create payload */
573
+ export const EmbedTokenCreateDataSchema = z.object({
574
+ agentId: z.string().min(1, 'agentId is required'),
575
+ environmentId: z.string().min(1, 'environmentId is required'),
576
+ expiresInDays: z.number().min(1).max(365).optional().default(30),
577
+ allowedDomains: z.array(z.string()).optional(),
578
+ });
579
+ /** Thread query parameters */
580
+ export const ThreadQuerySchema = z.object({
581
+ apiKey: z.string().min(1, 'apiKey is required'),
582
+ environmentId: z.string().min(1, 'environmentId is required'),
583
+ customerId: z.string().optional(),
584
+ });
585
+ /** Embed metadata query parameters */
586
+ export const EmbedMetadataQuerySchema = z.object({
587
+ token: z.string().min(1, 'token is required'),
588
+ });
589
+ /** Agentic execution request payload */
590
+ export const FunctionalAgentExecutionServiceRequestSchema = z.object({
591
+ apiKey: z.string().min(1, 'apiKey is required'),
592
+ environmentId: z.string().min(1, 'environmentId is required'),
593
+ userContext: z.string().optional(),
594
+ inputParameters: z.record(z.string(), z.any()).optional(),
595
+ backendJwtToken: z.string().optional(),
596
+ customerId: z.string().optional(),
597
+ });
598
+ /* V1 Public API Schemas */
599
+ /** V1 Chat message structure (credentials in headers) */
600
+ export const V1ChatMessageSchema = z.object({
601
+ agentId: z.string().min(1, 'agentId is required'),
602
+ environmentId: z.string().min(1, 'environmentId is required'),
603
+ messages: z
604
+ .array(z.object({
605
+ content: z.string().min(1, 'Message content is required'),
606
+ }))
607
+ .min(1, 'At least one message is required'),
608
+ customerId: z.string().optional(),
609
+ customInstructions: z.string().optional(),
610
+ logChannelId: z.string().optional(),
611
+ logToolScore: z.boolean().optional().default(false),
612
+ threadId: z.string().optional(),
613
+ uploadedFiles: UploadedFilesSchema.optional(),
614
+ screenState: ScreenStateSchema.optional(),
615
+ });
616
+ /** V1 HITL tool approval payload (credentials in headers) */
617
+ export const V1HitlToolApprovalSchema = z.object({
618
+ runId: z.string().min(1, 'runId is required'),
619
+ environmentId: z.string().optional(),
620
+ });
621
+ /** V1 Agentic execution request payload (credentials in headers) */
622
+ export const V1FunctionalAgentExecutionServiceRequestSchema = z.object({
623
+ agentId: z.string().min(1, 'agentId is required'),
624
+ environmentId: z.string().min(1, 'environmentId is required'),
625
+ userContext: z.string().optional(),
626
+ inputParameters: z.record(z.string(), z.any()).optional(),
627
+ customerId: z.string().optional(),
628
+ });
629
+ /** V1 Action data schema (credentials in headers) */
630
+ export const V1ActionDataSchema = EndpointDataSchema.extend({
631
+ environmentId: z.string().min(1, 'environmentId is required'),
632
+ });
633
+ export const Validation = {
634
+ // primitives / helpers
635
+ requireString,
636
+ optionalString,
637
+ optionalBoolean,
638
+ requireArray,
639
+ requireMessageArray,
640
+ requireEnum,
641
+ optionalEnum,
642
+ validateRequiredParams,
643
+ validateEmail,
644
+ validateUrl,
645
+ // IDs
646
+ validateId, // pass kind: 'uuid' | 'objectId' | 'string'
647
+ validateUUID: (id, fieldName = 'id') => validateId(id, { fieldName, kind: 'uuid' }),
648
+ validateObjectId: (id, fieldName = 'id') => validateId(id, { fieldName, kind: 'objectId' }),
649
+ // Body parsing with Zod
650
+ validateBody,
651
+ // High-level parsers (return parsed, typed data)
652
+ parseAppData: (data) => validateBody(data, AppDataSchema),
653
+ // Environment parsers
654
+ parseEnvironmentCreateData: (data) => validateBody(data, EnvironmentCreateDataSchema),
655
+ parseEnvironmentUpdateData: (data) => validateBody(data, EnvironmentUpdateDataSchema),
656
+ // Endpoint parsers
657
+ parseEndpointData: (data) => validateBody(data, EndpointDataSchema),
658
+ parseEndpointCreateData: (data) => validateBody(data, EndpointCreateDataSchema),
659
+ parseEndpointUpdateData: (data) => validateBody(data, EndpointUpdateDataSchema),
660
+ parseEndpointExecuteData: (data) => validateBody(data, EndpointExecuteDataSchema),
661
+ // MCP Tool parser
662
+ parseMcpToolData: (data) => validateBody(data, McpToolDataSchema),
663
+ parseMcpToolUpdateData: (data) => validateBody(data, McpToolUpdateDataSchema),
664
+ // Agent parsers
665
+ parseAgentData: (data) => validateBody(data, AgentDataSchema),
666
+ parseAgentUpdateData: (data) => validateBody(data, AgentUpdateDataSchema),
667
+ parseAgentConfigurationPatchData: (data) => validateBody(data, AgentConfigurationPatchDataSchema),
668
+ parseAgentRAGCreateData: (data) => validateBody(data, AgentRAGCreateDataSchema),
669
+ parseAgentRAGDeleteData: (data) => validateBody(data, AgentRAGDeleteDataSchema),
670
+ // WorkflowStep parsers
671
+ parseWorkflowStepData: (data) => validateBody(data, WorkflowStepDataSchema),
672
+ parseWorkflowStepUpdateData: (data) => validateBody(data, WorkflowStepUpdateDataSchema),
673
+ // Workflow parsers
674
+ parseWorkflowData: (data) => validateBody(data, WorkflowDataSchema),
675
+ parseWorkflowUpdateData: (data) => validateBody(data, WorkflowUpdateDataSchema),
676
+ // Organization parsers
677
+ parseCreateOrganizationData: (data) => validateBody(data, CreateOrganizationDataSchema),
678
+ parseUpdateOrganizationData: (data) => validateBody(data, UpdateOrganizationDataSchema),
679
+ parseUserToOrgData: (data) => validateBody(data, UserToOrgDataSchema),
680
+ parseOrganizationInviteCreateData: (data) => validateBody(data, OrganizationInviteCreateDataSchema),
681
+ // Field parsers
682
+ parseFieldData: (data) => validateBody(data, FieldSchema),
683
+ parseFieldCollectionData: (data) => validateBody(data, FlexibleFieldsSchema),
684
+ // Chat parsers
685
+ parseChatMessageData: (data) => validateBody(data, ChatMessageSchema),
686
+ parseEphemeralChatMessageData: (data) => validateBody(data, EphemeralChatMessageSchema),
687
+ parseEmbedChatMessageData: (data) => validateBody(data, EmbedChatMessageSchema),
688
+ parsePingMateManualRunData: (data) => validateBody(data, PingMateManualRunSchema),
689
+ // HITL parsers
690
+ parseHitlToolApprovalData: (data) => validateBody(data, HitlToolApprovalSchema),
691
+ // Log parsers
692
+ parseLogEntryData: (data) => validateBody(data, LogEntrySchema),
693
+ parseLogData: (data) => validateBody(data, LogDataSchema),
694
+ // Enhanced endpoint parsers
695
+ parseEnhancedEndpointData: (data) => validateBody(data, EnhancedEndpointSchema),
696
+ // Other parsers
697
+ parseEmbedTokenCreateData: (data) => validateBody(data, EmbedTokenCreateDataSchema),
698
+ parseThreadQuery: (data) => validateBody(data, ThreadQuerySchema),
699
+ parseEmbedMetadataQuery: (data) => validateBody(data, EmbedMetadataQuerySchema),
700
+ parseFunctionalAgentExecutionServiceRequest: (data) => validateBody(data, FunctionalAgentExecutionServiceRequestSchema),
701
+ // V1 Public API parsers (header-based auth)
702
+ parseV1ChatMessageData: (data) => validateBody(data, V1ChatMessageSchema),
703
+ parseV1HitlToolApprovalData: (data) => validateBody(data, V1HitlToolApprovalSchema),
704
+ parseV1FunctionalAgentExecutionServiceRequest: (data) => validateBody(data, V1FunctionalAgentExecutionServiceRequestSchema),
705
+ parseV1ActionData: (data) => validateBody(data, V1ActionDataSchema),
706
+ };
707
+ /** Enhanced endpoint schema for auto-onboarding */
708
+ export const EnhancedEndpointSchema = z.object({
709
+ systemInstructions: z
710
+ .string()
711
+ .describe('Clear, detailed instructions for what this endpoint does'),
712
+ inputFields: z
713
+ .record(z.string(), z.object({
714
+ type: FieldTypeSchema,
715
+ requiredByBackend: z.boolean(),
716
+ fieldInstructions: z
717
+ .string()
718
+ .describe('Specific instructions for this input field'),
719
+ format: z.string().optional(),
720
+ items: FieldSchema.optional(),
721
+ example: z.any().optional(),
722
+ }))
723
+ .describe('Enhanced input field definitions'),
724
+ });