diff --git a/sdk/kotlin/README.md b/sdk/kotlin/README.md
new file mode 100644
index 0000000..7f5ba90
--- /dev/null
+++ b/sdk/kotlin/README.md
@@ -0,0 +1,259 @@
+# Telecom Platform Kotlin SDK
+
+Kotlin SDK for the Telecom Platform with coroutines support and type safety.
+
+## Features
+
+- **Modular Architecture**: Separate modules for authentication, HTTP client, and API services
+- **Coroutines Support**: Full async/await support with Kotlin coroutines
+- **Type Safety**: Strong typing with Kotlin data classes
+- **Error Handling**: Comprehensive error handling with sealed classes
+- **Retry Logic**: Built-in retry mechanism with exponential backoff
+- **Multiplatform Support**: Works on JVM, Android, and more
+
+## Installation
+
+### Gradle (Kotlin DSL)
+
+```kotlin
+dependencies {
+ implementation("com.telecom:telecom-sdk:1.0.0")
+}
+```
+
+### Gradle (Groovy DSL)
+
+```groovy
+dependencies {
+ implementation 'com.telecom:telecom-sdk:1.0.0'
+}
+```
+
+### Maven
+
+```xml
+
+ com.telecom
+ telecom-sdk
+ 1.0.0
+
+```
+
+## Architecture
+
+The SDK is organized into modular components:
+
+- `AuthProvider.kt` - Authentication provider handling API keys and JWT tokens
+- `HTTPClient.kt` - HTTP client with retry logic and authentication
+- `SubscriberAPI.kt` - Subscriber management API
+- `UsageAPI.kt` - Usage tracking API
+- `PaymentAPI.kt` - Payment processing API
+- `RatingPlanAPI.kt` - Rating plan management API
+- `SystemAPI.kt` - System monitoring API
+- `GraphQLAPI.kt` - GraphQL query execution
+- `TelecomSDK.kt` - Main SDK client integrating all modules
+
+## Quick Start
+
+```kotlin
+import com.telecom.TelecomSDK
+import kotlinx.coroutines.runBlocking
+
+fun main() = runBlocking {
+ val sdk = TelecomSDK(
+ baseURL = "http://localhost:8000",
+ apiKey = "your-api-key"
+ )
+
+ // Get subscriber
+ val subscriber = sdk.subscribers.get(1)
+ println("Subscriber: ${subscriber.firstName} ${subscriber.lastName}")
+
+ // List subscribers
+ val subscribers = sdk.subscribers.list(1, 50, "active")
+ println("Total subscribers: ${subscribers.total}")
+}
+```
+
+## API Reference
+
+### Configuration
+
+```kotlin
+val config = TelecomConfig(
+ apiURL = "http://localhost:8000",
+ apiKey = "your-api-key",
+ jwtSecret = "your-jwt-secret",
+ timeout = Duration.ofSeconds(30),
+ maxRetries = 3,
+ retryDelay = Duration.ofSeconds(1),
+ enableLogging = false
+)
+```
+
+### Subscriber Management
+
+```kotlin
+// Get subscriber
+val subscriber = sdk.subscribers.get(1)
+
+// List subscribers
+val subscribers = sdk.subscribers.list(
+ page = 1,
+ pageSize = 50,
+ status = "active"
+)
+
+// Create subscriber
+val newSubscriber = sdk.subscribers.create(
+ msisdn = "+1234567890",
+ firstName = "John",
+ lastName = "Doe",
+ email = "john.doe@example.com",
+ planId = 1
+)
+
+// Update subscriber
+val updated = sdk.subscribers.update(
+ id = 1,
+ firstName = "Jane",
+ email = "jane.doe@example.com"
+)
+
+// Delete subscriber
+sdk.subscribers.delete(1)
+
+// Suspend subscriber
+sdk.subscribers.suspend(1)
+
+// Activate subscriber
+sdk.subscribers.activate(1)
+```
+
+### Usage Management
+
+```kotlin
+import java.time.Duration
+import java.time.Instant
+
+// Get usage stats
+val start = Instant.now().minus(Duration.ofDays(30))
+val end = Instant.now()
+val stats = sdk.usage.getStats(1, start, end)
+
+// List usage events
+val events = sdk.usage.listEvents(
+ subscriberId = 1,
+ usageType = "data",
+ page = 1,
+ pageSize = 50
+)
+
+// Get real-time usage
+val realtime = sdk.usage.getRealTime(1)
+```
+
+### Payment Management
+
+```kotlin
+// Create payment transaction
+val transaction = sdk.payments.createTransaction(
+ subscriberId = "1",
+ amount = 25.00,
+ currency = "USD",
+ gateway = "stripe",
+ metadata = mapOf("description" to "Monthly plan")
+)
+
+// Get transaction
+val transaction = sdk.payments.getTransaction("txn-123")
+
+// List transactions
+val transactions = sdk.payments.listTransactions(
+ subscriberId = 1,
+ status = "completed",
+ page = 1,
+ pageSize = 50
+)
+```
+
+### Rating Plans
+
+```kotlin
+// List rating plans
+val plans = sdk.ratingPlans.list()
+
+// Get specific plan
+val plan = sdk.ratingPlans.get("plan-123")
+```
+
+### System Management
+
+```kotlin
+// Get system stats
+val stats = sdk.system.getStats()
+
+// Get health status
+val health = sdk.system.getHealth()
+```
+
+### GraphQL
+
+```kotlin
+// Execute GraphQL query
+val query = """
+query GetSubscribers($first: Int) {
+ subscribers(first: $first) {
+ id
+ firstName
+ lastName
+ }
+}
+"""
+
+val variables = mapOf("first" to 10)
+val result = sdk.graphql.execute(query, variables)
+```
+
+## Error Handling
+
+```kotlin
+try {
+ val subscriber = sdk.subscribers.get(1)
+} catch (e: AuthError.JWTSecretNotConfigured) {
+ println("JWT secret not configured")
+} catch (e: AuthError.InvalidTokenFormat) {
+ println("Invalid token format")
+} catch (e: AuthError.InvalidTokenSignature) {
+ println("Invalid token signature")
+} catch (e: AuthError.TokenExpired) {
+ println("Token expired")
+} catch (e: AuthError.SigningFailed) {
+ println("Signing failed")
+} catch (e: Exception) {
+ println("Error: ${e.message}")
+}
+```
+
+## Development
+
+### Building
+
+```bash
+./gradlew build
+```
+
+### Testing
+
+```bash
+./gradlew test
+```
+
+## Requirements
+
+- Kotlin 1.9+
+- Java 11+
+
+## License
+
+This SDK is licensed under the MIT License.
diff --git a/sdk/kotlin/src/main/kotlin/com/telecom/AuthProvider.kt b/sdk/kotlin/src/main/kotlin/com/telecom/AuthProvider.kt
new file mode 100644
index 0000000..19ca344
--- /dev/null
+++ b/sdk/kotlin/src/main/kotlin/com/telecom/AuthProvider.kt
@@ -0,0 +1,215 @@
+package com.telecom
+
+import java.security.MessageDigest
+import java.util.Base64
+import javax.crypto.Mac
+import javax.crypto.spec.SecretKeySpec
+
+/**
+ * Authentication provider for the Telecom SDK
+ */
+class AuthProvider(
+ private val apiKey: String? = null,
+ private val jwtSecret: String? = null
+) {
+ private var tokenCache: String? = null
+ private var tokenExpiry: Long? = null
+
+ /**
+ * Get authentication headers for API requests
+ */
+ fun getHeaders(): Map {
+ val headers = mutableMapOf(
+ "Content-Type" to "application/json",
+ "User-Agent" to "Telecom-Kotlin-SDK/1.0.0"
+ )
+
+ apiKey?.let { headers["X-API-Key"] = it }
+
+ if (tokenCache != null && isTokenValid()) {
+ headers["Authorization"] = "Bearer $tokenCache"
+ }
+
+ return headers
+ }
+
+ /**
+ * Generate a JWT token for authentication
+ */
+ fun generateJWTToken(
+ userId: String,
+ expiryHours: Int,
+ additionalClaims: Map = emptyMap()
+ ): String {
+ val jwtSecret = jwtSecret ?: throw AuthError.JWTSecretNotConfigured
+
+ val now = System.currentTimeMillis() / 1000
+ val exp = now + (expiryHours * 3600)
+
+ val claims = mutableMapOf(
+ "sub" to userId,
+ "exp" to exp,
+ "iat" to now
+ )
+ claims.putAll(additionalClaims)
+
+ val header = mapOf("alg" to "HS256", "typ" to "JWT")
+ val encodedHeader = base64URLEncode(header)
+ val encodedPayload = base64URLEncode(claims)
+ val signature = sign("$encodedHeader.$encodedPayload", jwtSecret)
+
+ val token = "$encodedHeader.$encodedPayload.$signature"
+ tokenCache = token
+ tokenExpiry = exp
+
+ return token
+ }
+
+ /**
+ * Validate a JWT token
+ */
+ fun validateJWTToken(token: String): Map {
+ val jwtSecret = jwtSecret ?: throw AuthError.JWTSecretNotConfigured
+
+ val parts = token.split(".")
+ if (parts.size != 3) {
+ throw AuthError.InvalidTokenFormat
+ }
+
+ val (encodedHeader, encodedPayload, signature) = parts
+ val expectedSignature = sign("$encodedHeader.$encodedPayload", jwtSecret)
+
+ if (signature != expectedSignature) {
+ throw AuthError.InvalidTokenSignature
+ }
+
+ val payloadBytes = base64URLDecode(encodedPayload) ?: throw AuthError.FailedToDecodePayload
+ val payload = parseJson(payloadBytes) as? Map ?: throw AuthError.FailedToDecodePayload
+
+ val exp = payload["exp"] as? Number
+ if (exp != null && exp.toLong() < System.currentTimeMillis() / 1000) {
+ throw AuthError.TokenExpired
+ }
+
+ return payload
+ }
+
+ /**
+ * Clear the cached JWT token
+ */
+ fun clearTokenCache() {
+ tokenCache = null
+ tokenExpiry = null
+ }
+
+ private fun isTokenValid(): Boolean {
+ if (tokenCache == null || tokenExpiry == null) return false
+ return System.currentTimeMillis() / 1000 < (tokenExpiry ?: 0)
+ }
+
+ private fun base64URLEncode(data: Any): String {
+ val json = toJson(data)
+ return Base64.getUrlEncoder()
+ .withoutPadding()
+ .encodeToString(json.toByteArray())
+ }
+
+ private fun base64URLDecode(data: String): ByteArray? {
+ val base64String = data
+ .replace("-", "+")
+ .replace("_", "/")
+
+ val paddingNeeded = (4 - base64String.length % 4) % 4
+ val paddedString = base64String + "=".repeat(paddingNeeded)
+
+ return try {
+ Base64.getUrlDecoder().decode(paddedString)
+ } catch (e: Exception) {
+ null
+ }
+ }
+
+ private fun sign(data: String, secret: String): String {
+ return try {
+ val key = SecretKeySpec(secret.toByteArray(), "HmacSHA256")
+ val mac = Mac.getInstance("HmacSHA256")
+ mac.init(key)
+ val signature = mac.doFinal(data.toByteArray())
+ Base64.getUrlEncoder()
+ .withoutPadding()
+ .encodeToString(signature)
+ } catch (e: Exception) {
+ throw AuthError.SigningFailed
+ }
+ }
+
+ private fun toJson(data: Any): String {
+ return when (data) {
+ is Map<*, *> -> {
+ val entries = data.entries.joinToString(",") { (k, v) ->
+ "\"${k}\":${toJson(v)}"
+ }
+ "{$entries}"
+ }
+ is List<*> -> {
+ val items = data.joinToString(",") { toJson(it) }
+ "[$items]"
+ }
+ is String -> "\"$data\""
+ is Number -> data.toString()
+ is Boolean -> data.toString()
+ else -> "\"$data\""
+ }
+ }
+
+ private fun parseJson(json: String): Any? {
+ // JSON parser using kotlinx.serialization
+ // In production, use proper kotlinx.serialization with typed models
+ // For SDK compatibility without external dependencies, using basic parsing
+ return try {
+ when {
+ json.trim().startsWith("{") -> {
+ // Parse JSON object
+ val content = json.trim().removeSurrounding("{", "}")
+ val pairs = content.split(",")
+ val map = mutableMapOf()
+ pairs.forEach { pair ->
+ val (key, value) = pair.split(":", limit = 2)
+ val cleanKey = key.trim().removeSurrounding("\"")
+ val cleanValue = value.trim()
+ map[cleanKey] = when {
+ cleanValue.startsWith("\"") -> cleanValue.removeSurrounding("\"")
+ cleanValue == "true" -> true
+ cleanValue == "false" -> false
+ cleanValue.toIntOrNull() != null -> cleanValue.toInt()
+ cleanValue.toDoubleOrNull() != null -> cleanValue.toDouble()
+ else -> cleanValue
+ }
+ }
+ map
+ }
+ json.trim().startsWith("[") -> {
+ // Parse JSON array
+ val content = json.trim().removeSurrounding("[", "]")
+ if (content.isBlank()) {
+ emptyList()
+ } else {
+ content.split(",").map { it.trim().removeSurrounding("\"") }
+ }
+ }
+ else -> json.trim()
+ }
+ } catch (e: Exception) {
+ null
+ }
+ }
+}
+
+sealed class AuthError(message: String) : Exception(message) {
+ object JWTSecretNotConfigured : AuthError("JWT secret not configured")
+ object InvalidTokenFormat : AuthError("Invalid token format")
+ object InvalidTokenSignature : AuthError("Invalid token signature")
+ object FailedToDecodePayload : AuthError("Failed to decode payload")
+ object TokenExpired : AuthError("Token has expired")
+ object SigningFailed : AuthError("Signing failed")
+}
diff --git a/sdk/kotlin/src/main/kotlin/com/telecom/GraphQLAPI.kt b/sdk/kotlin/src/main/kotlin/com/telecom/GraphQLAPI.kt
new file mode 100644
index 0000000..f90414f
--- /dev/null
+++ b/sdk/kotlin/src/main/kotlin/com/telecom/GraphQLAPI.kt
@@ -0,0 +1,15 @@
+package com.telecom
+
+/**
+ * API for GraphQL queries
+ */
+class GraphQLAPI(private val client: HTTPClient) {
+
+ /**
+ * Execute a GraphQL query
+ */
+ suspend fun execute(query: String, variables: Map? = null): Map {
+ val request = GraphQLRequest(query, variables)
+ return client.post("/graphql", request)
+ }
+}
diff --git a/sdk/kotlin/src/main/kotlin/com/telecom/HTTPClient.kt b/sdk/kotlin/src/main/kotlin/com/telecom/HTTPClient.kt
new file mode 100644
index 0000000..43ac043
--- /dev/null
+++ b/sdk/kotlin/src/main/kotlin/com/telecom/HTTPClient.kt
@@ -0,0 +1,137 @@
+package com.telecom
+
+import io.ktor.client.*
+import io.ktor.client.call.*
+import io.ktor.client.plugins.*
+import io.ktor.client.plugins.contentnegotiation.*
+import io.ktor.client.request.*
+import io.ktor.http.*
+import io.ktor.serialization.kotlinx.json.*
+import kotlinx.serialization.json.Json
+
+/**
+ * HTTP client for making API requests
+ */
+class HTTPClient(
+ private val config: TelecomConfig,
+ private val authProvider: AuthProvider
+) {
+ private val client: HttpClient = HttpClient {
+ defaultRequest {
+ url(config.apiURL)
+ header("User-Agent", "Telecom-Kotlin-SDK/1.0.0")
+ }
+
+ install(ContentNegotiation) {
+ json(Json {
+ ignoreUnknownKeys = true
+ isLenient = true
+ })
+ }
+
+ install(HttpTimeout) {
+ requestTimeoutMillis = config.timeout.toMillis()
+ }
+ }
+
+ /**
+ * Make an HTTP GET request
+ */
+ suspend fun get(path: String, params: Map? = null): T {
+ return request("GET", path, null, params)
+ }
+
+ /**
+ * Make an HTTP POST request
+ */
+ suspend fun post(path: String, body: Any? = null): T {
+ return request("POST", path, body, null)
+ }
+
+ /**
+ * Make an HTTP PUT request
+ */
+ suspend fun put(path: String, body: Any? = null): T {
+ return request("PUT", path, body, null)
+ }
+
+ /**
+ * Make an HTTP DELETE request
+ */
+ suspend fun delete(path: String) {
+ request("DELETE", path, null, null)
+ }
+
+ private suspend fun request(
+ method: String,
+ path: String,
+ body: Any?,
+ params: Map?
+ ): T {
+ var lastError: Throwable? = null
+
+ for (attempt in 0..config.maxRetries) {
+ try {
+ val response = client.request(path) {
+ this.method = HttpMethod.parse(method)
+
+ // Set headers
+ val headers = authProvider.getHeaders()
+ for ((key, value) in headers) {
+ header(key, value)
+ }
+
+ // Add query parameters
+ params?.let {
+ it.forEach { (k, v) ->
+ parameter(k, v)
+ }
+ }
+
+ // Add body
+ body?.let {
+ setBody(it)
+ contentType(ContentType.Application.Json)
+ }
+ }
+
+ handleResponseErrors(response.status)
+
+ return response.body()
+ } catch (e: Exception) {
+ lastError = e
+ if (attempt < config.maxRetries) {
+ kotlinx.coroutines.delay(config.retryDelay * (1 shl attempt))
+ }
+ }
+ }
+
+ throw lastError ?: NetworkError.RequestFailed
+ }
+
+ private fun handleResponseErrors(status: HttpStatusCode) {
+ when (status) {
+ HttpStatusCode.Unauthorized -> throw AuthError.AuthenticationFailed
+ HttpStatusCode.TooManyRequests -> throw AuthError.RateLimitExceeded
+ in 400..499 -> throw NetworkError.ClientError(status.value)
+ in 500..599 -> throw NetworkError.ServerError(status.value)
+ else -> {}
+ }
+ }
+
+ fun close() {
+ client.close()
+ }
+}
+
+sealed class NetworkError(message: String) : Exception(message) {
+ object RequestFailed : NetworkError("Request failed")
+ class ClientError(code: Int) : NetworkError("Client error: $code")
+ class ServerError(code: Int) : NetworkError("Server error: $code")
+}
+
+// Extend AuthError with additional errors
+object AuthError {
+ object AuthenticationFailed : AuthError("Authentication failed")
+ object RateLimitExceeded : AuthError("Rate limit exceeded")
+}
diff --git a/sdk/kotlin/src/main/kotlin/com/telecom/PaymentAPI.kt b/sdk/kotlin/src/main/kotlin/com/telecom/PaymentAPI.kt
new file mode 100644
index 0000000..ce5f9d3
--- /dev/null
+++ b/sdk/kotlin/src/main/kotlin/com/telecom/PaymentAPI.kt
@@ -0,0 +1,41 @@
+package com.telecom
+
+/**
+ * API for payment management
+ */
+class PaymentAPI(private val client: HTTPClient) {
+
+ /**
+ * Create a payment transaction
+ */
+ suspend fun createTransaction(request: CreatePaymentRequest): PaymentTransaction {
+ return client.post("/v1/payments/transactions", request)
+ }
+
+ /**
+ * Get a payment transaction by ID
+ */
+ suspend fun getTransaction(transactionId: String): PaymentTransaction {
+ return client.get("/v1/payments/transactions/$transactionId")
+ }
+
+ /**
+ * List payment transactions
+ */
+ suspend fun listTransactions(
+ subscriberId: Long? = null,
+ status: PaymentStatus? = null,
+ page: Int = 1,
+ pageSize: Int = 50
+ ): SubscriberList {
+ val params = mutableMapOf(
+ "page" to page.toString(),
+ "page_size" to pageSize.toString()
+ )
+
+ subscriberId?.let { params["subscriber_id"] = it.toString() }
+ status?.let { params["status"] = it.toString() }
+
+ return client.get("/v1/payments/transactions", params)
+ }
+}
diff --git a/sdk/kotlin/src/main/kotlin/com/telecom/RatingPlanAPI.kt b/sdk/kotlin/src/main/kotlin/com/telecom/RatingPlanAPI.kt
new file mode 100644
index 0000000..a3991d4
--- /dev/null
+++ b/sdk/kotlin/src/main/kotlin/com/telecom/RatingPlanAPI.kt
@@ -0,0 +1,21 @@
+package com.telecom
+
+/**
+ * API for rating plan management
+ */
+class RatingPlanAPI(private val client: HTTPClient) {
+
+ /**
+ * List all available rating plans
+ */
+ suspend fun list(): List {
+ return client.get("/v1/rating-plans")
+ }
+
+ /**
+ * Get a rating plan by ID
+ */
+ suspend fun get(planId: String): RatingPlan {
+ return client.get("/v1/rating-plans/$planId")
+ }
+}
diff --git a/sdk/kotlin/src/main/kotlin/com/telecom/SubscriberAPI.kt b/sdk/kotlin/src/main/kotlin/com/telecom/SubscriberAPI.kt
new file mode 100644
index 0000000..b025387
--- /dev/null
+++ b/sdk/kotlin/src/main/kotlin/com/telecom/SubscriberAPI.kt
@@ -0,0 +1,63 @@
+package com.telecom
+
+/**
+ * API for subscriber management
+ */
+class SubscriberAPI(private val client: HTTPClient) {
+
+ /**
+ * Get subscriber by ID
+ */
+ suspend fun get(id: Long): Subscriber {
+ return client.get("/v1/subscribers/$id")
+ }
+
+ /**
+ * List subscribers with pagination
+ */
+ suspend fun list(page: Int = 1, pageSize: Int = 50, status: SubscriberStatus? = null): SubscriberList {
+ val params = mutableMapOf(
+ "page" to page.toString(),
+ "page_size" to pageSize.toString()
+ )
+
+ status?.let { params["status"] = it.toString() }
+
+ return client.get("/v1/subscribers", params)
+ }
+
+ /**
+ * Create a new subscriber
+ */
+ suspend fun create(request: CreateSubscriberRequest): Subscriber {
+ return client.post("/v1/subscribers", request)
+ }
+
+ /**
+ * Update an existing subscriber
+ */
+ suspend fun update(id: Long, request: UpdateSubscriberRequest): Subscriber {
+ return client.put("/v1/subscribers/$id", request)
+ }
+
+ /**
+ * Delete a subscriber
+ */
+ suspend fun delete(id: Long) {
+ client.delete("/v1/subscribers/$id")
+ }
+
+ /**
+ * Suspend a subscriber
+ */
+ suspend fun suspend(id: Long): Subscriber {
+ return client.post("/v1/subscribers/$id/suspend", null)
+ }
+
+ /**
+ * Activate a suspended subscriber
+ */
+ suspend fun activate(id: Long): Subscriber {
+ return client.post("/v1/subscribers/$id/activate", null)
+ }
+}
diff --git a/sdk/kotlin/src/main/kotlin/com/telecom/SystemAPI.kt b/sdk/kotlin/src/main/kotlin/com/telecom/SystemAPI.kt
new file mode 100644
index 0000000..9bdb103
--- /dev/null
+++ b/sdk/kotlin/src/main/kotlin/com/telecom/SystemAPI.kt
@@ -0,0 +1,21 @@
+package com.telecom
+
+/**
+ * API for system management
+ */
+class SystemAPI(private val client: HTTPClient) {
+
+ /**
+ * Get system statistics
+ */
+ suspend fun getStats(): SystemStats {
+ return client.get("/v1/system/stats")
+ }
+
+ /**
+ * Get system health status
+ */
+ suspend fun getHealth(): HealthStatus {
+ return client.get("/v1/health")
+ }
+}
diff --git a/sdk/kotlin/src/main/kotlin/com/telecom/TelecomSDK.kt b/sdk/kotlin/src/main/kotlin/com/telecom/TelecomSDK.kt
index fe1aa88..22e9f67 100644
--- a/sdk/kotlin/src/main/kotlin/com/telecom/TelecomSDK.kt
+++ b/sdk/kotlin/src/main/kotlin/com/telecom/TelecomSDK.kt
@@ -1,330 +1,83 @@
package com.telecom
-import io.ktor.client.*
-import io.ktor.client.call.*
-import io.ktor.client.plugins.*
-import io.ktor.client.plugins.contentnegotiation.*
-import io.ktor.client.request.*
-import io.ktor.client.statement.*
-import io.ktor.http.*
-import io.ktor.serialization.kotlinx.json.*
-import io.ktor.websocket.*
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-import kotlinx.serialization.*
-import kotlinx.serialization.json.*
-import java.time.*
-import java.time.format.DateTimeFormatter
-
/**
* Telecom Platform Kotlin SDK
*
* Provides coroutine-based access to the Telecom Platform API with full Kotlin serialization support.
*/
class TelecomSDK private constructor(
- private val httpClient: HttpClient,
private val config: TelecomConfig,
- private val webSocketClient: WebSocketClient
+ private val authProvider: AuthProvider,
+ private val httpClient: HTTPClient
) {
+ // API modules
+ val subscribers: SubscriberAPI
+ val usage: UsageAPI
+ val payments: PaymentAPI
+ val ratingPlans: RatingPlanAPI
+ val system: SystemAPI
+ val graphql: GraphQLAPI
+
companion object {
/**
* Create a new TelecomSDK instance
*/
fun create(config: TelecomConfig = TelecomConfig()): TelecomSDK {
- val httpClient = HttpClient {
- defaultRequest {
- url(config.apiURL)
- header("User-Agent", "Telecom-Kotlin-SDK/1.0.0")
- config.apiKey?.let { header("Authorization", "Bearer $it") }
- }
-
- install(ContentNegotiation) {
- json(Json {
- ignoreUnknownKeys = true
- isLenient = true
- })
- }
-
- install(HttpTimeout) {
- requestTimeoutMillis = config.timeout.toMillis()
- }
-
- install(Retry) {
- maxRetries = config.maxRetries
- retryOnExceptionIf { request, throwable ->
- throwable is HttpRequestTimeoutException ||
- throwable is ConnectTimeoutException
- }
- exponentialDelay()
- }
-
- HttpResponseValidator {
- handleResponseExceptionWithRequest { exception, request ->
- when (exception) {
- is ClientRequestException -> {
- when (exception.response.status) {
- HttpStatusCode.Unauthorized -> throw TelecomException.AuthenticationError("Authentication failed")
- HttpStatusCode.TooManyRequests -> throw TelecomException.RateLimitError("Rate limit exceeded")
- in HttpStatusCode.BadRequest..HttpStatusCode.UnprocessableEntity -> {
- val errorBody = exception.response.body()
- throw TelecomException.APIError("API error: $errorBody")
- }
- in HttpStatusCode.InternalServerError..HttpStatusCode.NetworkAuthenticationRequired -> {
- throw TelecomException.ServerError("Server error: ${exception.response.status}")
- }
- }
- }
- }
- }
- }
- }
+ val authProvider = AuthProvider(apiKey = config.apiKey, jwtSecret = config.jwtSecret)
+ val httpClient = HTTPClient(config = config, authProvider = authProvider)
- val webSocketClient = WebSocketClient()
+ // Initialize API modules
+ val subscribers = SubscriberAPI(httpClient)
+ val usage = UsageAPI(httpClient)
+ val payments = PaymentAPI(httpClient)
+ val ratingPlans = RatingPlanAPI(httpClient)
+ val system = SystemAPI(httpClient)
+ val graphql = GraphQLAPI(httpClient)
- return TelecomSDK(httpClient, config, webSocketClient)
+ return TelecomSDK(config, authProvider, httpClient, subscribers, usage, payments, ratingPlans, system, graphql)
}
}
- // Subscriber Management
+ private constructor(
+ config: TelecomConfig,
+ authProvider: AuthProvider,
+ httpClient: HTTPClient,
+ subscribers: SubscriberAPI,
+ usage: UsageAPI,
+ payments: PaymentAPI,
+ ratingPlans: RatingPlanAPI,
+ system: SystemAPI,
+ graphql: GraphQLAPI
+ ) {
+ this.config = config
+ this.authProvider = authProvider
+ this.httpClient = httpClient
+ this.subscribers = subscribers
+ this.usage = usage
+ this.payments = payments
+ this.ratingPlans = ratingPlans
+ this.system = system
+ this.graphql = graphql
+ }
+
+ // Authentication methods
/**
- * Get subscriber by ID
+ * Generate a JWT token for authentication
*/
- suspend fun getSubscriber(id: Long): Subscriber {
- return httpClient.get("/v1/subscribers/$id").body()
+ fun generateJWTToken(userId: String, expiryHours: Int, additionalClaims: Map = emptyMap()): String {
+ return authProvider.generateJWTToken(userId, expiryHours, additionalClaims)
}
/**
- * List subscribers with pagination
+ * Validate a JWT token
*/
- suspend fun listSubscribers(
- page: Int = 1,
- pageSize: Int = 50,
- status: SubscriberStatus? = null
- ): SubscriberList {
- val params = mutableListOf(
- "page" to page.toString(),
- "page_size" to pageSize.toString()
- )
- status?.let { params.add("status" to it.value) }
-
- return httpClient.get("/v1/subscribers") {
- parameter(params)
- }.body()
+ fun validateJWTToken(token: String): Map {
+ return authProvider.validateJWTToken(token)
}
- /**
- * Create a new subscriber
- */
- suspend fun createSubscriber(request: CreateSubscriberRequest): Subscriber {
- return httpClient.post("/v1/subscribers") {
- setBody(request)
- }.body()
- }
-
- /**
- * Update an existing subscriber
- */
- suspend fun updateSubscriber(id: Long, request: UpdateSubscriberRequest): Subscriber {
- return httpClient.put("/v1/subscribers/$id") {
- setBody(request)
- }.body()
- }
-
- /**
- * Suspend a subscriber
- */
- suspend fun suspendSubscriber(id: Long): Subscriber {
- return httpClient.post("/v1/subscribers/$id/suspend").body()
- }
-
- /**
- * Activate a suspended subscriber
- */
- suspend fun activateSubscriber(id: Long): Subscriber {
- return httpClient.post("/v1/subscribers/$id/activate").body()
- }
-
- /**
- * Terminate a subscriber
- */
- suspend fun terminateSubscriber(id: Long): Boolean {
- return httpClient.delete("/v1/subscribers/$id").body()
- }
-
- // Usage Management
-
- /**
- * Get usage statistics for a subscriber
- */
- suspend fun getUsageStats(
- subscriberId: Long,
- startDate: LocalDateTime,
- endDate: LocalDateTime
- ): UsageStats {
- return httpClient.get("/v1/subscribers/$subscriberId/usage") {
- parameter("start_date", startDate.format(DateTimeFormatter.ISO_DATE_TIME))
- parameter("end_date", endDate.format(DateTimeFormatter.ISO_DATE_TIME))
- }.body()
- }
-
- /**
- * List usage events with filtering
- */
- suspend fun listUsageEvents(
- subscriberId: Long? = null,
- usageType: UsageType? = null,
- startDate: LocalDateTime? = null,
- endDate: LocalDateTime? = null,
- page: Int = 1,
- pageSize: Int = 50
- ): UsageEventList {
- val params = mutableListOf(
- "page" to page.toString(),
- "page_size" to pageSize.toString()
- )
-
- subscriberId?.let { params.add("subscriber_id" to it.toString()) }
- usageType?.let { params.add("usage_type" to it.value) }
- startDate?.let { params.add("start_date", it.format(DateTimeFormatter.ISO_DATE_TIME)) }
- endDate?.let { params.add("end_date", it.format(DateTimeFormatter.ISO_DATE_TIME)) }
-
- return httpClient.get("/v1/usage/events") {
- parameter(params)
- }.body()
- }
-
- /**
- * Get real-time usage for a subscriber
- */
- suspend fun getRealTimeUsage(subscriberId: Long): RealTimeUsage {
- return httpClient.get("/v1/subscribers/$subscriberId/realtime").body()
- }
-
- // Payment Management
-
- /**
- * Create a payment transaction
- */
- suspend fun createPaymentTransaction(request: CreatePaymentRequest): PaymentTransaction {
- return httpClient.post("/v1/payments/transactions") {
- setBody(request)
- }.body()
- }
-
- /**
- * Get payment transaction by ID
- */
- suspend fun getPaymentTransaction(transactionId: String): PaymentTransaction {
- return httpClient.get("/v1/payments/transactions/$transactionId").body()
- }
-
- /**
- * List payment transactions with filtering
- */
- suspend fun listPaymentTransactions(
- subscriberId: Long? = null,
- status: PaymentStatus? = null,
- page: Int = 1,
- pageSize: Int = 50
- ): PaymentTransactionList {
- val params = mutableListOf(
- "page" to page.toString(),
- "page_size" to pageSize.toString()
- )
-
- subscriberId?.let { params.add("subscriber_id" to it.toString()) }
- status?.let { params.add("status" to it.value) }
-
- return httpClient.get("/v1/payments/transactions") {
- parameter(params)
- }.body()
- }
-
- // Rating Plans
-
- /**
- * List all available rating plans
- */
- suspend fun listRatingPlans(): List {
- return httpClient.get("/v1/rating-plans").body()
- }
-
- /**
- * Get rating plan by ID
- */
- suspend fun getRatingPlan(planId: String): RatingPlan {
- return httpClient.get("/v1/rating-plans/$planId").body()
- }
-
- // System Management
-
- /**
- * Get system statistics
- */
- suspend fun getSystemStats(): SystemStats {
- return httpClient.get("/v1/system/stats").body()
- }
-
- /**
- * Get system health status
- */
- suspend fun getHealthStatus(): HealthStatus {
- return httpClient.get("/v1/health").body()
- }
-
- // WebSocket Support
-
- /**
- * Connect to WebSocket for real-time updates
- */
- fun connectWebSocket(
- messageHandler: suspend (WebSocketMessage) -> Unit
- ): Flow = flow {
- val wsUrl = config.apiURL.replace("http://", "ws://") + "/ws"
-
- webSocketClient.webSocket(
- urlString = wsUrl,
- request = {
- config.apiKey?.let { header("Authorization", "Bearer $it") }
- }
- ) { session ->
- session.incoming.consumeAsFlow().collect { frame ->
- when (frame) {
- is Frame.Text -> {
- try {
- val message = Json.decodeFromString(frame.readText())
- emit(message)
- messageHandler(message)
- } catch (e: Exception) {
- throw TelecomException.WebSocketError("Failed to parse WebSocket message: $e")
- }
- }
- else -> {
- // Handle other frame types if needed
- }
- }
- }
- }
- }.catch { e ->
- throw TelecomException.WebSocketError("WebSocket connection failed: $e")
- }
-
- // GraphQL Support
-
- /**
- * Execute a GraphQL query
- */
- suspend fun executeGraphQLQuery(
- query: String,
- variables: Map = emptyMap()
- ): GraphQLResponse {
- val request = GraphQLRequest(query, variables)
- return httpClient.post("/graphql") {
- setBody(request)
- }.body()
- }
+ // Cleanup
/**
* Close the SDK and cleanup resources
@@ -340,6 +93,8 @@ class TelecomSDK private constructor(
data class TelecomConfig(
val apiURL: String = "http://localhost:8000",
val apiKey: String? = null,
- val timeout: Duration = Duration.ofSeconds(30),
- val maxRetries: Int = 3
+ val jwtSecret: String? = null,
+ val timeout: java.time.Duration = java.time.Duration.ofSeconds(30),
+ val maxRetries: Int = 3,
+ val retryDelay: Long = 1 // in seconds
)
diff --git a/sdk/kotlin/src/main/kotlin/com/telecom/UsageAPI.kt b/sdk/kotlin/src/main/kotlin/com/telecom/UsageAPI.kt
new file mode 100644
index 0000000..10aeca5
--- /dev/null
+++ b/sdk/kotlin/src/main/kotlin/com/telecom/UsageAPI.kt
@@ -0,0 +1,54 @@
+package com.telecom
+
+import java.time.format.DateTimeFormatter
+
+/**
+ * API for usage management
+ */
+class UsageAPI(private val client: HTTPClient) {
+
+ private val formatter = DateTimeFormatter.ISO_DATE_TIME
+
+ /**
+ * Get usage statistics for a subscriber
+ */
+ suspend fun getStats(subscriberId: Long, startDate: java.time.LocalDateTime, endDate: java.time.LocalDateTime): UsageStats {
+ val params = mapOf(
+ "start_date" to formatter.format(startDate),
+ "end_date" to formatter.format(endDate)
+ )
+
+ return client.get("/v1/subscribers/$subscriberId/usage", params)
+ }
+
+ /**
+ * List usage events
+ */
+ suspend fun listEvents(
+ subscriberId: Long? = null,
+ usageType: UsageType? = null,
+ startDate: java.time.LocalDateTime? = null,
+ endDate: java.time.LocalDateTime? = null,
+ page: Int = 1,
+ pageSize: Int = 50
+ ): UsageEventList {
+ val params = mutableMapOf(
+ "page" to page.toString(),
+ "page_size" to pageSize.toString()
+ )
+
+ subscriberId?.let { params["subscriber_id"] = it.toString() }
+ usageType?.let { params["usage_type"] = it.toString() }
+ startDate?.let { params["start_date"] = formatter.format(it) }
+ endDate?.let { params["end_date"] = formatter.format(it) }
+
+ return client.get("/v1/usage/events", params)
+ }
+
+ /**
+ * Get real-time usage for a subscriber
+ */
+ suspend fun getRealtime(subscriberId: Long): RealTimeUsage {
+ return client.get("/v1/subscribers/$subscriberId/realtime")
+ }
+}