Skip to content

Commit 9efd911

Browse files
[Chore] Add prettier code style, renewal kakao alimtalk template, channel model, request, response:
* Upgrade deps version
1 parent 9f0f5fa commit 9efd911

27 files changed

Lines changed: 2069 additions & 1489 deletions

.eslintrc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"parser": "@typescript-eslint/parser",
33
"plugins": [
44
"@typescript-eslint/eslint-plugin",
5-
"eslint-plugin-tsdoc"
5+
"eslint-plugin-tsdoc",
6+
"unused-imports"
67
],
78
"extends": [
89
"plugin:@typescript-eslint/recommended"
@@ -28,7 +29,8 @@
2829
"ignoreParameters": true
2930
}
3031
],
31-
"@typescript-eslint/no-unused-vars": "warn"
32+
"@typescript-eslint/no-unused-vars": "warn",
33+
"unused-imports/no-unused-imports": "warn"
3234
},
3335
"ignorePatterns": [
3436
"dist/**/*",

.parcelrc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
11
{
2-
"extends": "@parcel/config-default",
3-
"validators": {
4-
"*.{ts,tsx}": ["@parcel/validator-typescript"]
5-
}
2+
"extends": "@parcel/config-default"
63
}

changelog/ko/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# 5.2.0 (2022년 11월 24일)
2+
3+
- 5.1.1에서 추가된 카카오 알림톡 채널/템플릿 관리 기능을 안정화 했습니다.
4+
- 템플릿 내 아이템리스트 유형 및 바로연결 버튼 유형이 추가되었습니다.
5+
- send 메소드에 messages 파라미터 이후의 파라미터들을 하나의 오브젝트(requestConfigParameter)로 변경되었습니다.
6+
- breaking change가 발생하여 예약 발송, 중복 수신번호 허용, appId를 사용하시던 사용자는 업데이트 후 코드를 변경하셔야 합니다.
7+
- Message class내 constructor 파라미터가 변경되었습니다.

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,12 @@
4343
"crypto-js": "^4.1.1",
4444
"date-fns": "^2.29.3",
4545
"image-to-base64": "^2.2.0",
46-
"joi": "^17.7.0",
4746
"nanoid": "^3.3.4",
4847
"qs": "^6.11.0"
4948
},
5049
"devDependencies": {
5150
"@parcel/packager-ts": "2.8.0",
5251
"@parcel/transformer-typescript-types": "2.8.0",
53-
"@parcel/validator-typescript": "^2.8.0",
5452
"@types/crypto-js": "^4.1.1",
5553
"@types/image-to-base64": "^2.1.0",
5654
"@types/node": "^18.11.9",
@@ -59,6 +57,7 @@
5957
"@typescript-eslint/parser": "^5.44.0",
6058
"eslint": "^8.28.0",
6159
"eslint-plugin-tsdoc": "^0.2.17",
60+
"eslint-plugin-unused-imports": "^2.0.0",
6261
"parcel": "^2.8.0",
6362
"prettier": "^2.8.0",
6463
"rimraf": "^3.0.2",

src/errors/defaultError.ts

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,44 @@
1-
import {FailedMessage} from '../responses/messageResponses';
1+
import {FailedMessage} from '../responses/sendManyDetailResponse';
22

33
export type ErrorResponse = {
4-
errorCode: string,
5-
errorMessage: string
6-
}
4+
errorCode: string;
5+
errorMessage: string;
6+
};
77

88
export class InvalidDateError extends Error {
9-
constructor(message: string) {
10-
super(message);
11-
this.name = 'InvalidDateError';
12-
}
9+
constructor(message: string) {
10+
super(message);
11+
this.name = 'InvalidDateError';
12+
}
1313
}
1414

1515
export class ApiKeyError extends Error {
16-
constructor(message: string) {
17-
super(message);
18-
this.name = 'InvalidApiKeyError';
19-
}
16+
constructor(message: string) {
17+
super(message);
18+
this.name = 'InvalidApiKeyError';
19+
}
2020
}
2121

2222
export class DefaultError extends Error {
23-
constructor(errorCode: string, errorMessage: string) {
24-
super(errorMessage);
25-
this.name = errorCode;
26-
}
23+
constructor(errorCode: string, errorMessage: string) {
24+
super(errorMessage);
25+
this.name = errorCode;
26+
}
2727
}
2828

29+
/**
30+
* @description 메시지가 모두 발송 접수가 불가한 상태일 경우 MessageNotReceivedError 에러가 발생합니다.
31+
*/
2932
export class MessageNotReceivedError extends Error {
30-
constructor(errorList: Array<FailedMessage>) {
31-
super(JSON.stringify(errorList));
32-
this.name = 'MessagesNotReceivedError';
33-
}
33+
constructor(errorList: Array<FailedMessage>) {
34+
super(JSON.stringify(errorList));
35+
this.name = 'MessagesNotReceivedError';
36+
}
37+
}
38+
39+
export class BadRequestError extends Error {
40+
constructor(message: string) {
41+
super(message);
42+
this.name = 'BadRequestError';
43+
}
3444
}

src/lib/authenticator.ts

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,38 @@ import {HmacSHA256} from 'crypto-js';
44
import {ApiKeyError} from '../errors/defaultError';
55

66
enum AuthenticateType {
7-
API_KEY
7+
API_KEY,
88
}
99

1010
export type AuthenticationParameter = {
11-
apiKey?: string
12-
apiSecret?: string
13-
}
14-
11+
apiKey?: string;
12+
apiSecret?: string;
13+
};
1514

1615
/**
1716
* Get Authenticate Information for SOLAPI Requests
1817
* @param authenticationParameter
1918
* @param authType
2019
* @return string Authorization value
2120
*/
22-
export default function getAuthInfo(authenticationParameter: AuthenticationParameter, authType: AuthenticateType = AuthenticateType.API_KEY): string {
23-
const {apiKey, apiSecret} = authenticationParameter;
24-
switch (authType) {
25-
case AuthenticateType.API_KEY:
26-
default:
27-
const salt = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 32)();
28-
const date = formatISO(new Date());
29-
const hmacData = date + salt;
30-
if ((!apiKey || !apiSecret) || (apiKey === '' || apiSecret === '')) {
31-
throw new ApiKeyError('Invalid API Key Error');
32-
}
33-
const signature = HmacSHA256(hmacData, apiSecret).toString();
34-
return `HMAC-SHA256 apiKey=${apiKey}, date=${date}, salt=${salt}, signature=${signature}`;
35-
}
21+
export default function getAuthInfo(
22+
authenticationParameter: AuthenticationParameter,
23+
authType: AuthenticateType = AuthenticateType.API_KEY,
24+
): string {
25+
const {apiKey, apiSecret} = authenticationParameter;
26+
switch (authType) {
27+
case AuthenticateType.API_KEY:
28+
default:
29+
const salt = customAlphabet(
30+
'1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
31+
32,
32+
)();
33+
const date = formatISO(new Date());
34+
const hmacData = date + salt;
35+
if (!apiKey || !apiSecret || apiKey === '' || apiSecret === '') {
36+
throw new ApiKeyError('Invalid API Key Error');
37+
}
38+
const signature = HmacSHA256(hmacData, apiSecret).toString();
39+
return `HMAC-SHA256 apiKey=${apiKey}, date=${date}, salt=${salt}, signature=${signature}`;
40+
}
3641
}

src/lib/defaultFetcher.ts

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import fetch from 'cross-fetch';
33
import {DefaultError, ErrorResponse} from '../errors/defaultError';
44

55
type DefaultRequest = {
6-
url: string,
7-
method: string
8-
}
6+
url: string;
7+
method: string;
8+
};
99

1010
/**
1111
* 공용 API 클라이언트 함수
@@ -14,27 +14,34 @@ type DefaultRequest = {
1414
* @param request API URI, HTTP method 정의
1515
* @param data API에 요청할 request body 데이터
1616
*/
17-
export default async function defaultFetcher<T, R>(authParameter: AuthenticationParameter, request: DefaultRequest, data?: T): Promise<R> {
18-
const authorizationHeaderData = getAuthInfo(authParameter);
19-
return await fetch(request.url, {
20-
headers: {
21-
'Authorization': authorizationHeaderData,
22-
'Content-Type': 'application/json',
23-
},
24-
body: JSON.stringify(data),
25-
method: request.method
26-
}).then<R>(async (res) => {
27-
if (res.status >= 400 && res.status < 500) {
28-
const errorResponse: ErrorResponse = await res.json();
29-
throw new DefaultError(errorResponse.errorCode, errorResponse.errorMessage);
30-
} else if (res.status >= 500) {
31-
const responseText = await res.text();
32-
throw new DefaultError('UnknownException', responseText);
33-
}
34-
try {
35-
return res.json();
36-
} catch (exception) {
37-
throw new Error(await res.text());
38-
}
39-
});
17+
export default async function defaultFetcher<T, R>(
18+
authParameter: AuthenticationParameter,
19+
request: DefaultRequest,
20+
data?: T,
21+
): Promise<R> {
22+
const authorizationHeaderData = getAuthInfo(authParameter);
23+
return await fetch(request.url, {
24+
headers: {
25+
Authorization: authorizationHeaderData,
26+
'Content-Type': 'application/json',
27+
},
28+
body: JSON.stringify(data),
29+
method: request.method,
30+
}).then<R>(async res => {
31+
if (res.status >= 400 && res.status < 500) {
32+
const errorResponse: ErrorResponse = await res.json();
33+
throw new DefaultError(
34+
errorResponse.errorCode,
35+
errorResponse.errorMessage,
36+
);
37+
} else if (res.status >= 500) {
38+
const responseText = await res.text();
39+
throw new DefaultError('UnknownException', responseText);
40+
}
41+
try {
42+
return res.json();
43+
} catch (exception) {
44+
throw new Error(await res.text());
45+
}
46+
});
4047
}

src/lib/queryParameterGenerator.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,21 @@ import {URL, URLSearchParams} from 'url';
55
* @param url API URl
66
* @param data object data
77
*/
8-
export default function queryParameterGenerator<T extends object>(url: string, data?: T): string {
9-
const apiUrl = new URL(url);
10-
if (data) {
11-
const urlSearchParams = new URLSearchParams();
12-
Object.keys(data).forEach(key => {
13-
const reflectedValue = Reflect.get(data, key);
14-
if (reflectedValue) {
15-
urlSearchParams.append(key, reflectedValue);
16-
}
17-
});
18-
apiUrl.search = urlSearchParams.toString();
19-
}
20-
return apiUrl.toString();
8+
export default function queryParameterGenerator<T extends object>(
9+
url: string,
10+
data?: T,
11+
): string {
12+
const apiUrl = new URL(url);
13+
if (data) {
14+
const urlSearchParams = new URLSearchParams();
15+
Object.keys(data).forEach(key => {
16+
// eslint-disable-next-line
17+
const reflectedValue: any = Reflect.get(data, key);
18+
if (reflectedValue) {
19+
urlSearchParams.append(key, reflectedValue);
20+
}
21+
});
22+
apiUrl.search = urlSearchParams.toString();
23+
}
24+
return apiUrl.toString();
2125
}

src/lib/stringDateTrasnfer.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
1-
import {parseISO} from 'date-fns';
1+
import {formatISO, parseISO} from 'date-fns';
22
import {InvalidDateError} from '../errors/defaultError';
33

4+
/**
5+
* @name formatWithTransfer stringDateTransfer와 formatISO를 한번에 실행하는 함수
6+
* @param value Date 타입의 날짜
7+
* @throws InvalidDateError
8+
*/
9+
export function formatWithTransfer(value: string | Date): string {
10+
return formatISO(stringDateTransfer(value));
11+
}
12+
413
/**
514
* 일반 문자열 날짜가 있을 경우 Date 타입으로 변환해주는 함수
615
* @param value 일반 문자열 날짜 또는 Date 타입의 날짜
16+
* @throws InvalidDateError
717
*/
818
export default function stringDateTransfer(value: string | Date): Date {
9-
if (typeof value === 'string') {
10-
value = parseISO(value);
11-
const invalidDateText = 'Invalid Date';
12-
if (value.toString() === invalidDateText) {
13-
throw new InvalidDateError(invalidDateText);
14-
}
19+
if (typeof value === 'string') {
20+
value = parseISO(value);
21+
const invalidDateText = 'Invalid Date';
22+
if (value.toString() === invalidDateText) {
23+
throw new InvalidDateError(invalidDateText);
1524
}
16-
return value;
25+
}
26+
return value;
1727
}

0 commit comments

Comments
 (0)