@ait-co/devtools 0.1.67 → 0.1.69
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/dist/chii-relay-BNd3G3UG.js +152 -0
- package/dist/chii-relay-BNd3G3UG.js.map +1 -0
- package/dist/chii-relay-DngjQ2_A.cjs +151 -0
- package/dist/chii-relay-DngjQ2_A.cjs.map +1 -0
- package/dist/in-app/index.d.ts +24 -6
- package/dist/in-app/index.d.ts.map +1 -1
- package/dist/in-app/index.js +27 -8
- package/dist/in-app/index.js.map +1 -1
- package/dist/mcp/cli.js +332 -53
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/server.js +2 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/panel/index.js +52 -20
- package/dist/panel/index.js.map +1 -1
- package/dist/{qr-http-server-ChC7P6-H.js → qr-http-server-CyVQphTM.js} +213 -30
- package/dist/qr-http-server-CyVQphTM.js.map +1 -0
- package/dist/{qr-http-server-BUfbLGm1.js → qr-http-server-DKEca8J3.js} +213 -30
- package/dist/qr-http-server-DKEca8J3.js.map +1 -0
- package/dist/{qr-http-server-B5YndXcS.cjs → qr-http-server-DR__VNnX.cjs} +213 -30
- package/dist/qr-http-server-DR__VNnX.cjs.map +1 -0
- package/dist/{qr-http-server-DRlwR54D.cjs → qr-http-server-DnQSQ3hC.cjs} +213 -30
- package/dist/qr-http-server-DnQSQ3hC.cjs.map +1 -0
- package/dist/{tunnel-CrlCX5sZ.cjs → tunnel-BMY7KgO5.cjs} +4 -3
- package/dist/{tunnel-CrlCX5sZ.cjs.map → tunnel-BMY7KgO5.cjs.map} +1 -1
- package/dist/{tunnel-BNzbSCfB.js → tunnel-DIN5Vvbo.js} +4 -3
- package/dist/{tunnel-BNzbSCfB.js.map → tunnel-DIN5Vvbo.js.map} +1 -1
- package/dist/unplugin/index.cjs +10 -3
- package/dist/unplugin/index.cjs.map +1 -1
- package/dist/unplugin/index.d.cts.map +1 -1
- package/dist/unplugin/index.d.ts.map +1 -1
- package/dist/unplugin/index.js +10 -3
- package/dist/unplugin/index.js.map +1 -1
- package/dist/unplugin/tunnel.cjs +3 -2
- package/dist/unplugin/tunnel.cjs.map +1 -1
- package/dist/unplugin/tunnel.d.cts.map +1 -1
- package/dist/unplugin/tunnel.d.ts.map +1 -1
- package/dist/unplugin/tunnel.js +3 -2
- package/dist/unplugin/tunnel.js.map +1 -1
- package/package.json +1 -1
- package/dist/chii-relay-57BfqF_5.cjs +0 -88
- package/dist/chii-relay-57BfqF_5.cjs.map +0 -1
- package/dist/chii-relay-itXOz7kS.js +0 -89
- package/dist/chii-relay-itXOz7kS.js.map +0 -1
- package/dist/qr-http-server-B5YndXcS.cjs.map +0 -1
- package/dist/qr-http-server-BUfbLGm1.js.map +0 -1
- package/dist/qr-http-server-ChC7P6-H.js.map +0 -1
- package/dist/qr-http-server-DRlwR54D.cjs.map +0 -1
|
@@ -184,16 +184,27 @@ const en = {
|
|
|
184
184
|
"attach.title": "AIT Debug Session — QR Scan",
|
|
185
185
|
"attach.deployment": "deployment: {label}",
|
|
186
186
|
"attach.steps.section": "How to scan",
|
|
187
|
-
"attach.step1": "Open the Toss app.",
|
|
188
|
-
"attach.step2": "Scan the QR code with your phone camera app.",
|
|
189
|
-
"attach.step3": "Tap <strong>\"Open in Toss\"</strong> when the popup appears.",
|
|
190
|
-
"attach.step4": "The mini-app opens and the debug session attaches automatically.",
|
|
191
187
|
"attach.faq.section": "Troubleshooting checklist",
|
|
192
|
-
"attach.faq.appNotOpen": "<strong>Toss app does not open</strong> — check app version; scan with the system camera app (not the Toss in-app QR reader)",
|
|
193
|
-
"attach.faq.prepare": "<strong>Mini-app stuck in PREPARE state</strong> — verify the deep-link has a <code>_deploymentId</code> parameter",
|
|
194
|
-
"attach.faq.chii": "<strong>Chii injection failure / console is empty</strong> — verify the mini-app bundle has an <code>in-app</code> debug import",
|
|
195
|
-
"attach.faq.totp": "<strong>TOTP gate Layer C is inactive</strong> — check that <code>AIT_DEBUG_TOTP_SECRET</code> is set on the relay server",
|
|
196
188
|
"attach.url.section": "URL (fallback)",
|
|
189
|
+
"attach.mode.sandbox": "Env 2 — AITC Sandbox PWA",
|
|
190
|
+
"attach.mode.intossDev": "Env 3 — intoss-private relay dev",
|
|
191
|
+
"attach.mode.intossLive": "Env 4 — intoss live relay debug",
|
|
192
|
+
"attach.sandbox.step1": "Launch the launcher PWA icon on your home screen (if the Safari address bar is visible, it is not standalone).",
|
|
193
|
+
"attach.sandbox.step2": "Scan this QR code with <strong>\"Scan QR with camera\"</strong> inside the launcher.",
|
|
194
|
+
"attach.sandbox.step3": "The mini-app opens fullscreen and the debug session attaches automatically.",
|
|
195
|
+
"attach.sandbox.faq.notInstalled": "<strong>Launcher is not installed</strong> — open <code>devtools.aitc.dev/launcher/</code> once and add it to your home screen",
|
|
196
|
+
"attach.sandbox.faq.cameraApp": "<strong>Scanning with the camera app opens a Safari tab (bottom tab bar visible)</strong> — relaunch from the launcher icon and use the in-app scanner",
|
|
197
|
+
"attach.sandbox.faq.totp": "<strong>QR expired (TOTP 30 s)</strong> — scan a fresh QR code",
|
|
198
|
+
"attach.sandbox.faq.chii": "<strong>Chii injection failure / console is empty</strong> — verify the mini-app bundle has an <code>in-app</code> debug import",
|
|
199
|
+
"attach.intoss.step1": "Open the Toss app.",
|
|
200
|
+
"attach.intoss.step2": "Scan the QR code with your phone camera app.",
|
|
201
|
+
"attach.intoss.step3": "Tap <strong>\"Open in Toss\"</strong> when the popup appears.",
|
|
202
|
+
"attach.intoss.step4": "The mini-app opens and the debug session attaches automatically.",
|
|
203
|
+
"attach.intoss.faq.appNotOpen": "<strong>Toss app does not open</strong> — check app version; scan with the system camera app (not the Toss in-app QR reader)",
|
|
204
|
+
"attach.intoss.faq.prepare": "<strong>Mini-app stuck in PREPARE state</strong> — verify the deep-link has a <code>_deploymentId</code> parameter",
|
|
205
|
+
"attach.intoss.faq.chii": "<strong>Chii injection failure / console is empty</strong> — verify the mini-app bundle has an <code>in-app</code> debug import",
|
|
206
|
+
"attach.intoss.faq.totp": "<strong>TOTP gate Layer C is inactive</strong> — check that <code>AIT_DEBUG_TOTP_SECRET</code> is set on the relay server",
|
|
207
|
+
"attach.intoss.faq.liveReadOnly": "<strong>LIVE session is read-only</strong> — <code>call_sdk</code>/<code>evaluate</code> require an explicit <code>confirm</code>",
|
|
197
208
|
"launcher.title": "AITC DevTools Launcher",
|
|
198
209
|
"launcher.description": "Scan the terminal QR code or paste the tunnel URL.",
|
|
199
210
|
"launcher.installCta": "Install launcher to your phone",
|
|
@@ -207,7 +218,12 @@ const en = {
|
|
|
207
218
|
"launcher.invalidUrl": "Enter a valid http(s):// URL.",
|
|
208
219
|
"launcher.debugAuthFailed": "Debug connection authentication failed",
|
|
209
220
|
"launcher.debugAuthFailedHint": "The QR code may have expired. Scan a fresh QR code.",
|
|
210
|
-
"launcher.debugAuthRescanCta": "Scan a new QR"
|
|
221
|
+
"launcher.debugAuthRescanCta": "Scan a new QR",
|
|
222
|
+
"launcher.diagFab": "Diag",
|
|
223
|
+
"launcher.diagTitle": "Viewport diagnostics",
|
|
224
|
+
"launcher.diagYes": "yes",
|
|
225
|
+
"launcher.diagNo": "no",
|
|
226
|
+
"launcher.letterboxDetected": "Display area is {pt}pt short — likely an iOS standalone letterbox. Removing and re-adding the launcher to the home screen may fix it."
|
|
211
227
|
};
|
|
212
228
|
//#endregion
|
|
213
229
|
//#region src/i18n/index.ts
|
|
@@ -411,16 +427,27 @@ const tables = {
|
|
|
411
427
|
"attach.title": "AIT 디버그 세션 — QR 스캔",
|
|
412
428
|
"attach.deployment": "deployment: {label}",
|
|
413
429
|
"attach.steps.section": "스캔 절차",
|
|
414
|
-
"attach.step1": "토스 앱을 실행하세요.",
|
|
415
|
-
"attach.step2": "폰 카메라 앱으로 QR 코드를 스캔하세요.",
|
|
416
|
-
"attach.step3": "팝업이 뜨면 <strong>\"토스로 열기\"</strong>를 탭하세요.",
|
|
417
|
-
"attach.step4": "미니앱이 열리고 디버그 세션이 자동으로 attach됩니다.",
|
|
418
430
|
"attach.faq.section": "진단 체크리스트",
|
|
419
|
-
"attach.faq.appNotOpen": "<strong>토스 앱이 안 열리는 경우</strong> — 앱 버전 확인, 카메라 앱으로 스캔 (토스 앱 내 QR 리더 X)",
|
|
420
|
-
"attach.faq.prepare": "<strong>미니앱이 PREPARE 상태에서 멈추는 경우</strong> — deep-link에 <code>_deploymentId</code> 파라미터가 있는지 확인",
|
|
421
|
-
"attach.faq.chii": "<strong>Chii 주입 실패 / 콘솔이 비어 있는 경우</strong> — 미니앱 번들에 <code>in-app</code> debug import가 있는지 확인",
|
|
422
|
-
"attach.faq.totp": "<strong>TOTP gate Layer C가 비활성인 경우</strong> — relay 서버에 <code>AIT_DEBUG_TOTP_SECRET</code>이 설정돼 있는지 확인",
|
|
423
431
|
"attach.url.section": "URL (fallback)",
|
|
432
|
+
"attach.mode.sandbox": "환경 2 — AITC Sandbox PWA",
|
|
433
|
+
"attach.mode.intossDev": "환경 3 — intoss-private relay dev",
|
|
434
|
+
"attach.mode.intossLive": "환경 4 — intoss live relay debug",
|
|
435
|
+
"attach.sandbox.step1": "홈 화면의 launcher PWA 아이콘으로 실행하세요 (Safari 주소창이 보이면 standalone이 아닙니다).",
|
|
436
|
+
"attach.sandbox.step2": "launcher 안의 <strong>\"QR 카메라로 스캔\"</strong>으로 이 QR 코드를 스캔하세요.",
|
|
437
|
+
"attach.sandbox.step3": "미니앱이 풀스크린으로 열리고 디버그 세션이 자동으로 attach됩니다.",
|
|
438
|
+
"attach.sandbox.faq.notInstalled": "<strong>launcher가 설치돼 있지 않은 경우</strong> — <code>devtools.aitc.dev/launcher/</code>를 한 번 열어 홈 화면에 추가하세요",
|
|
439
|
+
"attach.sandbox.faq.cameraApp": "<strong>카메라 앱으로 스캔하면 Safari 탭으로 열립니다 (하단 탭 바 노출)</strong> — launcher 아이콘으로 다시 실행해 인앱 스캔을 사용하세요",
|
|
440
|
+
"attach.sandbox.faq.totp": "<strong>QR이 만료된 경우 (TOTP 30초)</strong> — 새 QR을 다시 스캔하세요",
|
|
441
|
+
"attach.sandbox.faq.chii": "<strong>Chii 주입 실패 / 콘솔이 비어 있는 경우</strong> — 미니앱 번들에 <code>in-app</code> debug import가 있는지 확인",
|
|
442
|
+
"attach.intoss.step1": "토스 앱을 실행하세요.",
|
|
443
|
+
"attach.intoss.step2": "폰 카메라 앱으로 QR 코드를 스캔하세요.",
|
|
444
|
+
"attach.intoss.step3": "팝업이 뜨면 <strong>\"토스로 열기\"</strong>를 탭하세요.",
|
|
445
|
+
"attach.intoss.step4": "미니앱이 열리고 디버그 세션이 자동으로 attach됩니다.",
|
|
446
|
+
"attach.intoss.faq.appNotOpen": "<strong>토스 앱이 안 열리는 경우</strong> — 앱 버전 확인, 카메라 앱으로 스캔 (토스 앱 내 QR 리더 X)",
|
|
447
|
+
"attach.intoss.faq.prepare": "<strong>미니앱이 PREPARE 상태에서 멈추는 경우</strong> — deep-link에 <code>_deploymentId</code> 파라미터가 있는지 확인",
|
|
448
|
+
"attach.intoss.faq.chii": "<strong>Chii 주입 실패 / 콘솔이 비어 있는 경우</strong> — 미니앱 번들에 <code>in-app</code> debug import가 있는지 확인",
|
|
449
|
+
"attach.intoss.faq.totp": "<strong>TOTP gate Layer C가 비활성인 경우</strong> — relay 서버에 <code>AIT_DEBUG_TOTP_SECRET</code>이 설정돼 있는지 확인",
|
|
450
|
+
"attach.intoss.faq.liveReadOnly": "<strong>LIVE 세션은 read-only입니다</strong> — <code>call_sdk</code>/<code>evaluate</code> 실행에는 명시적 <code>confirm</code>이 필요합니다",
|
|
424
451
|
"launcher.title": "AITC DevTools Launcher",
|
|
425
452
|
"launcher.description": "터미널 QR을 스캔하거나 URL을 입력하세요.",
|
|
426
453
|
"launcher.installCta": "폰에 런처 설치하기",
|
|
@@ -434,7 +461,12 @@ const tables = {
|
|
|
434
461
|
"launcher.invalidUrl": "올바른 http(s):// URL을 입력하세요.",
|
|
435
462
|
"launcher.debugAuthFailed": "디버그 연결 인증 실패",
|
|
436
463
|
"launcher.debugAuthFailedHint": "QR 코드가 만료되었을 수 있어요. 새 QR을 다시 스캔하세요.",
|
|
437
|
-
"launcher.debugAuthRescanCta": "새 QR 스캔하기"
|
|
464
|
+
"launcher.debugAuthRescanCta": "새 QR 스캔하기",
|
|
465
|
+
"launcher.diagFab": "진단",
|
|
466
|
+
"launcher.diagTitle": "뷰포트 진단",
|
|
467
|
+
"launcher.diagYes": "예",
|
|
468
|
+
"launcher.diagNo": "아니요",
|
|
469
|
+
"launcher.letterboxDetected": "표시 영역이 {pt}pt 부족합니다 — iOS standalone letterbox로 보입니다. 런처를 홈 화면에서 제거 후 다시 설치하면 해소될 수 있어요."
|
|
438
470
|
},
|
|
439
471
|
en
|
|
440
472
|
};
|
|
@@ -532,7 +564,7 @@ hr { border: none; border-top: 1px solid #21262d; width: 100%; margin: 0; }
|
|
|
532
564
|
.lang-switcher a { color: #58a6ff; text-decoration: none; opacity: 0.6; }
|
|
533
565
|
.lang-switcher a.active { font-weight: 700; text-decoration: underline; opacity: 1; }
|
|
534
566
|
</style></head><body><h1>AIT 디버그 Dashboard</h1>__LANG_SWITCHER__<p class="updated" id="updated">마지막 갱신: __NOW__</p><section><h2>터널 상태</h2><span class="status __TUNNEL_CLASS__" id="tunnel-status">__TUNNEL_STATUS__</span></section><hr/><section><h2>Attach QR</h2><div id="attach-section">__ATTACH_SECTION__</div></section>__PAGES_SECTION__</body></html>`;
|
|
535
|
-
const
|
|
567
|
+
const attachChromeHtmlKoSandbox = `<!DOCTYPE html>
|
|
536
568
|
<html lang="ko"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="image" href="__QR_DATA_URL__"/><title>AIT 디버그 세션 — QR 스캔</title><style>
|
|
537
569
|
*, *::before, *::after { box-sizing: border-box; }
|
|
538
570
|
body {
|
|
@@ -543,6 +575,61 @@ body {
|
|
|
543
575
|
gap: 1.5rem;
|
|
544
576
|
}
|
|
545
577
|
h1 { font-size: 1.25rem; font-weight: 600; color: #e6edf3; margin: 0; text-align: center; }
|
|
578
|
+
.mode-label {
|
|
579
|
+
font-size: 0.78rem; font-weight: 600; color: #79c0ff;
|
|
580
|
+
background: #161b22; border: 1px solid #30363d; border-radius: 999px;
|
|
581
|
+
padding: 0.25rem 0.75rem; margin: 0;
|
|
582
|
+
}
|
|
583
|
+
.label { font-size: 0.8rem; opacity: 0.5; font-family: monospace; margin: 0; }
|
|
584
|
+
img.qr {
|
|
585
|
+
width: min(90vw, 360px); height: auto;
|
|
586
|
+
image-rendering: pixelated;
|
|
587
|
+
background: #fff; padding: 1rem; border-radius: 12px;
|
|
588
|
+
display: block; margin: 0 auto;
|
|
589
|
+
}
|
|
590
|
+
section { width: 100%; max-width: 480px; }
|
|
591
|
+
h2 { font-size: 1rem; font-weight: 600; color: #e6edf3; margin: 0 0 0.5rem; }
|
|
592
|
+
ol, ul { margin: 0; padding-left: 1.25rem; }
|
|
593
|
+
li { margin-bottom: 0.4rem; font-size: 0.9rem; line-height: 1.5; }
|
|
594
|
+
.url-row {
|
|
595
|
+
display: flex; align-items: stretch; gap: 0;
|
|
596
|
+
border-radius: 6px; border: 1px solid #30363d; overflow: hidden;
|
|
597
|
+
}
|
|
598
|
+
.url-box {
|
|
599
|
+
font-family: monospace; font-size: 0.72rem;
|
|
600
|
+
word-break: break-all; opacity: 0.4;
|
|
601
|
+
background: #161b22; padding: 0.75rem 1rem;
|
|
602
|
+
flex: 1; cursor: pointer; border: none; border-radius: 0;
|
|
603
|
+
}
|
|
604
|
+
.url-box:hover { opacity: 0.6; }
|
|
605
|
+
.copy-btn {
|
|
606
|
+
flex-shrink: 0; padding: 0.5rem 0.8rem;
|
|
607
|
+
background: #21262d; border: none; border-left: 1px solid #30363d;
|
|
608
|
+
color: #58a6ff; font-size: 0.75rem; cursor: pointer; white-space: nowrap;
|
|
609
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
610
|
+
}
|
|
611
|
+
.copy-btn:hover { background: #30363d; }
|
|
612
|
+
hr { border: none; border-top: 1px solid #21262d; width: 100%; margin: 0.5rem 0; }
|
|
613
|
+
.lang-switcher { display: flex; gap: 0.5rem; font-size: 0.75rem; }
|
|
614
|
+
.lang-switcher a { color: #58a6ff; text-decoration: none; opacity: 0.6; }
|
|
615
|
+
.lang-switcher a.active { font-weight: 700; text-decoration: underline; opacity: 1; }
|
|
616
|
+
</style></head><body><h1>AIT 디버그 세션 — QR 스캔</h1>__MODE_LABEL____LANG_SWITCHER__<div id="attach-section"><img class="qr" src="__QR_DATA_URL__" alt="attach QR"/></div><section><h2>스캔 절차</h2><ol><li>홈 화면의 launcher PWA 아이콘으로 실행하세요 (Safari 주소창이 보이면 standalone이 아닙니다).</li><li>launcher 안의 <strong>"QR 카메라로 스캔"</strong>으로 이 QR 코드를 스캔하세요.</li><li>미니앱이 풀스크린으로 열리고 디버그 세션이 자동으로 attach됩니다.</li></ol></section><hr/><section><h2>진단 체크리스트</h2><ul><li><strong>launcher가 설치돼 있지 않은 경우</strong> — <code>devtools.aitc.dev/launcher/</code>를 한 번 열어 홈 화면에 추가하세요</li><li><strong>카메라 앱으로 스캔하면 Safari 탭으로 열립니다 (하단 탭 바 노출)</strong> — launcher 아이콘으로 다시 실행해 인앱 스캔을 사용하세요</li><li><strong>QR이 만료된 경우 (TOTP 30초)</strong> — 새 QR을 다시 스캔하세요</li><li><strong>Chii 주입 실패 / 콘솔이 비어 있는 경우</strong> — 미니앱 번들에 <code>in-app</code> debug import가 있는지 확인</li></ul></section><hr/><section id="url-section"><h2>URL (fallback)</h2><div class="url-row"><p class="url-box" id="url-box">__SAFE_ATTACH_URL__</p><button class="copy-btn" id="copy-btn" type="button" aria-label="복사">복사</button></div></section></body></html>`;
|
|
617
|
+
const attachChromeHtmlKoIntoss = `<!DOCTYPE html>
|
|
618
|
+
<html lang="ko"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="image" href="__QR_DATA_URL__"/><title>AIT 디버그 세션 — QR 스캔</title><style>
|
|
619
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
620
|
+
body {
|
|
621
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
622
|
+
background: #0d1117; color: #c9d1d9;
|
|
623
|
+
display: flex; flex-direction: column; align-items: center;
|
|
624
|
+
min-height: 100vh; margin: 0; padding: 2rem 1rem;
|
|
625
|
+
gap: 1.5rem;
|
|
626
|
+
}
|
|
627
|
+
h1 { font-size: 1.25rem; font-weight: 600; color: #e6edf3; margin: 0; text-align: center; }
|
|
628
|
+
.mode-label {
|
|
629
|
+
font-size: 0.78rem; font-weight: 600; color: #79c0ff;
|
|
630
|
+
background: #161b22; border: 1px solid #30363d; border-radius: 999px;
|
|
631
|
+
padding: 0.25rem 0.75rem; margin: 0;
|
|
632
|
+
}
|
|
546
633
|
.label { font-size: 0.8rem; opacity: 0.5; font-family: monospace; margin: 0; }
|
|
547
634
|
img.qr {
|
|
548
635
|
width: min(90vw, 360px); height: auto;
|
|
@@ -576,7 +663,7 @@ hr { border: none; border-top: 1px solid #21262d; width: 100%; margin: 0.5rem 0;
|
|
|
576
663
|
.lang-switcher { display: flex; gap: 0.5rem; font-size: 0.75rem; }
|
|
577
664
|
.lang-switcher a { color: #58a6ff; text-decoration: none; opacity: 0.6; }
|
|
578
665
|
.lang-switcher a.active { font-weight: 700; text-decoration: underline; opacity: 1; }
|
|
579
|
-
</style></head><body><h1>AIT 디버그 세션 — QR 스캔</h1>
|
|
666
|
+
</style></head><body><h1>AIT 디버그 세션 — QR 스캔</h1>__MODE_LABEL____LANG_SWITCHER__<p class="label">deployment: __SAFE_LABEL__</p><div id="attach-section"><img class="qr" src="__QR_DATA_URL__" alt="attach QR"/></div><section><h2>스캔 절차</h2><ol><li>토스 앱을 실행하세요.</li><li>폰 카메라 앱으로 QR 코드를 스캔하세요.</li><li>팝업이 뜨면 <strong>"토스로 열기"</strong>를 탭하세요.</li><li>미니앱이 열리고 디버그 세션이 자동으로 attach됩니다.</li></ol></section><hr/><section><h2>진단 체크리스트</h2><ul><li><strong>토스 앱이 안 열리는 경우</strong> — 앱 버전 확인, 카메라 앱으로 스캔 (토스 앱 내 QR 리더 X)</li><li><strong>미니앱이 PREPARE 상태에서 멈추는 경우</strong> — deep-link에 <code>_deploymentId</code> 파라미터가 있는지 확인</li><li><strong>Chii 주입 실패 / 콘솔이 비어 있는 경우</strong> — 미니앱 번들에 <code>in-app</code> debug import가 있는지 확인</li><li><strong>TOTP gate Layer C가 비활성인 경우</strong> — relay 서버에 <code>AIT_DEBUG_TOTP_SECRET</code>이 설정돼 있는지 확인</li>__LIVE_FAQ__</ul></section><hr/><section id="url-section"><h2>URL (fallback)</h2><div class="url-row"><p class="url-box" id="url-box">__SAFE_ATTACH_URL__</p><button class="copy-btn" id="copy-btn" type="button" aria-label="복사">복사</button></div></section></body></html>`;
|
|
580
667
|
const dashboardChromeHtmlEn = `<!DOCTYPE html>
|
|
581
668
|
<html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><title>AIT Debug Dashboard</title><style>
|
|
582
669
|
*, *::before, *::after { box-sizing: border-box; }
|
|
@@ -629,7 +716,7 @@ hr { border: none; border-top: 1px solid #21262d; width: 100%; margin: 0; }
|
|
|
629
716
|
.lang-switcher a { color: #58a6ff; text-decoration: none; opacity: 0.6; }
|
|
630
717
|
.lang-switcher a.active { font-weight: 700; text-decoration: underline; opacity: 1; }
|
|
631
718
|
</style></head><body><h1>AIT Debug Dashboard</h1>__LANG_SWITCHER__<p class="updated" id="updated">Last updated: __NOW__</p><section><h2>Tunnel status</h2><span class="status __TUNNEL_CLASS__" id="tunnel-status">__TUNNEL_STATUS__</span></section><hr/><section><h2>Attach QR</h2><div id="attach-section">__ATTACH_SECTION__</div></section>__PAGES_SECTION__</body></html>`;
|
|
632
|
-
const
|
|
719
|
+
const attachChromeHtmlEnSandbox = `<!DOCTYPE html>
|
|
633
720
|
<html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="image" href="__QR_DATA_URL__"/><title>AIT Debug Session — QR Scan</title><style>
|
|
634
721
|
*, *::before, *::after { box-sizing: border-box; }
|
|
635
722
|
body {
|
|
@@ -640,6 +727,11 @@ body {
|
|
|
640
727
|
gap: 1.5rem;
|
|
641
728
|
}
|
|
642
729
|
h1 { font-size: 1.25rem; font-weight: 600; color: #e6edf3; margin: 0; text-align: center; }
|
|
730
|
+
.mode-label {
|
|
731
|
+
font-size: 0.78rem; font-weight: 600; color: #79c0ff;
|
|
732
|
+
background: #161b22; border: 1px solid #30363d; border-radius: 999px;
|
|
733
|
+
padding: 0.25rem 0.75rem; margin: 0;
|
|
734
|
+
}
|
|
643
735
|
.label { font-size: 0.8rem; opacity: 0.5; font-family: monospace; margin: 0; }
|
|
644
736
|
img.qr {
|
|
645
737
|
width: min(90vw, 360px); height: auto;
|
|
@@ -673,19 +765,101 @@ hr { border: none; border-top: 1px solid #21262d; width: 100%; margin: 0.5rem 0;
|
|
|
673
765
|
.lang-switcher { display: flex; gap: 0.5rem; font-size: 0.75rem; }
|
|
674
766
|
.lang-switcher a { color: #58a6ff; text-decoration: none; opacity: 0.6; }
|
|
675
767
|
.lang-switcher a.active { font-weight: 700; text-decoration: underline; opacity: 1; }
|
|
676
|
-
</style></head><body><h1>AIT Debug Session — QR Scan</h1>
|
|
768
|
+
</style></head><body><h1>AIT Debug Session — QR Scan</h1>__MODE_LABEL____LANG_SWITCHER__<div id="attach-section"><img class="qr" src="__QR_DATA_URL__" alt="attach QR"/></div><section><h2>How to scan</h2><ol><li>Launch the launcher PWA icon on your home screen (if the Safari address bar is visible, it is not standalone).</li><li>Scan this QR code with <strong>"Scan QR with camera"</strong> inside the launcher.</li><li>The mini-app opens fullscreen and the debug session attaches automatically.</li></ol></section><hr/><section><h2>Troubleshooting checklist</h2><ul><li><strong>Launcher is not installed</strong> — open <code>devtools.aitc.dev/launcher/</code> once and add it to your home screen</li><li><strong>Scanning with the camera app opens a Safari tab (bottom tab bar visible)</strong> — relaunch from the launcher icon and use the in-app scanner</li><li><strong>QR expired (TOTP 30 s)</strong> — scan a fresh QR code</li><li><strong>Chii injection failure / console is empty</strong> — verify the mini-app bundle has an <code>in-app</code> debug import</li></ul></section><hr/><section id="url-section"><h2>URL (fallback)</h2><div class="url-row"><p class="url-box" id="url-box">__SAFE_ATTACH_URL__</p><button class="copy-btn" id="copy-btn" type="button" aria-label="Copy">Copy</button></div></section></body></html>`;
|
|
769
|
+
const attachChromeHtmlEnIntoss = `<!DOCTYPE html>
|
|
770
|
+
<html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="image" href="__QR_DATA_URL__"/><title>AIT Debug Session — QR Scan</title><style>
|
|
771
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
772
|
+
body {
|
|
773
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
774
|
+
background: #0d1117; color: #c9d1d9;
|
|
775
|
+
display: flex; flex-direction: column; align-items: center;
|
|
776
|
+
min-height: 100vh; margin: 0; padding: 2rem 1rem;
|
|
777
|
+
gap: 1.5rem;
|
|
778
|
+
}
|
|
779
|
+
h1 { font-size: 1.25rem; font-weight: 600; color: #e6edf3; margin: 0; text-align: center; }
|
|
780
|
+
.mode-label {
|
|
781
|
+
font-size: 0.78rem; font-weight: 600; color: #79c0ff;
|
|
782
|
+
background: #161b22; border: 1px solid #30363d; border-radius: 999px;
|
|
783
|
+
padding: 0.25rem 0.75rem; margin: 0;
|
|
784
|
+
}
|
|
785
|
+
.label { font-size: 0.8rem; opacity: 0.5; font-family: monospace; margin: 0; }
|
|
786
|
+
img.qr {
|
|
787
|
+
width: min(90vw, 360px); height: auto;
|
|
788
|
+
image-rendering: pixelated;
|
|
789
|
+
background: #fff; padding: 1rem; border-radius: 12px;
|
|
790
|
+
display: block; margin: 0 auto;
|
|
791
|
+
}
|
|
792
|
+
section { width: 100%; max-width: 480px; }
|
|
793
|
+
h2 { font-size: 1rem; font-weight: 600; color: #e6edf3; margin: 0 0 0.5rem; }
|
|
794
|
+
ol, ul { margin: 0; padding-left: 1.25rem; }
|
|
795
|
+
li { margin-bottom: 0.4rem; font-size: 0.9rem; line-height: 1.5; }
|
|
796
|
+
.url-row {
|
|
797
|
+
display: flex; align-items: stretch; gap: 0;
|
|
798
|
+
border-radius: 6px; border: 1px solid #30363d; overflow: hidden;
|
|
799
|
+
}
|
|
800
|
+
.url-box {
|
|
801
|
+
font-family: monospace; font-size: 0.72rem;
|
|
802
|
+
word-break: break-all; opacity: 0.4;
|
|
803
|
+
background: #161b22; padding: 0.75rem 1rem;
|
|
804
|
+
flex: 1; cursor: pointer; border: none; border-radius: 0;
|
|
805
|
+
}
|
|
806
|
+
.url-box:hover { opacity: 0.6; }
|
|
807
|
+
.copy-btn {
|
|
808
|
+
flex-shrink: 0; padding: 0.5rem 0.8rem;
|
|
809
|
+
background: #21262d; border: none; border-left: 1px solid #30363d;
|
|
810
|
+
color: #58a6ff; font-size: 0.75rem; cursor: pointer; white-space: nowrap;
|
|
811
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
812
|
+
}
|
|
813
|
+
.copy-btn:hover { background: #30363d; }
|
|
814
|
+
hr { border: none; border-top: 1px solid #21262d; width: 100%; margin: 0.5rem 0; }
|
|
815
|
+
.lang-switcher { display: flex; gap: 0.5rem; font-size: 0.75rem; }
|
|
816
|
+
.lang-switcher a { color: #58a6ff; text-decoration: none; opacity: 0.6; }
|
|
817
|
+
.lang-switcher a.active { font-weight: 700; text-decoration: underline; opacity: 1; }
|
|
818
|
+
</style></head><body><h1>AIT Debug Session — QR Scan</h1>__MODE_LABEL____LANG_SWITCHER__<p class="label">deployment: __SAFE_LABEL__</p><div id="attach-section"><img class="qr" src="__QR_DATA_URL__" alt="attach QR"/></div><section><h2>How to scan</h2><ol><li>Open the Toss app.</li><li>Scan the QR code with your phone camera app.</li><li>Tap <strong>"Open in Toss"</strong> when the popup appears.</li><li>The mini-app opens and the debug session attaches automatically.</li></ol></section><hr/><section><h2>Troubleshooting checklist</h2><ul><li><strong>Toss app does not open</strong> — check app version; scan with the system camera app (not the Toss in-app QR reader)</li><li><strong>Mini-app stuck in PREPARE state</strong> — verify the deep-link has a <code>_deploymentId</code> parameter</li><li><strong>Chii injection failure / console is empty</strong> — verify the mini-app bundle has an <code>in-app</code> debug import</li><li><strong>TOTP gate Layer C is inactive</strong> — check that <code>AIT_DEBUG_TOTP_SECRET</code> is set on the relay server</li>__LIVE_FAQ__</ul></section><hr/><section id="url-section"><h2>URL (fallback)</h2><div class="url-row"><p class="url-box" id="url-box">__SAFE_ATTACH_URL__</p><button class="copy-btn" id="copy-btn" type="button" aria-label="Copy">Copy</button></div></section></body></html>`;
|
|
677
819
|
/** Map from Locale to the precompiled dashboard chrome string. */
|
|
678
820
|
const dashboardChromeByLocale = {
|
|
679
821
|
ko: dashboardChromeHtmlKo,
|
|
680
822
|
en: dashboardChromeHtmlEn
|
|
681
823
|
};
|
|
682
|
-
/** Map from Locale to the precompiled attach page chrome string. */
|
|
824
|
+
/** Map from Locale × copy family to the precompiled attach page chrome string (#468). */
|
|
683
825
|
const attachChromeByLocale = {
|
|
684
|
-
ko:
|
|
685
|
-
|
|
826
|
+
ko: {
|
|
827
|
+
sandbox: attachChromeHtmlKoSandbox,
|
|
828
|
+
intoss: attachChromeHtmlKoIntoss
|
|
829
|
+
},
|
|
830
|
+
en: {
|
|
831
|
+
sandbox: attachChromeHtmlEnSandbox,
|
|
832
|
+
intoss: attachChromeHtmlEnIntoss
|
|
833
|
+
}
|
|
686
834
|
};
|
|
687
835
|
//#endregion
|
|
688
836
|
//#region src/mcp/qr-http-server.ts
|
|
837
|
+
/** mode → 어느 precompiled attach chrome family를 쓰는가 (#468). */
|
|
838
|
+
function attachFamilyForMode(mode) {
|
|
839
|
+
return mode === "relay-mobile" ? "sandbox" : "intoss";
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* mode → 페이지 상단 환경 라벨 HTML (`__MODE_LABEL__` 토큰 채움, #468).
|
|
843
|
+
* 사용자가 fidelity 사다리의 어느 겹에 있는지 즉시 알게 하는 환경 가시화 배지.
|
|
844
|
+
* mode 미지정/'mock'은 빈 문자열 — 알 수 없는 환경을 거짓으로 라벨링하지 않는다.
|
|
845
|
+
*/
|
|
846
|
+
function buildModeLabel(mode, s) {
|
|
847
|
+
let label;
|
|
848
|
+
switch (mode) {
|
|
849
|
+
case "relay-mobile":
|
|
850
|
+
label = s("attach.mode.sandbox");
|
|
851
|
+
break;
|
|
852
|
+
case "relay-dev":
|
|
853
|
+
label = s("attach.mode.intossDev");
|
|
854
|
+
break;
|
|
855
|
+
case "relay-live":
|
|
856
|
+
label = s("attach.mode.intossLive");
|
|
857
|
+
break;
|
|
858
|
+
case "mock":
|
|
859
|
+
case void 0: return "";
|
|
860
|
+
}
|
|
861
|
+
return `<p class="mode-label">${escapeHtml(label)}</p>`;
|
|
862
|
+
}
|
|
689
863
|
/** HTML 특수문자를 이스케이프한다. */
|
|
690
864
|
function escapeHtml(s) {
|
|
691
865
|
return s.replace(/[<>&"']/g, (c) => `&#${c.charCodeAt(0)};`);
|
|
@@ -919,8 +1093,14 @@ function buildSseScript(strings) {
|
|
|
919
1093
|
*
|
|
920
1094
|
* 동적 파트:
|
|
921
1095
|
* - __QR_DATA_URL__ : base64 data URL (QR 이미지)
|
|
922
|
-
* - __SAFE_LABEL__ : HTML-escaped deploymentId label
|
|
1096
|
+
* - __SAFE_LABEL__ : HTML-escaped deploymentId label (intoss family에만 존재)
|
|
923
1097
|
* - __SAFE_ATTACH_URL__ : HTML-escaped attach URL (TOTP at= 코드 포함 — 의도된 전달)
|
|
1098
|
+
* - __MODE_LABEL__ : 환경 배지 (`<p class="mode-label">…</p>` 또는 빈 문자열, #468)
|
|
1099
|
+
* - __LIVE_FAQ__ : 환경 4 LIVE read-only `<li>` 또는 빈 문자열 (intoss family에만 존재)
|
|
1100
|
+
*
|
|
1101
|
+
* mode-aware 분기 (#468): mode가 `relay-mobile`이면 sandbox family chrome(launcher
|
|
1102
|
+
* PWA 절차), 그 외는 intoss family chrome(토스 앱 절차)을 선택한다. `relay-live`는
|
|
1103
|
+
* intoss chrome에 LIVE read-only 라인을 추가한다.
|
|
924
1104
|
*
|
|
925
1105
|
* SSE 스크립트도 주입 — `#attach-section` hook이 있으면 `/events` push 때 QR이
|
|
926
1106
|
* `/qr.png?u=<fresh attachUrl>`로 자동 갱신된다. `#tunnel-status`·`#pages-list` 등
|
|
@@ -928,10 +1108,12 @@ function buildSseScript(strings) {
|
|
|
928
1108
|
*
|
|
929
1109
|
* SECRET-HANDLING: TOTP at= 코드는 attachUrl 캡슐 안에서만 노출 — 의도된 transport.
|
|
930
1110
|
*/
|
|
931
|
-
function buildAttachHtml(qrDataUrl, safeLabel, safeAttachUrl, locale, path = "/attach", params = new URLSearchParams()) {
|
|
1111
|
+
function buildAttachHtml(qrDataUrl, safeLabel, safeAttachUrl, locale, path = "/attach", params = new URLSearchParams(), mode) {
|
|
932
1112
|
const s = resolveLocaleStrings(locale);
|
|
933
1113
|
const langSwitcher = buildLangSwitcher(path, params, locale, s);
|
|
934
|
-
const
|
|
1114
|
+
const family = attachFamilyForMode(mode);
|
|
1115
|
+
const liveFaq = mode === "relay-live" ? `<li>${s("attach.intoss.faq.liveReadOnly")}</li>` : "";
|
|
1116
|
+
const filled = attachChromeByLocale[locale][family].replaceAll("__LANG_SWITCHER__", langSwitcher).replaceAll("__MODE_LABEL__", buildModeLabel(mode, s)).replaceAll("__LIVE_FAQ__", liveFaq).replaceAll("__QR_DATA_URL__", qrDataUrl).replaceAll("__SAFE_LABEL__", safeLabel).replaceAll("__SAFE_ATTACH_URL__", safeAttachUrl);
|
|
935
1117
|
const sseScript = buildSseScript({
|
|
936
1118
|
tunnelUp: JSON.stringify(s("dashboard.tunnel.up")),
|
|
937
1119
|
tunnelDown: JSON.stringify(s("dashboard.tunnel.down")),
|
|
@@ -1028,11 +1210,12 @@ async function startQrHttpServer(getDashboardState) {
|
|
|
1028
1210
|
const dpMatch = attachUrl.match(/[?&]_deploymentId=([^&]+)/);
|
|
1029
1211
|
if (dpMatch?.[1]) deploymentIdLabel = decodeURIComponent(dpMatch[1]).slice(0, 36);
|
|
1030
1212
|
} catch {}
|
|
1213
|
+
const mode = getDashboardState?.().mode;
|
|
1031
1214
|
QRCode.toDataURL(attachUrl, {
|
|
1032
1215
|
type: "image/png",
|
|
1033
1216
|
errorCorrectionLevel: "M"
|
|
1034
1217
|
}).then((dataUrl) => {
|
|
1035
|
-
const html = buildAttachHtml(dataUrl, escapeHtml(deploymentIdLabel), escapeHtml(attachUrl), locale, path, params);
|
|
1218
|
+
const html = buildAttachHtml(dataUrl, escapeHtml(deploymentIdLabel), escapeHtml(attachUrl), locale, path, params, mode);
|
|
1036
1219
|
res.writeHead(200, {
|
|
1037
1220
|
"Content-Type": "text/html; charset=utf-8",
|
|
1038
1221
|
"Cache-Control": "no-store"
|
|
@@ -1103,4 +1286,4 @@ async function startQrHttpServer(getDashboardState) {
|
|
|
1103
1286
|
//#endregion
|
|
1104
1287
|
exports.startQrHttpServer = startQrHttpServer;
|
|
1105
1288
|
|
|
1106
|
-
//# sourceMappingURL=qr-http-server-
|
|
1289
|
+
//# sourceMappingURL=qr-http-server-DnQSQ3hC.cjs.map
|