diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index e11691d..eb0ccaa 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -83,3 +83,8 @@ jobs: path: stream-android-core/build/reports/tests/testDebugUnitTest/index.html - uses: GetStream/android-ci-actions/actions/setup-ruby@main + + - name: Sonar + run: ./gradlew sonar + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c1cefed..bbb8209 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,9 +1,21 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.compose) } +kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_11) + freeCompilerArgs.addAll( + "-opt-in=io.getstream.android.core.annotations.StreamInternalApi", + "-XXLanguage:+PropertyParamAnnotationDefaultTargetMode" + ) + } +} + android { namespace = "io.getstream.android.core" compileSdk = 36 @@ -42,6 +54,7 @@ android { dependencies { implementation(project(":stream-android-core")) + implementation(project(":stream-android-core-annotations")) implementation(libs.androidx.core.ktx) implementation(libs.androidx.appcompat) diff --git a/buildSrc/src/main/kotlin/io/getstream/core/Configuration.kt b/buildSrc/src/main/kotlin/io/getstream/core/Configuration.kt index fee1e76..3f415bd 100644 --- a/buildSrc/src/main/kotlin/io/getstream/core/Configuration.kt +++ b/buildSrc/src/main/kotlin/io/getstream/core/Configuration.kt @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://github.com/GetStream/stream-feeds-android/blob/main/LICENSE + * https://github.com/GetStream/stream-core-android/blob/main/LICENSE * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/lint.xml b/lint.xml index 2c7b502..82addf1 100644 --- a/lint.xml +++ b/lint.xml @@ -8,8 +8,7 @@ - + diff --git a/stream-android-core-annotations/src/main/java/io/getstream/android/core/annotations/StreamApiMarkers.kt b/stream-android-core-annotations/src/main/java/io/getstream/android/core/annotations/StreamApiMarkers.kt index c64e6d8..3cc74f5 100644 --- a/stream-android-core-annotations/src/main/java/io/getstream/android/core/annotations/StreamApiMarkers.kt +++ b/stream-android-core-annotations/src/main/java/io/getstream/android/core/annotations/StreamApiMarkers.kt @@ -88,15 +88,9 @@ annotation class StreamInternalApi annotation class StreamDelicateApi(val message: String) /** - * Marks APIs that are part of the **Stream Core SDK layer**. - * - * These APIs are primarily intended for **internal use within Stream SDKs** (e.g. video, chat, or - * other verticals) and are not considered public surface APIs. - * - * While they may be accessible, external usage is **discouraged** because: - * - Support will typically focus on higher-level, public APIs instead. - * - A vertical can upgrade to a major version of Stream core that may no longer have or support - * this api. + * Marks APIs that are part of the **Stream core SDK layer**. This API can be safely published and + * used by other Stream SDKs. They can also be propagated and exposed via public APIs of the product + * SDKs. */ @Target( AnnotationTarget.CLASS, @@ -106,10 +100,4 @@ annotation class StreamDelicateApi(val message: String) AnnotationTarget.TYPEALIAS, ) @Retention(AnnotationRetention.BINARY) -@RequiresOptIn( - message = - "Stream Core SDK API – intended for use only within the Stream SDK core. " + - "External usage is discouraged and may not be supported.", - level = RequiresOptIn.Level.ERROR, -) -annotation class StreamCoreApi +annotation class StreamPublishedApi diff --git a/stream-android-core-lint/src/main/java/io/getstream/android/core/lint/StreamIssueRegistry.kt b/stream-android-core-lint/src/main/java/io/getstream/android/core/lint/StreamIssueRegistry.kt index 1bcfc1b..ed45173 100644 --- a/stream-android-core-lint/src/main/java/io/getstream/android/core/lint/StreamIssueRegistry.kt +++ b/stream-android-core-lint/src/main/java/io/getstream/android/core/lint/StreamIssueRegistry.kt @@ -22,7 +22,7 @@ import com.android.tools.lint.detector.api.Issue import io.getstream.android.core.lint.detectors.ExposeAsStateFlowDetector import io.getstream.android.core.lint.detectors.KeepInstanceDetector import io.getstream.android.core.lint.detectors.MustBeInternalDetector -import io.getstream.android.core.lint.detectors.StreamCoreApiDetector +import io.getstream.android.core.lint.detectors.StreamApiExplicitMarkerDetector import io.getstream.android.core.lint.detectors.SuspendRunCatchingDetector /** The stream lint rules registry. */ @@ -34,7 +34,7 @@ class StreamIssueRegistry : IssueRegistry() { KeepInstanceDetector.ISSUE, SuspendRunCatchingDetector.ISSUE, ExposeAsStateFlowDetector.ISSUE, - StreamCoreApiDetector.ISSUE, + StreamApiExplicitMarkerDetector.ISSUE, ) override val vendor = diff --git a/stream-android-core-lint/src/main/java/io/getstream/android/core/lint/detectors/StreamApiExplicitMarkerDetector.kt b/stream-android-core-lint/src/main/java/io/getstream/android/core/lint/detectors/StreamApiExplicitMarkerDetector.kt new file mode 100644 index 0000000..aab2e20 --- /dev/null +++ b/stream-android-core-lint/src/main/java/io/getstream/android/core/lint/detectors/StreamApiExplicitMarkerDetector.kt @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2014-2025 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-core-android/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.getstream.android.core.lint.detectors + +import com.android.tools.lint.client.api.UElementHandler +import com.android.tools.lint.detector.api.* +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.uast.* + +class StreamApiExplicitMarkerDetector : Detector(), Detector.UastScanner { + + override fun getApplicableUastTypes() = + listOf(UClass::class.java, UMethod::class.java, UField::class.java, UFile::class.java) + + override fun createUastHandler(context: JavaContext) = + object : UElementHandler() { + override fun visitClass(node: UClass) { + val uFile = node.getContainingUFileOrNull() ?: return + if (!context.packageMatchesConfig(uFile.packageName)) return + checkUAnnotated(context, node, node.sourcePsi as? KtDeclaration) + } + + override fun visitMethod(node: UMethod) { + val uFile = node.getContainingUFileOrNull() ?: return + if (!context.packageMatchesConfig(uFile.packageName)) return + checkUAnnotated(context, node, node.sourcePsi as? KtNamedFunction) + } + + override fun visitField(node: UField) { + val uFile = node.getContainingUFileOrNull() ?: return + if (!context.packageMatchesConfig(uFile.packageName)) return + checkUAnnotated(context, node, node.sourcePsi as? KtProperty) + } + + override fun visitFile(node: UFile) { + val ktFile = node.sourcePsi as? KtFile ?: return + val pkg = ktFile.packageFqName.asString() + if (!context.packageMatchesConfig(pkg)) return + ktFile.declarations.filterIsInstance().forEach { alias -> + checkTypeAlias(context, alias) + } + } + } + + private fun checkUAnnotated(context: JavaContext, u: UElement, kt: KtDeclaration?) { + kt ?: return + if (!kt.isTopLevelPublic()) return + val annotated = (u as? UAnnotated)?.hasAnyAnnotation(MARKERS) ?: false + if (annotated) return + reportWithDualFix(context, u, kt) + } + + private fun checkTypeAlias(context: JavaContext, alias: KtTypeAlias) { + if (!alias.isTopLevelPublic()) return + val annotated = alias.hasAnyAnnotationPsi(MARKERS_SIMPLE) + if (annotated) return + reportWithDualFix(context, alias, alias) + } + + private fun reportWithDualFix(context: JavaContext, node: KtTypeAlias, decl: KtDeclaration) { + val loc = context.getLocation(decl) + val fixPublished = + LintFix.create() + .name("Annotate with @$PUBLISHED_SIMPLE") + .replace() + .range(loc) + .pattern("^") + .with("@$PUBLISHED_FQ\n") + .reformat(true) + .shortenNames() + .autoFix() + .build() + val fixInternal = + LintFix.create() + .name("Annotate with @$INTERNAL_SIMPLE") + .replace() + .range(loc) + .pattern("^") + .with("@$INTERNAL_FQ\n") + .reformat(true) + .shortenNames() + .autoFix() + .build() + + context.report( + ISSUE, + node, + loc, + "Public API must be explicitly marked with @$PUBLISHED_SIMPLE or @$INTERNAL_SIMPLE.", + LintFix.create().group(fixPublished, fixInternal), + ) + } + + private fun reportWithDualFix(context: JavaContext, node: UElement, decl: KtDeclaration) { + val loc = context.getLocation(decl) + val fixPublished = + LintFix.create() + .name("Annotate with @$PUBLISHED_SIMPLE") + .replace() + .range(loc) + .pattern("^") + .with("@$PUBLISHED_FQ\n") + .reformat(true) + .shortenNames() + .autoFix() + .build() + val fixInternal = + LintFix.create() + .name("Annotate with @$INTERNAL_SIMPLE") + .replace() + .range(loc) + .pattern("^") + .with("@$INTERNAL_FQ\n") + .reformat(true) + .shortenNames() + .autoFix() + .build() + + context.report( + ISSUE, + node, + loc, + "Public API must be explicitly marked with @$PUBLISHED_SIMPLE or @$INTERNAL_SIMPLE.", + LintFix.create().group(fixPublished, fixInternal), + ) + } + + // ----- package filtering helpers ----- + + private fun JavaContext.packageMatchesConfig(pkg: String): Boolean { + val patterns = configuredPackageGlobs() + + // Default if not configured → only io.getstream.android.core.* + val effectivePatterns = patterns.ifEmpty { listOf("io.getstream.android.core.api") } + + val included = effectivePatterns.any { pkgMatchesGlob(pkg, it) } + val excluded = packageMatchesExcludeConfig(pkg) + return included && !excluded + } + + private fun JavaContext.packageMatchesExcludeConfig(pkg: String): Boolean { + val raw = configuration.getOption(ISSUE, OPTION_PACKAGES_EXCLUDE.name, "")?.trim().orEmpty() + if (raw.isEmpty()) return false + val patterns = raw.split(',').map { it.trim() }.filter { it.isNotEmpty() } + return patterns.any { pkgMatchesGlob(pkg, it) } + } + + private fun JavaContext.configuredPackageGlobs(): List { + val raw = configuration.getOption(ISSUE, OPTION_PACKAGES.name, "")?.trim().orEmpty() + if (raw.isEmpty()) return emptyList() + return raw.split(',').map { it.trim() }.filter { it.isNotEmpty() } + } + + /** Simple glob matcher: `*` → `.*`, `?` → `.`, dot escaped; anchored. */ + private fun pkgMatchesGlob(pkg: String, glob: String): Boolean = globToRegex(glob).matches(pkg) + + private fun globToRegex(glob: String): Regex { + val sb = StringBuilder("^") + for (ch in glob) { + when (ch) { + '*' -> sb.append(".*") + '?' -> sb.append('.') + '.' -> sb.append("\\.") + else -> sb.append(Regex.escape(ch.toString())) + } + } + sb.append('$') + return sb.toString().toRegex() + } + + // ----- misc helpers ----- + + private fun UAnnotated.hasAnyAnnotation(qns: Set) = + qns.any { findAnnotation(it) != null || findAnnotation(it.substringAfterLast('.')) != null } + + private fun KtAnnotated.hasAnyAnnotationPsi(simpleNames: Set): Boolean = + annotationEntries.any { entry -> + entry.shortName?.asString() in simpleNames || + entry.typeReference?.text in simpleNames // handles rare fully-qualified usage + } + + private fun UElement.getContainingUFileOrNull(): UFile? { + var cur: UElement? = this + while (cur != null) { + if (cur is UFile) return cur + cur = cur.uastParent + } + return null + } + + private fun KtDeclaration.isTopLevelPublic(): Boolean { + if (parent !is KtFile) return false + val mods = modifierList + val isPublic = + mods?.hasModifier(KtTokens.PUBLIC_KEYWORD) == true || + !(mods?.hasModifier(KtTokens.PRIVATE_KEYWORD) == true || + mods?.hasModifier(KtTokens.PROTECTED_KEYWORD) == true || + mods?.hasModifier(KtTokens.INTERNAL_KEYWORD) == true) + return isPublic + } + + companion object { + private const val PUBLISHED_FQ = "io.getstream.android.core.annotations.StreamPublishedApi" + private const val PUBLISHED_SIMPLE = "StreamPublishedApi" + private const val INTERNAL_FQ = "io.getstream.android.core.annotations.StreamInternalApi" + private const val INTERNAL_SIMPLE = "StreamInternalApi" + private val MARKERS = setOf(PUBLISHED_FQ, INTERNAL_FQ) + private val MARKERS_SIMPLE = setOf(PUBLISHED_SIMPLE, INTERNAL_SIMPLE) + + private val OPTION_PACKAGES = + StringOption( + name = "packages", + description = "Comma-separated package **glob** patterns where the rule applies.", + explanation = + """ + Supports wildcards: '*' (any sequence) and '?' (single char). + Examples: + - 'io.getstream.android.core.api' + - 'io.getstream.android.core.*.api' + - 'io.getstream.android.*' + """ + .trimIndent(), + ) + + private val OPTION_PACKAGES_EXCLUDE = + StringOption( + name = "exclude_packages", + description = "Comma-separated package **glob** patterns to exclude from the rule.", + explanation = + """ + Same glob syntax as 'packages'. Evaluated after includes. + """ + .trimIndent(), + ) + + private val IMPLEMENTATION = + Implementation(StreamApiExplicitMarkerDetector::class.java, Scope.JAVA_FILE_SCOPE) + + @JvmField + val ISSUE: Issue = + Issue.create( + "StreamApiExplicitMarkerMissing", + "Public API must be explicitly marked", + """ + To prevent accidental exposure, all top-level public declarations must be explicitly \ + marked as @StreamPublishedApi (allowed to leak) or @StreamInternalApi (not allowed to leak). + """ + .trimIndent(), + Category.CORRECTNESS, + 7, + Severity.ERROR, + IMPLEMENTATION, + ) + .setOptions(listOf(OPTION_PACKAGES, OPTION_PACKAGES_EXCLUDE)) + } +} diff --git a/stream-android-core-lint/src/main/java/io/getstream/android/core/lint/detectors/StreamCoreApiDetector.kt b/stream-android-core-lint/src/main/java/io/getstream/android/core/lint/detectors/StreamCoreApiDetector.kt deleted file mode 100644 index e8f94f3..0000000 --- a/stream-android-core-lint/src/main/java/io/getstream/android/core/lint/detectors/StreamCoreApiDetector.kt +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2014-2025 Stream.io Inc. All rights reserved. - * - * Licensed under the Stream License; - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://github.com/GetStream/stream-core-android/blob/main/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.getstream.android.core.lint.detectors - -import com.android.tools.lint.client.api.UElementHandler -import com.android.tools.lint.detector.api.Category -import com.android.tools.lint.detector.api.Detector -import com.android.tools.lint.detector.api.Implementation -import com.android.tools.lint.detector.api.Issue -import com.android.tools.lint.detector.api.JavaContext -import com.android.tools.lint.detector.api.LintFix -import com.android.tools.lint.detector.api.Scope -import com.android.tools.lint.detector.api.Severity -import com.android.tools.lint.detector.api.StringOption -import com.android.tools.lint.detector.api.TextFormat -import kotlin.text.iterator -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.psi.KtClass -import org.jetbrains.kotlin.psi.KtClassOrObject -import org.jetbrains.kotlin.psi.KtNamedFunction -import org.jetbrains.kotlin.psi.KtObjectDeclaration -import org.jetbrains.kotlin.psi.KtProperty -import org.jetbrains.uast.UAnnotated -import org.jetbrains.uast.UClass -import org.jetbrains.uast.UElement -import org.jetbrains.uast.UField -import org.jetbrains.uast.UFile -import org.jetbrains.uast.UMethod - -/** - * Flags any **top-level public** declaration in configured packages that is **not annotated** - * with @StreamCoreApi. - * - * Config: - */ -class StreamCoreApiDetector : Detector(), Detector.UastScanner { - override fun getApplicableUastTypes(): List> = - listOf(UClass::class.java, UMethod::class.java, UField::class.java) - - override fun createUastHandler(context: JavaContext): UElementHandler = - object : UElementHandler() { - override fun visitClass(node: UClass) { - // Only top-level declarations - val uFile = node.uastParent as? UFile ?: return - if (!context.packageMatchesConfig(uFile.packageName)) return - - val kt = node.sourcePsi as? KtClassOrObject ?: return - if (!kt.isTopLevel()) return - if (!kt.isPublicTopLevel()) return - if (node.isAnnotatedWithCoreApi()) return - - reportMissingCoreApi(context, node, kt, declKeyword(kt)) - } - - override fun visitMethod(node: UMethod) { - val uFile = node.getContainingUFileOrNull() ?: return - if (!context.packageMatchesConfig(uFile.packageName)) return - - val kt = node.sourcePsi as? KtNamedFunction ?: return - if (!kt.isTopLevel) return - if (!kt.isPublicTopLevel()) return - if ((node as UAnnotated).isAnnotatedWithCoreApi()) return - - reportMissingCoreApi(context, node, kt, "fun") - } - - override fun visitField(node: UField) { - val uFile = node.getContainingUFileOrNull() ?: return - if (!context.packageMatchesConfig(uFile.packageName)) return - - val kt = node.sourcePsi as? KtProperty ?: return - if (!kt.isTopLevel) return - if (!kt.isPublicTopLevel()) return - if ((node as UAnnotated).isAnnotatedWithCoreApi()) return - - val keyword = if (kt.isVar) "var" else "val" - reportMissingCoreApi(context, node, kt, keyword) - } - } - - // ----- Reporting & Fix ----- - - private fun reportMissingCoreApi( - context: JavaContext, - node: UElement, - psiDecl: org.jetbrains.kotlin.psi.KtDeclaration, - declKeyword: String, - ) { - val explanation = ISSUE.getExplanation(TextFormat.TEXT) - val declLocation = context.getLocation(psiDecl) - - // Insert the FQ annotation and let Lint shorten the import automatically. - val fix = - LintFix.create() - .name("Annotate with @StreamCoreApi") - .replace() - .range(declLocation) - // Prepend the annotation at the very start of the declaration text - .pattern("^") - .with("@$CORE_API_FQ\n") - .reformat(true) - .shortenNames() - .autoFix() - .build() - - context.report(ISSUE, node, declLocation, explanation, fix) - } - - // ----- Helpers ----- - - private fun JavaContext.packageMatchesConfig(pkg: String): Boolean { - val patterns = configuredPackageGlobs() - if (patterns.isEmpty()) return false - val included = patterns.any { pkgMatchesGlob(pkg, it) } - val excluded = packageMatchesExcludeConfig(pkg) - return included && !excluded - } - - private fun JavaContext.packageMatchesExcludeConfig(pkg: String): Boolean { - val raw = configuration.getOption(ISSUE, OPTION_PACKAGES_EXCLUDE.name, "")?.trim().orEmpty() - if (raw.isEmpty()) return false - val patterns = raw.split(',').map { it.trim() }.filter { it.isNotEmpty() } - if (patterns.isEmpty()) return false - return patterns.any { pkgMatchesGlob(pkg, it) } - } - - private fun JavaContext.configuredPackageGlobs(): List { - val raw = configuration.getOption(ISSUE, OPTION_PACKAGES.name, "")?.trim().orEmpty() - if (raw.isEmpty()) return emptyList() - return raw.split(',').map { it.trim() }.filter { it.isNotEmpty() } - } - - /** Simple glob matcher: `*` → `.*`, `?` → `.`, dot is escaped; anchored. */ - private fun pkgMatchesGlob(pkg: String, glob: String): Boolean = globToRegex(glob).matches(pkg) - - private fun globToRegex(glob: String): Regex { - val sb = StringBuilder("^") - for (ch in glob) { - when (ch) { - '*' -> sb.append(".*") - '?' -> sb.append('.') - '.' -> sb.append("\\.") - else -> sb.append(Regex.escape(ch.toString())) - } - } - sb.append('$') - return sb.toString().toRegex() - } - - private fun UAnnotated.isAnnotatedWithCoreApi(): Boolean = - findAnnotation(CORE_API_FQ) != null || findAnnotation(CORE_API_SIMPLE) != null - - private fun UMethod.getContainingUFileOrNull(): UFile? { - var cur: UElement? = this - while (cur != null) { - if (cur is UFile) return cur - cur = cur.uastParent - } - return null - } - - private fun UField.getContainingUFileOrNull(): UFile? { - var cur: UElement? = this - while (cur != null) { - if (cur is UFile) return cur - cur = cur.uastParent - } - return null - } - - private fun KtClassOrObject.isTopLevel(): Boolean = - this.parent is org.jetbrains.kotlin.psi.KtFile - - private fun org.jetbrains.kotlin.psi.KtDeclaration.isPublicTopLevel(): Boolean { - // top-level: public if no visibility modifier or explicit `public` - val isPublic = - hasModifier(KtTokens.PUBLIC_KEYWORD) || - (!hasModifier(KtTokens.INTERNAL_KEYWORD) && - !hasModifier(KtTokens.PRIVATE_KEYWORD) && - !hasModifier(KtTokens.PROTECTED_KEYWORD)) - return isPublic - } - - private fun declKeyword(kt: KtClassOrObject): String = - when (kt) { - is KtClass -> - when { - kt.isInterface() -> "interface" - kt.isEnum() -> "enum class" - else -> "class" - } - - is KtObjectDeclaration -> "object" - else -> "class" - } - - companion object { - private const val CORE_API_FQ = "io.getstream.android.core.annotations.StreamCoreApi" - private const val CORE_API_SIMPLE = "StreamCoreApi" - - private val IMPLEMENTATION = - Implementation(StreamCoreApiDetector::class.java, Scope.JAVA_FILE_SCOPE) - - private val OPTION_PACKAGES = - StringOption( - name = "packages", - description = - "Comma-separated package **glob** patterns where top-level public APIs must be annotated with @StreamCoreApi.", - explanation = - """ - Supports wildcards: '*' (any sequence) and '?' (single char). - Examples: - - 'io.getstream.android.core.api' - - 'io.getstream.android.core.*.api' - - 'io.getstream.android.core.api*' - """ - .trimIndent(), - ) - - private val OPTION_PACKAGES_EXCLUDE = - StringOption( - name = "exclude_packages", - description = - "Comma-separated package **glob** patterns where top-level public APIs are excluded from the check.", - explanation = - """ - Supports wildcards: '*' (any sequence) and '?' (single char). - Examples: - - 'io.getstream.android.core.api' - - 'io.getstream.android.core.*.api' - - 'io.getstream.android.core.api*' - """ - .trimIndent(), - ) - - @JvmField - val ISSUE: Issue = - Issue.create( - id = "StreamCoreApiMissing", - briefDescription = "Missing @StreamCoreApi on public API", - explanation = - """ - Top-level public declarations in configured packages must be annotated \ - with @StreamCoreApi to indicate they are part of the Stream Core API surface. - """ - .trimIndent(), - category = Category.CORRECTNESS, - priority = 7, - severity = Severity.ERROR, - implementation = IMPLEMENTATION, - ) - .setOptions(listOf(OPTION_PACKAGES, OPTION_PACKAGES_EXCLUDE)) - } -} diff --git a/stream-android-core/build.gradle.kts b/stream-android-core/build.gradle.kts index 08d945d..83bffe4 100644 --- a/stream-android-core/build.gradle.kts +++ b/stream-android-core/build.gradle.kts @@ -1,5 +1,8 @@ +@file:OptIn(ExperimentalAbiValidation::class) + import org.jetbrains.kotlin.gradle.dsl.JvmTarget import io.getstream.core.Configuration +import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation plugins { alias(libs.plugins.android.library) @@ -19,10 +22,12 @@ rootProject.extra.apply { apply(from = "${rootDir}/scripts/publish-module.gradle") kotlin { + explicitApi() compilerOptions { jvmTarget.set(JvmTarget.JVM_11) freeCompilerArgs.addAll( - "-opt-in=io.getstream.android.core.annotations.StreamCoreApi", "-XXLanguage:+PropertyParamAnnotationDefaultTargetMode" + "-opt-in=io.getstream.android.core.annotations.StreamInternalApi", + "-XXLanguage:+PropertyParamAnnotationDefaultTargetMode" ) } } diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/StreamClient.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/StreamClient.kt index 21f1e66..d4d2868 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/StreamClient.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/StreamClient.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.authentication.StreamTokenManager import io.getstream.android.core.api.authentication.StreamTokenProvider import io.getstream.android.core.api.http.StreamOkHttpInterceptors @@ -96,8 +96,8 @@ import kotlinx.coroutines.flow.StateFlow * client.disconnect() * ``` */ -@StreamCoreApi -interface StreamClient { +@StreamInternalApi +public interface StreamClient { /** * Read-only, hot state holder for this client. * @@ -105,7 +105,7 @@ interface StreamClient { * - Emits connection status changes (e.g., connecting/connected/disconnected). * - Hot & conflated: new collectors receive the latest value immediately. */ - val connectionState: StateFlow + public val connectionState: StateFlow /** * Establishes a connection for the current user. @@ -117,7 +117,7 @@ interface StreamClient { * **Cancellation** * - Throws [kotlinx.coroutines.CancellationException] if the awaiting coroutine is cancelled. */ - suspend fun connect(): Result + public suspend fun connect(): Result /** * Terminates the active connection and releases related resources. @@ -129,14 +129,14 @@ interface StreamClient { * **Cancellation** * - Throws [kotlinx.coroutines.CancellationException] if the awaiting coroutine is cancelled. */ - suspend fun disconnect(): Result + public suspend fun disconnect(): Result /** * Subscribes to client events and state * * @param listener The listener to subscribe. */ - fun subscribe(listener: StreamClientListener): Result + public fun subscribe(listener: StreamClientListener): Result } /** @@ -199,8 +199,8 @@ interface StreamClient { * @param healthMonitor The health monitor. * @param batcher The WebSocket event batcher. */ -@StreamCoreApi -fun StreamClient( +@StreamInternalApi +public fun StreamClient( // Client config apiKey: StreamApiKey, userId: StreamUserId, diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/authentication/StreamTokenManager.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/authentication/StreamTokenManager.kt index d872b3e..6e7506a 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/authentication/StreamTokenManager.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/authentication/StreamTokenManager.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.authentication -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.model.value.StreamToken import io.getstream.android.core.api.model.value.StreamUserId import io.getstream.android.core.api.processing.StreamSingleFlightProcessor @@ -49,15 +49,15 @@ import kotlinx.coroutines.flow.StateFlow * tokenManager.token.value // null * ``` */ -@StreamCoreApi -interface StreamTokenManager { +@StreamInternalApi +public interface StreamTokenManager { /** * A hot stream of the current authentication token. * * Emits `null` when there is no token (e.g., before the first load or after [invalidate] is * called) and updates with each successful set or refresh. */ - val token: StateFlow + public val token: StateFlow /** * Registers the provider used to load tokens on demand. @@ -69,7 +69,7 @@ interface StreamTokenManager { * @return [Result.success] on success, or [Result.failure] if the provider cannot be installed * in the current state. */ - fun setProvider(provider: StreamTokenProvider): Result + public fun setProvider(provider: StreamTokenProvider): Result /** * Sets the current token explicitly. @@ -81,7 +81,7 @@ interface StreamTokenManager { * @return [Result.success] on success, or [Result.failure] if the token is rejected by the * implementation (e.g., invalid format). */ - fun setToken(token: StreamToken): Result + public fun setToken(token: StreamToken): Result /** * Invalidates and clears the current token. @@ -92,7 +92,7 @@ interface StreamTokenManager { * @return [Result.success] on success, or [Result.failure] if the token cannot be invalidated * in the current state. */ - fun invalidate(): Result + public fun invalidate(): Result /** * Ensures that a valid token is available. @@ -103,14 +103,14 @@ interface StreamTokenManager { * @return [Result.success] containing the token, or [Result.failure] if no token is available * and fetching failed. */ - suspend fun loadIfAbsent(): Result + public suspend fun loadIfAbsent(): Result /** * Refreshes the current token from the provider. * * @return [Result.success] containing the token, or [Result.failure] if fetching failed. */ - suspend fun refresh(): Result + public suspend fun refresh(): Result } /** @@ -121,8 +121,8 @@ interface StreamTokenManager { * @param singleFlight The single-flight processor used to coordinate concurrent requests. * @return A new [StreamTokenManager] instance. */ -@StreamCoreApi -fun StreamTokenManager( +@StreamInternalApi +public fun StreamTokenManager( userId: StreamUserId, tokenProvider: StreamTokenProvider, singleFlight: StreamSingleFlightProcessor, diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/authentication/StreamTokenProvider.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/authentication/StreamTokenProvider.kt index 1530459..85633b2 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/authentication/StreamTokenProvider.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/authentication/StreamTokenProvider.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.authentication -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamPublishedApi import io.getstream.android.core.api.model.value.StreamToken import io.getstream.android.core.api.model.value.StreamUserId @@ -52,8 +52,8 @@ import io.getstream.android.core.api.model.value.StreamUserId * - Token creation/rotation must happen on your server. * - Prefer short expirations and refresh on demand. */ -@StreamCoreApi -fun interface StreamTokenProvider { +@StreamPublishedApi +public fun interface StreamTokenProvider { /** * Returns a JWT that authenticates the given [userId]. * @@ -67,5 +67,5 @@ fun interface StreamTokenProvider { * @throws Exception If the token cannot be obtained (network error, server error, invalid user, * etc.). */ - suspend fun loadToken(userId: StreamUserId): StreamToken + public suspend fun loadToken(userId: StreamUserId): StreamToken } diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/http/StreamOkHttpInterceptors.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/http/StreamOkHttpInterceptors.kt index d9cdefd..0e99d6b 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/http/StreamOkHttpInterceptors.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/http/StreamOkHttpInterceptors.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.http -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.authentication.StreamTokenManager import io.getstream.android.core.api.model.value.StreamApiKey import io.getstream.android.core.api.model.value.StreamHttpClientInfoHeader @@ -28,8 +28,6 @@ import io.getstream.android.core.internal.http.interceptor.StreamConnectionIdInt import io.getstream.android.core.internal.http.interceptor.StreamEndpointErrorInterceptor import okhttp3.Interceptor -// TODO: Think about better approach - /** * Provides a set of OkHttp interceptors for use with the Stream SDKs. * @@ -37,8 +35,8 @@ import okhttp3.Interceptor * @see [StreamConnectionIdInterceptor] * @see [StreamApiKeyInterceptor] */ -@StreamCoreApi -object StreamOkHttpInterceptors { +@StreamInternalApi +public object StreamOkHttpInterceptors { /** * Creates an OkHttp interceptor that adds authentication headers and retries on token errors. * @@ -47,7 +45,7 @@ object StreamOkHttpInterceptors { * @param jsonParser JSON parser used to decode error payloads when requests fail. * @return An OkHttp interceptor. */ - fun auth( + public fun auth( authType: String, tokenManager: StreamTokenManager, jsonParser: StreamJsonSerialization, @@ -59,7 +57,7 @@ object StreamOkHttpInterceptors { * @param connectionIdHolder The holder that provides the connection ID. * @return An OkHttp interceptor. */ - fun connectionId(connectionIdHolder: StreamConnectionIdHolder): Interceptor = + public fun connectionId(connectionIdHolder: StreamConnectionIdHolder): Interceptor = StreamConnectionIdInterceptor(connectionIdHolder) /** @@ -68,7 +66,7 @@ object StreamOkHttpInterceptors { * @param clientInfoHeader The client info header to add. * @return An OkHttp interceptor. */ - fun clientInfo(clientInfoHeader: StreamHttpClientInfoHeader): Interceptor = + public fun clientInfo(clientInfoHeader: StreamHttpClientInfoHeader): Interceptor = StreamClientInfoInterceptor(clientInfoHeader) /** @@ -78,7 +76,7 @@ object StreamOkHttpInterceptors { * @param apiKey The API key to add. * @return An OkHttp interceptor. */ - fun apiKey(apiKey: StreamApiKey): Interceptor = StreamApiKeyInterceptor(apiKey) + public fun apiKey(apiKey: StreamApiKey): Interceptor = StreamApiKeyInterceptor(apiKey) /** * Creates an OkHttp interceptor that parses and throws @@ -87,6 +85,6 @@ object StreamOkHttpInterceptors { * @param jsonParser JSON parser used to decode error payloads when requests fail. * @return An OkHttp interceptor. */ - fun error(jsonParser: StreamJsonSerialization): Interceptor = + public fun error(jsonParser: StreamJsonSerialization): Interceptor = StreamEndpointErrorInterceptor(jsonParser) } diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/log/StreamLogger.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/log/StreamLogger.kt index 17c6e03..a363515 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/log/StreamLogger.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/log/StreamLogger.kt @@ -15,40 +15,40 @@ */ package io.getstream.android.core.api.log -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi /** * Defines a logging contract for the Stream SDK. * * Implementations of this interface provide a way to log messages and exceptions at different * severity levels. By default, convenience functions are provided for each log level (e.g., [d], - * [e], [i], [w], [v], [wtf]). + * [e], [i], [w], [v]). * * @see StreamLoggerProvider for the global logger accessor. */ -@StreamCoreApi -interface StreamLogger { +@StreamInternalApi +public interface StreamLogger { /** * Represents the severity of a log message. * * @property level The integer value of the severity, where higher numbers represent more severe * log levels. */ - sealed class LogLevel(val level: Int) { + public sealed class LogLevel(public val level: Int) { /** Verbose log messages, typically for detailed debugging. */ - object Verbose : LogLevel(1) + public object Verbose : LogLevel(1) /** Debug log messages, used for general debugging. */ - object Debug : LogLevel(2) + public object Debug : LogLevel(2) /** Informational log messages, representing normal operation. */ - object Info : LogLevel(3) + public object Info : LogLevel(3) /** Warning log messages, representing non-fatal issues. */ - object Warning : LogLevel(4) + public object Warning : LogLevel(4) /** Error log messages, representing recoverable failures. */ - object Error : LogLevel(5) + public object Error : LogLevel(5) } /** @@ -56,14 +56,14 @@ interface StreamLogger { * * @param message A lambda returning the message to log. */ - fun d(message: () -> String) = log(LogLevel.Debug, null, message) + public fun d(message: () -> String): Unit = log(LogLevel.Debug, null, message) /** * Logs an error message. * * @param message A lambda returning the message to log. */ - fun e(message: () -> String) = log(LogLevel.Error, null, message) + public fun e(message: () -> String): Unit = log(LogLevel.Error, null, message) /** * Logs an error with an optional message. @@ -71,7 +71,7 @@ interface StreamLogger { * @param throwable The error or exception to log. * @param message An optional lambda returning a message to include. */ - fun e(throwable: Throwable, message: (() -> String)?) = + public fun e(throwable: Throwable, message: (() -> String)?): Unit = log(LogLevel.Error, throwable) { message?.invoke() ?: "${throwable.message}" } /** @@ -79,21 +79,21 @@ interface StreamLogger { * * @param message A lambda returning the message to log. */ - fun w(message: () -> String) = log(LogLevel.Warning, null, message) + public fun w(message: () -> String): Unit = log(LogLevel.Warning, null, message) /** * Logs an informational message. * * @param message A lambda returning the message to log. */ - fun i(message: () -> String) = log(LogLevel.Info, null, message) + public fun i(message: () -> String): Unit = log(LogLevel.Info, null, message) /** * Logs a verbose message. * * @param message A lambda returning the message to log. */ - fun v(message: () -> String) = log(LogLevel.Verbose, null, message) + public fun v(message: () -> String): Unit = log(LogLevel.Verbose, null, message) /** * Logs a message at the given severity level. @@ -102,5 +102,5 @@ interface StreamLogger { * @param throwable An optional [Throwable] associated with the log message. * @param message A lambda returning the message to log. */ - fun log(level: LogLevel, throwable: Throwable?, message: () -> String) + public fun log(level: LogLevel, throwable: Throwable?, message: () -> String) } diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/log/StreamLoggerProvider.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/log/StreamLoggerProvider.kt index d370d4d..1e8e649 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/log/StreamLoggerProvider.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/log/StreamLoggerProvider.kt @@ -16,7 +16,7 @@ package io.getstream.android.core.api.log import android.util.Log -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import kotlin.coroutines.cancellation.CancellationException import kotlin.math.min @@ -26,17 +26,17 @@ import kotlin.math.min * Implementations decide how loggers are created for specific tags and how log messages are * emitted. */ -@StreamCoreApi -interface StreamLoggerProvider { +@StreamInternalApi +public interface StreamLoggerProvider { /** * Creates a [StreamLogger] instance associated with the given tag. * * @param tag The tag to identify log messages. Typically corresponds to a class or module name. * @return A [StreamLogger] that will emit log messages using the given tag. */ - fun taggedLogger(tag: String): StreamLogger + public fun taggedLogger(tag: String): StreamLogger - companion object { + public companion object { private const val MAX_LEN = 4000 /** @@ -55,7 +55,8 @@ interface StreamLoggerProvider { * @return A [StreamLoggerProvider] that produces Android-backed [StreamLogger] instances. */ @JvmStatic - fun defaultAndroidLogger( + @StreamInternalApi + public fun defaultAndroidLogger( minLevel: StreamLogger.LogLevel = StreamLogger.LogLevel.Verbose, honorAndroidIsLoggable: Boolean = false, ): StreamLoggerProvider = diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/StreamRetryPolicy.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/StreamRetryPolicy.kt index fa3a044..9d8c5cd 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/StreamRetryPolicy.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/StreamRetryPolicy.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.model -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi /** * **Retry-policy value object** used by Stream’s internal implementations. @@ -44,9 +44,9 @@ import io.getstream.android.core.annotations.StreamCoreApi * @param nextBackOffDelayFunction Computes the delay for the upcoming retry. Receives the retry * index and the previous delay (or `initialDelayMillis` on the first retry). */ -@StreamCoreApi +@StreamInternalApi @ConsistentCopyVisibility -data class StreamRetryPolicy +public data class StreamRetryPolicy private constructor( val minRetries: Int, val maxRetries: Int, @@ -56,7 +56,7 @@ private constructor( val giveUpFunction: (retry: Int, cause: Throwable) -> Boolean, val nextBackOffDelayFunction: (retry: Int, previousDelay: Long) -> Long, ) { - companion object { + public companion object { /** * Creates an **exponential back-off** policy. * @@ -83,7 +83,7 @@ private constructor( * @param initialDelayMillis Delay before the *first* retry. * @param giveUp Custom predicate to override the default “> maxRetries”. */ - fun exponential( + public fun exponential( minRetries: Int = 1, maxRetries: Int = 5, backoffStepMillis: Long = 250, @@ -123,7 +123,7 @@ private constructor( * * Parameter semantics match [exponential]. */ - fun linear( + public fun linear( minRetries: Int = 1, maxRetries: Int = 5, backoffStepMillis: Long = 250, @@ -155,7 +155,7 @@ private constructor( * … * ``` */ - fun fixed( + public fun fixed( minRetries: Int = 1, maxRetries: Int = 5, delayMillis: Long = 500, @@ -200,7 +200,7 @@ private constructor( * @param nextDelay Lambda receives **1-based retry index** and previous delay (or * `initialDelayMillis` for the first retry) and must return the next delay in **ms**. */ - fun custom( + public fun custom( minRetries: Int, maxRetries: Int, minBackoffMills: Long, diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/StreamTypedKey.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/StreamTypedKey.kt index b7f5dec..6177590 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/StreamTypedKey.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/StreamTypedKey.kt @@ -15,16 +15,16 @@ */ package io.getstream.android.core.api.model -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi /** * A typed key that can be used to disambiguate between different types of requests. * * @property id The unique identifier for the key. */ -@StreamCoreApi -data class StreamTypedKey(val id: Any) { - companion object { +@StreamInternalApi +public data class StreamTypedKey(val id: Any) { + public companion object { /** * Creates a new [StreamTypedKey] with the given [id] and type [T]. * @@ -32,7 +32,8 @@ data class StreamTypedKey(val id: Any) { * @return A new [StreamTypedKey] with the given [id] and type [T]. * @receiver id The unique identifier for the key. */ - inline fun Any.asStreamTypedKey() = StreamTypedKey(this) + public inline fun Any.asStreamTypedKey(): StreamTypedKey = + StreamTypedKey(this) /** * Creates a new [StreamTypedKey] with a random [id] and type [T]. @@ -40,6 +41,6 @@ data class StreamTypedKey(val id: Any) { * @param T The type of the key. * @return A new [StreamTypedKey] with a random [id] and type [T]. */ - fun randomExecutionKey() = StreamTypedKey(Any()) + public fun randomExecutionKey(): StreamTypedKey = StreamTypedKey(Any()) } } diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/config/StreamClientSerializationConfig.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/config/StreamClientSerializationConfig.kt index 4e09714..e875531 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/config/StreamClientSerializationConfig.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/config/StreamClientSerializationConfig.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.model.config -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.model.event.StreamClientWsEvent import io.getstream.android.core.api.serialization.StreamEventSerialization import io.getstream.android.core.api.serialization.StreamJsonSerialization @@ -26,9 +26,9 @@ import io.getstream.android.core.api.serialization.StreamJsonSerialization * @param json The JSON serialization implementation. * @param eventParser The event parsing implementation. */ -@StreamCoreApi +@StreamInternalApi @ConsistentCopyVisibility -data class StreamClientSerializationConfig +public data class StreamClientSerializationConfig private constructor( val json: StreamJsonSerialization? = null, val eventParser: StreamEventSerialization? = null, @@ -36,7 +36,7 @@ private constructor( val internalTypes: Set = setOf("connection.ok", "connection.error", "health.check"), val alsoExternal: Set = emptySet(), ) { - companion object { + public companion object { /** * Creates a default [StreamClientSerializationConfig]. Using the internal implementations. * @@ -44,10 +44,10 @@ private constructor( * @param alsoExternal The event types to also parse as external. * @return A default [StreamClientSerializationConfig]. */ - fun default( + public fun default( productEvents: StreamEventSerialization, alsoExternal: Set = emptySet(), - ) = + ): StreamClientSerializationConfig = StreamClientSerializationConfig( productEventSerializers = productEvents, alsoExternal = alsoExternal, @@ -61,11 +61,11 @@ private constructor( * @param alsoExternal The event types to also parse as external. * @return A [StreamClientSerializationConfig] with the given JSON serialization. */ - fun json( + public fun json( serialization: StreamJsonSerialization, productEvents: StreamEventSerialization, alsoExternal: Set = emptySet(), - ) = + ): StreamClientSerializationConfig = StreamClientSerializationConfig( json = serialization, productEventSerializers = productEvents, @@ -80,11 +80,11 @@ private constructor( * @param alsoExternal The event types to also parse as external. * @return A [StreamClientSerializationConfig] with the given event parsing. */ - fun event( + public fun event( serialization: StreamEventSerialization, productEvents: StreamEventSerialization, alsoExternal: Set = emptySet(), - ) = + ): StreamClientSerializationConfig = StreamClientSerializationConfig( eventParser = serialization, productEventSerializers = productEvents, diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/config/StreamHttpConfig.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/config/StreamHttpConfig.kt index 787ea40..1a5a0f1 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/config/StreamHttpConfig.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/config/StreamHttpConfig.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.model.config -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import okhttp3.Interceptor import okhttp3.OkHttpClient @@ -26,8 +26,8 @@ import okhttp3.OkHttpClient * @param automaticInterceptors Whether to add automatic interceptors. * @param configuredInterceptors The configured interceptors. */ -@StreamCoreApi -data class StreamHttpConfig( +@StreamInternalApi +public data class StreamHttpConfig( val httpBuilder: OkHttpClient.Builder, val automaticInterceptors: Boolean = true, val configuredInterceptors: Set = emptySet(), diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/config/StreamSocketConfig.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/config/StreamSocketConfig.kt index 4976371..95cf9eb 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/config/StreamSocketConfig.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/config/StreamSocketConfig.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.model.config -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.model.value.StreamApiKey import io.getstream.android.core.api.model.value.StreamHttpClientInfoHeader @@ -27,16 +27,16 @@ import io.getstream.android.core.api.model.value.StreamHttpClientInfoHeader * @param authType The type of authentication used (e.g., "jwt"). * @param clientInfoHeader The client info header. */ -@StreamCoreApi +@StreamInternalApi @ConsistentCopyVisibility -data class StreamSocketConfig +public data class StreamSocketConfig private constructor( val url: String, val apiKey: StreamApiKey, val authType: String, val clientInfoHeader: StreamHttpClientInfoHeader, ) { - companion object { + public companion object { private const val JWT_AUTH_TYPE = "jwt" private const val ANONYMOUS_AUTH_TYPE = "anonymous" @@ -48,7 +48,7 @@ private constructor( * @param clientInfoHeader The client info header. * @return A JWT-based [StreamSocketConfig]. */ - fun jwt( + public fun jwt( url: String, apiKey: StreamApiKey, clientInfoHeader: StreamHttpClientInfoHeader, @@ -65,7 +65,7 @@ private constructor( * @param clientInfoHeader The client info header. * @return An anonymous [StreamSocketConfig]. */ - fun anonymous( + public fun anonymous( url: String, apiKey: StreamApiKey, clientInfoHeader: StreamHttpClientInfoHeader, @@ -83,7 +83,7 @@ private constructor( * @param clientInfoHeader The client info header. * @return A custom [StreamSocketConfig]. */ - fun custom( + public fun custom( url: String, apiKey: StreamApiKey, authType: String, diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/connection/StreamConnectedUser.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/connection/StreamConnectedUser.kt index 940df5a..85f7da6 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/connection/StreamConnectedUser.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/connection/StreamConnectedUser.kt @@ -17,7 +17,7 @@ package io.getstream.android.core.api.model.connection import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamPublishedApi import java.util.Date import kotlin.collections.Map @@ -38,22 +38,22 @@ import kotlin.collections.Map * @property lastActive The date and time when the user was last active. * @property name The name of the user. */ -@StreamCoreApi +@StreamPublishedApi @JsonClass(generateAdapter = true) -class StreamConnectedUser( - @Json(name = "created_at") val createdAt: Date, - @Json(name = "id") val id: String, - @Json(name = "language") val language: String, - @Json(name = "role") val role: String, - @Json(name = "updated_at") val updatedAt: Date, - @Json(name = "blocked_user_ids") val blockedUserIds: List = emptyList(), - @Json(name = "teams") val teams: List, - @Json(name = "custom") val custom: Map = emptyMap(), - @Json(name = "deactivated_at") val deactivatedAt: Date? = null, - @Json(name = "deleted_at") val deletedAt: Date? = null, - @Json(name = "image") val image: String? = null, - @Json(name = "last_active") val lastActive: Date? = null, - @Json(name = "name") val name: String? = null, +public class StreamConnectedUser( + @Json(name = "created_at") public val createdAt: Date, + @Json(name = "id") public val id: String, + @Json(name = "language") public val language: String, + @Json(name = "role") public val role: String, + @Json(name = "updated_at") public val updatedAt: Date, + @Json(name = "blocked_user_ids") public val blockedUserIds: List = emptyList(), + @Json(name = "teams") public val teams: List, + @Json(name = "custom") public val custom: Map = emptyMap(), + @Json(name = "deactivated_at") public val deactivatedAt: Date? = null, + @Json(name = "deleted_at") public val deletedAt: Date? = null, + @Json(name = "image") public val image: String? = null, + @Json(name = "last_active") public val lastActive: Date? = null, + @Json(name = "name") public val name: String? = null, ) { /** * Returns a string representation of the [StreamConnectedUser] object. diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/connection/StreamConnectionState.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/connection/StreamConnectionState.kt index 21c839b..aa6ca23 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/connection/StreamConnectionState.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/connection/StreamConnectionState.kt @@ -15,15 +15,15 @@ */ package io.getstream.android.core.api.model.connection -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamPublishedApi -@StreamCoreApi -sealed class StreamConnectionState { +@StreamPublishedApi +public sealed class StreamConnectionState { /** The client is not connected and not trying to connect. Initial state for fresh objects. */ - data object Idle : StreamConnectionState() + public data object Idle : StreamConnectionState() /** The client was connected and is now disconnected. */ - data class Disconnected(val cause: Throwable? = null) : StreamConnectionState() + public data class Disconnected(val cause: Throwable? = null) : StreamConnectionState() /** * The client is connected and authenticated. @@ -31,23 +31,23 @@ sealed class StreamConnectionState { * @property connectedUser The user that is connected to the client. * @property connectionId The connection ID. */ - data class Connected(val connectedUser: StreamConnectedUser, val connectionId: String) : + public data class Connected(val connectedUser: StreamConnectedUser, val connectionId: String) : StreamConnectionState() /** The client is trying to connect. */ - sealed class Connecting : StreamConnectionState() { + public sealed class Connecting : StreamConnectionState() { /** * Opening a new connection * * @property userId The user ID that is being connected. */ - data class Opening(val userId: String) : Connecting() + public data class Opening(val userId: String) : Connecting() /** * Authenticating a new connection. Socket is open, but not authenticated. * * @property userId The user ID that is being connected. */ - data class Authenticating(val userId: String) : Connecting() + public data class Authenticating(val userId: String) : Connecting() } } diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/event/StreamClientWsEvent.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/event/StreamClientWsEvent.kt index fd99db3..581709c 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/event/StreamClientWsEvent.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/event/StreamClientWsEvent.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.model.event -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi /** Represents a WebSocket event for the Stream client. */ -@StreamCoreApi interface StreamClientWsEvent +@StreamInternalApi public interface StreamClientWsEvent diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/exceptions/Exceptions.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/exceptions/Exceptions.kt index e4356bb..2423e3b 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/exceptions/Exceptions.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/exceptions/Exceptions.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.model.exceptions -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamPublishedApi import java.io.IOException /** @@ -26,8 +26,8 @@ import java.io.IOException * * @property message The error message associated with this exception. */ -@StreamCoreApi -open class StreamClientException(message: String = "", cause: Throwable? = null) : +@StreamPublishedApi +public open class StreamClientException(message: String = "", cause: Throwable? = null) : Exception(message, cause) /** @@ -41,10 +41,10 @@ open class StreamClientException(message: String = "", cause: Throwable? = null) * `null` otherwise. * @property cause The original exception that caused this error, if available, or `null` otherwise. */ -@StreamCoreApi -class StreamEndpointException( +@StreamPublishedApi +public class StreamEndpointException( message: String = "", - val apiError: StreamEndpointErrorData? = null, + public val apiError: StreamEndpointErrorData? = null, cause: Throwable? = null, ) : IOException(message, cause) @@ -58,6 +58,6 @@ class StreamEndpointException( * @property message A descriptive message about the failure. * @property causes The list of underlying exceptions that caused the failure. */ -@StreamCoreApi -class StreamAggregateException(message: String = "", val causes: List) : +@StreamPublishedApi +public class StreamAggregateException(message: String = "", public val causes: List) : StreamClientException(message) diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/exceptions/StreamEndpointErrorData.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/exceptions/StreamEndpointErrorData.kt index c494d76..3173ad3 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/exceptions/StreamEndpointErrorData.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/exceptions/StreamEndpointErrorData.kt @@ -17,7 +17,7 @@ package io.getstream.android.core.api.model.exceptions import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamPublishedApi /** * Represents an API error response from the Stream API. This data class encapsulates all the error @@ -38,7 +38,7 @@ import io.getstream.android.core.annotations.StreamCoreApi * @property exceptionFields Additional key-value pairs providing extra context about the exception. * Null if not provided. */ -@StreamCoreApi +@StreamPublishedApi @JsonClass(generateAdapter = true) public data class StreamEndpointErrorData( @Json(name = "code") val code: Int, diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamApiKey.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamApiKey.kt index 5ad2d04..df0e593 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamApiKey.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamApiKey.kt @@ -15,17 +15,17 @@ */ package io.getstream.android.core.api.model.value -import android.annotation.SuppressLint +import io.getstream.android.core.annotations.StreamPublishedApi /** * Represents an API key for authentication. * * @property rawValue The raw value of the API key. */ -@SuppressLint("StreamCoreApiMissing") +@StreamPublishedApi @JvmInline -value class StreamApiKey private constructor(val rawValue: String) { - companion object { +public value class StreamApiKey private constructor(public val rawValue: String) { + public companion object { /** * Creates a new [StreamApiKey] from a string. * @@ -33,7 +33,7 @@ value class StreamApiKey private constructor(val rawValue: String) { * @return The created [StreamApiKey]. * @throws IllegalArgumentException If the value is blank or contains only digits. */ - fun fromString(value: String): StreamApiKey { + public fun fromString(value: String): StreamApiKey { require(value.isNotBlank()) { "API key must not be blank" } return StreamApiKey(value) } diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamHttpClientInfoHeader.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamHttpClientInfoHeader.kt index 133baf7..b832e63 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamHttpClientInfoHeader.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamHttpClientInfoHeader.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.model.value -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import java.text.Normalizer import kotlin.text.iterator @@ -24,10 +24,10 @@ import kotlin.text.iterator * * @property rawValue The raw value of the header. */ -@StreamCoreApi +@StreamInternalApi @JvmInline -value class StreamHttpClientInfoHeader private constructor(val rawValue: String) { - companion object { +public value class StreamHttpClientInfoHeader private constructor(public val rawValue: String) { + public companion object { /** * Creates a new [StreamHttpClientInfoHeader] with the given values. * @@ -41,7 +41,7 @@ value class StreamHttpClientInfoHeader private constructor(val rawValue: String) * @return A new [StreamHttpClientInfoHeader] with the given values. */ @JvmStatic - fun create( + public fun create( product: String, productVersion: String, os: String, diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamHttpUrl.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamHttpUrl.kt index 43593a3..c465c8b 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamHttpUrl.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamHttpUrl.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.model.value -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import java.net.URI /** @@ -23,10 +23,10 @@ import java.net.URI * * @property rawValue The raw value of the HTTP URL. */ -@StreamCoreApi +@StreamInternalApi @JvmInline -value class StreamHttpUrl(val rawValue: String) { - companion object { +public value class StreamHttpUrl(public val rawValue: String) { + public companion object { /** * Creates a new [StreamHttpUrl] from a string. * @@ -34,7 +34,7 @@ value class StreamHttpUrl(val rawValue: String) { * @return The created [StreamHttpUrl]. * @throws IllegalArgumentException If the value is blank or not a valid URL. */ - fun fromString(value: String): StreamHttpUrl { + public fun fromString(value: String): StreamHttpUrl { require(value.isNotBlank()) { "HTTP URL must not be blank" } val validURl = try { diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamToken.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamToken.kt index fb13e61..4b5df16 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamToken.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamToken.kt @@ -15,17 +15,17 @@ */ package io.getstream.android.core.api.model.value -import android.annotation.SuppressLint +import io.getstream.android.core.annotations.StreamPublishedApi /** * Authentication token value-object. * * Always construct it with [fromString] so we can enforce invariants. */ -@SuppressLint("StreamCoreApiMissing") +@StreamPublishedApi @JvmInline -value class StreamToken private constructor(val rawValue: String) { - companion object { +public value class StreamToken private constructor(public val rawValue: String) { + public companion object { /** * Creates a new [StreamToken] from a string. * @@ -33,7 +33,7 @@ value class StreamToken private constructor(val rawValue: String) { * @return The created [StreamToken]. * @throws IllegalArgumentException If the token is blank. */ - fun fromString(token: String): StreamToken { + public fun fromString(token: String): StreamToken { require(token.isNotBlank()) { "Token must not be blank" } return StreamToken(token) } diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamUserId.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamUserId.kt index cea497e..69d16de 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamUserId.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamUserId.kt @@ -15,24 +15,24 @@ */ package io.getstream.android.core.api.model.value -import android.annotation.SuppressLint +import io.getstream.android.core.annotations.StreamPublishedApi /** * Represents a user ID. * * @property rawValue The raw value of the user ID. */ -@SuppressLint("StreamCoreApiMissing") +@StreamPublishedApi @JvmInline -value class StreamUserId private constructor(val rawValue: String) { - companion object { +public value class StreamUserId private constructor(public val rawValue: String) { + public companion object { /** * Creates a [StreamUserId] from a [rawValue]. * * @param rawValue The raw value of the user ID. * @return A [StreamUserId] instance. */ - fun fromString(rawValue: String): StreamUserId { + public fun fromString(rawValue: String): StreamUserId { require(rawValue.isNotBlank()) { "User ID cannot be blank" } return StreamUserId(rawValue) } diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamWsUrl.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamWsUrl.kt index 000b544..04fe0f8 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamWsUrl.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/model/value/StreamWsUrl.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.model.value -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import java.net.URI /** @@ -23,10 +23,10 @@ import java.net.URI * * @property rawValue The raw value of the WebSocket URL. */ -@StreamCoreApi +@StreamInternalApi @JvmInline -value class StreamWsUrl private constructor(val rawValue: String) { - companion object { +public value class StreamWsUrl private constructor(public val rawValue: String) { + public companion object { /** * Creates a new [StreamWsUrl] from a string. * @@ -34,7 +34,7 @@ value class StreamWsUrl private constructor(val rawValue: String) { * @return The created [StreamWsUrl]. * @throws IllegalArgumentException If the value is blank or not a valid WS URL. */ - fun fromString(value: String): StreamWsUrl { + public fun fromString(value: String): StreamWsUrl { require(value.isNotBlank()) { "WS URL must not be blank" } val validUrl = try { diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamBatcher.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamBatcher.kt index 46dbaaa..ac70437 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamBatcher.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamBatcher.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.processing -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.internal.processing.StreamBatcherImpl import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel @@ -44,15 +44,15 @@ import kotlinx.coroutines.channels.Channel * - Coalescing high-frequency events (socket messages, UI updates) into fewer handler invocations. * - Rate-limiting downstream work (parsing, I/O, UI recomposition). */ -@StreamCoreApi -interface StreamBatcher { +@StreamInternalApi +public interface StreamBatcher { /** * Starts the processor if it's not already running. * * @return `Result.success(Unit)` if the processor was started successfully; otherwise a * `Result.failure(cause)` describing why the start failed. */ - suspend fun start(): Result + public suspend fun start(): Result /** * Registers the batch handler to be invoked whenever a batch is ready. @@ -67,7 +67,7 @@ interface StreamBatcher { * * Calling this method replaces any previously registered handler. */ - fun onBatch(handler: suspend (List, Long, Int) -> Unit) + public fun onBatch(handler: suspend (List, Long, Int) -> Unit) /** * Enqueues a single item for debounced processing. @@ -81,7 +81,7 @@ interface StreamBatcher { * * @param item The item to enqueue. */ - suspend fun enqueue(item: T): Result + public suspend fun enqueue(item: T): Result /** * Enqueues a single item for debounced processing. @@ -91,7 +91,7 @@ interface StreamBatcher { * - `true` if the item was accepted, * - `false` if the processor is closed/stopped or cannot accept the item. */ - fun offer(item: T): Boolean + public fun offer(item: T): Boolean /** * Stops the processor and releases resources. @@ -103,7 +103,7 @@ interface StreamBatcher { * @return `Result.success(Unit)` on a successful stop; `Result.failure(cause)` if stopping * failed. */ - fun stop(): Result + public fun stop(): Result } /** @@ -118,8 +118,8 @@ interface StreamBatcher { * @param channelCapacity The capacity of the underlying channel. * @return A new [StreamBatcher] instance. */ -@StreamCoreApi -fun StreamBatcher( +@StreamInternalApi +public fun StreamBatcher( scope: CoroutineScope, batchSize: Int = 10, initialDelayMs: Long = 100L, diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamRetryProcessor.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamRetryProcessor.kt index 3e725f9..073f86a 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamRetryProcessor.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamRetryProcessor.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.processing -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.log.StreamLogger import io.getstream.android.core.api.model.StreamRetryPolicy import io.getstream.android.core.internal.processing.StreamRetryProcessorImpl @@ -43,8 +43,8 @@ import io.getstream.android.core.internal.processing.StreamRetryProcessorImpl * @return A [Result] wrapping either the successful value or the final error after all retries have * been exhausted. */ -@StreamCoreApi -interface StreamRetryProcessor { +@StreamInternalApi +public interface StreamRetryProcessor { /** * Executes [block] with the supplied [policy], retrying on failure. * @@ -53,7 +53,7 @@ interface StreamRetryProcessor { * @param block The suspending operation to execute. It should throw on failure; the processor * handles re-invocation. */ - suspend fun retry(policy: StreamRetryPolicy, block: suspend () -> T): Result + public suspend fun retry(policy: StreamRetryPolicy, block: suspend () -> T): Result } /** @@ -62,6 +62,6 @@ interface StreamRetryProcessor { * @param logger The logger to use for logging retry attempts. * @return A new [StreamRetryProcessor] instance. */ -@StreamCoreApi -fun StreamRetryProcessor(logger: StreamLogger): StreamRetryProcessor = +@StreamInternalApi +public fun StreamRetryProcessor(logger: StreamLogger): StreamRetryProcessor = StreamRetryProcessorImpl(logger) diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamSerialProcessingQueue.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamSerialProcessingQueue.kt index a42f1ed..f068c48 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamSerialProcessingQueue.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamSerialProcessingQueue.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.processing -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.log.StreamLogger import io.getstream.android.core.internal.processing.StreamSerialProcessingQueueImpl import kotlinx.coroutines.CoroutineScope @@ -46,8 +46,8 @@ import kotlinx.coroutines.channels.Channel * the job may still run if it was already accepted by the queue (implementation-specific). Call * [stop] to cancel/flush work at the queue level. */ -@StreamCoreApi -interface StreamSerialProcessingQueue { +@StreamInternalApi +public interface StreamSerialProcessingQueue { /** * Submits a suspending [job] for **serialized** execution. * @@ -65,7 +65,7 @@ interface StreamSerialProcessingQueue { * job once accepted (implementation-specific). Use [stop] to cancel at the queue level. * - **Exceptions:** Exceptions thrown by [job] are captured and returned via [Result.failure]. */ - suspend fun submit(job: suspend () -> T): Result + public suspend fun submit(job: suspend () -> T): Result /** * Starts the processor if it's not already running. @@ -73,7 +73,7 @@ interface StreamSerialProcessingQueue { * @return `Result.success(Unit)` if the processor was started successfully; otherwise a * `Result.failure(cause)` describing why the start failed. */ - suspend fun start(): Result + public suspend fun start(): Result /** * Stops the processor and **fails** outstanding work. @@ -89,7 +89,7 @@ interface StreamSerialProcessingQueue { * @return [Result.success] if the processor was stopped successfully; otherwise a * [Result.failure] describing why the stop failed. */ - suspend fun stop(timeout: Long? = null): Result + public suspend fun stop(timeout: Long? = null): Result } /** @@ -102,8 +102,8 @@ interface StreamSerialProcessingQueue { * @param capacity The capacity of the internal queue. * @return A new [StreamSerialProcessingQueue] instance. */ -@StreamCoreApi -fun StreamSerialProcessingQueue( +@StreamInternalApi +public fun StreamSerialProcessingQueue( logger: StreamLogger, scope: CoroutineScope, autoStart: Boolean = true, diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamSingleFlightProcessor.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamSingleFlightProcessor.kt index a03b716..8956af5 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamSingleFlightProcessor.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/processing/StreamSingleFlightProcessor.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.processing -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.model.StreamTypedKey import io.getstream.android.core.internal.processing.StreamSingleFlightProcessorImpl import kotlinx.coroutines.CancellationException @@ -53,8 +53,8 @@ import kotlinx.coroutines.CoroutineScope * * Implementations must be safe for concurrent use. */ -@StreamCoreApi -interface StreamSingleFlightProcessor { +@StreamInternalApi +public interface StreamSingleFlightProcessor { /** * Runs [block], ensuring that **at most one execution** for [key] is in flight. Concurrent * callers with the same [key] await the same shared execution and receive its [Result]. @@ -67,32 +67,32 @@ interface StreamSingleFlightProcessor { * cancelled. If the *awaiting caller* is cancelled, a [CancellationException] is thrown to * that caller instead. */ - suspend fun run(key: StreamTypedKey, block: suspend () -> T): Result + public suspend fun run(key: StreamTypedKey, block: suspend () -> T): Result /** * Checks if there is an in-flight execution for [key]. * * @param key The key to check. */ - fun has(key: StreamTypedKey): Boolean + public fun has(key: StreamTypedKey): Boolean /** * Cancels the current in-flight execution for [key], if any. Joiners will receive * `Result.failure(CancellationException)`. No-op if there is no in-flight execution. */ - fun cancel(key: StreamTypedKey): Result + public fun cancel(key: StreamTypedKey): Result /** * Clears internal bookkeeping. Useful if another component owns lifecycle/cancellation and you * want to drop references. */ - fun clear(cancelRunning: Boolean = true): Result + public fun clear(cancelRunning: Boolean = true): Result /** * Stops all execution and shuts down the runner. No further jobs are accepted. Stop is a * destructive action. */ - fun stop(): Result + public fun stop(): Result } /** @@ -101,6 +101,6 @@ interface StreamSingleFlightProcessor { * @param scope The coroutine scope to use for running the in-flight executions. * @return A new [StreamSingleFlightProcessor] instance. */ -@StreamCoreApi -fun StreamSingleFlightProcessor(scope: CoroutineScope): StreamSingleFlightProcessor = +@StreamInternalApi +public fun StreamSingleFlightProcessor(scope: CoroutineScope): StreamSingleFlightProcessor = StreamSingleFlightProcessorImpl(scope) diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/serialization/StreamEventSerialization.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/serialization/StreamEventSerialization.kt index fa53008..9179068 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/serialization/StreamEventSerialization.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/serialization/StreamEventSerialization.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.serialization -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.model.event.StreamClientWsEvent import io.getstream.android.core.internal.serialization.StreamClientEventSerializationImpl @@ -27,8 +27,8 @@ import io.getstream.android.core.internal.serialization.StreamClientEventSeriali * * @param T The product event type handled by this interface. */ -@StreamCoreApi -interface StreamEventSerialization { +@StreamInternalApi +public interface StreamEventSerialization { /** * Encodes a product event into a [String] suitable for transport or storage. @@ -37,7 +37,7 @@ interface StreamEventSerialization { * @return `Result.success(String)` when encoding succeeds, or `Result.failure(Throwable)` when * the process fails. */ - fun serialize(data: T): Result + public fun serialize(data: T): Result /** * Decodes a product event from a [String] representation. @@ -46,7 +46,7 @@ interface StreamEventSerialization { * @return `Result.success(T)` when decoding succeeds, or `Result.failure(Throwable)` when the * process fails. */ - fun deserialize(raw: String): Result + public fun deserialize(raw: String): Result } /** @@ -57,7 +57,7 @@ interface StreamEventSerialization { * deserialization. * @return A new [StreamEventSerialization] instance. */ -@StreamCoreApi -fun StreamEventSerialization( +@StreamInternalApi +public fun StreamEventSerialization( jsonParser: StreamJsonSerialization ): StreamEventSerialization = StreamClientEventSerializationImpl(jsonParser) diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/serialization/StreamJsonSerialization.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/serialization/StreamJsonSerialization.kt index 140fd1b..7fd01e5 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/serialization/StreamJsonSerialization.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/serialization/StreamJsonSerialization.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.serialization -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi /** * General contract for JSON serialization and deserialization. @@ -27,8 +27,8 @@ import io.getstream.android.core.annotations.StreamCoreApi * Implementations are expected to provide robust error handling and return results wrapped in * [Result]. */ -@StreamCoreApi -interface StreamJsonSerialization { +@StreamInternalApi +public interface StreamJsonSerialization { /** * Converts an object into its JSON string representation. * @@ -36,7 +36,7 @@ interface StreamJsonSerialization { * @return A [Result] containing the JSON string if successful, or a failure with the underlying * exception if serialization fails. */ - fun toJson(any: Any): Result + public fun toJson(any: Any): Result /** * Converts a JSON string into an object of the specified class. @@ -46,7 +46,7 @@ interface StreamJsonSerialization { * @return A [Result] containing the deserialized object if successful, or a failure with the * underlying exception if deserialization fails. */ - fun fromJson(raw: String, clazz: Class): Result + public fun fromJson(raw: String, clazz: Class): Result } /** @@ -57,7 +57,7 @@ interface StreamJsonSerialization { * underlying exception if deserialization fails. * @see [StreamJsonSerialization.fromJson] */ -@StreamCoreApi +@StreamInternalApi @JvmSynthetic -inline fun StreamJsonSerialization.fromJson(raw: String): Result = +public inline fun StreamJsonSerialization.fromJson(raw: String): Result = fromJson(raw, T::class.java) diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/socket/StreamConnectionIdHolder.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/socket/StreamConnectionIdHolder.kt index 0078cc1..a8bea23 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/socket/StreamConnectionIdHolder.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/socket/StreamConnectionIdHolder.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.socket -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.internal.socket.connection.StreamConnectionIdHolderImpl /** @@ -28,14 +28,14 @@ import io.getstream.android.core.internal.socket.connection.StreamConnectionIdHo * the expected value (or `null` if no connection ID is set). On failure, the [Result] contains the * relevant [Throwable]. */ -@StreamCoreApi -interface StreamConnectionIdHolder { +@StreamInternalApi +public interface StreamConnectionIdHolder { /** * Clears the stored connection ID. * * @return A [Result] indicating success, or containing an error if the operation fails. */ - fun clear(): Result + public fun clear(): Result /** * Stores the given connection ID. @@ -44,7 +44,7 @@ interface StreamConnectionIdHolder { * @return A [Result] containing the stored connection ID if successful, or an error if the * operation fails. */ - fun setConnectionId(connectionId: String): Result + public fun setConnectionId(connectionId: String): Result /** * Retrieves the stored connection ID. @@ -52,9 +52,9 @@ interface StreamConnectionIdHolder { * @return A [Result] containing the connection ID if available, `null` if none is set, or an * error if the operation fails. */ - fun getConnectionId(): Result + public fun getConnectionId(): Result } /** Creates a new [StreamConnectionIdHolder] instance. */ -@StreamCoreApi -fun StreamConnectionIdHolder(): StreamConnectionIdHolder = StreamConnectionIdHolderImpl() +@StreamInternalApi +public fun StreamConnectionIdHolder(): StreamConnectionIdHolder = StreamConnectionIdHolderImpl() diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/socket/StreamWebSocket.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/socket/StreamWebSocket.kt index 59c5f46..b8674ad 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/socket/StreamWebSocket.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/socket/StreamWebSocket.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.socket -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.log.StreamLogger import io.getstream.android.core.api.model.config.StreamSocketConfig import io.getstream.android.core.api.socket.listeners.StreamWebSocketListener @@ -30,8 +30,8 @@ import io.getstream.android.core.internal.socket.StreamWebSocketImpl * * @param T The type of listener used to receive WebSocket events. */ -@StreamCoreApi -interface StreamWebSocket : StreamSubscriptionManager { +@StreamInternalApi +public interface StreamWebSocket : StreamSubscriptionManager { /** * Opens the WebSocket connection using the provided configuration. * @@ -39,7 +39,7 @@ interface StreamWebSocket : StreamSubscriptionManag * authentication, and optional headers. * @return A [Result] indicating whether the connection was successfully initiated. */ - fun open(config: StreamSocketConfig): Result + public fun open(config: StreamSocketConfig): Result /** * Closes the WebSocket connection. @@ -48,7 +48,7 @@ interface StreamWebSocket : StreamSubscriptionManag * * @return A [Result] indicating whether the connection was successfully closed. */ - fun close(): Result + public fun close(): Result /** * Sends binary data through the WebSocket connection. @@ -57,7 +57,7 @@ interface StreamWebSocket : StreamSubscriptionManag * @return A [Result] containing the same [ByteArray] if successfully sent, or a failure if * sending failed. */ - fun send(data: ByteArray): Result + public fun send(data: ByteArray): Result /** * Sends a text message through the WebSocket connection. @@ -66,7 +66,7 @@ interface StreamWebSocket : StreamSubscriptionManag * @return A [Result] containing the same [String] if successfully sent, or a failure if sending * failed. */ - fun send(text: String): Result + public fun send(text: String): Result } /** @@ -77,8 +77,8 @@ interface StreamWebSocket : StreamSubscriptionManag * @param subscriptionManager The [StreamSubscriptionManager] to use for managing subscriptions. * @return A new [StreamWebSocket] instance. */ -@StreamCoreApi -fun StreamWebSocket( +@StreamInternalApi +public fun StreamWebSocket( logger: StreamLogger, socketFactory: StreamWebSocketFactory, subscriptionManager: StreamSubscriptionManager, diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/socket/StreamWebSocketFactory.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/socket/StreamWebSocketFactory.kt index 247970c..e1a83f7 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/socket/StreamWebSocketFactory.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/socket/StreamWebSocketFactory.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.socket -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.log.StreamLogger import io.getstream.android.core.api.model.config.StreamSocketConfig import io.getstream.android.core.internal.socket.factory.StreamWebSocketFactoryImpl @@ -33,8 +33,8 @@ import okhttp3.WebSocketListener * The created socket will be configured with the given [StreamSocketConfig], and bound to the * provided [WebSocketListener] for low-level socket events. */ -@StreamCoreApi -interface StreamWebSocketFactory { +@StreamInternalApi +public interface StreamWebSocketFactory { /** * Creates a new [WebSocket] instance. * @@ -45,7 +45,7 @@ interface StreamWebSocketFactory { * @return A [Result] wrapping the created [WebSocket]. On success, the returned [WebSocket] * will be connected and bound to [listener]. */ - fun create( + public fun create( streamSocketConfig: StreamSocketConfig, listener: WebSocketListener, ): Result @@ -58,8 +58,8 @@ interface StreamWebSocketFactory { * @param logger The logger to use for logging. * @return A [StreamWebSocketFactory] instance. */ -@StreamCoreApi -fun StreamWebSocketFactory( +@StreamInternalApi +public fun StreamWebSocketFactory( okHttpClient: OkHttpClient = OkHttpClient(), logger: StreamLogger, ): StreamWebSocketFactory = StreamWebSocketFactoryImpl(okHttpClient = okHttpClient, logger = logger) diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/socket/listeners/StreamClientListener.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/socket/listeners/StreamClientListener.kt index 548a021..d3f64fd 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/socket/listeners/StreamClientListener.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/socket/listeners/StreamClientListener.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.socket.listeners -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.model.connection.StreamConnectionState /** @@ -24,26 +24,26 @@ import io.getstream.android.core.api.model.connection.StreamConnectionState * This interface defines methods to handle socket state changes and events. Implement this * interface to receive updates about the socket connection state and incoming events. */ -@StreamCoreApi -interface StreamClientListener { +@StreamInternalApi +public interface StreamClientListener { /** * Called when the socket connection state changes. * * @param state The new state of the WebSocket connection. */ - fun onState(state: StreamConnectionState) {} + public fun onState(state: StreamConnectionState) {} /** * Called when a new event is received from the socket. * * @param event The event received from the WebSocket. */ - fun onEvent(event: Any) {} + public fun onEvent(event: Any) {} /** * Called when an error occurs on the client. * * @param err The error that occurred. */ - fun onError(err: Throwable) {} + public fun onError(err: Throwable) {} } diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/socket/listeners/StreamWebSocketListener.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/socket/listeners/StreamWebSocketListener.kt index b873451..9d72c53 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/socket/listeners/StreamWebSocketListener.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/socket/listeners/StreamWebSocketListener.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.socket.listeners -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.subscribe.StreamSubscription import okhttp3.Response import okio.ByteString @@ -49,28 +49,28 @@ import okio.ByteString * @see StreamSubscription For lifecycle management of subscriptions. * @see okhttp3.WebSocketListener For the underlying OkHttp implementation. */ -@StreamCoreApi -interface StreamWebSocketListener { +@StreamInternalApi +public interface StreamWebSocketListener { /** * Called when the socket connection is established. * * @param response The handshake response returned by the server. */ - fun onOpen(response: Response) {} + public fun onOpen(response: Response) {} /** * Called when a new binary message is received from the server. * * @param bytes The raw binary payload received. */ - fun onMessage(bytes: ByteString) {} + public fun onMessage(bytes: ByteString) {} /** * Called when a new text message is received from the server. * * @param text The UTF-8 encoded text payload received. */ - fun onMessage(text: String) {} + public fun onMessage(text: String) {} /** * Called when an error occurs on the socket. @@ -78,7 +78,7 @@ interface StreamWebSocketListener { * @param t The throwable cause of the failure. * @param response The optional server response associated with the error. */ - fun onFailure(t: Throwable, response: Response?) {} + public fun onFailure(t: Throwable, response: Response?) {} /** * Called when the socket connection has been closed. @@ -86,7 +86,7 @@ interface StreamWebSocketListener { * @param code The closure status code as defined by RFC 6455. * @param reason The reason message provided by the peer, if any. */ - fun onClosed(code: Int, reason: String) {} + public fun onClosed(code: Int, reason: String) {} /** * Called when the socket is about to close. @@ -94,5 +94,5 @@ interface StreamWebSocketListener { * @param code The closure status code as defined by RFC 6455. * @param reason The reason message provided by the peer, if any. */ - fun onClosing(code: Int, reason: String) {} + public fun onClosing(code: Int, reason: String) {} } diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/socket/monitor/StreamHealthMonitor.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/socket/monitor/StreamHealthMonitor.kt index dd231f0..322cd6d 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/socket/monitor/StreamHealthMonitor.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/socket/monitor/StreamHealthMonitor.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.socket.monitor -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.log.StreamLogger import io.getstream.android.core.internal.socket.monitor.StreamHealthMonitorImpl import kotlin.time.ExperimentalTime @@ -31,8 +31,8 @@ import kotlinx.coroutines.CoroutineScope * - Call [acknowledgeHeartbeat] when receiving a valid "I'm alive" signal. * - Start and stop the monitor as needed. */ -@StreamCoreApi -interface StreamHealthMonitor { +@StreamInternalApi +public interface StreamHealthMonitor { /** * Registers a callback that is invoked at every heartbeat interval. * @@ -41,7 +41,7 @@ interface StreamHealthMonitor { * * @param callback A function to be called on each heartbeat tick. */ - fun onHeartbeat(callback: suspend () -> Unit) + public fun onHeartbeat(callback: suspend () -> Unit) /** * Registers a callback that is invoked when the liveness threshold is exceeded. @@ -51,7 +51,7 @@ interface StreamHealthMonitor { * * @param callback A function to be called when the liveness timeout occurs. */ - fun onUnhealthy(callback: suspend () -> Unit) + public fun onUnhealthy(callback: suspend () -> Unit) /** * Acknowledges a heartbeat signal. @@ -59,18 +59,18 @@ interface StreamHealthMonitor { * This should be called whenever the monitored system successfully responds, indicating that it * is alive and healthy. Resets the liveness timer. */ - fun acknowledgeHeartbeat() + public fun acknowledgeHeartbeat() /** Starts the health monitor, beginning the heartbeat and liveness checks. */ - fun start() + public fun start() /** Stops the health monitor, halting heartbeat and liveness checks. */ - fun stop() + public fun stop() } @OptIn(ExperimentalTime::class) -@StreamCoreApi -fun StreamHealthMonitor( +@StreamInternalApi +public fun StreamHealthMonitor( logger: StreamLogger, scope: CoroutineScope, interval: Long = StreamHealthMonitorImpl.INTERVAL, diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/subscribe/StreamSubscription.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/subscribe/StreamSubscription.kt index 85c757c..002f24a 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/subscribe/StreamSubscription.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/subscribe/StreamSubscription.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.subscribe -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamPublishedApi /** * Handle returned by every **Stream** `subscribe(…)` call. @@ -29,8 +29,8 @@ import io.getstream.android.core.annotations.StreamCoreApi * Instances are **single-shot**: once you invoke [cancel] the subscription is permanently * terminated and calling `cancel()` again has no effect. */ -@StreamCoreApi -interface StreamSubscription { +@StreamPublishedApi +public interface StreamSubscription { /** * Terminates this subscription. * @@ -40,5 +40,5 @@ interface StreamSubscription { * * The operation is idempotent; invoking it multiple times is safe. */ - fun cancel() + public fun cancel() } diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/subscribe/StreamSubscriptionManager.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/subscribe/StreamSubscriptionManager.kt index 4726804..3d2b0a8 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/subscribe/StreamSubscriptionManager.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/subscribe/StreamSubscriptionManager.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.subscribe -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import io.getstream.android.core.api.log.StreamLogger import io.getstream.android.core.internal.subscribe.StreamSubscriptionManagerImpl @@ -37,16 +37,16 @@ import io.getstream.android.core.internal.subscribe.StreamSubscriptionManagerImp * * @param T the listener type (often a function type, e.g. `(Event) -> Unit`) */ -@StreamCoreApi -interface StreamSubscriptionManager { +@StreamInternalApi +public interface StreamSubscriptionManager { /** * Subscription behavior options. * * @property retention Controls how the manager retains the listener reference. */ - data class Options(val retention: Retention = Retention.AUTO_REMOVE) { + public data class Options(val retention: Retention = Retention.AUTO_REMOVE) { /** Retention policy for a subscribed listener. */ - enum class Retention { + public enum class Retention { /** * The manager keeps only an ephemeral reference. If caller code drops all references to * the listener (and does not call `cancel()`), the listener is automatically removed @@ -84,7 +84,7 @@ interface StreamSubscriptionManager { * @return `Result.success(StreamSubscription)` when the listener was added; * `Result.failure(Throwable)` if the operation cannot be completed (e.g., capacity limits). */ - fun subscribe(listener: T, options: Options = Options()): Result + public fun subscribe(listener: T, options: Options = Options()): Result /** * Removes **all** listeners and releases related resources. @@ -96,7 +96,7 @@ interface StreamSubscriptionManager { * @return `Result.success(Unit)` if cleared successfully; `Result.failure(Throwable)` * otherwise. */ - fun clear(): Result + public fun clear(): Result /** * Executes [block] for every currently registered listener. @@ -111,7 +111,7 @@ interface StreamSubscriptionManager { * @return `Result.success(Unit)` on normal completion; `Result.failure(Throwable)` if iteration * fails. */ - fun forEach(block: (T) -> Unit): Result + public fun forEach(block: (T) -> Unit): Result } /** @@ -123,8 +123,8 @@ interface StreamSubscriptionManager { * @param maxWeakSubscriptions The maximum number of weak listeners. * @return A new [StreamSubscriptionManager] instance. */ -@StreamCoreApi -fun StreamSubscriptionManager( +@StreamInternalApi +public fun StreamSubscriptionManager( logger: StreamLogger, maxStrongSubscriptions: Int = StreamSubscriptionManagerImpl.MAX_LISTENERS, maxWeakSubscriptions: Int = StreamSubscriptionManagerImpl.MAX_LISTENERS, diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/utils/Catching.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/utils/Catching.kt index f7b820b..8cc6591 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/utils/Catching.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/utils/Catching.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.utils -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -27,9 +27,9 @@ import kotlin.coroutines.cancellation.CancellationException * - On **cancellation**: **rethrows** [CancellationException]. * - On **other exceptions**: `Result.failure(cause)`. */ -@StreamCoreApi +@StreamInternalApi @OptIn(ExperimentalContracts::class) -inline fun runCatchingCancellable(block: () -> T): Result { +public inline fun runCatchingCancellable(block: () -> T): Result { contract { callsInPlace(block, InvocationKind.AT_MOST_ONCE) } return try { Result.success(block()) diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/utils/Map.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/utils/Map.kt index 7c4ed42..db5dd72 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/utils/Map.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/utils/Map.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.utils -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import java.util.concurrent.ConcurrentMap /** @@ -25,8 +25,11 @@ import java.util.concurrent.ConcurrentMap * @param defaultValue The function to compute the value. * @return The value for the given key. */ -@StreamCoreApi -inline fun ConcurrentMap.streamComputeIfAbsent(key: K, defaultValue: () -> V): V { +@StreamInternalApi +public inline fun ConcurrentMap.streamComputeIfAbsent( + key: K, + defaultValue: () -> V, +): V { this[key]?.let { return it } diff --git a/stream-android-core/src/main/java/io/getstream/android/core/api/utils/Result.kt b/stream-android-core/src/main/java/io/getstream/android/core/api/utils/Result.kt index b66c9ac..d4db062 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/api/utils/Result.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/api/utils/Result.kt @@ -15,7 +15,7 @@ */ package io.getstream.android.core.api.utils -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamInternalApi import kotlin.coroutines.cancellation.CancellationException /** @@ -32,6 +32,6 @@ import kotlin.coroutines.cancellation.CancellationException * failure if this [Result] is a failure. * @throws Throwable if [transform] throws, including [CancellationException]. */ -@StreamCoreApi -inline fun Result.flatMap(transform: (T) -> Result): Result = +@StreamInternalApi +public inline fun Result.flatMap(transform: (T) -> Result): Result = fold(onSuccess = { transform(it) }, onFailure = { Result.failure(it) }) diff --git a/stream-android-core/src/main/java/io/getstream/android/core/internal/model/events/StreamHealthCheckEvent.kt b/stream-android-core/src/main/java/io/getstream/android/core/internal/model/events/StreamHealthCheckEvent.kt index 19ee535..013d4c7 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/internal/model/events/StreamHealthCheckEvent.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/internal/model/events/StreamHealthCheckEvent.kt @@ -17,11 +17,11 @@ package io.getstream.android.core.internal.model.events import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import io.getstream.android.core.annotations.StreamCoreApi +import io.getstream.android.core.annotations.StreamPublishedApi import io.getstream.android.core.api.model.event.StreamClientWsEvent import java.util.Date -@StreamCoreApi +@StreamPublishedApi @JsonClass(generateAdapter = true) internal data class StreamHealthCheckEvent( @Json(name = "connection_id") val connectionId: String, diff --git a/stream-android-core/src/main/java/io/getstream/android/core/internal/processing/StreamRestartableChannel.kt b/stream-android-core/src/main/java/io/getstream/android/core/internal/processing/StreamRestartableChannel.kt index abb5ce5..f879170 100644 --- a/stream-android-core/src/main/java/io/getstream/android/core/internal/processing/StreamRestartableChannel.kt +++ b/stream-android-core/src/main/java/io/getstream/android/core/internal/processing/StreamRestartableChannel.kt @@ -19,6 +19,7 @@ package io.getstream.android.core.internal.processing import java.util.concurrent.atomic.AtomicReference import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.channels.* import kotlinx.coroutines.selects.SelectClause1 import kotlinx.coroutines.selects.SelectClause2 @@ -29,6 +30,7 @@ import kotlinx.coroutines.selects.SelectClause2 * - When [start] is called after the channel was closed-for-send, it swaps in a fresh channel. * - Adds `*Safe` helpers that wrap send/trySend/close in Result for ergonomic error handling. */ +@OptIn(DelicateCoroutinesApi::class) internal class StreamRestartableChannel(private val capacity: Int = Channel.BUFFERED) : Channel {