···11+declare const __brand: unique symbol
22+33+type Brand<T, B extends string> = T & { readonly [__brand]: B }
44+55+export type Did = Brand<string, 'Did'>
66+export type DidPlc = Brand<Did, 'DidPlc'>
77+export type DidWeb = Brand<Did, 'DidWeb'>
88+99+export type Handle = Brand<string, 'Handle'>
1010+export type AccessToken = Brand<string, 'AccessToken'>
1111+export type RefreshToken = Brand<string, 'RefreshToken'>
1212+export type ServiceToken = Brand<string, 'ServiceToken'>
1313+export type SetupToken = Brand<string, 'SetupToken'>
1414+1515+export type Cid = Brand<string, 'Cid'>
1616+export type Rkey = Brand<string, 'Rkey'>
1717+export type AtUri = Brand<string, 'AtUri'>
1818+export type Nsid = Brand<string, 'Nsid'>
1919+2020+export type ISODateString = Brand<string, 'ISODateString'>
2121+export type EmailAddress = Brand<string, 'EmailAddress'>
2222+export type InviteCode = Brand<string, 'InviteCode'>
2323+2424+export type PublicKeyMultibase = Brand<string, 'PublicKeyMultibase'>
2525+export type DidKeyString = Brand<string, 'DidKeyString'>
2626+2727+const DID_PLC_REGEX = /^did:plc:[a-z2-7]{24}$/
2828+const DID_WEB_REGEX = /^did:web:.+$/
2929+const HANDLE_REGEX = /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/
3030+const AT_URI_REGEX = /^at:\/\/[^/]+\/[^/]+\/[^/]+$/
3131+const CID_REGEX = /^[a-z2-7]{59}$|^baf[a-z2-7]+$/
3232+const NSID_REGEX = /^[a-z]([a-z0-9-]*[a-z0-9])?(\.[a-z]([a-z0-9-]*[a-z0-9])?)+$/
3333+const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
3434+const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/
3535+3636+export function isDid(s: string): s is Did {
3737+ return s.startsWith('did:plc:') || s.startsWith('did:web:')
3838+}
3939+4040+export function isDidPlc(s: string): s is DidPlc {
4141+ return DID_PLC_REGEX.test(s)
4242+}
4343+4444+export function isDidWeb(s: string): s is DidWeb {
4545+ return DID_WEB_REGEX.test(s)
4646+}
4747+4848+export function isHandle(s: string): s is Handle {
4949+ return HANDLE_REGEX.test(s) && s.length <= 253
5050+}
5151+5252+export function isAtUri(s: string): s is AtUri {
5353+ return AT_URI_REGEX.test(s)
5454+}
5555+5656+export function isCid(s: string): s is Cid {
5757+ return CID_REGEX.test(s)
5858+}
5959+6060+export function isNsid(s: string): s is Nsid {
6161+ return NSID_REGEX.test(s)
6262+}
6363+6464+export function isEmail(s: string): s is EmailAddress {
6565+ return EMAIL_REGEX.test(s)
6666+}
6767+6868+export function isISODate(s: string): s is ISODateString {
6969+ return ISO_DATE_REGEX.test(s)
7070+}
7171+7272+export function asDid(s: string): Did {
7373+ if (!isDid(s)) throw new TypeError(`Invalid DID: ${s}`)
7474+ return s
7575+}
7676+7777+export function asDidPlc(s: string): DidPlc {
7878+ if (!isDidPlc(s)) throw new TypeError(`Invalid DID:PLC: ${s}`)
7979+ return s as DidPlc
8080+}
8181+8282+export function asDidWeb(s: string): DidWeb {
8383+ if (!isDidWeb(s)) throw new TypeError(`Invalid DID:WEB: ${s}`)
8484+ return s as DidWeb
8585+}
8686+8787+export function asHandle(s: string): Handle {
8888+ if (!isHandle(s)) throw new TypeError(`Invalid handle: ${s}`)
8989+ return s
9090+}
9191+9292+export function asAtUri(s: string): AtUri {
9393+ if (!isAtUri(s)) throw new TypeError(`Invalid AT-URI: ${s}`)
9494+ return s
9595+}
9696+9797+export function asCid(s: string): Cid {
9898+ if (!isCid(s)) throw new TypeError(`Invalid CID: ${s}`)
9999+ return s
100100+}
101101+102102+export function asNsid(s: string): Nsid {
103103+ if (!isNsid(s)) throw new TypeError(`Invalid NSID: ${s}`)
104104+ return s
105105+}
106106+107107+export function asEmail(s: string): EmailAddress {
108108+ if (!isEmail(s)) throw new TypeError(`Invalid email: ${s}`)
109109+ return s
110110+}
111111+112112+export function asISODate(s: string): ISODateString {
113113+ if (!isISODate(s)) throw new TypeError(`Invalid ISO date: ${s}`)
114114+ return s
115115+}
116116+117117+export function unsafeAsDid(s: string): Did {
118118+ return s as Did
119119+}
120120+121121+export function unsafeAsHandle(s: string): Handle {
122122+ return s as Handle
123123+}
124124+125125+export function unsafeAsAccessToken(s: string): AccessToken {
126126+ return s as AccessToken
127127+}
128128+129129+export function unsafeAsRefreshToken(s: string): RefreshToken {
130130+ return s as RefreshToken
131131+}
132132+133133+export function unsafeAsServiceToken(s: string): ServiceToken {
134134+ return s as ServiceToken
135135+}
136136+137137+export function unsafeAsSetupToken(s: string): SetupToken {
138138+ return s as SetupToken
139139+}
140140+141141+export function unsafeAsCid(s: string): Cid {
142142+ return s as Cid
143143+}
144144+145145+export function unsafeAsRkey(s: string): Rkey {
146146+ return s as Rkey
147147+}
148148+149149+export function unsafeAsAtUri(s: string): AtUri {
150150+ return s as AtUri
151151+}
152152+153153+export function unsafeAsNsid(s: string): Nsid {
154154+ return s as Nsid
155155+}
156156+157157+export function unsafeAsISODate(s: string): ISODateString {
158158+ return s as ISODateString
159159+}
160160+161161+export function unsafeAsEmail(s: string): EmailAddress {
162162+ return s as EmailAddress
163163+}
164164+165165+export function unsafeAsInviteCode(s: string): InviteCode {
166166+ return s as InviteCode
167167+}
168168+169169+export function unsafeAsPublicKeyMultibase(s: string): PublicKeyMultibase {
170170+ return s as PublicKeyMultibase
171171+}
172172+173173+export function unsafeAsDidKey(s: string): DidKeyString {
174174+ return s as DidKeyString
175175+}
176176+177177+export function parseAtUri(uri: AtUri): { repo: Did; collection: Nsid; rkey: Rkey } {
178178+ const parts = uri.replace('at://', '').split('/')
179179+ return {
180180+ repo: unsafeAsDid(parts[0]),
181181+ collection: unsafeAsNsid(parts[1]),
182182+ rkey: unsafeAsRkey(parts[2]),
183183+ }
184184+}
185185+186186+export function makeAtUri(repo: Did, collection: Nsid, rkey: Rkey): AtUri {
187187+ return `at://${repo}/${collection}/${rkey}` as AtUri
188188+}