mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-18 11:02:54 +00:00
docs: Update TypeScript SDK README with new API structure and improve authentication implementation
- Update README to reflect new modular API structure (subscribers, usage, payments, ratingPlans, system, graphql modules) - Add Architecture section documenting SDK module organization - Update all code examples to use new API module paths (sdk.subscribers instead of sdk.subscribersService) - Remove deprecated methods (getSubscriberByImsi, terminateSubscriber, eSIM management, billing/invoices) - Add GraphQL query execution examples - Simplify usage examples to focus
This commit is contained in:
+84
-51
@@ -2,6 +2,22 @@
|
||||
|
||||
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.
|
||||
|
||||
## Architecture
|
||||
|
||||
The SDK is organized into modular components:
|
||||
|
||||
- `auth.ts` - Authentication provider handling API keys and JWT tokens
|
||||
- `api/` - Directory containing API modules:
|
||||
- `http-client.ts` - HTTP client with retry logic
|
||||
- `subscribers.ts` - Subscriber management API
|
||||
- `usage.ts` - Usage tracking API
|
||||
- `payments.ts` - Payment processing API
|
||||
- `rating-plans.ts` - Rating plan management API
|
||||
- `system.ts` - System monitoring API
|
||||
- `graphql.ts` - GraphQL query execution
|
||||
- `websocket.ts` - WebSocket client for real-time updates
|
||||
- `types.ts` - Type definitions and interfaces
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
@@ -74,22 +90,17 @@ const sdk = TelecomSDK.initialize({
|
||||
|
||||
```typescript
|
||||
// List subscribers
|
||||
const subscribers = await sdk.subscribersService.listSubscribers({
|
||||
const subscribers = await sdk.subscribers.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');
|
||||
const subscriber = await sdk.subscribers.getSubscriber(123);
|
||||
|
||||
// Create new subscriber
|
||||
const newSubscriber = await sdk.subscribersService.createSubscriber({
|
||||
const newSubscriber = await sdk.subscribers.createSubscriber({
|
||||
msisdn: '+1234567890',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
@@ -98,70 +109,96 @@ const newSubscriber = await sdk.subscribersService.createSubscriber({
|
||||
});
|
||||
|
||||
// Update subscriber
|
||||
const updated = await sdk.subscribersService.updateSubscriber(123, {
|
||||
const updated = await sdk.subscribers.updateSubscriber(123, {
|
||||
firstName: 'Jane',
|
||||
email: '[email protected]',
|
||||
});
|
||||
|
||||
// Delete subscriber
|
||||
await sdk.subscribersService.deleteSubscriber(123);
|
||||
await sdk.subscribers.deleteSubscriber(123);
|
||||
|
||||
// Suspend subscriber
|
||||
await sdk.subscribersService.suspendSubscriber(123);
|
||||
await sdk.subscribers.suspendSubscriber(123);
|
||||
|
||||
// Activate subscriber
|
||||
await sdk.subscribersService.activateSubscriber(123);
|
||||
|
||||
// Terminate subscriber
|
||||
await sdk.subscribersService.terminateSubscriber(123);
|
||||
await sdk.subscribers.activateSubscriber(123);
|
||||
```
|
||||
|
||||
### Account Management
|
||||
### Usage Management
|
||||
|
||||
```typescript
|
||||
// Get subscriber account
|
||||
const account = await sdk.subscribersService.getSubscriberAccount('123456789012345');
|
||||
// Get usage stats
|
||||
const stats = await sdk.usage.getStats(1, '2024-01-01', '2024-01-31');
|
||||
|
||||
// Top up balance
|
||||
const updatedAccount = await sdk.subscribersService.topUpBalance('123456789012345', {
|
||||
amount: 1000, // $10.00 in cents
|
||||
paymentMethodId: 'pm_123',
|
||||
// List usage events
|
||||
const events = await sdk.usage.listEvents({
|
||||
subscriberId: 1,
|
||||
usageType: 'data',
|
||||
page: 1,
|
||||
pageSize: 50,
|
||||
});
|
||||
|
||||
// Get usage statistics
|
||||
const stats = await sdk.subscribersService.getUsageStats('123456789012345', 'monthly');
|
||||
|
||||
// Get real-time usage
|
||||
const realtime = await sdk.subscribersService.getRealTimeUsage('123456789012345');
|
||||
const realtime = await sdk.usage.getRealTimeUsage(1);
|
||||
```
|
||||
|
||||
### eSIM Management
|
||||
### Payment Management
|
||||
|
||||
```typescript
|
||||
// Provision eSIM profile
|
||||
const esim = await sdk.subscribersService.provisionESIM('123456789012345');
|
||||
// Create payment transaction
|
||||
const transaction = await sdk.payments.createTransaction({
|
||||
subscriberId: 1,
|
||||
amount: 25.00,
|
||||
currency: 'USD',
|
||||
gateway: 'stripe',
|
||||
metadata: { description: 'Monthly plan' }
|
||||
});
|
||||
|
||||
// Activate eSIM profile
|
||||
await sdk.subscribersService.activateESIM('123456789012345', esim.profileId);
|
||||
// Get transaction
|
||||
const transaction = await sdk.payments.getTransaction('txn-123');
|
||||
|
||||
// Deactivate eSIM profile
|
||||
await sdk.subscribersService.deactivateESIM('123456789012345', esim.profileId);
|
||||
|
||||
// Get eSIM status
|
||||
const status = await sdk.subscribersService.getESIMStatus('123456789012345');
|
||||
// List transactions
|
||||
const transactions = await sdk.payments.listTransactions({
|
||||
subscriberId: 1,
|
||||
status: 'completed',
|
||||
page: 1,
|
||||
pageSize: 50,
|
||||
});
|
||||
```
|
||||
|
||||
### Billing & Invoices
|
||||
### Rating Plans
|
||||
|
||||
```typescript
|
||||
// Get subscriber invoices
|
||||
const invoices = await sdk.subscribersService.getInvoices('123456789012345');
|
||||
// List rating plans
|
||||
const plans = await sdk.ratingPlans.list();
|
||||
|
||||
// Get specific invoice
|
||||
const invoice = await sdk.subscribersService.getInvoice('inv_123');
|
||||
// Get specific plan
|
||||
const plan = await sdk.ratingPlans.get('plan-123');
|
||||
```
|
||||
|
||||
// Download invoice PDF
|
||||
const pdfBlob = await sdk.subscribersService.downloadInvoicePDF('inv_123');
|
||||
### System Management
|
||||
|
||||
```typescript
|
||||
// Get system stats
|
||||
const stats = await sdk.system.getStats();
|
||||
|
||||
// Get health status
|
||||
const health = await sdk.system.getHealth();
|
||||
```
|
||||
|
||||
### GraphQL
|
||||
|
||||
```typescript
|
||||
// Execute GraphQL query
|
||||
const result = await sdk.graphql.execute(`
|
||||
query GetSubscribers($first: Int) {
|
||||
subscribers(first: $first) {
|
||||
id
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
}
|
||||
`, { first: 10 });
|
||||
```
|
||||
|
||||
### Real-time Updates
|
||||
@@ -208,17 +245,13 @@ sdk.disconnectWebSocket();
|
||||
|
||||
```typescript
|
||||
// Get system statistics
|
||||
const stats = await sdk.getSystemStats();
|
||||
const stats = await sdk.system.getStats();
|
||||
console.log('Active sessions:', stats.activeSessions);
|
||||
console.log('Total accounts:', stats.totalAccounts);
|
||||
|
||||
// Get health status
|
||||
const health = await sdk.getHealthStatus();
|
||||
const health = await sdk.system.getHealth();
|
||||
console.log('Redis connected:', health.redisConnected);
|
||||
|
||||
// Test connection
|
||||
const test = await sdk.testConnection();
|
||||
console.log('API status:', test.status);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
@@ -227,7 +260,7 @@ The SDK provides comprehensive error handling with detailed error information:
|
||||
|
||||
```typescript
|
||||
try {
|
||||
const subscriber = await sdk.subscribersService.getSubscriber(123);
|
||||
const subscriber = await sdk.subscribers.getSubscriber(123);
|
||||
} catch (error) {
|
||||
console.error('Error:', error.code);
|
||||
console.error('Message:', error.message);
|
||||
@@ -263,7 +296,7 @@ The SDK is fully typed with TypeScript. All methods have proper type definitions
|
||||
import { Subscriber, SubscriberStatus, UsageType } from '@telecom-platform/sdk';
|
||||
|
||||
// Types are automatically inferred
|
||||
const subscriber: Subscriber = await sdk.subscribersService.getSubscriber(123);
|
||||
const subscriber: Subscriber = await sdk.subscribers.getSubscriber(123);
|
||||
const status: SubscriberStatus = subscriber.status;
|
||||
```
|
||||
|
||||
|
||||
+132
-19
@@ -112,11 +112,14 @@ export class AuthProvider {
|
||||
return this.tokenExpiry > Math.floor(Date.now() / 1000);
|
||||
}
|
||||
|
||||
private base64UrlEncode(str: string): string {
|
||||
return btoa(str)
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=+$/, '');
|
||||
private base64UrlEncode(data: string | Uint8Array): string {
|
||||
let binary: string;
|
||||
if (typeof data === 'string') {
|
||||
binary = btoa(data);
|
||||
} else {
|
||||
binary = btoa(String.fromCharCode(...data));
|
||||
}
|
||||
return binary.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
||||
}
|
||||
|
||||
private base64UrlDecode(str: string): string {
|
||||
@@ -128,22 +131,132 @@ export class AuthProvider {
|
||||
}
|
||||
|
||||
private sign(data: string, secret: string): string {
|
||||
// Simple HMAC-SHA256 implementation
|
||||
// In production, use a proper crypto library like crypto-js or Web Crypto API
|
||||
const hmac = this.simpleHMACSHA256(data, secret);
|
||||
return this.base64UrlEncode(hmac);
|
||||
// HMAC-SHA256 implementation
|
||||
// In production, use crypto-js: import CryptoJS from 'crypto-js';
|
||||
// const hash = CryptoJS.HmacSHA256(data, secret).toString(CryptoJS.enc.Base64);
|
||||
// For SDK compatibility without external dependencies, using reference implementation
|
||||
return this.syncHMACSHA256(data, secret);
|
||||
}
|
||||
|
||||
private simpleHMACSHA256(message: string, key: string): string {
|
||||
// This is a simplified implementation for demonstration
|
||||
// In production, use a proper crypto library
|
||||
let hash = 0;
|
||||
const str = message + key;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + char;
|
||||
hash = hash & hash;
|
||||
private syncHMACSHA256(message: string, key: string): string {
|
||||
// HMAC-SHA256 implementation for environments without crypto support
|
||||
// This is a reference implementation - in production use crypto-js or similar
|
||||
const encoder = new TextEncoder();
|
||||
const keyBytes = encoder.encode(key);
|
||||
const messageBytes = encoder.encode(message);
|
||||
|
||||
// Pad key to 64 bytes (block size for SHA-256)
|
||||
const block = 64;
|
||||
const paddedKey = new Uint8Array(block);
|
||||
paddedKey.set(keyBytes.slice(0, block));
|
||||
|
||||
// XOR with inner pad (0x36) and outer pad (0x5c)
|
||||
const innerPad = new Uint8Array(block);
|
||||
const outerPad = new Uint8Array(block);
|
||||
for (let i = 0; i < block; i++) {
|
||||
innerPad[i] = paddedKey[i] ^ 0x36;
|
||||
outerPad[i] = paddedKey[i] ^ 0x5c;
|
||||
}
|
||||
return Math.abs(hash).toString(16).padStart(64, '0');
|
||||
|
||||
// Inner hash: H((K ^ ipad) || message)
|
||||
const innerCombined = new Uint8Array(block + messageBytes.length);
|
||||
innerCombined.set(innerPad);
|
||||
innerCombined.set(messageBytes, block);
|
||||
const innerHash = this.sha256(innerCombined);
|
||||
|
||||
// Outer hash: H((K ^ opad) || inner_hash)
|
||||
const outerCombined = new Uint8Array(block + innerHash.length);
|
||||
outerCombined.set(outerPad);
|
||||
outerCombined.set(innerHash, block);
|
||||
const result = this.sha256(outerCombined);
|
||||
|
||||
return this.base64UrlEncode(result);
|
||||
}
|
||||
|
||||
private sha256(data: Uint8Array): Uint8Array {
|
||||
// SHA-256 implementation
|
||||
// In production, use a proper crypto library
|
||||
// This is a reference implementation
|
||||
const h = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19];
|
||||
|
||||
// Pad data
|
||||
const len = data.length * 8;
|
||||
const k = Math.ceil((len + 65) / 512) * 512;
|
||||
const padded = new Uint8Array(k / 8);
|
||||
padded.set(data);
|
||||
padded[data.length] = 0x80;
|
||||
|
||||
const view = new DataView(padded.buffer);
|
||||
view.setUint32(padded.length - 4, Math.floor(len / 0x100000000), true);
|
||||
view.setUint32(padded.length - 8, len >>> 0, true);
|
||||
|
||||
// Process blocks (simplified - in production use proper implementation)
|
||||
for (let i = 0; i < padded.length; i += 64) {
|
||||
const w = new Uint32Array(64);
|
||||
for (let j = 0; j < 16; j++) {
|
||||
w[j] = view.getUint32(i + j * 4, true);
|
||||
}
|
||||
|
||||
let [a, b, c, d, e, f, g, hVal] = h;
|
||||
|
||||
for (let j = 0; j < 64; j++) {
|
||||
if (j >= 16) {
|
||||
w[j] = this.sigma1(w[j - 2]) + w[j - 7] + this.sigma0(w[j - 15]) + w[j - 16];
|
||||
}
|
||||
const t1 = hVal + this.ep1(e) + this.ch(e, f, g) + this.k[j] + w[j];
|
||||
const t2 = this.ep0(a) + this.maj(a, b, c);
|
||||
[hVal, g, f, e, d, c, b, a] = [g, f, e, d + t1, c, b, a, t1 + t2];
|
||||
}
|
||||
|
||||
h[0] += a; h[1] += b; h[2] += c; h[3] += d;
|
||||
h[4] += e; h[5] += f; h[6] += g; h[7] += hVal;
|
||||
}
|
||||
|
||||
const result = new Uint8Array(32);
|
||||
const resultView = new DataView(result.buffer);
|
||||
for (let i = 0; i < 8; i++) {
|
||||
resultView.setUint32(i * 4, h[i], true);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private rotr(x: number, n: number): number {
|
||||
return (x >>> n) | (x << (32 - n));
|
||||
}
|
||||
|
||||
private ep0(x: number): number {
|
||||
return this.rotr(x, 2) ^ this.rotr(x, 13) ^ this.rotr(x, 22);
|
||||
}
|
||||
|
||||
private ep1(x: number): number {
|
||||
return this.rotr(x, 6) ^ this.rotr(x, 11) ^ this.rotr(x, 25);
|
||||
}
|
||||
|
||||
private sigma0(x: number): number {
|
||||
return this.rotr(x, 7) ^ this.rotr(x, 18) ^ (x >>> 3);
|
||||
}
|
||||
|
||||
private sigma1(x: number): number {
|
||||
return this.rotr(x, 17) ^ this.rotr(x, 19) ^ (x >>> 10);
|
||||
}
|
||||
|
||||
private ch(x: number, y: number, z: number): number {
|
||||
return (x & y) ^ (~x & z);
|
||||
}
|
||||
|
||||
private maj(x: number, y: number, z: number): number {
|
||||
return (x & y) ^ (x & z) ^ (y & z);
|
||||
}
|
||||
|
||||
private k = [
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user