atmosphere explorer pdsls.dev
atproto tool typescript

local validation

juli.ee 80b949a4 56735887

verified
Changed files
+38 -37
src
views
+38 -37
src/views/record.tsx
··· 7 7 import { AtprotoDid, Did, isNsid } from "@atcute/lexicons/syntax"; 8 8 import { verifyRecord } from "@atcute/repo"; 9 9 import { A, useLocation, useNavigate, useParams } from "@solidjs/router"; 10 - import { 11 - createEffect, 12 - createResource, 13 - createSignal, 14 - ErrorBoundary, 15 - Show, 16 - Suspense, 17 - } from "solid-js"; 10 + import { createResource, createSignal, ErrorBoundary, Show, Suspense } from "solid-js"; 18 11 import { Backlinks } from "../components/backlinks.jsx"; 19 12 import { Button } from "../components/button.jsx"; 20 13 import { RecordEditor, setPlaceholder } from "../components/create.jsx"; ··· 230 223 setPlaceholder(res.data.value); 231 224 setExternalLink(checkUri(res.data.uri, res.data.value)); 232 225 resolveLexicon(params.collection as Nsid); 226 + verifyRecordIntegrity(); 227 + validateLocalSchema(res.data.value); 233 228 234 229 return res.data; 235 230 }; 236 231 237 232 const [record, { refetch }] = createResource(fetchRecord); 238 233 239 - const validateSchema = async (record: Record<string, unknown>) => { 234 + const validateLocalSchema = async (record: Record<string, unknown>) => { 240 235 try { 241 236 if (params.collection === "com.atproto.lexicon.schema") { 242 237 setLexiconNotFound(false); ··· 245 240 } else if (params.collection && params.collection in lexicons) { 246 241 if (is(lexicons[params.collection], record)) setValidSchema(true); 247 242 else setValidSchema(false); 248 - } else { 249 - const { resolved, failed } = await resolveAllLexicons(params.collection as Nsid); 243 + } 244 + } catch (err: any) { 245 + console.error("Schema validation error:", err); 246 + setValidSchema(false); 247 + setValidationError(err.message || String(err)); 248 + } 249 + }; 250 250 251 - if (failed.size > 0) { 252 - console.error(`Failed to resolve ${failed.size} documents:`, Array.from(failed)); 253 - setValidSchema(false); 254 - setValidationError( 255 - `Unable to resolve lexicon documents: ${Array.from(failed).join(", ")}`, 256 - ); 257 - return; 258 - } 251 + const validateRemoteSchema = async (record: Record<string, unknown>) => { 252 + try { 253 + const { resolved, failed } = await resolveAllLexicons(params.collection as Nsid); 259 254 260 - const lexiconDocs = Object.fromEntries(resolved); 261 - console.log(lexiconDocs); 255 + if (failed.size > 0) { 256 + console.error(`Failed to resolve ${failed.size} documents:`, Array.from(failed)); 257 + setValidSchema(false); 258 + setValidationError(`Unable to resolve lexicon documents: ${Array.from(failed).join(", ")}`); 259 + return; 260 + } 262 261 263 - const validator = new RecordValidator(lexiconDocs, params.collection as Nsid); 264 - validator.parse({ 265 - key: params.rkey ?? null, 266 - object: record, 267 - }); 262 + const lexiconDocs = Object.fromEntries(resolved); 263 + console.log(lexiconDocs); 264 + 265 + const validator = new RecordValidator(lexiconDocs, params.collection as Nsid); 266 + validator.parse({ 267 + key: params.rkey ?? null, 268 + object: record, 269 + }); 268 270 269 - setValidSchema(true); 270 - } 271 + setValidSchema(true); 271 272 } catch (err: any) { 272 273 console.error("Schema validation error:", err); 273 274 setValidSchema(false); ··· 302 303 } 303 304 }; 304 305 305 - createEffect(() => { 306 - if (location.hash === "#info" && record()) { 307 - if (validSchema() === undefined) validateSchema(record()!.value); 308 - if (validRecord() === undefined) verifyRecordIntegrity(); 309 - } 310 - }); 311 - 312 306 const resolveLexicon = async (nsid: Nsid) => { 313 307 try { 314 308 const authority = await resolveLexiconAuthority(nsid); ··· 350 344 return template(parsedUri, record); 351 345 }; 352 346 353 - const RecordTab = (props: { tab: "record" | "backlinks" | "info" | "schema"; label: string }) => { 347 + const RecordTab = (props: { 348 + tab: "record" | "backlinks" | "info" | "schema"; 349 + label: string; 350 + error?: boolean; 351 + }) => { 354 352 const isActive = () => { 355 353 if (!location.hash && props.tab === "record") return true; 356 354 if (location.hash === `#${props.tab}`) return true; ··· 370 368 > 371 369 {props.label} 372 370 </A> 371 + <Show when={props.error && (validRecord() === false || validSchema() === false)}> 372 + <span class="iconify lucide--x text-red-500 dark:text-red-400"></span> 373 + </Show> 373 374 </div> 374 375 ); 375 376 }; ··· 382 383 <RecordTab tab="record" label="Record" /> 383 384 <RecordTab tab="schema" label="Schema" /> 384 385 <RecordTab tab="backlinks" label="Backlinks" /> 385 - <RecordTab tab="info" label="Info" /> 386 + <RecordTab tab="info" label="Info" error /> 386 387 </div> 387 388 <div class="flex gap-0.5"> 388 389 <Show when={agent() && agent()?.sub === record()?.uri.split("/")[2]}>