SOLAPI SDK for Node.js โ SMS, LMS, MMS, Kakao ๋ฉ์์ง(์๋ฆผํก/์น๊ตฌํก) ๋ฐ์ก์ ์ํ ์๋ฒ์ฌ์ด๋ SDK.
- Zero Tolerance for Errors โ ๋ชจ๋ ๊ฒ์ฆ ํต๊ณผ ํ์, ๊ฒฝ๊ณ ๋ฌด์ ๊ธ์ง
- Clarity over Cleverness โ ๋ช ํํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ ์ฝ๋ ์ฐ์
- Conciseness โ ์๋๋ฅผ ์์ ํ ํํํ๋ ์ต์ํ์ ์ฝ๋
- Reduce Comments โ ์ฝ๋๊ฐ ์์ฒด ์ค๋ช ์ ์ด์ด์ผ ํจ. "why"๋ง ์ฃผ์์ผ๋ก ๋จ๊น
- Read Before Writing โ ์ ์ฝ๋ ์์ฑ ์ ๊ธฐ์กด ํจํด์ ๋ฐ๋์ ํ์ธ
pnpm dev # Watch mode (tsup)
pnpm build # Lint + build (production)
pnpm lint # Biome check with auto-fix
pnpm test # Run all tests once
pnpm test:watch # Watch mode
pnpm vitest run <path> # Run specific test file
pnpm docs # Generate TypeDoc documentation์ฝ๋ ๋ณ๊ฒฝ ํ ๋ฐ๋์ ์์๋๋ก ์คํ:
pnpm lintโ Biome ์๋ ์์ pnpm testโ ์ ์ฒด ํ ์คํธ ํต๊ณผpnpm buildโ ํ์ ์ฒดํฌ + ๋น๋
์คํจ ์ ์์ ํ ์ฌ์คํ. ์คํจ ์ํ๋ก ์ปค๋ฐ ๊ธ์ง.
SolapiMessageService (src/index.ts)๊ฐ ๋ชจ๋ ๋๋ฉ์ธ ์๋น์ค ๋ฉ์๋๋ฅผ ๋ช
์์ .bind()๋ก ์์.
๋ชจ๋ ์๋น์ค๋ DefaultService (src/services/defaultService.ts) ์์:
- Base URL:
https://api.solapi.com AuthenticationParameter๊ธฐ๋ฐ ์ธ์ฆdefaultFetcherHTTP ์ถ์ํ
๋๋ฉ์ธ ์๋น์ค: MessageService, GroupService, KakaoChannelService, KakaoTemplateService, CashService, IamService, StorageService
- ์๋ฌ:
Data.TaggedError+ environment-awaretoString() - ๋น๋๊ธฐ:
Effect.gen+Effect.tryPromise - ๊ฒ์ฆ: Effect Schema (
Schema.filter,Schema.transform) - Promise ๋ณํ:
runSafePromise()
@models โ src/models @lib โ src/lib @services โ src/services
@errors โ src/errors @internal-types โ src/types @ โ src
anyํ์ ์ ๋ ๊ธ์ง โunknown+ type guards ๋๋ Effect Schema ์ฌ์ฉnoExplicitAny: error(Biome), strict mode ํ์ฑํ- ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์คํ์ผ (Effect library)
- ์ฝ๋ ์์ฑ ํ
pnpm lint์คํ
- ์๋ฌ๋ ๋ฐ๋์
Data.TaggedError์ฌ์ฉ (rawthrow new Error()๊ธ์ง) - Effect ์ฃผ๋ณ์ try-catch ๊ธ์ง โ
Effect.catchTag/Effect.catchAll์ฌ์ฉ - Promise ๋ณํ์ ๋ฐ๋์
runSafePromise()๊ฒฝ์
- ์ฝ๋๋ฅผ ๋จผ์ ์ฝ๊ณ ํ ์คํธ ์์ฑ โ ์ฝ๋๊ฐ ์ง์ค์ ์์ฒ
- ์ฑ๊ณต/์คํจ ๋ชจ๋ ํ ์คํธ โ happy path๋ง ํ ์คํธ ๊ธ์ง
- ๋ชจ๋ ์กฐ๊ฑด ๋ถ๊ธฐ, ๊ฒฝ๊ณ๊ฐ(null, empty, zero, min, max) ํ ์คํธ
- ๋ฒ๊ทธ ์์ ์ ๋ฐ๋์ ํ๊ท ํ ์คํธ ์ถ๊ฐ
- ๊ฒฐ์ ์ (deterministic) ํ ์คํธ๋ง ์์ฑ โ sleep ๊ธฐ๋ฐ ํ์ด๋ฐ ์์กด ๊ธ์ง
- ์ํ ์ผ๊ด์ฑ, ๋ถ์์ฉ, ๋ฉฑ๋ฑ์ฑ, ๋ฆฌ์์ค ์ ๋ฆฌ
- ์์กด์ฑ ์คํจ ์๋ฎฌ๋ ์ด์ (๋คํธ์ํฌ ์๋ฌ, ํ์์์)
- Effect ํ์ดํ๋ผ์ธ์ ํตํ ์๋ฌ ์ ํ
- Unit:
import {describe, expect, it} from 'vitest'- Schema ๊ฒ์ฆ:
Schema.decodeUnknownEither()/Schema.decodeUnknownSync() - ํ
์ด๋ธ ๊ธฐ๋ฐ:
it.each()ํ์ฉ
- Schema ๊ฒ์ฆ:
- E2E:
import {describe, expect, it} from '@effect/vitest'it.effect()+Effect.gen(function* () { ... })- Layer ์ ๊ณต:
.pipe(Effect.provide(XxxLive)) - ์๋ฌ ํ
์คํธ:
Effect.either() - ํ
์คํธ ๋ ์ด์ด:
test/lib/test-layers.ts
- ๋์ ๊ธฐ๋ฐ: "should return empty string for null"
- ์ฃ์ง ์ผ์ด์ค: "should reject BMS_IMAGE without imageId"
- ์คํจ ๋ชจ๋: "should handle network timeout gracefully"
- happy path๋ง ํ ์คํธ
- ์ฃ์ง ์ผ์ด์ค/์๋ฌ ๊ฒฝ๋ก ์๋ต
- ๋น๊ฒฐ์ ์ (non-deterministic) ํ ์คํธ
- ํ๋์ ํ ์คํธ์ ์ฌ๋ฌ ๊ด์ฌ์ฌ ๋ณํฉ
- ๋ผ์ธ ์ปค๋ฒ๋ฆฌ์ง๋ง ์์กด
์์ธํ ์ฝ๋ ํจํด๊ณผ ์ํฐํจํด์ AGENTS.md ์ฐธ์กฐ.