👁️
5
fork

Configure Feed

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

validate records on write

+39 -16
+39 -16
src/lib/atproto-client.ts
··· 116 116 } 117 117 } 118 118 119 - async function createRecord<T extends Record<string, unknown>>( 119 + async function createRecord<TSchema extends BaseSchema>( 120 120 agent: OAuthUserAgent, 121 - record: T, 122 - collection: Collection, 123 - entityName: string, 121 + record: InferOutput<TSchema> & { $type: Collection }, 122 + schema: TSchema, 124 123 ): Promise<Result<{ uri: AtUri; cid: string; rkey: Rkey }>> { 125 124 try { 125 + const validation = safeParse(schema, record); 126 + if (!validation.ok) { 127 + return { 128 + success: false, 129 + error: new Error( 130 + `Invalid ${record.$type} record: ${validation.message}`, 131 + ), 132 + }; 133 + } 134 + 126 135 const client = new Client({ handler: agent }); 127 136 const response = await client.post("com.atproto.repo.createRecord", { 128 137 input: { 129 138 repo: agent.sub, 130 - collection, 139 + collection: record.$type, 131 140 record, 132 141 }, 133 142 }); ··· 136 145 return { 137 146 success: false, 138 147 error: new Error( 139 - response.data.message || `Failed to create ${entityName} record`, 148 + response.data.message || `Failed to create ${record.$type} record`, 140 149 ), 141 150 }; 142 151 } ··· 163 172 } 164 173 } 165 174 166 - async function updateRecord<T extends Record<string, unknown>>( 175 + async function updateRecord<TSchema extends BaseSchema>( 167 176 agent: OAuthUserAgent, 168 177 rkey: Rkey, 169 - record: T, 170 - collection: Collection, 171 - entityName: string, 178 + record: InferOutput<TSchema> & { $type: Collection }, 179 + schema: TSchema, 172 180 ): Promise<Result<{ uri: AtUri; cid: string }>> { 173 181 try { 182 + const validation = safeParse(schema, record); 183 + if (!validation.ok) { 184 + return { 185 + success: false, 186 + error: new Error( 187 + `Invalid ${record.$type} record: ${validation.message}`, 188 + ), 189 + }; 190 + } 191 + 174 192 const client = new Client({ handler: agent }); 175 193 const response = await client.post("com.atproto.repo.putRecord", { 176 194 input: { 177 195 repo: agent.sub, 178 - collection, 196 + collection: record.$type, 179 197 rkey, 180 198 record, 181 199 }, ··· 185 203 return { 186 204 success: false, 187 205 error: new Error( 188 - response.data.message || `Failed to update ${entityName} record`, 206 + response.data.message || `Failed to update ${record.$type} record`, 189 207 ), 190 208 }; 191 209 } ··· 323 341 agent: OAuthUserAgent, 324 342 record: ComDeckbelcherDeckList.Main, 325 343 ) { 326 - return createRecord(agent, record, DECK_COLLECTION, "deck"); 344 + return createRecord(agent, record, ComDeckbelcherDeckList.mainSchema); 327 345 } 328 346 329 347 export function updateDeckRecord( ··· 331 349 rkey: Rkey, 332 350 record: ComDeckbelcherDeckList.Main, 333 351 ) { 334 - return updateRecord(agent, rkey, record, DECK_COLLECTION, "deck"); 352 + return updateRecord(agent, rkey, record, ComDeckbelcherDeckList.mainSchema); 335 353 } 336 354 337 355 export function listUserDecks(pdsUrl: PdsUrl, did: Did, cursor?: string) { ··· 370 388 agent: OAuthUserAgent, 371 389 record: ComDeckbelcherCollectionList.Main, 372 390 ) { 373 - return createRecord(agent, record, LIST_COLLECTION, "list"); 391 + return createRecord(agent, record, ComDeckbelcherCollectionList.mainSchema); 374 392 } 375 393 376 394 export function updateCollectionListRecord( ··· 378 396 rkey: Rkey, 379 397 record: ComDeckbelcherCollectionList.Main, 380 398 ) { 381 - return updateRecord(agent, rkey, record, LIST_COLLECTION, "list"); 399 + return updateRecord( 400 + agent, 401 + rkey, 402 + record, 403 + ComDeckbelcherCollectionList.mainSchema, 404 + ); 382 405 } 383 406 384 407 export function listUserCollectionLists(