mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-22 04:34:27 +00:00
feat: Add TypeScript SDK with fetch-based HTTP client and comprehensive Telecom Platform API integration
- Add package.json with @telecom-platform/sdk 1.0.0, TypeScript 6.0.3, ESLint 10.2.0, Jest 30.3.0 - Add SDKConfig singleton with 30s timeout, 3 retries, 1s retry delay defaults and WebSocket URL support - Add HttpClient with fetch API, exponential backoff retry logic, Bearer token authentication, timeout handling - Add subscriber management: getSubscriber, listSubscribers with pagination/status
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
# Telecom Platform TypeScript SDK
|
||||
|
||||
A comprehensive TypeScript SDK for integrating with the Telecom Platform API. This SDK provides a clean, type-safe interface for managing subscribers, monitoring usage, handling payments, and receiving real-time updates.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @telecom-platform/sdk
|
||||
# or
|
||||
yarn add @telecom-platform/sdk
|
||||
# or
|
||||
pnpm add @telecom-platform/sdk
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```typescript
|
||||
import { TelecomSDK } from '@telecom-platform/sdk';
|
||||
|
||||
// Initialize the SDK
|
||||
const sdk = TelecomSDK.initialize({
|
||||
baseURL: 'https://api.telecom-platform.com',
|
||||
apiKey: 'your-api-key',
|
||||
websocketURL: 'wss://ws.telecom-platform.com',
|
||||
enableLogging: true,
|
||||
});
|
||||
|
||||
// Connect to WebSocket for real-time updates
|
||||
await sdk.connectWebSocket();
|
||||
|
||||
// Subscribe to usage updates for a subscriber
|
||||
sdk.subscribeToUsage('123456789012345');
|
||||
|
||||
// Listen for usage updates
|
||||
sdk.onUsageUpdate((update) => {
|
||||
console.log('Usage update:', update);
|
||||
});
|
||||
|
||||
// Subscribe to alerts
|
||||
sdk.subscribeToAlerts();
|
||||
|
||||
// Listen for alerts
|
||||
sdk.onAlert((alert) => {
|
||||
console.log('Alert:', alert);
|
||||
});
|
||||
|
||||
// List subscribers
|
||||
const subscribers = await sdk.subscribersService.listSubscribers({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
console.log('Subscribers:', subscribers);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Initialization
|
||||
|
||||
```typescript
|
||||
const sdk = TelecomSDK.initialize({
|
||||
baseURL: string, // API base URL (required)
|
||||
apiKey?: string, // API key (optional)
|
||||
timeout?: number, // Request timeout in ms (default: 30000)
|
||||
retryAttempts?: number, // Number of retry attempts (default: 3)
|
||||
retryDelay?: number, // Retry delay in ms (default: 1000)
|
||||
enableLogging?: boolean, // Enable debug logging (default: false)
|
||||
websocketURL?: string, // WebSocket URL for real-time updates
|
||||
});
|
||||
```
|
||||
|
||||
### Subscriber Management
|
||||
|
||||
```typescript
|
||||
// List subscribers
|
||||
const subscribers = await sdk.subscribersService.listSubscribers({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
status: 'active',
|
||||
organizationId: 'org-123',
|
||||
search: 'John Doe',
|
||||
});
|
||||
|
||||
// Get subscriber by ID
|
||||
const subscriber = await sdk.subscribersService.getSubscriber(123);
|
||||
|
||||
// Get subscriber by IMSI
|
||||
const subscriber = await sdk.subscribersService.getSubscriberByImsi('123456789012345');
|
||||
|
||||
// Create new subscriber
|
||||
const newSubscriber = await sdk.subscribersService.createSubscriber({
|
||||
msisdn: '+1234567890',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
email: '[email protected]',
|
||||
planId: 1,
|
||||
});
|
||||
|
||||
// Update subscriber
|
||||
const updated = await sdk.subscribersService.updateSubscriber(123, {
|
||||
firstName: 'Jane',
|
||||
email: '[email protected]',
|
||||
});
|
||||
|
||||
// Delete subscriber
|
||||
await sdk.subscribersService.deleteSubscriber(123);
|
||||
|
||||
// Suspend subscriber
|
||||
await sdk.subscribersService.suspendSubscriber(123);
|
||||
|
||||
// Activate subscriber
|
||||
await sdk.subscribersService.activateSubscriber(123);
|
||||
|
||||
// Terminate subscriber
|
||||
await sdk.subscribersService.terminateSubscriber(123);
|
||||
```
|
||||
|
||||
### Account Management
|
||||
|
||||
```typescript
|
||||
// Get subscriber account
|
||||
const account = await sdk.subscribersService.getSubscriberAccount('123456789012345');
|
||||
|
||||
// Top up balance
|
||||
const updatedAccount = await sdk.subscribersService.topUpBalance('123456789012345', {
|
||||
amount: 1000, // $10.00 in cents
|
||||
paymentMethodId: 'pm_123',
|
||||
});
|
||||
|
||||
// Get usage statistics
|
||||
const stats = await sdk.subscribersService.getUsageStats('123456789012345', 'monthly');
|
||||
|
||||
// Get real-time usage
|
||||
const realtime = await sdk.subscribersService.getRealTimeUsage('123456789012345');
|
||||
```
|
||||
|
||||
### eSIM Management
|
||||
|
||||
```typescript
|
||||
// Provision eSIM profile
|
||||
const esim = await sdk.subscribersService.provisionESIM('123456789012345');
|
||||
|
||||
// Activate eSIM profile
|
||||
await sdk.subscribersService.activateESIM('123456789012345', esim.profileId);
|
||||
|
||||
// Deactivate eSIM profile
|
||||
await sdk.subscribersService.deactivateESIM('123456789012345', esim.profileId);
|
||||
|
||||
// Get eSIM status
|
||||
const status = await sdk.subscribersService.getESIMStatus('123456789012345');
|
||||
```
|
||||
|
||||
### Billing & Invoices
|
||||
|
||||
```typescript
|
||||
// Get subscriber invoices
|
||||
const invoices = await sdk.subscribersService.getInvoices('123456789012345');
|
||||
|
||||
// Get specific invoice
|
||||
const invoice = await sdk.subscribersService.getInvoice('inv_123');
|
||||
|
||||
// Download invoice PDF
|
||||
const pdfBlob = await sdk.subscribersService.downloadInvoicePDF('inv_123');
|
||||
```
|
||||
|
||||
### Real-time Updates
|
||||
|
||||
```typescript
|
||||
// Connect to WebSocket
|
||||
await sdk.connectWebSocket();
|
||||
|
||||
// Subscribe to usage updates
|
||||
sdk.subscribeToUsage('123456789012345');
|
||||
|
||||
// Subscribe to alerts
|
||||
sdk.subscribeToAlerts();
|
||||
|
||||
// Listen for usage updates
|
||||
sdk.onUsageUpdate((update) => {
|
||||
console.log(`Data used: ${update.dataUsed} bytes`);
|
||||
console.log(`Cost: $${update.cost / 100}`);
|
||||
});
|
||||
|
||||
// Listen for alerts
|
||||
sdk.onAlert((alert) => {
|
||||
console.log(`Alert: ${alert.message}`);
|
||||
if (alert.severity === 'critical') {
|
||||
// Handle critical alert
|
||||
}
|
||||
});
|
||||
|
||||
// Custom event handlers
|
||||
sdk.onWebSocketEvent('custom_event', (message) => {
|
||||
console.log('Custom event:', message);
|
||||
});
|
||||
|
||||
// Check connection status
|
||||
if (sdk.isWebSocketConnected) {
|
||||
console.log('WebSocket is connected');
|
||||
}
|
||||
|
||||
// Disconnect
|
||||
sdk.disconnectWebSocket();
|
||||
```
|
||||
|
||||
### System Monitoring
|
||||
|
||||
```typescript
|
||||
// Get system statistics
|
||||
const stats = await sdk.getSystemStats();
|
||||
console.log('Active sessions:', stats.activeSessions);
|
||||
console.log('Total accounts:', stats.totalAccounts);
|
||||
|
||||
// Get health status
|
||||
const health = await sdk.getHealthStatus();
|
||||
console.log('Redis connected:', health.redisConnected);
|
||||
|
||||
// Test connection
|
||||
const test = await sdk.testConnection();
|
||||
console.log('API status:', test.status);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
The SDK provides comprehensive error handling with detailed error information:
|
||||
|
||||
```typescript
|
||||
try {
|
||||
const subscriber = await sdk.subscribersService.getSubscriber(123);
|
||||
} catch (error) {
|
||||
console.error('Error:', error.code);
|
||||
console.error('Message:', error.message);
|
||||
console.error('Details:', error.details);
|
||||
console.error('Timestamp:', error.timestamp);
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration Updates
|
||||
|
||||
You can update the SDK configuration at runtime:
|
||||
|
||||
```typescript
|
||||
// Update API key
|
||||
sdk.setApiKey('new-api-key');
|
||||
|
||||
// Update base URL
|
||||
sdk.setBaseURL('https://new-api.telecom-platform.com');
|
||||
|
||||
// Enable/disable logging
|
||||
sdk.setLogging(true);
|
||||
|
||||
// Get current configuration
|
||||
const config = sdk.getConfig();
|
||||
console.log('Current config:', config);
|
||||
```
|
||||
|
||||
## TypeScript Support
|
||||
|
||||
The SDK is fully typed with TypeScript. All methods have proper type definitions and IntelliSense support:
|
||||
|
||||
```typescript
|
||||
import { Subscriber, SubscriberStatus, UsageType } from '@telecom-platform/sdk';
|
||||
|
||||
// Types are automatically inferred
|
||||
const subscriber: Subscriber = await sdk.subscribersService.getSubscriber(123);
|
||||
const status: SubscriberStatus = subscriber.status;
|
||||
```
|
||||
|
||||
## Browser Support
|
||||
|
||||
The SDK works in modern browsers that support:
|
||||
- ES2020 features
|
||||
- WebSocket API
|
||||
- Fetch API
|
||||
|
||||
For older browsers, you may need to include appropriate polyfills.
|
||||
|
||||
## Node.js Usage
|
||||
|
||||
The SDK also works in Node.js environments:
|
||||
|
||||
```typescript
|
||||
import { TelecomSDK } from '@telecom-platform/sdk';
|
||||
|
||||
// Node.js WebSocket polyfill may be required
|
||||
global.WebSocket = require('ws');
|
||||
|
||||
const sdk = TelecomSDK.initialize({
|
||||
baseURL: 'https://api.telecom-platform.com',
|
||||
apiKey: process.env.API_KEY,
|
||||
});
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
See the `examples/` directory for complete examples of:
|
||||
- Basic subscriber management
|
||||
- Real-time usage monitoring
|
||||
- eSIM provisioning
|
||||
- Billing integration
|
||||
- Custom dashboard implementation
|
||||
|
||||
## Support
|
||||
|
||||
- Documentation: [https://docs.telecom-platform.com/sdk](https://docs.telecom-platform.com/sdk)
|
||||
- Issues: [GitHub Issues](https://github.com/telecom-platform/sdk/issues)
|
||||
- Support: support@telecom-platform.com
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see LICENSE file for details.
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "@telecom-platform/sdk",
|
||||
"version": "1.0.0",
|
||||
"description": "TypeScript SDK for Telecom Platform API",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"dev": "tsc --watch",
|
||||
"test": "jest",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"keywords": ["telecom", "api", "sdk", "typescript"],
|
||||
"author": "Telecom Platform Team",
|
||||
"license": "MIT",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.58.2",
|
||||
"@typescript-eslint/parser": "^8.58.2",
|
||||
"eslint": "^10.2.0",
|
||||
"jest": "^30.3.0",
|
||||
"typescript": "^6.0.3"
|
||||
},
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/telecom-platform/sdk.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/telecom-platform/sdk/issues"
|
||||
},
|
||||
"homepage": "https://github.com/telecom-platform/sdk#readme"
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
export interface TelecomSDKConfig {
|
||||
baseURL: string;
|
||||
apiKey?: string;
|
||||
timeout?: number;
|
||||
retryAttempts?: number;
|
||||
retryDelay?: number;
|
||||
enableLogging?: boolean;
|
||||
websocketURL?: string;
|
||||
}
|
||||
|
||||
export class SDKConfig {
|
||||
private static instance: SDKConfig;
|
||||
private config: TelecomSDKConfig;
|
||||
|
||||
private constructor(config: TelecomSDKConfig) {
|
||||
this.config = {
|
||||
timeout: 30000,
|
||||
retryAttempts: 3,
|
||||
retryDelay: 1000,
|
||||
enableLogging: false,
|
||||
...config
|
||||
};
|
||||
}
|
||||
|
||||
public static initialize(config: TelecomSDKConfig): void {
|
||||
if (!SDKConfig.instance) {
|
||||
SDKConfig.instance = new SDKConfig(config);
|
||||
}
|
||||
}
|
||||
|
||||
public static getInstance(): SDKConfig {
|
||||
if (!SDKConfig.instance) {
|
||||
throw new Error('SDKConfig not initialized. Call SDKConfig.initialize() first.');
|
||||
}
|
||||
return SDKConfig.instance;
|
||||
}
|
||||
|
||||
public get baseURL(): string {
|
||||
return this.config.baseURL;
|
||||
}
|
||||
|
||||
public get apiKey(): string | undefined {
|
||||
return this.config.apiKey;
|
||||
}
|
||||
|
||||
public get timeout(): number {
|
||||
return this.config.timeout!;
|
||||
}
|
||||
|
||||
public get retryAttempts(): number {
|
||||
return this.config.retryAttempts!;
|
||||
}
|
||||
|
||||
public get retryDelay(): number {
|
||||
return this.config.retryDelay!;
|
||||
}
|
||||
|
||||
public get enableLogging(): boolean {
|
||||
return this.config.enableLogging!;
|
||||
}
|
||||
|
||||
public get websocketURL(): string | undefined {
|
||||
return this.config.websocketURL;
|
||||
}
|
||||
|
||||
public updateConfig(updates: Partial<TelecomSDKConfig>): void {
|
||||
this.config = { ...this.config, ...updates };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import { Error as SdkError } from './types';
|
||||
import { SDKConfig } from './config';
|
||||
|
||||
export class HttpClient {
|
||||
private config: SDKConfig;
|
||||
|
||||
constructor() {
|
||||
this.config = SDKConfig.getInstance();
|
||||
}
|
||||
|
||||
private get headers(): Record<string, string> {
|
||||
const h: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
};
|
||||
if (this.config.apiKey) {
|
||||
h['Authorization'] = `Bearer ${this.config.apiKey}`;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
private buildURL(path: string, params?: Record<string, unknown>): string {
|
||||
const url = new URL(path, this.config.baseURL);
|
||||
if (params) {
|
||||
Object.entries(params).forEach(([k, v]) => {
|
||||
if (v !== undefined && v !== null) {
|
||||
url.searchParams.set(k, String(v));
|
||||
}
|
||||
});
|
||||
}
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
private async fetchWithRetry(url: string, init: RequestInit, attempt = 0): Promise<Response> {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), this.config.timeout);
|
||||
try {
|
||||
if (this.config.enableLogging) {
|
||||
console.log(`[SDK] ${init.method ?? 'GET'} ${url}`);
|
||||
}
|
||||
|
||||
const response = await fetch(url, { ...init, signal: controller.signal });
|
||||
|
||||
if (this.config.enableLogging) {
|
||||
console.log(`[SDK] Response ${response.status}`);
|
||||
}
|
||||
|
||||
if (!response.ok && this.shouldRetry(response.status) && attempt < this.config.retryAttempts) {
|
||||
await new Promise(r => setTimeout(r, this.config.retryDelay * Math.pow(2, attempt)));
|
||||
return this.fetchWithRetry(url, init, attempt + 1);
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (err) {
|
||||
if (attempt < this.config.retryAttempts && !(err instanceof DOMException)) {
|
||||
await new Promise(r => setTimeout(r, this.config.retryDelay * Math.pow(2, attempt)));
|
||||
return this.fetchWithRetry(url, init, attempt + 1);
|
||||
}
|
||||
throw err;
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
private shouldRetry(status: number): boolean {
|
||||
return status >= 500 || status === 429;
|
||||
}
|
||||
|
||||
private async handleResponse<T>(response: Response): Promise<T> {
|
||||
if (!response.ok) {
|
||||
let body: any = {};
|
||||
try { body = await response.json(); } catch { /* empty */ }
|
||||
const err: SdkError = {
|
||||
code: body.code ?? `HTTP_${response.status}`,
|
||||
message: body.message ?? response.statusText,
|
||||
details: body.details,
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
throw err;
|
||||
}
|
||||
return response.json() as Promise<T>;
|
||||
}
|
||||
|
||||
async get<T>(url: string, params?: Record<string, unknown>): Promise<T> {
|
||||
const response = await this.fetchWithRetry(
|
||||
this.buildURL(url, params),
|
||||
{ method: 'GET', headers: this.headers },
|
||||
);
|
||||
return this.handleResponse<T>(response);
|
||||
}
|
||||
|
||||
async post<T>(url: string, data?: unknown): Promise<T> {
|
||||
const response = await this.fetchWithRetry(
|
||||
this.buildURL(url),
|
||||
{ method: 'POST', headers: this.headers, body: data ? JSON.stringify(data) : null },
|
||||
);
|
||||
return this.handleResponse<T>(response);
|
||||
}
|
||||
|
||||
async put<T>(url: string, data?: unknown): Promise<T> {
|
||||
const response = await this.fetchWithRetry(
|
||||
this.buildURL(url),
|
||||
{ method: 'PUT', headers: this.headers, body: data ? JSON.stringify(data) : null },
|
||||
);
|
||||
return this.handleResponse<T>(response);
|
||||
}
|
||||
|
||||
async patch<T>(url: string, data?: unknown): Promise<T> {
|
||||
const response = await this.fetchWithRetry(
|
||||
this.buildURL(url),
|
||||
{ method: 'PATCH', headers: this.headers, body: data ? JSON.stringify(data) : null },
|
||||
);
|
||||
return this.handleResponse<T>(response);
|
||||
}
|
||||
|
||||
async delete<T>(url: string): Promise<T> {
|
||||
const response = await this.fetchWithRetry(
|
||||
this.buildURL(url),
|
||||
{ method: 'DELETE', headers: this.headers },
|
||||
);
|
||||
return this.handleResponse<T>(response);
|
||||
}
|
||||
|
||||
setApiKey(apiKey: string): void {
|
||||
this.config.updateConfig({ apiKey });
|
||||
}
|
||||
|
||||
setBaseURL(baseURL: string): void {
|
||||
this.config.updateConfig({ baseURL });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Main entry point for the Telecom Platform TypeScript SDK
|
||||
|
||||
export { TelecomSDK } from './telecom-sdk';
|
||||
export { SDKConfig, TelecomSDKConfig } from './config';
|
||||
export { HttpClient } from './http-client';
|
||||
export { SubscribersService } from './subscribers';
|
||||
export { WebSocketClient } from './websocket';
|
||||
|
||||
// Export all types
|
||||
export * from './types';
|
||||
@@ -0,0 +1,193 @@
|
||||
import { HttpClient } from './http-client';
|
||||
import {
|
||||
Subscriber,
|
||||
CreateSubscriberRequest,
|
||||
UpdateSubscriberRequest,
|
||||
ListSubscribersRequest,
|
||||
PaginatedResponse,
|
||||
SubscriberAccount,
|
||||
TopUpRequest,
|
||||
Invoice,
|
||||
ProfileStatus,
|
||||
} from './types';
|
||||
|
||||
export class SubscribersService {
|
||||
private http: HttpClient;
|
||||
|
||||
constructor(http: HttpClient) {
|
||||
this.http = http;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all subscribers with pagination and filtering
|
||||
*/
|
||||
async listSubscribers(request?: ListSubscribersRequest): Promise<PaginatedResponse<Subscriber>> {
|
||||
const params = {
|
||||
page: request?.page || 1,
|
||||
pageSize: request?.pageSize || 20,
|
||||
status: request?.status,
|
||||
organizationId: request?.organizationId,
|
||||
search: request?.search,
|
||||
};
|
||||
|
||||
return this.http.get<PaginatedResponse<Subscriber>>('/api/subscribers', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific subscriber by ID
|
||||
*/
|
||||
async getSubscriber(id: number): Promise<Subscriber> {
|
||||
return this.http.get<Subscriber>(`/api/subscribers/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a subscriber by IMSI
|
||||
*/
|
||||
async getSubscriberByImsi(imsi: string): Promise<Subscriber> {
|
||||
return this.http.get<Subscriber>(`/api/subscribers/imsi/${imsi}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new subscriber
|
||||
*/
|
||||
async createSubscriber(request: CreateSubscriberRequest): Promise<Subscriber> {
|
||||
return this.http.post<Subscriber>('/api/subscribers', request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing subscriber
|
||||
*/
|
||||
async updateSubscriber(id: number, request: UpdateSubscriberRequest): Promise<Subscriber> {
|
||||
return this.http.put<Subscriber>(`/api/subscribers/${id}`, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a subscriber
|
||||
*/
|
||||
async deleteSubscriber(id: number): Promise<void> {
|
||||
await this.http.delete<void>(`/api/subscribers/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get subscriber account information
|
||||
*/
|
||||
async getSubscriberAccount(imsi: string): Promise<SubscriberAccount> {
|
||||
return this.http.get<SubscriberAccount>(`/api/subscribers/${imsi}/account`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Top up subscriber balance
|
||||
*/
|
||||
async topUpBalance(imsi: string, request: TopUpRequest): Promise<SubscriberAccount> {
|
||||
return this.http.post<SubscriberAccount>(`/api/subscribers/${imsi}/top-up`, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Suspend a subscriber
|
||||
*/
|
||||
async suspendSubscriber(id: number): Promise<Subscriber> {
|
||||
return this.http.post<Subscriber>(`/api/subscribers/${id}/suspend`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate a subscriber
|
||||
*/
|
||||
async activateSubscriber(id: number): Promise<Subscriber> {
|
||||
return this.http.post<Subscriber>(`/api/subscribers/${id}/activate`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate a subscriber
|
||||
*/
|
||||
async terminateSubscriber(id: number): Promise<Subscriber> {
|
||||
return this.http.post<Subscriber>(`/api/subscribers/${id}/terminate`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provision eSIM profile for subscriber
|
||||
*/
|
||||
async provisionESIM(imsi: string): Promise<{ profileId: string; activationCode: string }> {
|
||||
return this.http.post<{ profileId: string; activationCode: string }>(`/api/subscribers/${imsi}/esim/provision`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate eSIM profile
|
||||
*/
|
||||
async activateESIM(imsi: string, profileId: string): Promise<void> {
|
||||
return this.http.post<void>(`/api/subscribers/${imsi}/esim/activate`, { profileId });
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivate eSIM profile
|
||||
*/
|
||||
async deactivateESIM(imsi: string, profileId: string): Promise<void> {
|
||||
return this.http.post<void>(`/api/subscribers/${imsi}/esim/deactivate`, { profileId });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get eSIM profile status
|
||||
*/
|
||||
async getESIMStatus(imsi: string): Promise<ProfileStatus> {
|
||||
return this.http.get<ProfileStatus>(`/api/subscribers/${imsi}/esim/status`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get subscriber invoices
|
||||
*/
|
||||
async getInvoices(imsi: string, page = 1, pageSize = 20): Promise<PaginatedResponse<Invoice>> {
|
||||
return this.http.get<PaginatedResponse<Invoice>>(`/api/subscribers/${imsi}/invoices`, {
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get specific invoice
|
||||
*/
|
||||
async getInvoice(invoiceId: string): Promise<Invoice> {
|
||||
return this.http.get<Invoice>(`/api/invoices/${invoiceId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download invoice PDF
|
||||
*/
|
||||
async downloadInvoicePDF(invoiceId: string): Promise<Blob> {
|
||||
const response = await this.http.get(`/api/invoices/${invoiceId}/pdf`);
|
||||
return response as any; // Return blob for PDF download
|
||||
}
|
||||
|
||||
/**
|
||||
* Get subscriber usage statistics
|
||||
*/
|
||||
async getUsageStats(imsi: string, period: 'daily' | 'weekly' | 'monthly' = 'monthly'): Promise<{
|
||||
dataUsage: number;
|
||||
voiceUsage: number;
|
||||
smsUsage: number;
|
||||
cost: number;
|
||||
period: string;
|
||||
}> {
|
||||
return this.http.get(`/api/subscribers/${imsi}/usage/stats`, { period });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get real-time usage data
|
||||
*/
|
||||
async getRealTimeUsage(imsi: string): Promise<{
|
||||
currentSession: {
|
||||
sessionId: string;
|
||||
startTime: string;
|
||||
dataUsed: number;
|
||||
voiceUsed: number;
|
||||
smsUsed: number;
|
||||
cost: number;
|
||||
} | null;
|
||||
todayUsage: {
|
||||
dataUsed: number;
|
||||
voiceUsed: number;
|
||||
smsUsed: number;
|
||||
cost: number;
|
||||
};
|
||||
}> {
|
||||
return this.http.get(`/api/subscribers/${imsi}/usage/realtime`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
import { SDKConfig, TelecomSDKConfig } from './config';
|
||||
import { HttpClient } from './http-client';
|
||||
import { SubscribersService } from './subscribers';
|
||||
import { WebSocketClient, WebSocketEventHandler } from './websocket';
|
||||
import { SystemStats, HealthStatus, Alert, RealTimeUsageUpdate, WebSocketMessage } from './types';
|
||||
|
||||
export class TelecomSDK {
|
||||
private static instance: TelecomSDK;
|
||||
private http: HttpClient;
|
||||
private ws: WebSocketClient;
|
||||
private subscribers: SubscribersService;
|
||||
|
||||
private constructor() {
|
||||
this.http = new HttpClient();
|
||||
this.ws = new WebSocketClient();
|
||||
this.subscribers = new SubscribersService(this.http);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the SDK with configuration
|
||||
*/
|
||||
static initialize(config: TelecomSDKConfig): TelecomSDK {
|
||||
if (!TelecomSDK.instance) {
|
||||
SDKConfig.initialize(config);
|
||||
TelecomSDK.instance = new TelecomSDK();
|
||||
}
|
||||
return TelecomSDK.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton instance
|
||||
*/
|
||||
static getInstance(): TelecomSDK {
|
||||
if (!TelecomSDK.instance) {
|
||||
throw new Error('TelecomSDK not initialized. Call TelecomSDK.initialize() first.');
|
||||
}
|
||||
return TelecomSDK.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribers service
|
||||
*/
|
||||
get subscribersService(): SubscribersService {
|
||||
return this.subscribers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to WebSocket for real-time updates
|
||||
*/
|
||||
async connectWebSocket(): Promise<void> {
|
||||
await this.ws.connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from WebSocket
|
||||
*/
|
||||
disconnectWebSocket(): void {
|
||||
this.ws.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if WebSocket is connected
|
||||
*/
|
||||
get isWebSocketConnected(): boolean {
|
||||
return this.ws.isConnected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to real-time usage updates
|
||||
*/
|
||||
subscribeToUsage(imsi: string): void {
|
||||
this.ws.subscribeToUsage(imsi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from usage updates
|
||||
*/
|
||||
unsubscribeFromUsage(imsi: string): void {
|
||||
this.ws.unsubscribeFromUsage(imsi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to alerts
|
||||
*/
|
||||
subscribeToAlerts(): void {
|
||||
this.ws.subscribeToAlerts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from alerts
|
||||
*/
|
||||
unsubscribeFromAlerts(): void {
|
||||
this.ws.unsubscribeFromAlerts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add WebSocket event handler
|
||||
*/
|
||||
onWebSocketEvent(eventType: string, handler: WebSocketEventHandler): void {
|
||||
this.ws.on(eventType, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove WebSocket event handler
|
||||
*/
|
||||
offWebSocketEvent(eventType: string, handler: WebSocketEventHandler): void {
|
||||
this.ws.off(eventType, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get system statistics
|
||||
*/
|
||||
async getSystemStats(): Promise<SystemStats> {
|
||||
return this.http.get<SystemStats>('/api/system/stats');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get system health status
|
||||
*/
|
||||
async getHealthStatus(): Promise<HealthStatus> {
|
||||
return this.http.get<HealthStatus>('/api/system/health');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test API connection
|
||||
*/
|
||||
async testConnection(): Promise<{ status: string; timestamp: string }> {
|
||||
return this.http.get('/api/test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update API key
|
||||
*/
|
||||
setApiKey(apiKey: string): void {
|
||||
this.http.setApiKey(apiKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update base URL
|
||||
*/
|
||||
setBaseURL(baseURL: string): void {
|
||||
this.http.setBaseURL(baseURL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable logging
|
||||
*/
|
||||
setLogging(enabled: boolean): void {
|
||||
SDKConfig.getInstance().updateConfig({ enableLogging: enabled });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current configuration
|
||||
*/
|
||||
getConfig(): TelecomSDKConfig {
|
||||
const config = SDKConfig.getInstance();
|
||||
const result: TelecomSDKConfig = {
|
||||
baseURL: config.baseURL,
|
||||
timeout: config.timeout,
|
||||
retryAttempts: config.retryAttempts,
|
||||
retryDelay: config.retryDelay,
|
||||
enableLogging: config.enableLogging,
|
||||
};
|
||||
if (config.apiKey !== undefined) result.apiKey = config.apiKey;
|
||||
if (config.websocketURL !== undefined) result.websocketURL = config.websocketURL;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for usage updates
|
||||
*/
|
||||
onUsageUpdate(callback: (update: RealTimeUsageUpdate) => void): void {
|
||||
this.onWebSocketEvent('usage_update', (message: WebSocketMessage) => {
|
||||
callback(message.data as RealTimeUsageUpdate);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for alerts
|
||||
*/
|
||||
onAlert(callback: (alert: Alert) => void): void {
|
||||
this.onWebSocketEvent('alert', (message: WebSocketMessage) => {
|
||||
callback(message.data as Alert);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup resources
|
||||
*/
|
||||
destroy(): void {
|
||||
this.disconnectWebSocket();
|
||||
// Clear any other resources if needed
|
||||
}
|
||||
}
|
||||
|
||||
// Export types for external use
|
||||
export * from './types';
|
||||
export * from './config';
|
||||
export { WebSocketClient } from './websocket';
|
||||
export { HttpClient } from './http-client';
|
||||
export { SubscribersService } from './subscribers';
|
||||
@@ -0,0 +1,245 @@
|
||||
export interface Subscriber {
|
||||
id: number;
|
||||
imsi: string;
|
||||
msisdn: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string;
|
||||
organizationId?: string;
|
||||
planId: number;
|
||||
euiccId?: string;
|
||||
profileId?: string;
|
||||
profileStatus: ProfileStatus;
|
||||
status: SubscriberStatus;
|
||||
balance: number;
|
||||
dataLimit: number;
|
||||
dataUsed: number;
|
||||
voiceLimit: number;
|
||||
voiceUsed: number;
|
||||
smsLimit: number;
|
||||
smsUsed: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export enum SubscriberStatus {
|
||||
Active = 'active',
|
||||
Inactive = 'inactive',
|
||||
Suspended = 'suspended',
|
||||
Terminated = 'terminated',
|
||||
Provisioning = 'provisioning'
|
||||
}
|
||||
|
||||
export enum ProfileStatus {
|
||||
Active = 'active',
|
||||
Inactive = 'inactive',
|
||||
Downloading = 'downloading',
|
||||
Failed = 'failed'
|
||||
}
|
||||
|
||||
export interface CreateSubscriberRequest {
|
||||
msisdn: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string;
|
||||
organizationId?: string;
|
||||
planId: number;
|
||||
euiccId?: string;
|
||||
}
|
||||
|
||||
export interface UpdateSubscriberRequest {
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
email?: string;
|
||||
organizationId?: string;
|
||||
planId?: number;
|
||||
}
|
||||
|
||||
export interface SubscriberAccount {
|
||||
imsi: string;
|
||||
balance: number;
|
||||
dataLimit: number;
|
||||
dataUsed: number;
|
||||
voiceLimit: number;
|
||||
voiceUsed: number;
|
||||
smsLimit: number;
|
||||
smsUsed: number;
|
||||
status: SubscriberStatus;
|
||||
lastUpdated: string;
|
||||
}
|
||||
|
||||
export interface UsageEvent {
|
||||
imsi: string;
|
||||
sessionId: string;
|
||||
usageType: UsageType;
|
||||
volume: number;
|
||||
timestamp: string;
|
||||
rate: number;
|
||||
cost: number;
|
||||
}
|
||||
|
||||
export enum UsageType {
|
||||
Data = 'data',
|
||||
Voice = 'voice',
|
||||
SMS = 'sms'
|
||||
}
|
||||
|
||||
export interface RatingPlan {
|
||||
planId: string;
|
||||
name: string;
|
||||
dataRate: number;
|
||||
voiceRate: number;
|
||||
smsRate: number;
|
||||
monthlyFee: number;
|
||||
dataLimit: number;
|
||||
voiceLimit: number;
|
||||
smsLimit: number;
|
||||
}
|
||||
|
||||
export interface ChargingSession {
|
||||
sessionId: string;
|
||||
imsi: string;
|
||||
startTime: string;
|
||||
endTime?: string;
|
||||
dataBytes: number;
|
||||
voiceSeconds: number;
|
||||
smsCount: number;
|
||||
totalCost: number;
|
||||
status: SessionStatus;
|
||||
}
|
||||
|
||||
export enum SessionStatus {
|
||||
Active = 'active',
|
||||
Completed = 'completed',
|
||||
Terminated = 'terminated'
|
||||
}
|
||||
|
||||
export interface SystemStats {
|
||||
activeSessions: number;
|
||||
totalAccounts: number;
|
||||
blockedUsers: number;
|
||||
lowBalanceAlerts: number;
|
||||
uptime: number;
|
||||
}
|
||||
|
||||
export interface HealthStatus {
|
||||
redisConnected: boolean;
|
||||
activeSync: boolean;
|
||||
lastSync: string;
|
||||
memoryUsage: number;
|
||||
}
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
data: T;
|
||||
message: string;
|
||||
success: boolean;
|
||||
code: number;
|
||||
}
|
||||
|
||||
export interface PaginatedResponse<T> {
|
||||
data: T[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
totalPages: number;
|
||||
}
|
||||
|
||||
export interface ListSubscribersRequest {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
status?: SubscriberStatus;
|
||||
organizationId?: string;
|
||||
search?: string;
|
||||
}
|
||||
|
||||
export interface TopUpRequest {
|
||||
amount: number;
|
||||
paymentMethodId?: string;
|
||||
}
|
||||
|
||||
export interface PaymentMethod {
|
||||
id: string;
|
||||
type: PaymentMethodType;
|
||||
last4: string;
|
||||
expiryMonth: number;
|
||||
expiryYear: number;
|
||||
brand: string;
|
||||
isDefault: boolean;
|
||||
}
|
||||
|
||||
export enum PaymentMethodType {
|
||||
CreditCard = 'credit_card',
|
||||
BankAccount = 'bank_account'
|
||||
}
|
||||
|
||||
export interface Invoice {
|
||||
id: string;
|
||||
subscriberId: number;
|
||||
amount: number;
|
||||
currency: string;
|
||||
status: InvoiceStatus;
|
||||
dueDate: string;
|
||||
createdAt: string;
|
||||
lineItems: InvoiceLineItem[];
|
||||
}
|
||||
|
||||
export enum InvoiceStatus {
|
||||
Draft = 'draft',
|
||||
Pending = 'pending',
|
||||
Paid = 'paid',
|
||||
Overdue = 'overdue',
|
||||
Cancelled = 'cancelled'
|
||||
}
|
||||
|
||||
export interface InvoiceLineItem {
|
||||
description: string;
|
||||
quantity: number;
|
||||
unitPrice: number;
|
||||
amount: number;
|
||||
}
|
||||
|
||||
export interface WebSocketMessage {
|
||||
type: string;
|
||||
data: any;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
export interface RealTimeUsageUpdate {
|
||||
imsi: string;
|
||||
dataUsed: number;
|
||||
voiceUsed: number;
|
||||
smsUsed: number;
|
||||
cost: number;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
export interface Alert {
|
||||
id: string;
|
||||
type: AlertType;
|
||||
severity: AlertSeverity;
|
||||
message: string;
|
||||
subscriberId?: number;
|
||||
timestamp: string;
|
||||
resolved: boolean;
|
||||
}
|
||||
|
||||
export enum AlertType {
|
||||
LowBalance = 'low_balance',
|
||||
HighUsage = 'high_usage',
|
||||
PaymentFailed = 'payment_failed',
|
||||
SystemError = 'system_error'
|
||||
}
|
||||
|
||||
export enum AlertSeverity {
|
||||
Low = 'low',
|
||||
Medium = 'medium',
|
||||
High = 'high',
|
||||
Critical = 'critical'
|
||||
}
|
||||
|
||||
export interface Error {
|
||||
code: string;
|
||||
message: string;
|
||||
details?: any;
|
||||
timestamp: string;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "commonjs",
|
||||
"lib": ["ES2020", "DOM"],
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"removeComments": false,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"exactOptionalPropertyTypes": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"**/*.test.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user