You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

121 lines
3.8 KiB

/**
* Zod schemas for strong structural validation
*/
import { z } from 'zod';
import { JWT_ID_PATTERN } from './constants';
// Core schemas
export const PlanSummarySchema = z.object({
jwtId: z.string().regex(JWT_ID_PATTERN, 'Invalid JWT ID format'),
handleId: z.string().min(1),
name: z.string().min(1),
description: z.string(),
issuerDid: z.string().startsWith('did:key:'),
agentDid: z.string().startsWith('did:key:'),
startTime: z.string().datetime(),
endTime: z.string().datetime(),
locLat: z.number().nullable().optional(),
locLon: z.number().nullable().optional(),
url: z.string().url().nullable().optional(),
version: z.string()
});
export const PreviousClaimSchema = z.object({
jwtId: z.string().regex(JWT_ID_PATTERN),
claimType: z.string(),
claimData: z.record(z.unknown()),
metadata: z.object({
createdAt: z.string().datetime(),
updatedAt: z.string().datetime()
})
});
export const PlanSummaryAndPreviousClaimSchema = z.object({
planSummary: PlanSummarySchema,
previousClaim: PreviousClaimSchema.optional()
});
export const StarredProjectsResponseSchema = z.object({
data: z.array(PlanSummaryAndPreviousClaimSchema),
hitLimit: z.boolean(),
pagination: z.object({
hasMore: z.boolean(),
nextAfterId: z.string().regex(JWT_ID_PATTERN).nullable()
})
});
export const StarredProjectsRequestSchema = z.object({
planIds: z.array(z.string()).min(1),
afterId: z.string().regex(JWT_ID_PATTERN).optional(),
beforeId: z.string().regex(JWT_ID_PATTERN).optional(),
limit: z.number().min(1).max(100).default(100)
});
// Deep link parameter validation
export const DeepLinkParamsSchema = z.object({
jwtIds: z.array(z.string().regex(JWT_ID_PATTERN)).max(10).optional(),
projectId: z.string().regex(/^[a-zA-Z0-9_-]+$/).optional(),
jwtId: z.string().regex(JWT_ID_PATTERN).optional(),
shortlink: z.string().min(1).optional()
}).refine(
(data) => data.jwtIds || data.jwtId || data.projectId || data.shortlink,
'At least one of jwtIds, jwtId, projectId, or shortlink must be provided'
);
// Error response schema
export const ErrorResponseSchema = z.object({
error: z.string(),
code: z.string().optional(),
message: z.string(),
details: z.record(z.unknown()).optional(),
retryAfter: z.number().optional(),
requestId: z.string().optional()
});
// Rate limit response schema
export const RateLimitResponseSchema = z.object({
error: z.literal('Rate limit exceeded'),
code: z.literal('RATE_LIMIT_EXCEEDED'),
message: z.string(),
details: z.object({
limit: z.number(),
window: z.string(),
resetAt: z.string().datetime(),
remaining: z.number().optional()
}),
retryAfter: z.number(),
requestId: z.string()
});
// Acknowledgment request schema
export const AcknowledgmentRequestSchema = z.object({
acknowledgedJwtIds: z.array(z.string().regex(JWT_ID_PATTERN)).min(1),
acknowledgedAt: z.string().datetime(),
clientVersion: z.string()
});
// Acknowledgment response schema
export const AcknowledgmentResponseSchema = z.object({
acknowledged: z.number(),
failed: z.number(),
alreadyAcknowledged: z.number(),
acknowledgmentId: z.string(),
timestamp: z.string().datetime()
});
// Clock sync response schema
export const ClockSyncResponseSchema = z.object({
serverTime: z.number(),
clientTime: z.number(),
offset: z.number(),
ntpServers: z.array(z.string()).optional()
});
// Type exports for use in host apps (only export types not already in types.ts)
export type DeepLinkParams = z.infer<typeof DeepLinkParamsSchema>;
export type ErrorResponse = z.infer<typeof ErrorResponseSchema>;
export type RateLimitResponse = z.infer<typeof RateLimitResponseSchema>;
export type AcknowledgmentRequest = z.infer<typeof AcknowledgmentRequestSchema>;
export type AcknowledgmentResponse = z.infer<typeof AcknowledgmentResponseSchema>;
export type ClockSyncResponse = z.infer<typeof ClockSyncResponseSchema>;