@atproto/lexicon-resolver 0.4.4 → 0.4.5
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/CHANGELOG.md +16 -0
- package/package.json +19 -14
- package/src/index.ts +0 -2
- package/src/lexicon.ts +0 -164
- package/src/record.ts +0 -184
- package/src/util.ts +0 -10
- package/tests/lexicon.test.ts +0 -271
- package/tests/record.test.ts +0 -193
- package/tsconfig.build.json +0 -9
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -7
- package/tsconfig.tests.json +0 -8
- package/vitest.config.ts +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @atproto/lexicon-resolver
|
|
2
2
|
|
|
3
|
+
## 0.4.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#5099](https://github.com/bluesky-social/atproto/pull/5099) [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Update TypeScript build to rely on references to composite internal projects
|
|
8
|
+
|
|
9
|
+
- [#5099](https://github.com/bluesky-social/atproto/pull/5099) [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Bundle only necessary files in the NPM tarball, including the `CHANGELOG.md` and `README.md` files (if present).
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [[`28a0b58`](https://github.com/bluesky-social/atproto/commit/28a0b588147863eaef948cd2bb8fc0f19d08cda9), [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07), [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07), [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07), [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07), [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07)]:
|
|
12
|
+
- @atproto/syntax@0.6.4
|
|
13
|
+
- @atproto/identity@0.5.3
|
|
14
|
+
- @atproto-labs/fetch-node@0.3.4
|
|
15
|
+
- @atproto/lex-document@0.1.3
|
|
16
|
+
- @atproto/lex@0.1.7
|
|
17
|
+
- @atproto/repo@0.10.3
|
|
18
|
+
|
|
3
19
|
## 0.4.4
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/lexicon-resolver",
|
|
3
|
-
"version": "0.4.
|
|
4
|
-
"engines": {
|
|
5
|
-
"node": ">=22"
|
|
6
|
-
},
|
|
7
|
-
"type": "module",
|
|
3
|
+
"version": "0.4.5",
|
|
8
4
|
"license": "MIT",
|
|
9
5
|
"description": "ATProto Lexicon resolution",
|
|
10
6
|
"keywords": [
|
|
@@ -17,28 +13,37 @@
|
|
|
17
13
|
"url": "https://github.com/bluesky-social/atproto",
|
|
18
14
|
"directory": "packages/lexicon-resolver"
|
|
19
15
|
},
|
|
16
|
+
"files": [
|
|
17
|
+
"./dist",
|
|
18
|
+
"./README.md",
|
|
19
|
+
"./CHANGELOG.md"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
20
22
|
"exports": {
|
|
21
23
|
".": {
|
|
22
24
|
"types": "./dist/index.d.ts",
|
|
23
25
|
"default": "./dist/index.js"
|
|
24
26
|
}
|
|
25
27
|
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=22"
|
|
30
|
+
},
|
|
26
31
|
"dependencies": {
|
|
27
|
-
"@atproto-labs/fetch-node": "^0.3.
|
|
28
|
-
"@atproto/
|
|
29
|
-
"@atproto/identity": "^0.5.
|
|
30
|
-
"@atproto/lex-document": "^0.1.
|
|
31
|
-
"@atproto/
|
|
32
|
-
"@atproto/syntax": "^0.6.
|
|
32
|
+
"@atproto-labs/fetch-node": "^0.3.4",
|
|
33
|
+
"@atproto/repo": "^0.10.3",
|
|
34
|
+
"@atproto/identity": "^0.5.3",
|
|
35
|
+
"@atproto/lex-document": "^0.1.3",
|
|
36
|
+
"@atproto/lex": "^0.1.7",
|
|
37
|
+
"@atproto/syntax": "^0.6.4"
|
|
33
38
|
},
|
|
34
39
|
"devDependencies": {
|
|
35
40
|
"vitest": "^4.0.16",
|
|
36
|
-
"@atproto/lex-cbor": "^0.1.
|
|
41
|
+
"@atproto/lex-cbor": "^0.1.3"
|
|
37
42
|
},
|
|
38
43
|
"scripts": {
|
|
39
44
|
"test": "vitest run",
|
|
40
45
|
"build": "tsgo --build tsconfig.build.json",
|
|
41
|
-
"prebuild": "pnpm run codegen",
|
|
42
|
-
"codegen": "lex build --clear --indexFile --lexicons ../../lexicons --include com.atproto.sync.getRecord --include com.atproto.lexicon.schema"
|
|
46
|
+
"prebuild": "pnpm run '/^(codegen:.+)$/'",
|
|
47
|
+
"codegen:lex": "lex build --clear --indexFile --lexicons ../../lexicons --include com.atproto.sync.getRecord --include com.atproto.lexicon.schema"
|
|
43
48
|
}
|
|
44
49
|
}
|
package/src/index.ts
DELETED
package/src/lexicon.ts
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import * as dns from 'node:dns/promises'
|
|
2
|
-
import { Cid, l } from '@atproto/lex'
|
|
3
|
-
import { LexiconDocument, lexiconDocumentSchema } from '@atproto/lex-document'
|
|
4
|
-
import { Commit } from '@atproto/repo'
|
|
5
|
-
import { AtUri, DidString, NSID, NsidString } from '@atproto/syntax'
|
|
6
|
-
import * as lexiconsSchema from './lexicons/com/atproto/lexicon/schema.js'
|
|
7
|
-
import {
|
|
8
|
-
BuildRecordResolverOptions,
|
|
9
|
-
ResolveRecordOptions,
|
|
10
|
-
buildRecordResolver,
|
|
11
|
-
} from './record.js'
|
|
12
|
-
|
|
13
|
-
const DNS_SUBDOMAIN = '_lexicon'
|
|
14
|
-
const DNS_PREFIX = 'did='
|
|
15
|
-
|
|
16
|
-
export type LexiconDocumentRecord = lexiconsSchema.Main & LexiconDocument
|
|
17
|
-
export const LEXICON_SCHEMA_NSID = lexiconsSchema.$nsid
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Resolve Lexicon from an NSID
|
|
21
|
-
*/
|
|
22
|
-
export type LexiconResolver = (
|
|
23
|
-
nsid: NSID | NsidString,
|
|
24
|
-
) => Promise<LexiconResolution>
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Resolve Lexicon from an NSID using Lexicon DID authority and record resolution
|
|
28
|
-
*/
|
|
29
|
-
export type AtprotoLexiconResolver = (
|
|
30
|
-
nsid: NSID | NsidString,
|
|
31
|
-
options?: ResolveLexiconOptions,
|
|
32
|
-
) => Promise<LexiconResolution>
|
|
33
|
-
|
|
34
|
-
export type BuildLexiconResolverOptions = BuildRecordResolverOptions
|
|
35
|
-
|
|
36
|
-
export type ResolveLexiconOptions = ResolveRecordOptions & {
|
|
37
|
-
didAuthority?: DidString
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export type LexiconResolution = {
|
|
41
|
-
commit: Commit
|
|
42
|
-
uri: AtUri
|
|
43
|
-
cid: Cid
|
|
44
|
-
nsid: NSID
|
|
45
|
-
lexicon: LexiconDocumentRecord
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export { AtUri, NSID }
|
|
49
|
-
export type { Cid, Commit, DidString, LexiconDocument, NsidString }
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Build a Lexicon resolver function.
|
|
53
|
-
*/
|
|
54
|
-
export function buildLexiconResolver(
|
|
55
|
-
options: BuildLexiconResolverOptions = {},
|
|
56
|
-
): AtprotoLexiconResolver {
|
|
57
|
-
const resolveRecord = buildRecordResolver(options)
|
|
58
|
-
return async function (
|
|
59
|
-
input: NSID | NsidString,
|
|
60
|
-
opts: ResolveLexiconOptions = {},
|
|
61
|
-
): Promise<LexiconResolution> {
|
|
62
|
-
const nsid = NSID.from(input)
|
|
63
|
-
const didAuthority = await getDidAuthority(nsid, opts)
|
|
64
|
-
const verified = await resolveRecord(
|
|
65
|
-
AtUri.make(didAuthority, lexiconsSchema.$nsid, nsid.toString()),
|
|
66
|
-
{ forceRefresh: opts.forceRefresh },
|
|
67
|
-
).catch((err) => {
|
|
68
|
-
throw new LexiconResolutionError(
|
|
69
|
-
nsid,
|
|
70
|
-
'Could not resolve Lexicon schema record',
|
|
71
|
-
{ cause: err },
|
|
72
|
-
)
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
if (!lexiconsSchema.$matches(verified.record)) {
|
|
76
|
-
throw new LexiconResolutionError(nsid, 'Invalid Lexicon schema record')
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const validationResult = lexiconDocumentSchema.safeValidate(verified.record)
|
|
80
|
-
if (!validationResult.success) {
|
|
81
|
-
throw new LexiconResolutionError(nsid, 'Invalid Lexicon document', {
|
|
82
|
-
cause: validationResult.reason,
|
|
83
|
-
})
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const lexicon = validationResult.value
|
|
87
|
-
if (lexicon.id !== nsid.toString()) {
|
|
88
|
-
throw new LexiconResolutionError(
|
|
89
|
-
nsid,
|
|
90
|
-
`Lexicon schema record id (${lexicon.id}) does not match NSID`,
|
|
91
|
-
)
|
|
92
|
-
}
|
|
93
|
-
const { uri, cid, commit } = verified
|
|
94
|
-
return { commit, uri, cid, nsid, lexicon }
|
|
95
|
-
} satisfies LexiconResolver
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export const resolveLexicon = buildLexiconResolver()
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Resolve the DID authority for a Lexicon from the network using DNS, based on its NSID.
|
|
102
|
-
* @param input NSID or string representing one for which to lookup its Lexicon DID authority.
|
|
103
|
-
*/
|
|
104
|
-
export async function resolveLexiconDidAuthority(
|
|
105
|
-
input: NSID | NsidString,
|
|
106
|
-
): Promise<DidString | undefined> {
|
|
107
|
-
const nsid = NSID.from(input)
|
|
108
|
-
const did = await resolveDns(nsid.authority)
|
|
109
|
-
if (did == null || !l.isDidString(did)) return
|
|
110
|
-
return did
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export class LexiconResolutionError extends Error {
|
|
114
|
-
constructor(
|
|
115
|
-
public readonly nsid: NSID,
|
|
116
|
-
public readonly description = `Could not resolve Lexicon for NSID`,
|
|
117
|
-
options?: ErrorOptions,
|
|
118
|
-
) {
|
|
119
|
-
super(`${description} (${nsid})`, options)
|
|
120
|
-
this.name = 'LexiconResolutionError'
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
static from(
|
|
124
|
-
input: NSID | string,
|
|
125
|
-
description?: string,
|
|
126
|
-
options?: ErrorOptions,
|
|
127
|
-
): LexiconResolutionError {
|
|
128
|
-
const nsid = NSID.from(input)
|
|
129
|
-
return new LexiconResolutionError(nsid, description, options)
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
async function getDidAuthority(nsid: NSID, options: ResolveLexiconOptions) {
|
|
134
|
-
if (options.didAuthority) {
|
|
135
|
-
return options.didAuthority
|
|
136
|
-
}
|
|
137
|
-
const did = await resolveLexiconDidAuthority(nsid)
|
|
138
|
-
if (!did) {
|
|
139
|
-
throw new LexiconResolutionError(
|
|
140
|
-
nsid,
|
|
141
|
-
`Could not resolve a DID authority for NSID`,
|
|
142
|
-
)
|
|
143
|
-
}
|
|
144
|
-
return did
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
async function resolveDns(authority: string): Promise<string | undefined> {
|
|
148
|
-
let chunkedResults: string[][]
|
|
149
|
-
try {
|
|
150
|
-
chunkedResults = await dns.resolveTxt(`${DNS_SUBDOMAIN}.${authority}`)
|
|
151
|
-
} catch (err) {
|
|
152
|
-
return undefined
|
|
153
|
-
}
|
|
154
|
-
return parseDnsResult(chunkedResults)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function parseDnsResult(chunkedResults: string[][]): string | undefined {
|
|
158
|
-
const results = chunkedResults.map((chunks) => chunks.join(''))
|
|
159
|
-
const found = results.filter((i) => i.startsWith(DNS_PREFIX))
|
|
160
|
-
if (found.length !== 1) {
|
|
161
|
-
return undefined
|
|
162
|
-
}
|
|
163
|
-
return found[0].slice(DNS_PREFIX.length)
|
|
164
|
-
}
|
package/src/record.ts
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import { IdResolver, parseToAtprotoDocument } from '@atproto/identity'
|
|
2
|
-
import {
|
|
3
|
-
AgentConfig,
|
|
4
|
-
Cid,
|
|
5
|
-
Client,
|
|
6
|
-
DidString,
|
|
7
|
-
FetchHandler,
|
|
8
|
-
LexMap,
|
|
9
|
-
l,
|
|
10
|
-
} from '@atproto/lex'
|
|
11
|
-
import {
|
|
12
|
-
Commit,
|
|
13
|
-
MST,
|
|
14
|
-
MemoryBlockstore,
|
|
15
|
-
def as repoDef,
|
|
16
|
-
readCarWithRoot,
|
|
17
|
-
verifyCommitSig,
|
|
18
|
-
} from '@atproto/repo'
|
|
19
|
-
import { AtUri, AtUriString } from '@atproto/syntax'
|
|
20
|
-
import { safeFetchWrap } from '@atproto-labs/fetch-node'
|
|
21
|
-
import { com } from './lexicons/index.js'
|
|
22
|
-
|
|
23
|
-
export { AtUri, IdResolver }
|
|
24
|
-
export type {
|
|
25
|
-
AgentConfig,
|
|
26
|
-
AtUriString,
|
|
27
|
-
Cid,
|
|
28
|
-
Commit,
|
|
29
|
-
DidString,
|
|
30
|
-
FetchHandler,
|
|
31
|
-
LexMap,
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Resolve a record from the network.
|
|
36
|
-
*/
|
|
37
|
-
export type RecordResolver = (
|
|
38
|
-
uri: AtUri | AtUriString,
|
|
39
|
-
) => Promise<RecordResolution>
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Resolve a record from the network, verifying its authenticity.
|
|
43
|
-
*/
|
|
44
|
-
export type AtprotoRecordResolver = (
|
|
45
|
-
uri: AtUri | AtUriString,
|
|
46
|
-
options?: ResolveRecordOptions,
|
|
47
|
-
) => Promise<RecordResolution>
|
|
48
|
-
|
|
49
|
-
export type BuildRecordResolverOptions = {
|
|
50
|
-
idResolver?: IdResolver
|
|
51
|
-
rpc?: Partial<AgentConfig> | FetchHandler
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export type ResolveRecordOptions = {
|
|
55
|
-
forceRefresh?: boolean
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export type RecordResolution = {
|
|
59
|
-
commit: Commit
|
|
60
|
-
uri: AtUri
|
|
61
|
-
cid: Cid
|
|
62
|
-
record: LexMap
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Build a record resolver function.
|
|
67
|
-
*/
|
|
68
|
-
export function buildRecordResolver(
|
|
69
|
-
options: BuildRecordResolverOptions = {},
|
|
70
|
-
): AtprotoRecordResolver {
|
|
71
|
-
const { idResolver = new IdResolver(), rpc } = options
|
|
72
|
-
return async function resolveRecord(
|
|
73
|
-
uriStr: AtUri | AtUriString,
|
|
74
|
-
opts: ResolveRecordOptions = {},
|
|
75
|
-
): Promise<RecordResolution> {
|
|
76
|
-
const uri = typeof uriStr === 'string' ? new AtUri(uriStr) : uriStr
|
|
77
|
-
const did = await getDidFromUri(uri, { idResolver })
|
|
78
|
-
const identityDoc = await idResolver.did
|
|
79
|
-
.ensureResolve(did, opts.forceRefresh)
|
|
80
|
-
.catch((err) => {
|
|
81
|
-
throw new RecordResolutionError('Could not resolve DID identity data', {
|
|
82
|
-
cause: err,
|
|
83
|
-
})
|
|
84
|
-
})
|
|
85
|
-
const { pds, signingKey } = parseToAtprotoDocument(identityDoc)
|
|
86
|
-
if (!pds) {
|
|
87
|
-
throw new RecordResolutionError(
|
|
88
|
-
'Incomplete DID identity data: missing pds',
|
|
89
|
-
)
|
|
90
|
-
}
|
|
91
|
-
if (!signingKey) {
|
|
92
|
-
throw new RecordResolutionError(
|
|
93
|
-
'Incomplete DID identity data: missing signing key',
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
const client = new Client(
|
|
97
|
-
typeof rpc === 'function'
|
|
98
|
-
? { fetchHandler: rpc }
|
|
99
|
-
: {
|
|
100
|
-
...rpc,
|
|
101
|
-
service: rpc?.service ?? pds,
|
|
102
|
-
fetch: rpc?.fetch ?? safeFetch,
|
|
103
|
-
},
|
|
104
|
-
)
|
|
105
|
-
const proofBytes = await client
|
|
106
|
-
.call(com.atproto.sync.getRecord, {
|
|
107
|
-
did,
|
|
108
|
-
collection: uri.collection as l.NsidString,
|
|
109
|
-
rkey: uri.rkey as l.RecordKeyString,
|
|
110
|
-
})
|
|
111
|
-
.catch((err) => {
|
|
112
|
-
throw new RecordResolutionError('Could not fetch record proof', {
|
|
113
|
-
cause: err,
|
|
114
|
-
})
|
|
115
|
-
})
|
|
116
|
-
const verified = await verifyRecordProof(proofBytes, {
|
|
117
|
-
uri: AtUri.make(did, uri.collection, uri.rkey),
|
|
118
|
-
signingKey,
|
|
119
|
-
})
|
|
120
|
-
return verified
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export const resolveRecord = buildRecordResolver()
|
|
125
|
-
|
|
126
|
-
export const safeFetch = safeFetchWrap({
|
|
127
|
-
allowIpHost: false,
|
|
128
|
-
allowImplicitRedirect: true,
|
|
129
|
-
responseMaxSize: (1024 + 10) * 1024, // 1MB + 10kB, just a bit larger than max record size
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
export class RecordResolutionError extends Error {
|
|
133
|
-
constructor(message?: string, options?: ErrorOptions) {
|
|
134
|
-
super(message, options)
|
|
135
|
-
this.name = 'RecordResolutionError'
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
async function getDidFromUri(
|
|
140
|
-
uri: AtUri,
|
|
141
|
-
{ idResolver }: { idResolver: IdResolver },
|
|
142
|
-
): Promise<DidString> {
|
|
143
|
-
if (l.isDidString(uri.host)) {
|
|
144
|
-
return uri.host
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const resolved = await idResolver.handle.resolve(uri.host)
|
|
148
|
-
if (!resolved || !l.isDidString(resolved)) {
|
|
149
|
-
throw new RecordResolutionError('Could not resolve handle found in AT-URI')
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return resolved
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
async function verifyRecordProof(
|
|
156
|
-
proofBytes: Uint8Array,
|
|
157
|
-
{ uri, signingKey }: { uri: AtUri; signingKey: string },
|
|
158
|
-
): Promise<RecordResolution> {
|
|
159
|
-
const { root, blocks } = await readCarWithRoot(proofBytes).catch((err) => {
|
|
160
|
-
throw new RecordResolutionError('Malformed record proof', { cause: err })
|
|
161
|
-
})
|
|
162
|
-
const blockstore = new MemoryBlockstore(blocks)
|
|
163
|
-
const commit = await blockstore.readObj(root, repoDef.commit).catch((err) => {
|
|
164
|
-
throw new RecordResolutionError('Invalid commit in record proof', {
|
|
165
|
-
cause: err,
|
|
166
|
-
})
|
|
167
|
-
})
|
|
168
|
-
if (commit.did !== uri.host) {
|
|
169
|
-
throw new RecordResolutionError(`Invalid repo did: ${commit.did}`)
|
|
170
|
-
}
|
|
171
|
-
const validSig = await verifyCommitSig(commit, signingKey)
|
|
172
|
-
if (!validSig) {
|
|
173
|
-
throw new RecordResolutionError(
|
|
174
|
-
`Invalid signature on commit: ${root.toString()}`,
|
|
175
|
-
)
|
|
176
|
-
}
|
|
177
|
-
const mst = MST.load(blockstore, commit.data)
|
|
178
|
-
const cid = await mst.get(`${uri.collection}/${uri.rkey}`)
|
|
179
|
-
if (!cid) {
|
|
180
|
-
throw new RecordResolutionError('Record not found in proof')
|
|
181
|
-
}
|
|
182
|
-
const record = (await blockstore.readRecord(cid)) as LexMap
|
|
183
|
-
return { commit, uri, cid, record }
|
|
184
|
-
}
|
package/src/util.ts
DELETED
package/tests/lexicon.test.ts
DELETED
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'
|
|
2
|
-
import { SeedClient, TestNetworkNoAppView, usersSeed } from '@atproto/dev-env'
|
|
3
|
-
import { DidString, NSID } from '@atproto/syntax'
|
|
4
|
-
import {
|
|
5
|
-
AtprotoLexiconResolver,
|
|
6
|
-
buildLexiconResolver,
|
|
7
|
-
resolveLexiconDidAuthority,
|
|
8
|
-
} from '../src/index.js'
|
|
9
|
-
|
|
10
|
-
const dnsEntries: [entry: string, ...result: string[][]][] = []
|
|
11
|
-
|
|
12
|
-
vi.mock('node:dns/promises', () => {
|
|
13
|
-
const mock = {
|
|
14
|
-
resolveTxt: (entry: string) => {
|
|
15
|
-
const found = dnsEntries.find(([e]) => e === entry)
|
|
16
|
-
if (found) return found.slice(1)
|
|
17
|
-
return []
|
|
18
|
-
},
|
|
19
|
-
}
|
|
20
|
-
return { default: mock, ...mock }
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
describe('Lexicon resolution', () => {
|
|
24
|
-
let network: TestNetworkNoAppView
|
|
25
|
-
let sc: SeedClient
|
|
26
|
-
let resolveLexicon: AtprotoLexiconResolver
|
|
27
|
-
|
|
28
|
-
beforeAll(async () => {
|
|
29
|
-
network = await TestNetworkNoAppView.create({
|
|
30
|
-
dbPostgresSchema: 'lex_lexicon_resolution',
|
|
31
|
-
})
|
|
32
|
-
sc = network.getSeedClient()
|
|
33
|
-
await usersSeed(sc)
|
|
34
|
-
dnsEntries.push(['_lexicon.alice.example', [`did=${sc.dids.alice}`]])
|
|
35
|
-
resolveLexicon = buildLexiconResolver({
|
|
36
|
-
rpc: { fetch },
|
|
37
|
-
idResolver: network.pds.ctx.idResolver,
|
|
38
|
-
})
|
|
39
|
-
}, 20_000) // @NOTE seeding can take a while
|
|
40
|
-
|
|
41
|
-
afterAll(async () => {
|
|
42
|
-
await network?.close()
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
it('resolves Lexicon.', async () => {
|
|
46
|
-
const client = network.pds.getAgent()
|
|
47
|
-
const lex = await client.com.atproto.lexicon.schema.create(
|
|
48
|
-
{ repo: sc.dids.alice, rkey: 'example.alice.name1' },
|
|
49
|
-
{ id: 'example.alice.name1', lexicon: 1, defs: {} },
|
|
50
|
-
sc.getHeaders(sc.dids.alice),
|
|
51
|
-
)
|
|
52
|
-
const result = await resolveLexicon('example.alice.name1', {
|
|
53
|
-
forceRefresh: true,
|
|
54
|
-
})
|
|
55
|
-
expect(result.commit.did).toEqual(sc.dids.alice)
|
|
56
|
-
expect(result.cid.toString()).toEqual(lex.cid)
|
|
57
|
-
expect(result.uri.toString()).toEqual(lex.uri)
|
|
58
|
-
expect(result.nsid.toString()).toEqual('example.alice.name1')
|
|
59
|
-
expect(result.lexicon).toEqual({
|
|
60
|
-
$type: 'com.atproto.lexicon.schema',
|
|
61
|
-
id: 'example.alice.name1',
|
|
62
|
-
lexicon: 1,
|
|
63
|
-
defs: {},
|
|
64
|
-
})
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it('fails on mismatched id.', async () => {
|
|
68
|
-
const client = network.pds.getAgent()
|
|
69
|
-
await client.com.atproto.lexicon.schema.create(
|
|
70
|
-
{ repo: sc.dids.alice, rkey: 'example.alice.mismatch' },
|
|
71
|
-
{ id: 'example.test1.mismatch.bad', lexicon: 1, defs: {} },
|
|
72
|
-
sc.getHeaders(sc.dids.alice),
|
|
73
|
-
)
|
|
74
|
-
await expect(
|
|
75
|
-
resolveLexicon('example.alice.mismatch', {
|
|
76
|
-
forceRefresh: true,
|
|
77
|
-
}),
|
|
78
|
-
).rejects.toThrow(
|
|
79
|
-
'Lexicon schema record id (example.test1.mismatch.bad) does not match NSID (example.alice.mismatch)',
|
|
80
|
-
)
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('fails on missing DNS entry.', async () => {
|
|
84
|
-
const client = network.pds.getAgent()
|
|
85
|
-
await client.com.atproto.lexicon.schema.create(
|
|
86
|
-
{ repo: sc.dids.bob, rkey: 'example.bob.name' },
|
|
87
|
-
{ id: 'example.bob.name', lexicon: 1, defs: {} },
|
|
88
|
-
sc.getHeaders(sc.dids.bob),
|
|
89
|
-
)
|
|
90
|
-
await expect(
|
|
91
|
-
resolveLexicon('example.bob.name', {
|
|
92
|
-
forceRefresh: true,
|
|
93
|
-
}),
|
|
94
|
-
).rejects.toThrow(
|
|
95
|
-
'Could not resolve a DID authority for NSID (example.bob.name)',
|
|
96
|
-
)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('fails on missing record.', async () => {
|
|
100
|
-
await expect(
|
|
101
|
-
resolveLexicon('example.alice.missing', {
|
|
102
|
-
forceRefresh: true,
|
|
103
|
-
}),
|
|
104
|
-
).rejects.toThrow('Could not resolve Lexicon schema record')
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
it('fails on bad verification.', async () => {
|
|
108
|
-
const client = network.pds.getAgent()
|
|
109
|
-
const alicekey = await network.pds.ctx.actorStore.keypair(sc.dids.alice)
|
|
110
|
-
const bobkey = await network.pds.ctx.actorStore.keypair(sc.dids.bob)
|
|
111
|
-
await client.com.atproto.lexicon.schema.create(
|
|
112
|
-
{ repo: sc.dids.alice, rkey: 'example.alice.badsig' },
|
|
113
|
-
{ id: 'example.alice.badsig', lexicon: 1, defs: {} },
|
|
114
|
-
sc.getHeaders(sc.dids.alice),
|
|
115
|
-
)
|
|
116
|
-
// switch alice's key away from the one used by her pds
|
|
117
|
-
await network.pds.ctx.plcClient.updateAtprotoKey(
|
|
118
|
-
sc.dids.alice,
|
|
119
|
-
network.pds.ctx.plcRotationKey,
|
|
120
|
-
bobkey.did(),
|
|
121
|
-
)
|
|
122
|
-
await expect(
|
|
123
|
-
resolveLexicon('example.alice.badsig', {
|
|
124
|
-
forceRefresh: true,
|
|
125
|
-
}),
|
|
126
|
-
).rejects.toThrow(
|
|
127
|
-
expect.objectContaining({
|
|
128
|
-
name: 'LexiconResolutionError',
|
|
129
|
-
message:
|
|
130
|
-
'Could not resolve Lexicon schema record (example.alice.badsig)',
|
|
131
|
-
cause: expect.objectContaining({
|
|
132
|
-
name: 'RecordResolutionError',
|
|
133
|
-
message: expect.stringContaining('Invalid signature on commit'),
|
|
134
|
-
}),
|
|
135
|
-
}),
|
|
136
|
-
)
|
|
137
|
-
// reset alice's key
|
|
138
|
-
await network.pds.ctx.plcClient.updateAtprotoKey(
|
|
139
|
-
sc.dids.alice,
|
|
140
|
-
network.pds.ctx.plcRotationKey,
|
|
141
|
-
alicekey.did(),
|
|
142
|
-
)
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
it('fails on invalid Lexicon document.', async () => {
|
|
146
|
-
const client = network.pds.getAgent()
|
|
147
|
-
await client.com.atproto.lexicon.schema.create(
|
|
148
|
-
{ repo: sc.dids.alice, rkey: 'example.alice.baddoc' },
|
|
149
|
-
{ id: 'example.alice.baddoc', lexicon: 999, defs: {} },
|
|
150
|
-
sc.getHeaders(sc.dids.alice),
|
|
151
|
-
)
|
|
152
|
-
await expect(
|
|
153
|
-
resolveLexicon('example.alice.baddoc', {
|
|
154
|
-
forceRefresh: true,
|
|
155
|
-
}),
|
|
156
|
-
).rejects.toThrow(
|
|
157
|
-
expect.objectContaining({
|
|
158
|
-
name: 'LexiconResolutionError',
|
|
159
|
-
message: 'Invalid Lexicon document (example.alice.baddoc)',
|
|
160
|
-
cause: expect.objectContaining({
|
|
161
|
-
name: 'LexValidationError',
|
|
162
|
-
}),
|
|
163
|
-
}),
|
|
164
|
-
)
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
it('resolves Lexicon based on override authority.', async () => {
|
|
168
|
-
const client = network.pds.getAgent()
|
|
169
|
-
await client.com.atproto.lexicon.schema.create(
|
|
170
|
-
{ repo: sc.dids.alice, rkey: 'example.alice.override' },
|
|
171
|
-
{
|
|
172
|
-
id: 'example.alice.override',
|
|
173
|
-
lexicon: 1,
|
|
174
|
-
defs: { alice: { type: 'string' } },
|
|
175
|
-
},
|
|
176
|
-
sc.getHeaders(sc.dids.alice),
|
|
177
|
-
)
|
|
178
|
-
const carolLex = await client.com.atproto.lexicon.schema.create(
|
|
179
|
-
{ repo: sc.dids.carol, rkey: 'example.alice.override' },
|
|
180
|
-
{
|
|
181
|
-
id: 'example.alice.override',
|
|
182
|
-
lexicon: 1,
|
|
183
|
-
defs: { carol: { type: 'string' } },
|
|
184
|
-
},
|
|
185
|
-
sc.getHeaders(sc.dids.carol),
|
|
186
|
-
)
|
|
187
|
-
const result = await resolveLexicon('example.alice.override', {
|
|
188
|
-
didAuthority: sc.dids.carol as DidString,
|
|
189
|
-
forceRefresh: true,
|
|
190
|
-
})
|
|
191
|
-
expect(result.commit.did).toEqual(sc.dids.carol)
|
|
192
|
-
expect(result.cid.toString()).toEqual(carolLex.cid)
|
|
193
|
-
expect(result.uri.toString()).toEqual(carolLex.uri)
|
|
194
|
-
expect(result.nsid.toString()).toEqual('example.alice.override')
|
|
195
|
-
expect(result.lexicon).toEqual({
|
|
196
|
-
$type: 'com.atproto.lexicon.schema',
|
|
197
|
-
id: 'example.alice.override',
|
|
198
|
-
lexicon: 1,
|
|
199
|
-
defs: { carol: { type: 'string' } },
|
|
200
|
-
})
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
describe('DID authority', () => {
|
|
204
|
-
it('handles a simple DNS resolution', async () => {
|
|
205
|
-
dnsEntries.push(['_lexicon.simple.test', ['did=did:example:simpleDid']])
|
|
206
|
-
const did = await resolveLexiconDidAuthority('test.simple.name')
|
|
207
|
-
expect(did).toBe('did:example:simpleDid')
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
it('handles a noisy DNS resolution', async () => {
|
|
211
|
-
dnsEntries.push([
|
|
212
|
-
'_lexicon.noisy.test',
|
|
213
|
-
['blah blah blah'],
|
|
214
|
-
['did:example:fakeDid'],
|
|
215
|
-
['atproto=did:example:fakeDid'],
|
|
216
|
-
['did=did:example:noisyDid'],
|
|
217
|
-
[
|
|
218
|
-
'chunk long domain aspdfoiuwerpoaisdfupasodfiuaspdfoiuasdpfoiausdfpaosidfuaspodifuaspdfoiuasdpfoiasudfpasodifuaspdofiuaspdfoiuasd',
|
|
219
|
-
'apsodfiuweproiasudfpoasidfu',
|
|
220
|
-
],
|
|
221
|
-
])
|
|
222
|
-
const did = await resolveLexiconDidAuthority('test.noisy.name')
|
|
223
|
-
expect(did).toBe('did:example:noisyDid')
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
it('handles a bad DNS resolution', async () => {
|
|
227
|
-
dnsEntries.push([
|
|
228
|
-
'_lexicon.bad.test',
|
|
229
|
-
['blah blah blah'],
|
|
230
|
-
['did:example:fakeDid'],
|
|
231
|
-
['atproto=did:example:fakeDid'],
|
|
232
|
-
[
|
|
233
|
-
'chunk long domain aspdfoiuwerpoaisdfupasodfiuaspdfoiuasdpfoiausdfpaosidfuaspodifuaspdfoiuasdpfoiasudfpasodifuaspdofiuaspdfoiuasd',
|
|
234
|
-
'apsodfiuweproiasudfpoasidfu',
|
|
235
|
-
],
|
|
236
|
-
])
|
|
237
|
-
const did = await resolveLexiconDidAuthority('test.bad.name')
|
|
238
|
-
expect(did).toBeUndefined()
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
it('throws on multiple dids under same domain', async () => {
|
|
242
|
-
dnsEntries.push([
|
|
243
|
-
'_lexicon.bad.test',
|
|
244
|
-
['did=did:example:firstDid'],
|
|
245
|
-
['did=did:example:secondDid'],
|
|
246
|
-
])
|
|
247
|
-
const did = await resolveLexiconDidAuthority('test.multi.name')
|
|
248
|
-
expect(did).toBeUndefined()
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
it('fails on invalid NSID', async () => {
|
|
252
|
-
// @ts-expect-error testing invalid input
|
|
253
|
-
await expect(resolveLexiconDidAuthority('not an nsid')).rejects.toThrow(
|
|
254
|
-
'Disallowed characters in NSID',
|
|
255
|
-
)
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
it('fails on invalid DID result', async () => {
|
|
259
|
-
dnsEntries.push(['_lexicon.invalid.test', ['did=not:a:did']])
|
|
260
|
-
const did = await resolveLexiconDidAuthority('test.invalid.name')
|
|
261
|
-
expect(did).toBeUndefined()
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
it('accepts NSID object', async () => {
|
|
265
|
-
const did = await resolveLexiconDidAuthority(
|
|
266
|
-
NSID.parse('test.simple.name'),
|
|
267
|
-
)
|
|
268
|
-
expect(did).toBe('did:example:simpleDid')
|
|
269
|
-
})
|
|
270
|
-
})
|
|
271
|
-
})
|
package/tests/record.test.ts
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { afterAll, assert, beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
-
import { SeedClient, TestNetworkNoAppView, usersSeed } from '@atproto/dev-env'
|
|
3
|
-
import { AtUriString, l } from '@atproto/lex'
|
|
4
|
-
import { encode } from '@atproto/lex-cbor'
|
|
5
|
-
import { AtprotoRecordResolver, buildRecordResolver } from '../src/index.js'
|
|
6
|
-
|
|
7
|
-
describe('Record resolution', () => {
|
|
8
|
-
let network: TestNetworkNoAppView
|
|
9
|
-
let sc: SeedClient
|
|
10
|
-
let resolveRecord: AtprotoRecordResolver
|
|
11
|
-
|
|
12
|
-
beforeAll(async () => {
|
|
13
|
-
network = await TestNetworkNoAppView.create({
|
|
14
|
-
dbPostgresSchema: 'lex_record_resolution',
|
|
15
|
-
})
|
|
16
|
-
sc = network.getSeedClient()
|
|
17
|
-
await usersSeed(sc)
|
|
18
|
-
resolveRecord = buildRecordResolver({
|
|
19
|
-
rpc: { fetch },
|
|
20
|
-
idResolver: network.pds.ctx.idResolver,
|
|
21
|
-
})
|
|
22
|
-
}, 20_000) // @NOTE seeding can take a while
|
|
23
|
-
|
|
24
|
-
afterAll(async () => {
|
|
25
|
-
await network?.close()
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('resolves record by AT-URI object.', async () => {
|
|
29
|
-
const post = await sc.post(sc.dids.alice, 'post1')
|
|
30
|
-
const result = await resolveRecord(post.ref.uri, {
|
|
31
|
-
forceRefresh: true,
|
|
32
|
-
})
|
|
33
|
-
expect(result.commit.did).toEqual(sc.dids.alice)
|
|
34
|
-
expect(result.cid.toString()).toEqual(post.ref.cidStr)
|
|
35
|
-
expect(result.uri.toString()).toEqual(post.ref.uriStr)
|
|
36
|
-
expect(result.record.text).toEqual('post1')
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it('resolves record by AT-URI string.', async () => {
|
|
40
|
-
const post = await sc.post(sc.dids.alice, 'post2')
|
|
41
|
-
assert(l.isAtUriString(post.ref.uriStr))
|
|
42
|
-
const result = await resolveRecord(post.ref.uriStr, {
|
|
43
|
-
forceRefresh: true,
|
|
44
|
-
})
|
|
45
|
-
expect(result.commit.did).toEqual(sc.dids.alice)
|
|
46
|
-
expect(result.cid.toString()).toEqual(post.ref.cidStr)
|
|
47
|
-
expect(result.uri.toString()).toEqual(post.ref.uriStr)
|
|
48
|
-
expect(result.record.text).toEqual('post2')
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it("does not resolve record that doesn't exist.", async () => {
|
|
52
|
-
await expect(
|
|
53
|
-
resolveRecord(`at://${sc.dids.alice}/app.bsky.feed.post/2222222222222`, {
|
|
54
|
-
forceRefresh: true,
|
|
55
|
-
}),
|
|
56
|
-
).rejects.toThrow('Record not found')
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
it('does not resolve record with bad commit signature.', async () => {
|
|
60
|
-
const alicekey = await network.pds.ctx.actorStore.keypair(sc.dids.alice)
|
|
61
|
-
const bobkey = await network.pds.ctx.actorStore.keypair(sc.dids.bob)
|
|
62
|
-
const post = await sc.post(sc.dids.alice, 'post3')
|
|
63
|
-
// switch alice's key away from the one used by her pds
|
|
64
|
-
await network.pds.ctx.plcClient.updateAtprotoKey(
|
|
65
|
-
sc.dids.alice,
|
|
66
|
-
network.pds.ctx.plcRotationKey,
|
|
67
|
-
bobkey.did(),
|
|
68
|
-
)
|
|
69
|
-
await expect(
|
|
70
|
-
resolveRecord(post.ref.uri, {
|
|
71
|
-
forceRefresh: true,
|
|
72
|
-
}),
|
|
73
|
-
).rejects.toThrow('Invalid signature on commit')
|
|
74
|
-
// reset alice's key
|
|
75
|
-
await network.pds.ctx.plcClient.updateAtprotoKey(
|
|
76
|
-
sc.dids.alice,
|
|
77
|
-
network.pds.ctx.plcRotationKey,
|
|
78
|
-
alicekey.did(),
|
|
79
|
-
)
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
it('does not resolve record with corrupted CAR block.', async () => {
|
|
83
|
-
const post = await sc.post(sc.dids.alice, 'post4')
|
|
84
|
-
const badCbor = encode({})
|
|
85
|
-
await network.pds.ctx.actorStore.transact(sc.dids.alice, (txn) =>
|
|
86
|
-
txn.repo.db.db
|
|
87
|
-
.updateTable('repo_block')
|
|
88
|
-
.set({
|
|
89
|
-
content: badCbor,
|
|
90
|
-
size: badCbor.byteLength,
|
|
91
|
-
})
|
|
92
|
-
.where('cid', '=', post.ref.cidStr)
|
|
93
|
-
.execute(),
|
|
94
|
-
)
|
|
95
|
-
await expect(
|
|
96
|
-
resolveRecord(post.ref.uri, {
|
|
97
|
-
forceRefresh: true,
|
|
98
|
-
}),
|
|
99
|
-
).rejects.toThrow('Malformed record proof')
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
it('does not resolve record with missing signing key.', async () => {
|
|
103
|
-
const post = await sc.post(sc.dids.alice, 'post5')
|
|
104
|
-
await network.pds.ctx.plcClient.updateData(
|
|
105
|
-
sc.dids.alice,
|
|
106
|
-
network.pds.ctx.plcRotationKey,
|
|
107
|
-
(doc) => {
|
|
108
|
-
doc.verificationMethods = {
|
|
109
|
-
not_atproto: doc.verificationMethods.atproto,
|
|
110
|
-
}
|
|
111
|
-
return doc
|
|
112
|
-
},
|
|
113
|
-
)
|
|
114
|
-
await expect(
|
|
115
|
-
resolveRecord(post.ref.uri, {
|
|
116
|
-
forceRefresh: true,
|
|
117
|
-
}),
|
|
118
|
-
).rejects.toThrow('Incomplete DID identity data: missing signing key')
|
|
119
|
-
// reset alice's key
|
|
120
|
-
await network.pds.ctx.plcClient.updateData(
|
|
121
|
-
sc.dids.alice,
|
|
122
|
-
network.pds.ctx.plcRotationKey,
|
|
123
|
-
(doc) => {
|
|
124
|
-
doc.verificationMethods = {
|
|
125
|
-
atproto: doc.verificationMethods.not_atproto,
|
|
126
|
-
}
|
|
127
|
-
return doc
|
|
128
|
-
},
|
|
129
|
-
)
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
it('does not resolve record with missing pds.', async () => {
|
|
133
|
-
const post = await sc.post(sc.dids.alice, 'post6')
|
|
134
|
-
await network.pds.ctx.plcClient.updateData(
|
|
135
|
-
sc.dids.alice,
|
|
136
|
-
network.pds.ctx.plcRotationKey,
|
|
137
|
-
(doc) => {
|
|
138
|
-
doc.services = {
|
|
139
|
-
not_atproto_pds: doc.services.atproto_pds,
|
|
140
|
-
}
|
|
141
|
-
return doc
|
|
142
|
-
},
|
|
143
|
-
)
|
|
144
|
-
await expect(
|
|
145
|
-
resolveRecord(post.ref.uri, {
|
|
146
|
-
forceRefresh: true,
|
|
147
|
-
}),
|
|
148
|
-
).rejects.toThrow('Incomplete DID identity data: missing pds')
|
|
149
|
-
// reset alice's pds
|
|
150
|
-
await network.pds.ctx.plcClient.updateData(
|
|
151
|
-
sc.dids.alice,
|
|
152
|
-
network.pds.ctx.plcRotationKey,
|
|
153
|
-
(doc) => {
|
|
154
|
-
doc.services = {
|
|
155
|
-
atproto_pds: doc.services.not_atproto_pds,
|
|
156
|
-
}
|
|
157
|
-
return doc
|
|
158
|
-
},
|
|
159
|
-
)
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it('resolves record despite missing at:// handle.', async () => {
|
|
163
|
-
const post = await sc.post(sc.dids.alice, 'post7')
|
|
164
|
-
await network.pds.ctx.plcClient.updateData(
|
|
165
|
-
sc.dids.alice,
|
|
166
|
-
network.pds.ctx.plcRotationKey,
|
|
167
|
-
(doc) => {
|
|
168
|
-
doc.alsoKnownAs = doc.alsoKnownAs.map((aka) =>
|
|
169
|
-
aka.replace('at://', 'notat://'),
|
|
170
|
-
)
|
|
171
|
-
return doc
|
|
172
|
-
},
|
|
173
|
-
)
|
|
174
|
-
const result = await resolveRecord(post.ref.uriStr as AtUriString, {
|
|
175
|
-
forceRefresh: true,
|
|
176
|
-
})
|
|
177
|
-
expect(result.commit.did).toEqual(sc.dids.alice)
|
|
178
|
-
expect(result.cid.toString()).toEqual(post.ref.cidStr)
|
|
179
|
-
expect(result.uri.toString()).toEqual(post.ref.uriStr)
|
|
180
|
-
expect(result.record.text).toEqual('post7')
|
|
181
|
-
// reset alice's handle
|
|
182
|
-
await network.pds.ctx.plcClient.updateData(
|
|
183
|
-
sc.dids.alice,
|
|
184
|
-
network.pds.ctx.plcRotationKey,
|
|
185
|
-
(doc) => {
|
|
186
|
-
doc.alsoKnownAs = doc.alsoKnownAs.map((aka) =>
|
|
187
|
-
aka.replace('notat://', 'at://'),
|
|
188
|
-
)
|
|
189
|
-
return doc
|
|
190
|
-
},
|
|
191
|
-
)
|
|
192
|
-
})
|
|
193
|
-
})
|
package/tsconfig.build.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":"7.0.0-dev.20260614.1","root":["./src/index.ts","./src/lexicon.ts","./src/record.ts","./src/util.ts","./src/lexicons/com.ts","./src/lexicons/index.ts","./src/lexicons/com/atproto.ts","./src/lexicons/com/atproto/lexicon.ts","./src/lexicons/com/atproto/sync.ts","./src/lexicons/com/atproto/lexicon/schema.defs.ts","./src/lexicons/com/atproto/lexicon/schema.ts","./src/lexicons/com/atproto/sync/getRecord.defs.ts","./src/lexicons/com/atproto/sync/getRecord.ts"]}
|
package/tsconfig.json
DELETED
package/tsconfig.tests.json
DELETED