@atproto/lex-installer 0.1.2 → 0.1.4

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.
@@ -1,51 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { lexiconsManifestSchema } from './lexicons-manifest.js'
3
-
4
- describe('lexiconsManifestSchema', () => {
5
- it('parses a valid manifest', () => {
6
- expect(
7
- lexiconsManifestSchema.parse({
8
- version: 1,
9
- lexicons: ['com.example.lexicon'],
10
- resolutions: {
11
- 'com.example.lexicon': {
12
- uri: 'at://did:plc:foobar/com.atproto.lexicon.schema/com.example.lexicon',
13
- cid: 'bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku',
14
- },
15
- },
16
- }),
17
- ).toEqual({
18
- version: 1,
19
- lexicons: ['com.example.lexicon'],
20
- resolutions: {
21
- 'com.example.lexicon': {
22
- uri: 'at://did:plc:foobar/com.atproto.lexicon.schema/com.example.lexicon',
23
- cid: 'bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku',
24
- },
25
- },
26
- })
27
- })
28
-
29
- it('rejects an invalid manifest', () => {
30
- expect(() =>
31
- lexiconsManifestSchema.parse({
32
- version: 1,
33
- lexicons: ['com.example.lexicon'],
34
- resolutions: {
35
- 'com.example.lexicon': {
36
- uri: 'invalid-uri',
37
- cid: 'not-a-cid',
38
- },
39
- },
40
- }),
41
- ).toThrow()
42
-
43
- expect(() =>
44
- lexiconsManifestSchema.parse({
45
- version: 2,
46
- lexicons: ['com.example.lexicon'],
47
- resolutions: {},
48
- }),
49
- ).toThrow()
50
- })
51
- })
@@ -1,66 +0,0 @@
1
- import { l } from '@atproto/lex-schema'
2
-
3
- /**
4
- * Schema for validating and parsing lexicons manifest files.
5
- *
6
- * The manifest tracks which lexicons are installed and how they were resolved.
7
- * This schema ensures the manifest file conforms to the expected structure.
8
- */
9
- export const lexiconsManifestSchema = l.object({
10
- /** Schema version, currently always 1 */
11
- version: l.literal(1),
12
- /** Array of NSID strings for directly requested lexicons */
13
- lexicons: l.array(l.string({ format: 'nsid' })),
14
- /** Map of NSID to resolution info (AT URI and CID) for all installed lexicons */
15
- resolutions: l.dict(
16
- l.string({ format: 'nsid' }),
17
- l.object({
18
- /** AT URI where the lexicon was fetched from */
19
- uri: l.string({ format: 'at-uri' }),
20
- /** Content identifier (CID) of the lexicon document */
21
- cid: l.string({ format: 'cid' }),
22
- }),
23
- ),
24
- })
25
-
26
- /**
27
- * Type representing a parsed lexicons manifest.
28
- */
29
- export type LexiconsManifest = l.Infer<typeof lexiconsManifestSchema>
30
-
31
- /**
32
- * Normalizes a lexicons manifest for consistent storage and comparison.
33
- *
34
- * This function:
35
- * - Sorts the `lexicons` array alphabetically
36
- * - Sorts the `resolutions` object entries by key
37
- * - Validates the result against the schema
38
- *
39
- * Normalization ensures that manifests with the same content produce identical
40
- * JSON output, making them suitable for version control and comparison.
41
- *
42
- * @param manifest - The manifest to normalize
43
- * @returns A new normalized manifest object
44
- */
45
- export function normalizeLexiconsManifest(
46
- manifest: LexiconsManifest,
47
- ): LexiconsManifest {
48
- const normalized: LexiconsManifest = {
49
- version: manifest.version,
50
- lexicons: [...manifest.lexicons].sort(),
51
- resolutions: Object.fromEntries(
52
- Object.entries(manifest.resolutions)
53
- .sort(compareObjectEntriesFn)
54
- .map(([k, { uri, cid }]) => [k, { uri, cid }]),
55
- ),
56
- }
57
- // For good measure:
58
- return lexiconsManifestSchema.parse(normalized)
59
- }
60
-
61
- function compareObjectEntriesFn(
62
- a: [string, unknown],
63
- b: [string, unknown],
64
- ): number {
65
- return a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0
66
- }
package/src/nsid-map.ts DELETED
@@ -1,124 +0,0 @@
1
- import { NSID } from '@atproto/syntax'
2
-
3
- /**
4
- * A Map implementation that maps keys of type K to an internal representation I.
5
- *
6
- * Key identity is determined by the {@link Object.is} comparison of the
7
- * encoded keys. This is useful for complex key types that can be serialized
8
- * to a unique primitive representation (typically strings).
9
- *
10
- * @typeParam K - The external key type
11
- * @typeParam V - The value type stored in the map
12
- * @typeParam I - The internal encoded key type used for identity comparison
13
- */
14
- class MappedMap<K, V, I = any> implements Map<K, V> {
15
- private map = new Map<I, V>()
16
-
17
- /**
18
- * Creates a new MappedMap with custom key encoding/decoding functions.
19
- *
20
- * @param encodeKey - Function to convert external keys to internal representation
21
- * @param decodeKey - Function to convert internal representation back to external keys
22
- */
23
- constructor(
24
- private readonly encodeKey: (key: K) => I,
25
- private readonly decodeKey: (enc: I) => K,
26
- ) {}
27
-
28
- get size(): number {
29
- return this.map.size
30
- }
31
-
32
- clear(): void {
33
- this.map.clear()
34
- }
35
-
36
- set(key: K, value: V): this {
37
- this.map.set(this.encodeKey(key), value)
38
- return this
39
- }
40
-
41
- get(key: K): V | undefined {
42
- return this.map.get(this.encodeKey(key))
43
- }
44
-
45
- has(key: K): boolean {
46
- return this.map.has(this.encodeKey(key))
47
- }
48
-
49
- delete(key: K): boolean {
50
- return this.map.delete(this.encodeKey(key))
51
- }
52
-
53
- values(): IterableIterator<V> {
54
- return this.map.values()
55
- }
56
-
57
- *keys(): IterableIterator<K> {
58
- for (const key of this.map.keys()) {
59
- yield this.decodeKey(key)
60
- }
61
- }
62
-
63
- *entries(): IterableIterator<[K, V]> {
64
- for (const [key, value] of this.map.entries()) {
65
- yield [this.decodeKey(key), value]
66
- }
67
- }
68
-
69
- forEach(
70
- callbackfn: (value: V, key: K, map: MappedMap<K, V>) => void,
71
- thisArg?: any,
72
- ): void {
73
- for (const [key, value] of this) {
74
- callbackfn.call(thisArg, value, key, this)
75
- }
76
- }
77
-
78
- [Symbol.iterator](): IterableIterator<[K, V]> {
79
- return this.entries()
80
- }
81
-
82
- [Symbol.toStringTag]: string = 'MappedMap'
83
- }
84
-
85
- /**
86
- * A Map specialized for using NSID (Namespaced Identifier) values as keys.
87
- *
88
- * NSIDs are compared by their string representation, allowing different
89
- * NSID object instances with the same value to be treated as the same key.
90
- *
91
- * @typeParam T - The value type stored in the map
92
- *
93
- * @example
94
- * ```typescript
95
- * import { NsidMap } from '@atproto/lex-installer'
96
- * import { NSID } from '@atproto/syntax'
97
- * import { LexiconDocument } from '@atproto/lex-document'
98
- *
99
- * const lexicons = new NsidMap<LexiconDocument>()
100
- *
101
- * // Store lexicon documents by NSID
102
- * lexicons.set(NSID.from('app.bsky.feed.post'), postLexicon)
103
- * lexicons.set(NSID.from('app.bsky.actor.profile'), profileLexicon)
104
- *
105
- * // Retrieve by NSID (different object instance works)
106
- * const doc = lexicons.get(NSID.from('app.bsky.feed.post'))
107
- *
108
- * // Iterate over entries
109
- * for (const [nsid, lexicon] of lexicons) {
110
- * console.log(`${nsid}: ${lexicon.description}`)
111
- * }
112
- * ```
113
- */
114
- export class NsidMap<T> extends MappedMap<NSID, T, string> {
115
- /**
116
- * Creates a new empty NsidMap.
117
- */
118
- constructor() {
119
- super(
120
- (key) => key.toString(),
121
- (enc) => NSID.from(enc),
122
- )
123
- }
124
- }
package/src/nsid-set.ts DELETED
@@ -1,113 +0,0 @@
1
- import { NSID } from '@atproto/syntax'
2
-
3
- /**
4
- * A Set implementation that maps values of type K to an internal representation I.
5
- *
6
- * Value identity is determined by the {@link Object.is} comparison of the
7
- * encoded values. This is useful for complex types that can be serialized
8
- * to a unique primitive representation (typically strings).
9
- *
10
- * @typeParam K - The external value type stored in the set
11
- * @typeParam I - The internal encoded type used for identity comparison
12
- */
13
- export class MappedSet<K, I = any> implements Set<K> {
14
- private set = new Set<I>()
15
-
16
- /**
17
- * Creates a new MappedSet with custom encoding/decoding functions.
18
- *
19
- * @param encodeValue - Function to convert external values to internal representation
20
- * @param decodeValue - Function to convert internal representation back to external values
21
- */
22
- constructor(
23
- private readonly encodeValue: (val: K) => I,
24
- private readonly decodeValue: (enc: I) => K,
25
- ) {}
26
-
27
- get size(): number {
28
- return this.set.size
29
- }
30
-
31
- clear(): void {
32
- this.set.clear()
33
- }
34
-
35
- add(val: K): this {
36
- this.set.add(this.encodeValue(val))
37
- return this
38
- }
39
-
40
- has(val: K): boolean {
41
- return this.set.has(this.encodeValue(val))
42
- }
43
-
44
- delete(val: K): boolean {
45
- return this.set.delete(this.encodeValue(val))
46
- }
47
-
48
- *values(): IterableIterator<K> {
49
- for (const val of this.set.values()) {
50
- yield this.decodeValue(val)
51
- }
52
- }
53
-
54
- keys(): SetIterator<K> {
55
- return this.values()
56
- }
57
-
58
- *entries(): IterableIterator<[K, K]> {
59
- for (const val of this) yield [val, val]
60
- }
61
-
62
- forEach(
63
- callbackfn: (value: K, value2: K, set: Set<K>) => void,
64
- thisArg?: any,
65
- ): void {
66
- for (const val of this) {
67
- callbackfn.call(thisArg, val, val, this)
68
- }
69
- }
70
-
71
- [Symbol.iterator](): IterableIterator<K> {
72
- return this.values()
73
- }
74
-
75
- [Symbol.toStringTag]: string = 'MappedSet'
76
- }
77
-
78
- /**
79
- * A Set specialized for storing NSID (Namespaced Identifier) values.
80
- *
81
- * NSIDs are compared by their string representation, allowing different
82
- * NSID object instances with the same value to be treated as equal.
83
- *
84
- * @example
85
- * ```typescript
86
- * import { NsidSet } from '@atproto/lex-installer'
87
- * import { NSID } from '@atproto/syntax'
88
- *
89
- * const nsidSet = new NsidSet()
90
- *
91
- * nsidSet.add(NSID.from('app.bsky.feed.post'))
92
- * nsidSet.add(NSID.from('app.bsky.actor.profile'))
93
- *
94
- * // Check membership
95
- * nsidSet.has(NSID.from('app.bsky.feed.post')) // true
96
- *
97
- * // Iterate over NSIDs
98
- * for (const nsid of nsidSet) {
99
- * console.log(nsid.toString())
100
- * }
101
- * ```
102
- */
103
- export class NsidSet extends MappedSet<NSID, string> {
104
- /**
105
- * Creates a new empty NsidSet.
106
- */
107
- constructor() {
108
- super(
109
- (val) => val.toString(),
110
- (enc) => NSID.from(enc),
111
- )
112
- }
113
- }
@@ -1,13 +0,0 @@
1
- {
2
- "extends": ["../../../tsconfig/node.json"],
3
- "include": ["./src"],
4
- "exclude": ["**/*.test.ts"],
5
- "compilerOptions": {
6
- "noImplicitAny": true,
7
- "importHelpers": true,
8
- "target": "ES2023",
9
- "rootDir": "./src",
10
- "outDir": "./dist",
11
- "types": ["node"],
12
- },
13
- }
package/tsconfig.json DELETED
@@ -1,7 +0,0 @@
1
- {
2
- "include": [],
3
- "references": [
4
- { "path": "./tsconfig.build.json" },
5
- { "path": "./tsconfig.tests.json" },
6
- ],
7
- }
@@ -1,8 +0,0 @@
1
- {
2
- "extends": "../../../tsconfig/vitest.json",
3
- "include": ["./tests", "./src/**/*.test.ts"],
4
- "compilerOptions": {
5
- "noImplicitAny": true,
6
- "rootDir": "./",
7
- },
8
- }