@hamjimin/xplat-back 0.1.0 → 0.2.0
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/README.md +0 -1
- package/dist/cli/init.js +36 -0
- package/dist/cli/templates/api_code.ts.example +70 -0
- package/dist/cli/templates/constants.ts.example +113 -0
- package/dist/core/XplatSystem.d.ts +40 -0
- package/dist/core/XplatSystem.js +51 -0
- package/dist/index.d.ts +16 -3
- package/dist/index.js +29 -7
- package/dist/modules/app/app-factory.d.ts +12 -0
- package/dist/modules/app/app-factory.js +125 -0
- package/dist/modules/app/index.d.ts +11 -0
- package/dist/modules/app/index.js +16 -0
- package/dist/modules/auth/index.d.ts +36 -0
- package/dist/modules/auth/index.js +61 -0
- package/dist/modules/auth/jwt.d.ts +40 -0
- package/dist/modules/auth/jwt.js +49 -0
- package/dist/modules/auth/middleware.d.ts +20 -0
- package/dist/modules/auth/middleware.js +88 -0
- package/dist/modules/constants/api-code.d.ts +15 -0
- package/dist/modules/constants/api-code.js +50 -0
- package/dist/modules/constants/index.d.ts +30 -0
- package/dist/modules/constants/index.js +46 -0
- package/dist/modules/middleware/error-handler.d.ts +9 -0
- package/dist/modules/middleware/error-handler.js +31 -0
- package/dist/modules/middleware/index.d.ts +30 -0
- package/dist/modules/middleware/index.js +48 -0
- package/dist/modules/middleware/logger.d.ts +11 -0
- package/dist/modules/middleware/logger.js +43 -0
- package/dist/modules/middleware/validator.d.ts +13 -0
- package/dist/modules/middleware/validator.js +81 -0
- package/dist/modules/orm/index.d.ts +30 -0
- package/dist/modules/orm/index.js +46 -0
- package/dist/modules/orm/query-builder.d.ts +68 -0
- package/dist/modules/orm/query-builder.js +238 -0
- package/dist/modules/router/index.d.ts +10 -0
- package/dist/modules/router/index.js +16 -0
- package/dist/modules/router/route-factory.d.ts +10 -0
- package/dist/modules/router/route-factory.js +72 -0
- package/dist/modules/storage/index.d.ts +81 -0
- package/dist/modules/storage/index.js +86 -0
- package/dist/modules/storage/s3.d.ts +80 -0
- package/dist/modules/storage/s3.js +133 -0
- package/dist/modules/utils/date.d.ts +37 -0
- package/dist/modules/utils/date.js +72 -0
- package/dist/modules/utils/index.d.ts +44 -0
- package/dist/modules/utils/index.js +139 -0
- package/dist/modules/utils/lodash.d.ts +107 -0
- package/dist/modules/utils/lodash.js +154 -0
- package/dist/modules/utils/password.d.ts +31 -0
- package/dist/modules/utils/password.js +102 -0
- package/dist/modules/utils/pk.d.ts +18 -0
- package/dist/modules/utils/pk.js +41 -0
- package/dist/modules/utils/response.d.ts +20 -0
- package/dist/modules/utils/response.js +87 -0
- package/dist/modules/utils/validation.d.ts +50 -0
- package/dist/modules/utils/validation.js +90 -0
- package/dist/types/index.d.ts +26 -0
- package/package.json +14 -2
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LodashUtils = void 0;
|
|
7
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
+
/**
|
|
9
|
+
* Lodash 유틸리티 래퍼
|
|
10
|
+
*
|
|
11
|
+
* company-common-utils를 참고하여 작성되었습니다.
|
|
12
|
+
* 모든 lodash 함수에 직접 접근할 수 있도록 제공합니다.
|
|
13
|
+
*/
|
|
14
|
+
class LodashUtils {
|
|
15
|
+
/**
|
|
16
|
+
* lodash 인스턴스 직접 접근
|
|
17
|
+
*/
|
|
18
|
+
get _() {
|
|
19
|
+
return lodash_1.default;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 객체 깊은 복사
|
|
23
|
+
*/
|
|
24
|
+
deepClone(value) {
|
|
25
|
+
return lodash_1.default.cloneDeep(value);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 객체 병합
|
|
29
|
+
*/
|
|
30
|
+
merge(target, ...sources) {
|
|
31
|
+
return lodash_1.default.merge(target, ...sources);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 배열에서 중복 제거
|
|
35
|
+
*/
|
|
36
|
+
uniq(array) {
|
|
37
|
+
return lodash_1.default.uniq(array);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 객체에서 특정 경로의 값 가져오기
|
|
41
|
+
*/
|
|
42
|
+
get(object, path, defaultValue) {
|
|
43
|
+
return lodash_1.default.get(object, path, defaultValue);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 객체에 특정 경로로 값 설정
|
|
47
|
+
*/
|
|
48
|
+
set(object, path, value) {
|
|
49
|
+
return lodash_1.default.set(object, path, value);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 배열 그룹화
|
|
53
|
+
*/
|
|
54
|
+
groupBy(collection, iteratee) {
|
|
55
|
+
return lodash_1.default.groupBy(collection, iteratee);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 디바운스 함수
|
|
59
|
+
*/
|
|
60
|
+
debounce(func, wait, options) {
|
|
61
|
+
return lodash_1.default.debounce(func, wait, options);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 스로틀 함수
|
|
65
|
+
*/
|
|
66
|
+
throttle(func, wait, options) {
|
|
67
|
+
return lodash_1.default.throttle(func, wait, options);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 배열에서 특정 조건으로 필터링
|
|
71
|
+
*/
|
|
72
|
+
filter(collection, predicate) {
|
|
73
|
+
return lodash_1.default.filter(collection, predicate);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 배열에서 특정 조건으로 찾기
|
|
77
|
+
*/
|
|
78
|
+
find(collection, predicate) {
|
|
79
|
+
return lodash_1.default.find(collection, predicate);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 배열에서 특정 조건으로 매핑
|
|
83
|
+
*/
|
|
84
|
+
map(collection, iteratee) {
|
|
85
|
+
return lodash_1.default.map(collection, iteratee);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 배열에서 특정 조건으로 리듀스
|
|
89
|
+
*/
|
|
90
|
+
reduce(collection, iteratee, accumulator) {
|
|
91
|
+
return lodash_1.default.reduce(collection, iteratee, accumulator);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 객체 키 순회
|
|
95
|
+
*/
|
|
96
|
+
keys(object) {
|
|
97
|
+
return lodash_1.default.keys(object);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 객체 값 순회
|
|
101
|
+
*/
|
|
102
|
+
values(object) {
|
|
103
|
+
return lodash_1.default.values(object);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 객체가 비어있는지 확인
|
|
107
|
+
*/
|
|
108
|
+
isEmpty(value) {
|
|
109
|
+
return lodash_1.default.isEmpty(value);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 객체 병합 (assign과 유사)
|
|
113
|
+
*/
|
|
114
|
+
assign(target, ...sources) {
|
|
115
|
+
return lodash_1.default.assign(target, ...sources);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* 객체 키-값 쌍으로 변환
|
|
119
|
+
*/
|
|
120
|
+
toPairs(object) {
|
|
121
|
+
return lodash_1.default.toPairs(object);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* 키-값 쌍에서 객체로 변환
|
|
125
|
+
*/
|
|
126
|
+
fromPairs(pairs) {
|
|
127
|
+
return lodash_1.default.fromPairs(pairs);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 배열을 청크로 나누기
|
|
131
|
+
*/
|
|
132
|
+
chunk(array, size) {
|
|
133
|
+
return lodash_1.default.chunk(array, size);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 배열에서 특정 값 제거
|
|
137
|
+
*/
|
|
138
|
+
without(array, ...values) {
|
|
139
|
+
return lodash_1.default.without(array, ...values);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 배열 평탄화
|
|
143
|
+
*/
|
|
144
|
+
flatten(array) {
|
|
145
|
+
return lodash_1.default.flatten(array);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 배열 깊이 평탄화
|
|
149
|
+
*/
|
|
150
|
+
flattenDeep(array) {
|
|
151
|
+
return lodash_1.default.flattenDeep(array);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
exports.LodashUtils = LodashUtils;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bcrypt를 사용한 비밀번호 해싱
|
|
3
|
+
* @param password 평문 비밀번호
|
|
4
|
+
* @returns 해시된 비밀번호
|
|
5
|
+
*/
|
|
6
|
+
export declare function bcryptPassword(password: string): Promise<string>;
|
|
7
|
+
/**
|
|
8
|
+
* bcrypt를 사용한 비밀번호 검증
|
|
9
|
+
* @param password 평문 비밀번호
|
|
10
|
+
* @param hash 해시된 비밀번호
|
|
11
|
+
* @returns 일치 여부
|
|
12
|
+
*/
|
|
13
|
+
export declare function checkPassword(password: string, hash: string): Promise<boolean>;
|
|
14
|
+
/**
|
|
15
|
+
* AES-256-CBC를 사용한 비밀번호 암호화
|
|
16
|
+
* @param password 평문 비밀번호
|
|
17
|
+
* @returns 암호화된 비밀번호 (hex 문자열)
|
|
18
|
+
*/
|
|
19
|
+
export declare function cryptoPassword(password: string): Promise<string | null>;
|
|
20
|
+
/**
|
|
21
|
+
* AES-256-CBC를 사용한 비밀번호 복호화
|
|
22
|
+
* @param encryptedPassword 암호화된 비밀번호 (hex 문자열)
|
|
23
|
+
* @returns 복호화된 비밀번호
|
|
24
|
+
*/
|
|
25
|
+
export declare function decryptPassword(encryptedPassword: string): string | null;
|
|
26
|
+
/**
|
|
27
|
+
* 랜덤 비밀번호 생성
|
|
28
|
+
* @param length 비밀번호 길이 (기본값: 12)
|
|
29
|
+
* @returns 생성된 비밀번호
|
|
30
|
+
*/
|
|
31
|
+
export declare function generatePassword(length?: number): string;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.bcryptPassword = bcryptPassword;
|
|
7
|
+
exports.checkPassword = checkPassword;
|
|
8
|
+
exports.cryptoPassword = cryptoPassword;
|
|
9
|
+
exports.decryptPassword = decryptPassword;
|
|
10
|
+
exports.generatePassword = generatePassword;
|
|
11
|
+
const bcrypt_1 = __importDefault(require("bcrypt"));
|
|
12
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
13
|
+
/**
|
|
14
|
+
* 비밀번호 유틸리티
|
|
15
|
+
*
|
|
16
|
+
* zium-backend의 commonUtil.ts를 기반으로 작성되었습니다.
|
|
17
|
+
*/
|
|
18
|
+
// 환경변수에서 암호화 키 가져오기 (선택사항)
|
|
19
|
+
const getCryptoKey = () => {
|
|
20
|
+
const key = process.env.CRYPTO_KEY;
|
|
21
|
+
if (key) {
|
|
22
|
+
return Buffer.from(key, 'utf8').subarray(0, 32);
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
};
|
|
26
|
+
const getCryptoIV = () => {
|
|
27
|
+
const iv = process.env.CRYPTO_IV;
|
|
28
|
+
if (iv) {
|
|
29
|
+
return Buffer.from(iv, 'utf8').subarray(0, 16);
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
};
|
|
33
|
+
const algorithm = 'aes-256-cbc';
|
|
34
|
+
/**
|
|
35
|
+
* bcrypt를 사용한 비밀번호 해싱
|
|
36
|
+
* @param password 평문 비밀번호
|
|
37
|
+
* @returns 해시된 비밀번호
|
|
38
|
+
*/
|
|
39
|
+
async function bcryptPassword(password) {
|
|
40
|
+
const saltRounds = 10;
|
|
41
|
+
return await bcrypt_1.default.hash(password, saltRounds);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* bcrypt를 사용한 비밀번호 검증
|
|
45
|
+
* @param password 평문 비밀번호
|
|
46
|
+
* @param hash 해시된 비밀번호
|
|
47
|
+
* @returns 일치 여부
|
|
48
|
+
*/
|
|
49
|
+
async function checkPassword(password, hash) {
|
|
50
|
+
return await bcrypt_1.default.compare(password, hash);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* AES-256-CBC를 사용한 비밀번호 암호화
|
|
54
|
+
* @param password 평문 비밀번호
|
|
55
|
+
* @returns 암호화된 비밀번호 (hex 문자열)
|
|
56
|
+
*/
|
|
57
|
+
async function cryptoPassword(password) {
|
|
58
|
+
const key = getCryptoKey();
|
|
59
|
+
const iv = getCryptoIV();
|
|
60
|
+
if (key && iv) {
|
|
61
|
+
const cipher = crypto_1.default.createCipheriv(algorithm, key, iv);
|
|
62
|
+
let encrypted = cipher.update(password, 'utf8', 'hex');
|
|
63
|
+
encrypted += cipher.final('hex');
|
|
64
|
+
return encrypted;
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* AES-256-CBC를 사용한 비밀번호 복호화
|
|
70
|
+
* @param encryptedPassword 암호화된 비밀번호 (hex 문자열)
|
|
71
|
+
* @returns 복호화된 비밀번호
|
|
72
|
+
*/
|
|
73
|
+
function decryptPassword(encryptedPassword) {
|
|
74
|
+
const key = getCryptoKey();
|
|
75
|
+
const iv = getCryptoIV();
|
|
76
|
+
if (key && iv) {
|
|
77
|
+
try {
|
|
78
|
+
const decipher = crypto_1.default.createDecipheriv(algorithm, key, iv);
|
|
79
|
+
let decrypted = decipher.update(encryptedPassword, 'hex', 'utf8');
|
|
80
|
+
decrypted += decipher.final('utf8');
|
|
81
|
+
return decrypted;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 랜덤 비밀번호 생성
|
|
91
|
+
* @param length 비밀번호 길이 (기본값: 12)
|
|
92
|
+
* @returns 생성된 비밀번호
|
|
93
|
+
*/
|
|
94
|
+
function generatePassword(length = 12) {
|
|
95
|
+
const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';
|
|
96
|
+
let password = '';
|
|
97
|
+
for (let i = 0; i < length; i++) {
|
|
98
|
+
const randomIndex = Math.floor(Math.random() * charset.length);
|
|
99
|
+
password += charset[randomIndex];
|
|
100
|
+
}
|
|
101
|
+
return password;
|
|
102
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PK 생성 유틸리티
|
|
3
|
+
*
|
|
4
|
+
* zium-backend의 commonUtil.ts를 기반으로 작성되었습니다.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* UUID 기반 PK 생성
|
|
8
|
+
* @param convertStr 접두사 (예: "paymentLog")
|
|
9
|
+
* @returns 생성된 PK (예: "paymentLog12247a5935e18e6ce1b5225")
|
|
10
|
+
*/
|
|
11
|
+
export declare function makePK(convertStr?: string): Promise<string>;
|
|
12
|
+
/**
|
|
13
|
+
* 지정한 길이만큼의 ID를 생성합니다
|
|
14
|
+
* @param length 생성할 총 길이 (예: 32)
|
|
15
|
+
* @param prefix 선택: 앞쪽에 붙일 접두사 (예: "order")
|
|
16
|
+
* @returns 생성된 ID
|
|
17
|
+
*/
|
|
18
|
+
export declare function makePKWithLength(length: number, prefix?: string): Promise<string>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makePK = makePK;
|
|
4
|
+
exports.makePKWithLength = makePKWithLength;
|
|
5
|
+
const uuid_1 = require("uuid");
|
|
6
|
+
/**
|
|
7
|
+
* PK 생성 유틸리티
|
|
8
|
+
*
|
|
9
|
+
* zium-backend의 commonUtil.ts를 기반으로 작성되었습니다.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* UUID 기반 PK 생성
|
|
13
|
+
* @param convertStr 접두사 (예: "paymentLog")
|
|
14
|
+
* @returns 생성된 PK (예: "paymentLog12247a5935e18e6ce1b5225")
|
|
15
|
+
*/
|
|
16
|
+
async function makePK(convertStr) {
|
|
17
|
+
if (convertStr) {
|
|
18
|
+
const strLength = convertStr.length;
|
|
19
|
+
let makeIds = (0, uuid_1.v4)();
|
|
20
|
+
makeIds = makeIds.replace(/-/g, '');
|
|
21
|
+
return convertStr + makeIds.slice(strLength);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
return (0, uuid_1.v4)();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 지정한 길이만큼의 ID를 생성합니다
|
|
29
|
+
* @param length 생성할 총 길이 (예: 32)
|
|
30
|
+
* @param prefix 선택: 앞쪽에 붙일 접두사 (예: "order")
|
|
31
|
+
* @returns 생성된 ID
|
|
32
|
+
*/
|
|
33
|
+
async function makePKWithLength(length, prefix = '') {
|
|
34
|
+
const uuid = (0, uuid_1.v4)().replace(/-/g, '');
|
|
35
|
+
const prefixLength = prefix.length;
|
|
36
|
+
if (prefixLength >= length) {
|
|
37
|
+
return prefix.substring(0, length);
|
|
38
|
+
}
|
|
39
|
+
const randomPart = uuid.substring(0, length - prefixLength);
|
|
40
|
+
return prefix + randomPart;
|
|
41
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ApiCode } from '../constants/api-code';
|
|
2
|
+
/**
|
|
3
|
+
* 성공 응답 생성
|
|
4
|
+
* @param data 응답 데이터
|
|
5
|
+
* @returns 포맷된 응답 객체
|
|
6
|
+
*/
|
|
7
|
+
export declare function success(data: any): any;
|
|
8
|
+
/**
|
|
9
|
+
* 에러 응답 생성
|
|
10
|
+
* @param code 에러 코드
|
|
11
|
+
* @param message 커스텀 메시지 (선택사항)
|
|
12
|
+
* @returns 포맷된 에러 응답 객체
|
|
13
|
+
*/
|
|
14
|
+
export declare function error(code: number, message?: string): ApiCode;
|
|
15
|
+
/**
|
|
16
|
+
* 안전한 응답 전송 (null 처리 포함)
|
|
17
|
+
* @param data 응답 데이터
|
|
18
|
+
* @returns 처리된 응답 데이터
|
|
19
|
+
*/
|
|
20
|
+
export declare function safeResponse(data: any): any;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.success = success;
|
|
4
|
+
exports.error = error;
|
|
5
|
+
exports.safeResponse = safeResponse;
|
|
6
|
+
const api_code_1 = require("../constants/api-code");
|
|
7
|
+
/**
|
|
8
|
+
* 응답 포맷팅 유틸리티
|
|
9
|
+
*
|
|
10
|
+
* zium-backend의 commonUtil.ts를 기반으로 작성되었습니다.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* null 값을 빈 문자열로 변환 (재귀적)
|
|
14
|
+
* @param obj 변환할 객체
|
|
15
|
+
* @returns 변환된 객체
|
|
16
|
+
*/
|
|
17
|
+
function replaceNullWithEmptyString(obj) {
|
|
18
|
+
// 빈 객체는 그대로 유지
|
|
19
|
+
if (typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0) {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
// 빈 배열은 그대로 유지
|
|
23
|
+
if (Array.isArray(obj) && obj.length === 0) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
// 배열 처리 - 각 요소를 재귀적으로 처리
|
|
27
|
+
if (Array.isArray(obj)) {
|
|
28
|
+
return obj.map((item) => replaceNullWithEmptyString(item));
|
|
29
|
+
}
|
|
30
|
+
// 객체 처리 - 각 property를 재귀적으로 처리
|
|
31
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
32
|
+
const processed = Object.keys(obj).reduce((acc, key) => ({
|
|
33
|
+
...acc,
|
|
34
|
+
[key]: replaceNullWithEmptyString(obj[key]),
|
|
35
|
+
}), {});
|
|
36
|
+
return processed;
|
|
37
|
+
}
|
|
38
|
+
// null, undefined를 빈 문자열로 변환
|
|
39
|
+
if (obj === null || obj === undefined) {
|
|
40
|
+
return '';
|
|
41
|
+
}
|
|
42
|
+
// 기본값 (문자열, 숫자 등)은 그대로 반환
|
|
43
|
+
return obj;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 성공 응답 생성
|
|
47
|
+
* @param data 응답 데이터
|
|
48
|
+
* @returns 포맷된 응답 객체
|
|
49
|
+
*/
|
|
50
|
+
function success(data) {
|
|
51
|
+
const processedData = replaceNullWithEmptyString(data);
|
|
52
|
+
if (processedData.list) {
|
|
53
|
+
return {
|
|
54
|
+
...(0, api_code_1.getApiCode)(200),
|
|
55
|
+
list: processedData.list,
|
|
56
|
+
totalCount: processedData.totalCount,
|
|
57
|
+
totalPage: processedData.totalPage,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
return {
|
|
62
|
+
...(0, api_code_1.getApiCode)(200),
|
|
63
|
+
data: processedData,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 에러 응답 생성
|
|
69
|
+
* @param code 에러 코드
|
|
70
|
+
* @param message 커스텀 메시지 (선택사항)
|
|
71
|
+
* @returns 포맷된 에러 응답 객체
|
|
72
|
+
*/
|
|
73
|
+
function error(code, message) {
|
|
74
|
+
const apiCode = (0, api_code_1.getApiCode)(code);
|
|
75
|
+
return {
|
|
76
|
+
...apiCode,
|
|
77
|
+
message: message || apiCode.msg,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 안전한 응답 전송 (null 처리 포함)
|
|
82
|
+
* @param data 응답 데이터
|
|
83
|
+
* @returns 처리된 응답 데이터
|
|
84
|
+
*/
|
|
85
|
+
function safeResponse(data) {
|
|
86
|
+
return replaceNullWithEmptyString(data);
|
|
87
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 유효성 검증 유틸리티
|
|
3
|
+
*
|
|
4
|
+
* zium-backend의 commonUtil.ts를 기반으로 작성되었습니다.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* 이메일 형식 검증
|
|
8
|
+
* @param email 검증할 이메일 주소
|
|
9
|
+
* @returns 유효성 여부
|
|
10
|
+
*/
|
|
11
|
+
export declare function isEmail(email: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* 비밀번호 형식 검증
|
|
14
|
+
* - 최소 8자 이상
|
|
15
|
+
* - 영문, 숫자, 특수문자 포함 (선택사항)
|
|
16
|
+
* @param password 검증할 비밀번호
|
|
17
|
+
* @param options 검증 옵션
|
|
18
|
+
* @returns 유효성 여부
|
|
19
|
+
*/
|
|
20
|
+
export declare function isPassword(password: string, options?: {
|
|
21
|
+
minLength?: number;
|
|
22
|
+
requireUppercase?: boolean;
|
|
23
|
+
requireLowercase?: boolean;
|
|
24
|
+
requireNumber?: boolean;
|
|
25
|
+
requireSpecialChar?: boolean;
|
|
26
|
+
}): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* 휴대폰 번호 형식 검증 (한국)
|
|
29
|
+
* @param phone 검증할 휴대폰 번호
|
|
30
|
+
* @returns 유효성 여부
|
|
31
|
+
*/
|
|
32
|
+
export declare function isPhone(phone: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* 문자열이 비어있지 않은지 검증
|
|
35
|
+
* @param str 검증할 문자열
|
|
36
|
+
* @returns 유효성 여부
|
|
37
|
+
*/
|
|
38
|
+
export declare function isNotEmpty(str: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* 숫자 형식 검증
|
|
41
|
+
* @param value 검증할 값
|
|
42
|
+
* @returns 유효성 여부
|
|
43
|
+
*/
|
|
44
|
+
export declare function isNumber(value: any): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* URL 형식 검증
|
|
47
|
+
* @param url 검증할 URL
|
|
48
|
+
* @returns 유효성 여부
|
|
49
|
+
*/
|
|
50
|
+
export declare function isURL(url: string): boolean;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 유효성 검증 유틸리티
|
|
4
|
+
*
|
|
5
|
+
* zium-backend의 commonUtil.ts를 기반으로 작성되었습니다.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.isEmail = isEmail;
|
|
9
|
+
exports.isPassword = isPassword;
|
|
10
|
+
exports.isPhone = isPhone;
|
|
11
|
+
exports.isNotEmpty = isNotEmpty;
|
|
12
|
+
exports.isNumber = isNumber;
|
|
13
|
+
exports.isURL = isURL;
|
|
14
|
+
/**
|
|
15
|
+
* 이메일 형식 검증
|
|
16
|
+
* @param email 검증할 이메일 주소
|
|
17
|
+
* @returns 유효성 여부
|
|
18
|
+
*/
|
|
19
|
+
function isEmail(email) {
|
|
20
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
21
|
+
return emailRegex.test(email);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 비밀번호 형식 검증
|
|
25
|
+
* - 최소 8자 이상
|
|
26
|
+
* - 영문, 숫자, 특수문자 포함 (선택사항)
|
|
27
|
+
* @param password 검증할 비밀번호
|
|
28
|
+
* @param options 검증 옵션
|
|
29
|
+
* @returns 유효성 여부
|
|
30
|
+
*/
|
|
31
|
+
function isPassword(password, options = {}) {
|
|
32
|
+
const { minLength = 8, requireUppercase = false, requireLowercase = false, requireNumber = false, requireSpecialChar = false, } = options;
|
|
33
|
+
if (password.length < minLength) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
if (requireUppercase && !/[A-Z]/.test(password)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
if (requireLowercase && !/[a-z]/.test(password)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
if (requireNumber && !/[0-9]/.test(password)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
if (requireSpecialChar && !/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 휴대폰 번호 형식 검증 (한국)
|
|
52
|
+
* @param phone 검증할 휴대폰 번호
|
|
53
|
+
* @returns 유효성 여부
|
|
54
|
+
*/
|
|
55
|
+
function isPhone(phone) {
|
|
56
|
+
// 하이픈 포함/제외 모두 허용
|
|
57
|
+
const cleaned = phone.replace(/-/g, '');
|
|
58
|
+
const phoneRegex = /^01[0-9]{9}$/;
|
|
59
|
+
return phoneRegex.test(cleaned);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 문자열이 비어있지 않은지 검증
|
|
63
|
+
* @param str 검증할 문자열
|
|
64
|
+
* @returns 유효성 여부
|
|
65
|
+
*/
|
|
66
|
+
function isNotEmpty(str) {
|
|
67
|
+
return str !== null && str !== undefined && str.trim().length > 0;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 숫자 형식 검증
|
|
71
|
+
* @param value 검증할 값
|
|
72
|
+
* @returns 유효성 여부
|
|
73
|
+
*/
|
|
74
|
+
function isNumber(value) {
|
|
75
|
+
return !isNaN(value) && !isNaN(parseFloat(value));
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* URL 형식 검증
|
|
79
|
+
* @param url 검증할 URL
|
|
80
|
+
* @returns 유효성 여부
|
|
81
|
+
*/
|
|
82
|
+
function isURL(url) {
|
|
83
|
+
try {
|
|
84
|
+
new URL(url);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -73,3 +73,29 @@ export interface ExtendedRequest extends Request {
|
|
|
73
73
|
*/
|
|
74
74
|
export interface ExtendedResponse extends Response {
|
|
75
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* 인증된 요청 타입 (JWT 미들웨어 사용 시)
|
|
78
|
+
*/
|
|
79
|
+
export interface AuthenticatedRequest extends Request {
|
|
80
|
+
user?: {
|
|
81
|
+
id: string;
|
|
82
|
+
role?: string;
|
|
83
|
+
[key: string]: any;
|
|
84
|
+
};
|
|
85
|
+
accessToken?: {
|
|
86
|
+
id: string;
|
|
87
|
+
role?: string;
|
|
88
|
+
[key: string]: any;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* XplatSystem 인스턴스 타입
|
|
93
|
+
*/
|
|
94
|
+
export interface XplatSystemInstance {
|
|
95
|
+
app: import('../modules/app').AppModule;
|
|
96
|
+
router: import('../modules/router').RouterModule;
|
|
97
|
+
auth: import('../modules/auth').AuthModule;
|
|
98
|
+
utils: import('../modules/utils').UtilsModule;
|
|
99
|
+
middleware: import('../modules/middleware').MiddlewareModule;
|
|
100
|
+
constants: import('../modules/constants').ConstantsModule;
|
|
101
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hamjimin/xplat-back",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Express + TypeScript 백엔드 스캐폴딩 도구 (zium-backend 기반)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -34,13 +34,25 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"express": "^4.18.2",
|
|
36
36
|
"cookie-parser": "^1.4.6",
|
|
37
|
-
"cors": "^2.8.5"
|
|
37
|
+
"cors": "^2.8.5",
|
|
38
|
+
"jsonwebtoken": "^9.0.2",
|
|
39
|
+
"bcrypt": "^5.1.1",
|
|
40
|
+
"crypto-js": "^4.2.0",
|
|
41
|
+
"lodash": "^4.17.21",
|
|
42
|
+
"uuid": "^9.0.1",
|
|
43
|
+
"@aws-sdk/client-s3": "^3.922.0",
|
|
44
|
+
"@aws-sdk/s3-request-presigner": "^3.922.0"
|
|
38
45
|
},
|
|
39
46
|
"devDependencies": {
|
|
40
47
|
"@types/express": "^4.17.21",
|
|
41
48
|
"@types/node": "^20.10.0",
|
|
42
49
|
"@types/cookie-parser": "^1.4.6",
|
|
43
50
|
"@types/cors": "^2.8.17",
|
|
51
|
+
"@types/jsonwebtoken": "^9.0.5",
|
|
52
|
+
"@types/bcrypt": "^5.0.2",
|
|
53
|
+
"@types/crypto-js": "^4.2.2",
|
|
54
|
+
"@types/lodash": "^4.14.202",
|
|
55
|
+
"@types/uuid": "^9.0.8",
|
|
44
56
|
"typescript": "^5.3.3"
|
|
45
57
|
}
|
|
46
58
|
}
|