@@ -18,25 +18,205 @@ package io.getstream.android.core.api.model
1818
1919import io.getstream.android.core.annotations.StreamPublishedApi
2020
21+ /* *
22+ * Represents a Configuration Identifier (CID) in the Stream platform.
23+ *
24+ * A CID uniquely identifies a resource by combining a configuration type and a resource ID in the
25+ * format `"configuration:identifier"`. This is the primary identifier used throughout the Stream
26+ * SDK for referencing various resources such as channels, calls, feeds, and other configuration
27+ * entities.
28+ *
29+ * ## Format
30+ *
31+ * CIDs follow the pattern: `"<configuration>:<identifier>"`
32+ * - **configuration**: The resource configuration type (e.g., "messaging", "livestream", "call",
33+ * "feed")
34+ * - **identifier**: The unique identifier for the resource within that configuration (e.g.,
35+ * "general", "support", "user-123")
36+ *
37+ * ## Examples
38+ *
39+ * ```kotlin
40+ * // Parse from formatted string
41+ * val cid1 = StreamCid.parse("messaging:general")
42+ * println(cid1.configuration) // "messaging"
43+ * println(cid1.id) // "general"
44+ * println(cid1.formatted()) // "messaging:general"
45+ *
46+ * // Create from configuration and id
47+ * val cid2 = StreamCid.fromTypeAndId("call", "video-room-1")
48+ * println(cid2.formatted()) // "call:video-room-1"
49+ *
50+ * // Different configuration types
51+ * val channelCid = StreamCid.parse("messaging:support")
52+ * val callCid = StreamCid.parse("call:team-meeting")
53+ * val feedCid = StreamCid.parse("feed:user-timeline")
54+ *
55+ * // Use in equality comparisons
56+ * val cid3 = StreamCid.parse("messaging:general")
57+ * println(cid1 == cid3) // true (data class equality)
58+ * ```
59+ *
60+ * ## Thread Safety
61+ *
62+ * This class is immutable and thread-safe. All instances are created via factory methods in the
63+ * companion object, and the constructor is private to enforce validation.
64+ *
65+ * ## Validation
66+ *
67+ * Both [configuration] and [id] must be non-empty strings. Attempting to create a CID with empty
68+ * values will throw [IllegalArgumentException].
69+ *
70+ * @property configuration The configuration type (non-empty, e.g., "messaging", "call", "feed")
71+ * @property id The resource identifier within the configuration (non-empty, e.g., "general",
72+ * "support")
73+ * @see parse Factory method for creating a CID from a formatted string
74+ * @see fromTypeAndId Factory method for creating a CID from separate configuration and id
75+ * components
76+ * @see formatted Returns the string representation in "configuration:id" format
77+ */
2178@ConsistentCopyVisibility
2279@StreamPublishedApi
23- public data class StreamCid private constructor(public val type : String , public val id : String ) {
80+ public data class StreamCid
81+ private constructor (
82+ /* *
83+ * The configuration type component of the CID.
84+ *
85+ * Common configuration types include:
86+ * - `"messaging"` - Messaging channels
87+ * - `"livestream"` - Live streaming channels
88+ * - `"call"` - Audio/video calls
89+ * - `"feed"` - Activity feeds
90+ * - `"team"` - Team collaboration
91+ *
92+ * This value is guaranteed to be non-empty.
93+ *
94+ * @see id The resource identifier component
95+ */
96+ public val configuration: String ,
97+ /* *
98+ * The unique identifier for the resource within its [configuration].
99+ *
100+ * This can be any non-empty string that uniquely identifies the resource within its
101+ * configuration type. Common patterns include:
102+ * - User IDs: `"user-123"`
103+ * - Resource names: `"general"`, `"support"`, `"random"`
104+ * - Generated IDs: `"ch-abc123"`, `UUID.randomUUID().toString()`
105+ *
106+ * This value is guaranteed to be non-empty.
107+ *
108+ * @see configuration The configuration type component
109+ */
110+ public val id: String ,
111+ ) {
24112
25113 public companion object {
26114
115+ /* *
116+ * Parses a formatted CID string into a [StreamCid] instance.
117+ *
118+ * This method parses a CID from its standard string representation `"configuration:id"` and
119+ * creates a [StreamCid] instance with the extracted configuration and id components.
120+ *
121+ * ## Format Requirements
122+ *
123+ * The input string must:
124+ * - Be non-empty
125+ * - Contain exactly one colon (`:`) separator
126+ * - Have non-empty configuration and id components on both sides of the colon
127+ *
128+ * ## Examples
129+ *
130+ * ```kotlin
131+ * // Valid CIDs
132+ * val cid1 = StreamCid.parse("messaging:general")
133+ * val cid2 = StreamCid.parse("livestream:sports-2023")
134+ * val cid3 = StreamCid.parse("call:team-meeting")
135+ *
136+ * // Invalid CIDs (will throw IllegalArgumentException)
137+ * StreamCid.parse("") // Empty string
138+ * StreamCid.parse("messaging") // Missing colon separator
139+ * StreamCid.parse("messaging:") // Empty id
140+ * StreamCid.parse(":general") // Empty configuration
141+ * StreamCid.parse("messaging:general:extra") // Too many colons
142+ * ```
143+ *
144+ * @param cid The formatted CID string in "configuration:id" format
145+ * @return A new [StreamCid] instance with the parsed configuration and id
146+ * @throws IllegalArgumentException if the input is empty, doesn't contain exactly one
147+ * colon, or has empty configuration/id components
148+ * @see fromTypeAndId Alternative factory method for creating from separate components
149+ * @see formatted Returns the inverse transformation (CID → String)
150+ */
27151 public fun parse (cid : String ): StreamCid {
28- require(cid.isNotEmpty())
152+ require(cid.isNotEmpty()) { " CID string cannot be empty " }
29153 val split = cid.split(" :" )
30- require(split.size == 2 )
31- return StreamCid (split[0 ], split[1 ])
154+ require(split.size == 2 ) {
155+ " CID must be in format 'configuration:id' with exactly one colon separator, got: '$cid '"
156+ }
157+ return fromTypeAndId(split[0 ], split[1 ])
32158 }
33159
160+ /* *
161+ * Creates a [StreamCid] from separate configuration and id components.
162+ *
163+ * This method constructs a CID directly from its constituent parts without requiring a
164+ * pre-formatted string. This is useful when you already have the configuration and id as
165+ * separate values.
166+ *
167+ * ## Examples
168+ *
169+ * ```kotlin
170+ * // Create CID from components
171+ * val cid = StreamCid.fromTypeAndId(type = "messaging", id = "general")
172+ * println(cid.formatted()) // "messaging:general"
173+ *
174+ * // Useful when building CIDs dynamically
175+ * val configurationType = "call"
176+ * val resourceId = UUID.randomUUID().toString()
177+ * val dynamicCid = StreamCid.fromTypeAndId(configurationType, resourceId)
178+ * ```
179+ *
180+ * @param type The configuration type (must be non-empty)
181+ * @param id The resource identifier (must be non-empty)
182+ * @return A new [StreamCid] instance with the given configuration and id
183+ * @throws IllegalArgumentException if either [type] or [id] is empty
184+ * @see parse Alternative factory method for parsing from formatted strings
185+ */
34186 public fun fromTypeAndId (type : String , id : String ): StreamCid {
35- require(type.isNotEmpty())
36- require(id.isNotEmpty())
187+ require(type.isNotEmpty()) { " Configuration type cannot be empty " }
188+ require(id.isNotEmpty()) { " Resource id cannot be empty " }
37189 return StreamCid (type, id)
38190 }
39191 }
40192
41- public fun formatted (): String = " $type :$id "
193+ /* *
194+ * Returns the formatted string representation of this CID.
195+ *
196+ * Converts the CID back to its canonical string format `"configuration:id"`. This is the
197+ * inverse operation of [parse].
198+ *
199+ * ## Examples
200+ *
201+ * ```kotlin
202+ * val cid = StreamCid.fromTypeAndId("messaging", "general")
203+ * println(cid.formatted()) // "messaging:general"
204+ *
205+ * // Round-trip parsing
206+ * val original = "livestream:sports"
207+ * val parsed = StreamCid.parse(original)
208+ * val formatted = parsed.formatted()
209+ * println(original == formatted) // true
210+ * ```
211+ *
212+ * ## Use Cases
213+ * - Logging and debugging: Display CIDs in human-readable format
214+ * - API requests: Send CID as string parameter to backend
215+ * - Serialization: Convert CID to JSON/XML string representation
216+ * - UI display: Show resource identifiers to users
217+ *
218+ * @return The CID in "configuration:id" format
219+ * @see parse The inverse operation that creates a CID from this string format
220+ */
221+ public fun formatted (): String = " $configuration :$id "
42222}
0 commit comments