Suite of AT Protocol TypeScript libraries built on web standards
20
fork

Configure Feed

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

at main 94 lines 2.4 kB view raw
1import { 2 decode as cborgDecode, 3 decodeFirst as cborgDecodeFirst, 4 type DecodeOptions, 5 encode as cborgEncode, 6 type EncodeOptions, 7 type TagDecoder, 8 Token, 9 Type, 10} from "cborg"; 11import { asCid, type Cid, decodeCid } from "../data/cid.ts"; 12import type { LexValue } from "../data/lex.ts"; 13 14export type { Cid, LexValue }; 15 16const CID_CBOR_TAG = 42; 17 18function cidEncoder(obj: object): Token[] | null { 19 const cid = asCid(obj); 20 if (!cid) return null; 21 22 const bytes = new Uint8Array(cid.bytes.byteLength + 1); 23 bytes.set(cid.bytes, 1); 24 return [new Token(Type.tag, CID_CBOR_TAG), new Token(Type.bytes, bytes)]; 25} 26 27function undefinedEncoder(): null { 28 throw new Error("`undefined` is not allowed by the AT Data Model"); 29} 30 31function numberEncoder(num: number): null { 32 if (Number.isInteger(num)) return null; 33 throw new Error("Non-integer numbers are not allowed by the AT Data Model"); 34} 35 36function mapEncoder(map: Map<unknown, unknown>): null { 37 for (const key of map.keys()) { 38 if (typeof key !== "string") { 39 throw new Error( 40 'Only string keys are allowed in CBOR "map" by the AT Data Model', 41 ); 42 } 43 } 44 return null; 45} 46 47const encodeOptions: EncodeOptions = { 48 typeEncoders: { 49 Map: mapEncoder, 50 Object: cidEncoder, 51 undefined: undefinedEncoder, 52 number: numberEncoder, 53 }, 54}; 55 56function cidDecoder(bytes: Uint8Array): Cid { 57 if (bytes[0] !== 0) { 58 throw new Error("Invalid CID for CBOR tag 42; expected leading 0x00"); 59 } 60 return decodeCid(bytes.subarray(1)); 61} 62 63const tagDecoders: TagDecoder[] = []; 64tagDecoders[CID_CBOR_TAG] = cidDecoder; 65 66const decodeOptions: DecodeOptions = { 67 allowIndefinite: false, 68 coerceUndefinedToNull: true, 69 allowNaN: false, 70 allowInfinity: false, 71 allowBigInt: true, 72 strict: true, 73 useMaps: false, 74 rejectDuplicateMapKeys: true, 75 tags: tagDecoders, 76}; 77 78export function encode<T extends LexValue>(data: T): Uint8Array { 79 return cborgEncode(data, encodeOptions); 80} 81 82export function decode<T extends LexValue>(bytes: Uint8Array): T { 83 return cborgDecode(bytes, decodeOptions) as T; 84} 85 86export function* decodeAll<T extends LexValue = LexValue>( 87 data: Uint8Array, 88): Generator<T, void, unknown> { 89 do { 90 const [result, remainingBytes] = cborgDecodeFirst(data, decodeOptions); 91 yield result as T; 92 data = remainingBytes; 93 } while (data.byteLength > 0); 94}