@atproto/did 0.5.2 → 0.5.3

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/src/did.ts DELETED
@@ -1,265 +0,0 @@
1
- import { z } from 'zod'
2
- import { DidError, InvalidDidError } from './did-error.js'
3
-
4
- const DID_PREFIX = 'did:'
5
- const DID_PREFIX_LENGTH = DID_PREFIX.length
6
- export { DID_PREFIX }
7
-
8
- /**
9
- * Type representation of a Did, with method.
10
- *
11
- * ```bnf
12
- * did = "did:" method-name ":" method-specific-id
13
- * method-name = 1*method-char
14
- * method-char = %x61-7A / DIGIT
15
- * method-specific-id = *( *idchar ":" ) 1*idchar
16
- * idchar = ALPHA / DIGIT / "." / "-" / "_" / pct-encoded
17
- * pct-encoded = "%" HEXDIG HEXDIG
18
- * ```
19
- *
20
- * @example
21
- * ```ts
22
- * type DidWeb = Did<'web'> // `did:web:${string}`
23
- * type DidCustom = Did<'web' | 'plc'> // `did:${'web' | 'plc'}:${string}`
24
- * type DidNever = Did<' invalid 🥴 '> // never
25
- * type DidFoo = Did<'foo' | ' invalid 🥴 '> // `did:foo:${string}`
26
- * ```
27
- *
28
- * @see {@link https://www.w3.org/TR/did-core/#did-syntax}
29
- */
30
- export type Did<M extends string = string> = `did:${AsDidMethod<M>}:${string}`
31
-
32
- /**
33
- * DID Method
34
- */
35
- export type AsDidMethod<M> = string extends M
36
- ? string // can't know...
37
- : AsDidMethodInternal<M, ''>
38
-
39
- type AlphanumericChar = DigitChar | LowerAlphaChar
40
- type DigitChar = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
41
- type LowerAlphaChar =
42
- | 'a'
43
- | 'b'
44
- | 'c'
45
- | 'd'
46
- | 'e'
47
- | 'f'
48
- | 'g'
49
- | 'h'
50
- | 'i'
51
- | 'j'
52
- | 'k'
53
- | 'l'
54
- | 'm'
55
- | 'n'
56
- | 'o'
57
- | 'p'
58
- | 'q'
59
- | 'r'
60
- | 's'
61
- | 't'
62
- | 'u'
63
- | 'v'
64
- | 'w'
65
- | 'x'
66
- | 'y'
67
- | 'z'
68
-
69
- type AsDidMethodInternal<
70
- S,
71
- Acc extends string,
72
- > = S extends `${infer H}${infer T}`
73
- ? H extends AlphanumericChar
74
- ? AsDidMethodInternal<T, `${Acc}${H}`>
75
- : never
76
- : Acc extends ''
77
- ? never
78
- : Acc
79
-
80
- /**
81
- * DID Method-name check function.
82
- *
83
- * Check if the input is a valid DID method name, at the position between
84
- * `start` (inclusive) and `end` (exclusive).
85
- */
86
- export function assertDidMethod(
87
- input: string,
88
- start = 0,
89
- end = input.length,
90
- ): void {
91
- if (
92
- !Number.isFinite(end) ||
93
- !Number.isFinite(start) ||
94
- end < start ||
95
- end > input.length
96
- ) {
97
- throw new TypeError('Invalid start or end position')
98
- }
99
- if (end === start) {
100
- throw new InvalidDidError(input, `Empty method name`)
101
- }
102
-
103
- let c: number
104
- for (let i = start; i < end; i++) {
105
- c = input.charCodeAt(i)
106
- if (
107
- (c < 0x61 || c > 0x7a) && // a-z
108
- (c < 0x30 || c > 0x39) // 0-9
109
- ) {
110
- throw new InvalidDidError(
111
- input,
112
- `Invalid character at position ${i} in DID method name`,
113
- )
114
- }
115
- }
116
- }
117
-
118
- /**
119
- * This method assumes the input is a valid Did
120
- */
121
- export function extractDidMethod<D extends Did>(did: D) {
122
- const msidSep = did.indexOf(':', DID_PREFIX_LENGTH)
123
- const method = did.slice(DID_PREFIX_LENGTH, msidSep)
124
- return method as D extends Did<infer M> ? M : string
125
- }
126
-
127
- /**
128
- * DID Method-specific identifier check function.
129
- *
130
- * Check if the input is a valid DID method-specific identifier, at the position
131
- * between `start` (inclusive) and `end` (exclusive).
132
- */
133
- export function assertDidMsid(
134
- input: string,
135
- start = 0,
136
- end = input.length,
137
- ): void {
138
- if (
139
- !Number.isFinite(end) ||
140
- !Number.isFinite(start) ||
141
- end < start ||
142
- end > input.length
143
- ) {
144
- throw new TypeError('Invalid start or end position')
145
- }
146
- if (end === start) {
147
- throw new InvalidDidError(input, `DID method-specific id must not be empty`)
148
- }
149
-
150
- let c: number
151
- for (let i = start; i < end; i++) {
152
- c = input.charCodeAt(i)
153
-
154
- // Check for frequent chars first
155
- if (
156
- (c < 0x61 || c > 0x7a) && // a-z
157
- (c < 0x41 || c > 0x5a) && // A-Z
158
- (c < 0x30 || c > 0x39) && // 0-9
159
- c !== 0x2e && // .
160
- c !== 0x2d && // -
161
- c !== 0x5f // _
162
- ) {
163
- // Less frequent chars are checked here
164
-
165
- // ":"
166
- if (c === 0x3a) {
167
- if (i === end - 1) {
168
- throw new InvalidDidError(input, `DID cannot end with ":"`)
169
- }
170
- continue
171
- }
172
-
173
- // pct-encoded
174
- if (c === 0x25) {
175
- c = input.charCodeAt(++i)
176
- if ((c < 0x30 || c > 0x39) && (c < 0x41 || c > 0x46)) {
177
- throw new InvalidDidError(
178
- input,
179
- `Invalid pct-encoded character at position ${i}`,
180
- )
181
- }
182
-
183
- c = input.charCodeAt(++i)
184
- if ((c < 0x30 || c > 0x39) && (c < 0x41 || c > 0x46)) {
185
- throw new InvalidDidError(
186
- input,
187
- `Invalid pct-encoded character at position ${i}`,
188
- )
189
- }
190
-
191
- // There must always be 2 HEXDIG after a "%"
192
- if (i >= end) {
193
- throw new InvalidDidError(
194
- input,
195
- `Incomplete pct-encoded character at position ${i - 2}`,
196
- )
197
- }
198
-
199
- continue
200
- }
201
-
202
- throw new InvalidDidError(
203
- input,
204
- `Disallowed character in DID at position ${i}`,
205
- )
206
- }
207
- }
208
- }
209
-
210
- export function assertDid(input: unknown): asserts input is Did {
211
- if (typeof input !== 'string') {
212
- throw new InvalidDidError(typeof input, `DID must be a string`)
213
- }
214
-
215
- const { length } = input
216
- if (length > 2048) {
217
- throw new InvalidDidError(input, `DID is too long (2048 chars max)`)
218
- }
219
-
220
- if (!input.startsWith(DID_PREFIX)) {
221
- throw new InvalidDidError(input, `DID requires "${DID_PREFIX}" prefix`)
222
- }
223
-
224
- const idSep = input.indexOf(':', DID_PREFIX_LENGTH)
225
- if (idSep === -1) {
226
- throw new InvalidDidError(input, `Missing colon after method name`)
227
- }
228
-
229
- assertDidMethod(input, DID_PREFIX_LENGTH, idSep)
230
- assertDidMsid(input, idSep + 1, length)
231
- }
232
-
233
- export function isDid(input: unknown): input is Did {
234
- try {
235
- assertDid(input)
236
- return true
237
- } catch (err) {
238
- if (err instanceof DidError) {
239
- return false
240
- }
241
-
242
- // Unexpected TypeError (should never happen)
243
- throw err
244
- }
245
- }
246
-
247
- export function asDid<T>(input: T) {
248
- assertDid(input)
249
- return input
250
- }
251
-
252
- export const didSchema = z
253
- .string()
254
- .superRefine((value: string, ctx: z.RefinementCtx): value is Did => {
255
- try {
256
- assertDid(value)
257
- return true
258
- } catch (err) {
259
- ctx.addIssue({
260
- code: z.ZodIssueCode.custom,
261
- message: err instanceof Error ? err.message : 'Unexpected error',
262
- })
263
- return false
264
- }
265
- })
package/src/index.ts DELETED
@@ -1,7 +0,0 @@
1
- export * from './atproto.js'
2
- export * from './did-document.js'
3
- export * from './did-error.js'
4
- export * from './did-ref.js'
5
- export * from './did.js'
6
- export * from './methods.js'
7
- export * from './utils.js'
package/src/lib/uri.ts DELETED
@@ -1,78 +0,0 @@
1
- /**
2
- * @see {@link https://www.w3.org/TR/did-1.0/#dfn-did-fragments}
3
- * @see {@link https://datatracker.ietf.org/doc/html/rfc3986#section-3.5}
4
- */
5
- export function isFragment(
6
- value: string,
7
- startIdx = 0,
8
- endIdx = value.length,
9
- ): boolean {
10
- let charCode: number
11
- for (let i = startIdx; i < endIdx; i++) {
12
- charCode = value.charCodeAt(i)
13
-
14
- // fragment = *( pchar / "/" / "?" )
15
- // pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
16
- // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
17
- // pct-encoded = "%" HEXDIG HEXDIG
18
- // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
19
- if (
20
- (charCode >= 65 /* A */ && charCode <= 90) /* Z */ ||
21
- (charCode >= 97 /* a */ && charCode <= 122) /* z */ ||
22
- (charCode >= 48 /* 0 */ && charCode <= 57) /* 9 */ ||
23
- charCode === 45 /* "-" */ ||
24
- charCode === 46 /* "." */ ||
25
- charCode === 95 /* "_" */ ||
26
- charCode === 126 /* "~" */
27
- ) {
28
- // unreserved
29
- } else if (
30
- charCode === 33 /* "!" */ ||
31
- charCode === 36 /* "$" */ ||
32
- charCode === 38 /* "&" */ ||
33
- charCode === 39 /* "'" */ ||
34
- charCode === 40 /* "(" */ ||
35
- charCode === 41 /* ")" */ ||
36
- charCode === 42 /* "*" */ ||
37
- charCode === 43 /* "+" */ ||
38
- charCode === 44 /* "," */ ||
39
- charCode === 59 /* ";" */ ||
40
- charCode === 61 /* "=" */
41
- ) {
42
- // sub-delims
43
- } else if (charCode === 58 /* ":" */ || charCode === 64 /* "@" */) {
44
- // pchar extra
45
- } else if (charCode === 47 /* "/" */ || charCode === 63 /* "?" */) {
46
- // fragment extra
47
- } else if (charCode === 37 /* "%" */) {
48
- // pct-enc
49
- if (i + 2 >= endIdx) return false
50
- if (!isHexDigit(value.charCodeAt(i + 1))) return false
51
- if (!isHexDigit(value.charCodeAt(i + 2))) return false
52
- i += 2
53
- } else {
54
- return false
55
- }
56
- }
57
-
58
- return true
59
- }
60
-
61
- export function isHexDigit(code: number): boolean {
62
- return (
63
- (code >= 48 && code <= 57) || // 0-9
64
- (code >= 65 && code <= 70) || // A-F
65
- (code >= 97 && code <= 102) // a-f
66
- )
67
- }
68
-
69
- export const canParse =
70
- URL.canParse?.bind(URL) ??
71
- ((url, base) => {
72
- try {
73
- new URL(url, base)
74
- return true
75
- } catch {
76
- return false
77
- }
78
- })
@@ -1,54 +0,0 @@
1
- import { InvalidDidError } from '../did-error.js'
2
- import { Did } from '../did.js'
3
-
4
- const DID_PLC_PREFIX = `did:plc:`
5
- const DID_PLC_PREFIX_LENGTH = DID_PLC_PREFIX.length
6
- const DID_PLC_LENGTH = 32
7
-
8
- export { DID_PLC_PREFIX }
9
-
10
- export function isDidPlc(input: unknown): input is Did<'plc'> {
11
- // Optimization: equivalent to try/catch around "assertDidPlc"
12
- if (typeof input !== 'string') return false
13
- if (input.length !== DID_PLC_LENGTH) return false
14
- if (!input.startsWith(DID_PLC_PREFIX)) return false
15
- for (let i = DID_PLC_PREFIX_LENGTH; i < DID_PLC_LENGTH; i++) {
16
- if (!isBase32Char(input.charCodeAt(i))) return false
17
- }
18
- return true
19
- }
20
-
21
- export function asDidPlc<T>(input: T) {
22
- assertDidPlc(input)
23
- return input
24
- }
25
-
26
- export function assertDidPlc(input: unknown): asserts input is Did<'plc'> {
27
- if (typeof input !== 'string') {
28
- throw new InvalidDidError(typeof input, `DID must be a string`)
29
- }
30
-
31
- if (!input.startsWith(DID_PLC_PREFIX)) {
32
- throw new InvalidDidError(input, `Invalid did:plc prefix`)
33
- }
34
-
35
- if (input.length !== DID_PLC_LENGTH) {
36
- throw new InvalidDidError(
37
- input,
38
- `did:plc must be ${DID_PLC_LENGTH} characters long`,
39
- )
40
- }
41
-
42
- // The following check is not necessary, as the check below is more strict:
43
-
44
- // assertDidMsid(input, DID_PLC_PREFIX.length)
45
-
46
- for (let i = DID_PLC_PREFIX_LENGTH; i < DID_PLC_LENGTH; i++) {
47
- if (!isBase32Char(input.charCodeAt(i))) {
48
- throw new InvalidDidError(input, `Invalid character at position ${i}`)
49
- }
50
- }
51
- }
52
-
53
- const isBase32Char = (c: number): boolean =>
54
- (c >= 0x61 && c <= 0x7a) || (c >= 0x32 && c <= 0x37) // [a-z2-7]
@@ -1,83 +0,0 @@
1
- import { InvalidDidError } from '../did-error.js'
2
- import { Did, assertDidMsid } from '../did.js'
3
- import { canParse } from '../lib/uri.js'
4
-
5
- export const DID_WEB_PREFIX = `did:web:` satisfies Did<'web'>
6
-
7
- /**
8
- * This function checks if the input is a valid Web DID, as per DID spec.
9
- */
10
- export function isDidWeb(input: unknown): input is Did<'web'> {
11
- // Optimization: make cheap checks first
12
- if (typeof input !== 'string') return false
13
- if (!input.startsWith(DID_WEB_PREFIX)) return false
14
- if (input.charAt(DID_WEB_PREFIX.length) === ':') return false
15
-
16
- try {
17
- assertDidMsid(input, DID_WEB_PREFIX.length)
18
- } catch {
19
- return false
20
- }
21
-
22
- return canParse(buildDidWebUrl(input as Did<'web'>))
23
- }
24
-
25
- export function asDidWeb<T>(input: T) {
26
- assertDidWeb(input)
27
- return input
28
- }
29
-
30
- export function assertDidWeb(input: unknown): asserts input is Did<'web'> {
31
- if (typeof input !== 'string') {
32
- throw new InvalidDidError(typeof input, `DID must be a string`)
33
- }
34
-
35
- if (!input.startsWith(DID_WEB_PREFIX)) {
36
- throw new InvalidDidError(input, `Invalid did:web prefix`)
37
- }
38
-
39
- if (input.charAt(DID_WEB_PREFIX.length) === ':') {
40
- throw new InvalidDidError(input, 'did:web MSID must not start with a colon')
41
- }
42
-
43
- // Make sure every char is valid (per DID spec)
44
- assertDidMsid(input, DID_WEB_PREFIX.length)
45
-
46
- if (!canParse(buildDidWebUrl(input as Did<'web'>))) {
47
- throw new InvalidDidError(input, 'Invalid Web DID')
48
- }
49
- }
50
-
51
- export function didWebToUrl(did: Did<'web'>) {
52
- try {
53
- return new URL(buildDidWebUrl(did)) as URL & {
54
- protocol: 'http:' | 'https:'
55
- }
56
- } catch (cause) {
57
- throw new InvalidDidError(did, 'Invalid Web DID', cause)
58
- }
59
- }
60
-
61
- export function urlToDidWeb(url: URL): Did<'web'> {
62
- const port = url.port ? `%3A${url.port}` : ''
63
- const path = url.pathname === '/' ? '' : url.pathname.replaceAll('/', ':')
64
-
65
- return `did:web:${url.hostname}${port}${path}`
66
- }
67
-
68
- export function buildDidWebUrl(did: Did<'web'>): string {
69
- const hostIdx = DID_WEB_PREFIX.length
70
- const pathIdx = did.indexOf(':', hostIdx)
71
-
72
- const hostEnc =
73
- pathIdx === -1 ? did.slice(hostIdx) : did.slice(hostIdx, pathIdx)
74
- const host = hostEnc.replaceAll('%3A', ':')
75
- const path = pathIdx === -1 ? '' : did.slice(pathIdx).replaceAll(':', '/')
76
- const proto =
77
- host.startsWith('localhost') &&
78
- (host.length === 9 || host.charCodeAt(9) === 58) /* ':' */
79
- ? 'http'
80
- : 'https'
81
-
82
- return `${proto}://${host}${path}`
83
- }
package/src/methods.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './methods/plc.js'
2
- export * from './methods/web.js'
package/src/utils.ts DELETED
@@ -1,18 +0,0 @@
1
- export type Identifier<D extends string, I extends string> =
2
- | `#${I}`
3
- | `${D}#${I}`
4
- export function matchesIdentifier<D extends string, I extends string>(
5
- did: D,
6
- id: I,
7
- candidate: string,
8
- ): candidate is Identifier<D, I> {
9
- // optimized implementation of:
10
- // return candidate === `#${id}` || candidate === `${did}#${id}`
11
-
12
- return candidate.charCodeAt(0) === 35 // '#'
13
- ? candidate.length === id.length + 1 && candidate.endsWith(id)
14
- : candidate.length === id.length + 1 + did.length &&
15
- candidate.charCodeAt(did.length) === 35 && // '#'
16
- candidate.startsWith(did) &&
17
- candidate.endsWith(id)
18
- }
@@ -1,69 +0,0 @@
1
- import { isAtprotoDidRefAbsolute } from '../src/atproto.js'
2
- import { isDidRefRelative } from '../src/did-ref.js'
3
-
4
- describe('isAtprotoDidRefAbsolute', () => {
5
- it('accepts well-formed absolute references', () => {
6
- expect(
7
- isAtprotoDidRefAbsolute('did:plc:l3rouwludahu3ui3bt66mfvj#atproto'),
8
- ).toBe(true)
9
- expect(isAtprotoDidRefAbsolute('did:web:example.com#service_id')).toBe(true)
10
- expect(isAtprotoDidRefAbsolute('did:web:example.com#atproto_label')).toBe(
11
- true,
12
- )
13
- })
14
-
15
- it('rejects bare DIDs', () => {
16
- expect(isAtprotoDidRefAbsolute('did:plc:l3rouwludahu3ui3bt66mfvj')).toBe(
17
- false,
18
- )
19
- expect(isAtprotoDidRefAbsolute('did:web:example.com')).toBe(false)
20
- })
21
-
22
- it('rejects relative references', () => {
23
- expect(isAtprotoDidRefAbsolute('#atproto')).toBe(false)
24
- })
25
-
26
- it('rejects malformed input', () => {
27
- expect(isAtprotoDidRefAbsolute('')).toBe(false)
28
- expect(isAtprotoDidRefAbsolute('did:plc:l3rouwludahu3ui3bt66mfvj#')).toBe(
29
- false,
30
- )
31
- expect(
32
- isAtprotoDidRefAbsolute('did:plc:l3rouwludahu3ui3bt66mfvj##foo'),
33
- ).toBe(false)
34
- expect(
35
- isAtprotoDidRefAbsolute('did:plc:l3rouwludahu3ui3bt66mfvj#a#b'),
36
- ).toBe(false)
37
- expect(isAtprotoDidRefAbsolute('did:foo:bar#baz')).toBe(false)
38
- expect(isAtprotoDidRefAbsolute(null)).toBe(false)
39
- expect(isAtprotoDidRefAbsolute(123)).toBe(false)
40
- })
41
- })
42
-
43
- describe('isDidRefRelative', () => {
44
- it('accepts well-formed relative references', () => {
45
- expect(isDidRefRelative('#atproto')).toBe(true)
46
- expect(isDidRefRelative('#atproto_label')).toBe(true)
47
- expect(isDidRefRelative('#a')).toBe(true)
48
- })
49
-
50
- it('narrows on a specific id when supplied', () => {
51
- expect(isDidRefRelative('#atproto', 'atproto')).toBe(true)
52
- expect(isDidRefRelative('#atproto_label', 'atproto')).toBe(false)
53
- })
54
-
55
- it('rejects absolute references and bare strings', () => {
56
- expect(isDidRefRelative('did:plc:l3rouwludahu3ui3bt66mfvj#atproto')).toBe(
57
- false,
58
- )
59
- expect(isDidRefRelative('atproto')).toBe(false)
60
- })
61
-
62
- it('rejects malformed input', () => {
63
- expect(isDidRefRelative('')).toBe(false)
64
- expect(isDidRefRelative('#')).toBe(false)
65
- expect(isDidRefRelative('#a#b')).toBe(false)
66
- expect(isDidRefRelative(null)).toBe(false)
67
- expect(isDidRefRelative(123)).toBe(false)
68
- })
69
- })
@@ -1,72 +0,0 @@
1
- import { InvalidDidError } from '../../src/did-error.js'
2
- import { Did } from '../../src/did.js'
3
- import { asDidPlc, assertDidPlc, isDidPlc } from '../../src/methods/plc.js'
4
-
5
- const VALID: Did<'plc'>[] = [
6
- 'did:plc:l3rouwludahu3ui3bt66mfvj',
7
- 'did:plc:aaaaaaaaaaaaaaaaaaaaaaaa',
8
- 'did:plc:zzzzzzzzzzzzzzzzzzzzzzzz',
9
- ]
10
-
11
- const INVALID: [value: unknown, message: string][] = [
12
- ['did:plc:l3rouwludahu3ui3bt66mfv0', 'Invalid character at position 31'],
13
- ['did:plc:l3rouwludahu3ui3bt66mfv1', 'Invalid character at position 31'],
14
- ['did:plc:l3rouwludahu3ui3bt66mfv9', 'Invalid character at position 31'],
15
- ['did:plc:l3rouwludahu3ui3bt66mfv', 'did:plc must be 32 characters long'],
16
- ['did:plc:l3rouwludahu3ui3bt66mfvja', 'did:plc must be 32 characters long'],
17
- ['did:plc:example.com:', 'did:plc must be 32 characters long'],
18
- ['did:plc:exam%3Aple.com%3A8080', 'did:plc must be 32 characters long'],
19
- [3, 'DID must be a string'],
20
- [{ toString: () => 'did:plc:foo.com' }, 'DID must be a string'],
21
- [[''], 'DID must be a string'],
22
- ['random-string', 'Invalid did:plc prefix'],
23
- ['did plc', 'Invalid did:plc prefix'],
24
- ['lorem ipsum dolor sit', 'Invalid did:plc prefix'],
25
- ]
26
-
27
- describe('isDidPlc', () => {
28
- it('returns true for various valid dids', () => {
29
- for (const did of VALID) {
30
- expect(isDidPlc(did)).toBe(true)
31
- }
32
- })
33
-
34
- it('returns false for invalid dids', () => {
35
- for (const [did] of INVALID) {
36
- expect(isDidPlc(did)).toBe(false)
37
- }
38
- })
39
- })
40
-
41
- describe('assertDidPlc', () => {
42
- it('does not throw on valid dids', () => {
43
- for (const did of VALID) {
44
- expect(() => assertDidPlc(did)).not.toThrow()
45
- }
46
- })
47
-
48
- it('throws if called with non string argument', () => {
49
- for (const [val, message] of INVALID) {
50
- expect(() => assertDidPlc(val)).toThrow(
51
- new InvalidDidError(
52
- typeof val === 'string' ? val : typeof val,
53
- message,
54
- ),
55
- )
56
- }
57
- })
58
- })
59
-
60
- describe('asDidPlc', () => {
61
- it('returns the input for valid dids', () => {
62
- for (const did of VALID) {
63
- expect(asDidPlc(did)).toBe(did)
64
- }
65
- })
66
-
67
- it('throws if called with invalid dids', () => {
68
- for (const [val] of INVALID) {
69
- expect(() => asDidPlc(val)).toThrow(InvalidDidError)
70
- }
71
- })
72
- })