@things-factory/integration-base 9.1.16 → 9.1.17
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.
|
@@ -45,6 +45,7 @@ async function executeHeadlessRequestWithRecovery(connectionName, options, conte
|
|
|
45
45
|
// 재시도 로직
|
|
46
46
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
47
47
|
try {
|
|
48
|
+
logger.info(`[Attempt ${attempt + 1}/${maxRetries + 1}] Starting request attempt`);
|
|
48
49
|
// 페이지 획득
|
|
49
50
|
const sessionResult = await acquireSessionPage();
|
|
50
51
|
// reAuthenticateSession의 반환 형태 확인
|
|
@@ -59,7 +60,6 @@ async function executeHeadlessRequestWithRecovery(connectionName, options, conte
|
|
|
59
60
|
// 초기 페이지 상태 로깅
|
|
60
61
|
const initialUrl = page.url();
|
|
61
62
|
const initialCookies = await page.cookies();
|
|
62
|
-
console.log('init page');
|
|
63
63
|
logger.info(`[Initial Page] URL: ${initialUrl}, Cookies: ${initialCookies.length}`);
|
|
64
64
|
// 로그인 페이지에 있는지 확인
|
|
65
65
|
if (initialUrl.includes('/login') || initialUrl.includes('/signin') || initialCookies.length === 0) {
|
|
@@ -76,7 +76,12 @@ async function executeHeadlessRequestWithRecovery(connectionName, options, conte
|
|
|
76
76
|
// 또는 이전 시도에서 세션 관련 에러가 발생한 경우에만 수행
|
|
77
77
|
if (attempt > 0) {
|
|
78
78
|
logger.debug(`Validating session for connection '${connectionName}' (attempt: ${attempt + 1})`);
|
|
79
|
+
// 세션 검증 전 페이지 상태 로깅
|
|
80
|
+
const preValidateUrl = page.url();
|
|
81
|
+
const preValidateCookies = await page.cookies();
|
|
82
|
+
logger.info(`[Pre-Validate] URL: ${preValidateUrl}, Cookies: ${preValidateCookies.length}`);
|
|
79
83
|
const isSessionValid = await validateSession(page);
|
|
84
|
+
logger.info(`[Validate Result] isSessionValid: ${isSessionValid}`);
|
|
80
85
|
if (!isSessionValid) {
|
|
81
86
|
logger.warn(`Session invalid for connection '${connectionName}', attempting full connection reset (attempt: ${attempt + 1})`);
|
|
82
87
|
try {
|
|
@@ -147,11 +152,11 @@ async function executeHeadlessRequestWithRecovery(connectionName, options, conte
|
|
|
147
152
|
// 요청 직전 상태 로깅
|
|
148
153
|
logger.info(`[Request] ${method} ${url.toString()}`);
|
|
149
154
|
logger.debug(`[Request] Page: ${page.url()}, Closed: ${page.isClosed()}`);
|
|
150
|
-
// 브라우저 콘솔
|
|
155
|
+
// 브라우저 콘솔 에러 캡처 (혹시 모를 예외 상황 대비)
|
|
151
156
|
consoleListener = msg => {
|
|
152
|
-
const
|
|
153
|
-
if (
|
|
154
|
-
logger.
|
|
157
|
+
const type = msg.type();
|
|
158
|
+
if (type === 'error' || type === 'warning') {
|
|
159
|
+
logger.error(`[Browser Console ${type}] ${msg.text()}`);
|
|
155
160
|
}
|
|
156
161
|
};
|
|
157
162
|
page.on('console', consoleListener);
|
|
@@ -171,16 +176,30 @@ async function executeHeadlessRequestWithRecovery(connectionName, options, conte
|
|
|
171
176
|
networkError: true
|
|
172
177
|
};
|
|
173
178
|
}
|
|
174
|
-
// 🔍 fetch 직전 디버깅 정보
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
179
|
+
// 🔍 fetch 직전 디버깅 정보 수집
|
|
180
|
+
const debugInfo = {
|
|
181
|
+
beforeFetch: {
|
|
182
|
+
targetUrl: urlString,
|
|
183
|
+
currentLocation: pageLocation,
|
|
184
|
+
cookiesCount: document.cookie ? document.cookie.split(';').length : 0,
|
|
185
|
+
hasCookies: !!document.cookie
|
|
186
|
+
}
|
|
187
|
+
};
|
|
178
188
|
const response = await fetch(urlString, { ...opts, redirect: 'manual' });
|
|
189
|
+
// 🔍 fetch 응답 디버깅 정보 추가
|
|
190
|
+
debugInfo.afterFetch = {
|
|
191
|
+
status: response.status,
|
|
192
|
+
ok: response.ok,
|
|
193
|
+
type: response.type,
|
|
194
|
+
url: response.url,
|
|
195
|
+
statusText: response.statusText
|
|
196
|
+
};
|
|
179
197
|
const result = {
|
|
180
198
|
ok: response.ok,
|
|
181
199
|
status: response.status,
|
|
182
200
|
statusText: response.statusText,
|
|
183
|
-
headers: Object.fromEntries(response.headers.entries())
|
|
201
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
202
|
+
debugInfo // 디버깅 정보 포함
|
|
184
203
|
};
|
|
185
204
|
// 302 리디렉션 감지 - 로그인 페이지로의 리디렉션 체크
|
|
186
205
|
if ([301, 302, 307, 308].includes(response.status)) {
|
|
@@ -223,7 +242,8 @@ async function executeHeadlessRequestWithRecovery(connectionName, options, conte
|
|
|
223
242
|
headers: {},
|
|
224
243
|
error: 'HTTP 0 - Network connection failed (possible CORS, SSL, or connectivity issue)',
|
|
225
244
|
data: null,
|
|
226
|
-
networkError: true
|
|
245
|
+
networkError: true,
|
|
246
|
+
debugInfo // 디버깅 정보 포함
|
|
227
247
|
};
|
|
228
248
|
}
|
|
229
249
|
if (!response.ok) {
|
|
@@ -248,9 +268,6 @@ async function executeHeadlessRequestWithRecovery(connectionName, options, conte
|
|
|
248
268
|
}
|
|
249
269
|
catch (fetchError) {
|
|
250
270
|
// 네트워크 레벨 에러 처리
|
|
251
|
-
console.error('[Browser Context] Fetch failed:', fetchError.message);
|
|
252
|
-
console.error('[Browser Context] Fetch error name:', fetchError.name);
|
|
253
|
-
console.error('[Browser Context] Fetch error stack:', fetchError.stack);
|
|
254
271
|
return {
|
|
255
272
|
ok: false,
|
|
256
273
|
status: 0,
|
|
@@ -260,7 +277,20 @@ async function executeHeadlessRequestWithRecovery(connectionName, options, conte
|
|
|
260
277
|
errorName: fetchError.name,
|
|
261
278
|
errorStack: fetchError.stack,
|
|
262
279
|
data: null,
|
|
263
|
-
networkError: true
|
|
280
|
+
networkError: true,
|
|
281
|
+
debugInfo: {
|
|
282
|
+
beforeFetch: {
|
|
283
|
+
targetUrl: urlString,
|
|
284
|
+
currentLocation: window.location.href,
|
|
285
|
+
cookiesCount: document.cookie ? document.cookie.split(';').length : 0,
|
|
286
|
+
hasCookies: !!document.cookie
|
|
287
|
+
},
|
|
288
|
+
fetchError: {
|
|
289
|
+
message: fetchError.message,
|
|
290
|
+
name: fetchError.name,
|
|
291
|
+
stack: fetchError.stack
|
|
292
|
+
}
|
|
293
|
+
}
|
|
264
294
|
};
|
|
265
295
|
}
|
|
266
296
|
}, url.toString(), requestOptions, loginPagePath);
|
|
@@ -276,7 +306,17 @@ async function executeHeadlessRequestWithRecovery(connectionName, options, conte
|
|
|
276
306
|
}
|
|
277
307
|
// 네트워크 에러 체크 (fetch 자체가 실패한 경우)
|
|
278
308
|
if (response.networkError) {
|
|
279
|
-
logger.
|
|
309
|
+
logger.error(`[Network Error] ${response.error}`);
|
|
310
|
+
// 디버깅 정보 출력
|
|
311
|
+
if (response.debugInfo) {
|
|
312
|
+
logger.info(`[Debug] Before Fetch: ${JSON.stringify(response.debugInfo.beforeFetch)}`);
|
|
313
|
+
if (response.debugInfo.afterFetch) {
|
|
314
|
+
logger.info(`[Debug] After Fetch: ${JSON.stringify(response.debugInfo.afterFetch)}`);
|
|
315
|
+
}
|
|
316
|
+
if (response.debugInfo.fetchError) {
|
|
317
|
+
logger.error(`[Debug] Fetch Exception: ${JSON.stringify(response.debugInfo.fetchError)}`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
280
320
|
if (attempt < maxRetries) {
|
|
281
321
|
logger.warn(`Network error detected: ${response.error}, retrying... (${attempt + 1}/${maxRetries + 1})`);
|
|
282
322
|
await safeReleasePageResource(pageResource, releasePage, logger);
|
|
@@ -527,9 +567,19 @@ async function performFullConnectionReset(domain, connectionName, logger, pageRe
|
|
|
527
567
|
// 기존 연결 완전 해제
|
|
528
568
|
await connector.disconnect(connectionEntity);
|
|
529
569
|
logger.info(`Connection '${connectionName}' disconnected for reset`);
|
|
570
|
+
// 브라우저 완전 종료 및 리소스 정리 대기 (중요!)
|
|
571
|
+
// 수동 재연결 시에는 자연스럽게 시간이 지나가지만,
|
|
572
|
+
// 코드에서는 즉시 연결을 시도하므로 명시적 대기 필요
|
|
573
|
+
// disconnect는 ConnectionManager에서 인스턴스만 제거하고
|
|
574
|
+
// 실제 브라우저 pool 정리에는 시간이 필요함
|
|
575
|
+
logger.info(`Waiting for browser cleanup (3 seconds)...`);
|
|
576
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
530
577
|
// 새로운 연결 생성 (완전한 초기화)
|
|
531
578
|
await connector.connect(connectionEntity);
|
|
532
579
|
logger.info(`Connection '${connectionName}' reconnected after reset`);
|
|
580
|
+
// 새 브라우저 인스턴스 초기화 대기
|
|
581
|
+
logger.info(`Waiting for new browser initialization (2 seconds)...`);
|
|
582
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
533
583
|
// 새로운 connection 인스턴스 가져오기
|
|
534
584
|
const newConnection = await connection_manager_1.ConnectionManager.getConnectionInstanceByName(domain, connectionName);
|
|
535
585
|
if (!newConnection || !newConnection.acquireSessionPage) {
|
|
@@ -546,6 +596,13 @@ async function performFullConnectionReset(domain, connectionName, logger, pageRe
|
|
|
546
596
|
newPage = newSessionResult;
|
|
547
597
|
newPageResource = { page: newPage, requiresManualRelease: false };
|
|
548
598
|
}
|
|
599
|
+
// 새 페이지 안정화 대기
|
|
600
|
+
logger.info(`Waiting for new page stabilization (1 second)...`);
|
|
601
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
602
|
+
// 페이지 상태 확인
|
|
603
|
+
const pageUrl = newPage.url();
|
|
604
|
+
const pageCookies = await newPage.cookies();
|
|
605
|
+
logger.info(`New page ready - URL: ${pageUrl}, Cookies: ${pageCookies.length}`);
|
|
549
606
|
return { pageResource: newPageResource, page: newPage };
|
|
550
607
|
}
|
|
551
608
|
//# sourceMappingURL=headless-request-with-recovery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headless-request-with-recovery.js","sourceRoot":"","sources":["../../../../server/engine/task/utils/headless-request-with-recovery.ts"],"names":[],"mappings":"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","sourcesContent":["import { access } from '@things-factory/utils'\nimport { ConnectionManager } from '../../connection-manager'\n\nexport interface HeadlessRequestOptions {\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n path: string\n headers?: Record<string, string>\n body?: any\n queryParams?: Record<string, any>\n maxRetries?: number\n accessor?: string // POST 요청에서 data 접근용\n contentType?: string // POST 요청에서 content-type 지정용\n}\n\n/**\n * 세션 회복 기능을 포함한 headless HTTP 요청 함수\n */\nexport async function executeHeadlessRequestWithRecovery(\n connectionName: string,\n options: HeadlessRequestOptions,\n context: { logger: any; data: any; domain: any }\n): Promise<any> {\n const { logger, data, domain } = context\n const { method, path, headers = {}, body, queryParams, maxRetries = 2, accessor, contentType } = options\n\n // 요청 컨텍스트 로깅 (발전소 식별을 위한 데이터 포함)\n const contextInfo = [`Connection: ${connectionName}`, `Path: ${path}`]\n\n // 발전소 식별자 추출 (디버깅용)\n if (data) {\n const identifiers = ['ICUS', 'SEL_METER_ID', 'plantId', 'siteId', 'powerPlantId']\n identifiers.forEach(key => {\n if (data[key]) {\n contextInfo.push(`${key}: ${data[key]}`)\n }\n })\n }\n\n logger.info(`[Context] ${contextInfo.join(', ')}`)\n\n // accessor가 있으면 data에서 body 추출\n let requestBody = body\n if (accessor && data) {\n requestBody = access(accessor, data)\n }\n\n const connection = await ConnectionManager.getConnectionInstanceByName(domain, connectionName)\n if (!connection) {\n throw new Error(`Connection '${connectionName}' is not established.`)\n }\n\n const {\n endpoint,\n params: connectionParams,\n acquireSessionPage,\n releasePage,\n reAuthenticateSession,\n validateSession\n } = connection\n const loginPagePath = connectionParams?.loginPagePath || '/login'\n\n // Connection 설정 로깅 (발전소별 차이 확인용)\n logger.info(`[Connection Config] Endpoint: ${endpoint}`)\n if (connectionParams?.username) {\n logger.info(`[Connection Config] Username: ${connectionParams.username}`)\n }\n\n let page = null\n let pageResource = null // 리소스 추적 객체\n let lastError = null\n let consoleListener = null // 브라우저 콘솔 리스너\n\n // 재시도 로직\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n // 페이지 획득\n const sessionResult = await acquireSessionPage()\n\n // reAuthenticateSession의 반환 형태 확인\n if (sessionResult && typeof sessionResult === 'object' && sessionResult.page) {\n pageResource = sessionResult // {page, browser, requiresManualRelease}\n page = sessionResult.page\n } else {\n page = sessionResult\n pageResource = { page, requiresManualRelease: false }\n }\n\n // 초기 페이지 상태 로깅\n const initialUrl = page.url()\n const initialCookies = await page.cookies()\n console.log('init page')\n logger.info(`[Initial Page] URL: ${initialUrl}, Cookies: ${initialCookies.length}`)\n\n // 로그인 페이지에 있는지 확인\n if (initialUrl.includes('/login') || initialUrl.includes('/signin') || initialCookies.length === 0) {\n logger.error(`[Login Failed] Still on login page or no cookies! URL: ${initialUrl}`)\n }\n\n // 페이지가 올바른 도메인에 있는지 확인\n const currentUrl = page.url()\n const targetDomain = new URL(endpoint).origin\n if (!currentUrl.startsWith(targetDomain)) {\n logger.info(`Navigating to target domain: ${targetDomain}`)\n await page.goto(targetDomain, { waitUntil: 'networkidle2' })\n }\n\n // 세션 검증은 2번째 시도부터만 수행 (첫 번째는 새 페이지이므로 불필요)\n // 또는 이전 시도에서 세션 관련 에러가 발생한 경우에만 수행\n if (attempt > 0) {\n logger.debug(`Validating session for connection '${connectionName}' (attempt: ${attempt + 1})`)\n const isSessionValid = await validateSession(page)\n if (!isSessionValid) {\n logger.warn(\n `Session invalid for connection '${connectionName}', attempting full connection reset (attempt: ${attempt + 1})`\n )\n\n try {\n const resetResult = await performFullConnectionReset(\n domain,\n connectionName,\n logger,\n pageResource,\n releasePage\n )\n pageResource = resetResult.pageResource\n page = resetResult.page\n\n // 재연결 후 페이지 완전 준비 대기\n await page\n .waitForFunction(() => document.readyState === 'complete', { timeout: 10000 })\n .catch(() => logger.warn('Page readyState timeout'))\n\n // JavaScript 초기화를 위한 추가 대기 (핵심 해결책)\n await new Promise(resolve => setTimeout(resolve, 2000))\n\n // 페이지 상태 확인\n const resetUrl = page.url()\n const cookies = await page.cookies()\n\n logger.info(`[Reset Success] URL: ${resetUrl}, Cookies: ${cookies.length}`)\n\n // about:blank 체크\n if (resetUrl === 'about:blank') {\n throw new Error('Page stuck on about:blank after reset')\n }\n } catch (resetError) {\n logger.error(`Connection reset failed for connection '${connectionName}':`, resetError)\n // 재설정 실패 시 이번 시도는 실패로 처리하고 다음 시도로 넘어감\n if (attempt === maxRetries) {\n throw new Error(`Connection reset failed after ${maxRetries + 1} attempts: ${resetError.message}`)\n }\n continue\n }\n }\n }\n\n // URL 구성\n const url = new URL(path, endpoint)\n if (queryParams && typeof queryParams === 'object') {\n Object.keys(queryParams).forEach(key => {\n if (queryParams[key] !== null && queryParams[key] !== undefined) {\n url.searchParams.append(key, String(queryParams[key]))\n }\n })\n }\n\n // 요청 옵션 구성\n const requestOptions: any = {\n method,\n headers: {\n ...headers\n },\n credentials: 'include'\n }\n\n // Content-Type과 body 처리\n if (requestBody && ['POST', 'PUT', 'PATCH'].includes(method)) {\n if (contentType) {\n requestOptions.headers['content-type'] = contentType\n switch (contentType) {\n case 'text/plain':\n requestOptions.body = JSON.stringify(requestBody)\n break\n case 'application/json':\n default:\n requestOptions.body = typeof requestBody === 'string' ? requestBody : JSON.stringify(requestBody)\n break\n }\n } else {\n requestOptions.headers['Content-Type'] = 'application/json'\n requestOptions.body = typeof requestBody === 'string' ? requestBody : JSON.stringify(requestBody)\n }\n }\n\n // 요청 직전 상태 로깅\n logger.info(`[Request] ${method} ${url.toString()}`)\n logger.debug(`[Request] Page: ${page.url()}, Closed: ${page.isClosed()}`)\n\n // 브라우저 콘솔 메시지 캡처 (디버깅용)\n consoleListener = msg => {\n const text = msg.text()\n if (text.includes('[Browser Context]')) {\n logger.info(`[Browser] ${text}`)\n }\n }\n page.on('console', consoleListener)\n\n const response = await page.evaluate(\n async (urlString, opts, loginPagePath) => {\n try {\n // 페이지 상태 검증 (about:blank 또는 로딩 중인 페이지에서 fetch 방지)\n const pageLocation = window.location.href\n const pageReadyState = document.readyState\n\n if (pageLocation === 'about:blank' || pageReadyState !== 'complete') {\n return {\n ok: false,\n status: 0,\n statusText: 'Page Not Ready',\n headers: {},\n error: `Page state invalid - location: ${pageLocation}, readyState: ${pageReadyState}`,\n data: null,\n networkError: true\n }\n }\n\n // 🔍 fetch 직전 디버깅 정보\n console.log('[Browser Context] About to fetch:', urlString)\n console.log('[Browser Context] Current location:', pageLocation)\n console.log('[Browser Context] Cookies:', document.cookie)\n\n const response = await fetch(urlString, { ...opts, redirect: 'manual' })\n\n const result = {\n ok: response.ok,\n status: response.status,\n statusText: response.statusText,\n headers: Object.fromEntries(response.headers.entries())\n }\n\n // 302 리디렉션 감지 - 로그인 페이지로의 리디렉션 체크\n if ([301, 302, 307, 308].includes(response.status)) {\n const location = response.headers.get('location') || ''\n // connection의 loginPagePath와 일반적인 로그인 경로들을 체크\n if (\n location.includes(loginPagePath) ||\n location.includes('/login') ||\n location.includes('/signin') ||\n location.includes('/auth')\n ) {\n return {\n ...result,\n error: `Redirected to login page: ${location}`,\n redirectedToLogin: true,\n location,\n data: null\n }\n }\n // 다른 리디렉션은 follow\n const redirectResponse = await fetch(urlString, opts)\n return {\n ok: redirectResponse.ok,\n status: redirectResponse.status,\n statusText: redirectResponse.statusText,\n headers: Object.fromEntries(redirectResponse.headers.entries()),\n data: redirectResponse.ok\n ? await redirectResponse\n .json()\n .catch(() => redirectResponse.text())\n .catch(() => null)\n : null,\n error: redirectResponse.ok ? null : `HTTP ${redirectResponse.status}: ${redirectResponse.statusText}`\n }\n }\n\n // status가 0인 경우는 네트워크 레벨 에러 (CORS, 연결 실패 등)\n if (response.status === 0) {\n return {\n ok: false,\n status: 0,\n statusText: response.statusText || 'Network Error',\n headers: {},\n error: 'HTTP 0 - Network connection failed (possible CORS, SSL, or connectivity issue)',\n data: null,\n networkError: true\n }\n }\n\n if (!response.ok) {\n return {\n ...result,\n error: `HTTP ${response.status}: ${response.statusText}`,\n data: null\n }\n }\n\n const contentType = response.headers.get('content-type') || ''\n\n if (contentType.includes('application/json')) {\n result['data'] = await response.json()\n } else if (contentType.includes('text/')) {\n result['data'] = await response.text()\n } else {\n // 응답이 없는 경우 (204 No Content 등)\n result['data'] = null\n }\n\n return result\n } catch (fetchError) {\n // 네트워크 레벨 에러 처리\n console.error('[Browser Context] Fetch failed:', fetchError.message)\n console.error('[Browser Context] Fetch error name:', fetchError.name)\n console.error('[Browser Context] Fetch error stack:', fetchError.stack)\n\n return {\n ok: false,\n status: 0,\n statusText: 'Network Error',\n headers: {},\n error: fetchError.message || 'Failed to fetch',\n errorName: fetchError.name,\n errorStack: fetchError.stack,\n data: null,\n networkError: true\n }\n }\n },\n url.toString(),\n requestOptions,\n loginPagePath\n )\n\n // 브라우저 콘솔 리스너 제거\n if (consoleListener && page && !page.isClosed()) {\n try {\n page.off('console', consoleListener)\n consoleListener = null\n } catch (e) {\n // 리스너 제거 실패는 무시\n }\n }\n\n // 네트워크 에러 체크 (fetch 자체가 실패한 경우)\n if (response.networkError) {\n logger.info(`[networkError ERROR] response: ${JSON.stringify(response)}`)\n\n if (attempt < maxRetries) {\n logger.warn(`Network error detected: ${response.error}, retrying... (${attempt + 1}/${maxRetries + 1})`)\n await safeReleasePageResource(pageResource, releasePage, logger)\n page = null\n pageResource = null\n continue\n } else {\n await safeReleasePageResource(pageResource, releasePage, logger)\n throw new Error(`Network error after ${maxRetries + 1} attempts: ${response.error}`)\n }\n }\n\n // 로그인 리디렉션 감지 처리\n if (response.redirectedToLogin) {\n if (attempt < maxRetries) {\n logger.warn(\n `Login redirect detected: ${response.location}, performing full connection reset... (${attempt + 1}/${maxRetries + 1})`\n )\n\n // CRITICAL: 커넥션 재연결 방식으로 완전한 초기화\n try {\n const resetResult = await performFullConnectionReset(\n domain,\n connectionName,\n logger,\n pageResource,\n releasePage\n )\n pageResource = resetResult.pageResource\n page = resetResult.page\n\n // 재연결 후 페이지 완전 준비 대기\n await page\n .waitForFunction(() => document.readyState === 'complete', { timeout: 10000 })\n .catch(() => logger.warn('Page readyState timeout'))\n\n // JavaScript 초기화를 위한 추가 대기\n await new Promise(resolve => setTimeout(resolve, 2000))\n\n // 페이지 상태 확인\n const resetUrl = page.url()\n const cookies = await page.cookies()\n\n logger.info(`[Reset Success] URL: ${resetUrl}, Cookies: ${cookies.length}`)\n\n // about:blank 체크\n if (resetUrl === 'about:blank') {\n throw new Error('Page stuck on about:blank after reset')\n }\n } catch (resetError) {\n logger.error(`Connection reset failed after login redirect for connection '${connectionName}':`, resetError)\n if (attempt === maxRetries) {\n throw new Error(`Connection reset failed after login redirect: ${resetError.message}`)\n }\n continue\n }\n continue\n } else {\n await safeReleasePageResource(pageResource, releasePage, logger)\n throw new Error(`Login redirect after ${maxRetries + 1} attempts: ${response.error}`)\n }\n }\n\n // 세션 타임아웃 관련 에러 체크\n if (!response.ok && isSessionTimeoutError(response.status)) {\n if (attempt < maxRetries) {\n logger.warn(\n `Session timeout detected (${response.status}), performing full connection reset... (${attempt + 1}/${maxRetries + 1})`\n )\n\n // CRITICAL: 커넥션 재연결 방식으로 완전한 초기화\n try {\n const resetResult = await performFullConnectionReset(\n domain,\n connectionName,\n logger,\n pageResource,\n releasePage\n )\n pageResource = resetResult.pageResource\n page = resetResult.page\n\n // 재연결 후 페이지 완전 준비 대기\n await page\n .waitForFunction(() => document.readyState === 'complete', { timeout: 10000 })\n .catch(() => logger.warn('Page readyState timeout'))\n\n // JavaScript 초기화를 위한 추가 대기\n await new Promise(resolve => setTimeout(resolve, 2000))\n\n // 페이지 상태 확인\n const resetUrl = page.url()\n const cookies = await page.cookies()\n\n logger.info(`[Reset Success] URL: ${resetUrl}, Cookies: ${cookies.length}`)\n\n // about:blank 체크\n if (resetUrl === 'about:blank') {\n throw new Error('Page stuck on about:blank after reset')\n }\n } catch (resetError) {\n logger.error(\n `Connection reset failed after session timeout for connection '${connectionName}':`,\n resetError\n )\n if (attempt === maxRetries) {\n throw new Error(`Connection reset failed after session timeout: ${resetError.message}`)\n }\n continue\n }\n continue\n } else {\n await safeReleasePageResource(pageResource, releasePage, logger)\n throw new Error(`Session timeout after ${maxRetries + 1} attempts: ${response.error}`)\n }\n }\n\n // 기타 HTTP 에러\n if (!response.ok) {\n throw new Error(response.error)\n }\n\n // 성공 시 페이지 릴리즈 후 결과 반환\n if (consoleListener && page && !page.isClosed()) {\n try {\n page.off('console', consoleListener)\n consoleListener = null\n } catch (e) {\n // 리스너 제거 실패는 무시\n }\n }\n\n const result = {\n data: response.data,\n status: response.status,\n headers: response.headers\n }\n\n await safeReleasePageResource(pageResource, releasePage, logger)\n\n return result\n } catch (error) {\n lastError = error\n logger.error(`Headless request attempt ${attempt + 1} failed:`, error)\n\n if (consoleListener && page && !page.isClosed()) {\n try {\n page.off('console', consoleListener)\n consoleListener = null\n } catch (e) {\n // 리스너 제거 실패는 무시\n }\n }\n\n await safeReleasePageResource(pageResource, releasePage, logger)\n page = null\n pageResource = null\n\n // 세션 관련 에러가 아니거나 마지막 재시도면 에러 발생\n if (!isRecoverableError(error) || attempt === maxRetries) {\n throw error\n }\n\n logger.info(`Retrying request... (${attempt + 2}/${maxRetries + 1})`)\n }\n }\n\n // 모든 재시도가 실패한 경우 - 혹시 남은 리소스가 있으면 정리\n if (pageResource) {\n await safeReleasePageResource(pageResource, releasePage, logger)\n }\n throw lastError || new Error('Request failed after all retry attempts')\n}\n\n/**\n * 세션 타임아웃 관련 HTTP 상태 코드인지 확인\n */\nfunction isSessionTimeoutError(statusCode: number): boolean {\n return [401, 403].includes(statusCode)\n}\n\n/**\n * 복구 가능한 에러인지 확인\n */\nfunction isRecoverableError(error: any): boolean {\n const errorMessage = error.message?.toLowerCase() || ''\n\n // 복구 가능한 에러 키워드 (네트워크, 세션/인증 관련)\n const recoverableErrorKeywords = [\n 'failed to fetch',\n 'network error',\n 'connection failed',\n 'connection reset',\n 'timeout',\n 'timed out',\n 'unauthorized',\n 'forbidden',\n 'session',\n 'authentication',\n 'login',\n 'expired',\n 'redirected to login' // 로그인 리디렉션 추가\n ]\n\n return recoverableErrorKeywords.some(keyword => errorMessage.includes(keyword))\n}\n\n/**\n * Safely release page resource with comprehensive error handling\n */\nexport async function safeReleasePageResource(pageResource: any, releasePage: Function, logger: any): Promise<void> {\n if (!pageResource) {\n return\n }\n\n try {\n // Handle different pageResource formats\n if (pageResource.page) {\n // This is a complex resource object {page, browser, requiresManualRelease}\n const { page, browser, requiresManualRelease } = pageResource\n\n if (requiresManualRelease && browser) {\n // Manual release required - close page first, then release browser\n try {\n if (page && !page.isClosed()) {\n await page.close()\n logger.info('Page closed during manual resource release')\n }\n } catch (closeError) {\n logger.error('Failed to close page during manual release:', closeError)\n }\n\n // Release browser back to pool\n try {\n const { getHeadlessPool } = require('../../resource-pool/headless-pool')\n const pool = getHeadlessPool()\n await pool.release(browser)\n logger.info('Browser manually released to pool')\n } catch (releaseError) {\n logger.error('Failed to manually release browser to pool:', releaseError)\n }\n } else {\n // Standard release through releasePage\n await releasePage(page)\n logger.info('Page released through standard releasePage method')\n }\n } else {\n // Simple page object - use standard release\n await releasePage(pageResource)\n logger.info('Simple page resource released')\n }\n } catch (error) {\n logger.error('Critical error during page resource release:', error)\n\n // Last resort: try to force close the page if it exists\n try {\n const page = pageResource.page || pageResource\n if (page && !page.isClosed()) {\n await page.close()\n logger.warn('Force closed page as last resort')\n }\n } catch (forceCloseError) {\n logger.error('Failed to force close page:', forceCloseError)\n }\n }\n}\n\n/**\n * 커넥션을 완전 재초기화하는 함수\n * 세션 만료 시 커넥션 재연결과 동일한 완전한 초기화를 수행\n */\nasync function performFullConnectionReset(\n domain: any,\n connectionName: string,\n logger: any,\n pageResource: any,\n releasePage: Function\n): Promise<{ pageResource: any; page: any }> {\n // 기존 페이지 리소스 해제\n await safeReleasePageResource(pageResource, releasePage, logger)\n\n // 커넥션 엔티티 가져오기\n const connectionEntity = await ConnectionManager.getConnectionEntityByName(domain, connectionName)\n if (!connectionEntity) {\n throw new Error('Connection entity not found for reset')\n }\n\n // Connector를 직접 사용하여 연결 재설정\n const { type, edge } = connectionEntity\n const ProxyConnector = require('../../connector/proxy-connector').ProxyConnector\n const connector = edge ? ProxyConnector.instance : ConnectionManager.getConnector(type)\n\n if (!connector) {\n throw new Error(`Connector not found for type: ${type}`)\n }\n\n // 기존 연결 완전 해제\n await connector.disconnect(connectionEntity)\n logger.info(`Connection '${connectionName}' disconnected for reset`)\n\n // 새로운 연결 생성 (완전한 초기화)\n await connector.connect(connectionEntity)\n logger.info(`Connection '${connectionName}' reconnected after reset`)\n\n // 새로운 connection 인스턴스 가져오기\n const newConnection = await ConnectionManager.getConnectionInstanceByName(domain, connectionName)\n if (!newConnection || !newConnection.acquireSessionPage) {\n throw new Error('Failed to acquire session page after connection reset')\n }\n\n const newSessionResult = await newConnection.acquireSessionPage()\n let newPageResource: any\n let newPage: any\n\n if (newSessionResult && typeof newSessionResult === 'object' && newSessionResult.page) {\n newPageResource = newSessionResult\n newPage = newSessionResult.page\n } else {\n newPage = newSessionResult\n newPageResource = { page: newPage, requiresManualRelease: false }\n }\n\n return { pageResource: newPageResource, page: newPage }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"headless-request-with-recovery.js","sourceRoot":"","sources":["../../../../server/engine/task/utils/headless-request-with-recovery.ts"],"names":[],"mappings":";;AAiBA,gFAkiBC;AAsCD,0DAuDC;AAhpBD,iDAA8C;AAC9C,iEAA4D;AAa5D;;GAEG;AACI,KAAK,UAAU,kCAAkC,CACtD,cAAsB,EACtB,OAA+B,EAC/B,OAAgD;IAEhD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IACxC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,GAAG,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,OAAO,CAAA;IAExG,iCAAiC;IACjC,MAAM,WAAW,GAAG,CAAC,eAAe,cAAc,EAAE,EAAE,SAAS,IAAI,EAAE,CAAC,CAAA;IAEtE,oBAAoB;IACpB,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAA;QACjF,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;YACxB,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACd,WAAW,CAAC,IAAI,CAAC,GAAG,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YAC1C,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,aAAa,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAElD,+BAA+B;IAC/B,IAAI,WAAW,GAAG,IAAI,CAAA;IACtB,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;QACrB,WAAW,GAAG,IAAA,cAAM,EAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;IACtC,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,sCAAiB,CAAC,2BAA2B,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IAC9F,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,eAAe,cAAc,uBAAuB,CAAC,CAAA;IACvE,CAAC;IAED,MAAM,EACJ,QAAQ,EACR,MAAM,EAAE,gBAAgB,EACxB,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,eAAe,EAChB,GAAG,UAAU,CAAA;IACd,MAAM,aAAa,GAAG,gBAAgB,EAAE,aAAa,IAAI,QAAQ,CAAA;IAEjE,iCAAiC;IACjC,MAAM,CAAC,IAAI,CAAC,iCAAiC,QAAQ,EAAE,CAAC,CAAA;IACxD,IAAI,gBAAgB,EAAE,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,iCAAiC,gBAAgB,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC3E,CAAC;IAED,IAAI,IAAI,GAAG,IAAI,CAAA;IACf,IAAI,YAAY,GAAG,IAAI,CAAA,CAAC,YAAY;IACpC,IAAI,SAAS,GAAG,IAAI,CAAA;IACpB,IAAI,eAAe,GAAG,IAAI,CAAA,CAAC,cAAc;IAEzC,SAAS;IACT,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,YAAY,OAAO,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,4BAA4B,CAAC,CAAA;YAElF,SAAS;YACT,MAAM,aAAa,GAAG,MAAM,kBAAkB,EAAE,CAAA;YAEhD,kCAAkC;YAClC,IAAI,aAAa,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,CAAC,IAAI,EAAE,CAAC;gBAC7E,YAAY,GAAG,aAAa,CAAA,CAAC,yCAAyC;gBACtE,IAAI,GAAG,aAAa,CAAC,IAAI,CAAA;YAC3B,CAAC;iBAAM,CAAC;gBACN,IAAI,GAAG,aAAa,CAAA;gBACpB,YAAY,GAAG,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAA;YACvD,CAAC;YAED,eAAe;YACf,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YAC7B,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;YAC3C,MAAM,CAAC,IAAI,CAAC,uBAAuB,UAAU,cAAc,cAAc,CAAC,MAAM,EAAE,CAAC,CAAA;YAEnF,kBAAkB;YAClB,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACnG,MAAM,CAAC,KAAK,CAAC,0DAA0D,UAAU,EAAE,CAAC,CAAA;YACtF,CAAC;YAED,uBAAuB;YACvB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YAC7B,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAA;YAC7C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;gBACzC,MAAM,CAAC,IAAI,CAAC,gCAAgC,YAAY,EAAE,CAAC,CAAA;gBAC3D,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,CAAA;YAC9D,CAAC;YAED,2CAA2C;YAC3C,mCAAmC;YACnC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;gBAChB,MAAM,CAAC,KAAK,CAAC,sCAAsC,cAAc,eAAe,OAAO,GAAG,CAAC,GAAG,CAAC,CAAA;gBAE/F,oBAAoB;gBACpB,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;gBACjC,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;gBAC/C,MAAM,CAAC,IAAI,CAAC,uBAAuB,cAAc,cAAc,kBAAkB,CAAC,MAAM,EAAE,CAAC,CAAA;gBAE3F,MAAM,cAAc,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAA;gBAClD,MAAM,CAAC,IAAI,CAAC,qCAAqC,cAAc,EAAE,CAAC,CAAA;gBAElE,IAAI,CAAC,cAAc,EAAE,CAAC;oBACpB,MAAM,CAAC,IAAI,CACT,mCAAmC,cAAc,iDAAiD,OAAO,GAAG,CAAC,GAAG,CACjH,CAAA;oBAED,IAAI,CAAC;wBACH,MAAM,WAAW,GAAG,MAAM,0BAA0B,CAClD,MAAM,EACN,cAAc,EACd,MAAM,EACN,YAAY,EACZ,WAAW,CACZ,CAAA;wBACD,YAAY,GAAG,WAAW,CAAC,YAAY,CAAA;wBACvC,IAAI,GAAG,WAAW,CAAC,IAAI,CAAA;wBAEvB,qBAAqB;wBACrB,MAAM,IAAI;6BACP,eAAe,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,KAAK,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;6BAC7E,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAA;wBAEtD,oCAAoC;wBACpC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA;wBAEvD,YAAY;wBACZ,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;wBAC3B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;wBAEpC,MAAM,CAAC,IAAI,CAAC,wBAAwB,QAAQ,cAAc,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;wBAE3E,iBAAiB;wBACjB,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;4BAC/B,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;wBAC1D,CAAC;oBACH,CAAC;oBAAC,OAAO,UAAU,EAAE,CAAC;wBACpB,MAAM,CAAC,KAAK,CAAC,2CAA2C,cAAc,IAAI,EAAE,UAAU,CAAC,CAAA;wBACvF,sCAAsC;wBACtC,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;4BAC3B,MAAM,IAAI,KAAK,CAAC,iCAAiC,UAAU,GAAG,CAAC,cAAc,UAAU,CAAC,OAAO,EAAE,CAAC,CAAA;wBACpG,CAAC;wBACD,SAAQ;oBACV,CAAC;gBACH,CAAC;YACH,CAAC;YAED,SAAS;YACT,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;YACnC,IAAI,WAAW,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;gBACnD,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;oBACrC,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;wBAChE,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;oBACxD,CAAC;gBACH,CAAC,CAAC,CAAA;YACJ,CAAC;YAED,WAAW;YACX,MAAM,cAAc,GAAQ;gBAC1B,MAAM;gBACN,OAAO,EAAE;oBACP,GAAG,OAAO;iBACX;gBACD,WAAW,EAAE,SAAS;aACvB,CAAA;YAED,wBAAwB;YACxB,IAAI,WAAW,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC7D,IAAI,WAAW,EAAE,CAAC;oBAChB,cAAc,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,WAAW,CAAA;oBACpD,QAAQ,WAAW,EAAE,CAAC;wBACpB,KAAK,YAAY;4BACf,cAAc,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;4BACjD,MAAK;wBACP,KAAK,kBAAkB,CAAC;wBACxB;4BACE,cAAc,CAAC,IAAI,GAAG,OAAO,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;4BACjG,MAAK;oBACT,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,cAAc,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAA;oBAC3D,cAAc,CAAC,IAAI,GAAG,OAAO,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;gBACnG,CAAC;YACH,CAAC;YAED,cAAc;YACd,MAAM,CAAC,IAAI,CAAC,aAAa,MAAM,IAAI,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;YACpD,MAAM,CAAC,KAAK,CAAC,mBAAmB,IAAI,CAAC,GAAG,EAAE,aAAa,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;YAEzE,iCAAiC;YACjC,eAAe,GAAG,GAAG,CAAC,EAAE;gBACtB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;gBACvB,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;oBAC3C,MAAM,CAAC,KAAK,CAAC,oBAAoB,IAAI,KAAK,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;gBACzD,CAAC;YACH,CAAC,CAAA;YACD,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,eAAe,CAAC,CAAA;YAEnC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAClC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE;gBACvC,IAAI,CAAC;oBACH,kDAAkD;oBAClD,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAA;oBACzC,MAAM,cAAc,GAAG,QAAQ,CAAC,UAAU,CAAA;oBAE1C,IAAI,YAAY,KAAK,aAAa,IAAI,cAAc,KAAK,UAAU,EAAE,CAAC;wBACpE,OAAO;4BACL,EAAE,EAAE,KAAK;4BACT,MAAM,EAAE,CAAC;4BACT,UAAU,EAAE,gBAAgB;4BAC5B,OAAO,EAAE,EAAE;4BACX,KAAK,EAAE,kCAAkC,YAAY,iBAAiB,cAAc,EAAE;4BACtF,IAAI,EAAE,IAAI;4BACV,YAAY,EAAE,IAAI;yBACnB,CAAA;oBACH,CAAC;oBAED,wBAAwB;oBACxB,MAAM,SAAS,GAAQ;wBACrB,WAAW,EAAE;4BACX,SAAS,EAAE,SAAS;4BACpB,eAAe,EAAE,YAAY;4BAC7B,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;4BACrE,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM;yBAC9B;qBACF,CAAA;oBAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAA;oBAExE,wBAAwB;oBACxB,SAAS,CAAC,UAAU,GAAG;wBACrB,MAAM,EAAE,QAAQ,CAAC,MAAM;wBACvB,EAAE,EAAE,QAAQ,CAAC,EAAE;wBACf,IAAI,EAAE,QAAQ,CAAC,IAAI;wBACnB,GAAG,EAAE,QAAQ,CAAC,GAAG;wBACjB,UAAU,EAAE,QAAQ,CAAC,UAAU;qBAChC,CAAA;oBAED,MAAM,MAAM,GAAG;wBACb,EAAE,EAAE,QAAQ,CAAC,EAAE;wBACf,MAAM,EAAE,QAAQ,CAAC,MAAM;wBACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;wBAC/B,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;wBACvD,SAAS,CAAC,YAAY;qBACvB,CAAA;oBAED,kCAAkC;oBAClC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;wBACnD,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAA;wBACvD,8CAA8C;wBAC9C,IACE,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC;4BAChC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;4BAC3B,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;4BAC5B,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAC1B,CAAC;4BACD,OAAO;gCACL,GAAG,MAAM;gCACT,KAAK,EAAE,6BAA6B,QAAQ,EAAE;gCAC9C,iBAAiB,EAAE,IAAI;gCACvB,QAAQ;gCACR,IAAI,EAAE,IAAI;6BACX,CAAA;wBACH,CAAC;wBACD,kBAAkB;wBAClB,MAAM,gBAAgB,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;wBACrD,OAAO;4BACL,EAAE,EAAE,gBAAgB,CAAC,EAAE;4BACvB,MAAM,EAAE,gBAAgB,CAAC,MAAM;4BAC/B,UAAU,EAAE,gBAAgB,CAAC,UAAU;4BACvC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;4BAC/D,IAAI,EAAE,gBAAgB,CAAC,EAAE;gCACvB,CAAC,CAAC,MAAM,gBAAgB;qCACnB,IAAI,EAAE;qCACN,KAAK,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC;qCACpC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;gCACtB,CAAC,CAAC,IAAI;4BACR,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,gBAAgB,CAAC,MAAM,KAAK,gBAAgB,CAAC,UAAU,EAAE;yBACtG,CAAA;oBACH,CAAC;oBAED,4CAA4C;oBAC5C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBAC1B,OAAO;4BACL,EAAE,EAAE,KAAK;4BACT,MAAM,EAAE,CAAC;4BACT,UAAU,EAAE,QAAQ,CAAC,UAAU,IAAI,eAAe;4BAClD,OAAO,EAAE,EAAE;4BACX,KAAK,EAAE,gFAAgF;4BACvF,IAAI,EAAE,IAAI;4BACV,YAAY,EAAE,IAAI;4BAClB,SAAS,CAAC,YAAY;yBACvB,CAAA;oBACH,CAAC;oBAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;wBACjB,OAAO;4BACL,GAAG,MAAM;4BACT,KAAK,EAAE,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE;4BACxD,IAAI,EAAE,IAAI;yBACX,CAAA;oBACH,CAAC;oBAED,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAA;oBAE9D,IAAI,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;wBAC7C,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;oBACxC,CAAC;yBAAM,IAAI,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;wBACzC,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;oBACxC,CAAC;yBAAM,CAAC;wBACN,+BAA+B;wBAC/B,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAA;oBACvB,CAAC;oBAED,OAAO,MAAM,CAAA;gBACf,CAAC;gBAAC,OAAO,UAAU,EAAE,CAAC;oBACpB,gBAAgB;oBAChB,OAAO;wBACL,EAAE,EAAE,KAAK;wBACT,MAAM,EAAE,CAAC;wBACT,UAAU,EAAE,eAAe;wBAC3B,OAAO,EAAE,EAAE;wBACX,KAAK,EAAE,UAAU,CAAC,OAAO,IAAI,iBAAiB;wBAC9C,SAAS,EAAE,UAAU,CAAC,IAAI;wBAC1B,UAAU,EAAE,UAAU,CAAC,KAAK;wBAC5B,IAAI,EAAE,IAAI;wBACV,YAAY,EAAE,IAAI;wBAClB,SAAS,EAAE;4BACT,WAAW,EAAE;gCACX,SAAS,EAAE,SAAS;gCACpB,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI;gCACrC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gCACrE,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM;6BAC9B;4BACD,UAAU,EAAE;gCACV,OAAO,EAAE,UAAU,CAAC,OAAO;gCAC3B,IAAI,EAAE,UAAU,CAAC,IAAI;gCACrB,KAAK,EAAE,UAAU,CAAC,KAAK;6BACxB;yBACF;qBACF,CAAA;gBACH,CAAC;YACH,CAAC,EACD,GAAG,CAAC,QAAQ,EAAE,EACd,cAAc,EACd,aAAa,CACd,CAAA;YAED,iBAAiB;YACjB,IAAI,eAAe,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAChD,IAAI,CAAC;oBACH,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,eAAe,CAAC,CAAA;oBACpC,eAAe,GAAG,IAAI,CAAA;gBACxB,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,gBAAgB;gBAClB,CAAC;YACH,CAAC;YAED,gCAAgC;YAChC,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;gBAC1B,MAAM,CAAC,KAAK,CAAC,mBAAmB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;gBAEjD,YAAY;gBACZ,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;oBACvB,MAAM,CAAC,IAAI,CAAC,yBAAyB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;oBACtF,IAAI,QAAQ,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;wBAClC,MAAM,CAAC,IAAI,CAAC,wBAAwB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;oBACtF,CAAC;oBACD,IAAI,QAAQ,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;wBAClC,MAAM,CAAC,KAAK,CAAC,4BAA4B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;oBAC3F,CAAC;gBACH,CAAC;gBAED,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;oBACzB,MAAM,CAAC,IAAI,CAAC,2BAA2B,QAAQ,CAAC,KAAK,kBAAkB,OAAO,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,GAAG,CAAC,CAAA;oBACxG,MAAM,uBAAuB,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;oBAChE,IAAI,GAAG,IAAI,CAAA;oBACX,YAAY,GAAG,IAAI,CAAA;oBACnB,SAAQ;gBACV,CAAC;qBAAM,CAAC;oBACN,MAAM,uBAAuB,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;oBAChE,MAAM,IAAI,KAAK,CAAC,uBAAuB,UAAU,GAAG,CAAC,cAAc,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;gBACtF,CAAC;YACH,CAAC;YAED,iBAAiB;YACjB,IAAI,QAAQ,CAAC,iBAAiB,EAAE,CAAC;gBAC/B,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;oBACzB,MAAM,CAAC,IAAI,CACT,4BAA4B,QAAQ,CAAC,QAAQ,0CAA0C,OAAO,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,GAAG,CACxH,CAAA;oBAED,iCAAiC;oBACjC,IAAI,CAAC;wBACH,MAAM,WAAW,GAAG,MAAM,0BAA0B,CAClD,MAAM,EACN,cAAc,EACd,MAAM,EACN,YAAY,EACZ,WAAW,CACZ,CAAA;wBACD,YAAY,GAAG,WAAW,CAAC,YAAY,CAAA;wBACvC,IAAI,GAAG,WAAW,CAAC,IAAI,CAAA;wBAEvB,qBAAqB;wBACrB,MAAM,IAAI;6BACP,eAAe,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,KAAK,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;6BAC7E,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAA;wBAEtD,2BAA2B;wBAC3B,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA;wBAEvD,YAAY;wBACZ,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;wBAC3B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;wBAEpC,MAAM,CAAC,IAAI,CAAC,wBAAwB,QAAQ,cAAc,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;wBAE3E,iBAAiB;wBACjB,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;4BAC/B,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;wBAC1D,CAAC;oBACH,CAAC;oBAAC,OAAO,UAAU,EAAE,CAAC;wBACpB,MAAM,CAAC,KAAK,CAAC,gEAAgE,cAAc,IAAI,EAAE,UAAU,CAAC,CAAA;wBAC5G,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;4BAC3B,MAAM,IAAI,KAAK,CAAC,iDAAiD,UAAU,CAAC,OAAO,EAAE,CAAC,CAAA;wBACxF,CAAC;wBACD,SAAQ;oBACV,CAAC;oBACD,SAAQ;gBACV,CAAC;qBAAM,CAAC;oBACN,MAAM,uBAAuB,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;oBAChE,MAAM,IAAI,KAAK,CAAC,wBAAwB,UAAU,GAAG,CAAC,cAAc,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;gBACvF,CAAC;YACH,CAAC;YAED,mBAAmB;YACnB,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,qBAAqB,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3D,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;oBACzB,MAAM,CAAC,IAAI,CACT,6BAA6B,QAAQ,CAAC,MAAM,2CAA2C,OAAO,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,GAAG,CACxH,CAAA;oBAED,iCAAiC;oBACjC,IAAI,CAAC;wBACH,MAAM,WAAW,GAAG,MAAM,0BAA0B,CAClD,MAAM,EACN,cAAc,EACd,MAAM,EACN,YAAY,EACZ,WAAW,CACZ,CAAA;wBACD,YAAY,GAAG,WAAW,CAAC,YAAY,CAAA;wBACvC,IAAI,GAAG,WAAW,CAAC,IAAI,CAAA;wBAEvB,qBAAqB;wBACrB,MAAM,IAAI;6BACP,eAAe,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,KAAK,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;6BAC7E,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAA;wBAEtD,2BAA2B;wBAC3B,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA;wBAEvD,YAAY;wBACZ,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;wBAC3B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;wBAEpC,MAAM,CAAC,IAAI,CAAC,wBAAwB,QAAQ,cAAc,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;wBAE3E,iBAAiB;wBACjB,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;4BAC/B,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;wBAC1D,CAAC;oBACH,CAAC;oBAAC,OAAO,UAAU,EAAE,CAAC;wBACpB,MAAM,CAAC,KAAK,CACV,iEAAiE,cAAc,IAAI,EACnF,UAAU,CACX,CAAA;wBACD,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;4BAC3B,MAAM,IAAI,KAAK,CAAC,kDAAkD,UAAU,CAAC,OAAO,EAAE,CAAC,CAAA;wBACzF,CAAC;wBACD,SAAQ;oBACV,CAAC;oBACD,SAAQ;gBACV,CAAC;qBAAM,CAAC;oBACN,MAAM,uBAAuB,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;oBAChE,MAAM,IAAI,KAAK,CAAC,yBAAyB,UAAU,GAAG,CAAC,cAAc,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;gBACxF,CAAC;YACH,CAAC;YAED,aAAa;YACb,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;YACjC,CAAC;YAED,uBAAuB;YACvB,IAAI,eAAe,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAChD,IAAI,CAAC;oBACH,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,eAAe,CAAC,CAAA;oBACpC,eAAe,GAAG,IAAI,CAAA;gBACxB,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,gBAAgB;gBAClB,CAAC;YACH,CAAC;YAED,MAAM,MAAM,GAAG;gBACb,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,OAAO,EAAE,QAAQ,CAAC,OAAO;aAC1B,CAAA;YAED,MAAM,uBAAuB,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;YAEhE,OAAO,MAAM,CAAA;QACf,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,CAAA;YACjB,MAAM,CAAC,KAAK,CAAC,4BAA4B,OAAO,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAA;YAEtE,IAAI,eAAe,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAChD,IAAI,CAAC;oBACH,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,eAAe,CAAC,CAAA;oBACpC,eAAe,GAAG,IAAI,CAAA;gBACxB,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,gBAAgB;gBAClB,CAAC;YACH,CAAC;YAED,MAAM,uBAAuB,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;YAChE,IAAI,GAAG,IAAI,CAAA;YACX,YAAY,GAAG,IAAI,CAAA;YAEnB,gCAAgC;YAChC,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;gBACzD,MAAM,KAAK,CAAA;YACb,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,wBAAwB,OAAO,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,GAAG,CAAC,CAAA;QACvE,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,uBAAuB,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;IAClE,CAAC;IACD,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAA;AACzE,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,UAAkB;IAC/C,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;AACxC,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,KAAU;IACpC,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,CAAA;IAEvD,iCAAiC;IACjC,MAAM,wBAAwB,GAAG;QAC/B,iBAAiB;QACjB,eAAe;QACf,mBAAmB;QACnB,kBAAkB;QAClB,SAAS;QACT,WAAW;QACX,cAAc;QACd,WAAW;QACX,SAAS;QACT,gBAAgB;QAChB,OAAO;QACP,SAAS;QACT,qBAAqB,CAAC,cAAc;KACrC,CAAA;IAED,OAAO,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;AACjF,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,uBAAuB,CAAC,YAAiB,EAAE,WAAqB,EAAE,MAAW;IACjG,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAM;IACR,CAAC;IAED,IAAI,CAAC;QACH,wCAAwC;QACxC,IAAI,YAAY,CAAC,IAAI,EAAE,CAAC;YACtB,2EAA2E;YAC3E,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,qBAAqB,EAAE,GAAG,YAAY,CAAA;YAE7D,IAAI,qBAAqB,IAAI,OAAO,EAAE,CAAC;gBACrC,mEAAmE;gBACnE,IAAI,CAAC;oBACH,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;wBAC7B,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;wBAClB,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAA;oBAC3D,CAAC;gBACH,CAAC;gBAAC,OAAO,UAAU,EAAE,CAAC;oBACpB,MAAM,CAAC,KAAK,CAAC,6CAA6C,EAAE,UAAU,CAAC,CAAA;gBACzE,CAAC;gBAED,+BAA+B;gBAC/B,IAAI,CAAC;oBACH,MAAM,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,mCAAmC,CAAC,CAAA;oBACxE,MAAM,IAAI,GAAG,eAAe,EAAE,CAAA;oBAC9B,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;oBAC3B,MAAM,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAA;gBAClD,CAAC;gBAAC,OAAO,YAAY,EAAE,CAAC;oBACtB,MAAM,CAAC,KAAK,CAAC,6CAA6C,EAAE,YAAY,CAAC,CAAA;gBAC3E,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,uCAAuC;gBACvC,MAAM,WAAW,CAAC,IAAI,CAAC,CAAA;gBACvB,MAAM,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAA;YAClE,CAAC;QACH,CAAC;aAAM,CAAC;YACN,4CAA4C;YAC5C,MAAM,WAAW,CAAC,YAAY,CAAC,CAAA;YAC/B,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,8CAA8C,EAAE,KAAK,CAAC,CAAA;QAEnE,wDAAwD;QACxD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,IAAI,YAAY,CAAA;YAC9C,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAC7B,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;gBAClB,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAA;YACjD,CAAC;QACH,CAAC;QAAC,OAAO,eAAe,EAAE,CAAC;YACzB,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE,eAAe,CAAC,CAAA;QAC9D,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,0BAA0B,CACvC,MAAW,EACX,cAAsB,EACtB,MAAW,EACX,YAAiB,EACjB,WAAqB;IAErB,gBAAgB;IAChB,MAAM,uBAAuB,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;IAEhE,eAAe;IACf,MAAM,gBAAgB,GAAG,MAAM,sCAAiB,CAAC,yBAAyB,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IAClG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;IAC1D,CAAC;IAED,4BAA4B;IAC5B,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAA;IACvC,MAAM,cAAc,GAAG,OAAO,CAAC,iCAAiC,CAAC,CAAC,cAAc,CAAA;IAChF,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,sCAAiB,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;IAEvF,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,EAAE,CAAC,CAAA;IAC1D,CAAC;IAED,cAAc;IACd,MAAM,SAAS,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAA;IAC5C,MAAM,CAAC,IAAI,CAAC,eAAe,cAAc,0BAA0B,CAAC,CAAA;IAEpE,+BAA+B;IAC/B,8BAA8B;IAC9B,+BAA+B;IAC/B,6CAA6C;IAC7C,4BAA4B;IAC5B,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAA;IACzD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA;IAEvD,sBAAsB;IACtB,MAAM,SAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;IACzC,MAAM,CAAC,IAAI,CAAC,eAAe,cAAc,2BAA2B,CAAC,CAAA;IAErE,qBAAqB;IACrB,MAAM,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAA;IACpE,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA;IAEvD,2BAA2B;IAC3B,MAAM,aAAa,GAAG,MAAM,sCAAiB,CAAC,2BAA2B,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IACjG,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,CAAC,kBAAkB,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAA;IAC1E,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,aAAa,CAAC,kBAAkB,EAAE,CAAA;IACjE,IAAI,eAAoB,CAAA;IACxB,IAAI,OAAY,CAAA;IAEhB,IAAI,gBAAgB,IAAI,OAAO,gBAAgB,KAAK,QAAQ,IAAI,gBAAgB,CAAC,IAAI,EAAE,CAAC;QACtF,eAAe,GAAG,gBAAgB,CAAA;QAClC,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAA;IACjC,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,gBAAgB,CAAA;QAC1B,eAAe,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAA;IACnE,CAAC;IAED,eAAe;IACf,MAAM,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAA;IAC/D,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA;IAEvD,YAAY;IACZ,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAC7B,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAA;IAC3C,MAAM,CAAC,IAAI,CAAC,yBAAyB,OAAO,cAAc,WAAW,CAAC,MAAM,EAAE,CAAC,CAAA;IAE/E,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;AACzD,CAAC","sourcesContent":["import { access } from '@things-factory/utils'\nimport { ConnectionManager } from '../../connection-manager'\n\nexport interface HeadlessRequestOptions {\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n path: string\n headers?: Record<string, string>\n body?: any\n queryParams?: Record<string, any>\n maxRetries?: number\n accessor?: string // POST 요청에서 data 접근용\n contentType?: string // POST 요청에서 content-type 지정용\n}\n\n/**\n * 세션 회복 기능을 포함한 headless HTTP 요청 함수\n */\nexport async function executeHeadlessRequestWithRecovery(\n connectionName: string,\n options: HeadlessRequestOptions,\n context: { logger: any; data: any; domain: any }\n): Promise<any> {\n const { logger, data, domain } = context\n const { method, path, headers = {}, body, queryParams, maxRetries = 2, accessor, contentType } = options\n\n // 요청 컨텍스트 로깅 (발전소 식별을 위한 데이터 포함)\n const contextInfo = [`Connection: ${connectionName}`, `Path: ${path}`]\n\n // 발전소 식별자 추출 (디버깅용)\n if (data) {\n const identifiers = ['ICUS', 'SEL_METER_ID', 'plantId', 'siteId', 'powerPlantId']\n identifiers.forEach(key => {\n if (data[key]) {\n contextInfo.push(`${key}: ${data[key]}`)\n }\n })\n }\n\n logger.info(`[Context] ${contextInfo.join(', ')}`)\n\n // accessor가 있으면 data에서 body 추출\n let requestBody = body\n if (accessor && data) {\n requestBody = access(accessor, data)\n }\n\n const connection = await ConnectionManager.getConnectionInstanceByName(domain, connectionName)\n if (!connection) {\n throw new Error(`Connection '${connectionName}' is not established.`)\n }\n\n const {\n endpoint,\n params: connectionParams,\n acquireSessionPage,\n releasePage,\n reAuthenticateSession,\n validateSession\n } = connection\n const loginPagePath = connectionParams?.loginPagePath || '/login'\n\n // Connection 설정 로깅 (발전소별 차이 확인용)\n logger.info(`[Connection Config] Endpoint: ${endpoint}`)\n if (connectionParams?.username) {\n logger.info(`[Connection Config] Username: ${connectionParams.username}`)\n }\n\n let page = null\n let pageResource = null // 리소스 추적 객체\n let lastError = null\n let consoleListener = null // 브라우저 콘솔 리스너\n\n // 재시도 로직\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n logger.info(`[Attempt ${attempt + 1}/${maxRetries + 1}] Starting request attempt`)\n\n // 페이지 획득\n const sessionResult = await acquireSessionPage()\n\n // reAuthenticateSession의 반환 형태 확인\n if (sessionResult && typeof sessionResult === 'object' && sessionResult.page) {\n pageResource = sessionResult // {page, browser, requiresManualRelease}\n page = sessionResult.page\n } else {\n page = sessionResult\n pageResource = { page, requiresManualRelease: false }\n }\n\n // 초기 페이지 상태 로깅\n const initialUrl = page.url()\n const initialCookies = await page.cookies()\n logger.info(`[Initial Page] URL: ${initialUrl}, Cookies: ${initialCookies.length}`)\n\n // 로그인 페이지에 있는지 확인\n if (initialUrl.includes('/login') || initialUrl.includes('/signin') || initialCookies.length === 0) {\n logger.error(`[Login Failed] Still on login page or no cookies! URL: ${initialUrl}`)\n }\n\n // 페이지가 올바른 도메인에 있는지 확인\n const currentUrl = page.url()\n const targetDomain = new URL(endpoint).origin\n if (!currentUrl.startsWith(targetDomain)) {\n logger.info(`Navigating to target domain: ${targetDomain}`)\n await page.goto(targetDomain, { waitUntil: 'networkidle2' })\n }\n\n // 세션 검증은 2번째 시도부터만 수행 (첫 번째는 새 페이지이므로 불필요)\n // 또는 이전 시도에서 세션 관련 에러가 발생한 경우에만 수행\n if (attempt > 0) {\n logger.debug(`Validating session for connection '${connectionName}' (attempt: ${attempt + 1})`)\n\n // 세션 검증 전 페이지 상태 로깅\n const preValidateUrl = page.url()\n const preValidateCookies = await page.cookies()\n logger.info(`[Pre-Validate] URL: ${preValidateUrl}, Cookies: ${preValidateCookies.length}`)\n\n const isSessionValid = await validateSession(page)\n logger.info(`[Validate Result] isSessionValid: ${isSessionValid}`)\n\n if (!isSessionValid) {\n logger.warn(\n `Session invalid for connection '${connectionName}', attempting full connection reset (attempt: ${attempt + 1})`\n )\n\n try {\n const resetResult = await performFullConnectionReset(\n domain,\n connectionName,\n logger,\n pageResource,\n releasePage\n )\n pageResource = resetResult.pageResource\n page = resetResult.page\n\n // 재연결 후 페이지 완전 준비 대기\n await page\n .waitForFunction(() => document.readyState === 'complete', { timeout: 10000 })\n .catch(() => logger.warn('Page readyState timeout'))\n\n // JavaScript 초기화를 위한 추가 대기 (핵심 해결책)\n await new Promise(resolve => setTimeout(resolve, 2000))\n\n // 페이지 상태 확인\n const resetUrl = page.url()\n const cookies = await page.cookies()\n\n logger.info(`[Reset Success] URL: ${resetUrl}, Cookies: ${cookies.length}`)\n\n // about:blank 체크\n if (resetUrl === 'about:blank') {\n throw new Error('Page stuck on about:blank after reset')\n }\n } catch (resetError) {\n logger.error(`Connection reset failed for connection '${connectionName}':`, resetError)\n // 재설정 실패 시 이번 시도는 실패로 처리하고 다음 시도로 넘어감\n if (attempt === maxRetries) {\n throw new Error(`Connection reset failed after ${maxRetries + 1} attempts: ${resetError.message}`)\n }\n continue\n }\n }\n }\n\n // URL 구성\n const url = new URL(path, endpoint)\n if (queryParams && typeof queryParams === 'object') {\n Object.keys(queryParams).forEach(key => {\n if (queryParams[key] !== null && queryParams[key] !== undefined) {\n url.searchParams.append(key, String(queryParams[key]))\n }\n })\n }\n\n // 요청 옵션 구성\n const requestOptions: any = {\n method,\n headers: {\n ...headers\n },\n credentials: 'include'\n }\n\n // Content-Type과 body 처리\n if (requestBody && ['POST', 'PUT', 'PATCH'].includes(method)) {\n if (contentType) {\n requestOptions.headers['content-type'] = contentType\n switch (contentType) {\n case 'text/plain':\n requestOptions.body = JSON.stringify(requestBody)\n break\n case 'application/json':\n default:\n requestOptions.body = typeof requestBody === 'string' ? requestBody : JSON.stringify(requestBody)\n break\n }\n } else {\n requestOptions.headers['Content-Type'] = 'application/json'\n requestOptions.body = typeof requestBody === 'string' ? requestBody : JSON.stringify(requestBody)\n }\n }\n\n // 요청 직전 상태 로깅\n logger.info(`[Request] ${method} ${url.toString()}`)\n logger.debug(`[Request] Page: ${page.url()}, Closed: ${page.isClosed()}`)\n\n // 브라우저 콘솔 에러 캡처 (혹시 모를 예외 상황 대비)\n consoleListener = msg => {\n const type = msg.type()\n if (type === 'error' || type === 'warning') {\n logger.error(`[Browser Console ${type}] ${msg.text()}`)\n }\n }\n page.on('console', consoleListener)\n\n const response = await page.evaluate(\n async (urlString, opts, loginPagePath) => {\n try {\n // 페이지 상태 검증 (about:blank 또는 로딩 중인 페이지에서 fetch 방지)\n const pageLocation = window.location.href\n const pageReadyState = document.readyState\n\n if (pageLocation === 'about:blank' || pageReadyState !== 'complete') {\n return {\n ok: false,\n status: 0,\n statusText: 'Page Not Ready',\n headers: {},\n error: `Page state invalid - location: ${pageLocation}, readyState: ${pageReadyState}`,\n data: null,\n networkError: true\n }\n }\n\n // 🔍 fetch 직전 디버깅 정보 수집\n const debugInfo: any = {\n beforeFetch: {\n targetUrl: urlString,\n currentLocation: pageLocation,\n cookiesCount: document.cookie ? document.cookie.split(';').length : 0,\n hasCookies: !!document.cookie\n }\n }\n\n const response = await fetch(urlString, { ...opts, redirect: 'manual' })\n\n // 🔍 fetch 응답 디버깅 정보 추가\n debugInfo.afterFetch = {\n status: response.status,\n ok: response.ok,\n type: response.type,\n url: response.url,\n statusText: response.statusText\n }\n\n const result = {\n ok: response.ok,\n status: response.status,\n statusText: response.statusText,\n headers: Object.fromEntries(response.headers.entries()),\n debugInfo // 디버깅 정보 포함\n }\n\n // 302 리디렉션 감지 - 로그인 페이지로의 리디렉션 체크\n if ([301, 302, 307, 308].includes(response.status)) {\n const location = response.headers.get('location') || ''\n // connection의 loginPagePath와 일반적인 로그인 경로들을 체크\n if (\n location.includes(loginPagePath) ||\n location.includes('/login') ||\n location.includes('/signin') ||\n location.includes('/auth')\n ) {\n return {\n ...result,\n error: `Redirected to login page: ${location}`,\n redirectedToLogin: true,\n location,\n data: null\n }\n }\n // 다른 리디렉션은 follow\n const redirectResponse = await fetch(urlString, opts)\n return {\n ok: redirectResponse.ok,\n status: redirectResponse.status,\n statusText: redirectResponse.statusText,\n headers: Object.fromEntries(redirectResponse.headers.entries()),\n data: redirectResponse.ok\n ? await redirectResponse\n .json()\n .catch(() => redirectResponse.text())\n .catch(() => null)\n : null,\n error: redirectResponse.ok ? null : `HTTP ${redirectResponse.status}: ${redirectResponse.statusText}`\n }\n }\n\n // status가 0인 경우는 네트워크 레벨 에러 (CORS, 연결 실패 등)\n if (response.status === 0) {\n return {\n ok: false,\n status: 0,\n statusText: response.statusText || 'Network Error',\n headers: {},\n error: 'HTTP 0 - Network connection failed (possible CORS, SSL, or connectivity issue)',\n data: null,\n networkError: true,\n debugInfo // 디버깅 정보 포함\n }\n }\n\n if (!response.ok) {\n return {\n ...result,\n error: `HTTP ${response.status}: ${response.statusText}`,\n data: null\n }\n }\n\n const contentType = response.headers.get('content-type') || ''\n\n if (contentType.includes('application/json')) {\n result['data'] = await response.json()\n } else if (contentType.includes('text/')) {\n result['data'] = await response.text()\n } else {\n // 응답이 없는 경우 (204 No Content 등)\n result['data'] = null\n }\n\n return result\n } catch (fetchError) {\n // 네트워크 레벨 에러 처리\n return {\n ok: false,\n status: 0,\n statusText: 'Network Error',\n headers: {},\n error: fetchError.message || 'Failed to fetch',\n errorName: fetchError.name,\n errorStack: fetchError.stack,\n data: null,\n networkError: true,\n debugInfo: {\n beforeFetch: {\n targetUrl: urlString,\n currentLocation: window.location.href,\n cookiesCount: document.cookie ? document.cookie.split(';').length : 0,\n hasCookies: !!document.cookie\n },\n fetchError: {\n message: fetchError.message,\n name: fetchError.name,\n stack: fetchError.stack\n }\n }\n }\n }\n },\n url.toString(),\n requestOptions,\n loginPagePath\n )\n\n // 브라우저 콘솔 리스너 제거\n if (consoleListener && page && !page.isClosed()) {\n try {\n page.off('console', consoleListener)\n consoleListener = null\n } catch (e) {\n // 리스너 제거 실패는 무시\n }\n }\n\n // 네트워크 에러 체크 (fetch 자체가 실패한 경우)\n if (response.networkError) {\n logger.error(`[Network Error] ${response.error}`)\n\n // 디버깅 정보 출력\n if (response.debugInfo) {\n logger.info(`[Debug] Before Fetch: ${JSON.stringify(response.debugInfo.beforeFetch)}`)\n if (response.debugInfo.afterFetch) {\n logger.info(`[Debug] After Fetch: ${JSON.stringify(response.debugInfo.afterFetch)}`)\n }\n if (response.debugInfo.fetchError) {\n logger.error(`[Debug] Fetch Exception: ${JSON.stringify(response.debugInfo.fetchError)}`)\n }\n }\n\n if (attempt < maxRetries) {\n logger.warn(`Network error detected: ${response.error}, retrying... (${attempt + 1}/${maxRetries + 1})`)\n await safeReleasePageResource(pageResource, releasePage, logger)\n page = null\n pageResource = null\n continue\n } else {\n await safeReleasePageResource(pageResource, releasePage, logger)\n throw new Error(`Network error after ${maxRetries + 1} attempts: ${response.error}`)\n }\n }\n\n // 로그인 리디렉션 감지 처리\n if (response.redirectedToLogin) {\n if (attempt < maxRetries) {\n logger.warn(\n `Login redirect detected: ${response.location}, performing full connection reset... (${attempt + 1}/${maxRetries + 1})`\n )\n\n // CRITICAL: 커넥션 재연결 방식으로 완전한 초기화\n try {\n const resetResult = await performFullConnectionReset(\n domain,\n connectionName,\n logger,\n pageResource,\n releasePage\n )\n pageResource = resetResult.pageResource\n page = resetResult.page\n\n // 재연결 후 페이지 완전 준비 대기\n await page\n .waitForFunction(() => document.readyState === 'complete', { timeout: 10000 })\n .catch(() => logger.warn('Page readyState timeout'))\n\n // JavaScript 초기화를 위한 추가 대기\n await new Promise(resolve => setTimeout(resolve, 2000))\n\n // 페이지 상태 확인\n const resetUrl = page.url()\n const cookies = await page.cookies()\n\n logger.info(`[Reset Success] URL: ${resetUrl}, Cookies: ${cookies.length}`)\n\n // about:blank 체크\n if (resetUrl === 'about:blank') {\n throw new Error('Page stuck on about:blank after reset')\n }\n } catch (resetError) {\n logger.error(`Connection reset failed after login redirect for connection '${connectionName}':`, resetError)\n if (attempt === maxRetries) {\n throw new Error(`Connection reset failed after login redirect: ${resetError.message}`)\n }\n continue\n }\n continue\n } else {\n await safeReleasePageResource(pageResource, releasePage, logger)\n throw new Error(`Login redirect after ${maxRetries + 1} attempts: ${response.error}`)\n }\n }\n\n // 세션 타임아웃 관련 에러 체크\n if (!response.ok && isSessionTimeoutError(response.status)) {\n if (attempt < maxRetries) {\n logger.warn(\n `Session timeout detected (${response.status}), performing full connection reset... (${attempt + 1}/${maxRetries + 1})`\n )\n\n // CRITICAL: 커넥션 재연결 방식으로 완전한 초기화\n try {\n const resetResult = await performFullConnectionReset(\n domain,\n connectionName,\n logger,\n pageResource,\n releasePage\n )\n pageResource = resetResult.pageResource\n page = resetResult.page\n\n // 재연결 후 페이지 완전 준비 대기\n await page\n .waitForFunction(() => document.readyState === 'complete', { timeout: 10000 })\n .catch(() => logger.warn('Page readyState timeout'))\n\n // JavaScript 초기화를 위한 추가 대기\n await new Promise(resolve => setTimeout(resolve, 2000))\n\n // 페이지 상태 확인\n const resetUrl = page.url()\n const cookies = await page.cookies()\n\n logger.info(`[Reset Success] URL: ${resetUrl}, Cookies: ${cookies.length}`)\n\n // about:blank 체크\n if (resetUrl === 'about:blank') {\n throw new Error('Page stuck on about:blank after reset')\n }\n } catch (resetError) {\n logger.error(\n `Connection reset failed after session timeout for connection '${connectionName}':`,\n resetError\n )\n if (attempt === maxRetries) {\n throw new Error(`Connection reset failed after session timeout: ${resetError.message}`)\n }\n continue\n }\n continue\n } else {\n await safeReleasePageResource(pageResource, releasePage, logger)\n throw new Error(`Session timeout after ${maxRetries + 1} attempts: ${response.error}`)\n }\n }\n\n // 기타 HTTP 에러\n if (!response.ok) {\n throw new Error(response.error)\n }\n\n // 성공 시 페이지 릴리즈 후 결과 반환\n if (consoleListener && page && !page.isClosed()) {\n try {\n page.off('console', consoleListener)\n consoleListener = null\n } catch (e) {\n // 리스너 제거 실패는 무시\n }\n }\n\n const result = {\n data: response.data,\n status: response.status,\n headers: response.headers\n }\n\n await safeReleasePageResource(pageResource, releasePage, logger)\n\n return result\n } catch (error) {\n lastError = error\n logger.error(`Headless request attempt ${attempt + 1} failed:`, error)\n\n if (consoleListener && page && !page.isClosed()) {\n try {\n page.off('console', consoleListener)\n consoleListener = null\n } catch (e) {\n // 리스너 제거 실패는 무시\n }\n }\n\n await safeReleasePageResource(pageResource, releasePage, logger)\n page = null\n pageResource = null\n\n // 세션 관련 에러가 아니거나 마지막 재시도면 에러 발생\n if (!isRecoverableError(error) || attempt === maxRetries) {\n throw error\n }\n\n logger.info(`Retrying request... (${attempt + 2}/${maxRetries + 1})`)\n }\n }\n\n // 모든 재시도가 실패한 경우 - 혹시 남은 리소스가 있으면 정리\n if (pageResource) {\n await safeReleasePageResource(pageResource, releasePage, logger)\n }\n throw lastError || new Error('Request failed after all retry attempts')\n}\n\n/**\n * 세션 타임아웃 관련 HTTP 상태 코드인지 확인\n */\nfunction isSessionTimeoutError(statusCode: number): boolean {\n return [401, 403].includes(statusCode)\n}\n\n/**\n * 복구 가능한 에러인지 확인\n */\nfunction isRecoverableError(error: any): boolean {\n const errorMessage = error.message?.toLowerCase() || ''\n\n // 복구 가능한 에러 키워드 (네트워크, 세션/인증 관련)\n const recoverableErrorKeywords = [\n 'failed to fetch',\n 'network error',\n 'connection failed',\n 'connection reset',\n 'timeout',\n 'timed out',\n 'unauthorized',\n 'forbidden',\n 'session',\n 'authentication',\n 'login',\n 'expired',\n 'redirected to login' // 로그인 리디렉션 추가\n ]\n\n return recoverableErrorKeywords.some(keyword => errorMessage.includes(keyword))\n}\n\n/**\n * Safely release page resource with comprehensive error handling\n */\nexport async function safeReleasePageResource(pageResource: any, releasePage: Function, logger: any): Promise<void> {\n if (!pageResource) {\n return\n }\n\n try {\n // Handle different pageResource formats\n if (pageResource.page) {\n // This is a complex resource object {page, browser, requiresManualRelease}\n const { page, browser, requiresManualRelease } = pageResource\n\n if (requiresManualRelease && browser) {\n // Manual release required - close page first, then release browser\n try {\n if (page && !page.isClosed()) {\n await page.close()\n logger.info('Page closed during manual resource release')\n }\n } catch (closeError) {\n logger.error('Failed to close page during manual release:', closeError)\n }\n\n // Release browser back to pool\n try {\n const { getHeadlessPool } = require('../../resource-pool/headless-pool')\n const pool = getHeadlessPool()\n await pool.release(browser)\n logger.info('Browser manually released to pool')\n } catch (releaseError) {\n logger.error('Failed to manually release browser to pool:', releaseError)\n }\n } else {\n // Standard release through releasePage\n await releasePage(page)\n logger.info('Page released through standard releasePage method')\n }\n } else {\n // Simple page object - use standard release\n await releasePage(pageResource)\n logger.info('Simple page resource released')\n }\n } catch (error) {\n logger.error('Critical error during page resource release:', error)\n\n // Last resort: try to force close the page if it exists\n try {\n const page = pageResource.page || pageResource\n if (page && !page.isClosed()) {\n await page.close()\n logger.warn('Force closed page as last resort')\n }\n } catch (forceCloseError) {\n logger.error('Failed to force close page:', forceCloseError)\n }\n }\n}\n\n/**\n * 커넥션을 완전 재초기화하는 함수\n * 세션 만료 시 커넥션 재연결과 동일한 완전한 초기화를 수행\n */\nasync function performFullConnectionReset(\n domain: any,\n connectionName: string,\n logger: any,\n pageResource: any,\n releasePage: Function\n): Promise<{ pageResource: any; page: any }> {\n // 기존 페이지 리소스 해제\n await safeReleasePageResource(pageResource, releasePage, logger)\n\n // 커넥션 엔티티 가져오기\n const connectionEntity = await ConnectionManager.getConnectionEntityByName(domain, connectionName)\n if (!connectionEntity) {\n throw new Error('Connection entity not found for reset')\n }\n\n // Connector를 직접 사용하여 연결 재설정\n const { type, edge } = connectionEntity\n const ProxyConnector = require('../../connector/proxy-connector').ProxyConnector\n const connector = edge ? ProxyConnector.instance : ConnectionManager.getConnector(type)\n\n if (!connector) {\n throw new Error(`Connector not found for type: ${type}`)\n }\n\n // 기존 연결 완전 해제\n await connector.disconnect(connectionEntity)\n logger.info(`Connection '${connectionName}' disconnected for reset`)\n\n // 브라우저 완전 종료 및 리소스 정리 대기 (중요!)\n // 수동 재연결 시에는 자연스럽게 시간이 지나가지만,\n // 코드에서는 즉시 연결을 시도하므로 명시적 대기 필요\n // disconnect는 ConnectionManager에서 인스턴스만 제거하고\n // 실제 브라우저 pool 정리에는 시간이 필요함\n logger.info(`Waiting for browser cleanup (3 seconds)...`)\n await new Promise(resolve => setTimeout(resolve, 3000))\n\n // 새로운 연결 생성 (완전한 초기화)\n await connector.connect(connectionEntity)\n logger.info(`Connection '${connectionName}' reconnected after reset`)\n\n // 새 브라우저 인스턴스 초기화 대기\n logger.info(`Waiting for new browser initialization (2 seconds)...`)\n await new Promise(resolve => setTimeout(resolve, 2000))\n\n // 새로운 connection 인스턴스 가져오기\n const newConnection = await ConnectionManager.getConnectionInstanceByName(domain, connectionName)\n if (!newConnection || !newConnection.acquireSessionPage) {\n throw new Error('Failed to acquire session page after connection reset')\n }\n\n const newSessionResult = await newConnection.acquireSessionPage()\n let newPageResource: any\n let newPage: any\n\n if (newSessionResult && typeof newSessionResult === 'object' && newSessionResult.page) {\n newPageResource = newSessionResult\n newPage = newSessionResult.page\n } else {\n newPage = newSessionResult\n newPageResource = { page: newPage, requiresManualRelease: false }\n }\n\n // 새 페이지 안정화 대기\n logger.info(`Waiting for new page stabilization (1 second)...`)\n await new Promise(resolve => setTimeout(resolve, 1000))\n\n // 페이지 상태 확인\n const pageUrl = newPage.url()\n const pageCookies = await newPage.cookies()\n logger.info(`New page ready - URL: ${pageUrl}, Cookies: ${pageCookies.length}`)\n\n return { pageResource: newPageResource, page: newPage }\n}\n"]}
|