@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.
@@ -1,6 +1,6 @@
1
1
  import type { KMsgError } from "./errors";
2
2
  import type { Result } from "./result";
3
- import type { SendOptions, SendResult } from "./types/index";
3
+ import type { MessageType, SendOptions, SendResult } from "./types/index";
4
4
  export interface Template {
5
5
  id: string;
6
6
  code: string;
@@ -24,13 +24,16 @@ export interface TemplateProvider {
24
24
  limit?: number;
25
25
  }): Promise<Result<Template[], KMsgError>>;
26
26
  }
27
- /**
28
- * @deprecated Use `BaseProvider` from `@k-msg/core` instead.
29
- * Legacy provider interface that uses the Result<T, E> pattern for send().
30
- * New providers should implement `BaseProvider` which uses adapter-based patterns.
31
- */
27
+ export interface ProviderHealthStatus {
28
+ healthy: boolean;
29
+ issues: string[];
30
+ latencyMs?: number;
31
+ data?: Record<string, unknown>;
32
+ }
32
33
  export interface Provider {
33
34
  readonly id: string;
34
35
  readonly name: string;
36
+ readonly supportedTypes: readonly MessageType[];
37
+ healthCheck(): Promise<ProviderHealthStatus>;
35
38
  send(params: SendOptions): Promise<Result<SendResult, KMsgError>>;
36
39
  }
@@ -1,8 +1,13 @@
1
- import { KMsgError, KMsgErrorCode, type Provider, type Result, type SendOptions, type SendResult } from "./index";
1
+ import { KMsgError, KMsgErrorCode, type MessageType, type Provider, type Result, type SendOptions, type SendResult } from "./index";
2
2
  export declare class MockProvider implements Provider {
3
3
  readonly id: string;
4
4
  readonly name: string;
5
+ readonly supportedTypes: readonly MessageType[];
5
6
  constructor(id?: string, name?: string);
7
+ healthCheck(): Promise<{
8
+ healthy: boolean;
9
+ issues: never[];
10
+ }>;
6
11
  send(params: SendOptions): Promise<Result<SendResult, KMsgError>>;
7
12
  }
8
13
  export declare const TestAssertions: {
@@ -1,6 +1,3 @@
1
1
  export * from "./balance";
2
2
  export * from "./history";
3
3
  export * from "./message";
4
- export * from "./platform";
5
- export * from "./provider";
6
- export * from "./standard";
@@ -1,34 +1,188 @@
1
1
  export type MessageType = "ALIMTALK" | "FRIENDTALK" | "SMS" | "LMS" | "MMS" | "NSA" | "VOICE" | "FAX" | "RCS_SMS" | "RCS_LMS" | "RCS_MMS" | "RCS_TPL" | "RCS_ITPL" | "RCS_LTPL";
2
- export interface BaseOptions {
3
- to: string;
4
- from: string;
5
- messageId?: string;
6
- }
7
- export interface AlimTalkOptions extends BaseOptions {
8
- type: "ALIMTALK";
9
- templateId: string;
10
- variables: Record<string, string>;
11
- }
12
- export interface Button {
2
+ export type MessageStatus = "PENDING" | "SENT" | "FAILED";
3
+ export type MessageVariables = Record<string, string | number | boolean | Date | null | undefined>;
4
+ export interface MessageButton {
13
5
  name: string;
6
+ /**
7
+ * Provider-dependent. Common values: "WL" (web link), "AL" (app link), ...
8
+ */
14
9
  type: string;
15
10
  urlPc?: string;
16
11
  urlMobile?: string;
17
12
  }
18
- export interface FriendTalkOptions extends BaseOptions {
13
+ export interface CommonSendOptions {
14
+ /**
15
+ * Correlation id generated by KMsg (or provided by the caller).
16
+ * Providers must echo this value back in SendResult.messageId.
17
+ */
18
+ messageId?: string;
19
+ /**
20
+ * Optional routing hint to force a specific provider by id.
21
+ */
22
+ providerId?: string;
23
+ to: string;
24
+ /**
25
+ * Sender number / sender id. Optional at KMsg layer; providers may require it.
26
+ */
27
+ from?: string;
28
+ /**
29
+ * Common delivery options understood by multiple providers.
30
+ */
31
+ options?: {
32
+ scheduledAt?: Date;
33
+ /**
34
+ * Country code for providers that support it (e.g. SOLAPI).
35
+ * Examples: "82", "+82".
36
+ */
37
+ country?: string;
38
+ customFields?: Record<string, string>;
39
+ };
40
+ /**
41
+ * Provider-specific escape hatch (use sparingly).
42
+ */
43
+ providerOptions?: Record<string, unknown>;
44
+ }
45
+ export interface KakaoSendOptions {
46
+ profileId?: string;
47
+ disableSms?: boolean;
48
+ adFlag?: boolean;
49
+ buttons?: unknown[];
50
+ imageId?: string;
51
+ /**
52
+ * FriendTalk image upload link hint (SOLAPI).
53
+ */
54
+ imageLink?: string;
55
+ [key: string]: any;
56
+ }
57
+ export interface NaverSendOptions {
58
+ talkId?: string;
59
+ /**
60
+ * Override the template identifier for NSA (provider-specific).
61
+ */
62
+ templateCode?: string;
63
+ disableSms?: boolean;
64
+ variables?: MessageVariables;
65
+ buttons?: unknown[];
66
+ [key: string]: any;
67
+ }
68
+ export interface VoiceSendOptions {
69
+ voiceType?: "FEMALE" | "MALE";
70
+ headerMessage?: string;
71
+ tailMessage?: string;
72
+ replyRange?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
73
+ counselorNumber?: string;
74
+ [key: string]: any;
75
+ }
76
+ export interface FaxSendOptions {
77
+ fileIds?: string[];
78
+ fileUrls?: string[];
79
+ [key: string]: any;
80
+ }
81
+ export interface RcsSendOptions {
82
+ brandId?: string;
83
+ /**
84
+ * Override template identifier for RCS_*TPL types.
85
+ */
86
+ templateCode?: string;
87
+ copyAllowed?: boolean;
88
+ variables?: MessageVariables;
89
+ mmsType?: "M3" | "S3" | "M4" | "S4" | "M5" | "S5" | "M6" | "S6";
90
+ commercialType?: boolean;
91
+ disableSms?: boolean;
92
+ buttons?: unknown[];
93
+ additionalBody?: {
94
+ title?: string;
95
+ description?: string;
96
+ imageId?: string;
97
+ buttons?: unknown[];
98
+ [key: string]: any;
99
+ };
100
+ [key: string]: any;
101
+ }
102
+ export interface SmsSendOptions extends CommonSendOptions {
103
+ type: "SMS" | "LMS" | "MMS";
104
+ text: string;
105
+ /**
106
+ * LMS/MMS subject.
107
+ */
108
+ subject?: string;
109
+ /**
110
+ * Optional image URL for MMS (provider-specific).
111
+ */
112
+ imageUrl?: string;
113
+ variables?: MessageVariables;
114
+ }
115
+ export interface AlimTalkSendOptions extends CommonSendOptions {
116
+ type: "ALIMTALK";
117
+ templateCode: string;
118
+ variables: MessageVariables;
119
+ kakao?: KakaoSendOptions;
120
+ }
121
+ export interface FriendTalkSendOptions extends CommonSendOptions {
19
122
  type: "FRIENDTALK";
20
123
  text: string;
21
124
  imageUrl?: string;
22
- buttons?: Button[];
125
+ buttons?: MessageButton[];
126
+ variables?: MessageVariables;
127
+ kakao?: KakaoSendOptions;
23
128
  }
24
- export interface SmsOptions extends BaseOptions {
25
- type: "SMS" | "LMS" | "MMS";
129
+ export interface NsaSendOptions extends CommonSendOptions {
130
+ type: "NSA";
131
+ templateCode: string;
132
+ variables: MessageVariables;
133
+ naver?: NaverSendOptions;
134
+ }
135
+ export interface VoiceMessageSendOptions extends CommonSendOptions {
136
+ type: "VOICE";
137
+ text: string;
138
+ variables?: MessageVariables;
139
+ voice?: VoiceSendOptions;
140
+ }
141
+ export interface FaxMessageSendOptions extends CommonSendOptions {
142
+ type: "FAX";
143
+ fax: FaxSendOptions;
144
+ }
145
+ export interface RcsTextSendOptions extends CommonSendOptions {
146
+ type: "RCS_SMS" | "RCS_LMS" | "RCS_MMS";
26
147
  text: string;
27
148
  subject?: string;
149
+ imageUrl?: string;
150
+ variables?: MessageVariables;
151
+ rcs?: RcsSendOptions;
152
+ }
153
+ export interface RcsTemplateSendOptions extends CommonSendOptions {
154
+ type: "RCS_TPL" | "RCS_ITPL" | "RCS_LTPL";
155
+ templateCode: string;
156
+ variables: MessageVariables;
157
+ rcs?: RcsSendOptions;
28
158
  }
29
- export type SendOptions = AlimTalkOptions | FriendTalkOptions | SmsOptions;
159
+ export type SendOptions = SmsSendOptions | AlimTalkSendOptions | FriendTalkSendOptions | NsaSendOptions | VoiceMessageSendOptions | FaxMessageSendOptions | RcsTextSendOptions | RcsTemplateSendOptions;
160
+ export type SmsDefaultSendInput = Omit<SmsSendOptions, "type" | "text"> & {
161
+ type?: undefined;
162
+ /**
163
+ * SMS text. If omitted, `content` is used.
164
+ */
165
+ text?: string;
166
+ /**
167
+ * Alias for `text`.
168
+ */
169
+ content?: string;
170
+ };
171
+ /**
172
+ * Developer-facing input type.
173
+ * - SMS defaults allow omitting `type` and using `content`.
174
+ * - Other channels are modeled as discriminated unions on `type`.
175
+ */
176
+ export type SendInput = SendOptions | SmsDefaultSendInput;
30
177
  export interface SendResult {
178
+ /**
179
+ * Correlation id (equals the request `messageId`).
180
+ */
31
181
  messageId: string;
32
- status: "PENDING" | "SENT" | "FAILED";
33
- provider: string;
182
+ providerId: string;
183
+ providerMessageId?: string;
184
+ status: MessageStatus;
185
+ type: MessageType;
186
+ to: string;
187
+ raw?: unknown;
34
188
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k-msg/core",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "packageManager": "bun@1.3.8",
5
5
  "description": "Core types and interfaces for K-Message platform",
6
6
  "type": "module",
@@ -1,73 +0,0 @@
1
- import type { BalanceQuery, BalanceResult, BaseProvider, Config, HistoryQuery, HistoryResult, KMsg, MessageSendOptions, MessageSendResult, PlatformHealthStatus, PlatformInfo } from "./types/index";
2
- /**
3
- * Core AlimTalk Platform implementation
4
- */
5
- export declare class AlimTalkPlatform implements KMsg {
6
- private static readonly channelTemplateFallbacks;
7
- private static readonly directTemplateCodes;
8
- private providers;
9
- private config;
10
- private defaultProvider?;
11
- constructor(config: Config);
12
- getInfo(): PlatformInfo;
13
- registerProvider(provider: BaseProvider): void;
14
- getProvider(providerId: string): BaseProvider | null;
15
- listProviders(): string[];
16
- getDefaultProvider(): BaseProvider | null;
17
- private isLegacySendOptions;
18
- private getProviderOrThrow;
19
- private resolveProviderForSend;
20
- private normalizeUnifiedRecipients;
21
- private resolveTemplateCode;
22
- private toErrorMessage;
23
- private extractErrorMessage;
24
- private hasResultFailureShape;
25
- private hasResultSuccessShape;
26
- private isFailedDeliveryStatus;
27
- private normalizeSendResult;
28
- private hasTextContent;
29
- private validateUnifiedSendOptions;
30
- private toProviderChannel;
31
- private sendLegacyMessages;
32
- private sendUnifiedMessages;
33
- healthCheck(): Promise<PlatformHealthStatus>;
34
- get messages(): {
35
- send: (options: MessageSendOptions) => Promise<MessageSendResult>;
36
- getStatus: (_messageId: string) => Promise<string>;
37
- };
38
- balance(providerId?: string): Promise<{
39
- get: (query?: BalanceQuery) => Promise<BalanceResult>;
40
- }>;
41
- /**
42
- * @deprecated Template operations are not yet migrated to the new provider interface.
43
- * Use the provider's adapter directly for template management.
44
- */
45
- templates(providerId?: string): Promise<{
46
- /** @deprecated Not yet implemented */
47
- list: (_page?: number, _size?: number, _filters?: Record<string, unknown>) => Promise<never>;
48
- /** @deprecated Not yet implemented */
49
- create: (_name: string, _content: string, _category?: string, _variables?: unknown[], _buttons?: unknown[]) => Promise<never>;
50
- /** @deprecated Not yet implemented */
51
- modify: (_templateCode: string, _name: string, _content: string, _buttons?: unknown[]) => Promise<never>;
52
- /** @deprecated Not yet implemented */
53
- delete: (_templateCode: string) => Promise<never>;
54
- }>;
55
- /**
56
- * History operations (common API surface).
57
- *
58
- * Notes:
59
- * - Not all providers implement history. This method will throw when unsupported.
60
- * - For provider-specific, advanced fields, use provider adapter directly.
61
- */
62
- history(providerId?: string): Promise<{
63
- list: (queryOrPage?: HistoryQuery | number, pageSize?: number, filters?: Partial<Omit<HistoryQuery, "page" | "pageSize">> & {
64
- channel?: HistoryQuery["channel"];
65
- }) => Promise<HistoryResult>;
66
- cancelReservation: (_messageId: string) => Promise<never>;
67
- }>;
68
- providerHealth(providerId: string): Promise<import(".").ProviderHealthStatus>;
69
- private getProviderAdapter;
70
- private isSmsChannel;
71
- private normalizeHistoryQuery;
72
- private getFunction;
73
- }
@@ -1,135 +0,0 @@
1
- /**
2
- * Provider Registry System
3
- * 프로바이더 등록, 관리, 팩토리 시스템
4
- */
5
- import { type AdapterFactory, type BaseProvider, type ProviderConfig, type ProviderFactoryConfig, type ProviderMetadata, type StandardRequest, type StandardResult } from "./types/index";
6
- /**
7
- * 프로바이더 레지스트리
8
- * 모든 등록된 프로바이더와 어댑터 팩토리를 관리
9
- */
10
- export declare class ProviderRegistry {
11
- private factories;
12
- private providers;
13
- private metadata;
14
- private debug;
15
- /**
16
- * 어댑터 팩토리 등록
17
- */
18
- registerFactory(factory: AdapterFactory): void;
19
- /**
20
- * 프로바이더 인스턴스 생성
21
- */
22
- createProvider(providerId: string, config: ProviderConfig): BaseProvider<StandardRequest, StandardResult>;
23
- /**
24
- * 등록된 프로바이더 인스턴스 반환
25
- */
26
- getProvider(providerId: string): BaseProvider<StandardRequest, StandardResult> | null;
27
- /**
28
- * 사용 가능한 프로바이더 목록
29
- */
30
- getAvailableProviders(): string[];
31
- /**
32
- * 프로바이더 메타데이터 조회
33
- */
34
- getProviderMetadata(providerId: string): ProviderMetadata | null;
35
- /**
36
- * 모든 프로바이더 메타데이터 조회
37
- */
38
- getAllMetadata(): ProviderMetadata[];
39
- /**
40
- * 특정 기능을 지원하는 프로바이더 검색
41
- */
42
- findProvidersByFeature(feature: string): ProviderMetadata[];
43
- /**
44
- * 프로바이더 등록 해제
45
- */
46
- unregisterProvider(providerId: string): boolean;
47
- /**
48
- * 모든 프로바이더 등록 해제
49
- */
50
- clear(): void;
51
- /**
52
- * 레지스트리 상태 조회
53
- */
54
- getStatus(): {
55
- registeredFactories: number;
56
- activeProviders: number;
57
- availableProviders: string[];
58
- metadata: ProviderMetadata[];
59
- };
60
- /**
61
- * 프로바이더 헬스체크 실행
62
- */
63
- healthCheck(): Promise<Record<string, any>>;
64
- /**
65
- * 디버그 모드 설정
66
- */
67
- setDebug(enabled: boolean): void;
68
- }
69
- /**
70
- * 글로벌 프로바이더 레지스트리 인스턴스
71
- */
72
- export declare const globalProviderRegistry: ProviderRegistry;
73
- /**
74
- * 설정 기반 프로바이더 팩토리
75
- */
76
- export declare class ConfigBasedProviderFactory {
77
- private registry;
78
- private config;
79
- constructor(registry: ProviderRegistry, config: ProviderFactoryConfig);
80
- /**
81
- * 설정에서 프로바이더 생성
82
- */
83
- createFromConfig(providerId: string): BaseProvider<StandardRequest, StandardResult>;
84
- /**
85
- * 모든 설정된 프로바이더 생성
86
- */
87
- createAllFromConfig(): Record<string, BaseProvider<StandardRequest, StandardResult>>;
88
- }
89
- /**
90
- * 플러그인 기반 프로바이더 로더
91
- */
92
- export declare class ProviderPluginLoader {
93
- private registry;
94
- constructor(registry: ProviderRegistry);
95
- /**
96
- * 플러그인 모듈 동적 로딩
97
- */
98
- loadPlugin(pluginPath: string): Promise<void>;
99
- /**
100
- * 여러 플러그인 배치 로딩
101
- */
102
- loadPlugins(pluginPaths: string[]): Promise<void>;
103
- /**
104
- * 팩토리 인터페이스 검증
105
- */
106
- private isValidFactory;
107
- }
108
- /**
109
- * 프로바이더 헬스 모니터
110
- * HealthChecker를 활용하여 프로바이더들의 헬스 상태를 모니터링
111
- */
112
- export declare class ProviderHealthMonitor {
113
- private registry;
114
- private interval;
115
- private checker;
116
- private intervalId?;
117
- private registeredServices;
118
- constructor(registry: ProviderRegistry, interval?: number);
119
- /**
120
- * 헬스 모니터링 시작
121
- */
122
- start(): void;
123
- /**
124
- * 헬스 모니터링 중지
125
- */
126
- stop(): void;
127
- /**
128
- * 레지스트리의 프로바이더를 HealthChecker에 동기화
129
- */
130
- private syncProviders;
131
- /**
132
- * 현재 헬스 상태 조회
133
- */
134
- checkNow(): Promise<import("./health").HealthStatus>;
135
- }
@@ -1,20 +0,0 @@
1
- import type { BaseProvider, ProviderHealthStatus, StandardRequest, StandardResult } from "../types/index";
2
- /**
3
- * Round-robin router provider that forwards requests to upstream providers.
4
- * Useful for simple load distribution or provider rotation strategies.
5
- */
6
- export declare class RoundRobinRouterProvider implements BaseProvider<StandardRequest, StandardResult> {
7
- readonly id: string;
8
- readonly name: string;
9
- readonly type: "messaging";
10
- readonly version = "1.0.0";
11
- private readonly providers;
12
- private idx;
13
- constructor(params: {
14
- id: string;
15
- name?: string;
16
- providers: BaseProvider<StandardRequest, StandardResult>[];
17
- });
18
- healthCheck(): Promise<ProviderHealthStatus>;
19
- send<T extends StandardRequest = StandardRequest, R extends StandardResult = StandardResult>(request: T): Promise<R>;
20
- }
@@ -1,151 +0,0 @@
1
- import type { BalanceQuery, BalanceResult } from "./balance";
2
- import type { HistoryQuery, HistoryResult } from "./history";
3
- import type { Button, MessageType } from "./message";
4
- import type { BaseProvider } from "./provider";
5
- export interface PlatformHealthStatus {
6
- healthy: boolean;
7
- providers: Record<string, boolean>;
8
- issues: string[];
9
- }
10
- export interface PlatformInfo {
11
- version: string;
12
- providers: string[];
13
- features: string[];
14
- }
15
- export interface LegacyMessageSendOptions {
16
- templateId: string;
17
- recipients: {
18
- phoneNumber: string;
19
- variables?: Record<string, unknown>;
20
- }[];
21
- variables: Record<string, unknown>;
22
- }
23
- export interface UnifiedMessageRecipient {
24
- phoneNumber: string;
25
- variables?: Record<string, unknown>;
26
- }
27
- export interface UnifiedMessageSendOptions {
28
- channel: MessageType;
29
- recipients: Array<string | UnifiedMessageRecipient>;
30
- providerId?: string;
31
- templateCode?: string;
32
- variables?: Record<string, unknown>;
33
- text?: string;
34
- subject?: string;
35
- imageUrl?: string;
36
- buttons?: Button[];
37
- options?: {
38
- scheduledAt?: Date;
39
- senderNumber?: string;
40
- subject?: string;
41
- country?: string;
42
- customFields?: Record<string, string>;
43
- kakaoOptions?: {
44
- pfId?: string;
45
- templateId?: string;
46
- variables?: Record<string, string>;
47
- disableSms?: boolean;
48
- adFlag?: boolean;
49
- buttons?: unknown[];
50
- imageId?: string;
51
- [key: string]: unknown;
52
- };
53
- naverOptions?: {
54
- talkId?: string;
55
- templateId?: string;
56
- disableSms?: boolean;
57
- variables?: Record<string, string>;
58
- buttons?: unknown[];
59
- [key: string]: unknown;
60
- };
61
- voiceOptions?: {
62
- voiceType: "FEMALE" | "MALE";
63
- headerMessage?: string;
64
- tailMessage?: string;
65
- replyRange?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
66
- counselorNumber?: string;
67
- [key: string]: unknown;
68
- };
69
- faxOptions?: {
70
- fileIds?: string[];
71
- fileUrls?: string[];
72
- [key: string]: unknown;
73
- };
74
- rcsOptions?: {
75
- brandId?: string;
76
- templateId?: string;
77
- copyAllowed?: boolean;
78
- variables?: Record<string, string>;
79
- mmsType?: "M3" | "S3" | "M4" | "S4" | "M5" | "S5" | "M6" | "S6";
80
- commercialType?: boolean;
81
- disableSms?: boolean;
82
- buttons?: unknown[];
83
- additionalBody?: {
84
- title?: string;
85
- description?: string;
86
- imageId?: string;
87
- buttons?: unknown[];
88
- [key: string]: unknown;
89
- };
90
- [key: string]: unknown;
91
- };
92
- [key: string]: unknown;
93
- };
94
- }
95
- export type MessageSendOptions = LegacyMessageSendOptions | UnifiedMessageSendOptions;
96
- export interface MessageSendResult {
97
- results: Array<{
98
- messageId?: string;
99
- status: string;
100
- phoneNumber: string;
101
- error?: {
102
- message: string;
103
- };
104
- }>;
105
- summary: {
106
- total: number;
107
- sent: number;
108
- failed: number;
109
- };
110
- }
111
- export interface KMsg {
112
- getInfo(): PlatformInfo;
113
- registerProvider(provider: BaseProvider): void;
114
- getProvider(providerId: string): BaseProvider | null;
115
- listProviders(): string[];
116
- healthCheck(): Promise<PlatformHealthStatus>;
117
- balance(providerId?: string): Promise<{
118
- get(query?: BalanceQuery): Promise<BalanceResult>;
119
- }>;
120
- history(providerId?: string): Promise<{
121
- list(query: HistoryQuery): Promise<HistoryResult>;
122
- list(page?: number, pageSize?: number, filters?: Partial<Omit<HistoryQuery, "page" | "pageSize">> & {
123
- channel?: HistoryQuery["channel"];
124
- }): Promise<HistoryResult>;
125
- }>;
126
- messages: {
127
- send(options: MessageSendOptions): Promise<MessageSendResult>;
128
- getStatus(messageId: string): Promise<string>;
129
- };
130
- }
131
- export interface Config {
132
- defaultProvider?: string;
133
- providers: string[];
134
- features: {
135
- enableBulkSending?: boolean;
136
- enableScheduling?: boolean;
137
- enableAnalytics?: boolean;
138
- };
139
- messageDefaults?: {
140
- providerId?: string;
141
- senderNumber?: string;
142
- subject?: string;
143
- templateCodes?: Partial<Record<MessageType, string>>;
144
- channels?: Partial<Record<MessageType, {
145
- providerId?: string;
146
- senderNumber?: string;
147
- subject?: string;
148
- templateCode?: string;
149
- }>>;
150
- };
151
- }