@k-msg/core 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # @k-msg/core
2
2
 
3
- The foundational package of the K-Message platform, providing essential types, error handling, retry mechanisms, and platform interfaces for Korean multi-channel messaging.
3
+ Core types and utilities for the `k-msg` ecosystem.
4
+
5
+ This package intentionally stays low-level:
6
+
7
+ - Standard message model: `MessageType`, `SendInput`, `SendOptions`, `SendResult`
8
+ - Provider interface: `Provider`
9
+ - Result pattern: `Result`, `ok`, `fail`
10
+ - Errors: `KMsgError`, `KMsgErrorCode`
11
+ - Resilience helpers: retry / circuit-breaker / rate-limit / health monitor
12
+
13
+ If you want the end-user "send" experience, use `KMsg` from `@k-msg/messaging` (or `k-msg`).
4
14
 
5
15
  ## Installation
6
16
 
@@ -10,300 +20,54 @@ npm install @k-msg/core
10
20
  bun add @k-msg/core
11
21
  ```
12
22
 
13
- ## Features
14
-
15
- ### 🏗️ **Core Platform Interface**
16
- - **AlimTalkPlatform**: Unified messaging platform abstraction
17
- - **Provider Management**: Multi-provider support and switching
18
- - **Feature Flags**: Configurable platform capabilities
19
-
20
- ### 🔁 **Provider Rotation**
21
- - **RoundRobinRouterProvider**: Rotate across multiple upstream providers (round-robin)
22
-
23
- ### ⚠️ **Comprehensive Error Handling**
24
- - **KMessageError Hierarchy**: Structured error types for different scenarios
25
- - **Error Context**: Rich error information with operation context
26
- - **Error Recovery**: Built-in fallback and recovery strategies
27
-
28
- ### 🔄 **Retry & Resilience**
29
- - **Exponential Backoff**: Smart retry with increasing delays
30
- - **Circuit Breaker**: Automatic failure protection
31
- - **Jitter**: Randomized delays to prevent thundering herd
32
-
33
- ### 💊 **Health Monitoring**
34
- - **System Health Checks**: Multi-component health validation
35
- - **Service Discovery**: Dynamic provider health monitoring
36
- - **Dependency Tracking**: External service availability checks
37
-
38
- ## Quick Start
39
-
40
- ### Basic Platform Setup
41
-
42
- ```typescript
43
- import { AlimTalkPlatform } from '@k-msg/core';
44
-
45
- const platform = new AlimTalkPlatform({
46
- providers: ['iwinv'],
47
- defaultProvider: 'iwinv',
48
- features: {
49
- enableBulkSending: true,
50
- enableScheduling: true,
51
- enableAnalytics: true
23
+ ## Example: Implement a Provider
24
+
25
+ ```ts
26
+ import {
27
+ fail,
28
+ KMsgError,
29
+ KMsgErrorCode,
30
+ ok,
31
+ type MessageType,
32
+ type Provider,
33
+ type ProviderHealthStatus,
34
+ type Result,
35
+ type SendOptions,
36
+ type SendResult,
37
+ } from "@k-msg/core";
38
+
39
+ export class MyProvider implements Provider {
40
+ readonly id = "my-provider";
41
+ readonly name = "My Provider";
42
+ readonly supportedTypes: readonly MessageType[] = ["SMS"];
43
+
44
+ async healthCheck(): Promise<ProviderHealthStatus> {
45
+ return { healthy: true, issues: [] };
52
46
  }
53
- });
54
-
55
- // Get platform capabilities
56
- const info = platform.getInfo();
57
- console.log(`Platform: ${info.name}, Version: ${info.version}`);
58
- console.log(`Supported providers: ${info.supportedProviders.join(', ')}`);
59
-
60
- // Perform comprehensive health check
61
- const health = await platform.healthCheck();
62
- console.log(`Health: ${health.status}, Services: ${Object.keys(health.services).length}`);
63
- ```
64
-
65
- ### Round-robin Provider Rotation
66
-
67
- ```typescript
68
- import { RoundRobinRouterProvider, type BaseProvider } from "@k-msg/core";
69
-
70
- const router = new RoundRobinRouterProvider({
71
- id: "router",
72
- providers: [providerA, providerB] satisfies BaseProvider[],
73
- });
74
-
75
- await router.send({
76
- channel: "SMS",
77
- templateCode: "SMS_DIRECT",
78
- phoneNumber: "01012345678",
79
- variables: {},
80
- text: "hello",
81
- });
82
- ```
83
47
 
84
- ### Error Handling Patterns
85
-
86
- ```typescript
87
- import { KMessageError, KMessageErrorCode, Result } from '@k-msg/core';
88
-
89
- // Method 1: Result Pattern (Recommended)
90
- const result = await Result.fromPromise(
91
- provider.sendMessage(message)
92
- );
93
-
94
- if (result.isSuccess) {
95
- console.log(`Message sent: ${result.data.messageId}`);
96
- } else {
97
- console.error(`Send failed: ${result.error.message}`);
98
-
99
- // Handle specific error types
100
- if (result.error.code === KMessageErrorCode.PROVIDER_TIMEOUT) {
101
- // Retry with different provider
102
- } else if (result.error.code === KMessageErrorCode.TEMPLATE_NOT_FOUND) {
103
- // Create template or use fallback
104
- }
105
- }
106
-
107
- // Method 2: Try-Catch with Structured Errors
108
- try {
109
- const response = await provider.sendMessage(message);
110
- console.log('Success:', response);
111
- } catch (error) {
112
- if (error instanceof KMessageError) {
113
- console.error(`[${error.code}] ${error.message}`);
114
- console.error('Context:', error.context);
115
-
116
- // Access original cause if available
117
- if (error.cause) {
118
- console.error('Root cause:', error.cause);
48
+ async send(options: SendOptions): Promise<Result<SendResult, KMsgError>> {
49
+ const messageId = options.messageId || crypto.randomUUID();
50
+
51
+ if (options.type !== "SMS") {
52
+ return fail(
53
+ new KMsgError(
54
+ KMsgErrorCode.INVALID_REQUEST,
55
+ `Unsupported type: ${options.type}`,
56
+ { providerId: this.id, type: options.type },
57
+ ),
58
+ );
119
59
  }
120
- } else {
121
- // Handle unexpected errors
122
- console.error('Unexpected error:', error);
123
- }
124
- }
125
- ```
126
-
127
- ### Retry Configuration
128
-
129
- ```typescript
130
- import { RetryManager, RetryConfig } from '@k-msg/core';
131
-
132
- // Custom retry configuration
133
- const retryConfig: RetryConfig = {
134
- maxAttempts: 3,
135
- baseDelay: 1000, // 1 second
136
- maxDelay: 10000, // 10 seconds
137
- backoffMultiplier: 2,
138
- jitterType: 'full', // full, half, none
139
- retryableErrors: [
140
- KMessageErrorCode.NETWORK_ERROR,
141
- KMessageErrorCode.PROVIDER_TIMEOUT,
142
- KMessageErrorCode.RATE_LIMIT_EXCEEDED
143
- ]
144
- };
145
-
146
- const retryManager = new RetryManager(retryConfig);
147
-
148
- // Execute with retry
149
- const result = await retryManager.execute(async () => {
150
- return await provider.sendMessage(message);
151
- });
152
- ```
153
-
154
- ### Health Check Implementation
155
-
156
- ```typescript
157
- import { HealthChecker, HealthStatus } from '@k-msg/core';
158
-
159
- const healthChecker = new HealthChecker();
160
-
161
- // Register custom health checks
162
- healthChecker.register('database', async () => {
163
- const connected = await checkDatabaseConnection();
164
- return {
165
- status: connected ? HealthStatus.HEALTHY : HealthStatus.UNHEALTHY,
166
- details: { connected, lastCheck: new Date() }
167
- };
168
- });
169
60
 
170
- healthChecker.register('external-api', async () => {
171
- const responseTime = await measureApiResponseTime();
172
- return {
173
- status: responseTime < 1000 ? HealthStatus.HEALTHY : HealthStatus.DEGRADED,
174
- details: { responseTime, threshold: 1000 }
175
- };
176
- });
61
+ // ... send SMS here ...
177
62
 
178
- // Perform comprehensive health check
179
- const overallHealth = await healthChecker.checkAll();
180
- console.log(`Overall status: ${overallHealth.status}`);
181
- console.log(`Healthy services: ${overallHealth.healthyCount}/${overallHealth.totalCount}`);
182
- ```
183
-
184
- ## API Reference
185
-
186
- ### Core Types
187
-
188
- ```typescript
189
- // Platform configuration
190
- interface AlimTalkPlatformConfig {
191
- providers: string[];
192
- defaultProvider: string;
193
- features: PlatformFeatures;
194
- retryConfig?: RetryConfig;
195
- healthCheckConfig?: HealthCheckConfig;
196
- }
197
-
198
- // Error types
199
- enum KMessageErrorCode {
200
- UNKNOWN = 'UNKNOWN',
201
- NETWORK_ERROR = 'NETWORK_ERROR',
202
- PROVIDER_ERROR = 'PROVIDER_ERROR',
203
- TEMPLATE_ERROR = 'TEMPLATE_ERROR',
204
- VALIDATION_ERROR = 'VALIDATION_ERROR',
205
- RATE_LIMIT_EXCEEDED = 'RATE_LIMIT_EXCEEDED',
206
- // ... more error codes
207
- }
208
-
209
- // Health check results
210
- interface HealthCheckResult {
211
- status: HealthStatus;
212
- services: Record<string, ServiceHealthInfo>;
213
- timestamp: Date;
214
- totalChecks: number;
215
- passedChecks: number;
216
- }
217
- ```
218
-
219
- ### Test Utilities
220
-
221
- ```typescript
222
- import { TestData, TestAssertions } from '@k-msg/core/test-utils';
223
-
224
- // Generate test data
225
- const testMessage = TestData.createMessage({
226
- provider: 'iwinv',
227
- templateCode: 'AUTH_OTP',
228
- phoneNumber: '01012345678'
229
- });
230
-
231
- // Test assertions
232
- await TestAssertions.assertMessageSent(result);
233
- TestAssertions.assertErrorType(error, KMessageErrorCode.TEMPLATE_NOT_FOUND);
234
- ```
235
-
236
- ## Advanced Usage
237
-
238
- ### Custom Error Types
239
-
240
- ```typescript
241
- import { KMessageError, KMessageErrorCode } from '@k-msg/core';
242
-
243
- class CustomProviderError extends KMessageError {
244
- constructor(
245
- message: string,
246
- public readonly providerId: string,
247
- cause?: Error
248
- ) {
249
- super(
250
- message,
251
- KMessageErrorCode.PROVIDER_ERROR,
252
- { operation: 'send_message', provider: providerId },
253
- cause
254
- );
255
- }
256
- }
257
- ```
258
-
259
- ### Plugin Integration
260
-
261
- ```typescript
262
- import { AlimTalkPlatform, PlatformPlugin } from '@k-msg/core';
263
-
264
- class LoggingPlugin implements PlatformPlugin {
265
- name = 'logging';
266
-
267
- async initialize(platform: AlimTalkPlatform) {
268
- platform.on('message_sent', (event) => {
269
- console.log(`Message sent: ${event.messageId}`);
270
- });
271
-
272
- platform.on('error', (event) => {
273
- console.error(`Error: ${event.error.message}`);
63
+ return ok({
64
+ messageId,
65
+ providerId: this.id,
66
+ status: "SENT",
67
+ type: options.type,
68
+ to: options.to,
274
69
  });
275
70
  }
276
71
  }
277
-
278
- const platform = new AlimTalkPlatform(config);
279
- await platform.use(new LoggingPlugin());
280
72
  ```
281
73
 
282
- ## Best Practices
283
-
284
- 1. **Always use Result pattern** for error handling in production code
285
- 2. **Configure retries** appropriately for your use case
286
- 3. **Implement health checks** for all external dependencies
287
- 4. **Use structured logging** with error context information
288
- 5. **Monitor error rates** and adjust retry policies accordingly
289
-
290
- ## Testing
291
-
292
- ```bash
293
- # Run unit tests
294
- bun test
295
-
296
- # Run with coverage
297
- bun test --coverage
298
-
299
- # Run specific test files
300
- bun test retry.test.ts
301
- ```
302
-
303
- ## Contributing
304
-
305
- See the main [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines.
306
-
307
- ## License
308
-
309
- MIT License - see [LICENSE](../../LICENSE) for details.
package/dist/index.d.ts CHANGED
@@ -2,12 +2,8 @@ export * from "./config";
2
2
  export * from "./errors";
3
3
  export * from "./health";
4
4
  export * from "./logger";
5
- export * from "./platform";
6
5
  export * from "./provider";
7
- export * from "./provider-registry";
8
6
  export * from "./resilience/index";
9
7
  export * from "./result";
10
- export * from "./router/round-robin-router-provider";
11
8
  export * from "./test-utils";
12
9
  export * from "./types/index";
13
- export * from "./universal-provider";