@atcute/lexicon-resolver 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ BSD Zero Clause License
2
+
3
+ Copyright (c) 2025 Mary
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14
+ PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # @atcute/lexicon-resolver
2
+
3
+ atproto lexicon authority resolution and schema retrieval
4
+
5
+ ```ts
6
+ // authority resolution
7
+ const authorityResolver = new DohJsonLexiconAuthorityResolver({
8
+ dohUrl: 'https://mozilla.cloudflare-dns.com/dns-query',
9
+ });
10
+
11
+ try {
12
+ const authority = await authorityResolver.resolve('app.bsky.feed.post');
13
+ // ^? 'did:plc:4v4y5r3lwsbtmsxhile2ljac'
14
+ } catch (err) {
15
+ if (err instanceof AuthorityNotFoundError) {
16
+ // nsid returned no did
17
+ }
18
+ if (err instanceof InvalidResolvedAuthorityError) {
19
+ // nsid returned a did, but isn't a valid atproto did
20
+ }
21
+ if (err instanceof AmbiguousAuthorityError) {
22
+ // nsid returned multiple did values
23
+ }
24
+ if (err instanceof FailedAuthorityResolutionError) {
25
+ // nsid resolution had thrown something unexpected (fetch error)
26
+ }
27
+
28
+ if (err instanceof LexiconAuthorityResolutionError) {
29
+ // the errors above extend this class, so you can do a catch-all.
30
+ }
31
+ }
32
+
33
+ // schema resolution
34
+ const schemaResolver = new LexiconSchemaResolver({
35
+ didDocumentResolver: new CompositeDidDocumentResolver({
36
+ methods: {
37
+ plc: new PlcDidDocumentResolver(),
38
+ web: new WebDidDocumentResolver(),
39
+ },
40
+ }),
41
+ });
42
+
43
+ try {
44
+ const resolved = await schemaResolver.resolve(authority, 'app.bsky.feed.post');
45
+ // ^? { uri: string, cid: string, schema: LexiconDoc }
46
+ } catch (err) {
47
+ if (err instanceof LexiconNotFoundError) {
48
+ // lexicon record not found
49
+ }
50
+ if (err instanceof InvalidLexiconSchemaError) {
51
+ // lexicon schema is malformed
52
+ }
53
+ if (err instanceof InvalidLexiconProofError) {
54
+ // lexicon record proof verification failed
55
+ }
56
+ if (err instanceof FailedLexiconResolutionError) {
57
+ // lexicon resolution had thrown something unexpected (fetch error)
58
+ }
59
+
60
+ if (err instanceof LexiconResolutionError) {
61
+ // the errors above extend this class, so you can do a catch-all.
62
+ }
63
+ }
64
+ ```
@@ -0,0 +1,12 @@
1
+ import type { AtprotoDid, Nsid } from '@atcute/lexicons/syntax';
2
+ import type { LexiconAuthorityResolver, ResolveLexiconAuthorityOptions } from '../types.js';
3
+ export interface DohJsonLexiconAuthorityResolverOptions {
4
+ dohUrl: string;
5
+ fetch?: typeof fetch;
6
+ }
7
+ export declare class DohJsonLexiconAuthorityResolver implements LexiconAuthorityResolver {
8
+ #private;
9
+ readonly dohUrl: string;
10
+ constructor({ dohUrl, fetch: fetchThis }: DohJsonLexiconAuthorityResolverOptions);
11
+ resolve(nsid: Nsid, options?: ResolveLexiconAuthorityOptions): Promise<AtprotoDid>;
12
+ }
@@ -0,0 +1,107 @@
1
+ import * as v from '@badrap/valita';
2
+ import { isAtprotoDid } from '@atcute/identity';
3
+ import { isResponseOk, parseResponseAsJson, pipe, validateJsonWith } from '@atcute/util-fetch';
4
+ import * as err from '../errors.js';
5
+ import { nsidToLookupDomain } from '../utils.js';
6
+ const uint32 = v.number().assert((input) => Number.isInteger(input) && input >= 0 && input <= 2 ** 32 - 1);
7
+ const question = v.object({
8
+ name: v.string(),
9
+ type: v.literal(16), // TXT
10
+ });
11
+ const answer = v.object({
12
+ name: v.string(),
13
+ type: v.literal(16), // TXT
14
+ TTL: uint32,
15
+ data: v.string().chain((input) => {
16
+ return v.ok(input.replace(/^"|"$/g, '').replace(/\\"/g, '"'));
17
+ }),
18
+ });
19
+ const authority = v.object({
20
+ name: v.string(),
21
+ type: uint32,
22
+ TTL: uint32,
23
+ data: v.string(),
24
+ });
25
+ const result = v.object({
26
+ /** DNS response code */
27
+ Status: uint32,
28
+ /** Whether response is truncated */
29
+ TC: v.boolean(),
30
+ /** Whether recursive desired bit is set, always true for Google and Cloudflare DoH */
31
+ RD: v.boolean(),
32
+ /** Whether recursive available bit is set, always true for Google and Cloudflare DoH */
33
+ RA: v.boolean(),
34
+ /** Whether response data was validated with DNSSEC */
35
+ AD: v.boolean(),
36
+ /** Whether client asked to disable DNSSEC validation */
37
+ CD: v.boolean(),
38
+ /** Requested records */
39
+ Question: v.tuple([question]),
40
+ /** Answers */
41
+ Answer: v.array(answer).optional(() => []),
42
+ /** Authority */
43
+ Authority: v.array(authority).optional(),
44
+ /** Comment from the DNS server */
45
+ Comment: v.string().optional(),
46
+ });
47
+ const SUBDOMAIN = '_lexicon';
48
+ const PREFIX = 'did=';
49
+ const fetchDohJsonHandler = pipe(isResponseOk, parseResponseAsJson(/^application\/(dns-)?json$/, 16 * 1024), validateJsonWith(result, { mode: 'passthrough' }));
50
+ export class DohJsonLexiconAuthorityResolver {
51
+ dohUrl;
52
+ #fetch;
53
+ constructor({ dohUrl, fetch: fetchThis = fetch }) {
54
+ this.dohUrl = dohUrl;
55
+ this.#fetch = fetchThis;
56
+ }
57
+ async resolve(nsid, options) {
58
+ const lookupDomain = nsidToLookupDomain(nsid);
59
+ let json;
60
+ try {
61
+ const url = new URL(this.dohUrl);
62
+ url.searchParams.set('name', `${SUBDOMAIN}.${lookupDomain}`);
63
+ url.searchParams.set('type', 'TXT');
64
+ const response = await (0, this.#fetch)(url, {
65
+ signal: options?.signal,
66
+ cache: options?.noCache ? 'no-cache' : undefined,
67
+ headers: { accept: 'application/dns-json' },
68
+ });
69
+ const handled = await fetchDohJsonHandler(response);
70
+ json = handled.json;
71
+ }
72
+ catch (cause) {
73
+ throw new err.FailedAuthorityResolutionError(nsid, { cause });
74
+ }
75
+ const status = json.Status;
76
+ const answers = json.Answer;
77
+ if (status !== 0 /* NOERROR */) {
78
+ if (status === 3 /* NXDOMAIN */) {
79
+ throw new err.AuthorityNotFoundError(nsid);
80
+ }
81
+ throw new err.FailedAuthorityResolutionError(nsid, {
82
+ cause: new TypeError(`dns returned ${status}`),
83
+ });
84
+ }
85
+ for (let i = 0, il = answers.length; i < il; i++) {
86
+ const answer = answers[i];
87
+ const data = answer.data;
88
+ if (!data.startsWith(PREFIX)) {
89
+ continue;
90
+ }
91
+ for (let j = i + 1; j < il; j++) {
92
+ const data = answers[j].data;
93
+ if (data.startsWith(PREFIX)) {
94
+ throw new err.AmbiguousAuthorityError(nsid);
95
+ }
96
+ }
97
+ const did = data.slice(PREFIX.length);
98
+ if (!isAtprotoDid(did)) {
99
+ throw new err.InvalidResolvedAuthorityError(nsid, did);
100
+ }
101
+ return did;
102
+ }
103
+ // theoretically this shouldn't happen, it should've returned NXDOMAIN
104
+ throw new err.AuthorityNotFoundError(nsid);
105
+ }
106
+ }
107
+ //# sourceMappingURL=doh-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doh-json.js","sourceRoot":"","sources":["../../lib/authority/doh-json.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare const LEXICON_SCHEMA_COLLECTION = "com.atproto.lexicon.schema";
@@ -0,0 +1,2 @@
1
+ export const LEXICON_SCHEMA_COLLECTION = 'com.atproto.lexicon.schema';
2
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../lib/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,yBAAyB,GAAG,4BAA4B,CAAC"}
@@ -0,0 +1,43 @@
1
+ import type { Nsid } from '@atcute/lexicons/syntax';
2
+ export declare class LexiconAuthorityResolutionError extends Error {
3
+ name: string;
4
+ }
5
+ export declare class AuthorityNotFoundError extends LexiconAuthorityResolutionError {
6
+ nsid: Nsid;
7
+ name: string;
8
+ constructor(nsid: Nsid);
9
+ }
10
+ export declare class FailedAuthorityResolutionError extends LexiconAuthorityResolutionError {
11
+ nsid: Nsid;
12
+ name: string;
13
+ constructor(nsid: Nsid, options?: ErrorOptions);
14
+ }
15
+ export declare class InvalidResolvedAuthorityError extends LexiconAuthorityResolutionError {
16
+ nsid: Nsid;
17
+ did: string;
18
+ name: string;
19
+ constructor(nsid: Nsid, did: string);
20
+ }
21
+ export declare class AmbiguousAuthorityError extends LexiconAuthorityResolutionError {
22
+ nsid: Nsid;
23
+ name: string;
24
+ constructor(nsid: Nsid);
25
+ }
26
+ export declare class LexiconResolutionError extends Error {
27
+ name: string;
28
+ }
29
+ export declare class FailedLexiconResolutionError extends LexiconResolutionError {
30
+ nsid: Nsid;
31
+ name: string;
32
+ constructor(nsid: Nsid, options?: ErrorOptions);
33
+ }
34
+ export declare class InvalidLexiconSchemaError extends LexiconResolutionError {
35
+ nsid: Nsid;
36
+ name: string;
37
+ constructor(nsid: Nsid, options?: ErrorOptions);
38
+ }
39
+ export declare class InvalidLexiconProofError extends LexiconResolutionError {
40
+ nsid: Nsid;
41
+ name: string;
42
+ constructor(nsid: Nsid, options?: ErrorOptions);
43
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,69 @@
1
+ // #region Lexicon authority resolution errors
2
+ export class LexiconAuthorityResolutionError extends Error {
3
+ name = 'LexiconAuthorityResolutionError';
4
+ }
5
+ export class AuthorityNotFoundError extends LexiconAuthorityResolutionError {
6
+ nsid;
7
+ name = 'AuthorityNotFoundError';
8
+ constructor(nsid) {
9
+ super(`lexicon authority not found; nsid=${nsid}`);
10
+ this.nsid = nsid;
11
+ }
12
+ }
13
+ export class FailedAuthorityResolutionError extends LexiconAuthorityResolutionError {
14
+ nsid;
15
+ name = 'FailedAuthorityResolutionError';
16
+ constructor(nsid, options) {
17
+ super(`failed to resolve lexicon authority; nsid=${nsid}`, options);
18
+ this.nsid = nsid;
19
+ }
20
+ }
21
+ export class InvalidResolvedAuthorityError extends LexiconAuthorityResolutionError {
22
+ nsid;
23
+ did;
24
+ name = 'InvalidResolvedAuthorityError';
25
+ constructor(nsid, did) {
26
+ super(`lexicon authority returned invalid did; nsid=${nsid}; did=${did}`);
27
+ this.nsid = nsid;
28
+ this.did = did;
29
+ }
30
+ }
31
+ export class AmbiguousAuthorityError extends LexiconAuthorityResolutionError {
32
+ nsid;
33
+ name = 'AmbiguousAuthorityError';
34
+ constructor(nsid) {
35
+ super(`lexicon authority returned multiple did values; nsid=${nsid}`);
36
+ this.nsid = nsid;
37
+ }
38
+ }
39
+ // #endregion
40
+ // #region Lexicon resolution errors
41
+ export class LexiconResolutionError extends Error {
42
+ name = 'LexiconResolutionError';
43
+ }
44
+ export class FailedLexiconResolutionError extends LexiconResolutionError {
45
+ nsid;
46
+ name = 'FailedLexiconResolutionError';
47
+ constructor(nsid, options) {
48
+ super(`failed to resolve lexicon; nsid=${nsid}`, options);
49
+ this.nsid = nsid;
50
+ }
51
+ }
52
+ export class InvalidLexiconSchemaError extends LexiconResolutionError {
53
+ nsid;
54
+ name = 'InvalidLexiconSchemaError';
55
+ constructor(nsid, options) {
56
+ super(`invalid lexicon schema; nsid=${nsid}`, options);
57
+ this.nsid = nsid;
58
+ }
59
+ }
60
+ export class InvalidLexiconProofError extends LexiconResolutionError {
61
+ nsid;
62
+ name = 'InvalidLexiconProofError';
63
+ constructor(nsid, options) {
64
+ super(`invalid lexicon record proof; nsid=${nsid}`, options);
65
+ this.nsid = nsid;
66
+ }
67
+ }
68
+ // #endregion
69
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../lib/errors.ts"],"names":[],"mappings":"AAEA,8CAA8C;AAC9C,MAAM,OAAO,+BAAgC,SAAQ,KAAK;IAChD,IAAI,GAAG,iCAAiC,CAAC;CAClD;AAED,MAAM,OAAO,sBAAuB,SAAQ,+BAA+B;IAGvD;IAFV,IAAI,GAAG,wBAAwB,CAAC;IAEzC,YAAmB,IAAU;QAC5B,KAAK,CAAC,qCAAqC,IAAI,EAAE,CAAC,CAAC;QADjC,SAAI,GAAJ,IAAI,CAAM;IAE7B,CAAC;CACD;AAED,MAAM,OAAO,8BAA+B,SAAQ,+BAA+B;IAI1E;IAHC,IAAI,GAAG,gCAAgC,CAAC;IAEjD,YACQ,IAAU,EACjB,OAAsB;QAEtB,KAAK,CAAC,6CAA6C,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;QAH7D,SAAI,GAAJ,IAAI,CAAM;IAIlB,CAAC;CACD;AAED,MAAM,OAAO,6BAA8B,SAAQ,+BAA+B;IAIzE;IACA;IAJC,IAAI,GAAG,+BAA+B,CAAC;IAEhD,YACQ,IAAU,EACV,GAAW;QAElB,KAAK,CAAC,gDAAgD,IAAI,SAAS,GAAG,EAAE,CAAC,CAAC;QAHnE,SAAI,GAAJ,IAAI,CAAM;QACV,QAAG,GAAH,GAAG,CAAQ;IAGnB,CAAC;CACD;AAED,MAAM,OAAO,uBAAwB,SAAQ,+BAA+B;IAGxD;IAFV,IAAI,GAAG,yBAAyB,CAAC;IAE1C,YAAmB,IAAU;QAC5B,KAAK,CAAC,wDAAwD,IAAI,EAAE,CAAC,CAAC;QADpD,SAAI,GAAJ,IAAI,CAAM;IAE7B,CAAC;CACD;AACD,aAAa;AAEb,oCAAoC;AACpC,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IACvC,IAAI,GAAG,wBAAwB,CAAC;CACzC;AAGD,MAAM,OAAO,4BAA6B,SAAQ,sBAAsB;IAI/D;IAHC,IAAI,GAAG,8BAA8B,CAAC;IAE/C,YACQ,IAAU,EACjB,OAAsB;QAEtB,KAAK,CAAC,mCAAmC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;QAHnD,SAAI,GAAJ,IAAI,CAAM;IAIlB,CAAC;CACD;AAED,MAAM,OAAO,yBAA0B,SAAQ,sBAAsB;IAI5D;IAHC,IAAI,GAAG,2BAA2B,CAAC;IAE5C,YACQ,IAAU,EACjB,OAAsB;QAEtB,KAAK,CAAC,gCAAgC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;QAHhD,SAAI,GAAJ,IAAI,CAAM;IAIlB,CAAC;CACD;AAED,MAAM,OAAO,wBAAyB,SAAQ,sBAAsB;IAI3D;IAHC,IAAI,GAAG,0BAA0B,CAAC;IAE3C,YACQ,IAAU,EACjB,OAAsB;QAEtB,KAAK,CAAC,sCAAsC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;QAHtD,SAAI,GAAJ,IAAI,CAAM;IAIlB,CAAC;CACD;AACD,aAAa"}
@@ -0,0 +1,5 @@
1
+ export * from './authority/doh-json.js';
2
+ export * from './errors.js';
3
+ export * from './schemas/xrpc.js';
4
+ export * from './types.js';
5
+ export * from './utils.js';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './authority/doh-json.js';
2
+ export * from './errors.js';
3
+ export * from './schemas/xrpc.js';
4
+ export * from './types.js';
5
+ export * from './utils.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type DidDocument } from '@atcute/identity';
2
+ import { type AtprotoDid } from '@atcute/lexicons/syntax';
3
+ export interface VerifiedRecord {
4
+ /** AT-URI of the record */
5
+ uri: string;
6
+ /** CID of the record */
7
+ cid: string;
8
+ /** Record data */
9
+ record: unknown;
10
+ }
11
+ export interface VerifyRecordOptions {
12
+ did: AtprotoDid;
13
+ collection: string;
14
+ rkey: string;
15
+ didDocument: DidDocument;
16
+ carBytes: Uint8Array;
17
+ }
18
+ export declare const verifyRecord: ({ did, collection, rkey, didDocument, carBytes, }: VerifyRecordOptions) => Promise<VerifiedRecord>;
@@ -0,0 +1,169 @@
1
+ import * as CAR from '@atcute/car';
2
+ import { CarReader } from '@atcute/car/v4';
3
+ import * as CBOR from '@atcute/cbor';
4
+ import * as CID from '@atcute/cid';
5
+ import { getPublicKeyFromDidController, verifySig } from '@atcute/crypto';
6
+ import { getAtprotoVerificationMaterial } from '@atcute/identity';
7
+ import {} from '@atcute/lexicons/syntax';
8
+ import { toSha256 } from '@atcute/uint8array';
9
+ export const verifyRecord = async ({ did, collection, rkey, didDocument, carBytes, }) => {
10
+ // grab public key from did document
11
+ let publicKey;
12
+ {
13
+ const controller = getAtprotoVerificationMaterial(didDocument);
14
+ if (!controller) {
15
+ throw new Error(`did document does not contain verification material`);
16
+ }
17
+ publicKey = getPublicKeyFromDidController(controller);
18
+ }
19
+ // read the car
20
+ let blockmap;
21
+ let commit;
22
+ {
23
+ const reader = CarReader.fromUint8Array(carBytes);
24
+ if (reader.header.data.roots.length !== 1) {
25
+ throw new Error(`car must have exactly one root`);
26
+ }
27
+ blockmap = new Map();
28
+ for (const entry of reader) {
29
+ const cidString = CID.toString(entry.cid);
30
+ // Verify that `bytes` matches its associated CID
31
+ const expectedCid = CID.toString(await CID.create(entry.cid.codec, entry.bytes));
32
+ if (cidString !== expectedCid) {
33
+ throw new Error(`cid does not match bytes`);
34
+ }
35
+ blockmap.set(cidString, entry);
36
+ }
37
+ if (blockmap.size === 0) {
38
+ throw new Error(`car must have at least one block`);
39
+ }
40
+ commit = CAR.readBlock(blockmap, reader.header.data.roots[0], CAR.isCommit);
41
+ }
42
+ // verify did in commit matches the did
43
+ if (commit.did !== did) {
44
+ throw new Error(`did in commit does not match expected did`);
45
+ }
46
+ // verify signature contained in commit is valid
47
+ {
48
+ const { sig, ...unsigned } = commit;
49
+ const data = CBOR.encode(unsigned);
50
+ const valid = await verifySig(publicKey, CBOR.fromBytes(sig), data);
51
+ if (!valid) {
52
+ throw new Error(`signature verification failed`);
53
+ }
54
+ }
55
+ // find and verify the record in the commit
56
+ const targetKey = `${collection}/${rkey}`;
57
+ const { found } = await dfs(blockmap, commit.data.$link, targetKey);
58
+ if (!found) {
59
+ throw new Error(`could not find record in car`);
60
+ }
61
+ return {
62
+ uri: `at://${did}/${collection}/${rkey}`,
63
+ cid: found.cid,
64
+ record: found.record,
65
+ };
66
+ };
67
+ const encoder = new TextEncoder();
68
+ const decoder = new TextDecoder();
69
+ const dfs = async (blockmap, from, targetKey, visited = new Set()) => {
70
+ // If there's no starting point, return empty state
71
+ if (from == null) {
72
+ return { found: false };
73
+ }
74
+ // Check for cycles
75
+ {
76
+ if (visited.has(from)) {
77
+ throw new Error(`cycle detected; cid=${from}`);
78
+ }
79
+ visited.add(from);
80
+ }
81
+ // Get the block data
82
+ let node;
83
+ {
84
+ const entry = blockmap.get(from);
85
+ if (!entry) {
86
+ return { found: false };
87
+ }
88
+ const decoded = CBOR.decode(entry.bytes);
89
+ if (!CAR.isMstNode(decoded)) {
90
+ throw new Error(`invalid mst node; cid=${from}`);
91
+ }
92
+ node = decoded;
93
+ }
94
+ // Recursively process the left child
95
+ const left = await dfs(blockmap, node.l?.$link, targetKey, visited);
96
+ let key = '';
97
+ let found = left.found;
98
+ let depth;
99
+ let firstKey;
100
+ let lastKey;
101
+ // Process all entries in this node
102
+ for (const entry of node.e) {
103
+ // Construct the key by truncating and appending
104
+ key = key.substring(0, entry.p) + decoder.decode(CBOR.fromBytes(entry.k));
105
+ // Check if this is our target key
106
+ if (key === targetKey) {
107
+ const recordBlock = blockmap.get(entry.v.$link);
108
+ if (recordBlock) {
109
+ const record = CBOR.decode(recordBlock.bytes);
110
+ found = { cid: entry.v.$link, record };
111
+ }
112
+ }
113
+ // Calculate depth based on leading zeros in the hash
114
+ const keyDigest = await toSha256(encoder.encode(key));
115
+ let zeroCount = 0;
116
+ outerLoop: for (const byte of keyDigest) {
117
+ for (let bit = 7; bit >= 0; bit--) {
118
+ if (((byte >> bit) & 1) !== 0) {
119
+ break outerLoop;
120
+ }
121
+ zeroCount++;
122
+ }
123
+ }
124
+ const thisDepth = Math.floor(zeroCount / 2);
125
+ // Ensure consistent depth
126
+ if (depth === undefined) {
127
+ depth = thisDepth;
128
+ }
129
+ else if (depth !== thisDepth) {
130
+ throw new Error(`node has entries with different depths; cid=${from}`);
131
+ }
132
+ // Track first and last keys
133
+ if (lastKey === undefined) {
134
+ firstKey = key;
135
+ lastKey = key;
136
+ }
137
+ // Check key ordering
138
+ if (lastKey > key) {
139
+ throw new Error(`entries are out of order; cid=${from}`);
140
+ }
141
+ // Process right child
142
+ const right = await dfs(blockmap, entry.t?.$link, targetKey, visited);
143
+ // Check ordering with right subtree
144
+ if (right.min && right.min < lastKey) {
145
+ throw new Error(`entries are out of order; cid=${from}`);
146
+ }
147
+ found = found || right.found;
148
+ // Check depth ordering
149
+ if (left.depth !== undefined && left.depth >= thisDepth) {
150
+ throw new Error(`depths are out of order; cid=${from}`);
151
+ }
152
+ if (right.depth !== undefined && right.depth >= thisDepth) {
153
+ throw new Error(`depths are out of order; cid=${from}`);
154
+ }
155
+ // Update last key based on right subtree
156
+ lastKey = right.max ?? key;
157
+ }
158
+ // Check ordering with left subtree
159
+ if (left.max && firstKey && left.max > firstKey) {
160
+ throw new Error(`entries are out of order; cid=${from}`);
161
+ }
162
+ return {
163
+ found,
164
+ min: firstKey,
165
+ max: lastKey,
166
+ depth,
167
+ };
168
+ };
169
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../lib/schemas/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { DidDocumentResolver } from '@atcute/identity-resolver';
2
+ import type { AtprotoDid, Nsid } from '@atcute/lexicons/syntax';
3
+ import type { ResolvedSchema, ResolveLexiconRecordOptions } from '../types.js';
4
+ export interface LexiconSchemaResolverOptions {
5
+ didDocumentResolver: DidDocumentResolver;
6
+ fetch?: typeof fetch;
7
+ }
8
+ export declare class LexiconSchemaResolver {
9
+ #private;
10
+ readonly didDocumentResolver: DidDocumentResolver;
11
+ constructor({ didDocumentResolver, fetch: fetchThis }: LexiconSchemaResolverOptions);
12
+ resolve(authority: AtprotoDid, nsid: Nsid, options?: ResolveLexiconRecordOptions): Promise<ResolvedSchema>;
13
+ }
@@ -0,0 +1,82 @@
1
+ import { getPdsEndpoint } from '@atcute/identity';
2
+ import { lexiconDoc } from '@atcute/lexicon-doc';
3
+ import { FailedResponseError } from '@atcute/util-fetch';
4
+ import { LEXICON_SCHEMA_COLLECTION } from '../constants.js';
5
+ import * as err from '../errors.js';
6
+ import { verifyRecord } from './verify.js';
7
+ export class LexiconSchemaResolver {
8
+ didDocumentResolver;
9
+ #fetch;
10
+ constructor({ didDocumentResolver, fetch: fetchThis = fetch }) {
11
+ this.didDocumentResolver = didDocumentResolver;
12
+ this.#fetch = fetchThis;
13
+ }
14
+ async resolve(authority, nsid, options) {
15
+ // Step 1: Resolve DID to get PDS service endpoint
16
+ const didDocument = await this.didDocumentResolver.resolve(authority, {
17
+ signal: options?.signal,
18
+ noCache: options?.noCache,
19
+ });
20
+ const pdsEndpoint = getPdsEndpoint(didDocument);
21
+ if (!pdsEndpoint) {
22
+ throw new err.FailedLexiconResolutionError(nsid, {
23
+ cause: new TypeError(`no pds service in did document; did=${authority}`),
24
+ });
25
+ }
26
+ // Step 2: Fetch the record
27
+ let carBytes;
28
+ try {
29
+ const url = new URL('/xrpc/com.atproto.sync.getRecord', pdsEndpoint);
30
+ url.searchParams.set('did', authority);
31
+ url.searchParams.set('collection', LEXICON_SCHEMA_COLLECTION);
32
+ url.searchParams.set('rkey', nsid);
33
+ const response = await (0, this.#fetch)(url, {
34
+ signal: options?.signal,
35
+ cache: options?.noCache ? 'no-cache' : undefined,
36
+ headers: { accept: 'application/vnd.ipld.car' },
37
+ });
38
+ if (!response.ok) {
39
+ throw new FailedResponseError(response.status, `got http ${response.status}`);
40
+ }
41
+ carBytes = await response.bytes();
42
+ }
43
+ catch (cause) {
44
+ throw new err.FailedLexiconResolutionError(nsid, { cause });
45
+ }
46
+ // Step 3: Verify record and extract data
47
+ let verifiedRecord;
48
+ try {
49
+ verifiedRecord = await verifyRecord({
50
+ did: authority,
51
+ collection: LEXICON_SCHEMA_COLLECTION,
52
+ rkey: nsid,
53
+ didDocument,
54
+ carBytes,
55
+ });
56
+ }
57
+ catch (cause) {
58
+ throw new err.InvalidLexiconProofError(nsid, { cause });
59
+ }
60
+ // Step 4: Parse into lexicon schema
61
+ const rawSchema = verifiedRecord.record;
62
+ if (typeof rawSchema !== 'object' ||
63
+ rawSchema === null ||
64
+ rawSchema.$type !== LEXICON_SCHEMA_COLLECTION ||
65
+ rawSchema.id !== nsid) {
66
+ throw new err.InvalidLexiconSchemaError(nsid);
67
+ }
68
+ let schema;
69
+ try {
70
+ schema = lexiconDoc.parse(rawSchema, { mode: 'passthrough' });
71
+ }
72
+ catch (cause) {
73
+ throw new err.InvalidLexiconSchemaError(nsid, { cause });
74
+ }
75
+ return {
76
+ uri: verifiedRecord.uri,
77
+ cid: verifiedRecord.cid,
78
+ schema,
79
+ };
80
+ }
81
+ }
82
+ //# sourceMappingURL=xrpc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xrpc.js","sourceRoot":"","sources":["../../lib/schemas/xrpc.ts"],"names":[],"mappings":"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"}