A minimal AT Protocol Personal Data Server written in JavaScript.
atproto pds
at main 73 lines 2.0 kB view raw
1// @pds/core/validation - Reusable validation utilities 2 3/** 4 * DID format regex - supports did:plc and did:web 5 * did:plc uses base32 (a-z, 2-7) with 24 chars 6 */ 7export const DID_REGEX = /^did:(plc:[a-z2-7]{24}|web:.+)$/; 8 9/** 10 * Handle format regex - domain-like format 11 * Each label: starts/ends alphanumeric, can have hyphens in middle, 1-63 chars 12 * Must have at least 2 labels (e.g., user.bsky.social) 13 */ 14export const HANDLE_REGEX = 15 /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/; 16 17/** 18 * Hex string regex 19 */ 20export const HEX_REGEX = /^[0-9a-fA-F]+$/; 21 22/** 23 * Validate DID format 24 * @param {unknown} did 25 * @returns {did is string} 26 */ 27export function isValidDid(did) { 28 return typeof did === 'string' && DID_REGEX.test(did); 29} 30 31/** 32 * Validate handle format 33 * @param {unknown} handle 34 * @returns {handle is string} 35 */ 36export function isValidHandle(handle) { 37 return typeof handle === 'string' && HANDLE_REGEX.test(handle); 38} 39 40/** 41 * Validate hex string 42 * @param {unknown} str 43 * @returns {str is string} 44 */ 45export function isValidHex(str) { 46 return typeof str === 'string' && HEX_REGEX.test(str); 47} 48 49/** 50 * Validate private key bytes (32 bytes for secp256k1) 51 * @param {Uint8Array} key 52 * @returns {boolean} 53 */ 54export function isValidPrivateKeyLength(key) { 55 return key instanceof Uint8Array && key.length === 32; 56} 57 58/** 59 * Parse and validate a numeric cursor (non-negative integer) 60 * @param {string|null} cursor - Cursor string from URL params 61 * @returns {{valid: true, value: number} | {valid: false, error: string} | null} 62 */ 63export function parseNumericCursor(cursor) { 64 if (cursor === null || cursor === '') return null; 65 const num = parseInt(cursor, 10); 66 if (Number.isNaN(num)) { 67 return { valid: false, error: 'cursor must be a valid integer' }; 68 } 69 if (num < 0) { 70 return { valid: false, error: 'cursor must not be negative' }; 71 } 72 return { valid: true, value: num }; 73}