handy online tools for AT Protocol boat.kelinci.net
atproto bluesky atcute typescript solidjs
20
fork

Configure Feed

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

refactor: stricter did doc check

Mary 97eed392 4e2d7644

+64 -11
+62 -11
src/api/types/did-doc.ts
··· 1 1 import * as v from 'valibot'; 2 2 3 - import { didString, serviceUrlString } from './strings'; 3 + import { didString, serviceUrlString, urlString } from './strings'; 4 4 5 5 const verificationMethod = v.object({ 6 6 id: v.string(), ··· 9 9 publicKeyMultibase: v.optional(v.string()), 10 10 }); 11 11 12 - const service = v.object({ 13 - id: v.string(), 14 - type: v.string(), 15 - serviceEndpoint: v.union([v.string(), v.record(v.string(), v.unknown())]), 16 - }); 12 + const service = v.variant('type', [ 13 + v.object({ 14 + id: v.string(), 15 + type: v.union([ 16 + v.union([ 17 + v.literal('AtprotoPersonalDataServer'), 18 + v.literal('AtprotoLabeler'), 19 + v.literal('BskyFeedGenerator'), 20 + v.literal('BskyNotificationService'), 21 + ]), 22 + ]), 23 + serviceEndpoint: serviceUrlString, 24 + }), 25 + v.object({ 26 + id: v.string(), 27 + type: v.string(), 28 + serviceEndpoint: v.union([urlString, v.record(v.string(), urlString), v.array(urlString)]), 29 + }), 30 + ]); 17 31 18 32 export const didDocument = v.object({ 19 33 id: didString, 20 34 alsoKnownAs: v.optional(v.array(v.pipe(v.string(), v.url())), []), 21 35 verificationMethod: v.optional(v.array(verificationMethod), []), 22 - service: v.optional(v.array(service), []), 36 + service: v.optional( 37 + v.pipe( 38 + v.array(service), 39 + v.rawCheck(({ dataset, addIssue }) => { 40 + if (dataset.typed) { 41 + const set = new Set<string>(); 42 + const services = dataset.value; 43 + 44 + for (let idx = 0, len = services.length; idx < len; idx++) { 45 + const service = services[idx]; 46 + const id = service.id; 47 + 48 + if (!set.has(id)) { 49 + set.add(id); 50 + } else { 51 + addIssue({ 52 + message: `duplicate service id`, 53 + path: [ 54 + { 55 + type: 'array', 56 + origin: 'value', 57 + input: services, 58 + key: idx, 59 + value: service, 60 + }, 61 + { 62 + type: 'object', 63 + origin: 'value', 64 + input: service, 65 + key: 'id', 66 + value: id, 67 + }, 68 + ], 69 + }); 70 + } 71 + } 72 + } 73 + }), 74 + ), 75 + [], 76 + ), 23 77 }); 24 78 25 79 export type DidDocument = v.InferOutput<typeof didDocument>; ··· 42 96 return undefined; 43 97 } 44 98 45 - const endpoint = found.serviceEndpoint; 46 - if (v.is(serviceUrlString, found.serviceEndpoint)) { 47 - return endpoint; 48 - } 99 + return found.serviceEndpoint; 49 100 };
+2
src/api/types/strings.ts
··· 5 5 export const didString = v.pipe(v.string(), v.regex(DID_RE, 'must be a valid did')); 6 6 export const handleString = v.pipe(v.string(), v.regex(HANDLE_RE, 'must be a valid handle')); 7 7 8 + export const urlString = v.pipe(v.string(), v.url()); 9 + 8 10 export const serviceUrlString = v.pipe( 9 11 v.string(), 10 12 v.check((urlString) => {