@k-msg/provider 0.27.0 → 0.27.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.
- package/dist/aligo/aligo.helpers.d.ts +9 -24
- package/dist/aligo/aligo.shared.helpers.d.ts +22 -0
- package/dist/aligo/aligo.template.helpers.d.ts +2 -0
- package/dist/aligo/index.js +3 -3
- package/dist/aligo/index.mjs +3 -3
- package/dist/aligo/provider.d.ts +3 -28
- package/dist/aligo/provider.send.d.ts +38 -0
- package/dist/aligo/provider.template.d.ts +26 -0
- package/dist/aligo/send.d.ts +5 -0
- package/dist/aligo/send.js +5 -0
- package/dist/aligo/send.mjs +5 -0
- package/dist/aligo/template.d.ts +6 -0
- package/dist/aligo/template.js +5 -0
- package/dist/aligo/template.mjs +5 -0
- package/dist/index.js +3 -3
- package/dist/index.mjs +3 -3
- package/dist/iwinv/index.js +2 -2
- package/dist/iwinv/index.mjs +2 -2
- package/dist/iwinv/provider.d.ts +3 -14
- package/dist/iwinv/provider.send.d.ts +24 -0
- package/dist/iwinv/send.d.ts +5 -0
- package/dist/iwinv/send.js +4 -0
- package/dist/iwinv/send.mjs +4 -0
- package/dist/iwinv/template.d.ts +24 -0
- package/dist/iwinv/template.js +4 -0
- package/dist/iwinv/template.mjs +4 -0
- package/package.json +28 -6
- package/dist/aligo/index.js.map +0 -18
- package/dist/aligo/index.mjs.map +0 -18
- package/dist/index.js.map +0 -32
- package/dist/index.mjs.map +0 -32
- package/dist/iwinv/index.js.map +0 -23
- package/dist/iwinv/index.mjs.map +0 -23
- package/dist/solapi/index.js.map +0 -16
- package/dist/solapi/index.mjs.map +0 -16
package/dist/iwinv/index.mjs.map
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/iwinv/provider.ts", "../src/onboarding/specs.ts", "../src/shared/type-guards.ts", "../src/shared/http-json.ts", "../src/iwinv/iwinv.alimtalk.helpers.ts", "../src/shared/base64.ts", "../src/iwinv/iwinv.constants.ts", "../src/iwinv/iwinv.delivery.ts", "../src/iwinv/iwinv.sms.helpers.ts", "../src/iwinv/iwinv.time.ts", "../src/iwinv/iwinv.send.ts", "../src/iwinv/iwinv.image.ts", "../src/iwinv/iwinv.template.ts", "../src/iwinv/types/iwinv.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import {\n type BalanceProvider,\n type BalanceQuery,\n type BalanceResult,\n type DeliveryStatusQuery,\n type DeliveryStatusResult,\n fail,\n KMsgError,\n KMsgErrorCode,\n type MessageType,\n ok,\n type Provider,\n type ProviderHealthStatus,\n type Result,\n readRuntimeEnv,\n type SendOptions,\n type SendResult,\n type Template,\n type TemplateContext,\n type TemplateCreateInput,\n type TemplateProvider,\n type TemplateUpdateInput,\n} from \"@k-msg/core\";\nimport { getProviderOnboardingSpec } from \"../onboarding/specs\";\nimport { safeParseJson, toRecordOrFallback } from \"../shared/http-json\";\nimport {\n getAlimTalkHeaders,\n mapIwinvCodeToKMsgErrorCode,\n} from \"./iwinv.alimtalk.helpers\";\nimport { IWINV_ALIMTALK_BASE_URL } from \"./iwinv.constants\";\nimport {\n getAlimTalkDeliveryStatus,\n getSmsV2DeliveryStatus,\n} from \"./iwinv.delivery\";\nimport type {\n NormalizedIwinvConfig,\n SmsV2MessageType,\n} from \"./iwinv.internal.types\";\nimport { sendAlimTalk, sendSmsV2 } from \"./iwinv.send\";\nimport {\n buildSmsSecretHeader,\n canSendSmsV2,\n resolveSmsBaseUrl,\n} from \"./iwinv.sms.helpers\";\nimport {\n createTemplate,\n deleteTemplate,\n getTemplate,\n listTemplates,\n updateTemplate,\n} from \"./iwinv.template\";\nimport type { IWINVConfig } from \"./types/iwinv\";\n\nexport class IWINVProvider\n implements Provider, BalanceProvider, TemplateProvider\n{\n readonly id = \"iwinv\";\n readonly name = \"IWINV Messaging Provider\";\n readonly supportedTypes: readonly MessageType[];\n\n private readonly config: NormalizedIwinvConfig;\n\n getOnboardingSpec() {\n const spec = getProviderOnboardingSpec(this.id);\n if (!spec) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n `Onboarding spec missing for provider: ${this.id}`,\n { providerId: this.id },\n );\n }\n return spec;\n }\n\n constructor(config: IWINVConfig) {\n if (!config || typeof config !== \"object\") {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"IWINVProvider requires a config object\",\n { providerId: this.id },\n );\n }\n if (!config.apiKey || config.apiKey.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"IWINVProvider requires `apiKey` configuration\",\n { providerId: this.id },\n );\n }\n\n this.config = {\n ...config,\n baseUrl: IWINV_ALIMTALK_BASE_URL,\n sendEndpoint: config.sendEndpoint || \"/api/v2/send/\",\n };\n\n const types: MessageType[] = [\"ALIMTALK\"];\n if (canSendSmsV2(this.config)) {\n types.push(\"SMS\", \"LMS\", \"MMS\");\n }\n this.supportedTypes = types;\n }\n\n async healthCheck(): Promise<ProviderHealthStatus> {\n const start = Date.now();\n const issues: string[] = [];\n\n try {\n try {\n new URL(this.config.baseUrl);\n } catch {\n issues.push(\"Invalid baseUrl\");\n }\n\n if (canSendSmsV2(this.config)) {\n try {\n new URL(resolveSmsBaseUrl());\n } catch {\n issues.push(\"Invalid smsBaseUrl\");\n }\n }\n\n return {\n healthy: issues.length === 0,\n issues,\n latencyMs: Date.now() - start,\n data: {\n provider: this.id,\n baseUrl: this.config.baseUrl,\n smsBaseUrl: resolveSmsBaseUrl(),\n },\n };\n } catch (error) {\n issues.push(error instanceof Error ? error.message : String(error));\n return { healthy: false, issues, latencyMs: Date.now() - start };\n }\n }\n\n async send(options: SendOptions): Promise<Result<SendResult, KMsgError>> {\n const messageId = options.messageId || crypto.randomUUID();\n const normalized = { ...options, messageId } as SendOptions;\n\n switch (normalized.type) {\n case \"ALIMTALK\":\n return sendAlimTalk({\n providerId: this.id,\n config: this.config,\n options: normalized,\n });\n case \"SMS\":\n case \"LMS\":\n case \"MMS\":\n return sendSmsV2({\n providerId: this.id,\n config: this.config,\n options: normalized as Extract<\n SendOptions,\n { type: SmsV2MessageType }\n >,\n });\n default:\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n `IWINVProvider does not support type ${normalized.type}`,\n { providerId: this.id, type: normalized.type },\n ),\n );\n }\n }\n\n async getDeliveryStatus(\n query: DeliveryStatusQuery,\n ): Promise<Result<DeliveryStatusResult | null, KMsgError>> {\n switch (query.type) {\n case \"ALIMTALK\":\n return getAlimTalkDeliveryStatus({\n providerId: this.id,\n config: this.config,\n query,\n });\n case \"SMS\":\n case \"LMS\":\n case \"MMS\":\n return getSmsV2DeliveryStatus({\n providerId: this.id,\n config: this.config,\n query,\n });\n default:\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n `IWINVProvider does not support type ${query.type}`,\n { providerId: this.id, type: query.type },\n ),\n );\n }\n }\n\n async getBalance(\n query?: BalanceQuery,\n ): Promise<Result<BalanceResult, KMsgError>> {\n const channel = query?.channel ?? \"ALIMTALK\";\n\n switch (channel) {\n case \"ALIMTALK\":\n return this.getAlimTalkBalance(channel);\n case \"SMS\":\n case \"LMS\":\n case \"MMS\":\n return this.getSmsBalance(channel);\n default:\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n `IWINVProvider does not support balance query for type ${channel}`,\n { providerId: this.id, type: channel },\n ),\n );\n }\n }\n\n private async getAlimTalkBalance(\n channel: BalanceResult[\"channel\"],\n ): Promise<Result<BalanceResult, KMsgError>> {\n const url = `${this.config.baseUrl}/api/charge/`;\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: getAlimTalkHeaders(this.config),\n body: JSON.stringify({}),\n });\n\n const responseText = await response.text();\n const parsed = safeParseJson(responseText);\n const data = toRecordOrFallback(parsed, {});\n\n const codeRaw = data.code;\n const parsedCode =\n typeof codeRaw === \"string\" ? Number(codeRaw) : undefined;\n const code =\n typeof codeRaw === \"number\"\n ? codeRaw\n : typeof parsedCode === \"number\" && Number.isFinite(parsedCode)\n ? parsedCode\n : undefined;\n const message =\n typeof data.message === \"string\" && data.message.length > 0\n ? data.message\n : \"IWINV AlimTalk charge query failed\";\n\n if (!response.ok || code !== 200) {\n return fail(\n new KMsgError(\n mapIwinvCodeToKMsgErrorCode(code ?? response.status),\n message,\n { providerId: this.id, originalCode: codeRaw ?? response.status },\n ),\n );\n }\n\n const chargeRaw = data.charge;\n const amount =\n typeof chargeRaw === \"number\"\n ? chargeRaw\n : typeof chargeRaw === \"string\"\n ? Number(chargeRaw)\n : NaN;\n\n if (!Number.isFinite(amount)) {\n return fail(\n new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"Invalid charge value from IWINV AlimTalk charge API\",\n { providerId: this.id, raw: data },\n ),\n );\n }\n\n return ok({\n providerId: this.id,\n channel,\n amount,\n currency: \"KRW\",\n raw: data,\n });\n } catch (error) {\n return fail(\n new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId: this.id },\n ),\n );\n }\n }\n\n private async getSmsBalance(\n channel: BalanceResult[\"channel\"],\n ): Promise<Result<BalanceResult, KMsgError>> {\n if (!this.config.smsApiKey || !this.config.smsAuthKey) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"smsApiKey and smsAuthKey are required for SMS/LMS/MMS balance query\",\n { providerId: this.id },\n ),\n );\n }\n\n const secretHeader = buildSmsSecretHeader(this.config);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json;charset=UTF-8\",\n secret: secretHeader,\n };\n\n if (\n typeof this.config.xForwardedFor === \"string\" &&\n this.config.xForwardedFor.length > 0\n ) {\n headers[\"X-Forwarded-For\"] = this.config.xForwardedFor;\n }\n\n const mergedHeaders =\n this.config.extraHeaders && typeof this.config.extraHeaders === \"object\"\n ? { ...headers, ...this.config.extraHeaders }\n : headers;\n\n const url = `${resolveSmsBaseUrl()}/api/charge/`;\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: mergedHeaders,\n body: JSON.stringify({ version: \"1.0\" }),\n });\n\n const responseText = await response.text();\n const parsed = safeParseJson(responseText);\n const data = toRecordOrFallback(parsed, {});\n\n const codeRaw = data.code ?? data.resultCode;\n const parsedCode =\n typeof codeRaw === \"string\" ? Number(codeRaw) : undefined;\n const code =\n typeof codeRaw === \"number\"\n ? codeRaw\n : typeof parsedCode === \"number\" && Number.isFinite(parsedCode)\n ? parsedCode\n : NaN;\n const message =\n typeof data.message === \"string\" && data.message.length > 0\n ? data.message\n : \"IWINV SMS charge query failed\";\n\n if (!response.ok || code !== 0) {\n return fail(\n new KMsgError(KMsgErrorCode.PROVIDER_ERROR, message, {\n providerId: this.id,\n originalCode: codeRaw ?? response.status,\n }),\n );\n }\n\n const chargeRaw = data.charge;\n const amount =\n typeof chargeRaw === \"number\"\n ? chargeRaw\n : typeof chargeRaw === \"string\"\n ? Number(chargeRaw)\n : NaN;\n\n if (!Number.isFinite(amount)) {\n return fail(\n new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"Invalid charge value from IWINV SMS charge API\",\n { providerId: this.id, raw: data },\n ),\n );\n }\n\n return ok({\n providerId: this.id,\n channel,\n amount,\n currency: \"KRW\",\n raw: data,\n });\n } catch (error) {\n return fail(\n new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId: this.id },\n ),\n );\n }\n }\n\n async createTemplate(\n input: TemplateCreateInput,\n _ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n return createTemplate({\n providerId: this.id,\n config: this.config,\n input,\n });\n }\n\n async updateTemplate(\n code: string,\n patch: TemplateUpdateInput,\n ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n return updateTemplate({\n providerId: this.id,\n config: this.config,\n code,\n patch,\n ctx,\n });\n }\n\n async deleteTemplate(\n code: string,\n _ctx?: TemplateContext,\n ): Promise<Result<void, KMsgError>> {\n return deleteTemplate({\n providerId: this.id,\n config: this.config,\n code,\n });\n }\n\n async getTemplate(\n code: string,\n ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n return getTemplate({\n providerId: this.id,\n config: this.config,\n code,\n ctx,\n });\n }\n\n async listTemplates(\n params?: { status?: string; page?: number; limit?: number },\n ctx?: TemplateContext,\n ): Promise<Result<Template[], KMsgError>> {\n return listTemplates({\n providerId: this.id,\n config: this.config,\n query: params,\n ctx,\n });\n }\n}\n\nexport const createIWINVProvider = (config: IWINVConfig) =>\n new IWINVProvider(config);\n\nexport const createDefaultIWINVProvider = () => {\n const config: IWINVConfig = {\n apiKey: readRuntimeEnv(\"IWINV_API_KEY\") || \"\",\n smsApiKey: readRuntimeEnv(\"IWINV_SMS_API_KEY\"),\n smsAuthKey: readRuntimeEnv(\"IWINV_SMS_AUTH_KEY\"),\n smsCompanyId: readRuntimeEnv(\"IWINV_SMS_COMPANY_ID\"),\n senderNumber:\n readRuntimeEnv(\"IWINV_SENDER_NUMBER\") ||\n readRuntimeEnv(\"IWINV_SMS_SENDER_NUMBER\"),\n smsSenderNumber: readRuntimeEnv(\"IWINV_SMS_SENDER_NUMBER\"),\n sendEndpoint: readRuntimeEnv(\"IWINV_SEND_ENDPOINT\") || \"/api/v2/send/\",\n xForwardedFor: readRuntimeEnv(\"IWINV_X_FORWARDED_FOR\"),\n debug: readRuntimeEnv(\"NODE_ENV\") === \"development\",\n };\n\n if (!config.apiKey) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"IWINV_API_KEY environment variable is required\",\n { providerId: \"iwinv\" },\n );\n }\n\n return new IWINVProvider(config);\n};\n\n// biome-ignore lint/complexity/noStaticOnlyClass: kept as a factory for convenience\nexport class IWINVProviderFactory {\n static create(config: IWINVConfig): IWINVProvider {\n return new IWINVProvider(config);\n }\n\n static createDefault(): IWINVProvider {\n return createDefaultIWINVProvider();\n }\n}\n\nexport function initializeIWINV(): void {}\n",
|
|
6
|
-
"import type { ProviderOnboardingSpec } from \"@k-msg/core\";\n\nexport const providerOnboardingSpecs: Readonly<\n Record<string, ProviderOnboardingSpec>\n> = {\n iwinv: {\n providerId: \"iwinv\",\n providerName: \"IWINV Messaging Provider\",\n channelOnboarding: \"manual\",\n templateLifecycleApi: \"available\",\n plusIdPolicy: \"optional\",\n plusIdInference: \"unsupported\",\n liveTestSupport: \"supported\",\n checks: [\n {\n id: \"channel_registered_in_console\",\n title: \"Kakao channel is registered in IWINV console\",\n description:\n \"IWINV channel onboarding is manual. Confirm channel registration and approval in console.\",\n kind: \"manual\",\n severity: \"blocker\",\n scopes: [\"doctor\", \"preflight\"],\n },\n {\n id: \"iwinv_config_required\",\n title: \"IWINV config has required keys\",\n kind: \"config\",\n severity: \"blocker\",\n scopes: [\"doctor\", \"preflight\"],\n configKeys: [\"apiKey\"],\n },\n {\n id: \"template_capability_available\",\n title: \"Template lifecycle APIs are available\",\n kind: \"capability\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n capabilityMethods: [\n \"listTemplates\",\n \"getTemplate\",\n \"createTemplate\",\n \"updateTemplate\",\n \"deleteTemplate\",\n ],\n },\n {\n id: \"template_list_probe\",\n title: \"Template list API probe\",\n kind: \"api_probe\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n probeOperation: \"list_templates\",\n },\n ],\n notes: [\n \"Channel add/auth is not available via IWINV public API in current integration.\",\n \"Template APIs are available and can be probed.\",\n ],\n },\n aligo: {\n providerId: \"aligo\",\n providerName: \"Aligo Smart SMS\",\n channelOnboarding: \"api\",\n templateLifecycleApi: \"available\",\n plusIdPolicy: \"required_if_no_inference\",\n plusIdInference: \"supported\",\n liveTestSupport: \"supported\",\n checks: [\n {\n id: \"aligo_config_required\",\n title: \"Aligo config has required keys\",\n kind: \"config\",\n severity: \"blocker\",\n scopes: [\"doctor\", \"preflight\"],\n configKeys: [\"apiKey\", \"userId\"],\n },\n {\n id: \"channel_api_capability_available\",\n title: \"Kakao channel APIs are available\",\n kind: \"capability\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n capabilityMethods: [\n \"listKakaoChannels\",\n \"requestKakaoChannelAuth\",\n \"addKakaoChannel\",\n ],\n },\n {\n id: \"channel_list_probe\",\n title: \"Kakao channel list API probe\",\n kind: \"api_probe\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n probeOperation: \"list_kakao_channels\",\n },\n {\n id: \"template_list_probe\",\n title: \"Template list API probe\",\n kind: \"api_probe\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n probeOperation: \"list_templates\",\n },\n ],\n },\n solapi: {\n providerId: \"solapi\",\n providerName: \"SOLAPI Messaging Provider\",\n channelOnboarding: \"none\",\n templateLifecycleApi: \"unavailable\",\n plusIdPolicy: \"required_if_no_inference\",\n plusIdInference: \"unsupported\",\n liveTestSupport: \"partial\",\n checks: [\n {\n id: \"solapi_config_required\",\n title: \"SOLAPI config has required keys\",\n kind: \"config\",\n severity: \"blocker\",\n scopes: [\"doctor\", \"preflight\"],\n configKeys: [\"apiKey\", \"apiSecret\"],\n },\n ],\n notes: [\n \"SOLAPI ALIMTALK requires kakao profileId/pfId, but plusId inference is not available in current integration.\",\n ],\n },\n mock: {\n providerId: \"mock\",\n providerName: \"Mock Provider\",\n channelOnboarding: \"api\",\n templateLifecycleApi: \"available\",\n plusIdPolicy: \"optional\",\n plusIdInference: \"supported\",\n liveTestSupport: \"none\",\n checks: [\n {\n id: \"mock_template_capability_available\",\n title: \"Mock template APIs are available\",\n kind: \"capability\",\n severity: \"info\",\n scopes: [\"doctor\", \"preflight\"],\n capabilityMethods: [\"listTemplates\", \"getTemplate\", \"createTemplate\"],\n },\n ],\n },\n} as const;\n\nexport function getProviderOnboardingSpec(\n providerId: string,\n): ProviderOnboardingSpec | undefined {\n return providerOnboardingSpecs[providerId];\n}\n\nexport function listProviderOnboardingSpecs(): ProviderOnboardingSpec[] {\n return Object.values(providerOnboardingSpecs);\n}\n",
|
|
7
|
-
"export function isObjectRecord(\n value: unknown,\n): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n",
|
|
8
|
-
"import { isObjectRecord } from \"./type-guards\";\n\nexport function safeParseJson(text: string): unknown {\n if (!text) return {};\n\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nexport function toRecordOrFallback(\n parsed: unknown,\n fallback: Record<string, unknown>,\n): Record<string, unknown> {\n return isObjectRecord(parsed) ? parsed : fallback;\n}\n",
|
|
9
|
-
"import { KMsgErrorCode, type Template } from \"@k-msg/core\";\nimport { utf8ToBase64 } from \"../shared/base64\";\nimport type { NormalizedIwinvConfig } from \"./iwinv.internal.types\";\n\nexport function getSendEndpoint(config: NormalizedIwinvConfig): string {\n const raw = config.sendEndpoint || \"/api/v2/send/\";\n return raw.startsWith(\"/\") ? raw : `/${raw}`;\n}\n\nexport function getAlimTalkHeaders(\n config: NormalizedIwinvConfig,\n): Record<string, string> {\n const auth = utf8ToBase64(config.apiKey);\n const base: Record<string, string> = {\n AUTH: auth,\n \"Content-Type\": \"application/json;charset=UTF-8\",\n };\n\n if (\n typeof config.xForwardedFor === \"string\" &&\n config.xForwardedFor.length > 0\n ) {\n base[\"X-Forwarded-For\"] = config.xForwardedFor;\n }\n\n if (config.extraHeaders && typeof config.extraHeaders === \"object\") {\n return { ...base, ...config.extraHeaders };\n }\n\n return base;\n}\n\nexport function mapIwinvCodeToKMsgErrorCode(code: number): KMsgErrorCode {\n switch (code) {\n case 201:\n case 206:\n case 401:\n case 403:\n return KMsgErrorCode.AUTHENTICATION_FAILED;\n case 429:\n return KMsgErrorCode.RATE_LIMIT_EXCEEDED;\n case 519:\n return KMsgErrorCode.INSUFFICIENT_BALANCE;\n case 404:\n case 501:\n return KMsgErrorCode.TEMPLATE_NOT_FOUND;\n case 502:\n case 503:\n case 504:\n case 505:\n case 506:\n case 507:\n case 508:\n case 509:\n case 510:\n case 511:\n case 512:\n case 513:\n case 514:\n case 515:\n case 516:\n case 517:\n case 540:\n return KMsgErrorCode.INVALID_REQUEST;\n case 518:\n return KMsgErrorCode.PROVIDER_ERROR;\n default:\n if (code >= 500) return KMsgErrorCode.PROVIDER_ERROR;\n return KMsgErrorCode.INVALID_REQUEST;\n }\n}\n\nexport function normalizeIwinvCode(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value;\n }\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (trimmed.length === 0) return undefined;\n const num = Number(trimmed);\n if (Number.isFinite(num)) return num;\n }\n return undefined;\n}\n\nexport function toIwinvTemplateStatus(\n value: string | undefined,\n): \"Y\" | \"I\" | \"R\" | undefined {\n if (typeof value !== \"string\") return undefined;\n const normalized = value.trim().toUpperCase();\n if (!normalized) return undefined;\n\n switch (normalized) {\n case \"Y\":\n case \"APPROVED\":\n return \"Y\";\n case \"I\":\n case \"INSPECTION\":\n return \"I\";\n case \"R\":\n case \"REJECTED\":\n return \"R\";\n case \"PENDING\":\n return \"I\";\n default:\n return undefined;\n }\n}\n\nexport function mapIwinvTemplateStatus(value: unknown): Template[\"status\"] {\n const normalized =\n typeof value === \"string\" ? value.trim().toUpperCase() : \"\";\n switch (normalized) {\n case \"Y\":\n return \"APPROVED\";\n case \"I\":\n return \"INSPECTION\";\n case \"R\":\n return \"REJECTED\";\n default:\n return \"PENDING\";\n }\n}\n",
|
|
10
|
-
"const BASE64_ALPHABET =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\nexport function toBase64(bytes: Uint8Array): string {\n let output = \"\";\n let i = 0;\n\n while (i < bytes.length) {\n const a = bytes[i++] ?? 0;\n const b = bytes[i++] ?? 0;\n const c = bytes[i++] ?? 0;\n\n const chunk = (a << 16) | (b << 8) | c;\n output += BASE64_ALPHABET[(chunk >> 18) & 63];\n output += BASE64_ALPHABET[(chunk >> 12) & 63];\n output += i - 2 < bytes.length ? BASE64_ALPHABET[(chunk >> 6) & 63] : \"=\";\n output += i - 1 < bytes.length ? BASE64_ALPHABET[chunk & 63] : \"=\";\n }\n\n return output;\n}\n\nexport function utf8ToBase64(value: string): string {\n return toBase64(new TextEncoder().encode(value));\n}\n",
|
|
11
|
-
"export const IWINV_ALIMTALK_BASE_URL = \"https://alimtalk.bizservice.iwinv.kr\";\nexport const IWINV_SMS_BASE_URL = \"https://sms.bizservice.iwinv.kr\";\n",
|
|
12
|
-
"import {\n type DeliveryStatus,\n type DeliveryStatusQuery,\n type DeliveryStatusResult,\n fail,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n} from \"@k-msg/core\";\nimport { safeParseJson, toRecordOrFallback } from \"../shared/http-json\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport {\n getAlimTalkHeaders,\n mapIwinvCodeToKMsgErrorCode,\n normalizeIwinvCode,\n} from \"./iwinv.alimtalk.helpers\";\nimport type { NormalizedIwinvConfig } from \"./iwinv.internal.types\";\nimport {\n buildSmsSecretHeader,\n canSendSmsV2,\n mapSmsV2HistoryStatus,\n normalizePhoneNumber,\n resolveSmsBaseUrl,\n} from \"./iwinv.sms.helpers\";\nimport {\n addDays,\n formatIwinvDate,\n formatSmsHistoryDate,\n parseIwinvDateTime,\n} from \"./iwinv.time\";\n\nexport async function getAlimTalkDeliveryStatus(params: {\n providerId: string;\n config: NormalizedIwinvConfig;\n query: DeliveryStatusQuery;\n}): Promise<Result<DeliveryStatusResult | null, KMsgError>> {\n const { providerId, config, query } = params;\n const providerMessageId = query.providerMessageId.trim();\n if (!providerMessageId) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"providerMessageId is required\",\n { providerId },\n ),\n );\n }\n\n const to = normalizePhoneNumber(query.to);\n if (!to) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"to is required\", {\n providerId,\n }),\n );\n }\n\n const seqNoValue = Number(providerMessageId);\n const seqNo = Number.isFinite(seqNoValue) ? seqNoValue : undefined;\n\n const startDate = formatIwinvDate(addDays(query.requestedAt, -1));\n const endDate = formatIwinvDate(new Date());\n\n const payload: Record<string, unknown> = {\n pageNum: 1,\n pageSize: 15,\n phone: to,\n startDate,\n endDate,\n ...(seqNo !== undefined ? { seqNo } : {}),\n ...(query.scheduledAt instanceof Date &&\n !Number.isNaN(query.scheduledAt.getTime())\n ? { reserve: \"Y\" }\n : {}),\n };\n\n const url = `${config.baseUrl}/api/history/`;\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: getAlimTalkHeaders(config),\n body: JSON.stringify(payload),\n });\n\n const responseText = await response.text();\n const parsed = safeParseJson(responseText);\n\n const data = toRecordOrFallback(parsed, {});\n const codeRaw = data.code;\n const code = typeof codeRaw === \"number\" ? codeRaw : undefined;\n const message =\n typeof data.message === \"string\" && data.message.length > 0\n ? data.message\n : \"IWINV history query failed\";\n\n if (!response.ok || code !== 200) {\n return fail(\n new KMsgError(\n mapIwinvCodeToKMsgErrorCode(\n code ?? normalizeIwinvCode(parsed) ?? response.status,\n ),\n message,\n { providerId, originalCode: codeRaw ?? response.status },\n ),\n );\n }\n\n const listRaw = data.list;\n const list = Array.isArray(listRaw) ? (listRaw as Array<unknown>) : [];\n if (list.length === 0) return ok(null);\n\n const item = (() => {\n if (seqNo === undefined) return list[0];\n return (\n list.find((v) => isObjectRecord(v) && v.seqNo === seqNo) ?? list[0]\n );\n })();\n\n if (!isObjectRecord(item)) return ok(null);\n\n const statusCode =\n typeof item.statusCode === \"string\" ? item.statusCode : undefined;\n const statusMessage =\n typeof item.statusCodeName === \"string\" ? item.statusCodeName : undefined;\n\n const sendDate = parseIwinvDateTime(item.sendDate);\n const receiveDate = parseIwinvDateTime(item.receiveDate);\n\n const isDelivered =\n statusCode === \"OK\" ||\n (typeof statusMessage === \"string\" && statusMessage.includes(\"성공\"));\n\n const status: DeliveryStatus = isDelivered\n ? \"DELIVERED\"\n : sendDate\n ? \"FAILED\"\n : \"PENDING\";\n\n return ok({\n providerId,\n providerMessageId,\n status,\n statusCode,\n statusMessage,\n sentAt: sendDate,\n deliveredAt: isDelivered ? receiveDate || sendDate : undefined,\n failedAt: !isDelivered && sendDate ? sendDate : undefined,\n raw: item,\n });\n } catch (error) {\n return fail(\n new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n ),\n );\n }\n}\n\nexport async function getSmsV2DeliveryStatus(params: {\n providerId: string;\n config: NormalizedIwinvConfig;\n query: DeliveryStatusQuery;\n}): Promise<Result<DeliveryStatusResult | null, KMsgError>> {\n const { providerId, config, query } = params;\n\n if (!canSendSmsV2(config)) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"SMS v2 configuration missing (smsApiKey/smsAuthKey)\",\n { providerId },\n ),\n );\n }\n\n if (!config.smsCompanyId || config.smsCompanyId.length === 0) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"smsCompanyId required for history (config.smsCompanyId)\",\n { providerId },\n ),\n );\n }\n\n const providerMessageId = query.providerMessageId.trim();\n if (!providerMessageId) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"providerMessageId is required\",\n { providerId },\n ),\n );\n }\n\n const to = normalizePhoneNumber(query.to);\n if (!to) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"to is required\", {\n providerId,\n }),\n );\n }\n\n const start = addDays(query.requestedAt, -1);\n const end = new Date();\n const rangeMs = end.getTime() - start.getTime();\n const maxRangeMs = 90 * 24 * 60 * 60 * 1000;\n if (rangeMs > maxRangeMs) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"SMS history date range must be within 90 days\",\n { providerId },\n ),\n );\n }\n\n const payload: Record<string, unknown> = {\n version: \"1.0\",\n companyid: config.smsCompanyId,\n startDate: formatSmsHistoryDate(start),\n endDate: formatSmsHistoryDate(end),\n requestNo: providerMessageId,\n pageNum: 1,\n pageSize: 15,\n phone: to,\n };\n\n const secretHeader = buildSmsSecretHeader(config);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json;charset=UTF-8\",\n secret: secretHeader,\n };\n\n if (\n typeof config.xForwardedFor === \"string\" &&\n config.xForwardedFor.length > 0\n ) {\n headers[\"X-Forwarded-For\"] = config.xForwardedFor;\n }\n\n const mergedHeaders =\n config.extraHeaders && typeof config.extraHeaders === \"object\"\n ? { ...headers, ...config.extraHeaders }\n : headers;\n\n const url = `${resolveSmsBaseUrl()}/api/history/`;\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: mergedHeaders,\n body: JSON.stringify(payload),\n });\n\n const responseText = await response.text();\n const parsed = safeParseJson(responseText);\n\n const data = toRecordOrFallback(parsed, {});\n const codeRaw = data.resultCode;\n const code =\n typeof codeRaw === \"number\"\n ? codeRaw\n : typeof codeRaw === \"string\"\n ? Number(codeRaw)\n : NaN;\n const message =\n typeof data.message === \"string\" && data.message.length > 0\n ? data.message\n : \"IWINV SMS history query failed\";\n\n if (!response.ok || code !== 0) {\n return fail(\n new KMsgError(KMsgErrorCode.PROVIDER_ERROR, message, {\n providerId,\n originalCode: codeRaw ?? response.status,\n }),\n );\n }\n\n const listRaw = data.list;\n const list = Array.isArray(listRaw) ? (listRaw as Array<unknown>) : [];\n if (list.length === 0) return ok(null);\n\n const item = (() => {\n const found = list.find((v) => {\n if (!isObjectRecord(v)) return false;\n const req = v.requestNo;\n return req !== undefined && req !== null\n ? String(req) === providerMessageId\n : false;\n });\n return found ?? list[0];\n })();\n\n if (!isObjectRecord(item)) return ok(null);\n\n const statusCode =\n typeof item.sendStatusCode === \"string\" ? item.sendStatusCode : undefined;\n const statusMessage =\n typeof item.sendStatusMsg === \"string\"\n ? item.sendStatusMsg\n : typeof item.sendStatus === \"string\"\n ? item.sendStatus\n : undefined;\n\n const sendDate = parseIwinvDateTime(item.sendDate);\n const status = mapSmsV2HistoryStatus(statusCode, statusMessage);\n\n return ok({\n providerId,\n providerMessageId,\n status,\n statusCode,\n statusMessage,\n sentAt: sendDate,\n deliveredAt: status === \"DELIVERED\" ? sendDate : undefined,\n failedAt: status === \"FAILED\" ? sendDate : undefined,\n raw: item,\n });\n } catch (error) {\n return fail(\n new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n ),\n );\n }\n}\n",
|
|
13
|
-
"import { type DeliveryStatus, KMsgErrorCode } from \"@k-msg/core\";\nimport { utf8ToBase64 } from \"../shared/base64\";\nimport { IWINV_SMS_BASE_URL } from \"./iwinv.constants\";\nimport type { NormalizedIwinvConfig } from \"./iwinv.internal.types\";\n\nexport function normalizePhoneNumber(value: string): string {\n return value.replace(/[^0-9]/g, \"\");\n}\n\nexport function resolveSmsBaseUrl(): string {\n return IWINV_SMS_BASE_URL;\n}\n\nexport function buildSmsSecretHeader(config: NormalizedIwinvConfig): string {\n if (config.smsApiKey && config.smsAuthKey) {\n return utf8ToBase64(`${config.smsApiKey}&${config.smsAuthKey}`);\n }\n\n const legacyAuthKey = config.smsAuthKey || config.smsApiKey;\n if (!legacyAuthKey) return \"\";\n\n return utf8ToBase64(`${config.apiKey}&${legacyAuthKey}`);\n}\n\nexport function canSendSmsV2(config: NormalizedIwinvConfig): boolean {\n const secret = buildSmsSecretHeader(config);\n return secret.length > 0;\n}\n\nexport function normalizeCode(value: unknown): string {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value.toString();\n }\n if (typeof value === \"string\") {\n return value.trim();\n }\n return \"\";\n}\n\nexport function mapSmsResponseMessage(code: string, fallback: string): string {\n const knownMessages: Record<string, string> = {\n \"0\": \"전송 성공\",\n \"1\": \"메시지가 전송되지 않았습니다.\",\n \"11\": \"운영 중인 서비스가 아닙니다.\",\n \"12\": \"요금제 충전 중입니다. 잠시 후 다시 시도해 보시기 바랍니다.\",\n \"13\": \"등록되지 않은 발신번호입니다.\",\n \"14\": \"인증 요청이 올바르지 않습니다.\",\n \"15\": \"등록하지 않은 IP에서는 발송되지 않습니다.\",\n \"21\": \"장문 메시지는 2000 Bytes까지만 입력이 가능합니다.\",\n \"22\": \"제목 입력 가능 문자가 올바르지 않습니다.\",\n \"23\": \"제목은 40 Byte까지만 입력이 가능합니다.\",\n \"31\": \"파일 업로드는 100KB까지 가능합니다.\",\n \"32\": \"허용되지 않는 파일 확장자입니다.\",\n \"33\": \"이미지 업로드에 실패했습니다.\",\n \"41\": \"수신 번호를 입력하여 주세요.\",\n \"42\": \"예약 전송 가능 시간이 아닙니다.\",\n \"43\": \"날짜와 시간 표현 형식에 맞춰 입력하여 주십시오.\",\n \"44\": \"최대 1000건 전송 가능합니다.\",\n \"50\": \"SMS 자동 충전 한도를 초과하였습니다.\",\n \"202\": \"SMS API 인증 실패 또는 SMS 서비스 권한이 없습니다.\",\n \"206\": \"등록하지 않은 IP에서는 발송되지 않습니다.\",\n };\n return knownMessages[code] || fallback;\n}\n\nexport function mapSmsErrorCode(\n code: string,\n responseOk: boolean,\n): KMsgErrorCode {\n if (code === \"14\" || code === \"15\" || code === \"202\" || code === \"206\") {\n return KMsgErrorCode.AUTHENTICATION_FAILED;\n }\n if (code === \"50\") {\n return KMsgErrorCode.INSUFFICIENT_BALANCE;\n }\n if (\n code === \"13\" ||\n code === \"21\" ||\n code === \"22\" ||\n code === \"23\" ||\n code === \"31\" ||\n code === \"32\" ||\n code === \"33\" ||\n code === \"41\" ||\n code === \"42\" ||\n code === \"43\" ||\n code === \"44\"\n ) {\n return KMsgErrorCode.INVALID_REQUEST;\n }\n if (!responseOk) {\n return KMsgErrorCode.NETWORK_ERROR;\n }\n return KMsgErrorCode.PROVIDER_ERROR;\n}\n\nexport function buildLmsTitle(text: string, subject?: string): string {\n if (subject && subject.trim().length > 0) return subject.trim();\n return text.slice(0, 20);\n}\n\nexport function mapSmsV2HistoryStatus(\n statusCode?: string,\n statusMessage?: string,\n): DeliveryStatus {\n if (statusCode === \"06\") return \"DELIVERED\";\n if (statusCode === \"1000\") return \"DELIVERED\";\n\n if (typeof statusMessage === \"string\") {\n if (statusMessage.includes(\"전송 성공\")) return \"DELIVERED\";\n if (statusMessage.includes(\"대기\") || statusMessage.includes(\"처리중\")) {\n return \"PENDING\";\n }\n }\n\n if (statusCode === \"00\" || statusCode === \"01\") return \"PENDING\";\n if (!statusCode && !statusMessage) return \"UNKNOWN\";\n\n return \"FAILED\";\n}\n",
|
|
14
|
-
"export function addDays(date: Date, days: number): Date {\n return new Date(date.getTime() + days * 24 * 60 * 60 * 1000);\n}\n\nexport function formatSmsHistoryDate(date: Date): string {\n const pad = (v: number) => v.toString().padStart(2, \"0\");\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n}\n\nexport function parseIwinvDateTime(value: unknown): Date | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})\\s+(\\d{2}):(\\d{2}):(\\d{2})$/.exec(\n trimmed,\n );\n if (!match) return undefined;\n\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n const hour = Number(match[4]);\n const minute = Number(match[5]);\n const second = Number(match[6]);\n\n if (\n !Number.isFinite(year) ||\n !Number.isFinite(month) ||\n !Number.isFinite(day) ||\n !Number.isFinite(hour) ||\n !Number.isFinite(minute) ||\n !Number.isFinite(second)\n ) {\n return undefined;\n }\n\n const date = new Date(year, month - 1, day, hour, minute, second);\n if (Number.isNaN(date.getTime())) return undefined;\n return date;\n}\n\nexport function formatIwinvDate(date: Date): string {\n const pad = (v: number) => v.toString().padStart(2, \"0\");\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;\n}\n\nexport function formatSmsReserveDate(date: Date): string {\n const pad = (value: number) => value.toString().padStart(2, \"0\");\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;\n}\n",
|
|
15
|
-
"import {\n fail,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n type SendOptions,\n type SendResult,\n} from \"@k-msg/core\";\nimport { safeParseJson } from \"../shared/http-json\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport {\n getAlimTalkHeaders,\n getSendEndpoint,\n mapIwinvCodeToKMsgErrorCode,\n normalizeIwinvCode,\n} from \"./iwinv.alimtalk.helpers\";\nimport {\n resolveImageFilename,\n resolveImageInput,\n toImageBlob,\n} from \"./iwinv.image\";\nimport type {\n IWINVSendResponse,\n NormalizedIwinvConfig,\n SmsV2MessageType,\n SmsV2SendResponse,\n} from \"./iwinv.internal.types\";\nimport {\n buildLmsTitle,\n buildSmsSecretHeader,\n canSendSmsV2,\n mapSmsErrorCode,\n mapSmsResponseMessage,\n normalizeCode,\n normalizePhoneNumber,\n resolveSmsBaseUrl,\n} from \"./iwinv.sms.helpers\";\nimport { formatIwinvDate, formatSmsReserveDate } from \"./iwinv.time\";\n\nexport async function sendAlimTalk(params: {\n providerId: string;\n config: NormalizedIwinvConfig;\n options: Extract<SendOptions, { type: \"ALIMTALK\" }>;\n}): Promise<Result<SendResult, KMsgError>> {\n const { providerId, config, options } = params;\n const templateId = options.templateId;\n\n if (!templateId || templateId.length === 0) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"templateId is required for ALIMTALK\",\n { providerId },\n ),\n );\n }\n\n const scheduledAt = options.options?.scheduledAt;\n const scheduledAtValid =\n scheduledAt instanceof Date && !Number.isNaN(scheduledAt.getTime());\n const reserve: \"Y\" | \"N\" = scheduledAtValid ? \"Y\" : \"N\";\n const sendDate = scheduledAtValid\n ? formatIwinvDate(scheduledAt as Date)\n : undefined;\n\n const to = normalizePhoneNumber(options.to);\n if (!to) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"to is required\", {\n providerId,\n }),\n );\n }\n\n const templateParamOverride = options.providerOptions?.templateParam;\n const templateParam = Array.isArray(templateParamOverride)\n ? templateParamOverride.map((v) =>\n v === null || v === undefined ? \"\" : String(v),\n )\n : Object.values(options.variables || {}).map((v) =>\n v === null || v === undefined ? \"\" : String(v),\n );\n const failover = options.failover;\n\n const senderNumber =\n (typeof options.from === \"string\" && options.from.length > 0\n ? options.from\n : config.senderNumber || config.smsSenderNumber) || \"\";\n const normalizedSender = senderNumber\n ? normalizePhoneNumber(senderNumber)\n : \"\";\n\n const reSendOverrideRaw =\n typeof options.providerOptions?.reSend === \"string\"\n ? options.providerOptions.reSend.trim().toUpperCase()\n : \"\";\n const reSendOverride =\n reSendOverrideRaw === \"Y\" || reSendOverrideRaw === \"N\"\n ? (reSendOverrideRaw as \"Y\" | \"N\")\n : undefined;\n const reSendFromFailover =\n failover?.enabled === true\n ? \"Y\"\n : failover?.enabled === false\n ? \"N\"\n : undefined;\n const reSend =\n reSendOverride ?? reSendFromFailover ?? (normalizedSender ? \"Y\" : \"N\");\n\n const resendCallbackOverride =\n typeof options.providerOptions?.resendCallback === \"string\"\n ? normalizePhoneNumber(options.providerOptions.resendCallback)\n : \"\";\n const resendCallback = resendCallbackOverride || normalizedSender;\n\n if (reSend === \"Y\" && !resendCallback) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"resendCallback is required when reSend is 'Y' (options.from or providerOptions.resendCallback)\",\n { providerId },\n ),\n );\n }\n\n const resendTypeRaw =\n typeof options.providerOptions?.resendType === \"string\"\n ? options.providerOptions.resendType.trim().toUpperCase()\n : \"\";\n const resendType =\n resendTypeRaw === \"Y\" || resendTypeRaw === \"N\"\n ? (resendTypeRaw as \"Y\" | \"N\")\n : undefined;\n if (\n typeof options.providerOptions?.resendType === \"string\" &&\n options.providerOptions.resendType.length > 0 &&\n !resendType\n ) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"resendType must be 'Y' or 'N'\",\n {\n providerId,\n },\n ),\n );\n }\n\n const resendTypeFromFailover =\n failover?.fallbackChannel === \"lms\"\n ? \"Y\"\n : failover?.fallbackChannel === \"sms\"\n ? \"N\"\n : undefined;\n\n const resendTitle =\n typeof options.providerOptions?.resendTitle === \"string\" &&\n options.providerOptions.resendTitle.trim().length > 0\n ? options.providerOptions.resendTitle.trim()\n : typeof failover?.fallbackTitle === \"string\" &&\n failover.fallbackTitle.trim().length > 0\n ? failover.fallbackTitle.trim()\n : undefined;\n\n const resendContent =\n typeof options.providerOptions?.resendContent === \"string\" &&\n options.providerOptions.resendContent.trim().length > 0\n ? options.providerOptions.resendContent.trim()\n : typeof failover?.fallbackContent === \"string\" &&\n failover.fallbackContent.trim().length > 0\n ? failover.fallbackContent.trim()\n : undefined;\n\n const payload: Record<string, unknown> = {\n templateCode: templateId,\n reserve,\n ...(sendDate ? { sendDate } : {}),\n list: [\n {\n phone: to,\n templateParam: templateParam.length > 0 ? templateParam : undefined,\n },\n ],\n reSend,\n ...(resendCallback ? { resendCallback } : {}),\n ...((resendType ?? resendTypeFromFailover)\n ? { resendType: resendType ?? resendTypeFromFailover }\n : {}),\n ...(resendTitle ? { resendTitle } : {}),\n ...(resendContent ? { resendContent } : {}),\n };\n\n const url = `${config.baseUrl}${getSendEndpoint(config)}`;\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: getAlimTalkHeaders(config),\n body: JSON.stringify(payload),\n });\n\n const responseText = await response.text();\n const parsed = safeParseJson(responseText);\n\n const data: IWINVSendResponse = isObjectRecord(parsed)\n ? (parsed as IWINVSendResponse)\n : ({\n code: normalizeIwinvCode(parsed) ?? response.status,\n message: responseText || String(parsed || \"\"),\n } as IWINVSendResponse);\n\n if (!response.ok || data.code !== 200) {\n return fail(\n new KMsgError(\n mapIwinvCodeToKMsgErrorCode(data.code),\n data.message || \"IWINV send failed\",\n { providerId, originalCode: data.code },\n ),\n );\n }\n\n return ok({\n messageId: options.messageId || crypto.randomUUID(),\n providerId,\n providerMessageId:\n typeof data.seqNo === \"number\" ? String(data.seqNo) : undefined,\n status: scheduledAtValid ? \"PENDING\" : \"SENT\",\n type: options.type,\n to: options.to,\n raw: data,\n });\n } catch (error) {\n return fail(\n new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n ),\n );\n }\n}\n\nasync function sendSmsV2Mms(params: {\n providerId: string;\n config: NormalizedIwinvConfig;\n options: Extract<SendOptions, { type: SmsV2MessageType }>;\n to: string;\n from: string;\n text: string;\n scheduledAtValid: boolean;\n scheduledAt?: Date;\n}): Promise<Result<SendResult, KMsgError>> {\n const {\n providerId,\n config,\n options,\n to,\n from,\n text,\n scheduledAtValid,\n scheduledAt,\n } = params;\n\n if (options.type !== \"MMS\") {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"IWINVProvider: MMS handler called with non-MMS options\",\n { providerId, type: options.type },\n ),\n );\n }\n\n const title = buildLmsTitle(text, options.subject);\n\n const imageInputResult = resolveImageInput(options, providerId);\n if (imageInputResult.isFailure) return imageInputResult;\n\n const imageInput = imageInputResult.value;\n if (!imageInput) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"image is required for MMS; caller must provide options.media.image.blob or bytes\",\n { providerId },\n ),\n );\n }\n\n let image: {\n blob: Blob;\n filename: string;\n contentType: string;\n size: number;\n };\n\n try {\n image = await toImageBlob(imageInput);\n } catch (error) {\n return fail(\n error instanceof KMsgError\n ? error\n : new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n ),\n );\n }\n\n if (image.size > 100 * 1024) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"MMS image must be <= 100KB\",\n {\n providerId,\n bytes: image.size,\n },\n ),\n );\n }\n\n const form = new FormData();\n form.append(\"version\", \"1.0\");\n form.append(\"from\", from);\n form.append(\"to\", to);\n form.append(\"title\", title);\n form.append(\"text\", text);\n\n if (scheduledAtValid && scheduledAt) {\n form.append(\"date\", formatSmsReserveDate(scheduledAt));\n }\n\n form.append(\"image\", image.blob, resolveImageFilename(image));\n\n const secretHeader = buildSmsSecretHeader(config);\n const headers: Record<string, string> = {\n secret: secretHeader,\n };\n\n if (\n typeof config.xForwardedFor === \"string\" &&\n config.xForwardedFor.length > 0\n ) {\n headers[\"X-Forwarded-For\"] = config.xForwardedFor;\n }\n\n const mergedHeaders: Record<string, string> = { ...headers };\n if (config.extraHeaders && typeof config.extraHeaders === \"object\") {\n for (const [key, value] of Object.entries(config.extraHeaders)) {\n if (key.toLowerCase() === \"content-type\") continue;\n mergedHeaders[key] = value;\n }\n }\n\n const url = `${resolveSmsBaseUrl()}/api/v2/send/`;\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: mergedHeaders,\n body: form,\n });\n\n const responseText = await response.text();\n const parsed = safeParseJson(responseText);\n\n const data: SmsV2SendResponse = isObjectRecord(parsed)\n ? (parsed as SmsV2SendResponse)\n : ({ resultCode: parsed } as SmsV2SendResponse);\n\n const rawCode = data.resultCode ?? data.code;\n const code = normalizeCode(rawCode);\n const message =\n typeof data.message === \"string\" && data.message.length > 0\n ? data.message\n : mapSmsResponseMessage(code, \"MMS send failed\");\n\n const isSuccess = response.ok && code === \"0\";\n if (!isSuccess) {\n return fail(\n new KMsgError(mapSmsErrorCode(code, response.ok), message, {\n providerId,\n originalCode: rawCode,\n }),\n );\n }\n\n const providerMessageId =\n typeof data.requestNo === \"string\" && data.requestNo.length > 0\n ? data.requestNo\n : typeof data.msgid === \"string\" && data.msgid.length > 0\n ? data.msgid\n : undefined;\n\n return ok({\n messageId: options.messageId || crypto.randomUUID(),\n providerId,\n providerMessageId,\n status: scheduledAtValid ? \"PENDING\" : \"SENT\",\n type: options.type,\n to: options.to,\n raw: data,\n });\n } catch (error) {\n return fail(\n new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n ),\n );\n }\n}\n\nexport async function sendSmsV2(params: {\n providerId: string;\n config: NormalizedIwinvConfig;\n options: Extract<SendOptions, { type: SmsV2MessageType }>;\n}): Promise<Result<SendResult, KMsgError>> {\n const { providerId, config, options } = params;\n\n if (!canSendSmsV2(config)) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"SMS v2 configuration missing (smsApiKey/smsAuthKey)\",\n { providerId },\n ),\n );\n }\n\n const to = normalizePhoneNumber(options.to);\n if (!to) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"to is required\", {\n providerId,\n }),\n );\n }\n\n const text = options.text;\n if (!text || text.trim().length === 0) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"text is required for SMS/LMS/MMS\",\n {\n providerId,\n },\n ),\n );\n }\n\n const senderNumber =\n (typeof options.from === \"string\" && options.from.length > 0\n ? options.from\n : config.smsSenderNumber || config.senderNumber) || \"\";\n const from = senderNumber ? normalizePhoneNumber(senderNumber) : \"\";\n if (!from) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"from is required for SMS/LMS/MMS (options.from or config.smsSenderNumber)\",\n { providerId },\n ),\n );\n }\n\n const scheduledAt = options.options?.scheduledAt;\n const scheduledAtValid =\n scheduledAt instanceof Date && !Number.isNaN(scheduledAt.getTime());\n\n if (options.type === \"MMS\") {\n return await sendSmsV2Mms({\n providerId,\n config,\n options,\n to,\n from,\n text,\n scheduledAtValid,\n scheduledAt: scheduledAtValid ? (scheduledAt as Date) : undefined,\n });\n }\n\n const payload: Record<string, unknown> = {\n version: \"1.0\",\n from,\n to: [to],\n text,\n };\n\n if (options.type === \"LMS\") {\n payload.title = buildLmsTitle(text, options.subject);\n } else {\n const msgTypeOverride =\n typeof options.providerOptions?.msgType === \"string\" &&\n options.providerOptions.msgType.trim().length > 0\n ? options.providerOptions.msgType.trim()\n : undefined;\n payload.msgType = msgTypeOverride || options.type;\n }\n\n if (scheduledAtValid) {\n payload.date = formatSmsReserveDate(scheduledAt as Date);\n }\n\n const secretHeader = buildSmsSecretHeader(config);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json;charset=UTF-8\",\n secret: secretHeader,\n };\n\n if (\n typeof config.xForwardedFor === \"string\" &&\n config.xForwardedFor.length > 0\n ) {\n headers[\"X-Forwarded-For\"] = config.xForwardedFor;\n }\n\n const mergedHeaders =\n config.extraHeaders && typeof config.extraHeaders === \"object\"\n ? { ...headers, ...config.extraHeaders }\n : headers;\n\n const url = `${resolveSmsBaseUrl()}/api/v2/send/`;\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: mergedHeaders,\n body: JSON.stringify(payload),\n });\n\n const responseText = await response.text();\n const parsed = safeParseJson(responseText);\n\n const data: SmsV2SendResponse = isObjectRecord(parsed)\n ? (parsed as SmsV2SendResponse)\n : ({ resultCode: parsed } as SmsV2SendResponse);\n\n const rawCode = data.resultCode ?? data.code;\n const code = normalizeCode(rawCode);\n const message =\n typeof data.message === \"string\" && data.message.length > 0\n ? data.message\n : mapSmsResponseMessage(code, \"SMS send failed\");\n\n const isSuccess = response.ok && code === \"0\";\n if (!isSuccess) {\n return fail(\n new KMsgError(mapSmsErrorCode(code, response.ok), message, {\n providerId,\n originalCode: rawCode,\n }),\n );\n }\n\n const providerMessageId =\n typeof data.requestNo === \"string\" && data.requestNo.length > 0\n ? data.requestNo\n : typeof data.msgid === \"string\" && data.msgid.length > 0\n ? data.msgid\n : undefined;\n\n return ok({\n messageId: options.messageId || crypto.randomUUID(),\n providerId,\n providerMessageId,\n status: scheduledAtValid ? \"PENDING\" : \"SENT\",\n type: options.type,\n to: options.to,\n raw: data,\n });\n } catch (error) {\n return fail(\n new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n ),\n );\n }\n}\n",
|
|
16
|
-
"import { fail, KMsgError, KMsgErrorCode, ok, type Result } from \"@k-msg/core\";\nimport type { IWINVImageInput } from \"./iwinv.internal.types\";\n\nfunction getFileExtension(filename: string): string {\n const safe = filename.split(/[?#]/, 1)[0] ?? filename;\n const lastDot = safe.lastIndexOf(\".\");\n if (lastDot <= 0 || lastDot === safe.length - 1) return \"\";\n return safe.slice(lastDot).toLowerCase();\n}\n\nfunction guessImageContentType(filename: string): string | undefined {\n const ext = getFileExtension(filename);\n switch (ext) {\n case \".jpg\":\n case \".jpeg\":\n return \"image/jpeg\";\n case \".png\":\n return \"image/png\";\n case \".gif\":\n return \"image/gif\";\n case \".webp\":\n return \"image/webp\";\n default:\n return undefined;\n }\n}\n\nexport function resolveImageInput(\n options: unknown,\n providerId: string,\n): Result<IWINVImageInput | undefined, KMsgError> {\n const record =\n options && typeof options === \"object\"\n ? (options as Record<string, unknown>)\n : {};\n const media =\n record.media && typeof record.media === \"object\"\n ? (record.media as Record<string, unknown>)\n : undefined;\n const image = media?.image as Record<string, unknown> | undefined;\n\n if (image && typeof image === \"object\") {\n if (image.bytes instanceof Uint8Array) {\n return ok({\n bytes: image.bytes,\n filename:\n typeof image.filename === \"string\" ? image.filename : undefined,\n contentType:\n typeof image.contentType === \"string\" ? image.contentType : undefined,\n });\n }\n if (image.blob instanceof Blob) {\n return ok({\n blob: image.blob,\n filename:\n typeof image.filename === \"string\" ? image.filename : undefined,\n contentType:\n typeof image.contentType === \"string\" ? image.contentType : undefined,\n });\n }\n if (typeof image.ref === \"string\" && image.ref.trim().length > 0) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"IWINV MMS caller must provide blob/bytes in options.media.image\",\n { providerId, field: \"media.image.ref\" },\n ),\n );\n }\n }\n\n const imageUrlRaw = record.imageUrl;\n if (typeof imageUrlRaw === \"string\" && imageUrlRaw.trim().length > 0) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"IWINV MMS caller must provide blob/bytes in options.media.image\",\n { providerId, field: \"imageUrl\" },\n ),\n );\n }\n\n return ok(undefined);\n}\n\nexport async function toImageBlob(input: IWINVImageInput): Promise<{\n blob: Blob;\n filename: string;\n contentType: string;\n size: number;\n}> {\n if (\"blob\" in input) {\n const contentType =\n input.contentType || input.blob.type || \"application/octet-stream\";\n const filename = input.filename || \"image\";\n const blob =\n input.contentType && input.contentType !== input.blob.type\n ? new Blob([await input.blob.arrayBuffer()], { type: contentType })\n : input.blob;\n\n return { blob, filename, contentType, size: blob.size };\n }\n\n const contentType = input.contentType || \"application/octet-stream\";\n const copied = new Uint8Array(input.bytes.byteLength);\n copied.set(input.bytes);\n const blob = new Blob([copied], { type: contentType });\n const filename = input.filename || \"image\";\n return { blob, filename, contentType, size: blob.size };\n}\n\nexport function resolveImageFilename(image: {\n filename: string;\n contentType: string;\n}): string {\n const hasExt = getFileExtension(image.filename).length > 0;\n if (hasExt) return image.filename;\n\n const guessedExt =\n guessImageContentType(image.filename) === \"image/png\"\n ? \".png\"\n : guessImageContentType(image.filename) === \"image/gif\"\n ? \".gif\"\n : guessImageContentType(image.filename) === \"image/webp\"\n ? \".webp\"\n : image.contentType === \"image/png\"\n ? \".png\"\n : image.contentType === \"image/gif\"\n ? \".gif\"\n : image.contentType === \"image/webp\"\n ? \".webp\"\n : \".jpg\";\n\n return `${image.filename}${guessedExt}`;\n}\n",
|
|
17
|
-
"import {\n fail,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n type Template,\n type TemplateContext,\n type TemplateCreateInput,\n type TemplateUpdateInput,\n} from \"@k-msg/core\";\nimport { validateTemplatePayload } from \"@k-msg/template\";\nimport { safeParseJson, toRecordOrFallback } from \"../shared/http-json\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport {\n getAlimTalkHeaders,\n mapIwinvCodeToKMsgErrorCode,\n mapIwinvTemplateStatus,\n normalizeIwinvCode,\n toIwinvTemplateStatus,\n} from \"./iwinv.alimtalk.helpers\";\nimport type { NormalizedIwinvConfig } from \"./iwinv.internal.types\";\nimport { parseIwinvDateTime } from \"./iwinv.time\";\n\nasync function readIwinvTemplateResponse(\n response: Response,\n): Promise<Record<string, unknown>> {\n const responseText = await response.text();\n const parsed = safeParseJson(responseText);\n\n return toRecordOrFallback(parsed, {\n code: normalizeIwinvCode(parsed) ?? response.status,\n message: responseText || String(parsed || \"\"),\n });\n}\n\nfunction withProviderContext(error: KMsgError, providerId: string): KMsgError {\n return new KMsgError(error.code, error.message, {\n providerId,\n ...(error.details ?? {}),\n });\n}\n\nexport async function createTemplate(params: {\n providerId: string;\n config: NormalizedIwinvConfig;\n input: TemplateCreateInput;\n}): Promise<Result<Template, KMsgError>> {\n const { providerId, config, input } = params;\n\n if (!input || typeof input !== \"object\") {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"Template input is required\",\n {\n providerId,\n },\n ),\n );\n }\n const payloadValidation = validateTemplatePayload(input, {\n requireName: true,\n requireContent: true,\n });\n if (payloadValidation.isFailure) {\n return fail(withProviderContext(payloadValidation.error, providerId));\n }\n\n const url = `${config.baseUrl}/api/template/add/`;\n const payload: Record<string, unknown> = {\n templateName: payloadValidation.value.name ?? input.name,\n templateContent: payloadValidation.value.content ?? input.content,\n ...(payloadValidation.value.buttons\n ? { buttons: payloadValidation.value.buttons }\n : {}),\n };\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: getAlimTalkHeaders(config),\n body: JSON.stringify(payload),\n });\n\n const data = await readIwinvTemplateResponse(response);\n const code = normalizeIwinvCode(data.code) ?? response.status;\n const message =\n typeof data.message === \"string\" && data.message.length > 0\n ? data.message\n : \"IWINV template create failed\";\n\n if (!response.ok || code !== 200) {\n return fail(\n new KMsgError(mapIwinvCodeToKMsgErrorCode(code), message, {\n providerId,\n originalCode: code,\n }),\n );\n }\n\n const templateCodeRaw = data.templateCode;\n const templateCode =\n typeof templateCodeRaw === \"string\" && templateCodeRaw.trim().length > 0\n ? templateCodeRaw.trim()\n : \"\";\n\n if (!templateCode) {\n return fail(\n new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"IWINV template create did not return templateCode\",\n { providerId, raw: data },\n ),\n );\n }\n\n const now = new Date();\n return ok({\n id: templateCode,\n code: templateCode,\n name: payloadValidation.value.name ?? input.name,\n content: payloadValidation.value.content ?? input.content,\n category: input.category,\n status: \"INSPECTION\",\n buttons: payloadValidation.value.buttons,\n variables: input.variables,\n createdAt: now,\n updatedAt: now,\n });\n } catch (error) {\n return fail(\n new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n ),\n );\n }\n}\n\nexport async function updateTemplate(params: {\n providerId: string;\n config: NormalizedIwinvConfig;\n code: string;\n patch: TemplateUpdateInput;\n ctx?: TemplateContext;\n}): Promise<Result<Template, KMsgError>> {\n const { providerId, config, code, patch, ctx } = params;\n const templateCode = typeof code === \"string\" ? code.trim() : \"\";\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId,\n }),\n );\n }\n\n const existingResult = await getTemplate({\n providerId,\n config,\n code: templateCode,\n ctx,\n });\n if (existingResult.isFailure) return existingResult;\n const existing = existingResult.value;\n\n const nextName =\n typeof patch.name === \"string\" && patch.name.trim().length > 0\n ? patch.name.trim()\n : existing.name;\n const nextContent =\n typeof patch.content === \"string\" && patch.content.trim().length > 0\n ? patch.content\n : existing.content;\n const nextButtons =\n patch.buttons !== undefined ? patch.buttons : existing.buttons;\n const payloadValidation = validateTemplatePayload(\n {\n name: nextName,\n content: nextContent,\n buttons: nextButtons,\n },\n {\n requireName: true,\n requireContent: true,\n },\n );\n if (payloadValidation.isFailure) {\n return fail(withProviderContext(payloadValidation.error, providerId));\n }\n\n const url = `${config.baseUrl}/api/template/modify/`;\n const payload: Record<string, unknown> = {\n templateCode,\n templateName: payloadValidation.value.name ?? nextName,\n templateContent: payloadValidation.value.content ?? nextContent,\n ...(payloadValidation.value.buttons\n ? { buttons: payloadValidation.value.buttons }\n : {}),\n };\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: getAlimTalkHeaders(config),\n body: JSON.stringify(payload),\n });\n\n const data = await readIwinvTemplateResponse(response);\n const statusCode = normalizeIwinvCode(data.code) ?? response.status;\n const message =\n typeof data.message === \"string\" && data.message.length > 0\n ? data.message\n : \"IWINV template update failed\";\n\n if (!response.ok || statusCode !== 200) {\n return fail(\n new KMsgError(mapIwinvCodeToKMsgErrorCode(statusCode), message, {\n providerId,\n originalCode: statusCode,\n }),\n );\n }\n\n const refreshed = await getTemplate({\n providerId,\n config,\n code: templateCode,\n ctx,\n });\n if (refreshed.isSuccess) return refreshed;\n\n return ok({\n ...existing,\n name: payloadValidation.value.name ?? nextName,\n content: payloadValidation.value.content ?? nextContent,\n ...(patch.category !== undefined ? { category: patch.category } : {}),\n ...(patch.variables !== undefined ? { variables: patch.variables } : {}),\n ...(patch.buttons !== undefined\n ? { buttons: payloadValidation.value.buttons }\n : {}),\n updatedAt: new Date(),\n });\n } catch (error) {\n return fail(\n new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n ),\n );\n }\n}\n\nexport async function deleteTemplate(params: {\n providerId: string;\n config: NormalizedIwinvConfig;\n code: string;\n}): Promise<Result<void, KMsgError>> {\n const { providerId, config, code } = params;\n const templateCode = typeof code === \"string\" ? code.trim() : \"\";\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId,\n }),\n );\n }\n\n const url = `${config.baseUrl}/api/template/delete/`;\n const payload: Record<string, unknown> = { templateCode };\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: getAlimTalkHeaders(config),\n body: JSON.stringify(payload),\n });\n\n const data = await readIwinvTemplateResponse(response);\n const statusCode = normalizeIwinvCode(data.code) ?? response.status;\n const message =\n typeof data.message === \"string\" && data.message.length > 0\n ? data.message\n : typeof data.messgae === \"string\" && data.messgae.length > 0\n ? data.messgae\n : \"IWINV template delete failed\";\n\n if (!response.ok || statusCode !== 200) {\n return fail(\n new KMsgError(mapIwinvCodeToKMsgErrorCode(statusCode), message, {\n providerId,\n originalCode: statusCode,\n }),\n );\n }\n\n return ok(undefined);\n } catch (error) {\n return fail(\n new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n ),\n );\n }\n}\n\nexport async function getTemplate(params: {\n providerId: string;\n config: NormalizedIwinvConfig;\n code: string;\n ctx?: TemplateContext;\n}): Promise<Result<Template, KMsgError>> {\n const { providerId, config, code: inputCode } = params;\n const templateCode = typeof inputCode === \"string\" ? inputCode.trim() : \"\";\n\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId,\n }),\n );\n }\n\n const payload: Record<string, unknown> = {\n pageNum: \"1\",\n pageSize: \"15\",\n templateCode,\n };\n\n const url = `${config.baseUrl}/api/template/`;\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: getAlimTalkHeaders(config),\n body: JSON.stringify(payload),\n });\n\n const data = await readIwinvTemplateResponse(response);\n const statusCode = normalizeIwinvCode(data.code) ?? response.status;\n const message =\n typeof data.message === \"string\" && data.message.length > 0\n ? data.message\n : \"IWINV template get failed\";\n\n if (!response.ok || statusCode !== 200) {\n return fail(\n new KMsgError(mapIwinvCodeToKMsgErrorCode(statusCode), message, {\n providerId,\n originalCode: statusCode,\n }),\n );\n }\n\n const listRaw = data.list;\n const list = Array.isArray(listRaw) ? listRaw : [];\n const first = list.find(isObjectRecord);\n if (!first) {\n return fail(\n new KMsgError(KMsgErrorCode.TEMPLATE_NOT_FOUND, \"Template not found\", {\n providerId,\n templateCode,\n }),\n );\n }\n\n const templateCodeValue = first.templateCode;\n const resolvedCode =\n typeof templateCodeValue === \"string\"\n ? templateCodeValue\n : String(templateCodeValue ?? \"\");\n const name =\n typeof first.templateName === \"string\" ? first.templateName : \"\";\n const content =\n typeof first.templateContent === \"string\" ? first.templateContent : \"\";\n const status = mapIwinvTemplateStatus(first.status);\n const createdAt = parseIwinvDateTime(first.createDate) ?? new Date();\n\n return ok({\n id: resolvedCode,\n code: resolvedCode,\n name,\n content,\n status,\n buttons: Array.isArray(first.buttons) ? first.buttons : undefined,\n createdAt,\n updatedAt: createdAt,\n });\n } catch (error) {\n return fail(\n new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n ),\n );\n }\n}\n\nexport async function listTemplates(params: {\n providerId: string;\n config: NormalizedIwinvConfig;\n query?: { status?: string; page?: number; limit?: number };\n ctx?: TemplateContext;\n}): Promise<Result<Template[], KMsgError>> {\n const { providerId, config, query } = params;\n\n const pageNum =\n typeof query?.page === \"number\" && query.page > 0\n ? Math.floor(query.page)\n : 1;\n const pageSize =\n typeof query?.limit === \"number\" && query.limit > 0\n ? Math.floor(query.limit)\n : 15;\n\n const templateStatus = toIwinvTemplateStatus(query?.status);\n const payload: Record<string, unknown> = {\n pageNum: String(pageNum),\n pageSize: String(pageSize),\n ...(templateStatus ? { templateStatus } : {}),\n };\n\n const url = `${config.baseUrl}/api/template/`;\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: getAlimTalkHeaders(config),\n body: JSON.stringify(payload),\n });\n\n const data = await readIwinvTemplateResponse(response);\n const statusCode = normalizeIwinvCode(data.code) ?? response.status;\n const message =\n typeof data.message === \"string\" && data.message.length > 0\n ? data.message\n : \"IWINV template list failed\";\n\n if (!response.ok || statusCode !== 200) {\n return fail(\n new KMsgError(mapIwinvCodeToKMsgErrorCode(statusCode), message, {\n providerId,\n originalCode: statusCode,\n }),\n );\n }\n\n const listRaw = data.list;\n const list = Array.isArray(listRaw) ? listRaw : [];\n\n const templates: Template[] = list\n .filter(isObjectRecord)\n .map((item) => {\n const templateCodeValue = item.templateCode;\n const templateCode =\n typeof templateCodeValue === \"string\"\n ? templateCodeValue\n : String(templateCodeValue ?? \"\");\n const name =\n typeof item.templateName === \"string\" ? item.templateName : \"\";\n const content =\n typeof item.templateContent === \"string\" ? item.templateContent : \"\";\n const status = mapIwinvTemplateStatus(item.status);\n const createdAt = parseIwinvDateTime(item.createDate) ?? new Date();\n\n return {\n id: templateCode,\n code: templateCode,\n name,\n content,\n status,\n buttons: Array.isArray(item.buttons) ? item.buttons : undefined,\n createdAt,\n updatedAt: createdAt,\n };\n })\n .filter((tpl) => tpl.code.length > 0);\n\n return ok(templates);\n } catch (error) {\n return fail(\n new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n ),\n );\n }\n}\n",
|
|
18
|
-
"/**\n * IWINV API TypeScript 타입 정의\n * IWINV 알림톡 REST API 규격서 기반\n */\n\n// Standalone config interface (does not depend on core's removed StandardRequest system)\n\n// =============================================================================\n// 공통 응답 타입\n// =============================================================================\n\nexport interface IWINVBaseResponse {\n code: number;\n message: string;\n}\n\n// =============================================================================\n// 알림톡 발송 관련 타입\n// =============================================================================\n\nexport interface SendMessageRequest {\n templateCode: string;\n reserve?: \"Y\" | \"N\"; // 기본값: N\n sendDate?: string; // yyyy-MM-dd HH:mm:ss (예약발송시 필수)\n reSend?: \"Y\" | \"N\"; // 기본값: N\n resendCallback?: string; // 발신번호\n resendType?: \"Y\" | \"N\"; // 기본값: Y (Y:알림톡내용, N:직접입력)\n resendTitle?: string; // LMS 대체문자 제목\n resendContent?: string; // 대체문자 내용\n list: SendRecipient[];\n}\n\nexport interface SendRecipient {\n phone: string; // 수신번호\n templateParam?: string[]; // 템플릿 변수 배열\n}\n\nexport interface SendMessageResponse extends IWINVBaseResponse {\n success: number; // 정상 전송요청 연락처 개수\n fail: number; // 전송요청되지 않은 연락처 개수\n}\n\n// =============================================================================\n// 템플릿 관련 타입\n// =============================================================================\n\nexport interface CreateTemplateRequest {\n templateName: string; // 최대 15자\n templateContent: string; // 최대 1000자\n buttons?: CreateTemplateButton[];\n}\n\nexport interface CreateTemplateButton {\n type: \"WL\" | \"AL\" | \"DB\" | \"BK\" | \"MD\";\n name: string; // 최대 15자\n linkMo?: string; // WL타입 필수, 최대 200자\n linkPc?: string; // WL타입 필수, 최대 200자\n linkIos?: string; // AL타입 필수, 최대 200자\n linkAnd?: string; // AL타입 필수, 최대 200자\n}\n\nexport interface Template {\n templateCode: string;\n templateName: string;\n templateContent: string;\n status: \"Y\" | \"I\" | \"R\"; // Y:사용가능, I:검수중, R:부결\n templateStatusMsg?: string;\n templateStatusComments?: string;\n createDate: string;\n buttons: unknown[];\n}\n\nexport interface TemplateListRequest {\n pageNum?: string; // 기본값: \"1\"\n pageSize?: string; // 기본값: \"15\", 최대: \"1000\"\n templateCode?: string;\n templateName?: string;\n templateStatus?: \"Y\" | \"I\" | \"R\"; // Y:사용가능, I:검수중, R:부결\n}\n\nexport interface TemplateListResponse extends IWINVBaseResponse {\n totalCount: number;\n list: Template[];\n}\n\nexport interface ModifyTemplateRequest {\n templateCode: string;\n templateName: string; // 최대 15자\n templateContent: string; // 최대 1000자\n buttons?: CreateTemplateButton[];\n}\n\nexport interface DeleteTemplateRequest {\n templateCode: string;\n}\n\nexport type CreateTemplateResponse = IWINVBaseResponse;\nexport type ModifyTemplateResponse = IWINVBaseResponse;\nexport type DeleteTemplateResponse = IWINVBaseResponse;\n\n// =============================================================================\n// 전송 내역 관련 타입\n// =============================================================================\n\nexport interface HistoryRequest {\n pageNum?: number; // 기본값: 1\n pageSize?: number; // 기본값: 15, 최대: 1000\n reserve?: \"Y\" | \"N\"; // 예약발송 여부\n startDate?: string; // yyyy-MM-dd HH:mm:ss\n endDate?: string; // yyyy-MM-dd HH:mm:ss\n seqNo?: number; // 메시지 ID\n phone?: string; // 수신번호\n}\n\nexport interface MessageHistory {\n seqNo: number; // 메시지 ID\n phone: string; // 수신번호\n callback: string; // 발신번호\n templateCode: string;\n sendMessage: string; // 전송한 메시지\n reserve: \"Y\" | \"N\"; // 예약발송 여부\n requestDate: string; // 요청일\n sendDate: string; // 전송일\n receiveDate: string; // 수신일\n statusCode: string; // 알림톡 발송 요청 상태 코드\n statusCodeName: string; // 알림톡 발송 요청 상태 코드명\n resendStatus: string | null; // 대체 발송 상태 코드\n resendStatusName: string | null; // 대체 발송 상태 코드명\n buttons: {\n link1: string | null;\n link2: string | null;\n link3: string | null;\n link4: string | null;\n link5: string | null;\n };\n}\n\nexport interface HistoryResponse extends IWINVBaseResponse {\n totalCount: number;\n list: MessageHistory[];\n}\n\nexport interface CancelReservationRequest {\n seqNo: number; // 메시지 ID\n}\n\nexport type CancelReservationResponse = IWINVBaseResponse;\n\n// =============================================================================\n// 잔액 조회 관련 타입\n// =============================================================================\n\nexport interface BalanceResponse extends IWINVBaseResponse {\n charge: number; // 잔액\n}\n\n// =============================================================================\n// SMS(v2) 전송 내역/잔액 조회 타입\n// =============================================================================\n\nexport interface IWINVSmsChargeRequest {\n version: string; // \"1.0\"\n}\n\nexport interface IWINVSmsChargeResponse {\n code: number; // 0 on success\n message: string;\n charge: number; // remaining amount\n}\n\nexport interface IWINVSmsHistoryRequest {\n version: string; // \"1.0\"\n companyid: string;\n startDate: string; // yyyy-MM-dd\n endDate: string; // yyyy-MM-dd\n requestNo?: string;\n pageNum?: number;\n pageSize?: number;\n phone?: string;\n}\n\nexport interface IWINVSmsHistoryItem {\n requestNo: string | number;\n companyid: string;\n msgType: string; // SMS, LMS, MMS\n phone: string;\n callback: string;\n sendStatus?: string;\n sendStatusCode?: string;\n sendStatusMsg?: string;\n sendDate: string; // yyyy-MM-dd HH:mm:ss\n}\n\nexport interface IWINVSmsHistoryResponse {\n resultCode: number; // 0 on success\n message: string;\n totalCount: number;\n list: IWINVSmsHistoryItem[];\n}\n\n// =============================================================================\n// 설정 타입\n// =============================================================================\n\nexport interface IWINVConfig {\n /**\n * IWINV AlimTalk API key (used for AUTH header).\n */\n apiKey: string;\n\n smsApiKey?: string;\n smsAuthKey?: string;\n /**\n * SMS v2 전송 내역 조회시 필요한 조직(업체) 발송 아이디.\n * (API 문서의 `companyid`)\n */\n smsCompanyId?: string;\n senderNumber?: string;\n smsSenderNumber?: string;\n sendEndpoint?: string;\n /**\n * Optional proxy/IP override header for IP-restricted IWINV endpoints.\n * Intended for testing or controlled environments; production should whitelist real egress IPs.\n */\n xForwardedFor?: string;\n /**\n * Extra HTTP headers merged into outgoing requests.\n * Use with care: overriding AUTH/secret can break requests.\n */\n extraHeaders?: Record<string, string>;\n ipRetryCount?: number;\n ipRetryDelayMs?: number;\n ipAlertWebhookUrl?: string;\n onIpRestrictionAlert?: (\n payload: IWINVIPRestrictionAlert,\n ) => void | Promise<void>;\n debug?: boolean;\n}\n\nexport interface IWINVIPRestrictionAlert {\n provider: \"iwinv\";\n channel: string;\n endpoint: string;\n phoneNumber: string;\n templateCode?: string;\n code: string;\n message: string;\n attempt: number;\n maxAttempts: number;\n timestamp: string;\n}\n\n// =============================================================================\n// 상수\n// =============================================================================\n\nexport const IWINV_STATUS_CODES = {\n SUCCESS: 200,\n AUTH_FAILED: 201,\n BAD_REQUEST: 400,\n UNAUTHORIZED: 401,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n TOO_MANY_REQUESTS: 429,\n INTERNAL_SERVER_ERROR: 500,\n} as const;\n"
|
|
19
|
-
],
|
|
20
|
-
"mappings": "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",
|
|
21
|
-
"debugId": "8130AFA80FD809DC64756E2164756E21",
|
|
22
|
-
"names": []
|
|
23
|
-
}
|
package/dist/solapi/index.js.map
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/solapi/provider.ts", "../src/onboarding/specs.ts", "../src/solapi/solapi.delivery.ts", "../src/shared/type-guards.ts", "../src/solapi/solapi.error.ts", "../src/solapi/solapi.helpers.ts", "../src/solapi/solapi.send.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import {\n type BalanceProvider,\n type BalanceQuery,\n type BalanceResult,\n type DeliveryStatusQuery,\n type DeliveryStatusResult,\n fail,\n KMsgError,\n KMsgErrorCode,\n type MessageType,\n ok,\n type Provider,\n type ProviderHealthStatus,\n type Result,\n readRuntimeEnv,\n type SendOptions,\n type SendResult,\n} from \"@k-msg/core\";\nimport { SolapiMessageService } from \"solapi\";\nimport { getProviderOnboardingSpec } from \"../onboarding/specs\";\nimport { getSolapiDeliveryStatus } from \"./solapi.delivery\";\nimport { mapSolapiError } from \"./solapi.error\";\nimport type { SolapiSdkClient } from \"./solapi.internal.types\";\nimport { sendWithSolapi } from \"./solapi.send\";\nimport type { SolapiConfig } from \"./types/solapi\";\n\nexport class SolapiProvider implements Provider, BalanceProvider {\n readonly id = \"solapi\";\n readonly name = \"SOLAPI Messaging Provider\";\n readonly supportedTypes: readonly MessageType[] = [\n \"ALIMTALK\",\n \"FRIENDTALK\",\n \"SMS\",\n \"LMS\",\n \"MMS\",\n \"NSA\",\n \"VOICE\",\n \"FAX\",\n \"RCS_SMS\",\n \"RCS_LMS\",\n \"RCS_MMS\",\n \"RCS_TPL\",\n \"RCS_ITPL\",\n \"RCS_LTPL\",\n ];\n\n private readonly config: SolapiConfig;\n private readonly client: SolapiSdkClient;\n\n getOnboardingSpec() {\n const spec = getProviderOnboardingSpec(this.id);\n if (!spec) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n `Onboarding spec missing for provider: ${this.id}`,\n { providerId: this.id },\n );\n }\n return spec;\n }\n\n constructor(config: SolapiConfig, client?: SolapiSdkClient) {\n if (!config || typeof config !== \"object\") {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"SolapiProvider requires a config object\",\n { providerId: this.id },\n );\n }\n if (!config.apiKey || config.apiKey.length === 0) {\n throw new Error(\"SolapiProvider requires `apiKey`\");\n }\n if (!config.apiSecret || config.apiSecret.length === 0) {\n throw new Error(\"SolapiProvider requires `apiSecret`\");\n }\n\n this.config = {\n ...config,\n baseUrl:\n typeof config.baseUrl === \"string\" && config.baseUrl.length > 0\n ? config.baseUrl\n : \"https://api.solapi.com\",\n };\n this.client =\n client ??\n new SolapiMessageService(this.config.apiKey, this.config.apiSecret);\n }\n\n async healthCheck(): Promise<ProviderHealthStatus> {\n const issues: string[] = [];\n const start = Date.now();\n\n try {\n if (!this.config.apiKey) issues.push(\"Missing apiKey\");\n if (!this.config.apiSecret) issues.push(\"Missing apiSecret\");\n if (this.config.baseUrl) {\n try {\n new URL(this.config.baseUrl);\n } catch {\n issues.push(\"Invalid baseUrl\");\n }\n }\n\n return {\n healthy: issues.length === 0,\n issues,\n latencyMs: Date.now() - start,\n data: {\n provider: this.id,\n baseUrl: this.config.baseUrl,\n },\n };\n } catch (error) {\n issues.push(error instanceof Error ? error.message : String(error));\n return { healthy: false, issues, latencyMs: Date.now() - start };\n }\n }\n\n async send(options: SendOptions): Promise<Result<SendResult, KMsgError>> {\n const messageId = options.messageId || crypto.randomUUID();\n const normalized = { ...options, messageId } as SendOptions;\n\n try {\n return await sendWithSolapi({\n providerId: this.id,\n client: this.client,\n config: this.config,\n options: normalized,\n });\n } catch (error) {\n return fail(mapSolapiError(error, this.id));\n }\n }\n\n async getDeliveryStatus(\n query: DeliveryStatusQuery,\n ): Promise<Result<DeliveryStatusResult | null, KMsgError>> {\n return getSolapiDeliveryStatus({\n providerId: this.id,\n client: this.client,\n query,\n });\n }\n\n async getBalance(\n query?: BalanceQuery,\n ): Promise<Result<BalanceResult, KMsgError>> {\n try {\n const raw = await this.client.getBalance();\n const source = raw as Record<string, unknown>;\n const amountCandidates = [source.balance, source.point];\n\n let amount = Number.NaN;\n for (const candidate of amountCandidates) {\n if (typeof candidate === \"number\" && Number.isFinite(candidate)) {\n amount = candidate;\n break;\n }\n if (typeof candidate === \"string\") {\n const numeric = Number(candidate);\n if (Number.isFinite(numeric)) {\n amount = numeric;\n break;\n }\n }\n }\n\n if (!Number.isFinite(amount)) {\n return fail(\n mapSolapiError(\n new Error(\"Invalid balance response from SOLAPI\"),\n this.id,\n ),\n );\n }\n\n return ok({\n providerId: this.id,\n channel: query?.channel,\n amount,\n currency: \"KRW\",\n raw,\n });\n } catch (error) {\n return fail(mapSolapiError(error, this.id));\n }\n }\n}\n\nexport const createSolapiProvider = (config: SolapiConfig) =>\n new SolapiProvider(config);\n\nexport const createDefaultSolapiProvider = () => {\n const config: SolapiConfig = {\n apiKey: readRuntimeEnv(\"SOLAPI_API_KEY\") || \"\",\n apiSecret: readRuntimeEnv(\"SOLAPI_API_SECRET\") || \"\",\n baseUrl: readRuntimeEnv(\"SOLAPI_BASE_URL\") || \"https://api.solapi.com\",\n defaultFrom: readRuntimeEnv(\"SOLAPI_DEFAULT_FROM\"),\n kakaoPfId: readRuntimeEnv(\"SOLAPI_KAKAO_PF_ID\"),\n rcsBrandId: readRuntimeEnv(\"SOLAPI_RCS_BRAND_ID\"),\n naverTalkId: readRuntimeEnv(\"SOLAPI_NAVER_TALK_ID\"),\n appId: readRuntimeEnv(\"SOLAPI_APP_ID\"),\n defaultCountry: readRuntimeEnv(\"SOLAPI_DEFAULT_COUNTRY\"),\n debug: readRuntimeEnv(\"NODE_ENV\") === \"development\",\n };\n\n if (!config.apiKey || !config.apiSecret) {\n throw new Error(\n \"SOLAPI_API_KEY and SOLAPI_API_SECRET environment variables are required\",\n );\n }\n\n return createSolapiProvider(config);\n};\n\n// biome-ignore lint/complexity/noStaticOnlyClass: kept as a factory for convenience\nexport class SolapiProviderFactory {\n static create(config: SolapiConfig): SolapiProvider {\n return new SolapiProvider(config);\n }\n\n static createDefault(): SolapiProvider {\n return createDefaultSolapiProvider();\n }\n}\n\nexport function initializeSolapi(): void {}\n",
|
|
6
|
-
"import type { ProviderOnboardingSpec } from \"@k-msg/core\";\n\nexport const providerOnboardingSpecs: Readonly<\n Record<string, ProviderOnboardingSpec>\n> = {\n iwinv: {\n providerId: \"iwinv\",\n providerName: \"IWINV Messaging Provider\",\n channelOnboarding: \"manual\",\n templateLifecycleApi: \"available\",\n plusIdPolicy: \"optional\",\n plusIdInference: \"unsupported\",\n liveTestSupport: \"supported\",\n checks: [\n {\n id: \"channel_registered_in_console\",\n title: \"Kakao channel is registered in IWINV console\",\n description:\n \"IWINV channel onboarding is manual. Confirm channel registration and approval in console.\",\n kind: \"manual\",\n severity: \"blocker\",\n scopes: [\"doctor\", \"preflight\"],\n },\n {\n id: \"iwinv_config_required\",\n title: \"IWINV config has required keys\",\n kind: \"config\",\n severity: \"blocker\",\n scopes: [\"doctor\", \"preflight\"],\n configKeys: [\"apiKey\"],\n },\n {\n id: \"template_capability_available\",\n title: \"Template lifecycle APIs are available\",\n kind: \"capability\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n capabilityMethods: [\n \"listTemplates\",\n \"getTemplate\",\n \"createTemplate\",\n \"updateTemplate\",\n \"deleteTemplate\",\n ],\n },\n {\n id: \"template_list_probe\",\n title: \"Template list API probe\",\n kind: \"api_probe\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n probeOperation: \"list_templates\",\n },\n ],\n notes: [\n \"Channel add/auth is not available via IWINV public API in current integration.\",\n \"Template APIs are available and can be probed.\",\n ],\n },\n aligo: {\n providerId: \"aligo\",\n providerName: \"Aligo Smart SMS\",\n channelOnboarding: \"api\",\n templateLifecycleApi: \"available\",\n plusIdPolicy: \"required_if_no_inference\",\n plusIdInference: \"supported\",\n liveTestSupport: \"supported\",\n checks: [\n {\n id: \"aligo_config_required\",\n title: \"Aligo config has required keys\",\n kind: \"config\",\n severity: \"blocker\",\n scopes: [\"doctor\", \"preflight\"],\n configKeys: [\"apiKey\", \"userId\"],\n },\n {\n id: \"channel_api_capability_available\",\n title: \"Kakao channel APIs are available\",\n kind: \"capability\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n capabilityMethods: [\n \"listKakaoChannels\",\n \"requestKakaoChannelAuth\",\n \"addKakaoChannel\",\n ],\n },\n {\n id: \"channel_list_probe\",\n title: \"Kakao channel list API probe\",\n kind: \"api_probe\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n probeOperation: \"list_kakao_channels\",\n },\n {\n id: \"template_list_probe\",\n title: \"Template list API probe\",\n kind: \"api_probe\",\n severity: \"warning\",\n scopes: [\"doctor\", \"preflight\"],\n probeOperation: \"list_templates\",\n },\n ],\n },\n solapi: {\n providerId: \"solapi\",\n providerName: \"SOLAPI Messaging Provider\",\n channelOnboarding: \"none\",\n templateLifecycleApi: \"unavailable\",\n plusIdPolicy: \"required_if_no_inference\",\n plusIdInference: \"unsupported\",\n liveTestSupport: \"partial\",\n checks: [\n {\n id: \"solapi_config_required\",\n title: \"SOLAPI config has required keys\",\n kind: \"config\",\n severity: \"blocker\",\n scopes: [\"doctor\", \"preflight\"],\n configKeys: [\"apiKey\", \"apiSecret\"],\n },\n ],\n notes: [\n \"SOLAPI ALIMTALK requires kakao profileId/pfId, but plusId inference is not available in current integration.\",\n ],\n },\n mock: {\n providerId: \"mock\",\n providerName: \"Mock Provider\",\n channelOnboarding: \"api\",\n templateLifecycleApi: \"available\",\n plusIdPolicy: \"optional\",\n plusIdInference: \"supported\",\n liveTestSupport: \"none\",\n checks: [\n {\n id: \"mock_template_capability_available\",\n title: \"Mock template APIs are available\",\n kind: \"capability\",\n severity: \"info\",\n scopes: [\"doctor\", \"preflight\"],\n capabilityMethods: [\"listTemplates\", \"getTemplate\", \"createTemplate\"],\n },\n ],\n },\n} as const;\n\nexport function getProviderOnboardingSpec(\n providerId: string,\n): ProviderOnboardingSpec | undefined {\n return providerOnboardingSpecs[providerId];\n}\n\nexport function listProviderOnboardingSpecs(): ProviderOnboardingSpec[] {\n return Object.values(providerOnboardingSpecs);\n}\n",
|
|
7
|
-
"import {\n type DeliveryStatusQuery,\n type DeliveryStatusResult,\n fail,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n} from \"@k-msg/core\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport { mapSolapiError } from \"./solapi.error\";\nimport { mapSolapiStatusCode, parseDate } from \"./solapi.helpers\";\nimport type { SolapiSdkClient } from \"./solapi.internal.types\";\n\nexport async function getSolapiDeliveryStatus(params: {\n providerId: string;\n client: SolapiSdkClient;\n query: DeliveryStatusQuery;\n}): Promise<Result<DeliveryStatusResult | null, KMsgError>> {\n const { providerId, client, query } = params;\n const providerMessageId = query.providerMessageId.trim();\n if (!providerMessageId) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"providerMessageId is required\",\n { providerId },\n ),\n );\n }\n\n try {\n const response = await client.getMessages({\n messageId: providerMessageId,\n limit: 1,\n });\n\n const record = (isObjectRecord(response) ? response : {}) as Record<\n string,\n unknown\n >;\n const messageList = record.messageList;\n if (\n !messageList ||\n typeof messageList !== \"object\" ||\n Array.isArray(messageList)\n ) {\n return ok(null);\n }\n\n const recordList = messageList as Record<string, unknown>;\n const direct = recordList[providerMessageId];\n\n const values = Object.values(recordList);\n const found = values.find((v) => {\n if (!isObjectRecord(v)) return false;\n const mid = v.messageId;\n return typeof mid === \"string\" ? mid === providerMessageId : false;\n });\n\n const message = isObjectRecord(direct)\n ? direct\n : isObjectRecord(found)\n ? found\n : undefined;\n if (!message) return ok(null);\n\n const statusCode =\n typeof message.statusCode === \"string\" ? message.statusCode : undefined;\n const status = mapSolapiStatusCode(statusCode);\n\n const sentAt = parseDate(message.dateSent);\n const deliveredAt = parseDate(message.dateCompleted);\n\n return ok({\n providerId,\n providerMessageId,\n status,\n statusCode,\n statusMessage:\n typeof message.statusMessage === \"string\"\n ? message.statusMessage\n : undefined,\n sentAt,\n deliveredAt,\n raw: message,\n });\n } catch (error) {\n return fail(mapSolapiError(error, providerId));\n }\n}\n",
|
|
8
|
-
"export function isObjectRecord(\n value: unknown,\n): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n",
|
|
9
|
-
"import { KMsgError, KMsgErrorCode } from \"@k-msg/core\";\nimport {\n ApiKeyError,\n BadRequestError,\n ClientError,\n DefaultError,\n NetworkError,\n ServerError,\n} from \"solapi\";\nimport { isObjectRecord } from \"../shared/type-guards\";\n\nexport function mapSolapiError(error: unknown, providerId: string): KMsgError {\n if (error instanceof KMsgError) return error;\n\n const record = isObjectRecord(error) ? error : {};\n\n if (error instanceof ApiKeyError) {\n return new KMsgError(KMsgErrorCode.AUTHENTICATION_FAILED, error.message, {\n providerId,\n });\n }\n\n if (error instanceof BadRequestError) {\n return new KMsgError(KMsgErrorCode.INVALID_REQUEST, error.message, {\n providerId,\n validationErrors: record.validationErrors,\n });\n }\n\n if (error instanceof NetworkError) {\n return new KMsgError(KMsgErrorCode.NETWORK_ERROR, error.message, {\n providerId,\n url: typeof record.url === \"string\" ? record.url : undefined,\n method: typeof record.method === \"string\" ? record.method : undefined,\n isRetryable:\n typeof record.isRetryable === \"boolean\" ? record.isRetryable : true,\n });\n }\n\n if (error instanceof ClientError) {\n const httpStatus =\n typeof record.httpStatus === \"number\" ? record.httpStatus : undefined;\n const isInvalidRequest =\n typeof httpStatus === \"number\" && httpStatus >= 400 && httpStatus < 500;\n\n return new KMsgError(\n isInvalidRequest\n ? KMsgErrorCode.INVALID_REQUEST\n : KMsgErrorCode.PROVIDER_ERROR,\n error.message,\n {\n providerId,\n httpStatus,\n errorCode: record.errorCode,\n errorMessage: record.errorMessage,\n url: record.url,\n },\n );\n }\n\n if (error instanceof ServerError) {\n return new KMsgError(KMsgErrorCode.PROVIDER_ERROR, error.message, {\n providerId,\n httpStatus:\n typeof record.httpStatus === \"number\" ? record.httpStatus : undefined,\n });\n }\n\n if (error instanceof DefaultError) {\n return new KMsgError(KMsgErrorCode.PROVIDER_ERROR, error.message, {\n providerId,\n errorCode: record.errorCode,\n errorMessage: record.errorMessage,\n });\n }\n\n return new KMsgError(\n KMsgErrorCode.UNKNOWN_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n );\n}\n",
|
|
10
|
-
"import {\n type DeliveryStatus,\n KMsgError,\n KMsgErrorCode,\n type MessageBinaryInput,\n type MessageButton,\n type MessageVariables,\n type SendOptions,\n} from \"@k-msg/core\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport type {\n SolapiKakaoButton,\n SolapiMessageType,\n} from \"./solapi.internal.types\";\n\nexport function mapSolapiStatusCode(statusCode?: string): DeliveryStatus {\n if (!statusCode) return \"UNKNOWN\";\n if (statusCode === \"2000\") return \"PENDING\";\n if (statusCode === \"3000\") return \"SENT\";\n if (statusCode === \"4000\") return \"DELIVERED\";\n if (/^[123]\\\\d{3}$/.test(statusCode)) return \"FAILED\";\n return \"UNKNOWN\";\n}\n\nexport function parseDate(value: unknown): Date | undefined {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n return undefined;\n }\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return undefined;\n return date;\n}\n\nexport function normalizePhoneNumber(phone: string): string {\n const trimmed = phone.trim();\n if (trimmed.startsWith(\"+\")) {\n return `+${trimmed.slice(1).replace(/\\\\D/g, \"\")}`;\n }\n return trimmed.replace(/\\\\D/g, \"\");\n}\n\nexport function stringifyVariables(\n variables: MessageVariables | undefined,\n): Record<string, string> {\n const output: Record<string, string> = {};\n if (!variables) return output;\n\n for (const [key, value] of Object.entries(variables)) {\n if (value === undefined) continue;\n output[key] =\n value === null\n ? \"\"\n : value instanceof Date\n ? value.toISOString()\n : typeof value === \"string\"\n ? value\n : String(value);\n }\n\n return output;\n}\n\nexport function toKakaoButtons(\n buttons: MessageButton[] | undefined,\n): SolapiKakaoButton[] | undefined {\n if (!Array.isArray(buttons) || buttons.length === 0) return undefined;\n const out: SolapiKakaoButton[] = [];\n\n for (const button of buttons) {\n if (!button) continue;\n if (button.type !== \"WL\") continue;\n if (!button.name || !button.urlMobile) continue;\n out.push({\n buttonName: button.name,\n buttonType: \"WL\",\n linkMo: button.urlMobile,\n linkPc: button.urlPc,\n });\n }\n\n return out.length > 0 ? out : undefined;\n}\n\nexport function resolveImageRef(options: {\n imageUrl?: string;\n media?: { image?: MessageBinaryInput };\n providerId: string;\n}) {\n const imageUrl =\n typeof options.imageUrl === \"string\" && options.imageUrl.trim().length > 0\n ? options.imageUrl.trim()\n : undefined;\n if (imageUrl) return imageUrl;\n\n const image = options.media?.image;\n if (!image) return undefined;\n\n if (\"ref\" in image) {\n const ref = image.ref.trim();\n return ref.length > 0 ? ref : undefined;\n }\n\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"SOLAPI image upload requires `options.imageUrl` or `options.media.image.ref` (url/path).\",\n { providerId: options.providerId },\n );\n}\n\nexport function extractFileId(upload: unknown): string | undefined {\n return isObjectRecord(upload) && typeof upload.fileId === \"string\"\n ? upload.fileId\n : undefined;\n}\n\nexport function toSolapiMessageType(options: SendOptions): SolapiMessageType {\n switch (options.type) {\n case \"ALIMTALK\":\n return \"ATA\";\n case \"FRIENDTALK\":\n return (typeof options.imageUrl === \"string\" &&\n options.imageUrl.trim().length > 0) ||\n Boolean(options.media?.image)\n ? \"CTI\"\n : \"CTA\";\n default:\n return options.type as unknown as SolapiMessageType;\n }\n}\n",
|
|
11
|
-
"import {\n KMsgError,\n KMsgErrorCode,\n type MessageType,\n ok,\n type Result,\n type SendOptions,\n type SendResult,\n} from \"@k-msg/core\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport {\n extractFileId,\n normalizePhoneNumber,\n resolveImageRef,\n stringifyVariables,\n toKakaoButtons,\n toSolapiMessageType,\n} from \"./solapi.helpers\";\nimport type {\n SolapiSdkClient,\n SolapiSendOneMessage,\n} from \"./solapi.internal.types\";\nimport type { SolapiConfig } from \"./types/solapi\";\n\nexport function collectSolapiSendWarnings(\n options: SendOptions,\n providerId: string,\n): SendResult[\"warnings\"] {\n if (options.type !== \"ALIMTALK\") return undefined;\n if (options.failover?.enabled !== true) return undefined;\n\n return [\n {\n code: \"FAILOVER_PARTIAL_PROVIDER\",\n message:\n \"SOLAPI failover mapping is partial. API-level fallback may be attempted for non-Kakao-user failures.\",\n details: {\n providerId,\n mappedFields: [\"kakao.disableSms\", \"text\", \"subject\"],\n unsupportedFields: [\"fallbackChannel\"],\n },\n },\n ];\n}\n\nexport function adaptSolapiSendResult(params: {\n options: SendOptions;\n response: unknown;\n providerId: string;\n warnings?: SendResult[\"warnings\"];\n}): SendResult {\n const { options, response, providerId, warnings } = params;\n const record = isObjectRecord(response) ? response : {};\n const providerMessageId =\n typeof record.messageId === \"string\" ? record.messageId : undefined;\n\n return {\n messageId: options.messageId || crypto.randomUUID(),\n providerId,\n providerMessageId,\n status: \"SENT\",\n type: options.type,\n to: options.to,\n ...(Array.isArray(warnings) && warnings.length > 0 ? { warnings } : {}),\n raw: response,\n };\n}\n\nexport async function buildSolapiSendOneMessage(params: {\n options: SendOptions;\n providerId: string;\n config: SolapiConfig;\n client: SolapiSdkClient;\n}): Promise<SolapiSendOneMessage> {\n const { options, providerId, config, client } = params;\n\n const type = toSolapiMessageType(options);\n const scheduledAt = options.options?.scheduledAt;\n const senderNumber =\n typeof options.from === \"string\" && options.from.length > 0\n ? options.from\n : config.defaultFrom;\n\n const base: Record<string, unknown> = {\n to: normalizePhoneNumber(options.to),\n type,\n };\n\n const country =\n typeof options.options?.country === \"string\" &&\n options.options.country.length > 0\n ? options.options.country\n : typeof config.defaultCountry === \"string\"\n ? config.defaultCountry\n : undefined;\n if (country) {\n base.country = country;\n }\n\n const customFieldsRaw = options.options?.customFields;\n if (customFieldsRaw && typeof customFieldsRaw === \"object\") {\n const customFields: Record<string, string> = {};\n for (const [key, value] of Object.entries(customFieldsRaw)) {\n if (value === undefined) continue;\n customFields[key] = typeof value === \"string\" ? value : String(value);\n }\n if (Object.keys(customFields).length > 0) {\n base.customFields = customFields;\n }\n }\n\n if (scheduledAt) {\n base.scheduledDate = scheduledAt;\n }\n\n const requiresFrom =\n type === \"SMS\" ||\n type === \"LMS\" ||\n type === \"MMS\" ||\n type === \"VOICE\" ||\n type === \"FAX\" ||\n String(type).startsWith(\"RCS_\");\n\n if (requiresFrom) {\n if (!senderNumber || senderNumber.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"from is required (options.from or config.defaultFrom)\",\n { providerId, type: options.type as MessageType },\n );\n }\n base.from = normalizePhoneNumber(senderNumber);\n } else if (senderNumber) {\n base.from = normalizePhoneNumber(senderNumber);\n }\n\n if (type === \"SMS\" || type === \"LMS\" || type === \"MMS\") {\n const smsOptions = options as Extract<\n SendOptions,\n { type: \"SMS\" | \"LMS\" | \"MMS\" }\n >;\n const text = smsOptions.text;\n if (text.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"text is required for SMS/LMS/MMS\",\n { providerId, type: options.type as MessageType },\n );\n }\n\n base.text = text;\n const subject = smsOptions.subject;\n if (subject) {\n base.subject = subject;\n }\n\n if (type === \"MMS\") {\n const imageRef = resolveImageRef({\n imageUrl: smsOptions.imageUrl,\n media: smsOptions.media,\n providerId,\n });\n if (!imageRef) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"image is required for MMS (options.imageUrl or options.media.image.ref)\",\n { providerId },\n );\n }\n\n const upload = await client.uploadFile(imageRef, \"MMS\");\n const fileId = extractFileId(upload);\n if (typeof fileId === \"string\" && fileId.length > 0) {\n base.imageId = fileId;\n } else {\n throw new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"Failed to upload MMS image\",\n {\n providerId,\n },\n );\n }\n }\n\n return base as unknown as SolapiSendOneMessage;\n }\n\n if (type === \"ATA\") {\n const alimtalkOptions = options as Extract<\n SendOptions,\n { type: \"ALIMTALK\" }\n >;\n const failover = alimtalkOptions.failover;\n const pfId =\n typeof alimtalkOptions.kakao?.profileId === \"string\" &&\n alimtalkOptions.kakao.profileId.length > 0\n ? alimtalkOptions.kakao.profileId\n : config.kakaoPfId;\n\n if (!pfId || pfId.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"kakao profileId is required (options.kakao.profileId or config.kakaoPfId)\",\n { providerId },\n );\n }\n\n const fallbackContent =\n typeof failover?.fallbackContent === \"string\" &&\n failover.fallbackContent.trim().length > 0\n ? failover.fallbackContent.trim()\n : undefined;\n const fallbackTitle =\n typeof failover?.fallbackTitle === \"string\" &&\n failover.fallbackTitle.trim().length > 0\n ? failover.fallbackTitle.trim()\n : undefined;\n const disableSms =\n failover?.enabled === true\n ? false\n : failover?.enabled === false\n ? true\n : alimtalkOptions.kakao?.disableSms;\n\n if (fallbackContent) {\n base.text = fallbackContent;\n }\n if (fallbackTitle) {\n base.subject = fallbackTitle;\n }\n\n base.kakaoOptions = {\n pfId,\n templateId: alimtalkOptions.templateId,\n variables: stringifyVariables(alimtalkOptions.variables),\n disableSms,\n adFlag: alimtalkOptions.kakao?.adFlag,\n buttons: Array.isArray(alimtalkOptions.kakao?.buttons)\n ? alimtalkOptions.kakao.buttons\n : undefined,\n imageId: alimtalkOptions.kakao?.imageId,\n };\n\n return base as unknown as SolapiSendOneMessage;\n }\n\n if (type === \"CTA\" || type === \"CTI\") {\n const friendTalkOptions = options as Extract<\n SendOptions,\n { type: \"FRIENDTALK\" }\n >;\n const text = friendTalkOptions.text;\n if (text.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"text is required for FRIENDTALK\",\n { providerId },\n );\n }\n\n const pfId =\n typeof friendTalkOptions.kakao?.profileId === \"string\" &&\n friendTalkOptions.kakao.profileId.length > 0\n ? friendTalkOptions.kakao.profileId\n : config.kakaoPfId;\n\n if (!pfId || pfId.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"kakao profileId is required (options.kakao.profileId or config.kakaoPfId)\",\n { providerId },\n );\n }\n\n const kakaoButtons = toKakaoButtons(friendTalkOptions.buttons);\n const buttons = Array.isArray(friendTalkOptions.kakao?.buttons)\n ? friendTalkOptions.kakao.buttons\n : kakaoButtons;\n\n const imageLinkFromOptions =\n typeof friendTalkOptions.kakao?.imageLink === \"string\" &&\n friendTalkOptions.kakao.imageLink.length > 0\n ? friendTalkOptions.kakao.imageLink\n : undefined;\n const firstButton =\n Array.isArray(buttons) && buttons.length > 0 ? buttons[0] : undefined;\n const imageLinkFromButton =\n isObjectRecord(firstButton) && typeof firstButton.linkMo === \"string\"\n ? (firstButton.linkMo as string)\n : undefined;\n const imageLink = imageLinkFromOptions ?? imageLinkFromButton;\n\n let imageId: string | undefined;\n if (type === \"CTI\") {\n const imageRef = resolveImageRef({\n imageUrl: friendTalkOptions.imageUrl,\n media: friendTalkOptions.media,\n providerId,\n });\n if (!imageRef) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"image is required for CTI (friendtalk image) (options.imageUrl or options.media.image.ref)\",\n { providerId },\n );\n }\n if (!imageLink) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"imageLink is required for friendtalk image upload (options.kakao.imageLink or WL button)\",\n { providerId },\n );\n }\n\n const upload = await client.uploadFile(\n imageRef,\n \"KAKAO\",\n undefined,\n imageLink,\n );\n const fileId = extractFileId(upload);\n if (typeof fileId === \"string\" && fileId.length > 0) {\n imageId = fileId;\n } else {\n throw new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"Failed to upload friendtalk image\",\n {\n providerId,\n },\n );\n }\n }\n\n base.text = text;\n base.kakaoOptions = {\n pfId,\n variables: stringifyVariables(friendTalkOptions.variables),\n disableSms: friendTalkOptions.kakao?.disableSms,\n adFlag: friendTalkOptions.kakao?.adFlag,\n buttons,\n imageId,\n };\n\n return base as unknown as SolapiSendOneMessage;\n }\n\n if (type === \"NSA\") {\n const nsaOptions = options as Extract<SendOptions, { type: \"NSA\" }>;\n const talkId =\n typeof nsaOptions.naver?.talkId === \"string\" &&\n nsaOptions.naver.talkId.length > 0\n ? nsaOptions.naver.talkId\n : config.naverTalkId;\n\n if (!talkId || talkId.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"naver talkId is required (options.naver.talkId or config.naverTalkId)\",\n { providerId },\n );\n }\n\n const templateId =\n typeof nsaOptions.naver?.templateId === \"string\" &&\n nsaOptions.naver.templateId.length > 0\n ? nsaOptions.naver.templateId\n : nsaOptions.templateId;\n\n const variables = {\n ...stringifyVariables(nsaOptions.variables),\n ...stringifyVariables(nsaOptions.naver?.variables),\n };\n\n base.naverOptions = {\n talkId,\n templateId,\n variables,\n disableSms: nsaOptions.naver?.disableSms,\n buttons: Array.isArray(nsaOptions.naver?.buttons)\n ? nsaOptions.naver.buttons\n : undefined,\n };\n\n return base as unknown as SolapiSendOneMessage;\n }\n\n if (type === \"VOICE\") {\n const voiceMessageOptions = options as Extract<\n SendOptions,\n { type: \"VOICE\" }\n >;\n const text = voiceMessageOptions.text;\n if (text.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"text is required for VOICE\",\n {\n providerId,\n },\n );\n }\n\n const voiceTypeRaw = voiceMessageOptions.voice?.voiceType;\n const voiceType =\n voiceTypeRaw === \"FEMALE\" || voiceTypeRaw === \"MALE\"\n ? voiceTypeRaw\n : \"FEMALE\";\n\n base.text = text;\n base.voiceOptions = voiceMessageOptions.voice\n ? { ...voiceMessageOptions.voice, voiceType }\n : { voiceType };\n\n return base as unknown as SolapiSendOneMessage;\n }\n\n if (type === \"FAX\") {\n const faxOptions = options as Extract<SendOptions, { type: \"FAX\" }>;\n const fax = faxOptions.fax;\n const fileIdsFromOptions = Array.isArray(fax?.fileIds)\n ? fax.fileIds.filter(\n (value: unknown): value is string =>\n typeof value === \"string\" && value.length > 0,\n )\n : [];\n\n let fileIds = fileIdsFromOptions;\n\n if (fileIds.length === 0) {\n const fileUrls = Array.isArray(fax?.fileUrls)\n ? fax.fileUrls.filter(\n (value: unknown): value is string =>\n typeof value === \"string\" && value.length > 0,\n )\n : [];\n\n if (fileUrls.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"fax.fileIds or fax.fileUrls is required\",\n {\n providerId,\n },\n );\n }\n\n fileIds = [];\n for (const url of fileUrls) {\n const upload = await client.uploadFile(url, \"FAX\");\n const fileId = extractFileId(upload);\n if (typeof fileId === \"string\" && fileId.length > 0) {\n fileIds.push(fileId);\n }\n }\n }\n\n if (fileIds.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"Failed to resolve fax fileIds\",\n {\n providerId,\n },\n );\n }\n\n base.faxOptions = { fileIds };\n return base as unknown as SolapiSendOneMessage;\n }\n\n const rcsOptions = options as Extract<\n SendOptions,\n {\n type:\n | \"RCS_SMS\"\n | \"RCS_LMS\"\n | \"RCS_MMS\"\n | \"RCS_TPL\"\n | \"RCS_ITPL\"\n | \"RCS_LTPL\";\n }\n >;\n const rcs = rcsOptions.rcs;\n\n const brandId =\n typeof rcs?.brandId === \"string\" && rcs.brandId.length > 0\n ? rcs.brandId\n : config.rcsBrandId;\n\n if (!brandId || brandId.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"rcs brandId is required (options.rcs.brandId or config.rcsBrandId)\",\n { providerId },\n );\n }\n\n const rcsPayload: Record<string, unknown> = {\n brandId,\n buttons: Array.isArray(rcs?.buttons) ? rcs.buttons : undefined,\n copyAllowed: rcs?.copyAllowed,\n mmsType: rcs?.mmsType,\n commercialType: rcs?.commercialType,\n disableSms: rcs?.disableSms,\n variables: {\n ...stringifyVariables(rcsOptions.variables),\n ...stringifyVariables(rcs?.variables),\n },\n };\n\n if (type === \"RCS_TPL\" || type === \"RCS_ITPL\" || type === \"RCS_LTPL\") {\n const templateOptions = options as Extract<\n SendOptions,\n { type: \"RCS_TPL\" | \"RCS_ITPL\" | \"RCS_LTPL\" }\n >;\n rcsPayload.templateId =\n typeof templateOptions.rcs?.templateId === \"string\" &&\n templateOptions.rcs.templateId.length > 0\n ? templateOptions.rcs.templateId\n : templateOptions.templateId;\n }\n\n let text: string | undefined;\n let subject: string | undefined;\n if (type === \"RCS_SMS\" || type === \"RCS_LMS\" || type === \"RCS_MMS\") {\n const textOptions = options as Extract<\n SendOptions,\n { type: \"RCS_SMS\" | \"RCS_LMS\" | \"RCS_MMS\" }\n >;\n text = textOptions.text;\n subject = textOptions.subject;\n\n if (!text || text.length === 0) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"text is required for RCS text types\",\n { providerId },\n );\n }\n base.text = text;\n if (subject) base.subject = subject;\n }\n\n const additionalBodyRaw = rcs?.additionalBody;\n const additionalBody = isObjectRecord(additionalBodyRaw)\n ? additionalBodyRaw\n : undefined;\n const additionalBodyImageId =\n additionalBody &&\n typeof additionalBody.imageId === \"string\" &&\n additionalBody.imageId.length > 0\n ? additionalBody.imageId\n : additionalBody &&\n typeof additionalBody.imaggeId === \"string\" &&\n additionalBody.imaggeId.length > 0\n ? additionalBody.imaggeId\n : undefined;\n\n const buildAdditionalBody = (uploadedImageId?: string) => {\n const record = additionalBody ? { ...additionalBody } : {};\n const title =\n typeof record.title === \"string\" && record.title.length > 0\n ? record.title\n : subject || \"RCS\";\n const description =\n typeof record.description === \"string\" && record.description.length > 0\n ? record.description\n : text || \"\";\n const imaggeId = additionalBodyImageId ?? uploadedImageId;\n\n const normalized: Record<string, unknown> = {\n ...record,\n title,\n description,\n };\n\n if (typeof imaggeId === \"string\" && imaggeId.length > 0) {\n normalized.imaggeId = imaggeId;\n }\n\n return normalized;\n };\n\n if (type === \"RCS_MMS\") {\n const rcsTextOptions = options as Extract<\n SendOptions,\n { type: \"RCS_SMS\" | \"RCS_LMS\" | \"RCS_MMS\" }\n >;\n\n const imageRef = resolveImageRef({\n imageUrl: rcsTextOptions.imageUrl,\n media: rcsTextOptions.media,\n providerId,\n });\n if (imageRef) {\n const upload = await client.uploadFile(imageRef, \"RCS\");\n const fileId = extractFileId(upload);\n if (typeof fileId === \"string\" && fileId.length > 0) {\n rcsPayload.additionalBody = buildAdditionalBody(fileId);\n } else if (additionalBody) {\n rcsPayload.additionalBody = buildAdditionalBody(undefined);\n }\n } else if (additionalBody) {\n rcsPayload.additionalBody = buildAdditionalBody(undefined);\n }\n } else if (additionalBody) {\n rcsPayload.additionalBody = buildAdditionalBody(undefined);\n }\n\n base.rcsOptions = rcsPayload;\n return base as unknown as SolapiSendOneMessage;\n}\n\nexport async function sendWithSolapi(params: {\n providerId: string;\n client: SolapiSdkClient;\n config: SolapiConfig;\n options: SendOptions;\n}): Promise<Result<SendResult, KMsgError>> {\n const { providerId, client, config, options } = params;\n\n const warnings = collectSolapiSendWarnings(options, providerId);\n const message = await buildSolapiSendOneMessage({\n options,\n providerId,\n config,\n client,\n });\n const response = await client.sendOne(message, config.appId);\n\n return ok(\n adaptSolapiSendResult({\n options,\n response,\n providerId,\n warnings,\n }),\n );\n}\n"
|
|
12
|
-
],
|
|
13
|
-
"mappings": "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",
|
|
14
|
-
"debugId": "22D7FD78E1A81A5164756E2164756E21",
|
|
15
|
-
"names": []
|
|
16
|
-
}
|