@xfilecom/core-sdk 1.3.27 → 1.3.28

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xfilecom/core-sdk",
3
- "version": "1.3.27",
3
+ "version": "1.3.28",
4
4
  "description": "Core SDK for NestJS microservices - 통합 개발 키트",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -8,7 +8,8 @@
8
8
  "build": "tsc",
9
9
  "prepublishOnly": "npm run build",
10
10
  "publish:gitlab": "node scripts/publish-to-gitlab.mjs",
11
- "test:response-format": "node scripts/test-response-format.js"
11
+ "test:response-format": "node scripts/test-response-format.js",
12
+ "test:error-format": "node scripts/test-error-format.js"
12
13
  },
13
14
  "dependencies": {
14
15
  "@nestjs/common": "^10.0.0",
@@ -0,0 +1,134 @@
1
+ /**
2
+ * 에러 응답 형식 검증: error.message는 항상 문자열 (error.message.message 중복 없음)
3
+ * ErrorUtils / ControllerHelpers와 동일한 규칙을 재현해 검증 (Nest 의존성 없이 실행)
4
+ *
5
+ * 실행: node scripts/test-error-format.js
6
+ * 또는: npm run test:error-format
7
+ *
8
+ * --- 기존(수정 전) vs 현재(수정 후) ---
9
+ *
10
+ * 기존 (error.message가 객체라서 error.message.message로 접근해야 함):
11
+ * {
12
+ * "code": 401,
13
+ * "data": [],
14
+ * "error": {
15
+ * "message": {
16
+ * "message": "이메일 또는 비밀번호가 올바르지 않습니다.",
17
+ * "error": "Unauthorized",
18
+ * "statusCode": 401
19
+ * }
20
+ * }
21
+ * }
22
+ *
23
+ * 현재 (error.message는 문자열만, 한 번에 접근):
24
+ * {
25
+ * "code": 401,
26
+ * "data": [],
27
+ * "error": {
28
+ * "message": "이메일 또는 비밀번호가 올바르지 않습니다."
29
+ * }
30
+ * }
31
+ */
32
+
33
+ function normalizeMessage(message) {
34
+ if (typeof message === 'string') return message;
35
+ if (message && typeof message === 'object' && 'message' in message) {
36
+ const m = message.message;
37
+ if (typeof m === 'string') return m;
38
+ if (Array.isArray(m) && m.length > 0 && typeof m[0] === 'string') return m[0];
39
+ }
40
+ return typeof message === 'object' ? JSON.stringify(message) : String(message);
41
+ }
42
+
43
+ function createError(code, message) {
44
+ const errorCode = code === 0 ? 500 : code;
45
+ const messageStr = normalizeMessage(message);
46
+ return { code: errorCode, data: [], error: { message: messageStr } };
47
+ }
48
+
49
+ function fromException(exception) {
50
+ if (exception && typeof exception === 'object' && 'code' in exception && 'error' in exception && 'data' in exception) {
51
+ return exception;
52
+ }
53
+ if (exception && typeof exception === 'object' && 'getStatus' in exception && 'getResponse' in exception) {
54
+ const statusCode = exception.getStatus();
55
+ const response = exception.getResponse();
56
+ const message = typeof response === 'string' ? response : (response?.message || 'Internal server error');
57
+ return createError(statusCode, message);
58
+ }
59
+ if (exception instanceof Error) {
60
+ const statusCode = exception.status ?? 500;
61
+ const message = exception.message || 'Internal server error';
62
+ return createError(statusCode, message);
63
+ }
64
+ return createError(500, 'Internal server error');
65
+ }
66
+
67
+ function assert(condition, message) {
68
+ if (!condition) {
69
+ console.error('❌ FAIL:', message);
70
+ process.exit(1);
71
+ }
72
+ console.log('✅', message);
73
+ }
74
+
75
+ console.log('\n--- error.message는 항상 문자열인지 검증 ---\n');
76
+
77
+ // 반환값 확인: 로그인 실패 같은 401 시 실제 반환되는 구조 (테스트 끝에 한 번 더 출력)
78
+ function printReturnValue(label, dto) {
79
+ console.log(`\n[반환값] ${label}`);
80
+ console.log(JSON.stringify(dto, null, 2));
81
+ console.log('');
82
+ }
83
+
84
+ // 1. createError(코드, 문자열)
85
+ const dto1 = createError(401, '이메일 또는 비밀번호가 올바르지 않습니다.');
86
+ assert(dto1.code === 401, 'createError(401, string): code 401');
87
+ assert(dto1.error && typeof dto1.error.message === 'string', 'createError(401, string): error.message는 string');
88
+ assert(dto1.error.message === '이메일 또는 비밀번호가 올바르지 않습니다.', 'createError(401, string): 메시지 내용 일치');
89
+ assert(typeof dto1.error.message !== 'object', 'createError(401, string): error.message가 객체가 아님');
90
+
91
+ // 2. createError(코드, Nest 스타일 객체)
92
+ const nestResponse = { message: 'Bad request', error: 'Unauthorized', statusCode: 401 };
93
+ const dto2 = createError(400, nestResponse);
94
+ assert(dto2.error && typeof dto2.error.message === 'string', 'createError(400, object): error.message는 string');
95
+ assert(dto2.error.message === 'Bad request', 'createError(400, object): 객체에서 message 문자열 추출');
96
+
97
+ // 3. fromException - mock HttpException (Nest getResponse() 형태)
98
+ const mockHttpException = {
99
+ getStatus: () => 401,
100
+ getResponse: () => ({
101
+ message: '이메일 또는 비밀번호가 올바르지 않습니다.',
102
+ error: 'Unauthorized',
103
+ statusCode: 401,
104
+ }),
105
+ };
106
+ const dto3 = fromException(mockHttpException);
107
+ printReturnValue('로그인 실패(401) 시 응답 body', dto3);
108
+ assert(dto3.code === 401, 'fromException(mock HttpException): code 401');
109
+ assert(dto3.error && typeof dto3.error.message === 'string', 'fromException: error.message는 string');
110
+ assert(
111
+ dto3.error.message === '이메일 또는 비밀번호가 올바르지 않습니다.',
112
+ 'fromException: error.message가 문자열로 한 단계만 노출'
113
+ );
114
+ assert(!dto3.error.message || typeof dto3.error.message !== 'object', 'fromException: error.message.message 중복 구조 없음');
115
+
116
+ // 4. fromException - 일반 Error
117
+ const dto4 = fromException(new Error('Something went wrong'));
118
+ assert(dto4.error && typeof dto4.error.message === 'string', 'fromException(Error): error.message는 string');
119
+ assert(dto4.error.message === 'Something went wrong', 'fromException(Error): 메시지 일치');
120
+
121
+ // 5. JSON 직렬화 후 파싱해도 error.message는 문자열
122
+ const json = JSON.stringify(dto3);
123
+ const parsed = JSON.parse(json);
124
+ assert(typeof parsed.error.message === 'string', 'JSON 직렬화 후에도 error.message는 string');
125
+ assert(parsed.error.message === '이메일 또는 비밀번호가 올바르지 않습니다.', 'JSON 파싱 후 메시지 유지');
126
+
127
+ // 6. 클라이언트 사용: error.message만 읽으면 됨 (error.message.message 불필요)
128
+ const clientMessage = parsed.error.message;
129
+ assert(clientMessage === '이메일 또는 비밀번호가 올바르지 않습니다.', '클라이언트: error.message 한 번에 접근');
130
+
131
+ console.log('\n--- 최종 반환값 요약 (API 응답과 동일) ---');
132
+ printReturnValue('401 예시', dto3);
133
+
134
+ console.log('✅ 모든 에러 형식 검증 통과: error.message는 항상 문자열, 중복 구조 없음\n');