tangled
alpha
login
or
join now
retr0.id
/
pdsls
forked from
pds.ls/pdsls
1
fork
atom
atproto explorer
1
fork
atom
overview
issues
pulls
pipelines
add schema tab to any record
handle.invalid
4 months ago
00e9a156
110e2301
verified
This commit was signed with the committer's
known signature
.
handle.invalid
SSH Key Fingerprint:
SHA256:mBrT4x0JdzLpbVR95g1hjI1aaErfC02kmLRkPXwsYCk=
+45
-19
2 changed files
expand all
collapse all
unified
split
src
utils
api.ts
views
record.tsx
+12
-3
src/utils/api.ts
···
13
PlcDidDocumentResolver,
14
WellKnownHandleResolver,
15
} from "@atcute/identity-resolver";
16
-
import { DohJsonLexiconAuthorityResolver } from "@atcute/lexicon-resolver";
17
import { Did, Handle } from "@atcute/lexicons";
18
-
import { isHandle, Nsid } from "@atcute/lexicons/syntax";
19
import { createStore } from "solid-js/store";
20
import { setPDS } from "../components/navbar";
21
22
const didDocumentResolver = new CompositeDidDocumentResolver({
23
methods: {
24
plc: new PlcDidDocumentResolver({
25
-
apiUrl: localStorage.plcDirectory ?? "https://plc.directory",
26
}),
27
web: new AtprotoWebDidDocumentResolver(),
28
},
···
40
dohUrl: "https://mozilla.cloudflare-dns.com/dns-query",
41
});
42
0
0
0
0
43
const didPDSCache: Record<string, string> = {};
44
const [labelerCache, setLabelerCache] = createStore<Record<string, string>>({});
45
const didDocCache: Record<string, DidDocument> = {};
···
106
107
const resolveLexiconAuthority = async (nsid: Nsid) => {
108
return await authorityResolver.resolve(nsid);
0
0
0
0
109
};
110
111
interface LinkData {
···
186
resolveDidDoc,
187
resolveHandle,
188
resolveLexiconAuthority,
0
189
resolvePDS,
190
validateHandle,
191
type LinkData,
···
13
PlcDidDocumentResolver,
14
WellKnownHandleResolver,
15
} from "@atcute/identity-resolver";
16
+
import { DohJsonLexiconAuthorityResolver, LexiconSchemaResolver } from "@atcute/lexicon-resolver";
17
import { Did, Handle } from "@atcute/lexicons";
18
+
import { AtprotoDid, isHandle, Nsid } from "@atcute/lexicons/syntax";
19
import { createStore } from "solid-js/store";
20
import { setPDS } from "../components/navbar";
21
22
const didDocumentResolver = new CompositeDidDocumentResolver({
23
methods: {
24
plc: new PlcDidDocumentResolver({
25
+
apiUrl: localStorage.getItem("plcDirectory") ?? "https://plc.directory",
26
}),
27
web: new AtprotoWebDidDocumentResolver(),
28
},
···
40
dohUrl: "https://mozilla.cloudflare-dns.com/dns-query",
41
});
42
43
+
const schemaResolver = new LexiconSchemaResolver({
44
+
didDocumentResolver: didDocumentResolver,
45
+
});
46
+
47
const didPDSCache: Record<string, string> = {};
48
const [labelerCache, setLabelerCache] = createStore<Record<string, string>>({});
49
const didDocCache: Record<string, DidDocument> = {};
···
110
111
const resolveLexiconAuthority = async (nsid: Nsid) => {
112
return await authorityResolver.resolve(nsid);
113
+
};
114
+
115
+
const resolveLexiconSchema = async (authority: AtprotoDid, nsid: Nsid) => {
116
+
return await schemaResolver.resolve(authority, nsid);
117
};
118
119
interface LinkData {
···
194
resolveDidDoc,
195
resolveHandle,
196
resolveLexiconAuthority,
197
+
resolveLexiconSchema,
198
resolvePDS,
199
validateHandle,
200
type LinkData,
+33
-16
src/views/record.tsx
···
1
import { Client, CredentialManager } from "@atcute/client";
2
import { lexiconDoc } from "@atcute/lexicon-doc";
0
3
import { ActorIdentifier, is, Nsid, ResourceUri } from "@atcute/lexicons";
4
import { A, useLocation, useNavigate, useParams } from "@solidjs/router";
5
import { createResource, createSignal, ErrorBoundary, Show, Suspense } from "solid-js";
···
14
import { pds } from "../components/navbar.jsx";
15
import Tooltip from "../components/tooltip.jsx";
16
import { setNotif } from "../layout.jsx";
17
-
import { didDocCache, resolveLexiconAuthority, resolvePDS } from "../utils/api.js";
0
0
0
0
0
18
import { AtUri, uriTemplates } from "../utils/templates.js";
19
import { lexicons } from "../utils/types/lexicons.js";
20
import { verifyRecord } from "../utils/verify.js";
···
31
const [lexiconUri, setLexiconUri] = createSignal<string>();
32
const [validRecord, setValidRecord] = createSignal<boolean | undefined>(undefined);
33
const [validSchema, setValidSchema] = createSignal<boolean | undefined>(undefined);
0
0
34
const did = params.repo;
35
let rpc: Client;
36
···
72
if (is(lexicons[params.collection], record.value)) setValidSchema(true);
73
else setValidSchema(false);
74
} else if (params.collection === "com.atproto.lexicon.schema") {
0
75
try {
76
lexiconDoc.parse(record.value, { mode: "passthrough" });
77
setValidSchema(true);
···
101
102
const resolveLexicon = async (nsid: Nsid) => {
103
try {
104
-
const res = await resolveLexiconAuthority(nsid);
105
-
setLexiconUri(`at://${res}/com.atproto.lexicon.schema/${nsid}`);
106
-
} catch {}
0
0
0
0
0
0
0
107
};
108
109
const deleteRecord = async () => {
···
166
<div class="dark:shadow-dark-700 dark:bg-dark-300 mb-3 flex w-full justify-between rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 px-2 py-1.5 text-sm shadow-xs dark:border-neutral-700">
167
<div class="flex gap-3">
168
<RecordTab tab="record" label="Record" />
169
-
<Show when={params.collection === "com.atproto.lexicon.schema"}>
170
-
<RecordTab tab="schema" label="Schema" />
171
-
</Show>
172
<RecordTab tab="backlinks" label="Backlinks" />
173
<RecordTab tab="info" label="Info" error />
174
</div>
···
237
<JSONValue data={record()?.value as any} repo={record()!.uri.split("/")[2]} />
238
</div>
239
</Show>
240
-
<Show
241
-
when={
242
-
(location.hash === "#schema" || location.hash.startsWith("#schema:")) &&
243
-
params.collection === "com.atproto.lexicon.schema"
244
-
}
245
-
>
246
-
<ErrorBoundary fallback={(err) => <div>Error: {err.message}</div>}>
247
-
<LexiconSchemaView schema={record()?.value as any} />
248
-
</ErrorBoundary>
0
0
0
249
</Show>
250
<Show when={location.hash === "#backlinks"}>
251
<ErrorBoundary fallback={(err) => <div class="break-words">Error: {err.message}</div>}>
···
1
import { Client, CredentialManager } from "@atcute/client";
2
import { lexiconDoc } from "@atcute/lexicon-doc";
3
+
import { ResolvedSchema } from "@atcute/lexicon-resolver";
4
import { ActorIdentifier, is, Nsid, ResourceUri } from "@atcute/lexicons";
5
import { A, useLocation, useNavigate, useParams } from "@solidjs/router";
6
import { createResource, createSignal, ErrorBoundary, Show, Suspense } from "solid-js";
···
15
import { pds } from "../components/navbar.jsx";
16
import Tooltip from "../components/tooltip.jsx";
17
import { setNotif } from "../layout.jsx";
18
+
import {
19
+
didDocCache,
20
+
resolveLexiconAuthority,
21
+
resolveLexiconSchema,
22
+
resolvePDS,
23
+
} from "../utils/api.js";
24
import { AtUri, uriTemplates } from "../utils/templates.js";
25
import { lexicons } from "../utils/types/lexicons.js";
26
import { verifyRecord } from "../utils/verify.js";
···
37
const [lexiconUri, setLexiconUri] = createSignal<string>();
38
const [validRecord, setValidRecord] = createSignal<boolean | undefined>(undefined);
39
const [validSchema, setValidSchema] = createSignal<boolean | undefined>(undefined);
40
+
const [schema, setSchema] = createSignal<ResolvedSchema>();
41
+
const [lexiconNotFound, setLexiconNotFound] = createSignal<boolean>();
42
const did = params.repo;
43
let rpc: Client;
44
···
80
if (is(lexicons[params.collection], record.value)) setValidSchema(true);
81
else setValidSchema(false);
82
} else if (params.collection === "com.atproto.lexicon.schema") {
83
+
setLexiconNotFound(false);
84
try {
85
lexiconDoc.parse(record.value, { mode: "passthrough" });
86
setValidSchema(true);
···
110
111
const resolveLexicon = async (nsid: Nsid) => {
112
try {
113
+
const authority = await resolveLexiconAuthority(nsid);
114
+
setLexiconUri(`at://${authority}/com.atproto.lexicon.schema/${nsid}`);
115
+
if (params.collection !== "com.atproto.lexicon.schema") {
116
+
const schema = await resolveLexiconSchema(authority, nsid);
117
+
setSchema(schema);
118
+
setLexiconNotFound(false);
119
+
}
120
+
} catch {
121
+
setLexiconNotFound(true);
122
+
}
123
};
124
125
const deleteRecord = async () => {
···
182
<div class="dark:shadow-dark-700 dark:bg-dark-300 mb-3 flex w-full justify-between rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 px-2 py-1.5 text-sm shadow-xs dark:border-neutral-700">
183
<div class="flex gap-3">
184
<RecordTab tab="record" label="Record" />
185
+
<RecordTab tab="schema" label="Schema" />
0
0
186
<RecordTab tab="backlinks" label="Backlinks" />
187
<RecordTab tab="info" label="Info" error />
188
</div>
···
251
<JSONValue data={record()?.value as any} repo={record()!.uri.split("/")[2]} />
252
</div>
253
</Show>
254
+
<Show when={location.hash === "#schema" || location.hash.startsWith("#schema:")}>
255
+
<Show when={lexiconNotFound() === true}>
256
+
<span class="w-full px-2 text-sm">Lexicon schema could not be resolved.</span>
257
+
</Show>
258
+
<Show when={lexiconNotFound() === undefined}>
259
+
<span class="w-full px-2 text-sm">Resolving lexicon schema...</span>
260
+
</Show>
261
+
<Show when={schema() || params.collection === "com.atproto.lexicon.schema"}>
262
+
<ErrorBoundary fallback={(err) => <div>Error: {err.message}</div>}>
263
+
<LexiconSchemaView schema={schema()?.rawSchema ?? (record()?.value as any)} />
264
+
</ErrorBoundary>
265
+
</Show>
266
</Show>
267
<Show when={location.hash === "#backlinks"}>
268
<ErrorBoundary fallback={(err) => <div class="break-words">Error: {err.message}</div>}>