@k-msg/provider 0.1.0 → 0.1.2

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.
Files changed (47) hide show
  1. package/README.md +3 -1
  2. package/dist/abstract/provider.base.d.ts +108 -0
  3. package/dist/adapters/aligo.adapter.d.ts +50 -0
  4. package/dist/adapters/iwinv.adapter.d.ts +111 -0
  5. package/dist/aligo/provider.d.ts +18 -0
  6. package/dist/config/provider-config-v2.d.ts +122 -0
  7. package/dist/contracts/provider.contract.d.ts +355 -0
  8. package/dist/contracts/sms.contract.d.ts +135 -0
  9. package/dist/index.d.ts +29 -1424
  10. package/dist/index.js +21 -2003
  11. package/dist/index.js.map +98 -1
  12. package/dist/index.mjs +25 -0
  13. package/dist/index.mjs.map +98 -0
  14. package/dist/interfaces/index.d.ts +14 -0
  15. package/dist/interfaces/plugin.d.ts +122 -0
  16. package/dist/interfaces/services.d.ts +222 -0
  17. package/dist/iwinv/contracts/account.contract.d.ts +11 -0
  18. package/dist/iwinv/contracts/analytics.contract.d.ts +16 -0
  19. package/dist/iwinv/contracts/channel.contract.d.ts +15 -0
  20. package/dist/iwinv/contracts/messaging.contract.d.ts +14 -0
  21. package/dist/iwinv/contracts/sms.contract.d.ts +33 -0
  22. package/dist/iwinv/contracts/template.contract.d.ts +18 -0
  23. package/dist/iwinv/index.d.ts +5 -0
  24. package/dist/iwinv/provider-multi.d.ts +116 -0
  25. package/dist/iwinv/provider-sms.d.ts +55 -0
  26. package/dist/iwinv/provider.d.ts +42 -0
  27. package/dist/iwinv/types/iwinv.d.ts +153 -0
  28. package/dist/middleware/index.d.ts +27 -0
  29. package/dist/mock/index.d.ts +1 -0
  30. package/dist/providers/mock/index.d.ts +1 -0
  31. package/dist/providers/mock/mock.provider.d.ts +22 -0
  32. package/dist/registry/index.d.ts +1 -0
  33. package/dist/registry/plugin-registry.d.ts +15 -0
  34. package/dist/services/provider.manager.d.ts +24 -0
  35. package/dist/services/provider.service.d.ts +49 -0
  36. package/dist/test-helpers.d.ts +110 -0
  37. package/dist/types/aligo.d.ts +69 -0
  38. package/dist/types/base.d.ts +172 -0
  39. package/dist/types/typed-templates.d.ts +199 -0
  40. package/dist/types/unified-config.d.ts +197 -0
  41. package/dist/types/unified-errors.d.ts +225 -0
  42. package/dist/utils/base-plugin.d.ts +35 -0
  43. package/dist/utils/index.d.ts +12 -0
  44. package/package.json +25 -14
  45. package/dist/index.cjs +0 -2061
  46. package/dist/index.cjs.map +0 -1
  47. package/dist/index.d.cts +0 -1425
package/dist/index.cjs DELETED
@@ -1,2061 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- AligoRequestAdapter: () => AligoRequestAdapter,
24
- AligoResponseAdapter: () => AligoResponseAdapter,
25
- BaseAlimTalkProvider: () => BaseAlimTalkProvider,
26
- BasePlugin: () => BasePlugin,
27
- BaseRequestAdapter: () => BaseRequestAdapter,
28
- BaseResponseAdapter: () => BaseResponseAdapter,
29
- IWINVProvider: () => IWINVProvider,
30
- IWINVRequestAdapter: () => IWINVRequestAdapter,
31
- IWINVResponseAdapter: () => IWINVResponseAdapter,
32
- KakaoRequestAdapter: () => KakaoRequestAdapter,
33
- KakaoResponseAdapter: () => KakaoResponseAdapter,
34
- NHNResponseAdapter: () => NHNResponseAdapter,
35
- PluginRegistry: () => PluginRegistry,
36
- ProviderManager: () => ProviderManager,
37
- RequestAdapterFactory: () => RequestAdapterFactory,
38
- ResponseAdapterFactory: () => ResponseAdapterFactory,
39
- createCircuitBreakerMiddleware: () => createCircuitBreakerMiddleware,
40
- createLoggingMiddleware: () => createLoggingMiddleware,
41
- createMetricsMiddleware: () => createMetricsMiddleware,
42
- createRateLimitMiddleware: () => createRateLimitMiddleware,
43
- createRetryMiddleware: () => createRetryMiddleware,
44
- delay: () => delay,
45
- extractVariables: () => extractVariables,
46
- formatDateTime: () => formatDateTime,
47
- normalizePhoneNumber: () => normalizePhoneNumber,
48
- parseTemplate: () => parseTemplate,
49
- retry: () => retry,
50
- validatePhoneNumber: () => validatePhoneNumber
51
- });
52
- module.exports = __toCommonJS(index_exports);
53
-
54
- // src/registry/plugin-registry.ts
55
- var import_events = require("events");
56
- var PluginRegistry = class {
57
- plugins = /* @__PURE__ */ new Map();
58
- instances = /* @__PURE__ */ new Map();
59
- register(plugin) {
60
- const id = plugin.metadata.name.toLowerCase();
61
- if (this.plugins.has(id)) {
62
- throw new Error(`Plugin ${id} is already registered`);
63
- }
64
- this.plugins.set(id, plugin);
65
- }
66
- async create(pluginId, config, options = {}) {
67
- const plugin = this.plugins.get(pluginId.toLowerCase());
68
- if (!plugin) {
69
- throw new Error(`Plugin ${pluginId} not found`);
70
- }
71
- const PluginClass = plugin.constructor;
72
- const instance = new PluginClass();
73
- const context = {
74
- config,
75
- logger: options.logger || new ConsoleLogger(),
76
- metrics: options.metrics || new NoOpMetricsCollector(),
77
- storage: options.storage || new MemoryStorage(),
78
- eventBus: new import_events.EventEmitter()
79
- };
80
- await instance.initialize(context);
81
- const instanceKey = `${pluginId}-${Date.now()}`;
82
- this.instances.set(instanceKey, instance);
83
- return instance;
84
- }
85
- async loadAndCreate(pluginId, config, options) {
86
- return this.create(pluginId, config, options);
87
- }
88
- getSupportedTypes() {
89
- return Array.from(this.plugins.keys());
90
- }
91
- validateProviderConfig(type, config) {
92
- const plugin = this.plugins.get(type.toLowerCase());
93
- if (!plugin) return false;
94
- return !!(config.apiUrl && config.apiKey);
95
- }
96
- async destroyAll() {
97
- const destroyPromises = Array.from(this.instances.values()).map(
98
- (instance) => instance.destroy()
99
- );
100
- await Promise.all(destroyPromises);
101
- this.instances.clear();
102
- }
103
- };
104
- var ConsoleLogger = class {
105
- info(message, ...args) {
106
- console.log(`[INFO] ${message}`, ...args);
107
- }
108
- error(message, error) {
109
- console.error(`[ERROR] ${message}`, error);
110
- }
111
- debug(message, ...args) {
112
- console.debug(`[DEBUG] ${message}`, ...args);
113
- }
114
- warn(message, ...args) {
115
- console.warn(`[WARN] ${message}`, ...args);
116
- }
117
- };
118
- var NoOpMetricsCollector = class {
119
- increment(_metric, _labels) {
120
- }
121
- histogram(_metric, _value, _labels) {
122
- }
123
- gauge(_metric, _value, _labels) {
124
- }
125
- };
126
- var MemoryStorage = class {
127
- store = /* @__PURE__ */ new Map();
128
- async get(key) {
129
- const item = this.store.get(key);
130
- if (!item) return void 0;
131
- if (item.expiry && Date.now() > item.expiry) {
132
- this.store.delete(key);
133
- return void 0;
134
- }
135
- return item.value;
136
- }
137
- async set(key, value, ttl) {
138
- const expiry = ttl ? Date.now() + ttl * 1e3 : void 0;
139
- this.store.set(key, { value, expiry });
140
- }
141
- async delete(key) {
142
- this.store.delete(key);
143
- }
144
- };
145
-
146
- // src/middleware/index.ts
147
- function createRetryMiddleware(options) {
148
- return {
149
- name: "retry",
150
- error: async (error, context) => {
151
- const retries = context.metadata.retries || 0;
152
- if (retries >= options.maxRetries) {
153
- throw error;
154
- }
155
- const isRetryable = options.retryableErrors?.includes(error.code) || options.retryableStatusCodes?.includes(error.status) || error.code === "ETIMEDOUT" || error.code === "ECONNRESET";
156
- if (!isRetryable) {
157
- throw error;
158
- }
159
- await new Promise(
160
- (resolve) => setTimeout(resolve, options.retryDelay * (retries + 1))
161
- );
162
- context.metadata.retries = retries + 1;
163
- throw { ...error, shouldRetry: true };
164
- }
165
- };
166
- }
167
- function createRateLimitMiddleware(options) {
168
- const windows = /* @__PURE__ */ new Map();
169
- return {
170
- name: "rate-limit",
171
- pre: async (context) => {
172
- const now = Date.now();
173
- const key = "global";
174
- if (!windows.has(key)) {
175
- windows.set(key, []);
176
- }
177
- const timestamps = windows.get(key);
178
- if (options.messagesPerSecond) {
179
- const recentCount = timestamps.filter((t) => now - t < 1e3).length;
180
- if (recentCount >= options.messagesPerSecond) {
181
- throw new Error("Rate limit exceeded: messages per second");
182
- }
183
- }
184
- if (options.messagesPerMinute) {
185
- const recentCount = timestamps.filter((t) => now - t < 6e4).length;
186
- if (recentCount >= options.messagesPerMinute) {
187
- throw new Error("Rate limit exceeded: messages per minute");
188
- }
189
- }
190
- timestamps.push(now);
191
- const cutoff = now - 36e5;
192
- const filtered = timestamps.filter((t) => t > cutoff);
193
- windows.set(key, filtered);
194
- }
195
- };
196
- }
197
- function createLoggingMiddleware(options) {
198
- return {
199
- name: "logging",
200
- pre: async (context) => {
201
- if (options.logLevel === "debug") {
202
- options.logger.debug("Request started", {
203
- metadata: context.metadata,
204
- timestamp: context.startTime
205
- });
206
- }
207
- },
208
- post: async (context) => {
209
- const duration = Date.now() - context.startTime;
210
- options.logger.info("Request completed", {
211
- duration,
212
- success: true
213
- });
214
- },
215
- error: async (error, context) => {
216
- const duration = Date.now() - context.startTime;
217
- options.logger.error("Request failed", {
218
- error: error.message,
219
- duration,
220
- stack: error.stack
221
- });
222
- }
223
- };
224
- }
225
- function createMetricsMiddleware(options) {
226
- return {
227
- name: "metrics",
228
- pre: async (context) => {
229
- options.collector.increment("requests_total", options.labels);
230
- },
231
- post: async (context) => {
232
- const duration = Date.now() - context.startTime;
233
- options.collector.histogram("request_duration_ms", duration, options.labels);
234
- options.collector.increment("requests_success_total", options.labels);
235
- },
236
- error: async (error, context) => {
237
- const duration = Date.now() - context.startTime;
238
- options.collector.histogram("request_duration_ms", duration, options.labels);
239
- options.collector.increment("requests_error_total", {
240
- ...options.labels,
241
- error_type: error.constructor.name
242
- });
243
- }
244
- };
245
- }
246
- function createCircuitBreakerMiddleware(options) {
247
- let state = "CLOSED";
248
- let failures = 0;
249
- let nextAttempt = 0;
250
- return {
251
- name: "circuit-breaker",
252
- pre: async (context) => {
253
- const now = Date.now();
254
- if (state === "OPEN") {
255
- if (now < nextAttempt) {
256
- throw new Error("Circuit breaker is OPEN");
257
- }
258
- state = "HALF_OPEN";
259
- }
260
- },
261
- post: async (context) => {
262
- if (state === "HALF_OPEN") {
263
- state = "CLOSED";
264
- failures = 0;
265
- }
266
- },
267
- error: async (error, context) => {
268
- failures++;
269
- if (failures >= options.threshold) {
270
- state = "OPEN";
271
- nextAttempt = Date.now() + options.resetTimeout;
272
- }
273
- throw error;
274
- }
275
- };
276
- }
277
-
278
- // src/utils/base-plugin.ts
279
- var BasePlugin = class {
280
- context;
281
- middleware = [];
282
- async initialize(context) {
283
- this.context = context;
284
- this.context.logger.info(`Initializing plugin: ${this.metadata.name}`);
285
- }
286
- async destroy() {
287
- this.context.logger.info(`Destroying plugin: ${this.metadata.name}`);
288
- }
289
- async executeMiddleware(phase, context, error) {
290
- for (const middleware of this.middleware) {
291
- try {
292
- if (phase === "pre" && middleware.pre) {
293
- await middleware.pre(context);
294
- } else if (phase === "post" && middleware.post) {
295
- await middleware.post(context);
296
- } else if (phase === "error" && middleware.error && error) {
297
- await middleware.error(error, context);
298
- }
299
- } catch (err) {
300
- this.context.logger.error(`Middleware ${middleware.name} failed`, err);
301
- throw err;
302
- }
303
- }
304
- }
305
- createMiddlewareContext(request, metadata = {}) {
306
- return {
307
- request,
308
- response: void 0,
309
- metadata: {
310
- ...metadata,
311
- pluginName: this.metadata.name,
312
- pluginVersion: this.metadata.version
313
- },
314
- startTime: Date.now()
315
- };
316
- }
317
- validateConfig(config, required) {
318
- for (const field of required) {
319
- if (!config[field]) {
320
- throw new Error(`${this.metadata.name}: Missing required config field: ${field}`);
321
- }
322
- }
323
- }
324
- async makeRequest(url, options, metadata = {}) {
325
- const context = this.createMiddlewareContext({ url, options }, metadata);
326
- try {
327
- await this.executeMiddleware("pre", context);
328
- const response = await fetch(url, {
329
- ...options,
330
- headers: {
331
- "User-Agent": `K-OTP-${this.metadata.name}/${this.metadata.version}`,
332
- ...this.context.config.headers,
333
- ...options.headers
334
- },
335
- signal: AbortSignal.timeout(this.context.config.timeout || 3e4)
336
- });
337
- context.response = response;
338
- await this.executeMiddleware("post", context);
339
- return response;
340
- } catch (error) {
341
- await this.executeMiddleware("error", context, error);
342
- throw error;
343
- }
344
- }
345
- /**
346
- * Make HTTP request and parse JSON response
347
- * Subclasses should use their specific response adapters to transform the result
348
- */
349
- async makeJSONRequest(url, options, metadata = {}) {
350
- const response = await this.makeRequest(url, options, metadata);
351
- if (!response.ok) {
352
- const error = new Error(`HTTP ${response.status}: ${response.statusText}`);
353
- error.response = response;
354
- error.status = response.status;
355
- throw error;
356
- }
357
- try {
358
- return await response.json();
359
- } catch (parseError) {
360
- const error = new Error("Failed to parse JSON response");
361
- error.response = response;
362
- error.parseError = parseError;
363
- throw error;
364
- }
365
- }
366
- /**
367
- * Helper method for logging provider-specific operations
368
- */
369
- logOperation(operation, data) {
370
- this.context.logger.info(`${this.metadata.name}: ${operation}`, data);
371
- }
372
- /**
373
- * Helper method for logging provider-specific errors
374
- */
375
- logError(operation, error, data) {
376
- this.context.logger.error(`${this.metadata.name}: ${operation} failed`, { error, data });
377
- }
378
- };
379
-
380
- // src/utils/index.ts
381
- function normalizePhoneNumber(phone) {
382
- const cleaned = phone.replace(/[^\d]/g, "");
383
- if (cleaned.startsWith("82")) {
384
- return "0" + cleaned.substring(2);
385
- }
386
- if (cleaned.startsWith("0")) {
387
- return cleaned;
388
- }
389
- if (cleaned.length >= 10 && cleaned.length <= 11) {
390
- return "0" + cleaned;
391
- }
392
- return cleaned;
393
- }
394
- function validatePhoneNumber(phone) {
395
- const normalized = normalizePhoneNumber(phone);
396
- return /^01[0-9]{8,9}$/.test(normalized);
397
- }
398
- function formatDateTime(date) {
399
- const year = date.getFullYear();
400
- const month = String(date.getMonth() + 1).padStart(2, "0");
401
- const day = String(date.getDate()).padStart(2, "0");
402
- const hours = String(date.getHours()).padStart(2, "0");
403
- const minutes = String(date.getMinutes()).padStart(2, "0");
404
- const seconds = String(date.getSeconds()).padStart(2, "0");
405
- return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
406
- }
407
- function parseTemplate(template, variables) {
408
- let result = template;
409
- for (const [key, value] of Object.entries(variables)) {
410
- const regex = new RegExp(`#{${key}}`, "g");
411
- result = result.replace(regex, value);
412
- }
413
- for (const [key, value] of Object.entries(variables)) {
414
- const regex = new RegExp(`{{${key}}}`, "g");
415
- result = result.replace(regex, value);
416
- }
417
- return result;
418
- }
419
- function extractVariables(template) {
420
- const variables = /* @__PURE__ */ new Set();
421
- const hashMatches = template.match(/#\{([^}]+)\}/g);
422
- if (hashMatches) {
423
- hashMatches.forEach((match) => {
424
- const variable = match.slice(2, -1);
425
- variables.add(variable);
426
- });
427
- }
428
- const braceMatches = template.match(/\{\{([^}]+)\}\}/g);
429
- if (braceMatches) {
430
- braceMatches.forEach((match) => {
431
- const variable = match.slice(2, -2);
432
- variables.add(variable);
433
- });
434
- }
435
- return Array.from(variables);
436
- }
437
- function delay(ms) {
438
- return new Promise((resolve) => setTimeout(resolve, ms));
439
- }
440
- function retry(fn, options) {
441
- return new Promise(async (resolve, reject) => {
442
- let lastError;
443
- for (let attempt = 0; attempt <= options.maxRetries; attempt++) {
444
- try {
445
- if (attempt > 0) {
446
- const delayMs = options.backoff === "exponential" ? options.delay * Math.pow(2, attempt - 1) : options.delay * attempt;
447
- await delay(delayMs);
448
- }
449
- const result = await fn();
450
- resolve(result);
451
- return;
452
- } catch (error) {
453
- lastError = error;
454
- if (attempt === options.maxRetries) {
455
- reject(lastError);
456
- return;
457
- }
458
- }
459
- }
460
- });
461
- }
462
-
463
- // src/abstract/provider.base.ts
464
- var BaseAlimTalkProvider = class {
465
- config = {};
466
- isConfigured = false;
467
- constructor(config) {
468
- if (config) {
469
- this.configure(config);
470
- }
471
- }
472
- /**
473
- * Configure the provider with necessary credentials and settings
474
- */
475
- configure(config) {
476
- this.validateConfiguration(config);
477
- this.config = { ...config };
478
- this.isConfigured = true;
479
- this.onConfigured();
480
- }
481
- /**
482
- * Validate the provided configuration
483
- */
484
- validateConfiguration(config) {
485
- const schema = this.getConfigurationSchema();
486
- for (const field of schema.required) {
487
- if (!(field.key in config)) {
488
- throw new Error(`Required configuration field '${field.key}' is missing`);
489
- }
490
- this.validateFieldValue(field, config[field.key]);
491
- }
492
- for (const field of schema.optional) {
493
- if (field.key in config) {
494
- this.validateFieldValue(field, config[field.key]);
495
- }
496
- }
497
- }
498
- validateFieldValue(field, value) {
499
- switch (field.type) {
500
- case "string":
501
- if (typeof value !== "string") {
502
- throw new Error(`Field '${field.key}' must be a string`);
503
- }
504
- break;
505
- case "number":
506
- if (typeof value !== "number") {
507
- throw new Error(`Field '${field.key}' must be a number`);
508
- }
509
- break;
510
- case "boolean":
511
- if (typeof value !== "boolean") {
512
- throw new Error(`Field '${field.key}' must be a boolean`);
513
- }
514
- break;
515
- case "url":
516
- try {
517
- new URL(String(value));
518
- } catch {
519
- throw new Error(`Field '${field.key}' must be a valid URL`);
520
- }
521
- break;
522
- }
523
- if (field.validation) {
524
- if (field.validation.pattern) {
525
- const regex = new RegExp(field.validation.pattern);
526
- if (!regex.test(String(value))) {
527
- throw new Error(`Field '${field.key}' does not match required pattern`);
528
- }
529
- }
530
- if (field.validation.min !== void 0 && Number(value) < field.validation.min) {
531
- throw new Error(`Field '${field.key}' must be at least ${field.validation.min}`);
532
- }
533
- if (field.validation.max !== void 0 && Number(value) > field.validation.max) {
534
- throw new Error(`Field '${field.key}' must be at most ${field.validation.max}`);
535
- }
536
- }
537
- }
538
- /**
539
- * Called after configuration is set
540
- */
541
- onConfigured() {
542
- }
543
- /**
544
- * Check if the provider is properly configured
545
- */
546
- isReady() {
547
- return this.isConfigured;
548
- }
549
- /**
550
- * Get configuration value
551
- */
552
- getConfig(key) {
553
- if (!this.isConfigured) {
554
- throw new Error("Provider is not configured");
555
- }
556
- return this.config[key];
557
- }
558
- /**
559
- * Check if a configuration key exists
560
- */
561
- hasConfig(key) {
562
- return key in this.config;
563
- }
564
- /**
565
- * Perform health check on the provider
566
- */
567
- async healthCheck() {
568
- const issues = [];
569
- const startTime = Date.now();
570
- try {
571
- if (!this.isReady()) {
572
- issues.push("Provider is not configured");
573
- return { healthy: false, issues };
574
- }
575
- await this.testConnectivity();
576
- await this.testAuthentication();
577
- const latency = Date.now() - startTime;
578
- return {
579
- healthy: issues.length === 0,
580
- issues,
581
- latency
582
- };
583
- } catch (error) {
584
- issues.push(`Health check failed: ${error instanceof Error ? error.message : "Unknown error"}`);
585
- return { healthy: false, issues };
586
- }
587
- }
588
- /**
589
- * Get provider information
590
- */
591
- getInfo() {
592
- return {
593
- id: this.id,
594
- name: this.name,
595
- version: this.getVersion(),
596
- capabilities: this.capabilities,
597
- configured: this.isConfigured
598
- };
599
- }
600
- /**
601
- * Cleanup resources when provider is destroyed
602
- */
603
- destroy() {
604
- this.config = {};
605
- this.isConfigured = false;
606
- this.onDestroy();
607
- }
608
- /**
609
- * Called when provider is being destroyed
610
- */
611
- onDestroy() {
612
- }
613
- /**
614
- * Create standardized error
615
- */
616
- createError(code, message, details) {
617
- const error = new Error(message);
618
- error.code = code;
619
- error.provider = this.id;
620
- error.details = details;
621
- return error;
622
- }
623
- /**
624
- * Log provider activity
625
- */
626
- log(level, message, data) {
627
- const logData = {
628
- provider: this.id,
629
- level,
630
- message,
631
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
632
- };
633
- if (data) {
634
- logData.data = data;
635
- }
636
- console.log(JSON.stringify(logData));
637
- }
638
- /**
639
- * Handle rate limiting
640
- */
641
- async handleRateLimit(operation) {
642
- const rateLimit = this.capabilities.messaging.maxRequestsPerSecond;
643
- if (rateLimit > 0) {
644
- const delay2 = 1e3 / rateLimit;
645
- await new Promise((resolve) => setTimeout(resolve, delay2));
646
- }
647
- }
648
- /**
649
- * Retry mechanism for failed operations
650
- */
651
- async withRetry(operation, options = {}) {
652
- const {
653
- maxRetries = 3,
654
- initialDelay = 1e3,
655
- maxDelay = 1e4,
656
- backoffFactor = 2
657
- } = options;
658
- let lastError;
659
- let delay2 = initialDelay;
660
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
661
- try {
662
- return await operation();
663
- } catch (error) {
664
- lastError = error;
665
- if (attempt === maxRetries) {
666
- break;
667
- }
668
- this.log("warn", `Operation failed, retrying in ${delay2}ms`, {
669
- attempt: attempt + 1,
670
- maxRetries,
671
- error: lastError.message
672
- });
673
- await new Promise((resolve) => setTimeout(resolve, delay2));
674
- delay2 = Math.min(delay2 * backoffFactor, maxDelay);
675
- }
676
- }
677
- throw lastError;
678
- }
679
- };
680
-
681
- // src/adapters/request.adapter.ts
682
- var BaseRequestAdapter = class {
683
- /**
684
- * Common transformation utilities
685
- */
686
- formatPhoneNumber(phoneNumber, countryCode = "KR") {
687
- const digits = phoneNumber.replace(/\D/g, "");
688
- if (countryCode === "KR") {
689
- if (digits.startsWith("82")) {
690
- return digits.substring(2);
691
- }
692
- if (digits.startsWith("0")) {
693
- return digits;
694
- }
695
- return "0" + digits;
696
- }
697
- return phoneNumber;
698
- }
699
- formatVariables(variables) {
700
- const formatted = {};
701
- for (const [key, value] of Object.entries(variables)) {
702
- if (value instanceof Date) {
703
- formatted[key] = value.toISOString();
704
- } else if (typeof value === "object") {
705
- formatted[key] = JSON.stringify(value);
706
- } else {
707
- formatted[key] = String(value);
708
- }
709
- }
710
- return formatted;
711
- }
712
- validateRequiredFields(data, requiredFields) {
713
- const obj = data;
714
- for (const field of requiredFields) {
715
- if (!(field in obj) || obj[field] === void 0 || obj[field] === null) {
716
- throw new Error(`Required field '${field}' is missing`);
717
- }
718
- }
719
- }
720
- };
721
- var IWINVRequestAdapter = class extends BaseRequestAdapter {
722
- transformMessageRequest(request) {
723
- this.validateRequiredFields(request, ["templateCode", "phoneNumber"]);
724
- return {
725
- profile_key: this.getProfileKey(),
726
- template_code: request.templateCode,
727
- phone_number: this.formatPhoneNumber(request.phoneNumber),
728
- message_variables: this.formatVariables(request.variables),
729
- sender_number: request.senderNumber,
730
- reserve_time: request.options?.scheduledAt ? Math.floor(new Date(request.options.scheduledAt).getTime() / 1e3) : void 0
731
- };
732
- }
733
- transformTemplateRequest(request) {
734
- this.validateRequiredFields(request, ["name", "content"]);
735
- return {
736
- profile_key: this.getProfileKey(),
737
- template_name: request.name,
738
- template_content: request.content,
739
- template_category: this.mapCategory(request.category),
740
- template_variables: request.variables?.map((v) => ({
741
- name: v.name,
742
- type: v.type,
743
- required: v.required ? "Y" : "N",
744
- max_length: v.maxLength
745
- })),
746
- template_buttons: request.buttons?.map((b) => ({
747
- type: b.type,
748
- name: b.name,
749
- url_mobile: b.linkMobile,
750
- url_pc: b.linkPc,
751
- scheme_ios: b.schemeIos,
752
- scheme_android: b.schemeAndroid
753
- }))
754
- };
755
- }
756
- getProfileKey() {
757
- return process.env.IWINV_PROFILE_KEY || "";
758
- }
759
- mapCategory(category) {
760
- const categoryMap = {
761
- "AUTHENTICATION": "A",
762
- "NOTIFICATION": "N",
763
- "PROMOTION": "P",
764
- "INFORMATION": "I"
765
- };
766
- return categoryMap[category] || "I";
767
- }
768
- };
769
- var AligoRequestAdapter = class extends BaseRequestAdapter {
770
- transformMessageRequest(request) {
771
- this.validateRequiredFields(request, ["templateCode", "phoneNumber"]);
772
- return {
773
- apikey: this.getApiKey(),
774
- userid: this.getUserId(),
775
- senderkey: this.getSenderKey(),
776
- template_code: request.templateCode,
777
- receiver: this.formatPhoneNumber(request.phoneNumber),
778
- subject: "AlimTalk",
779
- message: this.buildMessage(request),
780
- button: request.variables.buttons ? JSON.stringify(request.variables.buttons) : void 0,
781
- reservation: request.options?.scheduledAt ? this.formatDateTime(new Date(request.options.scheduledAt)) : void 0
782
- };
783
- }
784
- transformTemplateRequest(request) {
785
- this.validateRequiredFields(request, ["name", "content"]);
786
- return {
787
- apikey: this.getApiKey(),
788
- userid: this.getUserId(),
789
- senderkey: this.getSenderKey(),
790
- template_name: request.name,
791
- template_content: request.content,
792
- template_emphasis: this.extractEmphasis(request.content),
793
- template_extra: this.buildTemplateExtra(request),
794
- template_ad: this.isPromotional(request.category) ? "Y" : "N"
795
- };
796
- }
797
- getApiKey() {
798
- return process.env.ALIGO_API_KEY || "";
799
- }
800
- getUserId() {
801
- return process.env.ALIGO_USER_ID || "";
802
- }
803
- getSenderKey() {
804
- return process.env.ALIGO_SENDER_KEY || "";
805
- }
806
- buildMessage(request) {
807
- return request.templateCode;
808
- }
809
- formatDateTime(date) {
810
- return date.toISOString().replace(/[-:]/g, "").replace("T", "").substring(0, 12);
811
- }
812
- extractEmphasis(content) {
813
- const emphasisMatch = content.match(/\*\*(.*?)\*\*/);
814
- return emphasisMatch ? emphasisMatch[1] : "";
815
- }
816
- buildTemplateExtra(request) {
817
- const extra = {};
818
- if (request.buttons) {
819
- extra.buttons = request.buttons;
820
- }
821
- if (request.variables) {
822
- extra.variables = request.variables;
823
- }
824
- return JSON.stringify(extra);
825
- }
826
- isPromotional(category) {
827
- return category === "PROMOTION";
828
- }
829
- };
830
- var KakaoRequestAdapter = class extends BaseRequestAdapter {
831
- transformMessageRequest(request) {
832
- this.validateRequiredFields(request, ["templateCode", "phoneNumber"]);
833
- return {
834
- template_object: {
835
- object_type: "text",
836
- text: this.buildTemplateText(request),
837
- link: this.buildTemplateLink(request),
838
- button_title: request.variables.buttonTitle || ""
839
- },
840
- user_ids: [this.formatPhoneNumber(request.phoneNumber)]
841
- };
842
- }
843
- transformTemplateRequest(request) {
844
- this.validateRequiredFields(request, ["name", "content"]);
845
- return {
846
- template: {
847
- name: request.name,
848
- content: request.content,
849
- category_code: this.mapCategoryCode(request.category),
850
- template_message_type: "BA",
851
- // Basic AlimTalk
852
- template_emphasis_type: this.extractEmphasisType(request.content),
853
- template_title: request.name,
854
- template_subtitle: "",
855
- template_imageurl: "",
856
- template_header: "",
857
- template_item_highlight: {
858
- title: "",
859
- description: ""
860
- },
861
- template_item: {
862
- list: []
863
- },
864
- template_button: this.buildTemplateButtons(request.buttons || [])
865
- }
866
- };
867
- }
868
- buildTemplateText(request) {
869
- let text = request.templateCode;
870
- for (const [key, value] of Object.entries(request.variables)) {
871
- text = text.replace(new RegExp(`#{${key}}`, "g"), String(value));
872
- }
873
- return text;
874
- }
875
- buildTemplateLink(request) {
876
- if (request.variables.linkUrl) {
877
- return {
878
- web_url: request.variables.linkUrl,
879
- mobile_web_url: request.variables.linkUrl
880
- };
881
- }
882
- return {};
883
- }
884
- mapCategoryCode(category) {
885
- const categoryMap = {
886
- "AUTHENTICATION": "999999",
887
- "NOTIFICATION": "999998",
888
- "PROMOTION": "999997",
889
- "INFORMATION": "999996"
890
- };
891
- return categoryMap[category] || "999999";
892
- }
893
- extractEmphasisType(content) {
894
- if (content.includes("**")) return "BOLD";
895
- if (content.includes("__")) return "UNDERLINE";
896
- return "NONE";
897
- }
898
- buildTemplateButtons(buttons) {
899
- return buttons.map((button) => {
900
- const btn = button;
901
- return {
902
- name: btn.name,
903
- type: btn.type,
904
- url_mobile: btn.linkMobile,
905
- url_pc: btn.linkPc,
906
- scheme_ios: btn.schemeIos,
907
- scheme_android: btn.schemeAndroid
908
- };
909
- });
910
- }
911
- };
912
- var RequestAdapterFactory = class _RequestAdapterFactory {
913
- static adapters = /* @__PURE__ */ new Map();
914
- static {
915
- _RequestAdapterFactory.adapters.set("iwinv", IWINVRequestAdapter);
916
- _RequestAdapterFactory.adapters.set("aligo", AligoRequestAdapter);
917
- _RequestAdapterFactory.adapters.set("kakao", KakaoRequestAdapter);
918
- }
919
- static create(providerId) {
920
- const AdapterClass = this.adapters.get(providerId.toLowerCase());
921
- if (!AdapterClass) {
922
- throw new Error(`No request adapter found for provider: ${providerId}`);
923
- }
924
- return new AdapterClass();
925
- }
926
- static register(providerId, adapterClass) {
927
- this.adapters.set(providerId.toLowerCase(), adapterClass);
928
- }
929
- };
930
-
931
- // src/adapters/response.adapter.ts
932
- var BaseResponseAdapter = class {
933
- /**
934
- * Common error transformation
935
- */
936
- transformError(providerError) {
937
- return {
938
- code: this.extractErrorCode(providerError),
939
- message: this.extractErrorMessage(providerError),
940
- details: this.extractErrorDetails(providerError)
941
- };
942
- }
943
- /**
944
- * Common status mapping utilities
945
- */
946
- mapMessageStatus(providerStatus) {
947
- const statusMap = {
948
- "queued": "QUEUED" /* QUEUED */,
949
- "sending": "SENDING" /* SENDING */,
950
- "sent": "SENT" /* SENT */,
951
- "delivered": "DELIVERED" /* DELIVERED */,
952
- "failed": "FAILED" /* FAILED */,
953
- "cancelled": "CANCELLED" /* CANCELLED */
954
- };
955
- return statusMap[providerStatus.toLowerCase()] || "FAILED" /* FAILED */;
956
- }
957
- mapTemplateStatus(providerStatus) {
958
- const statusMap = {
959
- "draft": "DRAFT" /* DRAFT */,
960
- "pending": "PENDING" /* PENDING */,
961
- "approved": "APPROVED" /* APPROVED */,
962
- "rejected": "REJECTED" /* REJECTED */,
963
- "disabled": "DISABLED" /* DISABLED */
964
- };
965
- return statusMap[providerStatus.toLowerCase()] || "DRAFT" /* DRAFT */;
966
- }
967
- parseDate(dateString) {
968
- if (!dateString) return void 0;
969
- try {
970
- return new Date(dateString);
971
- } catch {
972
- return void 0;
973
- }
974
- }
975
- };
976
- var IWINVResponseAdapter = class extends BaseResponseAdapter {
977
- transformMessageResponse(providerResponse) {
978
- const response = providerResponse;
979
- return {
980
- messageId: response.msg_id || response.msgid,
981
- status: this.mapIWINVMessageStatus(response.result_code),
982
- sentAt: this.parseDate(response.send_time),
983
- error: response.result_code !== "1" ? this.transformError(providerResponse) : void 0
984
- };
985
- }
986
- transformTemplateResponse(providerResponse) {
987
- const response = providerResponse;
988
- return {
989
- templateId: response.template_id,
990
- providerTemplateCode: response.template_code,
991
- status: this.mapIWINVTemplateStatus(response.status),
992
- message: response.message || response.comment
993
- };
994
- }
995
- mapIWINVMessageStatus(resultCode) {
996
- const statusMap = {
997
- "1": "SENT" /* SENT */,
998
- "0": "FAILED" /* FAILED */,
999
- "-1": "FAILED" /* FAILED */,
1000
- "-2": "FAILED" /* FAILED */,
1001
- "-3": "FAILED" /* FAILED */,
1002
- "-4": "FAILED" /* FAILED */
1003
- };
1004
- return statusMap[resultCode] || "FAILED" /* FAILED */;
1005
- }
1006
- mapIWINVTemplateStatus(status) {
1007
- const statusMap = {
1008
- "R": "PENDING" /* PENDING */,
1009
- // Request
1010
- "A": "APPROVED" /* APPROVED */,
1011
- // Approved
1012
- "C": "REJECTED" /* REJECTED */,
1013
- // Cancelled/Rejected
1014
- "S": "PENDING" /* PENDING */
1015
- // Standby
1016
- };
1017
- return statusMap[status] || "DRAFT" /* DRAFT */;
1018
- }
1019
- extractErrorCode(providerError) {
1020
- const error = providerError;
1021
- return error.result_code || error.error_code || "UNKNOWN_ERROR";
1022
- }
1023
- extractErrorMessage(providerError) {
1024
- const error = providerError;
1025
- return error.message || error.error_message || "Unknown error occurred";
1026
- }
1027
- extractErrorDetails(providerError) {
1028
- const error = providerError;
1029
- return {
1030
- resultCode: error.result_code,
1031
- originalResponse: providerError
1032
- };
1033
- }
1034
- };
1035
- var AligoResponseAdapter = class extends BaseResponseAdapter {
1036
- transformMessageResponse(providerResponse) {
1037
- const response = providerResponse;
1038
- return {
1039
- messageId: response.msg_id || response.mid,
1040
- status: this.mapAligoMessageStatus(response.result_code),
1041
- sentAt: this.parseDate(response.send_time),
1042
- error: response.result_code !== "1" ? this.transformError(providerResponse) : void 0
1043
- };
1044
- }
1045
- transformTemplateResponse(providerResponse) {
1046
- const response = providerResponse;
1047
- return {
1048
- templateId: response.template_code,
1049
- providerTemplateCode: response.template_code,
1050
- status: this.mapAligoTemplateStatus(response.inspect_status),
1051
- message: response.comment
1052
- };
1053
- }
1054
- mapAligoMessageStatus(resultCode) {
1055
- const statusMap = {
1056
- "1": "SENT" /* SENT */,
1057
- "0": "FAILED" /* FAILED */,
1058
- "-1": "FAILED" /* FAILED */,
1059
- "-101": "FAILED" /* FAILED */,
1060
- "-102": "FAILED" /* FAILED */
1061
- };
1062
- return statusMap[resultCode] || "FAILED" /* FAILED */;
1063
- }
1064
- mapAligoTemplateStatus(inspectStatus) {
1065
- const statusMap = {
1066
- "REG": "PENDING" /* PENDING */,
1067
- // Registered
1068
- "REQ": "PENDING" /* PENDING */,
1069
- // Request
1070
- "APR": "APPROVED" /* APPROVED */,
1071
- // Approved
1072
- "REJ": "REJECTED" /* REJECTED */,
1073
- // Rejected
1074
- "STOP": "DISABLED" /* DISABLED */
1075
- // Stopped
1076
- };
1077
- return statusMap[inspectStatus] || "DRAFT" /* DRAFT */;
1078
- }
1079
- extractErrorCode(providerError) {
1080
- const error = providerError;
1081
- return error.result_code || error.code || "UNKNOWN_ERROR";
1082
- }
1083
- extractErrorMessage(providerError) {
1084
- const error = providerError;
1085
- return error.message || error.error || "Unknown error occurred";
1086
- }
1087
- extractErrorDetails(providerError) {
1088
- const error = providerError;
1089
- return {
1090
- resultCode: error.result_code,
1091
- inspectStatus: error.inspect_status,
1092
- originalResponse: providerError
1093
- };
1094
- }
1095
- };
1096
- var KakaoResponseAdapter = class extends BaseResponseAdapter {
1097
- transformMessageResponse(providerResponse) {
1098
- const response = providerResponse;
1099
- return {
1100
- messageId: response.message_id,
1101
- status: this.mapKakaoMessageStatus(response.result_code),
1102
- sentAt: this.parseDate(response.sent_time),
1103
- error: response.result_code !== 0 ? this.transformError(providerResponse) : void 0
1104
- };
1105
- }
1106
- transformTemplateResponse(providerResponse) {
1107
- const response = providerResponse;
1108
- return {
1109
- templateId: response.template_id,
1110
- providerTemplateCode: response.template_code,
1111
- status: this.mapKakaoTemplateStatus(response.status),
1112
- message: response.comments
1113
- };
1114
- }
1115
- mapKakaoMessageStatus(resultCode) {
1116
- const statusMap = {
1117
- 0: "SENT" /* SENT */,
1118
- [-1]: "FAILED" /* FAILED */,
1119
- [-2]: "FAILED" /* FAILED */,
1120
- [-3]: "FAILED" /* FAILED */,
1121
- [-999]: "FAILED" /* FAILED */
1122
- };
1123
- return statusMap[resultCode] || "FAILED" /* FAILED */;
1124
- }
1125
- mapKakaoTemplateStatus(status) {
1126
- const statusMap = {
1127
- "TSC01": "PENDING" /* PENDING */,
1128
- // Under review
1129
- "TSC02": "APPROVED" /* APPROVED */,
1130
- // Approved
1131
- "TSC03": "REJECTED" /* REJECTED */,
1132
- // Rejected
1133
- "TSC04": "DISABLED" /* DISABLED */
1134
- // Disabled
1135
- };
1136
- return statusMap[status] || "DRAFT" /* DRAFT */;
1137
- }
1138
- extractErrorCode(providerError) {
1139
- const error = providerError;
1140
- return String(error.result_code || error.error_code || "UNKNOWN_ERROR");
1141
- }
1142
- extractErrorMessage(providerError) {
1143
- const error = providerError;
1144
- return error.message || error.error_message || "Unknown error occurred";
1145
- }
1146
- extractErrorDetails(providerError) {
1147
- const error = providerError;
1148
- return {
1149
- resultCode: error.result_code,
1150
- originalResponse: providerError
1151
- };
1152
- }
1153
- };
1154
- var NHNResponseAdapter = class extends BaseResponseAdapter {
1155
- transformMessageResponse(providerResponse) {
1156
- const response = providerResponse;
1157
- return {
1158
- messageId: response.requestId,
1159
- status: this.mapNHNMessageStatus(response.statusCode),
1160
- sentAt: this.parseDate(response.statusDateTime),
1161
- error: response.statusCode !== "SSS" ? this.transformError(providerResponse) : void 0
1162
- };
1163
- }
1164
- transformTemplateResponse(providerResponse) {
1165
- const response = providerResponse;
1166
- return {
1167
- templateId: response.templateId,
1168
- providerTemplateCode: response.templateId,
1169
- status: this.mapNHNTemplateStatus(response.templateStatus),
1170
- message: response.templateStatusName
1171
- };
1172
- }
1173
- mapNHNMessageStatus(statusCode) {
1174
- const statusMap = {
1175
- "SSS": "SENT" /* SENT */,
1176
- // Success
1177
- "RDY": "QUEUED" /* QUEUED */,
1178
- // Ready
1179
- "PRG": "SENDING" /* SENDING */,
1180
- // Progress
1181
- "CPL": "DELIVERED" /* DELIVERED */,
1182
- // Complete
1183
- "FAL": "FAILED" /* FAILED */,
1184
- // Failed
1185
- "CAL": "CANCELLED" /* CANCELLED */
1186
- // Cancelled
1187
- };
1188
- return statusMap[statusCode] || "FAILED" /* FAILED */;
1189
- }
1190
- mapNHNTemplateStatus(templateStatus) {
1191
- const statusMap = {
1192
- "WAITING": "PENDING" /* PENDING */,
1193
- "APPROVED": "APPROVED" /* APPROVED */,
1194
- "REJECTED": "REJECTED" /* REJECTED */,
1195
- "DISABLED": "DISABLED" /* DISABLED */
1196
- };
1197
- return statusMap[templateStatus] || "DRAFT" /* DRAFT */;
1198
- }
1199
- extractErrorCode(providerError) {
1200
- const error = providerError;
1201
- return error.statusCode || error.errorCode || "UNKNOWN_ERROR";
1202
- }
1203
- extractErrorMessage(providerError) {
1204
- const error = providerError;
1205
- return error.statusMessage || error.errorMessage || "Unknown error occurred";
1206
- }
1207
- extractErrorDetails(providerError) {
1208
- const error = providerError;
1209
- return {
1210
- statusCode: error.statusCode,
1211
- statusMessage: error.statusMessage,
1212
- originalResponse: providerError
1213
- };
1214
- }
1215
- };
1216
- var ResponseAdapterFactory = class {
1217
- static adapters = /* @__PURE__ */ new Map([
1218
- ["iwinv", IWINVResponseAdapter],
1219
- ["aligo", AligoResponseAdapter],
1220
- ["kakao", KakaoResponseAdapter],
1221
- ["nhn", NHNResponseAdapter]
1222
- ]);
1223
- static create(providerId) {
1224
- const AdapterClass = this.adapters.get(providerId.toLowerCase());
1225
- if (!AdapterClass) {
1226
- throw new Error(`No response adapter found for provider: ${providerId}`);
1227
- }
1228
- return new AdapterClass();
1229
- }
1230
- static register(providerId, adapterClass) {
1231
- this.adapters.set(providerId.toLowerCase(), adapterClass);
1232
- }
1233
- };
1234
-
1235
- // src/services/provider.manager.ts
1236
- var ProviderManager = class {
1237
- providers = /* @__PURE__ */ new Map();
1238
- defaultProvider;
1239
- registerProvider(provider) {
1240
- this.providers.set(provider.id, provider);
1241
- if (!this.defaultProvider) {
1242
- this.defaultProvider = provider.id;
1243
- }
1244
- }
1245
- unregisterProvider(providerId) {
1246
- this.providers.delete(providerId);
1247
- if (this.defaultProvider === providerId) {
1248
- const remaining = Array.from(this.providers.keys());
1249
- this.defaultProvider = remaining.length > 0 ? remaining[0] : void 0;
1250
- }
1251
- }
1252
- getProvider(providerId) {
1253
- const id = providerId || this.defaultProvider;
1254
- return id ? this.providers.get(id) || null : null;
1255
- }
1256
- listProviders() {
1257
- return Array.from(this.providers.values());
1258
- }
1259
- setDefaultProvider(providerId) {
1260
- if (!this.providers.has(providerId)) {
1261
- throw new Error(`Provider ${providerId} not found`);
1262
- }
1263
- this.defaultProvider = providerId;
1264
- }
1265
- async healthCheckAll() {
1266
- const results = {};
1267
- for (const [id, provider] of this.providers.entries()) {
1268
- try {
1269
- const health = await provider.healthCheck();
1270
- results[id] = health.healthy;
1271
- } catch (error) {
1272
- results[id] = false;
1273
- }
1274
- }
1275
- return results;
1276
- }
1277
- getProvidersForChannel(channel) {
1278
- return Array.from(this.providers.values()).filter((provider) => {
1279
- const providerWithChannels = provider;
1280
- return providerWithChannels.supportedChannels?.includes(channel);
1281
- });
1282
- }
1283
- };
1284
-
1285
- // src/iwinv/contracts/messaging.contract.ts
1286
- var IWINVMessagingContract = class {
1287
- constructor(config) {
1288
- this.config = config;
1289
- }
1290
- async send(message) {
1291
- try {
1292
- const response = await fetch(`${this.config.baseUrl}/send`, {
1293
- method: "POST",
1294
- headers: {
1295
- "Content-Type": "application/json",
1296
- "Authorization": `Bearer ${this.config.apiKey}`
1297
- },
1298
- body: JSON.stringify({
1299
- templateCode: message.templateCode,
1300
- phone: message.phoneNumber,
1301
- variables: message.variables,
1302
- senderNumber: message.senderNumber,
1303
- ...message.options
1304
- })
1305
- });
1306
- const result = await response.json();
1307
- if (!response.ok) {
1308
- return {
1309
- messageId: `failed_${Date.now()}`,
1310
- status: "FAILED" /* FAILED */,
1311
- error: {
1312
- code: result.code || "SEND_FAILED",
1313
- message: result.message || "Failed to send message"
1314
- }
1315
- };
1316
- }
1317
- return {
1318
- messageId: result.messageId || `msg_${Date.now()}`,
1319
- status: "SENT" /* SENT */,
1320
- sentAt: /* @__PURE__ */ new Date()
1321
- };
1322
- } catch (error) {
1323
- return {
1324
- messageId: `error_${Date.now()}`,
1325
- status: "FAILED" /* FAILED */,
1326
- error: {
1327
- code: "NETWORK_ERROR",
1328
- message: error instanceof Error ? error.message : "Network error occurred"
1329
- }
1330
- };
1331
- }
1332
- }
1333
- async sendBulk(messages) {
1334
- const results = [];
1335
- for (const message of messages) {
1336
- const result = await this.send(message);
1337
- results.push(result);
1338
- }
1339
- const sent = results.filter((r) => r.status === "SENT" /* SENT */).length;
1340
- const failed = results.filter((r) => r.status === "FAILED" /* FAILED */).length;
1341
- return {
1342
- requestId: `bulk_${Date.now()}`,
1343
- results,
1344
- summary: {
1345
- total: messages.length,
1346
- sent,
1347
- failed
1348
- }
1349
- };
1350
- }
1351
- async schedule(message, scheduledAt) {
1352
- return {
1353
- scheduleId: `schedule_${Date.now()}`,
1354
- messageId: `msg_${Date.now()}`,
1355
- scheduledAt,
1356
- status: "scheduled"
1357
- };
1358
- }
1359
- async cancel(messageId) {
1360
- const response = await fetch(`${this.config.baseUrl}/cancel`, {
1361
- method: "POST",
1362
- headers: {
1363
- "Content-Type": "application/json",
1364
- "Authorization": `Bearer ${this.config.apiKey}`
1365
- },
1366
- body: JSON.stringify({ messageId })
1367
- });
1368
- if (!response.ok) {
1369
- const result = await response.json();
1370
- throw new Error(`Failed to cancel message: ${result.message}`);
1371
- }
1372
- }
1373
- async getStatus(messageId) {
1374
- try {
1375
- const response = await fetch(`${this.config.baseUrl}/status`, {
1376
- method: "POST",
1377
- headers: {
1378
- "Content-Type": "application/json",
1379
- "Authorization": `Bearer ${this.config.apiKey}`
1380
- },
1381
- body: JSON.stringify({ messageId })
1382
- });
1383
- const result = await response.json();
1384
- if (!response.ok) {
1385
- return "FAILED" /* FAILED */;
1386
- }
1387
- switch (result.statusCode) {
1388
- case "OK":
1389
- return "DELIVERED" /* DELIVERED */;
1390
- case "PENDING":
1391
- return "SENDING" /* SENDING */;
1392
- case "FAILED":
1393
- return "FAILED" /* FAILED */;
1394
- default:
1395
- return "SENT" /* SENT */;
1396
- }
1397
- } catch (error) {
1398
- return "FAILED" /* FAILED */;
1399
- }
1400
- }
1401
- };
1402
-
1403
- // src/iwinv/contracts/template.contract.ts
1404
- var IWINVTemplateContract = class {
1405
- constructor(config) {
1406
- this.config = config;
1407
- }
1408
- async create(template) {
1409
- try {
1410
- const response = await fetch(`${this.config.baseUrl}/template/create`, {
1411
- method: "POST",
1412
- headers: {
1413
- "Content-Type": "application/json",
1414
- "Authorization": `Bearer ${this.config.apiKey}`
1415
- },
1416
- body: JSON.stringify({
1417
- templateName: template.name,
1418
- templateContent: template.content,
1419
- templateCategory: template.category,
1420
- templateVariables: template.variables,
1421
- templateButtons: template.buttons
1422
- })
1423
- });
1424
- const result = await response.json();
1425
- if (!response.ok) {
1426
- throw new Error(`Template creation failed: ${result.message}`);
1427
- }
1428
- return {
1429
- templateId: result.templateId || `tpl_${Date.now()}`,
1430
- providerTemplateCode: result.templateCode || template.name,
1431
- status: "PENDING" /* PENDING */,
1432
- message: result.message || "Template created successfully"
1433
- };
1434
- } catch (error) {
1435
- throw new Error(`Failed to create template: ${error instanceof Error ? error.message : "Unknown error"}`);
1436
- }
1437
- }
1438
- async update(templateId, template) {
1439
- try {
1440
- const response = await fetch(`${this.config.baseUrl}/template/modify`, {
1441
- method: "POST",
1442
- headers: {
1443
- "Content-Type": "application/json",
1444
- "Authorization": `Bearer ${this.config.apiKey}`
1445
- },
1446
- body: JSON.stringify({
1447
- templateCode: templateId,
1448
- templateName: template.name,
1449
- templateContent: template.content,
1450
- templateButtons: template.buttons
1451
- })
1452
- });
1453
- const result = await response.json();
1454
- if (!response.ok) {
1455
- throw new Error(`Template update failed: ${result.message}`);
1456
- }
1457
- return {
1458
- templateId,
1459
- status: "PENDING" /* PENDING */,
1460
- message: result.message || "Template updated successfully"
1461
- };
1462
- } catch (error) {
1463
- throw new Error(`Failed to update template: ${error instanceof Error ? error.message : "Unknown error"}`);
1464
- }
1465
- }
1466
- async delete(templateId) {
1467
- try {
1468
- const response = await fetch(`${this.config.baseUrl}/template/delete`, {
1469
- method: "POST",
1470
- headers: {
1471
- "Content-Type": "application/json",
1472
- "Authorization": `Bearer ${this.config.apiKey}`
1473
- },
1474
- body: JSON.stringify({
1475
- templateCode: templateId
1476
- })
1477
- });
1478
- const result = await response.json();
1479
- if (!response.ok) {
1480
- throw new Error(`Template deletion failed: ${result.message}`);
1481
- }
1482
- } catch (error) {
1483
- throw new Error(`Failed to delete template: ${error instanceof Error ? error.message : "Unknown error"}`);
1484
- }
1485
- }
1486
- async get(templateId) {
1487
- const templates = await this.list({ templateCode: templateId });
1488
- const template = templates.find((t) => t.code === templateId);
1489
- if (!template) {
1490
- throw new Error(`Template ${templateId} not found`);
1491
- }
1492
- return template;
1493
- }
1494
- async list(filters) {
1495
- try {
1496
- const response = await fetch(`${this.config.baseUrl}/template/list`, {
1497
- method: "POST",
1498
- headers: {
1499
- "Content-Type": "application/json",
1500
- "Authorization": `Bearer ${this.config.apiKey}`
1501
- },
1502
- body: JSON.stringify({
1503
- page: 1,
1504
- size: 100,
1505
- ...filters
1506
- })
1507
- });
1508
- const result = await response.json();
1509
- if (!response.ok) {
1510
- throw new Error(`Failed to list templates: ${result.message}`);
1511
- }
1512
- return (result.list || []).map((template) => ({
1513
- id: template.templateId || template.templateCode,
1514
- code: template.templateCode,
1515
- name: template.templateName,
1516
- content: template.templateContent,
1517
- status: this.mapIWINVStatus(template.status || template.templateStatus),
1518
- createdAt: template.createDate ? new Date(template.createDate) : /* @__PURE__ */ new Date(),
1519
- updatedAt: template.updateDate ? new Date(template.updateDate) : /* @__PURE__ */ new Date(),
1520
- approvedAt: template.approvedAt ? new Date(template.approvedAt) : void 0,
1521
- rejectedAt: template.rejectedAt ? new Date(template.rejectedAt) : void 0,
1522
- rejectionReason: template.rejectionReason
1523
- }));
1524
- } catch (error) {
1525
- throw new Error(`Failed to list templates: ${error instanceof Error ? error.message : "Unknown error"}`);
1526
- }
1527
- }
1528
- async sync() {
1529
- try {
1530
- const templates = await this.list();
1531
- return {
1532
- synced: templates.length,
1533
- created: 0,
1534
- updated: 0,
1535
- deleted: 0,
1536
- errors: []
1537
- };
1538
- } catch (error) {
1539
- return {
1540
- synced: 0,
1541
- created: 0,
1542
- updated: 0,
1543
- deleted: 0,
1544
- errors: [{
1545
- templateId: "unknown",
1546
- error: error instanceof Error ? error.message : "Sync failed"
1547
- }]
1548
- };
1549
- }
1550
- }
1551
- mapIWINVStatus(status) {
1552
- switch (status) {
1553
- case "Y":
1554
- return "APPROVED" /* APPROVED */;
1555
- case "I":
1556
- return "PENDING" /* PENDING */;
1557
- case "R":
1558
- return "REJECTED" /* REJECTED */;
1559
- case "D":
1560
- return "DISABLED" /* DISABLED */;
1561
- default:
1562
- return "DRAFT" /* DRAFT */;
1563
- }
1564
- }
1565
- };
1566
-
1567
- // src/iwinv/contracts/channel.contract.ts
1568
- var IWINVChannelContract = class {
1569
- constructor(config) {
1570
- this.config = config;
1571
- }
1572
- async register(channel) {
1573
- return {
1574
- id: `channel_${Date.now()}`,
1575
- name: channel.name,
1576
- profileKey: channel.profileKey,
1577
- status: "pending",
1578
- createdAt: /* @__PURE__ */ new Date(),
1579
- updatedAt: /* @__PURE__ */ new Date()
1580
- };
1581
- }
1582
- async list() {
1583
- return [
1584
- {
1585
- id: "iwinv-default",
1586
- name: "IWINV Default Channel",
1587
- profileKey: "default",
1588
- status: "active",
1589
- createdAt: /* @__PURE__ */ new Date(),
1590
- updatedAt: /* @__PURE__ */ new Date()
1591
- }
1592
- ];
1593
- }
1594
- async addSenderNumber(channelId, number) {
1595
- return {
1596
- id: `sender_${Date.now()}`,
1597
- channelId,
1598
- phoneNumber: number,
1599
- isVerified: false,
1600
- createdAt: /* @__PURE__ */ new Date()
1601
- };
1602
- }
1603
- async verifySenderNumber(number, verificationCode) {
1604
- return true;
1605
- }
1606
- };
1607
-
1608
- // src/iwinv/contracts/analytics.contract.ts
1609
- var IWINVAnalyticsContract = class {
1610
- constructor(config) {
1611
- this.config = config;
1612
- }
1613
- async getUsage(period) {
1614
- try {
1615
- const response = await fetch(`${this.config.baseUrl}/history/list`, {
1616
- method: "POST",
1617
- headers: {
1618
- "Content-Type": "application/json",
1619
- "Authorization": `Bearer ${this.config.apiKey}`
1620
- },
1621
- body: JSON.stringify({
1622
- startDate: period.from.toISOString(),
1623
- endDate: period.to.toISOString(),
1624
- page: 1,
1625
- size: 1e3
1626
- })
1627
- });
1628
- const result = await response.json();
1629
- if (!response.ok) {
1630
- throw new Error(`Failed to get usage stats: ${result.message}`);
1631
- }
1632
- const messages = result.list || [];
1633
- const totalMessages = messages.length;
1634
- const deliveredMessages = messages.filter((msg) => msg.statusCode === "OK").length;
1635
- const failedMessages = messages.filter((msg) => msg.statusCode === "FAILED").length;
1636
- const sentMessages = totalMessages - failedMessages;
1637
- return {
1638
- period,
1639
- totalMessages,
1640
- sentMessages,
1641
- deliveredMessages,
1642
- failedMessages,
1643
- deliveryRate: totalMessages > 0 ? deliveredMessages / totalMessages * 100 : 0,
1644
- failureRate: totalMessages > 0 ? failedMessages / totalMessages * 100 : 0,
1645
- breakdown: {
1646
- byTemplate: this.groupByTemplate(messages),
1647
- byDay: this.groupByDay(messages, period),
1648
- byHour: this.groupByHour(messages)
1649
- }
1650
- };
1651
- } catch (error) {
1652
- return {
1653
- period,
1654
- totalMessages: 0,
1655
- sentMessages: 0,
1656
- deliveredMessages: 0,
1657
- failedMessages: 0,
1658
- deliveryRate: 0,
1659
- failureRate: 0,
1660
- breakdown: {
1661
- byTemplate: {},
1662
- byDay: {},
1663
- byHour: {}
1664
- }
1665
- };
1666
- }
1667
- }
1668
- async getTemplateStats(templateId, period) {
1669
- try {
1670
- const usage = await this.getUsage(period);
1671
- const templateMessages = usage.breakdown.byTemplate[templateId] || 0;
1672
- return {
1673
- templateId,
1674
- period,
1675
- totalSent: templateMessages,
1676
- delivered: Math.round(templateMessages * (usage.deliveryRate / 100)),
1677
- failed: Math.round(templateMessages * (usage.failureRate / 100)),
1678
- deliveryRate: usage.deliveryRate,
1679
- averageDeliveryTime: 30
1680
- // Mock average delivery time in seconds
1681
- };
1682
- } catch (error) {
1683
- return {
1684
- templateId,
1685
- period,
1686
- totalSent: 0,
1687
- delivered: 0,
1688
- failed: 0,
1689
- deliveryRate: 0,
1690
- averageDeliveryTime: 0
1691
- };
1692
- }
1693
- }
1694
- async getDeliveryReport(messageId) {
1695
- try {
1696
- const response = await fetch(`${this.config.baseUrl}/history/detail`, {
1697
- method: "POST",
1698
- headers: {
1699
- "Content-Type": "application/json",
1700
- "Authorization": `Bearer ${this.config.apiKey}`
1701
- },
1702
- body: JSON.stringify({
1703
- messageId: parseInt(messageId) || 0
1704
- })
1705
- });
1706
- const result = await response.json();
1707
- if (!response.ok) {
1708
- throw new Error(`Failed to get delivery report: ${result.message}`);
1709
- }
1710
- return {
1711
- messageId,
1712
- phoneNumber: result.phone || "unknown",
1713
- templateCode: result.templateCode || "unknown",
1714
- status: this.mapStatus(result.statusCode),
1715
- sentAt: result.sendDate ? new Date(result.sendDate) : void 0,
1716
- deliveredAt: result.receiveDate ? new Date(result.receiveDate) : void 0,
1717
- failedAt: result.statusCode === "FAILED" ? new Date(result.sendDate) : void 0,
1718
- clickedAt: result.clickedAt ? new Date(result.clickedAt) : void 0,
1719
- error: result.statusCode !== "OK" ? {
1720
- code: result.statusCode,
1721
- message: result.statusCodeName
1722
- } : void 0,
1723
- attempts: [
1724
- {
1725
- attemptNumber: 1,
1726
- attemptedAt: new Date(result.requestDate),
1727
- status: this.mapStatus(result.statusCode),
1728
- error: result.statusCode !== "OK" ? {
1729
- code: result.statusCode,
1730
- message: result.statusCodeName
1731
- } : void 0
1732
- }
1733
- ]
1734
- };
1735
- } catch (error) {
1736
- return {
1737
- messageId,
1738
- phoneNumber: "unknown",
1739
- templateCode: "unknown",
1740
- status: "FAILED",
1741
- error: {
1742
- code: "API_ERROR",
1743
- message: error instanceof Error ? error.message : "Unknown error"
1744
- },
1745
- attempts: []
1746
- };
1747
- }
1748
- }
1749
- groupByTemplate(messages) {
1750
- const groups = {};
1751
- messages.forEach((msg) => {
1752
- const template = msg.templateCode || "unknown";
1753
- groups[template] = (groups[template] || 0) + 1;
1754
- });
1755
- return groups;
1756
- }
1757
- groupByDay(messages, period) {
1758
- const groups = {};
1759
- const current = new Date(period.from);
1760
- while (current <= period.to) {
1761
- const dateKey = current.toISOString().split("T")[0];
1762
- groups[dateKey] = 0;
1763
- current.setDate(current.getDate() + 1);
1764
- }
1765
- messages.forEach((msg) => {
1766
- if (msg.requestDate) {
1767
- const dateKey = new Date(msg.requestDate).toISOString().split("T")[0];
1768
- if (groups.hasOwnProperty(dateKey)) {
1769
- groups[dateKey]++;
1770
- }
1771
- }
1772
- });
1773
- return groups;
1774
- }
1775
- groupByHour(messages) {
1776
- const groups = {};
1777
- for (let i = 0; i < 24; i++) {
1778
- groups[i.toString()] = 0;
1779
- }
1780
- messages.forEach((msg) => {
1781
- if (msg.requestDate) {
1782
- const hour = new Date(msg.requestDate).getHours();
1783
- groups[hour.toString()]++;
1784
- }
1785
- });
1786
- return groups;
1787
- }
1788
- mapStatus(statusCode) {
1789
- switch (statusCode) {
1790
- case "OK":
1791
- return "DELIVERED";
1792
- case "PENDING":
1793
- return "SENDING";
1794
- case "FAILED":
1795
- return "FAILED";
1796
- default:
1797
- return "SENT";
1798
- }
1799
- }
1800
- };
1801
-
1802
- // src/iwinv/contracts/account.contract.ts
1803
- var IWINVAccountContract = class {
1804
- constructor(config) {
1805
- this.config = config;
1806
- }
1807
- async getBalance() {
1808
- try {
1809
- const response = await fetch(`${this.config.baseUrl}/balance`, {
1810
- method: "GET",
1811
- headers: {
1812
- "Authorization": `Bearer ${this.config.apiKey}`
1813
- }
1814
- });
1815
- const result = await response.json();
1816
- if (!response.ok) {
1817
- throw new Error(`Failed to get balance: ${result.message}`);
1818
- }
1819
- return {
1820
- current: Number(result.balance) || 0,
1821
- currency: "KRW",
1822
- lastUpdated: /* @__PURE__ */ new Date(),
1823
- threshold: Number(result.threshold) || void 0
1824
- };
1825
- } catch (error) {
1826
- return {
1827
- current: 0,
1828
- currency: "KRW",
1829
- lastUpdated: /* @__PURE__ */ new Date()
1830
- };
1831
- }
1832
- }
1833
- async getProfile() {
1834
- try {
1835
- const balance = await this.getBalance();
1836
- return {
1837
- accountId: "iwinv-account",
1838
- name: "IWINV Account",
1839
- email: "account@iwinv.kr",
1840
- phone: "1588-1234",
1841
- status: balance.current > 0 ? "active" : "suspended",
1842
- tier: "standard",
1843
- features: ["alimtalk", "sms", "lms"],
1844
- limits: {
1845
- dailyMessageLimit: 1e4,
1846
- monthlyMessageLimit: 3e5,
1847
- rateLimit: 100
1848
- // per second
1849
- }
1850
- };
1851
- } catch (error) {
1852
- return {
1853
- accountId: "iwinv-account",
1854
- name: "IWINV Account",
1855
- email: "account@iwinv.kr",
1856
- phone: "1588-1234",
1857
- status: "active",
1858
- tier: "basic",
1859
- features: ["alimtalk"],
1860
- limits: {
1861
- dailyMessageLimit: 1e3,
1862
- monthlyMessageLimit: 3e4,
1863
- rateLimit: 10
1864
- }
1865
- };
1866
- }
1867
- }
1868
- };
1869
-
1870
- // src/iwinv/provider.ts
1871
- var IWINVProvider = class extends BaseAlimTalkProvider {
1872
- id = "iwinv";
1873
- name = "IWINV AlimTalk Provider";
1874
- capabilities = {
1875
- templates: {
1876
- maxLength: 1e3,
1877
- maxVariables: 20,
1878
- maxButtons: 5,
1879
- supportedButtonTypes: ["WL", "AL", "DB", "BK", "MD"],
1880
- requiresApproval: true,
1881
- approvalTime: "1-2 days"
1882
- },
1883
- messaging: {
1884
- maxRecipientsPerRequest: 1,
1885
- maxRequestsPerSecond: 100,
1886
- supportsBulk: false,
1887
- // IWINV doesn't have native bulk API
1888
- supportsScheduling: true,
1889
- maxScheduleDays: 30,
1890
- supportsFallback: true
1891
- },
1892
- channels: {
1893
- requiresBusinessVerification: true,
1894
- maxSenderNumbers: 10,
1895
- supportsMultipleChannels: false
1896
- }
1897
- };
1898
- // Contract implementations
1899
- templates;
1900
- channels;
1901
- messaging;
1902
- analytics;
1903
- account;
1904
- constructor(config) {
1905
- super(config);
1906
- const iwinvConfig = this.getIWINVConfig();
1907
- this.templates = new IWINVTemplateContract(iwinvConfig);
1908
- this.channels = new IWINVChannelContract(iwinvConfig);
1909
- this.messaging = new IWINVMessagingContract(iwinvConfig);
1910
- this.analytics = new IWINVAnalyticsContract(iwinvConfig);
1911
- this.account = new IWINVAccountContract(iwinvConfig);
1912
- }
1913
- getConfigurationSchema() {
1914
- return {
1915
- required: [
1916
- {
1917
- key: "apiKey",
1918
- name: "IWINV API Key",
1919
- type: "password",
1920
- description: "Your IWINV API key",
1921
- required: true,
1922
- validation: {
1923
- pattern: "^[a-zA-Z0-9-_]+$",
1924
- min: 10
1925
- }
1926
- }
1927
- ],
1928
- optional: [
1929
- {
1930
- key: "baseUrl",
1931
- name: "Base URL",
1932
- type: "url",
1933
- description: "IWINV API base URL",
1934
- required: false,
1935
- default: "https://alimtalk.bizservice.iwinv.kr",
1936
- validation: {
1937
- pattern: "^https?://.+"
1938
- }
1939
- },
1940
- {
1941
- key: "debug",
1942
- name: "Debug Mode",
1943
- type: "boolean",
1944
- description: "Enable debug logging",
1945
- required: false,
1946
- default: false
1947
- }
1948
- ]
1949
- };
1950
- }
1951
- async testConnectivity() {
1952
- const config = this.getIWINVConfig();
1953
- try {
1954
- const response = await fetch(`${config.baseUrl}/balance`, {
1955
- method: "GET",
1956
- headers: {
1957
- "Authorization": `Bearer ${config.apiKey}`
1958
- }
1959
- });
1960
- if (!response.ok) {
1961
- throw new Error(`Connectivity test failed: ${response.status} ${response.statusText}`);
1962
- }
1963
- } catch (error) {
1964
- throw new Error(`Cannot connect to IWINV API: ${error instanceof Error ? error.message : "Unknown error"}`);
1965
- }
1966
- }
1967
- async testAuthentication() {
1968
- const config = this.getIWINVConfig();
1969
- try {
1970
- const response = await fetch(`${config.baseUrl}/balance`, {
1971
- method: "GET",
1972
- headers: {
1973
- "Authorization": `Bearer ${config.apiKey}`
1974
- }
1975
- });
1976
- if (response.status === 401 || response.status === 403) {
1977
- throw new Error("Invalid API key or insufficient permissions");
1978
- }
1979
- if (!response.ok) {
1980
- const result = await response.json().catch(() => ({}));
1981
- throw new Error(`Authentication failed: ${result.message || response.statusText}`);
1982
- }
1983
- } catch (error) {
1984
- if (error instanceof Error && error.message.includes("Authentication failed")) {
1985
- throw error;
1986
- }
1987
- throw new Error(`Authentication test failed: ${error instanceof Error ? error.message : "Unknown error"}`);
1988
- }
1989
- }
1990
- getVersion() {
1991
- return "2.0.0";
1992
- }
1993
- /**
1994
- * Get IWINV-specific configuration
1995
- */
1996
- getIWINVConfig() {
1997
- return {
1998
- apiKey: this.getConfig("apiKey"),
1999
- baseUrl: this.getConfig("baseUrl") || "https://alimtalk.bizservice.iwinv.kr",
2000
- debug: this.getConfig("debug") || false
2001
- };
2002
- }
2003
- /**
2004
- * IWINV-specific methods for backward compatibility
2005
- */
2006
- /**
2007
- * Send AlimTalk message (legacy method)
2008
- */
2009
- async sendMessage(options) {
2010
- return this.messaging.send({
2011
- templateCode: options.templateCode,
2012
- phoneNumber: options.phoneNumber,
2013
- variables: options.variables,
2014
- senderNumber: options.senderNumber
2015
- });
2016
- }
2017
- /**
2018
- * Get account balance (legacy method)
2019
- */
2020
- async getBalance() {
2021
- return this.account.getBalance();
2022
- }
2023
- /**
2024
- * List templates (legacy method)
2025
- */
2026
- async listTemplates(filters) {
2027
- return this.templates.list(filters);
2028
- }
2029
- };
2030
- // Annotate the CommonJS export names for ESM import in node:
2031
- 0 && (module.exports = {
2032
- AligoRequestAdapter,
2033
- AligoResponseAdapter,
2034
- BaseAlimTalkProvider,
2035
- BasePlugin,
2036
- BaseRequestAdapter,
2037
- BaseResponseAdapter,
2038
- IWINVProvider,
2039
- IWINVRequestAdapter,
2040
- IWINVResponseAdapter,
2041
- KakaoRequestAdapter,
2042
- KakaoResponseAdapter,
2043
- NHNResponseAdapter,
2044
- PluginRegistry,
2045
- ProviderManager,
2046
- RequestAdapterFactory,
2047
- ResponseAdapterFactory,
2048
- createCircuitBreakerMiddleware,
2049
- createLoggingMiddleware,
2050
- createMetricsMiddleware,
2051
- createRateLimitMiddleware,
2052
- createRetryMiddleware,
2053
- delay,
2054
- extractVariables,
2055
- formatDateTime,
2056
- normalizePhoneNumber,
2057
- parseTemplate,
2058
- retry,
2059
- validatePhoneNumber
2060
- });
2061
- //# sourceMappingURL=index.cjs.map