Atproto AMA app
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 129 lines 4.2 kB view raw
1/** 2 * Shared schema definitions and constraints used by both Drizzle and Lexicon schemas 3 */ 4 5// Source types for questions and answers 6export const SOURCE_TYPES = { 7 ASKIMUT: 'askimut', 8 BLUESKY: 'bsky', 9 STANDARD_SITE: 'standard.site', 10 MASTODON: 'mastodon', 11 NOSTR: 'nostr' 12} as const; 13 14export type SourceType = typeof SOURCE_TYPES[keyof typeof SOURCE_TYPES]; 15 16// Shared field definitions and constraints 17export const FIELD_CONSTRAINTS = { 18 question: { 19 content: { minLength: 1, maxLength: 1000 }, 20 tags: { maxItems: 10, itemMaxLength: 50 } 21 }, 22 answer: { 23 content: { minLength: 1, maxLength: 5000 } 24 }, 25 user: { 26 handle: { pattern: /^[a-zA-Z0-9.-]+$/, maxLength: 253 }, 27 displayName: { maxLength: 64 } 28 }, 29 source: { 30 validTypes: Object.values(SOURCE_TYPES) 31 } 32} as const; 33 34// Shared TypeScript interfaces 35export interface BaseQuestion { 36 content: string; 37 targetDid: string; 38 authorDid: string; 39 sourceType: SourceType; 40 anonymous: boolean; 41 createdAt: string; 42 tags?: string[]; 43 sourceUri?: string; // Original URI from source platform 44 sourceData?: Record<string, unknown>; // Platform-specific metadata 45} 46 47export interface BaseAnswer { 48 content: string; 49 questionUri: string; 50 authorDid: string; 51 sourceType: SourceType; 52 createdAt: string; 53 sourceUri?: string; // Original URI from source platform 54 sourceData?: Record<string, unknown>; // Platform-specific metadata 55} 56 57export interface BaseProfile { 58 displayName?: string; 59 description?: string; 60 questionsOpen: boolean; 61} 62 63// Validation helpers 64export function validateQuestionContent(content: string): boolean { 65 return content.length >= FIELD_CONSTRAINTS.question.content.minLength && 66 content.length <= FIELD_CONSTRAINTS.question.content.maxLength; 67} 68 69export function validateAnswerContent(content: string): boolean { 70 return content.length >= FIELD_CONSTRAINTS.answer.content.minLength && 71 content.length <= FIELD_CONSTRAINTS.answer.content.maxLength; 72} 73 74export function validateHandle(handle: string): boolean { 75 return FIELD_CONSTRAINTS.user.handle.pattern.test(handle) && 76 handle.length <= FIELD_CONSTRAINTS.user.handle.maxLength; 77} 78 79export function validateDisplayName(displayName: string): boolean { 80 return displayName.length <= FIELD_CONSTRAINTS.user.displayName.maxLength; 81} 82 83export function validateTags(tags: string[]): boolean { 84 if (tags.length > FIELD_CONSTRAINTS.question.tags.maxItems) { 85 return false; 86 } 87 return tags.every(tag => 88 tag.length <= FIELD_CONSTRAINTS.question.tags.itemMaxLength 89 ); 90} 91 92export function validateSourceType(sourceType: string): sourceType is SourceType { 93 return FIELD_CONSTRAINTS.source.validTypes.includes(sourceType as SourceType); 94} 95 96export function isAskimutNative(sourceType: SourceType): boolean { 97 return sourceType === SOURCE_TYPES.ASKIMUT; 98} 99 100export function isBlueSkySource(sourceType: SourceType): boolean { 101 return sourceType === SOURCE_TYPES.BLUESKY; 102} 103 104export function isStandardSiteSource(sourceType: SourceType): boolean { 105 return sourceType === SOURCE_TYPES.STANDARD_SITE; 106} 107 108// Common error messages 109export const VALIDATION_ERRORS = { 110 question: { 111 contentTooShort: `Question must be at least ${FIELD_CONSTRAINTS.question.content.minLength} character`, 112 contentTooLong: `Question cannot exceed ${FIELD_CONSTRAINTS.question.content.maxLength} characters`, 113 tooManyTags: `Cannot have more than ${FIELD_CONSTRAINTS.question.tags.maxItems} tags`, 114 tagTooLong: `Tag cannot exceed ${FIELD_CONSTRAINTS.question.tags.itemMaxLength} characters` 115 }, 116 answer: { 117 contentTooShort: `Answer must be at least ${FIELD_CONSTRAINTS.answer.content.minLength} character`, 118 contentTooLong: `Answer cannot exceed ${FIELD_CONSTRAINTS.answer.content.maxLength} characters` 119 }, 120 user: { 121 invalidHandle: 'Handle contains invalid characters', 122 handleTooLong: `Handle cannot exceed ${FIELD_CONSTRAINTS.user.handle.maxLength} characters`, 123 displayNameTooLong: `Display name cannot exceed ${FIELD_CONSTRAINTS.user.displayName.maxLength} characters` 124 }, 125 source: { 126 invalidType: `Source type must be one of: ${FIELD_CONSTRAINTS.source.validTypes.join(', ')}`, 127 required: 'Source type is required' 128 } 129} as const;