@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/index.js.map
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/aligo/provider.ts", "../src/onboarding/specs.ts", "../src/aligo/aligo.kakao.ts", "../src/shared/type-guards.ts", "../src/aligo/aligo.error.ts", "../src/aligo/aligo.helpers.ts", "../src/aligo/aligo.http.ts", "../src/aligo/aligo.send.ts", "../src/aligo/aligo.template.ts", "../src/config-fields.ts", "../src/iwinv/provider.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/provider-cli-metadata.ts", "../src/providers/mock/mock.provider.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import {\n type KakaoChannel,\n type KakaoChannelCategories,\n type KakaoChannelProvider,\n type KMsgError,\n type MessageType,\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 TemplateInspectionProvider,\n type TemplateProvider,\n type TemplateUpdateInput,\n} from \"@k-msg/core\";\nimport { getProviderOnboardingSpec } from \"../onboarding/specs\";\nimport type { AligoRuntimeContext } from \"./aligo.internal.types\";\nimport {\n addKakaoChannel,\n listKakaoChannelCategories,\n listKakaoChannels,\n requestKakaoChannelAuth,\n} from \"./aligo.kakao\";\nimport { sendWithAligo } from \"./aligo.send\";\nimport {\n createTemplate,\n deleteTemplate,\n getTemplate,\n listTemplates,\n requestTemplateInspection,\n updateTemplate,\n} from \"./aligo.template\";\nimport type { AligoConfig } from \"./types/aligo\";\n\nexport class AligoProvider\n implements\n Provider,\n TemplateProvider,\n TemplateInspectionProvider,\n KakaoChannelProvider\n{\n readonly id = \"aligo\";\n readonly name = \"Aligo Smart SMS\";\n readonly supportedTypes: readonly MessageType[] = [\n \"ALIMTALK\",\n \"FRIENDTALK\",\n \"SMS\",\n \"LMS\",\n \"MMS\",\n ];\n\n private readonly smsHost: string;\n private readonly alimtalkHost: string;\n\n getOnboardingSpec() {\n const spec = getProviderOnboardingSpec(this.id);\n if (!spec) {\n throw new Error(`Onboarding spec missing for provider: ${this.id}`);\n }\n return spec;\n }\n\n constructor(private readonly config: AligoConfig) {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"AligoProvider requires a config object\");\n }\n if (!config.apiKey || config.apiKey.length === 0) {\n throw new Error(\"AligoProvider requires `apiKey`\");\n }\n if (!config.userId || config.userId.length === 0) {\n throw new Error(\"AligoProvider requires `userId`\");\n }\n\n this.smsHost = config.smsBaseUrl || \"https://apis.aligo.in\";\n this.alimtalkHost = config.alimtalkBaseUrl || \"https://kakaoapi.aligo.in\";\n }\n\n private getRuntimeContext(): AligoRuntimeContext {\n return {\n providerId: this.id,\n config: this.config,\n smsHost: this.smsHost,\n alimtalkHost: this.alimtalkHost,\n };\n }\n\n async healthCheck(): Promise<ProviderHealthStatus> {\n const start = Date.now();\n const issues: string[] = [];\n\n try {\n if (!this.config.apiKey) issues.push(\"Missing apiKey\");\n if (!this.config.userId) issues.push(\"Missing userId\");\n if (!this.config.sender) {\n issues.push(\"Missing sender (default from)\");\n }\n\n try {\n new URL(this.smsHost);\n } catch {\n issues.push(\"Invalid smsBaseUrl\");\n }\n\n try {\n new URL(this.alimtalkHost);\n } catch {\n issues.push(\"Invalid alimtalkBaseUrl\");\n }\n\n return {\n healthy: issues.length === 0,\n issues,\n latencyMs: Date.now() - start,\n data: {\n provider: this.id,\n smsBaseUrl: this.smsHost,\n alimtalkBaseUrl: this.alimtalkHost,\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 return sendWithAligo(this.getRuntimeContext(), normalized);\n }\n\n async listKakaoChannels(params?: {\n plusId?: string;\n senderKey?: string;\n }): Promise<Result<KakaoChannel[], KMsgError>> {\n return listKakaoChannels(this.getRuntimeContext(), params);\n }\n\n async listKakaoChannelCategories(): Promise<\n Result<KakaoChannelCategories, KMsgError>\n > {\n return listKakaoChannelCategories(this.getRuntimeContext());\n }\n\n async requestKakaoChannelAuth(params: {\n plusId: string;\n phoneNumber: string;\n }): Promise<Result<void, KMsgError>> {\n return requestKakaoChannelAuth(this.getRuntimeContext(), params);\n }\n\n async addKakaoChannel(params: {\n plusId: string;\n authNum: string;\n phoneNumber: string;\n categoryCode: string;\n }): Promise<Result<KakaoChannel, KMsgError>> {\n return addKakaoChannel(this.getRuntimeContext(), params);\n }\n\n async createTemplate(\n input: TemplateCreateInput,\n ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n return createTemplate(this.getRuntimeContext(), input, ctx);\n }\n\n async updateTemplate(\n code: string,\n patch: TemplateUpdateInput,\n ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n return updateTemplate(this.getRuntimeContext(), code, patch, ctx);\n }\n\n async deleteTemplate(\n code: string,\n ctx?: TemplateContext,\n ): Promise<Result<void, KMsgError>> {\n return deleteTemplate(this.getRuntimeContext(), code, ctx);\n }\n\n async getTemplate(\n code: string,\n ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n return getTemplate(this.getRuntimeContext(), code, ctx);\n }\n\n async listTemplates(\n params?: { status?: string; page?: number; limit?: number },\n ctx?: TemplateContext,\n ): Promise<Result<Template[], KMsgError>> {\n return listTemplates(this.getRuntimeContext(), params, ctx);\n }\n\n async requestTemplateInspection(\n code: string,\n ctx?: TemplateContext,\n ): Promise<Result<void, KMsgError>> {\n return requestTemplateInspection(this.getRuntimeContext(), code, ctx);\n }\n}\n\nexport const createAligoProvider = (config: AligoConfig) =>\n new AligoProvider(config);\n\nexport const createDefaultAligoProvider = () => {\n const config: AligoConfig = {\n apiKey: readRuntimeEnv(\"ALIGO_API_KEY\") || \"\",\n userId: readRuntimeEnv(\"ALIGO_USER_ID\") || \"\",\n senderKey: readRuntimeEnv(\"ALIGO_SENDER_KEY\") || \"\",\n sender: readRuntimeEnv(\"ALIGO_SENDER\") || \"\",\n friendtalkEndpoint: readRuntimeEnv(\"ALIGO_FRIENDTALK_ENDPOINT\"),\n testMode: readRuntimeEnv(\"NODE_ENV\") !== \"production\",\n debug: readRuntimeEnv(\"NODE_ENV\") === \"development\",\n };\n\n if (!config.apiKey || !config.userId) {\n throw new Error(\"ALIGO_API_KEY and ALIGO_USER_ID are required\");\n }\n\n return new AligoProvider(config);\n};\n\n// biome-ignore lint/complexity/noStaticOnlyClass: kept as a factory for convenience\nexport class AligoProviderFactory {\n static create(config: AligoConfig): AligoProvider {\n return new AligoProvider(config);\n }\n\n static createDefault(): AligoProvider {\n return createDefaultAligoProvider();\n }\n}\n\nexport function initializeAligo(): 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 fail,\n type KakaoCategoryEntry,\n type KakaoChannel,\n type KakaoChannelCategories,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n} from \"@k-msg/core\";\nimport { isObjectRecord } from \"../shared/type-guards\";\nimport { mapAligoKakaoError } from \"./aligo.error\";\nimport { parseAligoDateTime } from \"./aligo.helpers\";\nimport { ensureAligoKakaoOk, requestAligo } from \"./aligo.http\";\nimport type { AligoRuntimeContext } from \"./aligo.internal.types\";\n\nexport async function listKakaoChannels(\n ctx: AligoRuntimeContext,\n params?: {\n plusId?: string;\n senderKey?: string;\n },\n): Promise<Result<KakaoChannel[], KMsgError>> {\n try {\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n ...(typeof params?.plusId === \"string\" && params.plusId.trim().length > 0\n ? { plusid: params.plusId.trim() }\n : {}),\n ...(typeof params?.senderKey === \"string\" &&\n params.senderKey.trim().length > 0\n ? { senderkey: params.senderKey.trim() }\n : {}),\n };\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/profile/list/\",\n data: body,\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"channel list failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const listRaw = response.list;\n const list = Array.isArray(listRaw) ? listRaw : [];\n const channels: KakaoChannel[] = list\n .filter(isObjectRecord)\n .map((item) => ({\n providerId: ctx.providerId,\n senderKey: String(item.senderKey ?? \"\"),\n plusId: typeof item.uuid === \"string\" ? item.uuid : undefined,\n name: typeof item.name === \"string\" ? item.name : undefined,\n status: typeof item.status === \"string\" ? item.status : undefined,\n createdAt: parseAligoDateTime(item.cdate),\n updatedAt: parseAligoDateTime(item.udate),\n raw: item,\n }))\n .filter((channel) => channel.senderKey.length > 0);\n\n return ok(channels);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function listKakaoChannelCategories(\n ctx: AligoRuntimeContext,\n): Promise<Result<KakaoChannelCategories, KMsgError>> {\n try {\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/category/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"category list failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const data = isObjectRecord(response.data) ? response.data : {};\n\n const mapEntries = (raw: unknown): KakaoCategoryEntry[] => {\n const arr = Array.isArray(raw) ? raw : [];\n return arr\n .filter(isObjectRecord)\n .map((entry) => ({\n code: String(entry.code ?? \"\"),\n name: String(entry.name ?? \"\"),\n parentCode:\n typeof entry.parentCode === \"string\" && entry.parentCode.length > 0\n ? entry.parentCode\n : undefined,\n }))\n .filter((entry) => entry.code.length > 0);\n };\n\n return ok({\n first: mapEntries(data.firstBusinessType),\n second: mapEntries(data.secondBusinessType),\n third: mapEntries(data.thirdBusinessType),\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function requestKakaoChannelAuth(\n ctx: AligoRuntimeContext,\n params: {\n plusId: string;\n phoneNumber: string;\n },\n): Promise<Result<void, KMsgError>> {\n try {\n const plusId = params.plusId.trim();\n const phoneNumber = params.phoneNumber.trim();\n if (!plusId || !phoneNumber) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"plusId and phoneNumber are required\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/profile/auth/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n plusid: plusId,\n phonenumber: phoneNumber,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"channel auth failed\",\n });\n if (okResult.isFailure) return okResult;\n\n return ok(undefined);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function addKakaoChannel(\n ctx: AligoRuntimeContext,\n params: {\n plusId: string;\n authNum: string;\n phoneNumber: string;\n categoryCode: string;\n },\n): Promise<Result<KakaoChannel, KMsgError>> {\n try {\n const plusId = params.plusId.trim();\n const authNum = params.authNum.trim();\n const phoneNumber = params.phoneNumber.trim();\n const categoryCode = params.categoryCode.trim();\n\n if (!plusId || !authNum || !phoneNumber || !categoryCode) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"plusId, authNum, phoneNumber, categoryCode are required\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/profile/add/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n plusid: plusId,\n authnum: authNum,\n phonenumber: phoneNumber,\n categorycode: categoryCode,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"channel add failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const dataRaw = response.data;\n const data = Array.isArray(dataRaw)\n ? dataRaw.find(isObjectRecord)\n : isObjectRecord(dataRaw)\n ? dataRaw\n : undefined;\n\n if (!data) {\n return fail(\n new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"channel add returned empty data\",\n {\n providerId: ctx.providerId,\n raw: response,\n },\n ),\n );\n }\n\n const senderKey = String(data.senderKey ?? \"\");\n if (!senderKey) {\n return fail(\n new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"channel add did not return senderKey\",\n { providerId: ctx.providerId, raw: data },\n ),\n );\n }\n\n return ok({\n providerId: ctx.providerId,\n senderKey,\n plusId: typeof data.uuid === \"string\" ? data.uuid : plusId,\n name: typeof data.name === \"string\" ? data.name : undefined,\n status: typeof data.status === \"string\" ? data.status : undefined,\n createdAt: parseAligoDateTime(data.cdate),\n updatedAt: parseAligoDateTime(data.udate),\n raw: data,\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.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 { isObjectRecord } from \"../shared/type-guards\";\n\nexport function mapAligoKakaoError(\n error: unknown,\n providerId: string,\n): KMsgError {\n if (error instanceof KMsgError) return error;\n return new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n error instanceof Error ? error.message : String(error),\n { providerId },\n );\n}\n\nexport function mapAligoError(error: unknown, providerId: string): KMsgError {\n if (error instanceof KMsgError) return error;\n\n const record = isObjectRecord(error) ? error : {};\n const resultCodeRaw = record.result_code;\n const resultCode =\n resultCodeRaw !== undefined && resultCodeRaw !== null\n ? String(resultCodeRaw)\n : \"UNKNOWN\";\n\n const message =\n typeof record.message === \"string\" && record.message.length > 0\n ? record.message\n : typeof record.msg === \"string\" && record.msg.length > 0\n ? record.msg\n : error instanceof Error\n ? error.message\n : \"Unknown Aligo error\";\n\n let code: KMsgErrorCode = KMsgErrorCode.PROVIDER_ERROR;\n\n switch (resultCode) {\n case \"-100\":\n case \"-101\":\n code = KMsgErrorCode.AUTHENTICATION_FAILED;\n break;\n case \"-102\":\n case \"-201\":\n code = KMsgErrorCode.INSUFFICIENT_BALANCE;\n break;\n case \"-103\":\n case \"-105\":\n code = KMsgErrorCode.INVALID_REQUEST;\n break;\n case \"-501\":\n code = KMsgErrorCode.TEMPLATE_NOT_FOUND;\n break;\n default:\n code = KMsgErrorCode.PROVIDER_ERROR;\n }\n\n return new KMsgError(code, `${message} (code: ${resultCode})`, {\n providerId,\n resultCode,\n });\n}\n",
|
|
10
|
-
"import {\n KMsgError,\n KMsgErrorCode,\n type MessageBinaryInput,\n type Template,\n type TemplateContext,\n} from \"@k-msg/core\";\nimport {\n ButtonParser,\n interpolate,\n type TemplateButton,\n} from \"@k-msg/template\";\nimport type { AligoConfig } from \"./types/aligo\";\n\nexport function resolveImageRef(options: {\n imageUrl?: string;\n media?: { image?: MessageBinaryInput };\n providerId: string;\n}): string | undefined {\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 \"Aligo MMS/FriendTalk image requires `options.imageUrl` or `options.media.image.ref` (url/path).\",\n { providerId: options.providerId },\n );\n}\n\nexport function getAligoEndpoint(\n operation: \"sendSMS\" | \"sendAlimTalk\" | \"sendFriendTalk\",\n config: AligoConfig,\n): string {\n switch (operation) {\n case \"sendSMS\":\n return \"/send/\";\n case \"sendAlimTalk\":\n return \"/akv10/alimtalk/send/\";\n case \"sendFriendTalk\":\n return config.friendtalkEndpoint || \"/akv10/friendtalk/send/\";\n default:\n return \"/\";\n }\n}\n\nexport function formatAligoDate(date: Date): { date: string; time: string } {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n\n return {\n date: `${year}${month}${day}`,\n time: `${hours}${minutes}`,\n };\n}\n\nexport function normalizeAligoKakaoCode(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n const num = Number(trimmed);\n if (Number.isFinite(num)) return num;\n }\n return undefined;\n}\n\nexport function resolveKakaoSenderKey(\n params: {\n providerId: string;\n config: AligoConfig;\n },\n ctx?: TemplateContext,\n): string {\n const senderKey =\n (typeof ctx?.kakaoChannelSenderKey === \"string\" &&\n ctx.kakaoChannelSenderKey.trim().length > 0\n ? ctx.kakaoChannelSenderKey.trim()\n : params.config.senderKey) || \"\";\n if (!senderKey) {\n throw new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"kakao channel senderKey is required (ctx.kakaoChannelSenderKey or config.senderKey)\",\n { providerId: params.providerId },\n );\n }\n return senderKey;\n}\n\nexport function toAligoTplButton(\n buttons: TemplateButton[] | undefined,\n): string | undefined {\n if (!Array.isArray(buttons) || buttons.length === 0) return undefined;\n\n const serializedButtons = JSON.parse(\n ButtonParser.serializeButtons(buttons),\n ) as unknown[];\n return JSON.stringify({ button: serializedButtons });\n}\n\nexport function mapAligoTemplateStatus(\n item: Record<string, unknown>,\n): Template[\"status\"] {\n const insp =\n typeof item.inspStatus === \"string\"\n ? item.inspStatus.trim().toUpperCase()\n : \"\";\n switch (insp) {\n case \"APR\":\n return \"APPROVED\";\n case \"REJ\":\n return \"REJECTED\";\n case \"REQ\":\n case \"REG\":\n return \"INSPECTION\";\n default:\n return \"PENDING\";\n }\n}\n\nexport function parseAligoDateTime(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 const date = new Date(year, month - 1, day, hour, minute, second);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\nexport function resolveAligoTemplateMessage(\n variables: Record<string, unknown> | undefined,\n templateContent?: string,\n): string {\n if (!variables) return \"\";\n const fullText = variables._full_text;\n if (fullText !== undefined && fullText !== null) return String(fullText);\n if (!templateContent) return Object.values(variables).map(String).join(\"\\n\");\n\n return interpolate(templateContent, variables);\n}\n",
|
|
11
|
-
"import { fail, KMsgError, KMsgErrorCode, ok, type Result } from \"@k-msg/core\";\nimport { normalizeAligoKakaoCode } from \"./aligo.helpers\";\n\nexport async function requestAligo(params: {\n host: string;\n endpoint: string;\n data: Record<string, unknown>;\n providerId: string;\n}): Promise<Record<string, unknown>> {\n const formData = new FormData();\n for (const [key, value] of Object.entries(params.data)) {\n if (value !== undefined && value !== null) {\n formData.append(key, String(value));\n }\n }\n\n const response = await fetch(`${params.host}${params.endpoint}`, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n throw new KMsgError(\n KMsgErrorCode.NETWORK_ERROR,\n `HTTP error! status: ${response.status}`,\n { providerId: params.providerId },\n );\n }\n\n return (await response.json()) as Record<string, unknown>;\n}\n\nexport function ensureAligoKakaoOk(params: {\n providerId: string;\n response: Record<string, unknown>;\n fallbackMessage: string;\n}): Result<void, KMsgError> {\n const { providerId, response, fallbackMessage } = params;\n const rawCode = response.code;\n const code = normalizeAligoKakaoCode(rawCode);\n if (code === 0) return ok(undefined);\n\n const message =\n typeof response.message === \"string\" && response.message.length > 0\n ? response.message\n : fallbackMessage;\n const mapped =\n code === 509 || code === -99\n ? KMsgErrorCode.INVALID_REQUEST\n : KMsgErrorCode.PROVIDER_ERROR;\n return fail(\n new KMsgError(mapped, message, {\n providerId,\n originalCode: rawCode,\n raw: response,\n }),\n );\n}\n",
|
|
12
|
-
"import {\n fail,\n KMsgError,\n KMsgErrorCode,\n ok,\n type Result,\n type SendOptions,\n type SendResult,\n} from \"@k-msg/core\";\nimport { mapAligoError } from \"./aligo.error\";\nimport {\n formatAligoDate,\n getAligoEndpoint,\n resolveAligoTemplateMessage,\n resolveImageRef,\n} from \"./aligo.helpers\";\nimport { requestAligo } from \"./aligo.http\";\nimport type {\n AligoMessageType,\n AligoRuntimeContext,\n} from \"./aligo.internal.types\";\nimport type { AligoResponse, AligoSMSRequest } from \"./types/aligo\";\n\nexport function collectSendWarnings(\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 \"Aligo failover mapping is partial. API-level fallback may be attempted for non-Kakao-user failures.\",\n details: {\n providerId,\n mappedFields: [\"failover\", \"fmessage_1\", \"fsubject_1\"],\n unsupportedFields: [\"fallbackChannel\"],\n },\n },\n ];\n}\n\nasync function sendSMS(\n ctx: AligoRuntimeContext,\n options: Extract<SendOptions, { type: \"SMS\" | \"LMS\" | \"MMS\" }>,\n): Promise<Result<SendResult, KMsgError>> {\n const sender = options.from || ctx.config.sender || \"\";\n if (!sender) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"from is required for SMS/LMS/MMS (options.from or config.sender)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const body: AligoSMSRequest = {\n key: ctx.config.apiKey,\n user_id: ctx.config.userId,\n sender,\n receiver: options.to,\n msg: options.text,\n msg_type: options.type,\n title: options.subject,\n testmode_yn: ctx.config.testMode ? \"Y\" : \"N\",\n };\n\n const scheduledAt = options.options?.scheduledAt;\n if (scheduledAt instanceof Date && !Number.isNaN(scheduledAt.getTime())) {\n const { date, time } = formatAligoDate(scheduledAt);\n body.rdate = date;\n body.rtime = time;\n }\n\n if (options.type === \"MMS\") {\n const imageRef = resolveImageRef({\n imageUrl: options.imageUrl,\n media: options.media,\n providerId: ctx.providerId,\n });\n if (!imageRef) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"image is required for MMS (options.imageUrl or options.media.image.ref)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n body.image = imageRef;\n }\n\n const response = (await requestAligo({\n host: ctx.smsHost,\n endpoint: getAligoEndpoint(\"sendSMS\", ctx.config),\n data: body as unknown as Record<string, unknown>,\n providerId: ctx.providerId,\n })) as unknown as AligoResponse;\n\n if (response.result_code !== \"1\") {\n return fail(mapAligoError(response, ctx.providerId));\n }\n\n return ok({\n messageId: options.messageId || crypto.randomUUID(),\n providerId: ctx.providerId,\n providerMessageId: response.msg_id,\n status: \"PENDING\",\n type: options.type,\n to: options.to,\n raw: response,\n });\n}\n\nasync function sendAlimTalk(\n ctx: AligoRuntimeContext,\n options: Extract<SendOptions, { type: \"ALIMTALK\" }>,\n): Promise<Result<SendResult, KMsgError>> {\n const warnings = collectSendWarnings(options, ctx.providerId);\n const senderKey =\n (typeof options.kakao?.profileId === \"string\"\n ? options.kakao.profileId\n : ctx.config.senderKey) || \"\";\n if (!senderKey) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"kakao profileId is required (options.kakao.profileId or config.senderKey)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const sender = options.from || ctx.config.sender || \"\";\n if (!sender) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"from is required for ALIMTALK (options.from or config.sender)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const variables = options.variables as Record<string, unknown>;\n const templateId = options.templateId;\n if (!templateId || templateId.length === 0) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"templateId is required for ALIMTALK\",\n { providerId: ctx.providerId },\n ),\n );\n }\n const templateContent =\n typeof options.providerOptions?.templateContent === \"string\"\n ? options.providerOptions.templateContent\n : undefined;\n\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateId,\n sender,\n receiver_1: options.to,\n subject_1: \"알림톡\",\n message_1: resolveAligoTemplateMessage(variables, templateContent),\n testMode: ctx.config.testMode ? \"Y\" : \"N\",\n };\n\n const failoverOverrideRaw =\n typeof options.providerOptions?.failover === \"string\"\n ? options.providerOptions.failover.trim().toUpperCase()\n : \"\";\n const failoverOverride =\n failoverOverrideRaw === \"Y\" || failoverOverrideRaw === \"N\"\n ? failoverOverrideRaw\n : undefined;\n const failoverFromOptions =\n options.failover?.enabled === true\n ? \"Y\"\n : options.failover?.enabled === false\n ? \"N\"\n : undefined;\n const failover = failoverOverride ?? failoverFromOptions;\n\n const fallbackTitle =\n typeof options.providerOptions?.fsubject_1 === \"string\" &&\n options.providerOptions.fsubject_1.trim().length > 0\n ? options.providerOptions.fsubject_1.trim()\n : typeof options.failover?.fallbackTitle === \"string\" &&\n options.failover.fallbackTitle.trim().length > 0\n ? options.failover.fallbackTitle.trim()\n : undefined;\n const fallbackContent =\n typeof options.providerOptions?.fmessage_1 === \"string\" &&\n options.providerOptions.fmessage_1.trim().length > 0\n ? options.providerOptions.fmessage_1.trim()\n : typeof options.failover?.fallbackContent === \"string\" &&\n options.failover.fallbackContent.trim().length > 0\n ? options.failover.fallbackContent.trim()\n : undefined;\n\n if (failover) {\n body.failover = failover;\n }\n if (fallbackTitle) {\n body.fsubject_1 = fallbackTitle;\n }\n if (fallbackContent) {\n body.fmessage_1 = fallbackContent;\n }\n\n const scheduledAt = options.options?.scheduledAt;\n if (scheduledAt instanceof Date && !Number.isNaN(scheduledAt.getTime())) {\n const { date, time } = formatAligoDate(scheduledAt);\n body.reserve = \"Y\";\n body.reserve_date = date;\n body.reserve_time = time;\n }\n\n const response = (await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: getAligoEndpoint(\"sendAlimTalk\", ctx.config),\n data: body,\n providerId: ctx.providerId,\n })) as unknown as AligoResponse;\n\n if (response.result_code !== \"0\") {\n return fail(mapAligoError(response, ctx.providerId));\n }\n\n return ok({\n messageId: options.messageId || crypto.randomUUID(),\n providerId: ctx.providerId,\n providerMessageId: response.msg_id,\n status: \"PENDING\",\n type: options.type,\n to: options.to,\n ...(Array.isArray(warnings) && warnings.length > 0 ? { warnings } : {}),\n raw: response,\n });\n}\n\nasync function sendFriendTalk(\n ctx: AligoRuntimeContext,\n options: Extract<SendOptions, { type: \"FRIENDTALK\" }>,\n): Promise<Result<SendResult, KMsgError>> {\n const senderKey =\n (typeof options.kakao?.profileId === \"string\"\n ? options.kakao.profileId\n : ctx.config.senderKey) || \"\";\n if (!senderKey) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"kakao profileId is required (options.kakao.profileId or config.senderKey)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const sender = options.from || ctx.config.sender || \"\";\n if (!sender) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"from is required for FRIENDTALK (options.from or config.sender)\",\n { providerId: ctx.providerId },\n ),\n );\n }\n\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n sender,\n receiver_1: options.to,\n subject_1: \"친구톡\",\n message_1: options.text,\n testMode: ctx.config.testMode ? \"Y\" : \"N\",\n };\n\n const imageRef = resolveImageRef({\n imageUrl: options.imageUrl,\n media: options.media,\n providerId: ctx.providerId,\n });\n if (imageRef) {\n body.image_1 = imageRef;\n }\n\n const buttons = Array.isArray(options.kakao?.buttons)\n ? options.kakao.buttons\n : options.buttons;\n if (buttons) {\n body.button_1 = JSON.stringify(buttons);\n }\n\n const scheduledAt = options.options?.scheduledAt;\n if (scheduledAt instanceof Date && !Number.isNaN(scheduledAt.getTime())) {\n const { date, time } = formatAligoDate(scheduledAt);\n body.reserve = \"Y\";\n body.reserve_date = date;\n body.reserve_time = time;\n }\n\n const response = (await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: getAligoEndpoint(\"sendFriendTalk\", ctx.config),\n data: body,\n providerId: ctx.providerId,\n })) as unknown as AligoResponse;\n\n if (response.result_code !== \"0\") {\n return fail(mapAligoError(response, ctx.providerId));\n }\n\n return ok({\n messageId: options.messageId || crypto.randomUUID(),\n providerId: ctx.providerId,\n providerMessageId: response.msg_id,\n status: \"PENDING\",\n type: options.type,\n to: options.to,\n raw: response,\n });\n}\n\nexport async function sendWithAligo(\n ctx: AligoRuntimeContext,\n options: SendOptions,\n): Promise<Result<SendResult, KMsgError>> {\n try {\n switch (options.type as AligoMessageType) {\n case \"ALIMTALK\":\n return await sendAlimTalk(\n ctx,\n options as Extract<SendOptions, { type: \"ALIMTALK\" }>,\n );\n case \"FRIENDTALK\":\n return await sendFriendTalk(\n ctx,\n options as Extract<SendOptions, { type: \"FRIENDTALK\" }>,\n );\n case \"SMS\":\n case \"LMS\":\n case \"MMS\":\n return await sendSMS(\n ctx,\n options as Extract<SendOptions, { type: \"SMS\" | \"LMS\" | \"MMS\" }>,\n );\n default:\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n `AligoProvider does not support type ${options.type}`,\n { providerId: ctx.providerId, type: options.type },\n ),\n );\n }\n } catch (error) {\n return fail(mapAligoError(error, ctx.providerId));\n }\n}\n",
|
|
13
|
-
"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 { isObjectRecord } from \"../shared/type-guards\";\nimport { mapAligoKakaoError } from \"./aligo.error\";\nimport {\n mapAligoTemplateStatus,\n parseAligoDateTime,\n resolveKakaoSenderKey,\n toAligoTplButton,\n} from \"./aligo.helpers\";\nimport { ensureAligoKakaoOk, requestAligo } from \"./aligo.http\";\nimport type { AligoRuntimeContext } from \"./aligo.internal.types\";\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(\n ctx: AligoRuntimeContext,\n input: TemplateCreateInput,\n templateCtx?: TemplateContext,\n): Promise<Result<Template, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const payloadValidation = validateTemplatePayload(input, {\n requireName: true,\n requireContent: true,\n });\n if (payloadValidation.isFailure) {\n return fail(withProviderContext(payloadValidation.error, ctx.providerId));\n }\n\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_name: payloadValidation.value.name ?? input.name,\n tpl_content: payloadValidation.value.content ?? input.content,\n };\n\n const tplButton = toAligoTplButton(payloadValidation.value.buttons);\n if (tplButton) body.tpl_button = tplButton;\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/add/\",\n data: body,\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template create failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const data = isObjectRecord(response.data) ? response.data : {};\n const code = String(data.templtCode ?? \"\");\n if (!code) {\n return fail(\n new KMsgError(\n KMsgErrorCode.PROVIDER_ERROR,\n \"template create did not return templtCode\",\n { providerId: ctx.providerId, raw: response },\n ),\n );\n }\n\n const createdAt = parseAligoDateTime(data.cdate) ?? new Date();\n const updatedAt =\n parseAligoDateTime(data.udate) ??\n parseAligoDateTime(data.cdate) ??\n createdAt;\n\n return ok({\n id: code,\n code,\n name: String(\n data.templtName ?? payloadValidation.value.name ?? input.name,\n ),\n content: String(\n data.templtContent ?? payloadValidation.value.content ?? input.content,\n ),\n category: input.category,\n status: mapAligoTemplateStatus(data),\n buttons: Array.isArray(data.buttons)\n ? data.buttons\n : payloadValidation.value.buttons,\n variables: input.variables,\n createdAt,\n updatedAt,\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function getTemplate(\n ctx: AligoRuntimeContext,\n code: string,\n templateCtx?: TemplateContext,\n): Promise<Result<Template, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const templateCode = code.trim();\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId: ctx.providerId,\n }),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/list/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateCode,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template get failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const listRaw = response.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: ctx.providerId,\n templateCode,\n }),\n );\n }\n\n const tplCode = String(first.templtCode ?? templateCode);\n const createdAt = parseAligoDateTime(first.cdate) ?? new Date();\n const updatedAt =\n parseAligoDateTime(first.udate) ??\n parseAligoDateTime(first.cdate) ??\n createdAt;\n\n return ok({\n id: tplCode,\n code: tplCode,\n name: String(first.templtName ?? \"\"),\n content: String(first.templtContent ?? \"\"),\n status: mapAligoTemplateStatus(first),\n buttons: Array.isArray(first.buttons) ? first.buttons : undefined,\n createdAt,\n updatedAt,\n });\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function updateTemplate(\n ctx: AligoRuntimeContext,\n code: string,\n patch: TemplateUpdateInput,\n templateCtx?: TemplateContext,\n): Promise<Result<Template, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const templateCode = code.trim();\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId: ctx.providerId,\n }),\n );\n }\n\n const existingResult = await getTemplate(ctx, templateCode, {\n kakaoChannelSenderKey: senderKey,\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 payloadValidation = validateTemplatePayload(\n {\n name: nextName,\n content: nextContent,\n buttons: patch.buttons !== undefined ? patch.buttons : existing.buttons,\n },\n {\n requireName: true,\n requireContent: true,\n },\n );\n if (payloadValidation.isFailure) {\n return fail(withProviderContext(payloadValidation.error, ctx.providerId));\n }\n\n const body: Record<string, unknown> = {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateCode,\n tpl_name: payloadValidation.value.name ?? nextName,\n tpl_content: payloadValidation.value.content ?? nextContent,\n };\n\n const tplButton = toAligoTplButton(payloadValidation.value.buttons);\n if (tplButton) body.tpl_button = tplButton;\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/modify/\",\n data: body,\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template update failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const refreshed = await getTemplate(ctx, templateCode, {\n kakaoChannelSenderKey: senderKey,\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(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function deleteTemplate(\n ctx: AligoRuntimeContext,\n code: string,\n templateCtx?: TemplateContext,\n): Promise<Result<void, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const templateCode = code.trim();\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId: ctx.providerId,\n }),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/del/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateCode,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template delete failed\",\n });\n if (okResult.isFailure) return okResult;\n\n return ok(undefined);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function listTemplates(\n ctx: AligoRuntimeContext,\n params?: { status?: string; page?: number; limit?: number },\n templateCtx?: TemplateContext,\n): Promise<Result<Template[], KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/list/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template list failed\",\n });\n if (okResult.isFailure) return okResult;\n\n const listRaw = response.list;\n const list = Array.isArray(listRaw) ? listRaw : [];\n const templates = list\n .filter(isObjectRecord)\n .map((item) => {\n const tplCode = String(item.templtCode ?? \"\");\n const createdAt = parseAligoDateTime(item.cdate) ?? new Date();\n const updatedAt =\n parseAligoDateTime(item.udate) ??\n parseAligoDateTime(item.cdate) ??\n createdAt;\n\n return {\n id: tplCode,\n code: tplCode,\n name: String(item.templtName ?? \"\"),\n content: String(item.templtContent ?? \"\"),\n status: mapAligoTemplateStatus(item),\n buttons: Array.isArray(item.buttons) ? item.buttons : undefined,\n createdAt,\n updatedAt,\n } satisfies Template;\n })\n .filter((template) => template.code.length > 0);\n\n if (params?.status) {\n const status = params.status.trim().toUpperCase();\n return ok(templates.filter((template) => template.status === status));\n }\n\n return ok(templates);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n\nexport async function requestTemplateInspection(\n ctx: AligoRuntimeContext,\n code: string,\n templateCtx?: TemplateContext,\n): Promise<Result<void, KMsgError>> {\n try {\n const senderKey = resolveKakaoSenderKey(ctx, templateCtx);\n const templateCode = code.trim();\n\n if (!templateCode) {\n return fail(\n new KMsgError(KMsgErrorCode.INVALID_REQUEST, \"code is required\", {\n providerId: ctx.providerId,\n }),\n );\n }\n\n const response = await requestAligo({\n host: ctx.alimtalkHost,\n endpoint: \"/akv10/template/request/\",\n data: {\n apikey: ctx.config.apiKey,\n userid: ctx.config.userId,\n senderkey: senderKey,\n tpl_code: templateCode,\n },\n providerId: ctx.providerId,\n });\n\n const okResult = ensureAligoKakaoOk({\n providerId: ctx.providerId,\n response,\n fallbackMessage: \"template inspection request failed\",\n });\n if (okResult.isFailure) return okResult;\n\n return ok(undefined);\n } catch (error) {\n return fail(mapAligoKakaoError(error, ctx.providerId));\n }\n}\n",
|
|
14
|
-
"export type ProviderConfigFieldType =\n | \"string\"\n | \"number\"\n | \"boolean\"\n | \"stringRecord\";\n\nexport interface ProviderConfigFieldSpec {\n type: ProviderConfigFieldType;\n required?: boolean;\n description?: string;\n defaultValue?: string;\n}\n\nexport type ProviderConfigFieldMap = Record<string, ProviderConfigFieldSpec>;\n\nexport const providerConfigFieldSpecs = {\n mock: {},\n aligo: {\n apiKey: {\n type: \"string\",\n required: true,\n description: \"Aligo API key\",\n defaultValue: \"env:ALIGO_API_KEY\",\n },\n userId: {\n type: \"string\",\n required: true,\n description: \"Aligo user id\",\n defaultValue: \"env:ALIGO_USER_ID\",\n },\n senderKey: {\n type: \"string\",\n description: \"Default Kakao sender key\",\n defaultValue: \"env:ALIGO_SENDER_KEY\",\n },\n sender: {\n type: \"string\",\n description: \"Default SMS/LMS sender number\",\n defaultValue: \"env:ALIGO_SENDER\",\n },\n testMode: {\n type: \"boolean\",\n description: \"Enable Aligo test mode\",\n },\n debug: {\n type: \"boolean\",\n description: \"Enable debug logging\",\n },\n smsBaseUrl: {\n type: \"string\",\n description: \"Override SMS API base URL\",\n },\n alimtalkBaseUrl: {\n type: \"string\",\n description: \"Override AlimTalk API base URL\",\n },\n friendtalkEndpoint: {\n type: \"string\",\n description: \"Override FriendTalk endpoint path\",\n },\n },\n iwinv: {\n apiKey: {\n type: \"string\",\n required: true,\n description: \"IWINV AlimTalk API key (AUTH header)\",\n defaultValue: \"env:IWINV_API_KEY\",\n },\n smsApiKey: {\n type: \"string\",\n description: \"IWINV SMS API key\",\n defaultValue: \"env:IWINV_SMS_API_KEY\",\n },\n smsAuthKey: {\n type: \"string\",\n description: \"IWINV SMS auth key\",\n defaultValue: \"env:IWINV_SMS_AUTH_KEY\",\n },\n smsCompanyId: {\n type: \"string\",\n description: \"IWINV SMS company id\",\n defaultValue: \"env:IWINV_SMS_COMPANY_ID\",\n },\n senderNumber: {\n type: \"string\",\n description: \"Default sender number\",\n defaultValue: \"env:IWINV_SENDER_NUMBER\",\n },\n smsSenderNumber: {\n type: \"string\",\n description: \"SMS/LMS sender number override\",\n },\n sendEndpoint: {\n type: \"string\",\n description: \"Override IWINV send endpoint path\",\n },\n xForwardedFor: {\n type: \"string\",\n description: \"X-Forwarded-For header override\",\n },\n extraHeaders: {\n type: \"stringRecord\",\n description: \"Additional HTTP headers\",\n },\n ipRetryCount: {\n type: \"number\",\n description: \"IP-restriction retry count\",\n },\n ipRetryDelayMs: {\n type: \"number\",\n description: \"IP-restriction retry delay in ms\",\n },\n ipAlertWebhookUrl: {\n type: \"string\",\n description: \"Webhook URL for IP restriction alerts\",\n },\n debug: {\n type: \"boolean\",\n description: \"Enable debug logging\",\n },\n },\n solapi: {\n apiKey: {\n type: \"string\",\n required: true,\n description: \"SOLAPI API key\",\n defaultValue: \"env:SOLAPI_API_KEY\",\n },\n apiSecret: {\n type: \"string\",\n required: true,\n description: \"SOLAPI API secret\",\n defaultValue: \"env:SOLAPI_API_SECRET\",\n },\n defaultFrom: {\n type: \"string\",\n description: \"Default sender number\",\n defaultValue: \"env:SOLAPI_DEFAULT_FROM\",\n },\n kakaoPfId: {\n type: \"string\",\n description: \"Default Kakao PF ID\",\n defaultValue: \"env:SOLAPI_KAKAO_PF_ID\",\n },\n rcsBrandId: {\n type: \"string\",\n description: \"Default RCS brand id\",\n },\n naverTalkId: {\n type: \"string\",\n description: \"Default Naver Talk id\",\n },\n appId: {\n type: \"string\",\n description: \"SOLAPI app id\",\n },\n defaultCountry: {\n type: \"string\",\n description: \"Default country code\",\n },\n baseUrl: {\n type: \"string\",\n description: \"Override SOLAPI API base URL\",\n },\n debug: {\n type: \"boolean\",\n description: \"Enable debug logging\",\n },\n },\n} as const satisfies Record<string, ProviderConfigFieldMap>;\n\nexport type ProviderTypeWithConfig = keyof typeof providerConfigFieldSpecs;\n",
|
|
15
|
-
"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",
|
|
16
|
-
"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",
|
|
17
|
-
"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",
|
|
18
|
-
"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",
|
|
19
|
-
"export const IWINV_ALIMTALK_BASE_URL = \"https://alimtalk.bizservice.iwinv.kr\";\nexport const IWINV_SMS_BASE_URL = \"https://sms.bizservice.iwinv.kr\";\n",
|
|
20
|
-
"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",
|
|
21
|
-
"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",
|
|
22
|
-
"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",
|
|
23
|
-
"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",
|
|
24
|
-
"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",
|
|
25
|
-
"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",
|
|
26
|
-
"import type { MessageType } from \"@k-msg/core\";\nimport type { ProviderTypeWithConfig } from \"./config-fields\";\n\nexport interface ProviderCliMetadata {\n label: string;\n routingSeedTypes: readonly MessageType[];\n defaultKakaoSenderKey?: string;\n}\n\nexport const providerCliMetadata: Record<\n ProviderTypeWithConfig,\n ProviderCliMetadata\n> = {\n mock: {\n label: \"Mock (local test)\",\n routingSeedTypes: [\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 defaultKakaoSenderKey: \"env:MOCK_SENDER_KEY\",\n },\n aligo: {\n label: \"Aligo\",\n routingSeedTypes: [\"ALIMTALK\", \"FRIENDTALK\", \"SMS\", \"LMS\", \"MMS\"],\n defaultKakaoSenderKey: \"env:ALIGO_SENDER_KEY\",\n },\n iwinv: {\n label: \"IWINV\",\n routingSeedTypes: [\"ALIMTALK\", \"SMS\", \"LMS\", \"MMS\"],\n },\n solapi: {\n label: \"SOLAPI\",\n routingSeedTypes: [\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 defaultKakaoSenderKey: \"env:SOLAPI_KAKAO_PF_ID\",\n },\n};\n",
|
|
27
|
-
"import {\n fail,\n type KakaoChannel,\n type KakaoChannelCategories,\n type KakaoChannelProvider,\n KMsgError,\n KMsgErrorCode,\n type MessageType,\n ok,\n type Provider,\n type Result,\n type SendOptions,\n type SendResult,\n type Template,\n type TemplateContext,\n type TemplateCreateInput,\n type TemplateInspectionProvider,\n type TemplateProvider,\n type TemplateUpdateInput,\n} from \"@k-msg/core\";\nimport { getProviderOnboardingSpec } from \"../../onboarding/specs\";\n\ntype MockSendScenarioStep = {\n outcome: \"success\" | \"failure\" | \"timeout\" | \"delay\";\n code?: KMsgErrorCode | string;\n message?: string;\n providerErrorCode?: string;\n providerErrorText?: string;\n httpStatus?: number;\n retryAfterMs?: number;\n causeChain?: unknown[];\n durationMs?: number;\n};\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => {\n setTimeout(resolve, Math.max(0, Math.floor(ms)));\n });\n\nconst normalizeMockErrorCode = (\n code: MockSendScenarioStep[\"code\"],\n): KMsgErrorCode => {\n if (\n code === KMsgErrorCode.INVALID_REQUEST ||\n code === KMsgErrorCode.AUTHENTICATION_FAILED ||\n code === KMsgErrorCode.INSUFFICIENT_BALANCE ||\n code === KMsgErrorCode.TEMPLATE_NOT_FOUND ||\n code === KMsgErrorCode.RATE_LIMIT_EXCEEDED ||\n code === KMsgErrorCode.NETWORK_ERROR ||\n code === KMsgErrorCode.NETWORK_TIMEOUT ||\n code === KMsgErrorCode.NETWORK_SERVICE_UNAVAILABLE ||\n code === KMsgErrorCode.PROVIDER_ERROR ||\n code === KMsgErrorCode.MESSAGE_SEND_FAILED ||\n code === KMsgErrorCode.UNKNOWN_ERROR\n ) {\n return code;\n }\n\n return KMsgErrorCode.PROVIDER_ERROR;\n};\n\nexport class MockProvider\n implements\n Provider,\n TemplateProvider,\n TemplateInspectionProvider,\n KakaoChannelProvider\n{\n readonly id = \"mock\";\n readonly name = \"Mock 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 public calls: SendOptions[] = [];\n private failureCount = 0;\n private scenario: MockSendScenarioStep[] = [];\n private scenarioCursor = 0;\n private templates: Map<string, Template> = new Map();\n private templateSeq = 0;\n private channelSeq = 0;\n private kakaoChannels: Map<string, KakaoChannel> = new Map();\n\n getOnboardingSpec() {\n const spec = getProviderOnboardingSpec(this.id);\n if (!spec) {\n throw new Error(`Onboarding spec missing for provider: ${this.id}`);\n }\n return spec;\n }\n\n constructor() {\n // Seed with a deterministic channel/template so CLI calls can be tested\n // without relying on cross-process state.\n const now = new Date();\n\n const seedTemplate: Template = {\n id: \"MOCK_TPL_SEED\",\n code: \"MOCK_TPL_SEED\",\n name: \"Mock Seed Template\",\n content: \"Hello #{name}\",\n status: \"APPROVED\",\n createdAt: now,\n updatedAt: now,\n };\n this.templates.set(seedTemplate.code, seedTemplate);\n\n const seedChannel: KakaoChannel = {\n providerId: this.id,\n senderKey: \"mock-sender-seed\",\n plusId: \"@mock\",\n name: \"Mock Seed Channel\",\n status: \"A\",\n createdAt: now,\n updatedAt: now,\n };\n this.kakaoChannels.set(seedChannel.senderKey, seedChannel);\n }\n\n async healthCheck() {\n return { healthy: true, issues: [] };\n }\n\n async send(params: SendOptions): Promise<Result<SendResult, KMsgError>> {\n this.calls.push(params);\n\n let outcome = this.nextScenarioOutcome();\n\n while (outcome.outcome === \"delay\") {\n await sleep(outcome.durationMs ?? 0);\n outcome = this.nextScenarioOutcome();\n }\n\n if (outcome.outcome === \"timeout\") {\n await sleep(outcome.durationMs ?? 0);\n return fail(\n new KMsgError(\n KMsgErrorCode.NETWORK_TIMEOUT,\n outcome.message ?? \"Mock provider simulated timeout\",\n { provider: this.id },\n {\n providerErrorCode: outcome.providerErrorCode ?? \"TIMEOUT\",\n providerErrorText: outcome.providerErrorText,\n httpStatus: outcome.httpStatus,\n retryAfterMs: outcome.retryAfterMs,\n },\n ),\n );\n }\n\n if (outcome.outcome === \"failure\") {\n const code = normalizeMockErrorCode(outcome.code);\n return fail(\n new KMsgError(\n code,\n outcome.message ?? \"Mock provider simulated failure\",\n { provider: this.id },\n {\n providerErrorCode: outcome.providerErrorCode,\n providerErrorText: outcome.providerErrorText,\n httpStatus: outcome.httpStatus,\n retryAfterMs: outcome.retryAfterMs,\n causeChain: outcome.causeChain,\n },\n ),\n );\n }\n\n if (outcome.outcome !== \"success\") {\n return fail(\n new KMsgError(\n KMsgErrorCode.UNKNOWN_ERROR,\n `Unsupported mock outcome: ${String(outcome.outcome)}`,\n { provider: this.id },\n ),\n );\n }\n\n const result: SendResult = {\n messageId: params.messageId || crypto.randomUUID(),\n status: \"SENT\",\n providerId: this.id,\n providerMessageId: `mock-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`,\n type: params.type,\n to: params.to,\n ...(params.type === \"ALIMTALK\" && params.failover?.enabled === true\n ? {\n warnings: [\n {\n code: \"FAILOVER_UNSUPPORTED_PROVIDER\",\n message:\n \"Mock provider does not support native ALIMTALK failover.\",\n details: { providerId: this.id },\n },\n ],\n }\n : {}),\n };\n\n return ok(result);\n }\n\n mockSuccess(): void {\n this.failureCount = 0;\n this.clearScenario();\n }\n\n mockFailure(count: number): void {\n this.failureCount = count;\n this.clearScenario();\n }\n\n mockScenario(steps: MockSendScenarioStep[]): void {\n this.scenario = Array.isArray(steps) ? steps.slice() : [];\n this.scenarioCursor = 0;\n }\n\n clearScenario(): void {\n this.scenario = [];\n this.scenarioCursor = 0;\n }\n\n private nextScenarioOutcome(): MockSendScenarioStep {\n if (this.scenarioCursor < this.scenario.length) {\n const next = this.scenario[this.scenarioCursor];\n this.scenarioCursor += 1;\n return next;\n }\n\n if (this.failureCount > 0) {\n this.failureCount -= 1;\n return {\n outcome: \"failure\",\n code: KMsgErrorCode.PROVIDER_ERROR,\n message: \"Mock provider simulated failure\",\n };\n }\n\n return { outcome: \"success\" };\n }\n\n getHistory(): SendOptions[] {\n return this.calls;\n }\n\n clearHistory(): void {\n this.calls = [];\n }\n\n async createTemplate(\n input: TemplateCreateInput,\n _ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n this.templateSeq += 1;\n const code = `MOCK_TPL_${this.templateSeq}`;\n const newTemplate: Template = {\n id: code,\n code,\n name: input.name,\n content: input.content,\n category: input.category,\n buttons: input.buttons,\n variables: input.variables,\n status: \"APPROVED\",\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n this.templates.set(newTemplate.code, newTemplate);\n return ok(newTemplate);\n }\n\n async updateTemplate(\n code: string,\n patch: TemplateUpdateInput,\n _ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n const existing = this.templates.get(code);\n if (!existing) {\n return fail(\n new KMsgError(\n KMsgErrorCode.TEMPLATE_NOT_FOUND,\n `Template not found: ${code}`,\n ),\n );\n }\n const updated: Template = {\n ...existing,\n ...(typeof patch.name === \"string\" ? { name: patch.name } : {}),\n ...(typeof patch.content === \"string\" ? { content: patch.content } : {}),\n ...(patch.category !== undefined ? { category: patch.category } : {}),\n ...(patch.buttons !== undefined ? { buttons: patch.buttons } : {}),\n ...(patch.variables !== undefined ? { variables: patch.variables } : {}),\n updatedAt: new Date(),\n };\n this.templates.set(code, updated);\n return ok(updated);\n }\n\n async deleteTemplate(\n code: string,\n _ctx?: TemplateContext,\n ): Promise<Result<void, KMsgError>> {\n if (!this.templates.has(code)) {\n return fail(\n new KMsgError(\n KMsgErrorCode.TEMPLATE_NOT_FOUND,\n `Template not found: ${code}`,\n ),\n );\n }\n this.templates.delete(code);\n return ok(undefined);\n }\n\n async getTemplate(\n code: string,\n _ctx?: TemplateContext,\n ): Promise<Result<Template, KMsgError>> {\n const template = this.templates.get(code);\n if (!template) {\n return fail(\n new KMsgError(\n KMsgErrorCode.TEMPLATE_NOT_FOUND,\n `Template not found: ${code}`,\n ),\n );\n }\n return ok(template);\n }\n\n async listTemplates(\n params?: {\n status?: string;\n page?: number;\n limit?: number;\n },\n _ctx?: TemplateContext,\n ): Promise<Result<Template[], KMsgError>> {\n let templates = Array.from(this.templates.values());\n if (params?.status) {\n templates = templates.filter((t) => t.status === params.status);\n }\n const page = params?.page || 1;\n const limit = params?.limit || 10;\n const start = (page - 1) * limit;\n const end = start + limit;\n return ok(templates.slice(start, end));\n }\n\n async requestTemplateInspection(\n code: string,\n _ctx?: TemplateContext,\n ): Promise<Result<void, KMsgError>> {\n if (!this.templates.has(code)) {\n return fail(\n new KMsgError(\n KMsgErrorCode.TEMPLATE_NOT_FOUND,\n `Template not found: ${code}`,\n ),\n );\n }\n return ok(undefined);\n }\n\n async listKakaoChannels(params?: {\n plusId?: string;\n senderKey?: string;\n }): Promise<Result<KakaoChannel[], KMsgError>> {\n let channels = Array.from(this.kakaoChannels.values());\n if (params?.plusId) {\n channels = channels.filter((c) => c.plusId === params.plusId);\n }\n if (params?.senderKey) {\n channels = channels.filter((c) => c.senderKey === params.senderKey);\n }\n return ok(channels);\n }\n\n async listKakaoChannelCategories(): Promise<\n Result<KakaoChannelCategories, KMsgError>\n > {\n const categories: KakaoChannelCategories = {\n first: [{ code: \"001\", name: \"Mock First\" }],\n second: [{ code: \"001001\", name: \"Mock Second\", parentCode: \"001\" }],\n third: [\n {\n code: \"001001001\",\n name: \"Mock Third\",\n parentCode: \"001001\",\n },\n ],\n };\n return ok(categories);\n }\n\n async requestKakaoChannelAuth(params: {\n plusId: string;\n phoneNumber: string;\n }): Promise<Result<void, KMsgError>> {\n if (!params.plusId || !params.phoneNumber) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"plusId and phoneNumber are required\",\n { providerId: this.id },\n ),\n );\n }\n return ok(undefined);\n }\n\n async addKakaoChannel(params: {\n plusId: string;\n authNum: string;\n phoneNumber: string;\n categoryCode: string;\n }): Promise<Result<KakaoChannel, KMsgError>> {\n if (\n !params.plusId ||\n !params.authNum ||\n !params.phoneNumber ||\n !params.categoryCode\n ) {\n return fail(\n new KMsgError(\n KMsgErrorCode.INVALID_REQUEST,\n \"plusId, authNum, phoneNumber, categoryCode are required\",\n { providerId: this.id },\n ),\n );\n }\n\n this.channelSeq += 1;\n const senderKey = `mock-sender-${this.channelSeq}`;\n const channel: KakaoChannel = {\n providerId: this.id,\n senderKey,\n plusId: params.plusId,\n name: \"Mock Channel\",\n status: \"A\",\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n this.kakaoChannels.set(senderKey, channel);\n return ok(channel);\n }\n}\n"
|
|
28
|
-
],
|
|
29
|
-
"mappings": "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,KAAM,SACN,SAAU,GACV,YAAa,gBACb,aAAc,mBAChB,EACA,UAAW,CACT,KAAM,SACN,YAAa,2BACb,aAAc,sBAChB,EACA,OAAQ,CACN,KAAM,SACN,YAAa,gCACb,aAAc,kBAChB,EACA,SAAU,CACR,KAAM,UACN,YAAa,wBACf,EACA,MAAO,CACL,KAAM,UACN,YAAa,sBACf,EACA,WAAY,CACV,KAAM,SACN,YAAa,2BACf,EACA,gBAAiB,CACf,KAAM,SACN,YAAa,gCACf,EACA,mBAAoB,CAClB,KAAM,SACN,YAAa,mCACf,CACF,EACA,MAAO,CACL,OAAQ,CACN,KAAM,SACN,SAAU,GACV,YAAa,uCACb,aAAc,mBAChB,EACA,UAAW,CACT,KAAM,SACN,YAAa,oBACb,aAAc,uBAChB,EACA,WAAY,CACV,KAAM,SACN,YAAa,qBACb,aAAc,wBAChB,EACA,aAAc,CACZ,KAAM,SACN,YAAa,uBACb,aAAc,0BAChB,EACA,aAAc,CACZ,KAAM,SACN,YAAa,wBACb,aAAc,yBAChB,EACA,gBAAiB,CACf,KAAM,SACN,YAAa,gCACf,EACA,aAAc,CACZ,KAAM,SACN,YAAa,mCACf,EACA,cAAe,CACb,KAAM,SACN,YAAa,iCACf,EACA,aAAc,CACZ,KAAM,eACN,YAAa,yBACf,EACA,aAAc,CACZ,KAAM,SACN,YAAa,4BACf,EACA,eAAgB,CACd,KAAM,SACN,YAAa,kCACf,EACA,kBAAmB,CACjB,KAAM,SACN,YAAa,uCACf,EACA,MAAO,CACL,KAAM,UACN,YAAa,sBACf,CACF,EACA,OAAQ,CACN,OAAQ,CACN,KAAM,SACN,SAAU,GACV,YAAa,iBACb,aAAc,oBAChB,EACA,UAAW,CACT,KAAM,SACN,SAAU,GACV,YAAa,oBACb,aAAc,uBAChB,EACA,YAAa,CACX,KAAM,SACN,YAAa,wBACb,aAAc,yBAChB,EACA,UAAW,CACT,KAAM,SACN,YAAa,sBACb,aAAc,wBAChB,EACA,WAAY,CACV,KAAM,SACN,YAAa,sBACf,EACA,YAAa,CACX,KAAM,SACN,YAAa,uBACf,EACA,MAAO,CACL,KA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",
|
|
30
|
-
"debugId": "9D2074B801C1F2AE64756E2164756E21",
|
|
31
|
-
"names": []
|
|
32
|
-
}
|