This repository has no description
1import { ValueObject } from '../../../shared/domain/ValueObject';
2import { Result, ok, err } from '../../../shared/core/Result';
3import { DID } from './DID';
4
5export class InvalidATUriError extends Error {
6 constructor(message: string) {
7 super(message);
8 this.name = 'InvalidATUriError';
9 }
10}
11
12interface ATUriProps {
13 value: string;
14 did: DID;
15 collection: string;
16 rkey: string;
17}
18
19export class ATUri extends ValueObject<ATUriProps> {
20 get value(): string {
21 return this.props.value;
22 }
23
24 get did(): DID {
25 return this.props.did;
26 }
27
28 get collection(): string {
29 return this.props.collection;
30 }
31
32 get rkey(): string {
33 return this.props.rkey;
34 }
35
36 private constructor(props: ATUriProps) {
37 super(props);
38 }
39
40 public static create(uri: string): Result<ATUri, InvalidATUriError> {
41 if (!uri || uri.trim().length === 0) {
42 return err(new InvalidATUriError('AT URI cannot be empty'));
43 }
44
45 const trimmedUri = uri.trim();
46
47 if (!trimmedUri.startsWith('at://')) {
48 return err(new InvalidATUriError('AT URI must start with "at://"'));
49 }
50
51 const parts = trimmedUri.split('/');
52 if (parts.length !== 5) {
53 return err(
54 new InvalidATUriError(
55 'AT URI must have exactly 5 parts separated by "/"',
56 ),
57 );
58 }
59
60 const didResult = DID.create(parts[2]!);
61 if (didResult.isErr()) {
62 return err(
63 new InvalidATUriError(
64 `Invalid DID in AT URI: ${didResult.error.message}`,
65 ),
66 );
67 }
68
69 const collection = parts[3]!;
70 const rkey = parts[4]!;
71
72 if (!collection || collection.length === 0) {
73 return err(new InvalidATUriError('Collection cannot be empty'));
74 }
75
76 if (!rkey || rkey.length === 0) {
77 return err(new InvalidATUriError('Record key cannot be empty'));
78 }
79
80 return ok(
81 new ATUri({
82 value: trimmedUri,
83 did: didResult.value,
84 collection,
85 rkey,
86 }),
87 );
88 }
89
90 public static fromParts(
91 did: DID,
92 collection: string,
93 rkey: string,
94 ): Result<ATUri, InvalidATUriError> {
95 if (!collection || collection.length === 0) {
96 return err(new InvalidATUriError('Collection cannot be empty'));
97 }
98
99 if (!rkey || rkey.length === 0) {
100 return err(new InvalidATUriError('Record key cannot be empty'));
101 }
102
103 const uri = `at://${did.value}/${collection}/${rkey}`;
104
105 return ok(
106 new ATUri({
107 value: uri,
108 did,
109 collection,
110 rkey,
111 }),
112 );
113 }
114
115 public toString(): string {
116 return this.props.value;
117 }
118
119 public equals(other: ATUri): boolean {
120 return this.props.value === other.props.value;
121 }
122}