@k-msg/core 0.24.0 → 0.25.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.
@@ -1,56 +1,123 @@
1
1
  import type { KMsgError } from "./errors";
2
2
  import type { Result } from "./result";
3
3
  import type { BalanceQuery, BalanceResult, DeliveryStatusQuery, DeliveryStatusResult, KakaoChannel, KakaoChannelCategories, MessageType, ProviderOnboardingSpec, SendOptions, SendResult } from "./types/index";
4
+ /**
5
+ * Represents an AlimTalk template registered with a provider.
6
+ * Templates must be approved by Kakao before use.
7
+ */
4
8
  export interface Template {
9
+ /** Unique template identifier. */
5
10
  id: string;
11
+ /** Template code used in send requests. */
6
12
  code: string;
13
+ /** Human-readable template name. */
7
14
  name: string;
15
+ /** Template body with #{variable} placeholders. */
8
16
  content: string;
17
+ /** Template category (e.g., "authentication", "promotion"). */
9
18
  category?: string;
19
+ /** Approval status of the template. */
10
20
  status: "APPROVED" | "REJECTED" | "PENDING" | "INSPECTION";
21
+ /** Button configurations attached to the template. */
11
22
  buttons?: unknown[];
23
+ /** Names of variables expected in the template content. */
12
24
  variables?: string[];
25
+ /** When the template was created. */
13
26
  createdAt: Date;
27
+ /** When the template was last updated. */
14
28
  updatedAt: Date;
15
29
  }
30
+ /**
31
+ * Input for creating a new AlimTalk template.
32
+ */
16
33
  export type TemplateCreateInput = {
34
+ /** Human-readable template name. */
17
35
  name: string;
36
+ /** Template body with #{variable} placeholders. */
18
37
  content: string;
38
+ /** Template category. */
19
39
  category?: string;
40
+ /** Button configurations. */
20
41
  buttons?: unknown[];
42
+ /** Expected variable names in the template. */
21
43
  variables?: string[];
22
44
  };
45
+ /**
46
+ * Partial input for updating an existing template.
47
+ */
23
48
  export type TemplateUpdateInput = Partial<TemplateCreateInput>;
49
+ /**
50
+ * Context passed to template operations.
51
+ */
24
52
  export type TemplateContext = {
25
53
  /**
26
54
  * Provider-specific Kakao channel key (e.g. Aligo senderKey).
27
55
  */
28
56
  kakaoChannelSenderKey?: string;
29
57
  };
58
+ /**
59
+ * Interface for providers that support AlimTalk template management.
60
+ */
30
61
  export interface TemplateProvider {
62
+ /**
63
+ * Create a new template.
64
+ */
31
65
  createTemplate(input: TemplateCreateInput, ctx?: TemplateContext): Promise<Result<Template, KMsgError>>;
66
+ /**
67
+ * Update an existing template by code.
68
+ */
32
69
  updateTemplate(code: string, patch: TemplateUpdateInput, ctx?: TemplateContext): Promise<Result<Template, KMsgError>>;
70
+ /**
71
+ * Delete a template by code.
72
+ */
33
73
  deleteTemplate(code: string, ctx?: TemplateContext): Promise<Result<void, KMsgError>>;
74
+ /**
75
+ * Get a template by code.
76
+ */
34
77
  getTemplate(code: string, ctx?: TemplateContext): Promise<Result<Template, KMsgError>>;
78
+ /**
79
+ * List templates with optional filtering and pagination.
80
+ */
35
81
  listTemplates(params?: {
36
82
  status?: string;
37
83
  page?: number;
38
84
  limit?: number;
39
85
  }, ctx?: TemplateContext): Promise<Result<Template[], KMsgError>>;
40
86
  }
87
+ /**
88
+ * Interface for providers that support requesting template inspection.
89
+ */
41
90
  export interface TemplateInspectionProvider {
91
+ /**
92
+ * Request inspection for a template (submits for approval review).
93
+ */
42
94
  requestTemplateInspection(code: string, ctx?: TemplateContext): Promise<Result<void, KMsgError>>;
43
95
  }
96
+ /**
97
+ * Interface for providers that support Kakao channel management.
98
+ */
44
99
  export interface KakaoChannelProvider {
100
+ /**
101
+ * List registered Kakao channels.
102
+ */
45
103
  listKakaoChannels(params?: {
46
104
  plusId?: string;
47
105
  senderKey?: string;
48
106
  }): Promise<Result<KakaoChannel[], KMsgError>>;
107
+ /**
108
+ * List available channel categories for registration.
109
+ */
49
110
  listKakaoChannelCategories?(): Promise<Result<KakaoChannelCategories, KMsgError>>;
111
+ /**
112
+ * Request authentication SMS for channel registration.
113
+ */
50
114
  requestKakaoChannelAuth?(params: {
51
115
  plusId: string;
52
116
  phoneNumber: string;
53
117
  }): Promise<Result<void, KMsgError>>;
118
+ /**
119
+ * Add a Kakao channel after authentication.
120
+ */
54
121
  addKakaoChannel?(params: {
55
122
  plusId: string;
56
123
  authNum: string;
@@ -58,21 +125,81 @@ export interface KakaoChannelProvider {
58
125
  categoryCode: string;
59
126
  }): Promise<Result<KakaoChannel, KMsgError>>;
60
127
  }
128
+ /**
129
+ * Health check result from a provider.
130
+ */
61
131
  export interface ProviderHealthStatus {
132
+ /** Whether the provider is operational. */
62
133
  healthy: boolean;
134
+ /** List of issues if not healthy. */
63
135
  issues: string[];
136
+ /** Response latency in milliseconds. */
64
137
  latencyMs?: number;
138
+ /** Provider-specific health details. */
65
139
  data?: Record<string, unknown>;
66
140
  }
141
+ /**
142
+ * Interface for providers that support balance queries.
143
+ */
67
144
  export interface BalanceProvider {
145
+ /**
146
+ * Query the remaining balance/points for the provider account.
147
+ */
68
148
  getBalance(query?: BalanceQuery): Promise<Result<BalanceResult, KMsgError>>;
69
149
  }
150
+ /**
151
+ * Core provider interface for sending messages.
152
+ *
153
+ * All providers must implement this interface. Optional capabilities
154
+ * (balance, templates, delivery status) are exposed via separate interfaces.
155
+ *
156
+ * @example
157
+ * ```ts
158
+ * class MyProvider implements Provider {
159
+ * readonly id = "my-provider";
160
+ * readonly name = "My Provider";
161
+ * readonly supportedTypes = ["SMS", "LMS"] as const;
162
+ *
163
+ * async healthCheck() { return { healthy: true, issues: [] }; }
164
+ * async send(params) { ... }
165
+ * }
166
+ * ```
167
+ */
70
168
  export interface Provider {
169
+ /**
170
+ * Unique identifier for this provider instance.
171
+ * Used for routing and logging.
172
+ * @example "solapi"
173
+ */
71
174
  readonly id: string;
175
+ /**
176
+ * Human-readable name for display purposes.
177
+ * @example "SOLAPI"
178
+ */
72
179
  readonly name: string;
180
+ /**
181
+ * Message types this provider supports.
182
+ * Messages of unsupported types will be rejected.
183
+ */
73
184
  readonly supportedTypes: readonly MessageType[];
185
+ /**
186
+ * Check if the provider is operational.
187
+ * Used for health monitoring and circuit breaker decisions.
188
+ */
74
189
  healthCheck(): Promise<ProviderHealthStatus>;
190
+ /**
191
+ * Send a message through this provider.
192
+ * @returns Result with SendResult on success, KMsgError on failure.
193
+ */
75
194
  send(params: SendOptions): Promise<Result<SendResult, KMsgError>>;
195
+ /**
196
+ * Query delivery status for a previously sent message.
197
+ * Optional capability - not all providers support this.
198
+ */
76
199
  getDeliveryStatus?(query: DeliveryStatusQuery): Promise<Result<DeliveryStatusResult | null, KMsgError>>;
200
+ /**
201
+ * Get the onboarding specification for this provider.
202
+ * Used by tooling to guide provider configuration.
203
+ */
77
204
  getOnboardingSpec?(): ProviderOnboardingSpec;
78
205
  }
package/dist/result.d.ts CHANGED
@@ -1,15 +1,59 @@
1
+ /**
2
+ * Represents a successful result containing a value.
3
+ */
1
4
  export type Ok<T> = {
5
+ /** Always true for successful results. */
2
6
  readonly isSuccess: true;
7
+ /** Always false for successful results. */
3
8
  readonly isFailure: false;
9
+ /** The contained success value. */
4
10
  readonly value: T;
5
11
  };
12
+ /**
13
+ * Represents a failed result containing an error.
14
+ */
6
15
  export type Fail<E> = {
16
+ /** Always false for failed results. */
7
17
  readonly isSuccess: false;
18
+ /** Always true for failed results. */
8
19
  readonly isFailure: true;
20
+ /** The contained error. */
9
21
  readonly error: E;
10
22
  };
23
+ /**
24
+ * A result type that represents either success (Ok) or failure (Fail).
25
+ * Used throughout k-msg for explicit error handling without exceptions.
26
+ *
27
+ * @template T - The type of the success value
28
+ * @template E - The type of the error (defaults to Error)
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * function divide(a: number, b: number): Result<number, string> {
33
+ * if (b === 0) return fail("division by zero");
34
+ * return ok(a / b);
35
+ * }
36
+ *
37
+ * const result = divide(10, 2);
38
+ * if (result.isSuccess) {
39
+ * console.log(result.value); // 5
40
+ * } else {
41
+ * console.error(result.error);
42
+ * }
43
+ * ```
44
+ */
11
45
  export type Result<T, E = Error> = Ok<T> | Fail<E>;
46
+ /**
47
+ * Create a successful result containing the given value.
48
+ * @param value - The success value to wrap
49
+ * @returns An Ok result containing the value
50
+ */
12
51
  export declare const ok: <T>(value: T) => Ok<T>;
52
+ /**
53
+ * Create a failed result containing the given error.
54
+ * @param error - The error to wrap
55
+ * @returns A Fail result containing the error
56
+ */
13
57
  export declare const fail: <E>(error: E) => Fail<E>;
14
58
  /**
15
59
  * Result utility functions for chaining and transformation
@@ -58,4 +102,63 @@ export declare const Result: {
58
102
  * Check if a Result is Fail
59
103
  */
60
104
  isFail<T, E>(result: Result<T, E>): result is Fail<E>;
105
+ /**
106
+ * Execute a side-effect without breaking the chain.
107
+ * Calls fn with the result (ok or fail) and returns the same result.
108
+ *
109
+ * @param result - The Result to tap
110
+ * @param fn - Side-effect function called with the result
111
+ * @returns The same Result for chaining
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * const result = await provider.send(options);
116
+ * Result.tap(result, r => console.log('Completed:', r));
117
+ * ```
118
+ */
119
+ tap<T, E>(result: Result<T, E>, fn: (result: Result<T, E>) => void): Result<T, E>;
120
+ /**
121
+ * Execute a side-effect on success only.
122
+ * Calls fn with the value only if result is ok, returns the same result.
123
+ *
124
+ * @param result - The Result to tap
125
+ * @param fn - Side-effect function called with the value on success
126
+ * @returns The same Result for chaining
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * Result.tapOk(result, value => console.log('Success:', value.messageId));
131
+ * ```
132
+ */
133
+ tapOk<T, E>(result: Result<T, E>, fn: (value: T) => void): Result<T, E>;
134
+ /**
135
+ * Execute a side-effect on failure only.
136
+ * Calls fn with the error only if result is fail, returns the same result.
137
+ *
138
+ * @param result - The Result to tap
139
+ * @param fn - Side-effect function called with the error on failure
140
+ * @returns The same Result for chaining
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * Result.tapErr(result, error => console.error('Failed:', error.message));
145
+ * ```
146
+ */
147
+ tapErr<T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E>;
148
+ /**
149
+ * Return the value on success, or throw with a custom message on failure.
150
+ * Use this when you want to convert a failed Result to an exception.
151
+ *
152
+ * @param result - The Result to expect
153
+ * @param message - Custom error message to use if result is fail
154
+ * @returns The success value
155
+ * @throws Error with the provided message (and original error as cause)
156
+ *
157
+ * @example
158
+ * ```ts
159
+ * const value = Result.expect(result, 'Message send failed');
160
+ * // throws Error('Message send failed') if result is fail
161
+ * ```
162
+ */
163
+ expect<T, E>(result: Result<T, E>, message: string): T;
61
164
  };
@@ -1,8 +1,34 @@
1
+ /**
2
+ * Supported message types in the k-msg platform.
3
+ *
4
+ * - ALIMTALK: Kakao AlimTalk (notification talk) with approved template
5
+ * - FRIENDTALK: Kakao FriendTalk (friend message, no template required)
6
+ * - SMS: Short message (up to 90 bytes, typically ~90 Korean characters)
7
+ * - LMS: Long message with subject line
8
+ * - MMS: Multimedia message with image attachment
9
+ * - NSA: Naver Smart Alarm (notification service)
10
+ * - VOICE: Voice call message
11
+ * - FAX: Fax transmission
12
+ * - RCS_SMS/LMS/MMS: Rich Communication Services text/media messages
13
+ * - RCS_TPL/ITPL/LTPL: RCS template-based messages
14
+ */
1
15
  export type MessageType = "ALIMTALK" | "FRIENDTALK" | "SMS" | "LMS" | "MMS" | "NSA" | "VOICE" | "FAX" | "RCS_SMS" | "RCS_LMS" | "RCS_MMS" | "RCS_TPL" | "RCS_ITPL" | "RCS_LTPL";
16
+ /**
17
+ * Message delivery status.
18
+ *
19
+ * - PENDING: Queued or in transit
20
+ * - SENT: Successfully delivered to the carrier
21
+ * - FAILED: Delivery failed
22
+ */
2
23
  export type MessageStatus = "PENDING" | "SENT" | "FAILED";
3
24
  export declare const KNOWN_MESSAGE_STATUSES: MessageStatus[];
4
25
  export declare const QUEUED_MESSAGE_STATUS: MessageStatus;
5
26
  export declare const normalizeMessageStatus: (status: unknown) => MessageStatus;
27
+ /**
28
+ * Variables for template interpolation.
29
+ * Values are substituted into #{variableName} placeholders in templates.
30
+ * @example { name: "John", code: "123456" }
31
+ */
6
32
  export type MessageVariables = Record<string, string | number | boolean | Date | null | undefined>;
7
33
  export interface MessageButton {
8
34
  name: string;
@@ -45,6 +71,10 @@ export interface CommonSendOptions {
45
71
  * Optional routing hint to force a specific provider by id.
46
72
  */
47
73
  providerId?: string;
74
+ /**
75
+ * Recipient phone number in Korean format without hyphens.
76
+ * @example "01012345678"
77
+ */
48
78
  to: string;
49
79
  /**
50
80
  * Sender number / sender id. Optional at KMsg layer; providers may require it.
@@ -202,7 +232,15 @@ export interface RcsTemplateSendOptions extends CommonSendOptions {
202
232
  variables: MessageVariables;
203
233
  rcs?: RcsSendOptions;
204
234
  }
235
+ /**
236
+ * Union of all supported send option types.
237
+ * Use this for type narrowing based on the `type` discriminator.
238
+ */
205
239
  export type SendOptions = SmsSendOptions | AlimTalkSendOptions | FriendTalkSendOptions | NsaSendOptions | VoiceMessageSendOptions | FaxMessageSendOptions | RcsTextSendOptions | RcsTemplateSendOptions;
240
+ /**
241
+ * Relaxed SMS input type that allows omitting `type` and using `content` as an alias for `text`.
242
+ * Used for developer convenience when sending simple SMS messages.
243
+ */
206
244
  export type SmsDefaultSendInput = Omit<SmsSendOptions, "type" | "text"> & {
207
245
  type?: undefined;
208
246
  /**
@@ -220,16 +258,41 @@ export type SmsDefaultSendInput = Omit<SmsSendOptions, "type" | "text"> & {
220
258
  * - Other channels are modeled as discriminated unions on `type`.
221
259
  */
222
260
  export type SendInput = SendOptions | SmsDefaultSendInput;
261
+ /**
262
+ * Result of a message send operation.
263
+ * Returned by Provider.send() and KMsg.send().
264
+ */
223
265
  export interface SendResult {
224
266
  /**
225
267
  * Correlation id (equals the request `messageId`).
226
268
  */
227
269
  messageId: string;
270
+ /**
271
+ * Identifier of the provider that handled this message.
272
+ */
228
273
  providerId: string;
274
+ /**
275
+ * Provider-specific message identifier for tracking.
276
+ */
229
277
  providerMessageId?: string;
278
+ /**
279
+ * Current delivery status of the message.
280
+ */
230
281
  status: MessageStatus;
282
+ /**
283
+ * The message type that was sent.
284
+ */
231
285
  type: MessageType;
286
+ /**
287
+ * Recipient phone number.
288
+ */
232
289
  to: string;
290
+ /**
291
+ * Non-fatal warnings (e.g., failover partially applied).
292
+ */
233
293
  warnings?: SendWarning[];
294
+ /**
295
+ * Raw provider response for debugging (provider-specific shape).
296
+ */
234
297
  raw?: unknown;
235
298
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k-msg/core",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "packageManager": "bun@1.3.8",
5
5
  "description": "Core types and interfaces for K-Message platform",
6
6
  "type": "module",