@ait-co/devtools 0.0.1 → 0.0.2

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/panel/styles.ts","../../src/panel/index.ts"],"sourcesContent":["/**\n * Floating Panel CSS (inline, 외부 의존성 없음)\n */\n\nexport const PANEL_STYLES = /* css */ `\n .ait-panel-toggle {\n position: fixed;\n bottom: 16px;\n right: 16px;\n z-index: 99999;\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: #3182F6;\n border: none;\n cursor: pointer;\n box-shadow: 0 2px 12px rgba(0,0,0,0.2);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 20px;\n color: white;\n transition: transform 0.15s;\n font-family: -apple-system, BlinkMacSystemFont, sans-serif;\n }\n .ait-panel-toggle:hover {\n transform: scale(1.1);\n }\n\n .ait-panel {\n position: fixed;\n bottom: 72px;\n right: 16px;\n z-index: 99998;\n width: 360px;\n max-height: 520px;\n background: #1a1a2e;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.4);\n font-family: -apple-system, BlinkMacSystemFont, 'Pretendard', sans-serif;\n font-size: 13px;\n color: #e0e0e0;\n overflow: hidden;\n display: none;\n }\n .ait-panel.open {\n display: flex;\n flex-direction: column;\n }\n\n .ait-panel-header {\n padding: 12px 16px;\n background: #16213e;\n font-weight: 600;\n font-size: 14px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n border-bottom: 1px solid #2a2a4a;\n }\n .ait-panel-header span {\n color: #3182F6;\n }\n\n .ait-panel-tabs {\n display: flex;\n background: #16213e;\n border-bottom: 1px solid #2a2a4a;\n overflow-x: auto;\n scrollbar-width: none;\n }\n .ait-panel-tabs::-webkit-scrollbar { display: none; }\n\n .ait-panel-tab {\n padding: 8px 12px;\n font-size: 12px;\n color: #888;\n cursor: pointer;\n white-space: nowrap;\n border-bottom: 2px solid transparent;\n background: none;\n border-top: none;\n border-left: none;\n border-right: none;\n font-family: inherit;\n }\n .ait-panel-tab:hover {\n color: #bbb;\n }\n .ait-panel-tab.active {\n color: #3182F6;\n border-bottom-color: #3182F6;\n }\n\n .ait-panel-body {\n padding: 12px 16px;\n overflow-y: auto;\n max-height: 400px;\n flex: 1;\n }\n\n .ait-section {\n margin-bottom: 16px;\n }\n .ait-section-title {\n font-size: 11px;\n text-transform: uppercase;\n color: #666;\n margin-bottom: 8px;\n letter-spacing: 0.5px;\n }\n\n .ait-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 6px;\n }\n .ait-row label {\n color: #aaa;\n font-size: 12px;\n }\n\n .ait-select {\n background: #2a2a4a;\n color: #e0e0e0;\n border: 1px solid #3a3a5a;\n border-radius: 4px;\n padding: 4px 8px;\n font-size: 12px;\n font-family: inherit;\n cursor: pointer;\n }\n\n .ait-input {\n background: #2a2a4a;\n color: #e0e0e0;\n border: 1px solid #3a3a5a;\n border-radius: 4px;\n padding: 4px 8px;\n font-size: 12px;\n width: 100px;\n font-family: inherit;\n }\n\n .ait-btn {\n background: #3182F6;\n color: white;\n border: none;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 12px;\n cursor: pointer;\n font-family: inherit;\n }\n .ait-btn:hover {\n background: #1b6ef3;\n }\n .ait-btn-sm {\n padding: 4px 8px;\n font-size: 11px;\n }\n .ait-btn-danger {\n background: #e74c3c;\n }\n .ait-btn-danger:hover {\n background: #c0392b;\n }\n\n .ait-log-entry {\n font-family: 'SF Mono', 'Menlo', monospace;\n font-size: 11px;\n padding: 3px 0;\n border-bottom: 1px solid #2a2a4a;\n color: #aaa;\n }\n .ait-log-entry .ait-log-type {\n color: #3182F6;\n font-weight: 600;\n margin-right: 6px;\n }\n .ait-log-entry .ait-log-time {\n color: #555;\n margin-right: 6px;\n }\n\n .ait-storage-row {\n font-family: 'SF Mono', 'Menlo', monospace;\n font-size: 11px;\n display: flex;\n gap: 8px;\n padding: 4px 0;\n border-bottom: 1px solid #2a2a4a;\n }\n .ait-storage-key {\n color: #e8a87c;\n min-width: 80px;\n word-break: break-all;\n }\n .ait-storage-value {\n color: #95e6cb;\n flex: 1;\n word-break: break-all;\n }\n`;\n","/**\n * ait-devtools Floating Panel\n *\n * import 하면 자동으로 페이지에 DevTools 패널을 마운트한다.\n * 외부 의존성 없이 vanilla DOM으로 구현.\n */\n\nimport { aitState } from '../mock/state.js';\nimport type { PermissionName, PermissionStatus, NetworkStatus, PlatformOS, OperationalEnvironment, IapNextResult } from '../mock/state.js';\nimport { PANEL_STYLES } from './styles.js';\n\ntype TabId = 'env' | 'permissions' | 'location' | 'iap' | 'events' | 'analytics' | 'storage';\n\nconst TABS: Array<{ id: TabId; label: string }> = [\n { id: 'env', label: 'Environment' },\n { id: 'permissions', label: 'Permissions' },\n { id: 'location', label: 'Location' },\n { id: 'iap', label: 'IAP' },\n { id: 'events', label: 'Events' },\n { id: 'analytics', label: 'Analytics' },\n { id: 'storage', label: 'Storage' },\n];\n\nfunction h<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n attrs?: Record<string, string>,\n ...children: (string | Node)[]\n): HTMLElementTagNameMap[K] {\n const el = document.createElement(tag);\n if (attrs) {\n for (const [k, v] of Object.entries(attrs)) {\n if (k === 'className') el.className = v;\n else el.setAttribute(k, v);\n }\n }\n for (const child of children) {\n el.append(typeof child === 'string' ? document.createTextNode(child) : child);\n }\n return el;\n}\n\nfunction selectRow(\n label: string,\n options: string[],\n value: string,\n onChange: (v: string) => void,\n): HTMLElement {\n const select = h('select', { className: 'ait-select' });\n for (const opt of options) {\n const option = h('option', { value: opt }, opt);\n if (opt === value) option.selected = true;\n select.appendChild(option);\n }\n select.addEventListener('change', () => onChange(select.value));\n return h('div', { className: 'ait-row' }, h('label', {}, label), select);\n}\n\nfunction inputRow(label: string, value: string, onChange: (v: string) => void): HTMLElement {\n const input = h('input', { className: 'ait-input', value });\n input.addEventListener('change', () => onChange(input.value));\n return h('div', { className: 'ait-row' }, h('label', {}, label), input);\n}\n\nfunction renderEnvTab(): HTMLElement {\n const s = aitState.state;\n const container = h('div');\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Platform'),\n selectRow('OS', ['ios', 'android'], s.platform, v => aitState.update({ platform: v as PlatformOS })),\n inputRow('App Version', s.appVersion, v => aitState.update({ appVersion: v })),\n selectRow('Environment', ['toss', 'sandbox'], s.environment, v => aitState.update({ environment: v as OperationalEnvironment })),\n inputRow('Locale', s.locale, v => aitState.update({ locale: v })),\n ),\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Network'),\n selectRow('Status', ['WIFI', '4G', '5G', '3G', '2G', 'OFFLINE', 'WWAN', 'UNKNOWN'], s.networkStatus, v => aitState.update({ networkStatus: v as NetworkStatus })),\n ),\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Safe Area Insets'),\n inputRow('Top', String(s.safeAreaInsets.top), v => aitState.patch('safeAreaInsets', { top: Number(v) })),\n inputRow('Bottom', String(s.safeAreaInsets.bottom), v => aitState.patch('safeAreaInsets', { bottom: Number(v) })),\n ),\n );\n return container;\n}\n\nfunction renderPermissionsTab(): HTMLElement {\n const s = aitState.state;\n const container = h('div');\n const names: PermissionName[] = ['camera', 'photos', 'geolocation', 'clipboard', 'contacts', 'microphone'];\n const statuses: PermissionStatus[] = ['allowed', 'denied', 'notDetermined'];\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Device Permissions'),\n ...names.map(name =>\n selectRow(name, statuses, s.permissions[name], v => {\n aitState.patch('permissions', { [name]: v as PermissionStatus });\n }),\n ),\n ),\n );\n return container;\n}\n\nfunction renderLocationTab(): HTMLElement {\n const s = aitState.state;\n const container = h('div');\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Current Location'),\n inputRow('Latitude', String(s.location.coords.latitude), v => {\n const coords = { ...s.location.coords, latitude: Number(v) };\n aitState.patch('location', { coords } as Partial<typeof s.location>);\n }),\n inputRow('Longitude', String(s.location.coords.longitude), v => {\n const coords = { ...s.location.coords, longitude: Number(v) };\n aitState.patch('location', { coords } as Partial<typeof s.location>);\n }),\n inputRow('Accuracy', String(s.location.coords.accuracy), v => {\n const coords = { ...s.location.coords, accuracy: Number(v) };\n aitState.patch('location', { coords } as Partial<typeof s.location>);\n }),\n ),\n );\n return container;\n}\n\nfunction renderIapTab(): HTMLElement {\n const s = aitState.state;\n const container = h('div');\n const results: IapNextResult[] = ['success', 'USER_CANCELED', 'INVALID_PRODUCT_ID', 'PAYMENT_PENDING', 'NETWORK_ERROR', 'ITEM_ALREADY_OWNED', 'INTERNAL_ERROR'];\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'IAP Simulator'),\n selectRow('Next Purchase Result', results, s.iap.nextResult, v => {\n aitState.patch('iap', { nextResult: v as IapNextResult });\n }),\n ),\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'TossPay'),\n selectRow('Next Payment Result', ['success', 'fail'], s.payment.nextResult, v => {\n aitState.patch('payment', { nextResult: v as 'success' | 'fail' });\n }),\n ),\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, `Completed Orders (${s.iap.completedOrders.length})`),\n ...s.iap.completedOrders.slice(-5).map(o =>\n h('div', { className: 'ait-log-entry' },\n h('span', { className: 'ait-log-type' }, o.status),\n `${o.sku} (${o.orderId.slice(-8)})`,\n ),\n ),\n ),\n );\n return container;\n}\n\nfunction renderEventsTab(): HTMLElement {\n const container = h('div');\n\n const backBtn = h('button', { className: 'ait-btn' }, 'Trigger Back Event');\n backBtn.addEventListener('click', () => aitState.trigger('backEvent'));\n\n const homeBtn = h('button', { className: 'ait-btn' }, 'Trigger Home Event');\n homeBtn.addEventListener('click', () => aitState.trigger('homeEvent'));\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Navigation Events'),\n h('div', { className: 'ait-row' }, backBtn, homeBtn),\n ),\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Login'),\n selectRow('Logged In', ['true', 'false'], String(aitState.state.auth.isLoggedIn), v => {\n aitState.patch('auth', { isLoggedIn: v === 'true' });\n }),\n selectRow('Toss Login Integrated', ['true', 'false'], String(aitState.state.auth.isTossLoginIntegrated), v => {\n aitState.patch('auth', { isTossLoginIntegrated: v === 'true' });\n }),\n ),\n );\n return container;\n}\n\nfunction renderAnalyticsTab(): HTMLElement {\n const container = h('div');\n const logs = aitState.state.analyticsLog;\n\n const clearBtn = h('button', { className: 'ait-btn ait-btn-sm ait-btn-danger' }, 'Clear');\n clearBtn.addEventListener('click', () => {\n aitState.state.analyticsLog.length = 0;\n refreshPanel();\n });\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-row' },\n h('div', { className: 'ait-section-title' }, `Analytics Log (${logs.length})`),\n clearBtn,\n ),\n ...logs.slice(-30).reverse().map(entry => {\n const time = new Date(entry.timestamp).toLocaleTimeString('ko-KR', { hour12: false });\n return h('div', { className: 'ait-log-entry' },\n h('span', { className: 'ait-log-time' }, time),\n h('span', { className: 'ait-log-type' }, entry.type),\n JSON.stringify(entry.params),\n );\n }),\n ),\n );\n return container;\n}\n\nfunction renderStorageTab(): HTMLElement {\n const container = h('div');\n const prefix = '__ait_storage:';\n const entries: Array<[string, string]> = [];\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(prefix)) {\n entries.push([key.slice(prefix.length), localStorage.getItem(key) ?? '']);\n }\n }\n\n const clearBtn = h('button', { className: 'ait-btn ait-btn-sm ait-btn-danger' }, 'Clear All');\n clearBtn.addEventListener('click', () => {\n entries.forEach(([key]) => localStorage.removeItem(prefix + key));\n refreshPanel();\n });\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-row' },\n h('div', { className: 'ait-section-title' }, `Storage (${entries.length} items)`),\n clearBtn,\n ),\n entries.length === 0\n ? h('div', { style: 'color:#555;font-size:12px' }, 'No items in storage')\n : h('div', {},\n ...entries.map(([key, value]) =>\n h('div', { className: 'ait-storage-row' },\n h('span', { className: 'ait-storage-key' }, key),\n h('span', { className: 'ait-storage-value' }, value.length > 100 ? value.slice(0, 100) + '...' : value),\n ),\n ),\n ),\n ),\n );\n return container;\n}\n\nconst TAB_RENDERERS: Record<TabId, () => HTMLElement> = {\n env: renderEnvTab,\n permissions: renderPermissionsTab,\n location: renderLocationTab,\n iap: renderIapTab,\n events: renderEventsTab,\n analytics: renderAnalyticsTab,\n storage: renderStorageTab,\n};\n\n// --- Mount ---\n\nlet currentTab: TabId = 'env';\nlet panelEl: HTMLElement | null = null;\nlet bodyEl: HTMLElement | null = null;\nlet tabsEl: HTMLElement | null = null;\n\nfunction refreshPanel() {\n if (!bodyEl || !tabsEl) return;\n bodyEl.innerHTML = '';\n bodyEl.appendChild(TAB_RENDERERS[currentTab]());\n\n tabsEl.querySelectorAll('.ait-panel-tab').forEach(el => {\n el.classList.toggle('active', el.getAttribute('data-tab') === currentTab);\n });\n}\n\nfunction mount() {\n if (typeof document === 'undefined') return;\n if (document.querySelector('.ait-panel-toggle')) return;\n\n // Styles\n const style = document.createElement('style');\n style.textContent = PANEL_STYLES;\n document.head.appendChild(style);\n\n // Toggle button\n const toggle = h('button', { className: 'ait-panel-toggle', title: 'AIT DevTools' }, 'AIT');\n let isOpen = false;\n\n // Panel\n panelEl = h('div', { className: 'ait-panel' });\n\n const header = h('div', { className: 'ait-panel-header' },\n h('span', {}, 'AIT DevTools'),\n h('span', { style: 'font-size:11px;color:#666;font-weight:400' }, `v${aitState.state.appVersion}`),\n );\n\n tabsEl = h('div', { className: 'ait-panel-tabs' });\n for (const tab of TABS) {\n const tabEl = h('button', { className: 'ait-panel-tab', 'data-tab': tab.id }, tab.label);\n tabEl.addEventListener('click', () => {\n currentTab = tab.id;\n refreshPanel();\n });\n tabsEl.appendChild(tabEl);\n }\n\n bodyEl = h('div', { className: 'ait-panel-body' });\n\n panelEl.append(header, tabsEl, bodyEl);\n document.body.append(panelEl, toggle);\n\n toggle.addEventListener('click', () => {\n isOpen = !isOpen;\n panelEl!.classList.toggle('open', isOpen);\n if (isOpen) refreshPanel();\n });\n\n // 상태 변경 시 자동 갱신 (analytics, storage 탭)\n aitState.subscribe(() => {\n if (isOpen && (currentTab === 'analytics' || currentTab === 'storage')) {\n refreshPanel();\n }\n });\n\n refreshPanel();\n}\n\n// DOM ready 시 마운트\nif (typeof document !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', mount);\n } else {\n mount();\n }\n}\n\nexport { mount };\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/panel/styles.ts","../../src/panel/index.ts"],"sourcesContent":["/**\n * Floating Panel CSS (inline, 외부 의존성 없음)\n */\n\nexport const PANEL_WIDTH = 360;\nexport const PANEL_HEIGHT = 480;\n\nexport const PANEL_STYLES = /* css */ `\n .ait-panel-toggle {\n position: fixed;\n z-index: 99999;\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: #3182F6;\n border: none;\n cursor: pointer;\n box-shadow: 0 2px 12px rgba(0,0,0,0.2);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 20px;\n color: white;\n transition: transform 0.15s;\n font-family: -apple-system, BlinkMacSystemFont, sans-serif;\n touch-action: none;\n user-select: none;\n }\n .ait-panel-toggle:hover:not(.dragging) {\n transform: scale(1.1);\n }\n\n .ait-panel {\n position: fixed;\n z-index: 99998;\n width: ${PANEL_WIDTH}px;\n height: ${PANEL_HEIGHT}px;\n background: #1a1a2e;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.4);\n font-family: -apple-system, BlinkMacSystemFont, 'Pretendard', sans-serif;\n font-size: 13px;\n color: #e0e0e0;\n overflow: hidden;\n display: none;\n }\n .ait-panel.open {\n display: flex;\n flex-direction: column;\n }\n\n .ait-panel-header {\n padding: 12px 16px;\n background: #16213e;\n font-weight: 600;\n font-size: 14px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n border-bottom: 1px solid #2a2a4a;\n }\n .ait-panel-header > span:first-child {\n color: #3182F6;\n }\n\n .ait-panel-tabs {\n display: flex;\n background: #16213e;\n border-bottom: 1px solid #2a2a4a;\n overflow-x: auto;\n scrollbar-width: none;\n }\n .ait-panel-tabs::-webkit-scrollbar { display: none; }\n\n .ait-panel-tab {\n padding: 8px 12px;\n font-size: 12px;\n color: #888;\n cursor: pointer;\n white-space: nowrap;\n border-bottom: 2px solid transparent;\n background: none;\n border-top: none;\n border-left: none;\n border-right: none;\n font-family: inherit;\n }\n .ait-panel-tab:hover {\n color: #bbb;\n }\n .ait-panel-tab.active {\n color: #3182F6;\n border-bottom-color: #3182F6;\n }\n\n .ait-panel-body {\n padding: 12px 16px;\n overflow-y: auto;\n flex: 1;\n min-height: 0;\n }\n\n .ait-section {\n margin-bottom: 16px;\n }\n .ait-section-title {\n font-size: 11px;\n text-transform: uppercase;\n color: #666;\n margin-bottom: 8px;\n letter-spacing: 0.5px;\n }\n\n .ait-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 6px;\n }\n .ait-row label {\n color: #aaa;\n font-size: 12px;\n }\n\n .ait-select {\n background: #2a2a4a;\n color: #e0e0e0;\n border: 1px solid #3a3a5a;\n border-radius: 4px;\n padding: 4px 8px;\n font-size: 12px;\n font-family: inherit;\n cursor: pointer;\n }\n\n .ait-input {\n background: #2a2a4a;\n color: #e0e0e0;\n border: 1px solid #3a3a5a;\n border-radius: 4px;\n padding: 4px 8px;\n font-size: 12px;\n width: 100px;\n font-family: inherit;\n }\n\n .ait-btn {\n background: #3182F6;\n color: white;\n border: none;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 12px;\n cursor: pointer;\n font-family: inherit;\n }\n .ait-btn:hover {\n background: #1b6ef3;\n }\n .ait-btn-sm {\n padding: 4px 8px;\n font-size: 11px;\n }\n .ait-btn-danger {\n background: #e74c3c;\n }\n .ait-btn-danger:hover {\n background: #c0392b;\n }\n\n .ait-log-entry {\n font-family: 'SF Mono', 'Menlo', monospace;\n font-size: 11px;\n padding: 3px 0;\n border-bottom: 1px solid #2a2a4a;\n color: #aaa;\n }\n .ait-log-entry .ait-log-type {\n color: #3182F6;\n font-weight: 600;\n margin-right: 6px;\n }\n .ait-log-entry .ait-log-time {\n color: #555;\n margin-right: 6px;\n }\n\n .ait-storage-row {\n font-family: 'SF Mono', 'Menlo', monospace;\n font-size: 11px;\n display: flex;\n gap: 8px;\n padding: 4px 0;\n border-bottom: 1px solid #2a2a4a;\n }\n .ait-storage-key {\n color: #e8a87c;\n min-width: 80px;\n word-break: break-all;\n }\n .ait-storage-value {\n color: #95e6cb;\n flex: 1;\n word-break: break-all;\n }\n\n /* Device tab */\n .ait-image-grid {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n margin-top: 8px;\n }\n .ait-image-thumb {\n position: relative;\n width: 64px;\n height: 64px;\n border-radius: 4px;\n overflow: hidden;\n border: 1px solid #3a3a5a;\n }\n .ait-image-thumb img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n .ait-image-thumb .ait-image-remove {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: rgba(231,76,60,0.9);\n color: white;\n border: none;\n cursor: pointer;\n font-size: 10px;\n line-height: 18px;\n text-align: center;\n padding: 0;\n }\n .ait-btn-row {\n display: flex;\n gap: 6px;\n margin-top: 8px;\n }\n .ait-btn-secondary {\n background: #2a2a4a;\n color: #e0e0e0;\n border: 1px solid #3a3a5a;\n border-radius: 4px;\n padding: 4px 8px;\n font-size: 11px;\n cursor: pointer;\n font-family: inherit;\n }\n .ait-btn-secondary:hover {\n background: #3a3a5a;\n }\n\n /* Prompt notification */\n .ait-prompt-banner {\n background: #2d1b69;\n border: 1px solid #6c3bd5;\n border-radius: 6px;\n padding: 10px 12px;\n margin-bottom: 12px;\n }\n .ait-prompt-banner .ait-prompt-title {\n color: #b388ff;\n font-size: 12px;\n font-weight: 600;\n margin-bottom: 8px;\n }\n .ait-prompt-input-row {\n display: flex;\n gap: 6px;\n align-items: center;\n margin-top: 6px;\n }\n .ait-prompt-input-row input {\n background: #2a2a4a;\n color: #e0e0e0;\n border: 1px solid #3a3a5a;\n border-radius: 4px;\n padding: 4px 8px;\n font-size: 12px;\n width: 80px;\n font-family: inherit;\n }\n .ait-prompt-input-row label {\n color: #aaa;\n font-size: 11px;\n min-width: 30px;\n }\n\n .ait-panel-close {\n display: none;\n background: none;\n border: none;\n color: #888;\n font-size: 18px;\n cursor: pointer;\n padding: 0 4px;\n font-family: inherit;\n }\n .ait-panel-close:hover {\n color: #e0e0e0;\n }\n\n /* Disabled state for monitoring-only mode */\n .ait-select:disabled,\n .ait-input:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n .ait-btn:disabled,\n .ait-btn-secondary:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n .ait-btn-danger:disabled {\n background: #5a5a5a;\n }\n\n /* Mock status badge */\n .ait-mock-badge {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.3px;\n cursor: pointer;\n }\n .ait-mock-badge-on {\n background: #1a4731;\n color: #4ade80;\n }\n .ait-mock-badge-off {\n background: #4a1a1a;\n color: #f87171;\n }\n\n /* Monitoring-only notice */\n .ait-monitoring-notice {\n background: #2a1a00;\n border: 1px solid #6b4c00;\n border-radius: 4px;\n padding: 6px 10px;\n margin-bottom: 12px;\n font-size: 11px;\n color: #fbbf24;\n }\n\n @media (max-width: 480px) {\n .ait-panel.open {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 100%;\n max-height: 100%;\n border-radius: 0;\n }\n .ait-panel-toggle {\n z-index: 100000;\n }\n .ait-panel-close {\n display: block;\n }\n }\n`;\n","/**\n * @ait-co/devtools Floating Panel\n *\n * import 하면 자동으로 페이지에 DevTools 패널을 마운트한다.\n * 외부 의존성 없이 vanilla DOM으로 구현.\n */\n\nimport { aitState } from '../mock/state.js';\nimport type { PermissionName, PermissionStatus, NetworkStatus, PlatformOS, OperationalEnvironment, IapNextResult, DeviceApiMode } from '../mock/state.js';\nimport { getDefaultPlaceholderImages } from '../mock/device/index.js';\nimport { PANEL_STYLES, PANEL_WIDTH, PANEL_HEIGHT } from './styles.js';\n\ntype TabId = 'env' | 'permissions' | 'location' | 'iap' | 'events' | 'analytics' | 'storage' | 'device';\n\nconst TABS: Array<{ id: TabId; label: string }> = [\n { id: 'env', label: 'Environment' },\n { id: 'permissions', label: 'Permissions' },\n { id: 'location', label: 'Location' },\n { id: 'device', label: 'Device' },\n { id: 'iap', label: 'IAP' },\n { id: 'events', label: 'Events' },\n { id: 'analytics', label: 'Analytics' },\n { id: 'storage', label: 'Storage' },\n];\n\nfunction h<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n attrs?: Record<string, string>,\n ...children: (string | Node)[]\n): HTMLElementTagNameMap[K] {\n const el = document.createElement(tag);\n if (attrs) {\n for (const [k, v] of Object.entries(attrs)) {\n if (k === 'className') el.className = v;\n else el.setAttribute(k, v);\n }\n }\n for (const child of children) {\n el.append(typeof child === 'string' ? document.createTextNode(child) : child);\n }\n return el;\n}\n\nfunction selectRow(\n label: string,\n options: string[],\n value: string,\n onChange: (v: string) => void,\n disabled = false,\n): HTMLElement {\n const select = h('select', { className: 'ait-select' });\n if (disabled) select.disabled = true;\n for (const opt of options) {\n const option = h('option', { value: opt }, opt);\n if (opt === value) option.selected = true;\n select.appendChild(option);\n }\n select.addEventListener('change', () => onChange(select.value));\n return h('div', { className: 'ait-row' }, h('label', {}, label), select);\n}\n\nfunction inputRow(label: string, value: string, onChange: (v: string) => void, disabled = false): HTMLElement {\n const input = h('input', { className: 'ait-input', value });\n if (disabled) input.disabled = true;\n input.addEventListener('change', () => onChange(input.value));\n return h('div', { className: 'ait-row' }, h('label', {}, label), input);\n}\n\nfunction renderEnvTab(): HTMLElement {\n const s = aitState.state;\n const disabled = !s.panelEditable;\n const container = h('div');\n\n if (disabled) container.appendChild(monitoringNotice());\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Platform'),\n selectRow('OS', ['ios', 'android'], s.platform, v => aitState.update({ platform: v as PlatformOS }), disabled),\n inputRow('App Version', s.appVersion, v => aitState.update({ appVersion: v }), disabled),\n selectRow('Environment', ['toss', 'sandbox'], s.environment, v => aitState.update({ environment: v as OperationalEnvironment }), disabled),\n inputRow('Locale', s.locale, v => aitState.update({ locale: v }), disabled),\n ),\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Network'),\n selectRow('Status', ['WIFI', '4G', '5G', '3G', '2G', 'OFFLINE', 'WWAN', 'UNKNOWN'], s.networkStatus, v => aitState.update({ networkStatus: v as NetworkStatus }), disabled),\n ),\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Safe Area Insets'),\n inputRow('Top', String(s.safeAreaInsets.top), v => aitState.patch('safeAreaInsets', { top: Number(v) }), disabled),\n inputRow('Bottom', String(s.safeAreaInsets.bottom), v => aitState.patch('safeAreaInsets', { bottom: Number(v) }), disabled),\n ),\n );\n return container;\n}\n\nfunction renderPermissionsTab(): HTMLElement {\n const s = aitState.state;\n const disabled = !s.panelEditable;\n const container = h('div');\n const names: PermissionName[] = ['camera', 'photos', 'geolocation', 'clipboard', 'contacts', 'microphone'];\n const statuses: PermissionStatus[] = ['allowed', 'denied', 'notDetermined'];\n\n if (disabled) container.appendChild(monitoringNotice());\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Device Permissions'),\n ...names.map(name =>\n selectRow(name, statuses, s.permissions[name], v => {\n aitState.patch('permissions', { [name]: v as PermissionStatus });\n }, disabled),\n ),\n ),\n );\n return container;\n}\n\nfunction renderLocationTab(): HTMLElement {\n const s = aitState.state;\n const disabled = !s.panelEditable;\n const container = h('div');\n\n if (disabled) container.appendChild(monitoringNotice());\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Current Location'),\n inputRow('Latitude', String(s.location.coords.latitude), v => {\n const coords = { ...s.location.coords, latitude: Number(v) };\n aitState.patch('location', { coords } as Partial<typeof s.location>);\n }, disabled),\n inputRow('Longitude', String(s.location.coords.longitude), v => {\n const coords = { ...s.location.coords, longitude: Number(v) };\n aitState.patch('location', { coords } as Partial<typeof s.location>);\n }, disabled),\n inputRow('Accuracy', String(s.location.coords.accuracy), v => {\n const coords = { ...s.location.coords, accuracy: Number(v) };\n aitState.patch('location', { coords } as Partial<typeof s.location>);\n }, disabled),\n ),\n );\n return container;\n}\n\nfunction renderIapTab(): HTMLElement {\n const s = aitState.state;\n const disabled = !s.panelEditable;\n const container = h('div');\n const results: IapNextResult[] = ['success', 'USER_CANCELED', 'INVALID_PRODUCT_ID', 'PAYMENT_PENDING', 'NETWORK_ERROR', 'ITEM_ALREADY_OWNED', 'INTERNAL_ERROR'];\n\n if (disabled) container.appendChild(monitoringNotice());\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'IAP Simulator'),\n selectRow('Next Purchase Result', results, s.iap.nextResult, v => {\n aitState.patch('iap', { nextResult: v as IapNextResult });\n }, disabled),\n ),\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'TossPay'),\n selectRow('Next Payment Result', ['success', 'fail'], s.payment.nextResult, v => {\n aitState.patch('payment', { nextResult: v as 'success' | 'fail' });\n }, disabled),\n ),\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, `Completed Orders (${s.iap.completedOrders.length})`),\n ...s.iap.completedOrders.slice(-5).map(o =>\n h('div', { className: 'ait-log-entry' },\n h('span', { className: 'ait-log-type' }, o.status),\n `${o.sku} (${o.orderId.slice(-8)})`,\n ),\n ),\n ),\n );\n return container;\n}\n\nfunction renderEventsTab(): HTMLElement {\n const disabled = !aitState.state.panelEditable;\n const container = h('div');\n\n if (disabled) container.appendChild(monitoringNotice());\n\n const backBtn = h('button', { className: 'ait-btn' }, 'Trigger Back Event');\n backBtn.addEventListener('click', () => aitState.trigger('backEvent'));\n if (disabled) backBtn.disabled = true;\n\n const homeBtn = h('button', { className: 'ait-btn' }, 'Trigger Home Event');\n homeBtn.addEventListener('click', () => aitState.trigger('homeEvent'));\n if (disabled) homeBtn.disabled = true;\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Navigation Events'),\n h('div', { className: 'ait-row' }, backBtn, homeBtn),\n ),\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Login'),\n selectRow('Logged In', ['true', 'false'], String(aitState.state.auth.isLoggedIn), v => {\n aitState.patch('auth', { isLoggedIn: v === 'true' });\n }, disabled),\n selectRow('Toss Login Integrated', ['true', 'false'], String(aitState.state.auth.isTossLoginIntegrated), v => {\n aitState.patch('auth', { isTossLoginIntegrated: v === 'true' });\n }, disabled),\n ),\n );\n return container;\n}\n\nfunction renderAnalyticsTab(): HTMLElement {\n const disabled = !aitState.state.panelEditable;\n const container = h('div');\n if (disabled) container.appendChild(monitoringNotice());\n const logs = aitState.state.analyticsLog;\n\n const clearBtn = h('button', { className: 'ait-btn ait-btn-sm ait-btn-danger' }, 'Clear');\n if (disabled) clearBtn.disabled = true;\n clearBtn.addEventListener('click', () => {\n aitState.state.analyticsLog.length = 0;\n refreshPanel();\n });\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-row' },\n h('div', { className: 'ait-section-title' }, `Analytics Log (${logs.length})`),\n clearBtn,\n ),\n ...logs.slice(-30).reverse().map(entry => {\n const time = new Date(entry.timestamp).toLocaleTimeString('ko-KR', { hour12: false });\n return h('div', { className: 'ait-log-entry' },\n h('span', { className: 'ait-log-time' }, time),\n h('span', { className: 'ait-log-type' }, entry.type),\n JSON.stringify(entry.params),\n );\n }),\n ),\n );\n return container;\n}\n\nfunction renderStorageTab(): HTMLElement {\n const disabled = !aitState.state.panelEditable;\n const container = h('div');\n if (disabled) container.appendChild(monitoringNotice());\n const prefix = '__ait_storage:';\n const entries: Array<[string, string]> = [];\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(prefix)) {\n entries.push([key.slice(prefix.length), localStorage.getItem(key) ?? '']);\n }\n }\n\n const clearBtn = h('button', { className: 'ait-btn ait-btn-sm ait-btn-danger' }, 'Clear All');\n if (disabled) clearBtn.disabled = true;\n clearBtn.addEventListener('click', () => {\n entries.forEach(([key]) => localStorage.removeItem(prefix + key));\n refreshPanel();\n });\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-row' },\n h('div', { className: 'ait-section-title' }, `Storage (${entries.length} items)`),\n clearBtn,\n ),\n entries.length === 0\n ? h('div', { style: 'color:#555;font-size:12px' }, 'No items in storage')\n : h('div', {},\n ...entries.map(([key, value]) =>\n h('div', { className: 'ait-storage-row' },\n h('span', { className: 'ait-storage-key' }, key),\n h('span', { className: 'ait-storage-value' }, value.length > 100 ? value.slice(0, 100) + '...' : value),\n ),\n ),\n ),\n ),\n );\n return container;\n}\n\n// --- Prompt mode state ---\ninterface PendingPrompt {\n type: string;\n}\nlet pendingPrompt: PendingPrompt | null = null;\n\n// Listen for prompt requests from device APIs\nif (typeof window !== 'undefined') {\n window.addEventListener('__ait:prompt-request', (e: Event) => {\n const detail = (e as CustomEvent).detail as { type: string };\n pendingPrompt = { type: detail.type };\n // Auto-switch to device tab and open panel\n currentTab = 'device';\n if (panelEl && !panelEl.classList.contains('open')) {\n panelEl.classList.add('open');\n }\n refreshPanel();\n });\n}\n\nfunction resolvePrompt(type: string, data: unknown) {\n window.dispatchEvent(new CustomEvent('__ait:prompt-response:' + type, { detail: data }));\n pendingPrompt = null;\n refreshPanel();\n}\n\nfunction renderPromptBanner(): HTMLElement | null {\n if (!pendingPrompt) return null;\n\n const banner = h('div', { className: 'ait-prompt-banner' });\n\n if (pendingPrompt.type === 'camera') {\n banner.append(\n h('div', { className: 'ait-prompt-title' }, 'Camera Prompt — Select an image'),\n );\n const input = h('input', { type: 'file', accept: 'image/*', style: 'font-size:11px;color:#aaa' });\n input.addEventListener('change', () => {\n const file = (input as HTMLInputElement).files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = () => resolvePrompt('camera', reader.result as string);\n reader.readAsDataURL(file);\n });\n banner.appendChild(input);\n } else if (pendingPrompt.type === 'photos') {\n banner.append(\n h('div', { className: 'ait-prompt-title' }, 'Photos Prompt — Select images'),\n );\n const input = h('input', { type: 'file', accept: 'image/*', multiple: '', style: 'font-size:11px;color:#aaa' });\n input.addEventListener('change', () => {\n const files = Array.from((input as HTMLInputElement).files ?? []);\n if (files.length === 0) return;\n Promise.all(files.map(file => new Promise<string>((res) => {\n const reader = new FileReader();\n reader.onload = () => res(reader.result as string);\n reader.readAsDataURL(file);\n }))).then(dataUris => resolvePrompt('photos', dataUris));\n });\n banner.appendChild(input);\n } else if (pendingPrompt.type === 'location' || pendingPrompt.type === 'location-update') {\n banner.append(\n h('div', { className: 'ait-prompt-title' },\n pendingPrompt.type === 'location' ? 'Location Prompt — Enter coordinates' : 'Location Update — Send coordinates'),\n );\n const latInput = h('input', { className: 'ait-input', value: String(aitState.state.location.coords.latitude), style: 'width:80px' });\n const lngInput = h('input', { className: 'ait-input', value: String(aitState.state.location.coords.longitude), style: 'width:80px' });\n const sendBtn = h('button', { className: 'ait-btn ait-btn-sm' }, 'Send');\n sendBtn.addEventListener('click', () => {\n const loc = {\n coords: {\n latitude: Number((latInput as HTMLInputElement).value),\n longitude: Number((lngInput as HTMLInputElement).value),\n altitude: 0,\n accuracy: 10,\n altitudeAccuracy: 0,\n heading: 0,\n },\n timestamp: Date.now(),\n accessLocation: 'FINE' as const,\n };\n resolvePrompt(pendingPrompt!.type, loc);\n });\n banner.append(\n h('div', { className: 'ait-prompt-input-row' },\n h('label', {}, 'Lat'), latInput,\n h('label', {}, 'Lng'), lngInput,\n sendBtn,\n ),\n );\n } else {\n // Fallback for unknown prompt types\n banner.append(\n h('div', { className: 'ait-prompt-title' }, `Prompt: ${pendingPrompt.type}`),\n );\n }\n\n // Cancel button for all prompt types\n const cancelBtn = h('button', { className: 'ait-btn ait-btn-sm ait-btn-danger', style: 'margin-top:8px' }, 'Cancel');\n cancelBtn.addEventListener('click', () => {\n pendingPrompt = null;\n window.dispatchEvent(new CustomEvent('__ait:prompt-cancel'));\n refreshPanel();\n });\n banner.appendChild(cancelBtn);\n\n return banner;\n}\n\nfunction renderDeviceTab(): HTMLElement {\n const s = aitState.state;\n const disabled = !s.panelEditable;\n const container = h('div');\n\n if (disabled) container.appendChild(monitoringNotice());\n\n // Prompt banner (if active, only when panelEditable)\n if (s.panelEditable) {\n const promptBanner = renderPromptBanner();\n if (promptBanner) container.appendChild(promptBanner);\n }\n\n // Device API Mode selectors\n const modeEntries: Array<{ label: string; key: keyof typeof s.deviceModes; options: string[] }> = [\n { label: 'Camera', key: 'camera', options: ['mock', 'web', 'prompt'] },\n { label: 'Photos', key: 'photos', options: ['mock', 'web', 'prompt'] },\n { label: 'Location', key: 'location', options: ['mock', 'web', 'prompt'] },\n { label: 'Network', key: 'network', options: ['mock', 'web'] },\n { label: 'Clipboard', key: 'clipboard', options: ['mock', 'web'] },\n ];\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Device API Modes'),\n ...modeEntries.map(entry =>\n selectRow(entry.label, entry.options, s.deviceModes[entry.key], v => {\n aitState.patch('deviceModes', { [entry.key]: v } as Partial<typeof s.deviceModes>);\n refreshPanel();\n }, disabled),\n ),\n ),\n );\n\n // Mock Images management\n const images = s.mockData.images;\n const imageGrid = h('div', { className: 'ait-image-grid' });\n images.forEach((dataUri, idx) => {\n const thumb = h('div', { className: 'ait-image-thumb' });\n const img = h('img', { src: dataUri });\n const removeBtn = h('button', { className: 'ait-image-remove' }, 'x');\n removeBtn.addEventListener('click', () => {\n const newImages = [...aitState.state.mockData.images];\n newImages.splice(idx, 1);\n aitState.patch('mockData', { images: newImages });\n refreshPanel();\n });\n if (disabled) removeBtn.disabled = true;\n thumb.append(img, removeBtn);\n imageGrid.appendChild(thumb);\n });\n\n const addBtn = h('button', { className: 'ait-btn-secondary' }, '+ Add');\n addBtn.addEventListener('click', () => {\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = 'image/*';\n input.multiple = true;\n input.onchange = () => {\n const files = Array.from(input.files ?? []);\n Promise.all(files.map(file => new Promise<string>((res) => {\n const reader = new FileReader();\n reader.onload = () => res(reader.result as string);\n reader.readAsDataURL(file);\n }))).then(dataUris => {\n aitState.patch('mockData', { images: [...aitState.state.mockData.images, ...dataUris] });\n refreshPanel();\n });\n };\n input.click();\n });\n if (disabled) addBtn.disabled = true;\n\n const defaultsBtn = h('button', { className: 'ait-btn-secondary' }, 'Use defaults');\n defaultsBtn.addEventListener('click', () => {\n aitState.patch('mockData', { images: [...getDefaultPlaceholderImages()] });\n refreshPanel();\n });\n if (disabled) defaultsBtn.disabled = true;\n\n const clearImagesBtn = h('button', { className: 'ait-btn-secondary' }, 'Clear');\n clearImagesBtn.addEventListener('click', () => {\n aitState.patch('mockData', { images: [] });\n refreshPanel();\n });\n if (disabled) clearImagesBtn.disabled = true;\n\n container.append(\n h('div', { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, `Mock Images (${images.length})`),\n imageGrid,\n h('div', { className: 'ait-btn-row' }, addBtn, defaultsBtn, clearImagesBtn),\n ),\n );\n\n return container;\n}\n\nfunction monitoringNotice(): HTMLElement {\n return h('div', { className: 'ait-monitoring-notice' },\n 'Read-only — mock responses are controlled at build time.',\n );\n}\n\nconst TAB_RENDERERS: Record<TabId, () => HTMLElement> = {\n env: renderEnvTab,\n permissions: renderPermissionsTab,\n location: renderLocationTab,\n device: renderDeviceTab,\n iap: renderIapTab,\n events: renderEventsTab,\n analytics: renderAnalyticsTab,\n storage: renderStorageTab,\n};\n\n// --- Draggable toggle button ---\n\nfunction makeDraggable(el: HTMLElement, onClickOnly: () => void) {\n let isDragging = false;\n let startX = 0, startY = 0;\n let startLeft = 0, startTop = 0;\n let hasMoved = false;\n\n el.addEventListener('pointerdown', (e) => {\n isDragging = true;\n hasMoved = false;\n startX = e.clientX;\n startY = e.clientY;\n const rect = el.getBoundingClientRect();\n startLeft = rect.left;\n startTop = rect.top;\n el.setPointerCapture(e.pointerId);\n e.preventDefault();\n });\n\n el.addEventListener('pointermove', (e) => {\n if (!isDragging) return;\n const dx = e.clientX - startX;\n const dy = e.clientY - startY;\n if (Math.abs(dx) > 3 || Math.abs(dy) > 3) {\n hasMoved = true;\n el.classList.add('dragging');\n }\n if (!hasMoved) return;\n\n el.style.left = (startLeft + dx) + 'px';\n el.style.top = (startTop + dy) + 'px';\n el.style.right = 'auto';\n el.style.bottom = 'auto';\n });\n\n el.addEventListener('pointerup', (e) => {\n if (!isDragging) return;\n isDragging = false;\n el.classList.remove('dragging');\n el.releasePointerCapture(e.pointerId);\n\n if (hasMoved) {\n snapToEdge(el);\n updatePanelPosition(el);\n saveButtonPosition(el);\n } else {\n onClickOnly();\n }\n });\n\n el.addEventListener('pointercancel', (e) => {\n isDragging = false;\n el.classList.remove('dragging');\n el.releasePointerCapture(e.pointerId);\n if (hasMoved) {\n snapToEdge(el);\n updatePanelPosition(el);\n saveButtonPosition(el);\n }\n });\n}\n\nfunction snapToEdge(el: HTMLElement) {\n const rect = el.getBoundingClientRect();\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const cx = rect.left + rect.width / 2;\n const margin = 16;\n\n if (cx < vw / 2) {\n el.style.left = margin + 'px';\n el.style.right = 'auto';\n } else {\n el.style.left = 'auto';\n el.style.right = margin + 'px';\n }\n\n const top = Math.max(margin, Math.min(vh - rect.height - margin, rect.top));\n el.style.top = top + 'px';\n el.style.bottom = 'auto';\n}\n\nfunction updatePanelPosition(toggleEl: HTMLElement) {\n if (!panelEl) return;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n\n // On mobile viewports, CSS media query handles fullscreen — clear any inline positioning\n if (vw <= 480) {\n panelEl.style.top = '';\n panelEl.style.left = '';\n panelEl.style.right = '';\n panelEl.style.bottom = '';\n return;\n }\n\n const rect = toggleEl.getBoundingClientRect();\n const panelWidth = PANEL_WIDTH;\n const panelHeight = PANEL_HEIGHT;\n const margin = 16;\n\n // Horizontal: place panel on the same side as the toggle button\n if (rect.left < vw / 2) {\n panelEl.style.left = margin + 'px';\n panelEl.style.right = 'auto';\n } else {\n panelEl.style.left = 'auto';\n panelEl.style.right = margin + 'px';\n }\n\n // Vertical: place below button if it's in top half, above if bottom half\n // Clamp so panel stays within viewport\n if (rect.top < vh / 2) {\n const top = Math.min(rect.bottom + 8, vh - panelHeight - margin);\n panelEl.style.top = Math.max(margin, top) + 'px';\n panelEl.style.bottom = 'auto';\n } else {\n const bottom = Math.min(vh - rect.top + 8, vh - panelHeight - margin);\n panelEl.style.top = 'auto';\n panelEl.style.bottom = Math.max(margin, bottom) + 'px';\n }\n}\n\nfunction saveButtonPosition(el: HTMLElement) {\n localStorage.setItem('__ait_btn_pos', JSON.stringify({\n left: el.style.left,\n top: el.style.top,\n right: el.style.right,\n bottom: el.style.bottom,\n }));\n}\n\n// Uses __ait_btn_pos (not __ait_storage: prefix) — panel-internal state, not mock storage\nfunction restoreButtonPosition(el: HTMLElement) {\n const saved = localStorage.getItem('__ait_btn_pos');\n if (saved) {\n try {\n const pos = JSON.parse(saved);\n if (typeof pos !== 'object' || pos === null) return;\n const allowedKeys = ['left', 'top', 'right', 'bottom'] as const;\n const validCssValue = /^(\\d+px|auto)$/;\n for (const key of allowedKeys) {\n if (key in pos && typeof pos[key] === 'string' && validCssValue.test(pos[key])) {\n el.style[key] = pos[key];\n }\n }\n } catch { /* ignore */ }\n } else {\n el.style.bottom = '16px';\n el.style.right = '16px';\n }\n}\n\n// --- Mount ---\n\nlet currentTab: TabId = 'env';\nlet panelEl: HTMLElement | null = null;\nlet bodyEl: HTMLElement | null = null;\nlet tabsEl: HTMLElement | null = null;\n\nfunction refreshPanel() {\n if (!bodyEl || !tabsEl) return;\n bodyEl.innerHTML = '';\n bodyEl.appendChild(TAB_RENDERERS[currentTab]());\n\n tabsEl.querySelectorAll('.ait-panel-tab').forEach(el => {\n el.classList.toggle('active', el.getAttribute('data-tab') === currentTab);\n });\n}\n\nfunction mount() {\n if (typeof document === 'undefined') return;\n if (document.querySelector('.ait-panel-toggle')) return;\n\n // Styles\n const style = document.createElement('style');\n style.textContent = PANEL_STYLES;\n document.head.appendChild(style);\n\n // Toggle button\n const toggle = h('button', { className: 'ait-panel-toggle', title: 'AIT DevTools' }, 'AIT');\n let isOpen = false;\n restoreButtonPosition(toggle);\n\n // Panel\n panelEl = h('div', { className: 'ait-panel' });\n\n const closeBtn = h('button', { className: 'ait-panel-close', title: 'Close' }, '\\u00d7');\n closeBtn.addEventListener('click', () => {\n isOpen = false;\n panelEl!.classList.remove('open');\n });\n\n const mockBadge = h('span', {\n className: `ait-mock-badge ${aitState.state.panelEditable ? 'ait-mock-badge-on' : 'ait-mock-badge-off'}`,\n title: 'Toggle panel edit mode',\n }, aitState.state.panelEditable ? 'EDIT' : 'READ-ONLY');\n\n mockBadge.addEventListener('click', () => {\n aitState.update({ panelEditable: !aitState.state.panelEditable });\n mockBadge.className = `ait-mock-badge ${aitState.state.panelEditable ? 'ait-mock-badge-on' : 'ait-mock-badge-off'}`;\n mockBadge.textContent = aitState.state.panelEditable ? 'EDIT' : 'READ-ONLY';\n refreshPanel();\n });\n\n const headerRight = h('span', { style: 'display:flex;align-items:center;gap:6px' },\n mockBadge,\n h('span', { style: 'font-size:11px;color:#666;font-weight:400' }, `v${__VERSION__}`),\n closeBtn,\n );\n const header = h('div', { className: 'ait-panel-header' },\n h('span', {}, 'AIT DevTools'),\n headerRight,\n );\n\n tabsEl = h('div', { className: 'ait-panel-tabs' });\n for (const tab of TABS) {\n const tabEl = h('button', { className: 'ait-panel-tab', 'data-tab': tab.id }, tab.label);\n tabEl.addEventListener('click', () => {\n currentTab = tab.id;\n refreshPanel();\n });\n tabsEl.appendChild(tabEl);\n }\n\n bodyEl = h('div', { className: 'ait-panel-body' });\n\n panelEl.append(header, tabsEl, bodyEl);\n document.body.append(panelEl, toggle);\n\n // Re-clamp restored position to current viewport (e.g., saved on wider screen)\n snapToEdge(toggle);\n saveButtonPosition(toggle);\n\n makeDraggable(toggle, () => {\n isOpen = !isOpen;\n panelEl!.classList.toggle('open', isOpen);\n if (isOpen) {\n updatePanelPosition(toggle);\n refreshPanel();\n }\n });\n\n // Re-clamp button and panel position on window resize (rAF-throttled)\n let resizeRaf = 0;\n window.addEventListener('resize', () => {\n if (resizeRaf) return;\n resizeRaf = requestAnimationFrame(() => {\n resizeRaf = 0;\n snapToEdge(toggle);\n saveButtonPosition(toggle);\n if (isOpen) updatePanelPosition(toggle);\n });\n });\n\n // 상태 변경 시 자동 갱신 (analytics, storage 탭)\n aitState.subscribe(() => {\n if (isOpen && (currentTab === 'analytics' || currentTab === 'storage' || currentTab === 'device')) {\n refreshPanel();\n }\n });\n\n refreshPanel();\n}\n\n// DOM ready 시 마운트\nif (typeof document !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', mount);\n } else {\n mount();\n }\n}\n\nexport { mount };\n"],"mappings":"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","names":[]}
@@ -33,28 +33,29 @@ var FRAMEWORK_ID = "@apps-in-toss/web-framework";
33
33
  var BRIDGE_ID = "@apps-in-toss/web-bridge";
34
34
  var ANALYTICS_ID = "@apps-in-toss/web-analytics";
35
35
  var aitDevtoolsPlugin = (0, import_unplugin.createUnplugin)((options) => {
36
- const _panel = options?.panel ?? true;
36
+ const isDev = process.env.NODE_ENV !== "production";
37
+ const shouldEnable = isDev || (options?.forceEnable ?? false);
38
+ const shouldMock = shouldEnable && (options?.mock ?? isDev);
39
+ const shouldPanel = shouldEnable && (options?.panel ?? true);
37
40
  return {
38
- name: "ait-devtools",
41
+ name: "ait-co-devtools",
39
42
  enforce: "pre",
40
43
  resolveId(id) {
44
+ if (!shouldMock) return null;
41
45
  if (id === FRAMEWORK_ID || id === BRIDGE_ID || id === ANALYTICS_ID) {
42
- return "ait-devtools/mock";
46
+ return "@ait-co/devtools/mock";
43
47
  }
44
48
  return null;
45
49
  },
46
50
  transformInclude(id) {
47
- if (!_panel) return false;
48
- return /\.(tsx?|jsx?)$/.test(id) && /main|index|entry|app/i.test(id);
51
+ if (!shouldPanel) return false;
52
+ return /\.(tsx?|jsx?)$/.test(id) && /\/(main|index|entry|app)\.[tj]sx?$/i.test(id) && !id.includes("node_modules");
49
53
  },
50
- transform(code, id) {
51
- if (!_panel) return null;
52
- if (code.includes("ait-devtools/panel")) return null;
53
- if (/main|index|entry/i.test(id) && !id.includes("node_modules")) {
54
- return `import 'ait-devtools/panel';
54
+ transform(code) {
55
+ if (!shouldPanel) return null;
56
+ if (code.includes("@ait-co/devtools/panel")) return null;
57
+ return `import '@ait-co/devtools/panel';
55
58
  ${code}`;
56
- }
57
- return null;
58
59
  }
59
60
  };
60
61
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/unplugin/index.ts"],"sourcesContent":["/**\n * ait-devtools unplugin\n *\n * 모든 주요 번들러를 지원하는 단일 플러그인.\n * @apps-in-toss/web-framework → ait-devtools/mock 으로 alias 설정.\n *\n * Usage:\n * import aitDevtools from 'ait-devtools/unplugin';\n *\n * // Vite\n * export default { plugins: [aitDevtools.vite()] };\n *\n * // Webpack / Next.js\n * config.plugins.push(aitDevtools.webpack());\n *\n * // Rspack\n * config.plugins.push(aitDevtools.rspack());\n *\n * // esbuild\n * { plugins: [aitDevtools.esbuild()] }\n *\n * // Rollup\n * { plugins: [aitDevtools.rollup()] }\n */\n\nimport { createUnplugin } from 'unplugin';\n\nexport interface AitDevtoolsOptions {\n /**\n * 패널 자동 주입 여부 (default: true)\n * true이면 진입점에 floating panel import를 자동 추가한다.\n */\n panel?: boolean;\n}\n\nconst FRAMEWORK_ID = '@apps-in-toss/web-framework';\nconst BRIDGE_ID = '@apps-in-toss/web-bridge';\nconst ANALYTICS_ID = '@apps-in-toss/web-analytics';\n\nconst aitDevtoolsPlugin = createUnplugin((options?: AitDevtoolsOptions) => {\n const _panel = options?.panel ?? true;\n\n return {\n name: 'ait-devtools',\n enforce: 'pre' as const,\n\n resolveId(id: string) {\n // @apps-in-toss/web-framework → ait-devtools/mock\n if (id === FRAMEWORK_ID || id === BRIDGE_ID || id === ANALYTICS_ID) {\n return 'ait-devtools/mock';\n }\n return null;\n },\n\n transformInclude(id: string) {\n if (!_panel) return false;\n // 진입점 파일에만 패널 import를 주입\n return /\\.(tsx?|jsx?)$/.test(id) && /main|index|entry|app/i.test(id);\n },\n\n transform(code: string, id: string) {\n if (!_panel) return null;\n // 이미 패널이 import 되어있으면 스킵\n if (code.includes('ait-devtools/panel')) return null;\n // 진입점에서 가장 처음으로 실행되도록 prepend\n if (/main|index|entry/i.test(id) && !id.includes('node_modules')) {\n return `import 'ait-devtools/panel';\\n${code}`;\n }\n return null;\n },\n };\n});\n\nexport const vite = aitDevtoolsPlugin.vite;\nexport const webpack = aitDevtoolsPlugin.webpack;\nexport const rollup = aitDevtoolsPlugin.rollup;\nexport const esbuild = aitDevtoolsPlugin.esbuild;\nexport const rspack = aitDevtoolsPlugin.rspack;\n\nexport default aitDevtoolsPlugin;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBA,sBAA+B;AAU/B,IAAM,eAAe;AACrB,IAAM,YAAY;AAClB,IAAM,eAAe;AAErB,IAAM,wBAAoB,gCAAe,CAAC,YAAiC;AACzE,QAAM,SAAS,SAAS,SAAS;AAEjC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,UAAU,IAAY;AAEpB,UAAI,OAAO,gBAAgB,OAAO,aAAa,OAAO,cAAc;AAClE,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IAEA,iBAAiB,IAAY;AAC3B,UAAI,CAAC,OAAQ,QAAO;AAEpB,aAAO,iBAAiB,KAAK,EAAE,KAAK,wBAAwB,KAAK,EAAE;AAAA,IACrE;AAAA,IAEA,UAAU,MAAc,IAAY;AAClC,UAAI,CAAC,OAAQ,QAAO;AAEpB,UAAI,KAAK,SAAS,oBAAoB,EAAG,QAAO;AAEhD,UAAI,oBAAoB,KAAK,EAAE,KAAK,CAAC,GAAG,SAAS,cAAc,GAAG;AAChE,eAAO;AAAA,EAAiC,IAAI;AAAA,MAC9C;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF,CAAC;AAEM,IAAM,OAAO,kBAAkB;AAC/B,IAAM,UAAU,kBAAkB;AAClC,IAAM,SAAS,kBAAkB;AACjC,IAAM,UAAU,kBAAkB;AAClC,IAAM,SAAS,kBAAkB;AAExC,IAAO,mBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../src/unplugin/index.ts"],"sourcesContent":["/**\n * @ait-co/devtools unplugin\n *\n * 모든 주요 번들러를 지원하는 단일 플러그인.\n * @apps-in-toss/web-framework → @ait-co/devtools/mock 으로 alias 설정.\n *\n * Usage:\n * import aitDevtools from '@ait-co/devtools/unplugin';\n *\n * // Vite\n * export default { plugins: [aitDevtools.vite()] };\n *\n * // Webpack / Next.js\n * config.plugins.push(aitDevtools.webpack());\n *\n * // Rspack\n * config.plugins.push(aitDevtools.rspack());\n *\n * // esbuild\n * { plugins: [aitDevtools.esbuild()] }\n *\n * // Rollup\n * { plugins: [aitDevtools.rollup()] }\n */\n\nimport { createUnplugin } from 'unplugin';\n\nexport interface AitDevtoolsOptions {\n /**\n * 패널 자동 주입 여부 (default: true)\n * true이면 진입점에 floating panel import를 자동 추가한다.\n */\n panel?: boolean;\n /**\n * production 환경에서도 devtools를 강제로 활성화 (default: false)\n */\n forceEnable?: boolean;\n /**\n * mock alias 활성화 여부. default: true (development), false (production + forceEnable)\n */\n mock?: boolean;\n}\n\nconst FRAMEWORK_ID = '@apps-in-toss/web-framework';\nconst BRIDGE_ID = '@apps-in-toss/web-bridge';\nconst ANALYTICS_ID = '@apps-in-toss/web-analytics';\n\nconst aitDevtoolsPlugin = createUnplugin((options?: AitDevtoolsOptions) => {\n const isDev = process.env.NODE_ENV !== 'production';\n const shouldEnable = isDev || (options?.forceEnable ?? false);\n const shouldMock = shouldEnable && (options?.mock ?? isDev);\n const shouldPanel = shouldEnable && (options?.panel ?? true);\n\n return {\n name: 'ait-co-devtools',\n enforce: 'pre' as const,\n\n resolveId(id: string) {\n if (!shouldMock) return null;\n // @apps-in-toss/web-framework → @ait-co/devtools/mock\n if (id === FRAMEWORK_ID || id === BRIDGE_ID || id === ANALYTICS_ID) {\n return '@ait-co/devtools/mock';\n }\n return null;\n },\n\n transformInclude(id: string) {\n if (!shouldPanel) return false;\n // 진입점 파일에만 패널 import를 주입\n return /\\.(tsx?|jsx?)$/.test(id) && /\\/(main|index|entry|app)\\.[tj]sx?$/i.test(id) && !id.includes('node_modules');\n },\n\n transform(code: string) {\n // transformInclude가 이미 shouldPanel을 확인하지만, 안전망으로 유지\n if (!shouldPanel) return null;\n // 이미 패널이 import 되어있으면 스킵\n if (code.includes('@ait-co/devtools/panel')) return null;\n // transformInclude가 진입점 파일만 통과시키므로 바로 prepend\n return `import '@ait-co/devtools/panel';\\n${code}`;\n },\n };\n});\n\nexport const vite = aitDevtoolsPlugin.vite;\nexport const webpack = aitDevtoolsPlugin.webpack;\nexport const rollup = aitDevtoolsPlugin.rollup;\nexport const esbuild = aitDevtoolsPlugin.esbuild;\nexport const rspack = aitDevtoolsPlugin.rspack;\n\nexport default aitDevtoolsPlugin;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBA,sBAA+B;AAkB/B,IAAM,eAAe;AACrB,IAAM,YAAY;AAClB,IAAM,eAAe;AAErB,IAAM,wBAAoB,gCAAe,CAAC,YAAiC;AACzE,QAAM,QAAQ,QAAQ,IAAI,aAAa;AACvC,QAAM,eAAe,UAAU,SAAS,eAAe;AACvD,QAAM,aAAa,iBAAiB,SAAS,QAAQ;AACrD,QAAM,cAAc,iBAAiB,SAAS,SAAS;AAEvD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,UAAU,IAAY;AACpB,UAAI,CAAC,WAAY,QAAO;AAExB,UAAI,OAAO,gBAAgB,OAAO,aAAa,OAAO,cAAc;AAClE,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IAEA,iBAAiB,IAAY;AAC3B,UAAI,CAAC,YAAa,QAAO;AAEzB,aAAO,iBAAiB,KAAK,EAAE,KAAK,sCAAsC,KAAK,EAAE,KAAK,CAAC,GAAG,SAAS,cAAc;AAAA,IACnH;AAAA,IAEA,UAAU,MAAc;AAEtB,UAAI,CAAC,YAAa,QAAO;AAEzB,UAAI,KAAK,SAAS,wBAAwB,EAAG,QAAO;AAEpD,aAAO;AAAA,EAAqC,IAAI;AAAA,IAClD;AAAA,EACF;AACF,CAAC;AAEM,IAAM,OAAO,kBAAkB;AAC/B,IAAM,UAAU,kBAAkB;AAClC,IAAM,SAAS,kBAAkB;AACjC,IAAM,UAAU,kBAAkB;AAClC,IAAM,SAAS,kBAAkB;AAExC,IAAO,mBAAQ;","names":[]}
@@ -0,0 +1,51 @@
1
+ import * as _rollup from 'rollup';
2
+ import * as _vite from 'vite';
3
+ import * as unplugin from 'unplugin';
4
+
5
+ /**
6
+ * @ait-co/devtools unplugin
7
+ *
8
+ * 모든 주요 번들러를 지원하는 단일 플러그인.
9
+ * @apps-in-toss/web-framework → @ait-co/devtools/mock 으로 alias 설정.
10
+ *
11
+ * Usage:
12
+ * import aitDevtools from '@ait-co/devtools/unplugin';
13
+ *
14
+ * // Vite
15
+ * export default { plugins: [aitDevtools.vite()] };
16
+ *
17
+ * // Webpack / Next.js
18
+ * config.plugins.push(aitDevtools.webpack());
19
+ *
20
+ * // Rspack
21
+ * config.plugins.push(aitDevtools.rspack());
22
+ *
23
+ * // esbuild
24
+ * { plugins: [aitDevtools.esbuild()] }
25
+ *
26
+ * // Rollup
27
+ * { plugins: [aitDevtools.rollup()] }
28
+ */
29
+ interface AitDevtoolsOptions {
30
+ /**
31
+ * 패널 자동 주입 여부 (default: true)
32
+ * true이면 진입점에 floating panel import를 자동 추가한다.
33
+ */
34
+ panel?: boolean;
35
+ /**
36
+ * production 환경에서도 devtools를 강제로 활성화 (default: false)
37
+ */
38
+ forceEnable?: boolean;
39
+ /**
40
+ * mock alias 활성화 여부. default: true (development), false (production + forceEnable)
41
+ */
42
+ mock?: boolean;
43
+ }
44
+ declare const aitDevtoolsPlugin: unplugin.UnpluginInstance<AitDevtoolsOptions | undefined, boolean>;
45
+ declare const vite: (options?: AitDevtoolsOptions | undefined) => _vite.Plugin<any> | _vite.Plugin<any>[];
46
+ declare const webpack: (options?: AitDevtoolsOptions | undefined) => WebpackPluginInstance;
47
+ declare const rollup: (options?: AitDevtoolsOptions | undefined) => _rollup.Plugin<any> | _rollup.Plugin<any>[];
48
+ declare const esbuild: (options?: AitDevtoolsOptions | undefined) => unplugin.EsbuildPlugin;
49
+ declare const rspack: (options?: AitDevtoolsOptions | undefined) => RspackPluginInstance;
50
+
51
+ export { type AitDevtoolsOptions, aitDevtoolsPlugin as default, esbuild, rollup, rspack, vite, webpack };
@@ -0,0 +1,51 @@
1
+ import * as _rollup from 'rollup';
2
+ import * as _vite from 'vite';
3
+ import * as unplugin from 'unplugin';
4
+
5
+ /**
6
+ * @ait-co/devtools unplugin
7
+ *
8
+ * 모든 주요 번들러를 지원하는 단일 플러그인.
9
+ * @apps-in-toss/web-framework → @ait-co/devtools/mock 으로 alias 설정.
10
+ *
11
+ * Usage:
12
+ * import aitDevtools from '@ait-co/devtools/unplugin';
13
+ *
14
+ * // Vite
15
+ * export default { plugins: [aitDevtools.vite()] };
16
+ *
17
+ * // Webpack / Next.js
18
+ * config.plugins.push(aitDevtools.webpack());
19
+ *
20
+ * // Rspack
21
+ * config.plugins.push(aitDevtools.rspack());
22
+ *
23
+ * // esbuild
24
+ * { plugins: [aitDevtools.esbuild()] }
25
+ *
26
+ * // Rollup
27
+ * { plugins: [aitDevtools.rollup()] }
28
+ */
29
+ interface AitDevtoolsOptions {
30
+ /**
31
+ * 패널 자동 주입 여부 (default: true)
32
+ * true이면 진입점에 floating panel import를 자동 추가한다.
33
+ */
34
+ panel?: boolean;
35
+ /**
36
+ * production 환경에서도 devtools를 강제로 활성화 (default: false)
37
+ */
38
+ forceEnable?: boolean;
39
+ /**
40
+ * mock alias 활성화 여부. default: true (development), false (production + forceEnable)
41
+ */
42
+ mock?: boolean;
43
+ }
44
+ declare const aitDevtoolsPlugin: unplugin.UnpluginInstance<AitDevtoolsOptions | undefined, boolean>;
45
+ declare const vite: (options?: AitDevtoolsOptions | undefined) => _vite.Plugin<any> | _vite.Plugin<any>[];
46
+ declare const webpack: (options?: AitDevtoolsOptions | undefined) => WebpackPluginInstance;
47
+ declare const rollup: (options?: AitDevtoolsOptions | undefined) => _rollup.Plugin<any> | _rollup.Plugin<any>[];
48
+ declare const esbuild: (options?: AitDevtoolsOptions | undefined) => unplugin.EsbuildPlugin;
49
+ declare const rspack: (options?: AitDevtoolsOptions | undefined) => RspackPluginInstance;
50
+
51
+ export { type AitDevtoolsOptions, aitDevtoolsPlugin as default, esbuild, rollup, rspack, vite, webpack };
@@ -4,28 +4,29 @@ var FRAMEWORK_ID = "@apps-in-toss/web-framework";
4
4
  var BRIDGE_ID = "@apps-in-toss/web-bridge";
5
5
  var ANALYTICS_ID = "@apps-in-toss/web-analytics";
6
6
  var aitDevtoolsPlugin = createUnplugin((options) => {
7
- const _panel = options?.panel ?? true;
7
+ const isDev = process.env.NODE_ENV !== "production";
8
+ const shouldEnable = isDev || (options?.forceEnable ?? false);
9
+ const shouldMock = shouldEnable && (options?.mock ?? isDev);
10
+ const shouldPanel = shouldEnable && (options?.panel ?? true);
8
11
  return {
9
- name: "ait-devtools",
12
+ name: "ait-co-devtools",
10
13
  enforce: "pre",
11
14
  resolveId(id) {
15
+ if (!shouldMock) return null;
12
16
  if (id === FRAMEWORK_ID || id === BRIDGE_ID || id === ANALYTICS_ID) {
13
- return "ait-devtools/mock";
17
+ return "@ait-co/devtools/mock";
14
18
  }
15
19
  return null;
16
20
  },
17
21
  transformInclude(id) {
18
- if (!_panel) return false;
19
- return /\.(tsx?|jsx?)$/.test(id) && /main|index|entry|app/i.test(id);
22
+ if (!shouldPanel) return false;
23
+ return /\.(tsx?|jsx?)$/.test(id) && /\/(main|index|entry|app)\.[tj]sx?$/i.test(id) && !id.includes("node_modules");
20
24
  },
21
- transform(code, id) {
22
- if (!_panel) return null;
23
- if (code.includes("ait-devtools/panel")) return null;
24
- if (/main|index|entry/i.test(id) && !id.includes("node_modules")) {
25
- return `import 'ait-devtools/panel';
25
+ transform(code) {
26
+ if (!shouldPanel) return null;
27
+ if (code.includes("@ait-co/devtools/panel")) return null;
28
+ return `import '@ait-co/devtools/panel';
26
29
  ${code}`;
27
- }
28
- return null;
29
30
  }
30
31
  };
31
32
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/unplugin/index.ts"],"sourcesContent":["/**\n * ait-devtools unplugin\n *\n * 모든 주요 번들러를 지원하는 단일 플러그인.\n * @apps-in-toss/web-framework → ait-devtools/mock 으로 alias 설정.\n *\n * Usage:\n * import aitDevtools from 'ait-devtools/unplugin';\n *\n * // Vite\n * export default { plugins: [aitDevtools.vite()] };\n *\n * // Webpack / Next.js\n * config.plugins.push(aitDevtools.webpack());\n *\n * // Rspack\n * config.plugins.push(aitDevtools.rspack());\n *\n * // esbuild\n * { plugins: [aitDevtools.esbuild()] }\n *\n * // Rollup\n * { plugins: [aitDevtools.rollup()] }\n */\n\nimport { createUnplugin } from 'unplugin';\n\nexport interface AitDevtoolsOptions {\n /**\n * 패널 자동 주입 여부 (default: true)\n * true이면 진입점에 floating panel import를 자동 추가한다.\n */\n panel?: boolean;\n}\n\nconst FRAMEWORK_ID = '@apps-in-toss/web-framework';\nconst BRIDGE_ID = '@apps-in-toss/web-bridge';\nconst ANALYTICS_ID = '@apps-in-toss/web-analytics';\n\nconst aitDevtoolsPlugin = createUnplugin((options?: AitDevtoolsOptions) => {\n const _panel = options?.panel ?? true;\n\n return {\n name: 'ait-devtools',\n enforce: 'pre' as const,\n\n resolveId(id: string) {\n // @apps-in-toss/web-framework → ait-devtools/mock\n if (id === FRAMEWORK_ID || id === BRIDGE_ID || id === ANALYTICS_ID) {\n return 'ait-devtools/mock';\n }\n return null;\n },\n\n transformInclude(id: string) {\n if (!_panel) return false;\n // 진입점 파일에만 패널 import를 주입\n return /\\.(tsx?|jsx?)$/.test(id) && /main|index|entry|app/i.test(id);\n },\n\n transform(code: string, id: string) {\n if (!_panel) return null;\n // 이미 패널이 import 되어있으면 스킵\n if (code.includes('ait-devtools/panel')) return null;\n // 진입점에서 가장 처음으로 실행되도록 prepend\n if (/main|index|entry/i.test(id) && !id.includes('node_modules')) {\n return `import 'ait-devtools/panel';\\n${code}`;\n }\n return null;\n },\n };\n});\n\nexport const vite = aitDevtoolsPlugin.vite;\nexport const webpack = aitDevtoolsPlugin.webpack;\nexport const rollup = aitDevtoolsPlugin.rollup;\nexport const esbuild = aitDevtoolsPlugin.esbuild;\nexport const rspack = aitDevtoolsPlugin.rspack;\n\nexport default aitDevtoolsPlugin;\n"],"mappings":";AAyBA,SAAS,sBAAsB;AAU/B,IAAM,eAAe;AACrB,IAAM,YAAY;AAClB,IAAM,eAAe;AAErB,IAAM,oBAAoB,eAAe,CAAC,YAAiC;AACzE,QAAM,SAAS,SAAS,SAAS;AAEjC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,UAAU,IAAY;AAEpB,UAAI,OAAO,gBAAgB,OAAO,aAAa,OAAO,cAAc;AAClE,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IAEA,iBAAiB,IAAY;AAC3B,UAAI,CAAC,OAAQ,QAAO;AAEpB,aAAO,iBAAiB,KAAK,EAAE,KAAK,wBAAwB,KAAK,EAAE;AAAA,IACrE;AAAA,IAEA,UAAU,MAAc,IAAY;AAClC,UAAI,CAAC,OAAQ,QAAO;AAEpB,UAAI,KAAK,SAAS,oBAAoB,EAAG,QAAO;AAEhD,UAAI,oBAAoB,KAAK,EAAE,KAAK,CAAC,GAAG,SAAS,cAAc,GAAG;AAChE,eAAO;AAAA,EAAiC,IAAI;AAAA,MAC9C;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF,CAAC;AAEM,IAAM,OAAO,kBAAkB;AAC/B,IAAM,UAAU,kBAAkB;AAClC,IAAM,SAAS,kBAAkB;AACjC,IAAM,UAAU,kBAAkB;AAClC,IAAM,SAAS,kBAAkB;AAExC,IAAO,mBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../src/unplugin/index.ts"],"sourcesContent":["/**\n * @ait-co/devtools unplugin\n *\n * 모든 주요 번들러를 지원하는 단일 플러그인.\n * @apps-in-toss/web-framework → @ait-co/devtools/mock 으로 alias 설정.\n *\n * Usage:\n * import aitDevtools from '@ait-co/devtools/unplugin';\n *\n * // Vite\n * export default { plugins: [aitDevtools.vite()] };\n *\n * // Webpack / Next.js\n * config.plugins.push(aitDevtools.webpack());\n *\n * // Rspack\n * config.plugins.push(aitDevtools.rspack());\n *\n * // esbuild\n * { plugins: [aitDevtools.esbuild()] }\n *\n * // Rollup\n * { plugins: [aitDevtools.rollup()] }\n */\n\nimport { createUnplugin } from 'unplugin';\n\nexport interface AitDevtoolsOptions {\n /**\n * 패널 자동 주입 여부 (default: true)\n * true이면 진입점에 floating panel import를 자동 추가한다.\n */\n panel?: boolean;\n /**\n * production 환경에서도 devtools를 강제로 활성화 (default: false)\n */\n forceEnable?: boolean;\n /**\n * mock alias 활성화 여부. default: true (development), false (production + forceEnable)\n */\n mock?: boolean;\n}\n\nconst FRAMEWORK_ID = '@apps-in-toss/web-framework';\nconst BRIDGE_ID = '@apps-in-toss/web-bridge';\nconst ANALYTICS_ID = '@apps-in-toss/web-analytics';\n\nconst aitDevtoolsPlugin = createUnplugin((options?: AitDevtoolsOptions) => {\n const isDev = process.env.NODE_ENV !== 'production';\n const shouldEnable = isDev || (options?.forceEnable ?? false);\n const shouldMock = shouldEnable && (options?.mock ?? isDev);\n const shouldPanel = shouldEnable && (options?.panel ?? true);\n\n return {\n name: 'ait-co-devtools',\n enforce: 'pre' as const,\n\n resolveId(id: string) {\n if (!shouldMock) return null;\n // @apps-in-toss/web-framework → @ait-co/devtools/mock\n if (id === FRAMEWORK_ID || id === BRIDGE_ID || id === ANALYTICS_ID) {\n return '@ait-co/devtools/mock';\n }\n return null;\n },\n\n transformInclude(id: string) {\n if (!shouldPanel) return false;\n // 진입점 파일에만 패널 import를 주입\n return /\\.(tsx?|jsx?)$/.test(id) && /\\/(main|index|entry|app)\\.[tj]sx?$/i.test(id) && !id.includes('node_modules');\n },\n\n transform(code: string) {\n // transformInclude가 이미 shouldPanel을 확인하지만, 안전망으로 유지\n if (!shouldPanel) return null;\n // 이미 패널이 import 되어있으면 스킵\n if (code.includes('@ait-co/devtools/panel')) return null;\n // transformInclude가 진입점 파일만 통과시키므로 바로 prepend\n return `import '@ait-co/devtools/panel';\\n${code}`;\n },\n };\n});\n\nexport const vite = aitDevtoolsPlugin.vite;\nexport const webpack = aitDevtoolsPlugin.webpack;\nexport const rollup = aitDevtoolsPlugin.rollup;\nexport const esbuild = aitDevtoolsPlugin.esbuild;\nexport const rspack = aitDevtoolsPlugin.rspack;\n\nexport default aitDevtoolsPlugin;\n"],"mappings":";AAyBA,SAAS,sBAAsB;AAkB/B,IAAM,eAAe;AACrB,IAAM,YAAY;AAClB,IAAM,eAAe;AAErB,IAAM,oBAAoB,eAAe,CAAC,YAAiC;AACzE,QAAM,QAAQ,QAAQ,IAAI,aAAa;AACvC,QAAM,eAAe,UAAU,SAAS,eAAe;AACvD,QAAM,aAAa,iBAAiB,SAAS,QAAQ;AACrD,QAAM,cAAc,iBAAiB,SAAS,SAAS;AAEvD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,UAAU,IAAY;AACpB,UAAI,CAAC,WAAY,QAAO;AAExB,UAAI,OAAO,gBAAgB,OAAO,aAAa,OAAO,cAAc;AAClE,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IAEA,iBAAiB,IAAY;AAC3B,UAAI,CAAC,YAAa,QAAO;AAEzB,aAAO,iBAAiB,KAAK,EAAE,KAAK,sCAAsC,KAAK,EAAE,KAAK,CAAC,GAAG,SAAS,cAAc;AAAA,IACnH;AAAA,IAEA,UAAU,MAAc;AAEtB,UAAI,CAAC,YAAa,QAAO;AAEzB,UAAI,KAAK,SAAS,wBAAwB,EAAG,QAAO;AAEpD,aAAO;AAAA,EAAqC,IAAI;AAAA,IAClD;AAAA,EACF;AACF,CAAC;AAEM,IAAM,OAAO,kBAAkB;AAC/B,IAAM,UAAU,kBAAkB;AAClC,IAAM,SAAS,kBAAkB;AACjC,IAAM,UAAU,kBAAkB;AAClC,IAAM,SAAS,kBAAkB;AAExC,IAAO,mBAAQ;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ait-co/devtools",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Development tools for Apps in Toss mini-apps — mock SDK, floating devtools panel, and universal bundler plugin",
5
5
  "type": "module",
6
6
  "main": "./dist/mock/index.js",
@@ -27,6 +27,15 @@
27
27
  "files": [
28
28
  "dist"
29
29
  ],
30
+ "scripts": {
31
+ "build": "rm -rf dist && tsup",
32
+ "dev": "tsup --watch",
33
+ "typecheck": "tsc --noEmit",
34
+ "test": "vitest run",
35
+ "test:e2e": "playwright test",
36
+ "check-sdk-update": "tsx scripts/check-sdk-update.ts",
37
+ "example": "pnpm build && pnpm --dir examples/vite-react dev"
38
+ },
30
39
  "peerDependencies": {
31
40
  "@apps-in-toss/web-framework": "^2.0.0"
32
41
  },
@@ -40,10 +49,12 @@
40
49
  },
41
50
  "devDependencies": {
42
51
  "@apps-in-toss/web-framework": "^2.4.1",
52
+ "@playwright/test": "^1.59.1",
53
+ "jsdom": "^29.0.2",
43
54
  "tsup": "^8.4.0",
55
+ "tsx": "^4.19.4",
44
56
  "typescript": "^5.8.3",
45
- "vitest": "^3.1.1",
46
- "tsx": "^4.19.4"
57
+ "vitest": "^3.1.1"
47
58
  },
48
59
  "keywords": [
49
60
  "apps-in-toss",
@@ -53,6 +64,7 @@
53
64
  "mock",
54
65
  "sdk"
55
66
  ],
67
+ "packageManager": "pnpm@10.8.1",
56
68
  "license": "BSD-3-Clause",
57
69
  "publishConfig": {
58
70
  "access": "public"
@@ -61,11 +73,8 @@
61
73
  "type": "git",
62
74
  "url": "https://github.com/apps-in-toss-community/devtools"
63
75
  },
64
- "scripts": {
65
- "build": "tsup",
66
- "dev": "tsup --watch",
67
- "typecheck": "tsc --noEmit",
68
- "test": "vitest run",
69
- "check-sdk-update": "tsx scripts/check-sdk-update.ts"
76
+ "homepage": "https://www.npmjs.com/package/@ait-co/devtools",
77
+ "bugs": {
78
+ "url": "https://github.com/apps-in-toss-community/devtools/issues"
70
79
  }
71
- }
80
+ }