@ait-co/devtools 0.1.1 → 0.1.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,"file":"index.d.ts","names":[],"sources":["../../src/mock/ads/index.ts","../../src/mock/analytics/index.ts","../../src/mock/auth/index.ts","../../src/mock/device/_helpers.ts","../../src/mock/types.ts","../../src/mock/device/camera.ts","../../src/mock/device/clipboard.ts","../../src/mock/device/contacts.ts","../../src/mock/device/haptic.ts","../../src/mock/device/location.ts","../../src/mock/device/storage.ts","../../src/mock/game/index.ts","../../src/mock/iap/index.ts","../../src/mock/navigation/index.ts","../../src/mock/partner/index.ts","../../src/mock/permissions.ts","../../src/mock/state.ts"],"mappings":";;AAgBA;;cAAa,WAAA;;IAGP,OAAA,GAAU,IAAA;MAAQ,IAAA;MAAc,IAAA;IAAA;IAChC,OAAA,GAAU,KAAA,EAAO,KAAA;IACjB,OAAA;MAAY,SAAA;IAAA;EAAA;;;;IAYZ,OAAA,GAAU,IAAA;MAAQ,IAAA;MAAc,IAAA;IAAA;IAChC,OAAA,GAAU,KAAA,EAAO,KAAA;IACjB,OAAA;MAAY,SAAA;IAAA;EAAA;;;;IAqBK,SAAA;EAAA,MAAuB,OAAA;;;;cAMjC,OAAA;;;;gCAKU,MAAA,WAAmB,WAAA,EAAW,QAAA;;;sCAY9B,MAAA,WAAmB,WAAA,EAAW,QAAA;;;;;;;;;;;;cAkBxC,gBAAA,IAAgB,IAAA;EAEzB,OAAA,GAAU,IAAA;IAAQ,IAAA;IAAc,IAAA;EAAA;EAChC,OAAA,GAAU,KAAA,EAAO,KAAA;EACjB,OAAA;IAAY,SAAA;EAAA;AAAA;;;cAUH,gBAAA,IAAgB,IAAA;EAEzB,OAAA,GAAU,IAAA;IAAQ,IAAA;IAAc,IAAA;EAAA;EAChC,OAAA,GAAU,KAAA,EAAO,KAAA;EACjB,OAAA;IAAY,SAAA;EAAA;AAAA;;;;;;AAnGhB;;KCVK,WAAA;AAAA,KACA,YAAA;EAAiB,QAAA;AAAA,IAAsB,MAAA,SAAe,WAAA;AAAA,cAI9C,SAAA;oBACO,YAAA,KAAe,OAAA;wBAIX,YAAA,KAAe,OAAA;mBAIpB,YAAA,KAAe,OAAA;AAAA;AAAA,iBAMZ,QAAA,CAAS,MAAA;EAC7B,QAAA;EACA,QAAA;EACA,MAAA,EAAQ,MAAA,SAAe,WAAA;AAAA,IACrB,OAAA;;;;ADdJ;;iBEVsB,QAAA,CAAA,GAAY,OAAA;EAChC,iBAAA;EACA,QAAA;AAAA;AAAA,iBAQoB,+BAAA,CAAA,GAAmC,OAAA;AAAA,iBAInC,iBAAA,CAAA,GAAqB,OAAA;EACvC,IAAA;EAAc,IAAA;AAAA;AAAA,UAMD,4BAAA;EACf,IAAA;AAAA;AAAA,iBAGoB,sBAAA,CAAuB,OAAA,EAAS,4BAAA,GAA+B,OAAA;;;;AFfrF;;iBGyBgB,2BAAA,CAAA;;;KCzCJ,SAAA;AAAA,KAEA,UAAA;AAAA,KACA,sBAAA;AAAA,KACA,aAAA;AAAA,KACA,gBAAA;AAAA,KACA,cAAA;AAAA,KAOA,kBAAA;AAAA,KAYA,aAAA;AAAA,UAEK,WAAA;EACf,MAAA,EAAQ,aAAA;EACR,MAAA,EAAQ,aAAA;EACR,QAAA,EAAU,aAAA;EACV,OAAA;EACA,SAAA;AAAA;AAAA,UAGe,QAAA;EACf,MAAA;EACA,aAAA;AAAA;AAAA,UAGe,cAAA;EACf,QAAA;EACA,SAAA;EACA,QAAA;EACA,QAAA;EACA,gBAAA;EACA,OAAA;AAAA;AAAA,UAGe,YAAA;EACf,MAAA,EAAQ,cAAA;EACR,SAAA;EACA,cAAA;AAAA;AAAA,UAGe,WAAA;EACf,IAAA;EACA,WAAA;AAAA;AAAA,UAGe,cAAA;EACf,GAAA;EACA,IAAA;EACA,WAAA;EACA,aAAA;EACA,OAAA;EACA,WAAA;EACA,YAAA;AAAA;AAAA,KAGU,aAAA;AAAA,UASK,iBAAA;EACf,SAAA;EACA,IAAA;EACA,MAAA,EAAQ,MAAA;AAAA;AAAA,UAGO,gBAAA;EACf,GAAA;EACA,MAAA;EACA,IAAA;EACA,KAAA;AAAA;;;;AJzEF;;;cK+Ca,UAAA,IAAU,QAAA;EATrB,MAAA;EACA,QAAA;AAAA,MACE,OAAA;EAAU,EAAA;EAAY,OAAA;AAAA;+BAAf,gBAAA;;;cA8EE,gBAAA,IAAgB,OAAA;EAX3B,QAAA;EACA,QAAA;EACA,MAAA;AAAA,MACE,OAAA,CAAQ,KAAA;EAAQ,EAAA;EAAY,OAAA;AAAA;+BAArB,gBAAA;;;;;;AL9GX;;;cMGa,gBAAA,SAXuB,OAAA;+BAAO,gBAAA;;;cAuB9B,gBAAA,IAAgB,IAAA,aAVmB,OAAA;+BAAO,gBAAA;;;;;;ANLvD;;cOYa,aAAA,IAAa,OAAA;EApBxB,IAAA;EACA,MAAA;EACA,KAAA;IAAU,QAAA;EAAA;AAAA,MACX,OAAA;UAiBsE,WAAA;;;;+BAjBtE,gBAAA;;;;;;APKD;;iBQVsB,sBAAA,CAAuB,OAAA;EAAW,IAAA;AAAA,IAAiB,OAAA;AAAA,iBAKnD,cAAA,CAAe,MAAA;EACnC,IAAA;EACA,QAAA;EACA,QAAA;AAAA,IACE,OAAA;;;aCLC,QAAA;EACH,MAAA;EACA,GAAA;EACA,QAAA;EACA,IAAA;EACA,OAAA;EACA,iBAAA;AAAA;AAAA,cA4DW,kBAAA,IAAkB,QAAA;EAPiB,QAAA,EAAU,QAAA;AAAA,MAAa,OAAA,CAAQ,YAAA;+BAAD,gBAAA;;;UAWpE,8BAAA;EACR,OAAA,GAAU,QAAA,EAAU,YAAA;EACpB,OAAA,GAAU,KAAA;EACV,OAAA;IAAW,QAAA,EAAU,QAAA;IAAU,YAAA;IAAsB,gBAAA;EAAA;AAAA;AAAA,cA2D1C,mBAAA,IAAmB,WAAA,EANW,8BAAA;+BAA8B,gBAAA;;;;;;ATxHzE;;;cUTa,OAAA;4BACmB,OAAA;yBAGH,KAAA,aAAkB,OAAA;+BAGZ,OAAA;oBAGX,OAAA;AAAA;;;;AVDxB;;iBWVsB,oBAAA,CAAqB,MAAA;EACzC,MAAA;IAAU,aAAA;IAAuB,MAAA;EAAA;AAAA,IAC/B,OAAA;EAAU,GAAA;AAAA;EAAkB,SAAA;EAAmB,OAAA;AAAA;AAAA,iBAK7B,2BAAA,CAA4B,MAAA;EAChD,MAAA;IAAU,aAAA;IAAuB,MAAA;EAAA;AAAA,IAC/B,OAAA;EAAU,GAAA;AAAA;EAAkB,SAAA;EAAmB,OAAA;AAAA;AAAA,iBAK7B,gCAAA,CAAiC,MAAA;EACrD,KAAA;AAAA,IACE,OAAA;EACE,UAAA;AAAA;AAAA,iBAYgB,wBAAA,CAAA,GAA4B,OAAA;EAC5C,UAAA;EAAuB,QAAA;EAAkB,eAAA;AAAA;EACzC,UAAA;AAAA;AAAA,iBAYgB,yBAAA,CAAA,GAA6B,OAAA;AAAA,UAIzC,kBAAA;EACR,IAAA;EACA,IAAA,EAAM,MAAA;AAAA;AAAA,iBAGQ,aAAA,CAAc,MAAA;EAC5B,OAAA;IAAW,QAAA;EAAA;EACX,OAAA,GAAU,KAAA,EAAO,kBAAA;EACjB,OAAA,GAAU,KAAA;AAAA;;;;AX7CZ;;UYDU,oCAAA;EACR,OAAA;IACE,GAAA;IACA,SAAA;IACA,mBAAA,GAAsB,MAAA;MAAU,OAAA;IAAA,gBAAgC,OAAA;EAAA;EAElE,OAAA,GAAU,KAAA;IAAS,IAAA;IAAiB,IAAA,EAAM,cAAA;EAAA,aAA4B,OAAA;EACtE,OAAA,GAAU,KAAA,qBAA0B,OAAA;AAAA;AAAA,UAG5B,sCAAA;EACR,OAAA;IACE,GAAA;IACA,OAAA;IACA,mBAAA,GAAsB,MAAA;MACpB,OAAA;MACA,cAAA;IAAA,gBACc,OAAA;EAAA;EAElB,OAAA,GAAU,KAAA;IAAS,IAAA;IAAiB,IAAA,EAAM,cAAA;EAAA,aAA4B,OAAA;EACtE,OAAA,GAAU,KAAA,qBAA0B,OAAA;AAAA;AAAA,UAG5B,cAAA;EACR,OAAA;EACA,WAAA;EACA,aAAA;EACA,MAAA;EACA,QAAA;EACA,QAAA;EACA,cAAA;AAAA;AAAA,cAiEW,GAAA;qCAEwB,oCAAA;0CAQK,sCAAA;wBAUZ,OAAA;IAAU,QAAA;EAAA;sBASZ,OAAA;IACxB,MAAA,EAAQ,KAAA;MAAQ,OAAA;MAAiB,GAAA;MAAa,oBAAA;IAAA;EAAA;kCAKV,OAAA;IACpC,OAAA;IACA,OAAA;IACA,MAAA,EAAQ,KAAA;MAAQ,OAAA;MAAiB,GAAA;MAAa,MAAA;MAAkC,IAAA;IAAA;EAAA;;IAS/C,MAAA;MAAU,OAAA;IAAA;EAAA,IAAsB,OAAA;;IAsBhC,MAAA;MAAU,OAAA;IAAA;EAAA,IAAmB,OAAA;;;;;;;;;;;iBAgB5C,eAAA,CAAgB,OAAA;EACpC,MAAA;IAAU,QAAA;EAAA;AAAA,IACR,OAAA;EAAU,OAAA;EAAkB,MAAA;AAAA;;;iBC7LV,SAAA,CAAA,GAAa,OAAA;AAAA,iBAKb,OAAA,CAAQ,GAAA,WAAc,OAAA;AAAA,iBAKtB,KAAA,CAAM,OAAA;EAAW,OAAA;AAAA,IAAoB,OAAA;AAAA,iBAQrC,gBAAA,CAAiB,IAAA,UAAc,WAAA,YAAuB,OAAA;AAAA,iBAItD,yBAAA,CAA0B,QAAA;EAAY,SAAA;AAAA,IAAuB,OAAA;AAAA,iBAI7D,oBAAA,CAAqB,QAAA;EACzC,IAAA;AAAA,IACE,OAAA;AAAA,iBAIkB,kBAAA,CAAmB,OAAA;EACvC,OAAA;AAAA,IACE,OAAA;EAAU,OAAA;AAAA;AAAA,iBAKQ,eAAA,CAAgB,OAAA;EACpC,OAAA;AAAA,IACE,OAAA;EAAU,OAAA;AAAA;AAAA,iBAKQ,aAAA,CAAA,GAAiB,OAAA;AAAA,iBAOvB,aAAA,CAAA;AAAA,iBAIA,yBAAA,CAAA;AAAA,iBAIA,iBAAA,CAAA;AAAA,iBAIA,qBAAA,CAAsB,WAAA;EAAe,OAAA;EAAiB,GAAA;AAAA;AAAA,iBAetD,YAAA,CAAA;AAAA,iBAIA,SAAA,CAAA;AAAA,iBAIA,WAAA,CAAA;AAAA,iBAIA,UAAA,CAAA;AAAA,iBAIM,gBAAA,CAAA,GAAoB,OAAA,CAAQ,aAAA;AAAA,iBAM5B,aAAA,CAAA,GAAiB,OAAA;AAAA,UAO7B,eAAA;EACR,SAAA;IAAa,OAAA;IAAqB,OAAA,IAAW,KAAA,EAAO,KAAA;IAAgB,OAAA;EAAA;EACpE,SAAA;IAAa,OAAA;IAAqB,OAAA,IAAW,KAAA,EAAO,KAAA;IAAgB,OAAA;EAAA;AAAA;AAAA,cAGzD,YAAA;mCACsB,eAAA,EAAe,KAAA,EACvC,CAAA;IAAC,OAAA;IAAA;EAAA;IAKN,OAAA,EAAS,eAAA,CAAgB,CAAA;IACzB,OAAA,GAAU,eAAA,CAAgB,CAAA;IAC1B,OAAA,GAAU,eAAA,CAAgB,CAAA;EAAA;AAAA;AAAA,cAenB,eAAA;qCACsB,MAAA,EACvB,CAAA,EAAC,SAAA;IAEP,OAAA,MAAa,IAAA;IACb,OAAA,IAAW,KAAA,EAAO,KAAA;IAClB,OAAA;EAAA;AAAA;AAAA,UAOI,WAAA;EACR,wBAAA;IACE,OAAA,GAAU,IAAA;MAAQ,EAAA;IAAA;IAClB,OAAA,IAAW,KAAA,EAAO,KAAA;IAClB,OAAA;EAAA;AAAA;AAAA,cAIS,QAAA;mCACsB,WAAA,EAAW,KAAA,EACnC,CAAA;IAAC;EAAA;IAIN,OAAA,EAAS,WAAA,CAAY,CAAA;IACrB,OAAA,GAAU,WAAA,CAAY,CAAA;IACtB,OAAA,GAAU,WAAA,CAAY,CAAA;EAAA;AAAA;AAAA,iBAYZ,0CAAA,CAA2C,WAAA;EACzD,OAAA;IAAW,UAAA;EAAA;EACX,OAAA,GAAU,SAAA;EACV,OAAA,GAAU,KAAA;AAAA;AAAA,cASC,GAAA;EAEZ,eAAA;AAAA;AAAA,iBAEe,oBAAA,CAAA;;;;;;KAWX,mBAAA;EAAwB,GAAA;EAAa,MAAA;EAAgB,IAAA;EAAc,KAAA;AAAA;AAAA,KACnE,8BAAA;EAAmC,OAAA,GAAU,IAAA,EAAM,mBAAA;AAAA;AAAA,cAE3C,cAAA;aACF,mBAAA;;;KAGgB,8BAAA;AAAA;;iBAMX,iBAAA,CAAA;;;;AbnNhB;;UcZU,yBAAA;EACR,EAAA;EACA,KAAA;EACA,IAAA;IAAQ,IAAA;EAAA;AAAA;AAAA,cAGG,OAAA;8BACuB,yBAAA,GAA4B,OAAA;2BAG/B,OAAA;AAAA;;;iBCNX,aAAA,CAAc,IAAA,EAAM,cAAA,GAAiB,OAAA,CAAQ,gBAAA;AAAA,iBAI7C,oBAAA,CAAqB,IAAA,EAAM,cAAA,GAAiB,OAAA;AAAA,iBAS5C,iBAAA,CAAkB,UAAA;EACtC,IAAA,EAAM,cAAA;EACN,MAAA;AAAA,IACE,OAAA;;;KCgBC,QAAA;AAAA,UAEY,gBAAA;EAEf,QAAA,EAAU,UAAA;EACV,WAAA,EAAa,sBAAA;EACb,UAAA;EACA,MAAA;EACA,SAAA;EACA,OAAA;EACA,YAAA;EACA,QAAA;EAGA,KAAA;IACE,WAAA;IACA,IAAA;IACA,YAAA;EAAA;EAIF,aAAA,EAAe,aAAA;EAGf,WAAA,EAAa,MAAA,CAAO,cAAA,EAAgB,gBAAA;EAGpC,QAAA,EAAU,YAAA;EAGV,cAAA,EAAgB,gBAAA;EAGhB,QAAA,EAAU,WAAA;EAGV,GAAA;IACE,QAAA,EAAU,cAAA;IACV,UAAA,EAAY,aAAA;IACZ,aAAA,EAAe,KAAA;MAAQ,OAAA;MAAiB,GAAA;MAAa,oBAAA;IAAA;IACrD,eAAA,EAAiB,KAAA;MACf,OAAA;MACA,GAAA;MACA,MAAA;MACA,IAAA;IAAA;EAAA;EAKJ,OAAA;IACE,UAAA;IACA,UAAA;EAAA;EAIF,IAAA;IACE,UAAA;IACA,qBAAA;IACA,WAAA;EAAA;EAIF,GAAA;IACE,QAAA;IACA,SAAA;EAAA;EAUF,IAAA;IACE,OAAA;MAAW,QAAA;MAAkB,eAAA;IAAA;IAC7B,iBAAA,EAAmB,KAAA;MAAQ,KAAA;MAAe,SAAA;IAAA;EAAA;EAI5C,YAAA,EAAc,iBAAA;EAGd,WAAA,EAAa,WAAA;EAGb,QAAA,EAAU,QAAA;EAGV,aAAA;AAAA;AAAA,cAiHW,eAAA;EAAA,QACH,MAAA;EAAA,QACA,UAAA;;MAWJ,KAAA,CAAA,GAAS,gBAAA;EAIb,MAAA,CAAO,OAAA,EAAS,OAAA,CAAQ,gBAAA;EhB/JtB;EgBqKF,KAAA,iBAAsB,gBAAA,CAAA,CAAkB,GAAA,EAAK,CAAA,EAAG,OAAA,EAAS,OAAA,CAAQ,gBAAA,CAAiB,CAAA;EAalF,SAAA,CAAU,QAAA,EAAU,QAAA;EhBjLlB;EgBuLF,YAAA,CAAa,KAAA,EAAO,IAAA,CAAK,iBAAA;EhB3LE;EgBoM3B,OAAA,CAAQ,KAAA;EAIR,KAAA,CAAA;EAAA,QAMQ,OAAA;AAAA;AAAA,cAOG,QAAA,EAAQ,eAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/mock/ads/index.ts","../../src/mock/analytics/index.ts","../../src/mock/auth/index.ts","../../src/mock/device/_helpers.ts","../../src/mock/types.ts","../../src/mock/device/camera.ts","../../src/mock/device/clipboard.ts","../../src/mock/device/contacts.ts","../../src/mock/device/haptic.ts","../../src/mock/device/location.ts","../../src/mock/device/storage.ts","../../src/mock/game/index.ts","../../src/mock/iap/index.ts","../../src/mock/navigation/index.ts","../../src/mock/partner/index.ts","../../src/mock/permissions.ts","../../src/mock/state.ts"],"mappings":"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"}
@@ -105,7 +105,7 @@ const DEFAULT_STATE = {
105
105
  photos: "mock",
106
106
  location: "mock",
107
107
  network: "mock",
108
- clipboard: "web"
108
+ clipboard: "mock"
109
109
  },
110
110
  mockData: {
111
111
  images: [],
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/mock/proxy.ts","../../src/mock/state.ts","../../src/mock/ads/index.ts","../../src/mock/analytics/index.ts","../../src/mock/auth/index.ts","../../src/mock/device/_helpers.ts","../../src/mock/permissions.ts","../../src/mock/device/camera.ts","../../src/mock/device/clipboard.ts","../../src/mock/device/contacts.ts","../../src/mock/device/haptic.ts","../../src/mock/device/location.ts","../../src/mock/device/network.ts","../../src/mock/device/storage.ts","../../src/mock/game/index.ts","../../src/mock/iap/index.ts","../../src/mock/navigation/index.ts","../../src/mock/partner/index.ts"],"sourcesContent":["/**\n * 미구현 API용 Proxy 트립와이어.\n *\n * 미구현 프로퍼티에 접근하면 throw한다. 이는 \"devtools에서는 멀쩡히 돌지만\n * 실 SDK에선 실제로 동작하는\" 시나리오를 차단하기 위한 의도적 선택이다.\n * mock이 미구현인 API는 실 SDK에서는 존재할 수 있고, 사용자가 이를 인지하지\n * 못한 채 개발을 이어가면 배포 시점에 놀라게 된다. 에러 메시지에 이슈 URL을\n * 포함해 사용자가 mock 누락을 제보할 수 있게 한다.\n */\n\nconst ISSUES_URL = 'https://github.com/apps-in-toss-community/devtools/issues';\n\nexport function createMockProxy<T extends Record<string, unknown>>(\n moduleName: string,\n implementations: T,\n): T {\n return new Proxy(implementations, {\n get(target, prop) {\n // 심볼 접근(Symbol.toPrimitive, Symbol.iterator 등)은 프레임워크/런타임이\n // 내부적으로 호출하므로 throw하면 console.log, 구조분해 등이 깨진다.\n if (typeof prop === 'symbol') return undefined;\n if (prop in target) return target[prop];\n\n throw new Error(\n `[@ait-co/devtools] ${moduleName}.${prop} is not mocked. ` +\n `This API may exist in @apps-in-toss/web-framework, ` +\n `but devtools' mock does not cover it yet. ` +\n `Please file an issue: ${ISSUES_URL}`,\n );\n },\n }) as T;\n}\n","/**\n * @ait-co/devtools 중앙 상태 관리\n * DevTools Panel과 mock 구현체가 이 상태를 공유한다.\n */\n\nimport type {\n AnalyticsLogEntry,\n DeviceModes,\n IapNextResult,\n MockContact,\n MockData,\n MockIapProduct,\n MockLocation,\n NetworkStatus,\n OperationalEnvironment,\n PermissionName,\n PermissionStatus,\n PlatformOS,\n SafeAreaInsets,\n} from './types.js';\n\nexport type {\n AnalyticsLogEntry,\n DeviceApiMode,\n DeviceModes,\n HapticFeedbackType,\n IapNextResult,\n LocationCoords,\n MockContact,\n MockData,\n MockIapProduct,\n MockLocation,\n NetworkStatus,\n OperationalEnvironment,\n PermissionName,\n PermissionStatus,\n PlatformOS,\n SafeAreaInsets,\n} from './types.js';\n\ntype Listener = () => void;\n\nexport interface AitDevtoolsState {\n // 환경\n platform: PlatformOS;\n environment: OperationalEnvironment;\n appVersion: string;\n locale: string;\n schemeUri: string;\n groupId: string;\n deploymentId: string;\n deviceId: string;\n\n // 브랜드\n brand: {\n displayName: string;\n icon: string;\n primaryColor: string;\n };\n\n // 네트워크\n networkStatus: NetworkStatus;\n\n // 권한\n permissions: Record<PermissionName, PermissionStatus>;\n\n // 위치\n location: MockLocation;\n\n // Safe Area\n safeAreaInsets: SafeAreaInsets;\n\n // 연락처\n contacts: MockContact[];\n\n // IAP\n iap: {\n products: MockIapProduct[];\n nextResult: IapNextResult;\n pendingOrders: Array<{ orderId: string; sku: string; paymentCompletedDate: string }>;\n completedOrders: Array<{\n orderId: string;\n sku: string;\n status: 'COMPLETED' | 'REFUNDED';\n date: string;\n }>;\n };\n\n // 결제 (TossPay)\n payment: {\n nextResult: 'success' | 'fail';\n failReason: string;\n };\n\n // 로그인\n auth: {\n isLoggedIn: boolean;\n isTossLoginIntegrated: boolean;\n userKeyHash: string;\n };\n\n // 광고\n ads: {\n isLoaded: boolean;\n nextEvent:\n | 'loaded'\n | 'clicked'\n | 'dismissed'\n | 'failedToShow'\n | 'impression'\n | 'userEarnedReward';\n };\n\n // 게임\n game: {\n profile: { nickname: string; profileImageUri: string } | null;\n leaderboardScores: Array<{ score: string; timestamp: number }>;\n };\n\n // 분석 로그\n analyticsLog: AnalyticsLogEntry[];\n\n // 디바이스 API 모드\n deviceModes: DeviceModes;\n\n // mock 모드용 더미 데이터\n mockData: MockData;\n\n // mock 활성화 상태\n panelEditable: boolean;\n}\n\nconst DEFAULT_STATE: AitDevtoolsState = {\n platform: 'ios',\n environment: 'sandbox',\n appVersion: '5.240.0',\n locale: 'ko-KR',\n schemeUri: '/',\n groupId: 'mock-group-id',\n deploymentId: 'mock-deployment-id',\n deviceId: '',\n\n brand: {\n displayName: 'Mock App',\n icon: '',\n primaryColor: '#3182F6',\n },\n\n networkStatus: 'WIFI',\n\n permissions: {\n clipboard: 'allowed',\n contacts: 'allowed',\n photos: 'allowed',\n geolocation: 'allowed',\n camera: 'allowed',\n microphone: 'notDetermined',\n },\n\n location: {\n coords: {\n latitude: 37.5665,\n longitude: 126.978,\n altitude: 0,\n accuracy: 10,\n altitudeAccuracy: 0,\n heading: 0,\n },\n timestamp: Date.now(),\n accessLocation: 'FINE',\n },\n\n safeAreaInsets: { top: 47, bottom: 34, left: 0, right: 0 },\n\n contacts: [\n { name: '홍길동', phoneNumber: '010-1234-5678' },\n { name: '김토스', phoneNumber: '010-9876-5432' },\n ],\n\n iap: {\n products: [\n {\n sku: 'mock-gem-100',\n type: 'CONSUMABLE',\n displayName: '보석 100개',\n displayAmount: '1,000원',\n iconUrl: '',\n description: '게임에서 사용할 수 있는 보석 100개',\n },\n ],\n nextResult: 'success',\n pendingOrders: [],\n completedOrders: [],\n },\n\n payment: {\n nextResult: 'success',\n failReason: '',\n },\n\n auth: {\n isLoggedIn: true,\n isTossLoginIntegrated: true,\n userKeyHash: 'mock-user-hash-abc123',\n },\n\n ads: {\n isLoaded: false,\n nextEvent: 'loaded',\n },\n\n game: {\n profile: { nickname: 'MockPlayer', profileImageUri: '' },\n leaderboardScores: [],\n },\n\n analyticsLog: [],\n\n deviceModes: {\n camera: 'mock',\n photos: 'mock',\n location: 'mock',\n network: 'mock',\n clipboard: 'web',\n },\n\n mockData: {\n images: [],\n clipboardText: '',\n },\n\n panelEditable: true,\n};\n\nfunction generateDeviceId(): string {\n const stored = localStorage.getItem('__ait_device_id');\n if (stored) return stored;\n const id = crypto.randomUUID();\n localStorage.setItem('__ait_device_id', id);\n return id;\n}\n\nexport class AitStateManager {\n private _state: AitDevtoolsState;\n private _listeners = new Set<Listener>();\n\n constructor() {\n this._state = structuredClone(DEFAULT_STATE);\n try {\n this._state.deviceId = generateDeviceId();\n } catch {\n this._state.deviceId = `mock-device-${Math.random().toString(36).slice(2)}`;\n }\n }\n\n get state(): AitDevtoolsState {\n return this._state;\n }\n\n update(partial: Partial<AitDevtoolsState>) {\n this._state = { ...this._state, ...partial };\n this._notify();\n }\n\n /** 중첩 객체 업데이트용 */\n patch<K extends keyof AitDevtoolsState>(key: K, partial: Partial<AitDevtoolsState[K]>) {\n const current = this._state[key];\n if (typeof current === 'object' && current !== null && !Array.isArray(current)) {\n this._state = {\n ...this._state,\n [key]: { ...(current as Record<string, unknown>), ...(partial as Record<string, unknown>) },\n };\n } else {\n this._state = { ...this._state, [key]: partial as AitDevtoolsState[K] };\n }\n this._notify();\n }\n\n subscribe(listener: Listener): () => void {\n this._listeners.add(listener);\n return () => this._listeners.delete(listener);\n }\n\n /** 분석 로그 추가 */\n logAnalytics(entry: Omit<AnalyticsLogEntry, 'timestamp'>) {\n this._state = {\n ...this._state,\n analyticsLog: [...this._state.analyticsLog, { ...entry, timestamp: Date.now() }],\n };\n this._notify();\n }\n\n /** 이벤트 트리거 (backEvent, homeEvent 등) */\n trigger(event: string) {\n window.dispatchEvent(new CustomEvent(`__ait:${event}`));\n }\n\n reset() {\n const deviceId = this._state.deviceId;\n this._state = { ...structuredClone(DEFAULT_STATE), deviceId };\n this._notify();\n }\n\n private _notify() {\n for (const listener of this._listeners) {\n listener();\n }\n }\n}\n\nexport const aitState = new AitStateManager();\n\n// 브라우저 콘솔에서 접근 가능하도록\nif (typeof window !== 'undefined') {\n window.__ait = aitState;\n}\n","/**\n * 광고 mock (GoogleAdMob, TossAds, FullScreenAd)\n */\n\nimport { createMockProxy } from '../proxy.js';\nimport { aitState } from '../state.js';\n\nfunction withIsSupported<T extends (...args: never[]) => unknown>(\n fn: T,\n): T & { isSupported: () => boolean } {\n (fn as T & { isSupported: () => boolean }).isSupported = () => true;\n return fn as T & { isSupported: () => boolean };\n}\n\n// --- Google AdMob ---\n\nexport const GoogleAdMob = createMockProxy('GoogleAdMob', {\n loadAppsInTossAdMob: withIsSupported(\n (args: {\n onEvent: (data: { type: string; data?: unknown }) => void;\n onError: (error: Error) => void;\n options?: { adGroupId?: string };\n }): (() => void) => {\n setTimeout(() => {\n aitState.patch('ads', { isLoaded: true });\n args.onEvent({ type: 'loaded', data: { adGroupId: args.options?.adGroupId } });\n }, 200);\n return () => {};\n },\n ),\n\n showAppsInTossAdMob: withIsSupported(\n (args: {\n onEvent: (data: { type: string; data?: unknown }) => void;\n onError: (error: Error) => void;\n options?: { adGroupId?: string };\n }): (() => void) => {\n if (!aitState.state.ads.isLoaded) {\n args.onError(new Error('Ad not loaded'));\n return () => {};\n }\n setTimeout(() => args.onEvent({ type: 'requested' }), 50);\n setTimeout(() => args.onEvent({ type: 'show' }), 100);\n setTimeout(() => args.onEvent({ type: 'impression' }), 150);\n setTimeout(() => {\n args.onEvent({ type: 'userEarnedReward', data: { unitType: 'coins', unitAmount: 10 } });\n }, 1000);\n setTimeout(() => {\n args.onEvent({ type: 'dismissed' });\n aitState.patch('ads', { isLoaded: false });\n }, 1500);\n return () => {};\n },\n ),\n\n isAppsInTossAdMobLoaded: withIsSupported(\n async (_options: { adGroupId?: string }): Promise<boolean> => aitState.state.ads.isLoaded,\n ),\n});\n\n// --- TossAds ---\n\nexport const TossAds = createMockProxy('TossAds', {\n initialize: withIsSupported((_options: unknown) => {\n console.log('[@ait-co/devtools] TossAds.initialize (mock)');\n }),\n attach: withIsSupported(\n (_adGroupId: string, target: string | HTMLElement, _options?: unknown) => {\n const el = typeof target === 'string' ? document.querySelector(target) : target;\n if (el) {\n const placeholder = document.createElement('div');\n placeholder.style.cssText =\n 'background:#f0f0f0;border:1px dashed #999;padding:16px;text-align:center;color:#666;font-size:14px;';\n placeholder.textContent = '[@ait-co/devtools] TossAds Placeholder';\n el.appendChild(placeholder);\n }\n },\n ),\n attachBanner: withIsSupported(\n (_adGroupId: string, target: string | HTMLElement, _options?: unknown) => {\n const el = typeof target === 'string' ? document.querySelector(target) : target;\n if (el) {\n const placeholder = document.createElement('div');\n placeholder.style.cssText =\n 'background:#f0f0f0;border:1px dashed #999;padding:12px;text-align:center;color:#666;font-size:12px;';\n placeholder.textContent = '[@ait-co/devtools] Banner Ad Placeholder';\n el.appendChild(placeholder);\n }\n return { destroy: () => {} };\n },\n ),\n destroy: withIsSupported((_slotId: string) => {}),\n destroyAll: withIsSupported(() => {}),\n});\n\n// --- FullScreen Ad ---\n\nexport const loadFullScreenAd = withIsSupported(\n (args: {\n onEvent: (data: { type: string; data?: unknown }) => void;\n onError: (error: Error) => void;\n options?: { adGroupId?: string };\n }): (() => void) => {\n setTimeout(() => {\n aitState.patch('ads', { isLoaded: true });\n args.onEvent({ type: 'loaded', data: { adGroupId: args.options?.adGroupId } });\n }, 200);\n return () => {};\n },\n);\n\nexport const showFullScreenAd = withIsSupported(\n (args: {\n onEvent: (data: { type: string; data?: unknown }) => void;\n onError: (error: Error) => void;\n options?: { adGroupId?: string };\n }): (() => void) => {\n if (!aitState.state.ads.isLoaded) {\n args.onError(new Error('Ad not loaded'));\n return () => {};\n }\n setTimeout(() => args.onEvent({ type: 'show' }), 100);\n setTimeout(() => args.onEvent({ type: 'dismissed' }), 1500);\n return () => {};\n },\n);\n","/**\n * Analytics mock\n */\n\nimport { aitState } from '../state.js';\n\ntype Primitive = string | number | boolean | null | undefined | symbol;\ntype LoggerParams = { log_name?: string } & Record<string, Primitive>;\n\n// Analytics methods return `Promise<void> | undefined` to match the original SDK signature,\n// so they cannot use `async` (which always returns a Promise).\nexport const Analytics = {\n screen: (params?: LoggerParams): Promise<void> | undefined => {\n aitState.logAnalytics({ type: 'screen', params: params ?? {} });\n return Promise.resolve();\n },\n impression: (params?: LoggerParams): Promise<void> | undefined => {\n aitState.logAnalytics({ type: 'impression', params: params ?? {} });\n return Promise.resolve();\n },\n click: (params?: LoggerParams): Promise<void> | undefined => {\n aitState.logAnalytics({ type: 'click', params: params ?? {} });\n return Promise.resolve();\n },\n};\n\nexport async function eventLog(params: {\n log_name: string;\n log_type: 'debug' | 'info' | 'warn' | 'error' | 'event' | 'screen' | 'impression' | 'click';\n params: Record<string, Primitive>;\n}): Promise<void> {\n aitState.logAnalytics({\n type: params.log_type,\n params: { log_name: params.log_name, ...params.params },\n });\n}\n","/**\n * 인증/로그인 mock\n */\n\nimport { aitState } from '../state.js';\n\nexport async function appLogin(): Promise<{\n authorizationCode: string;\n referrer: 'DEFAULT' | 'SANDBOX';\n}> {\n return {\n authorizationCode: `mock-auth-${crypto.randomUUID()}`,\n referrer: aitState.state.environment === 'toss' ? 'DEFAULT' : 'SANDBOX',\n };\n}\n\nexport async function getIsTossLoginIntegratedService(): Promise<boolean | undefined> {\n return aitState.state.auth.isTossLoginIntegrated;\n}\n\nexport async function getUserKeyForGame(): Promise<\n { hash: string; type: 'HASH' } | 'INVALID_CATEGORY' | 'ERROR' | undefined\n> {\n if (!aitState.state.auth.userKeyHash) return undefined;\n return { hash: aitState.state.auth.userKeyHash, type: 'HASH' };\n}\n\nexport interface AppsInTossSignTossCertParams {\n txId: string;\n}\n\nexport async function appsInTossSignTossCert(_params: AppsInTossSignTossCertParams): Promise<void> {\n console.log('[@ait-co/devtools] appsInTossSignTossCert called (no-op in mock)');\n}\n","/**\n * 디바이스 모듈 내부 공유 헬퍼\n */\n\nimport { aitState } from '../state.js';\n\n// --- Placeholder Image Generator ---\n\nfunction generatePlaceholderImage(\n width: number,\n height: number,\n text: string,\n color: string,\n): string {\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n // jsdom 등 Canvas API 미지원 환경에서는 간단한 SVG data URI 반환\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\"><rect fill=\"${color}\" width=\"${width}\" height=\"${height}\"/><text x=\"50%\" y=\"50%\" fill=\"white\" font-size=\"16\" text-anchor=\"middle\" dominant-baseline=\"middle\">${text}</text></svg>`;\n return `data:image/svg+xml;base64,${btoa(svg)}`;\n }\n ctx.fillStyle = color;\n ctx.fillRect(0, 0, width, height);\n ctx.fillStyle = 'white';\n ctx.font = '16px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, width / 2, height / 2);\n return canvas.toDataURL('image/png');\n}\n\nconst DEFAULT_PLACEHOLDERS = [\n { text: 'Mock Photo 1', color: '#3182F6' },\n { text: 'Mock Photo 2', color: '#27ae60' },\n { text: 'Mock Photo 3', color: '#e67e22' },\n];\n\nlet cachedPlaceholders: string[] | null = null;\n\nexport function getDefaultPlaceholderImages(): string[] {\n if (!cachedPlaceholders) {\n cachedPlaceholders = DEFAULT_PLACEHOLDERS.map((p) =>\n generatePlaceholderImage(320, 240, p.text, p.color),\n );\n }\n return [...cachedPlaceholders];\n}\n\n/** @internal device 모듈 내부 전용 */\nexport function getMockImages(): string[] {\n const images = aitState.state.mockData.images;\n if (images.length > 0) return images;\n return getDefaultPlaceholderImages();\n}\n\n// --- Prompt Mode Helper ---\n\nconst PROMPT_TIMEOUT_MS = 30_000;\n\n/** @internal device 모듈 내부 전용 */\nexport function waitForPromptResponse<T>(type: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const eventName = `__ait:prompt-response:${type}`;\n const cancelName = '__ait:prompt-cancel';\n\n function cleanup() {\n clearTimeout(timer);\n window.removeEventListener(eventName, handler);\n window.removeEventListener(cancelName, cancelHandler);\n }\n\n const timer = setTimeout(() => {\n cleanup();\n const panelMounted = !!document.querySelector('.ait-panel');\n const hint = panelMounted\n ? 'Please provide input via the DevTools panel.'\n : 'Is @ait-co/devtools/panel imported?';\n reject(\n new Error(\n `[@ait-co/devtools] Prompt timeout for \"${type}\" after ${PROMPT_TIMEOUT_MS / 1000}s. ${hint}`,\n ),\n );\n }, PROMPT_TIMEOUT_MS);\n\n const handler = (e: Event) => {\n cleanup();\n resolve((e as CustomEvent).detail as T);\n };\n\n const cancelHandler = () => {\n cleanup();\n reject(new Error(`[@ait-co/devtools] Prompt cancelled for \"${type}\"`));\n };\n\n window.addEventListener(eventName, handler);\n window.addEventListener(cancelName, cancelHandler);\n window.dispatchEvent(new CustomEvent('__ait:prompt-request', { detail: { type } }));\n });\n}\n","/**\n * 권한 시스템 mock\n * 각 디바이스 API (.getPermission, .openPermissionDialog)에 부착된다.\n */\n\nimport { aitState } from './state.js';\nimport type { PermissionName, PermissionStatus } from './types.js';\n\nexport async function getPermission(name: PermissionName): Promise<PermissionStatus> {\n return aitState.state.permissions[name];\n}\n\nexport async function openPermissionDialog(name: PermissionName): Promise<'allowed' | 'denied'> {\n const current = aitState.state.permissions[name];\n if (current === 'allowed') return 'allowed';\n // notDetermined나 denied일 때 — Panel에서 설정된 값을 사용\n // 기본적으로는 allowed로 전환\n aitState.patch('permissions', { [name]: 'allowed' });\n return 'allowed';\n}\n\nexport async function requestPermission(permission: {\n name: PermissionName;\n access: string;\n}): Promise<'allowed' | 'denied'> {\n return openPermissionDialog(permission.name);\n}\n\n/** 권한이 필요한 함수에 .getPermission(), .openPermissionDialog()를 부착 */\nexport function withPermission<T extends (...args: never[]) => unknown>(\n fn: T,\n permissionName: PermissionName,\n): T & {\n getPermission: () => Promise<PermissionStatus>;\n openPermissionDialog: () => Promise<'allowed' | 'denied'>;\n} {\n const enhanced = fn as T & {\n getPermission: () => Promise<PermissionStatus>;\n openPermissionDialog: () => Promise<'allowed' | 'denied'>;\n };\n enhanced.getPermission = () => getPermission(permissionName);\n enhanced.openPermissionDialog = () => openPermissionDialog(permissionName);\n return enhanced;\n}\n\n/** 권한 체크 후 denied면 에러 throw */\nexport function checkPermission(name: PermissionName, fnName: string): void {\n const status = aitState.state.permissions[name];\n if (status === 'denied') {\n throw new Error(\n `[@ait-co/devtools] ${fnName}: Permission \"${name}\" is denied. Change it in the DevTools panel.`,\n );\n }\n}\n","/**\n * Camera & Album Photos mock\n * mock/web/prompt 모드 지원\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\nimport { getMockImages, waitForPromptResponse } from './_helpers.js';\n\n// --- Camera ---\n\nasync function openCameraMock(): Promise<{ id: string; dataUri: string }> {\n const images = getMockImages();\n return { id: crypto.randomUUID(), dataUri: images[0] };\n}\n\nasync function openCameraWeb(): Promise<{ id: string; dataUri: string }> {\n return new Promise((resolve, reject) => {\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = 'image/*';\n input.capture = 'environment';\n let settled = false;\n input.onchange = () => {\n settled = true;\n const file = input.files?.[0];\n if (!file) {\n reject(new Error('No file selected'));\n return;\n }\n const reader = new FileReader();\n reader.onload = () => resolve({ id: crypto.randomUUID(), dataUri: reader.result as string });\n reader.onerror = () => reject(new Error('Failed to read file'));\n reader.readAsDataURL(file);\n };\n // Detect file picker cancel via focus heuristic.\n // Note: unreliable on some mobile browsers and Safari where focus events differ.\n const onFocus = () => {\n setTimeout(() => {\n if (!settled) reject(new Error('File picker cancelled'));\n window.removeEventListener('focus', onFocus);\n }, 300);\n };\n window.addEventListener('focus', onFocus);\n input.click();\n });\n}\n\nasync function openCameraPrompt(): Promise<{ id: string; dataUri: string }> {\n const dataUri = await waitForPromptResponse<string>('camera');\n return { id: crypto.randomUUID(), dataUri };\n}\n\nconst _openCamera = async (_options?: {\n base64?: boolean;\n maxWidth?: number;\n}): Promise<{ id: string; dataUri: string }> => {\n checkPermission('camera', 'openCamera');\n const mode = aitState.state.deviceModes.camera;\n if (mode === 'web') return openCameraWeb();\n if (mode === 'prompt') return openCameraPrompt();\n return openCameraMock();\n};\nexport const openCamera = withPermission(_openCamera, 'camera');\n\n// --- Album Photos ---\n\nasync function fetchAlbumPhotosMock(\n maxCount: number,\n): Promise<Array<{ id: string; dataUri: string }>> {\n const images = getMockImages();\n return images.slice(0, maxCount).map((dataUri) => ({ id: crypto.randomUUID(), dataUri }));\n}\n\nasync function fetchAlbumPhotosWeb(\n maxCount: number,\n): Promise<Array<{ id: string; dataUri: string }>> {\n return new Promise((resolve, reject) => {\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = 'image/*';\n input.multiple = true;\n let settled = false;\n input.onchange = async () => {\n settled = true;\n const files = Array.from(input.files ?? []).slice(0, maxCount);\n if (files.length === 0) {\n reject(new Error('No files selected'));\n return;\n }\n const results = await Promise.all(\n files.map(\n (file) =>\n new Promise<{ id: string; dataUri: string }>((res, rej) => {\n const reader = new FileReader();\n reader.onload = () =>\n res({ id: crypto.randomUUID(), dataUri: reader.result as string });\n reader.onerror = () => rej(new Error('Failed to read file'));\n reader.readAsDataURL(file);\n }),\n ),\n );\n resolve(results);\n };\n const onFocus = () => {\n setTimeout(() => {\n if (!settled) reject(new Error('File picker cancelled'));\n window.removeEventListener('focus', onFocus);\n }, 300);\n };\n window.addEventListener('focus', onFocus);\n input.click();\n });\n}\n\nasync function fetchAlbumPhotosPrompt(\n maxCount: number,\n): Promise<Array<{ id: string; dataUri: string }>> {\n const dataUris = await waitForPromptResponse<string[]>('photos');\n return dataUris.slice(0, maxCount).map((dataUri) => ({ id: crypto.randomUUID(), dataUri }));\n}\n\nconst _fetchAlbumPhotos = async (options?: {\n maxCount?: number;\n maxWidth?: number;\n base64?: boolean;\n}): Promise<Array<{ id: string; dataUri: string }>> => {\n checkPermission('photos', 'fetchAlbumPhotos');\n const maxCount = options?.maxCount ?? 10;\n const mode = aitState.state.deviceModes.photos;\n if (mode === 'web') return fetchAlbumPhotosWeb(maxCount);\n if (mode === 'prompt') return fetchAlbumPhotosPrompt(maxCount);\n return fetchAlbumPhotosMock(maxCount);\n};\nexport const fetchAlbumPhotos = withPermission(_fetchAlbumPhotos, 'photos');\n","/**\n * Clipboard mock\n * mock/web 모드 지원\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\n\nconst _getClipboardText = async (): Promise<string> => {\n checkPermission('clipboard', 'getClipboardText');\n const mode = aitState.state.deviceModes.clipboard;\n if (mode === 'mock') return aitState.state.mockData.clipboardText;\n // web mode (default)\n try {\n return await navigator.clipboard.readText();\n } catch {\n return '';\n }\n};\nexport const getClipboardText = withPermission(_getClipboardText, 'clipboard');\n\nconst _setClipboardText = async (text: string): Promise<void> => {\n checkPermission('clipboard', 'setClipboardText');\n const mode = aitState.state.deviceModes.clipboard;\n if (mode === 'mock') {\n aitState.patch('mockData', { clipboardText: text });\n return;\n }\n // web mode (default)\n await navigator.clipboard.writeText(text);\n};\nexport const setClipboardText = withPermission(_setClipboardText, 'clipboard');\n","/**\n * Contacts mock\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\n\nconst _fetchContacts = async (options: {\n size: number;\n offset: number;\n query?: { contains?: string };\n}) => {\n checkPermission('contacts', 'fetchContacts');\n let contacts = aitState.state.contacts;\n if (options.query?.contains) {\n const q = options.query.contains.toLowerCase();\n contacts = contacts.filter(\n (c) => c.name.toLowerCase().includes(q) || c.phoneNumber.includes(q),\n );\n }\n const sliced = contacts.slice(options.offset, options.offset + options.size);\n const nextOffset = options.offset + options.size;\n return {\n result: sliced,\n nextOffset: nextOffset < contacts.length ? nextOffset : null,\n done: nextOffset >= contacts.length,\n };\n};\nexport const fetchContacts = withPermission(_fetchContacts, 'contacts');\n","/**\n * Haptic Feedback & saveBase64Data mock\n */\n\nimport { aitState } from '../state.js';\n\nexport async function generateHapticFeedback(options: { type: string }): Promise<void> {\n console.log(`[@ait-co/devtools] haptic: ${options.type}`);\n aitState.logAnalytics({ type: 'haptic', params: { hapticType: options.type } });\n}\n\nexport async function saveBase64Data(params: {\n data: string;\n fileName: string;\n mimeType: string;\n}): Promise<void> {\n const a = document.createElement('a');\n a.href = `data:${params.mimeType};base64,${params.data}`;\n a.download = params.fileName;\n a.click();\n}\n","/**\n * Location mock (getCurrentLocation, startUpdateLocation)\n * mock/web/prompt 모드 지원\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\nimport type { MockLocation } from '../types.js';\nimport { waitForPromptResponse } from './_helpers.js';\n\nenum Accuracy {\n Lowest = 1,\n Low = 2,\n Balanced = 3,\n High = 4,\n Highest = 5,\n BestForNavigation = 6,\n}\n\nexport { Accuracy };\n\nfunction buildLocation(): MockLocation {\n return {\n coords: { ...aitState.state.location.coords },\n timestamp: Date.now(),\n accessLocation: aitState.state.location.accessLocation,\n };\n}\n\n// -- getCurrentLocation --\n\nasync function getCurrentLocationMock(): Promise<MockLocation> {\n return buildLocation();\n}\n\nasync function getCurrentLocationWeb(): Promise<MockLocation> {\n return new Promise((resolve) => {\n if (!navigator.geolocation) {\n console.warn('[@ait-co/devtools] Geolocation API not available, falling back to mock');\n resolve(buildLocation());\n return;\n }\n navigator.geolocation.getCurrentPosition(\n (pos) => {\n resolve({\n coords: {\n latitude: pos.coords.latitude,\n longitude: pos.coords.longitude,\n altitude: pos.coords.altitude ?? 0,\n accuracy: pos.coords.accuracy,\n altitudeAccuracy: pos.coords.altitudeAccuracy ?? 0,\n heading: pos.coords.heading ?? 0,\n },\n timestamp: pos.timestamp,\n accessLocation: 'FINE',\n });\n },\n () => {\n console.warn('[@ait-co/devtools] Geolocation failed, falling back to mock');\n resolve(buildLocation());\n },\n );\n });\n}\n\nasync function getCurrentLocationPrompt(): Promise<MockLocation> {\n return waitForPromptResponse<MockLocation>('location');\n}\n\nconst _getCurrentLocation = async (_options?: { accuracy: Accuracy }): Promise<MockLocation> => {\n checkPermission('geolocation', 'getCurrentLocation');\n const mode = aitState.state.deviceModes.location;\n if (mode === 'web') return getCurrentLocationWeb();\n if (mode === 'prompt') return getCurrentLocationPrompt();\n return getCurrentLocationMock();\n};\nexport const getCurrentLocation = withPermission(_getCurrentLocation, 'geolocation');\n\n// -- startUpdateLocation --\n\ninterface StartUpdateLocationEventParams {\n onEvent: (response: MockLocation) => void;\n onError: (error: unknown) => void;\n options: { accuracy: Accuracy; timeInterval: number; distanceInterval: number };\n}\n\nfunction startUpdateLocationMock(eventParams: StartUpdateLocationEventParams): () => void {\n const { onEvent, options } = eventParams;\n const interval = Math.max(options.timeInterval, 500);\n const id = setInterval(() => {\n const loc = buildLocation();\n loc.coords.latitude += (Math.random() - 0.5) * 0.0001;\n loc.coords.longitude += (Math.random() - 0.5) * 0.0001;\n onEvent(loc);\n }, interval);\n return () => clearInterval(id);\n}\n\nfunction startUpdateLocationWeb(eventParams: StartUpdateLocationEventParams): () => void {\n const { onEvent, onError } = eventParams;\n if (!navigator.geolocation) {\n console.warn('[@ait-co/devtools] Geolocation API not available, falling back to mock');\n return startUpdateLocationMock(eventParams);\n }\n const watchId = navigator.geolocation.watchPosition(\n (pos) => {\n onEvent({\n coords: {\n latitude: pos.coords.latitude,\n longitude: pos.coords.longitude,\n altitude: pos.coords.altitude ?? 0,\n accuracy: pos.coords.accuracy,\n altitudeAccuracy: pos.coords.altitudeAccuracy ?? 0,\n heading: pos.coords.heading ?? 0,\n },\n timestamp: pos.timestamp,\n accessLocation: 'FINE',\n });\n },\n (err) => onError(err),\n );\n return () => navigator.geolocation.clearWatch(watchId);\n}\n\nfunction startUpdateLocationPrompt(eventParams: StartUpdateLocationEventParams): () => void {\n const { onEvent } = eventParams;\n const handler = (e: Event) => {\n onEvent((e as CustomEvent).detail as MockLocation);\n };\n window.addEventListener('__ait:prompt-response:location-update', handler);\n window.dispatchEvent(\n new CustomEvent('__ait:prompt-request', { detail: { type: 'location-update' } }),\n );\n return () => window.removeEventListener('__ait:prompt-response:location-update', handler);\n}\n\nconst _startUpdateLocation = (eventParams: StartUpdateLocationEventParams): (() => void) => {\n const mode = aitState.state.deviceModes.location;\n if (mode === 'web') return startUpdateLocationWeb(eventParams);\n if (mode === 'prompt') return startUpdateLocationPrompt(eventParams);\n return startUpdateLocationMock(eventParams);\n};\nexport const startUpdateLocation = withPermission(_startUpdateLocation, 'geolocation');\n","/**\n * Network Status mock (mode-aware helper)\n * navigation 모듈에서 사용. circular dep 방지를 위해 device에 위치.\n */\n\nimport { aitState } from '../state.js';\nimport type { NetworkStatus } from '../types.js';\n\n/**\n * Web mode: uses navigator.connection.effectiveType (4g/3g/2g) and navigator.onLine.\n * Limitations: WIFI, 5G, WWAN cannot be detected via the Network Information API.\n * Falls back to state-based value when effectiveType is unavailable.\n */\nexport function getNetworkStatusByMode(): NetworkStatus | null {\n const mode = aitState.state.deviceModes.network;\n if (mode === 'mock') return null; // use default state-based logic\n if (mode === 'web') {\n if (!navigator.onLine) return 'OFFLINE';\n const conn = (navigator as unknown as Record<string, unknown>).connection as\n | { effectiveType?: string }\n | undefined;\n if (conn?.effectiveType) {\n const mapping: Record<string, NetworkStatus> = {\n '4g': '4G',\n '3g': '3G',\n '2g': '2G',\n 'slow-2g': '2G',\n };\n return mapping[conn.effectiveType] ?? 'UNKNOWN';\n }\n return aitState.state.networkStatus;\n }\n // prompt mode: not supported for network, fall back to mock\n return null;\n}\n","/**\n * Storage mock\n * localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리\n */\n\nimport { createMockProxy } from '../proxy.js';\n\nexport const Storage = createMockProxy('Storage', {\n getItem: async (key: string): Promise<string | null> => {\n return localStorage.getItem(`__ait_storage:${key}`);\n },\n setItem: async (key: string, value: string): Promise<void> => {\n localStorage.setItem(`__ait_storage:${key}`, value);\n },\n removeItem: async (key: string): Promise<void> => {\n localStorage.removeItem(`__ait_storage:${key}`);\n },\n clearItems: async (): Promise<void> => {\n const keys = Object.keys(localStorage).filter((k) => k.startsWith('__ait_storage:'));\n for (const k of keys) {\n localStorage.removeItem(k);\n }\n },\n});\n","/**\n * 게임/프로모션 mock\n */\n\nimport { aitState } from '../state.js';\n\nexport async function grantPromotionReward(params: {\n params: { promotionCode: string; amount: number };\n}): Promise<{ key: string } | { errorCode: string; message: string } | 'ERROR' | undefined> {\n console.log('[@ait-co/devtools] grantPromotionReward:', params.params);\n return { key: `mock-reward-${Date.now()}` };\n}\n\nexport async function grantPromotionRewardForGame(params: {\n params: { promotionCode: string; amount: number };\n}): Promise<{ key: string } | { errorCode: string; message: string } | 'ERROR' | undefined> {\n console.log('[@ait-co/devtools] grantPromotionRewardForGame:', params.params);\n return { key: `mock-reward-${Date.now()}` };\n}\n\nexport async function submitGameCenterLeaderBoardScore(params: {\n score: string;\n}): Promise<\n | { statusCode: 'SUCCESS' | 'LEADERBOARD_NOT_FOUND' | 'PROFILE_NOT_FOUND' | 'UNPARSABLE_SCORE' }\n | undefined\n> {\n aitState.patch('game', {\n leaderboardScores: [\n ...aitState.state.game.leaderboardScores,\n { score: params.score, timestamp: Date.now() },\n ],\n });\n return { statusCode: 'SUCCESS' };\n}\n\nexport async function getGameCenterGameProfile(): Promise<\n | { statusCode: 'SUCCESS'; nickname: string; profileImageUri: string }\n | { statusCode: 'PROFILE_NOT_FOUND' }\n | undefined\n> {\n const profile = aitState.state.game.profile;\n if (!profile) return { statusCode: 'PROFILE_NOT_FOUND' };\n return {\n statusCode: 'SUCCESS',\n nickname: profile.nickname,\n profileImageUri: profile.profileImageUri,\n };\n}\n\nexport async function openGameCenterLeaderboard(): Promise<void> {\n console.log('[@ait-co/devtools] openGameCenterLeaderboard (no-op in browser)');\n}\n\ninterface ContactsViralEvent {\n type: string;\n data: Record<string, unknown>;\n}\n\nexport function contactsViral(params: {\n options: { moduleId: string };\n onEvent: (event: ContactsViralEvent) => void;\n onError: (error: unknown) => void;\n}): () => void {\n setTimeout(() => {\n params.onEvent({\n type: 'close',\n data: {\n closeReason: 'noReward',\n sentRewardsCount: 0,\n },\n });\n }, 500);\n return () => {};\n}\n","/**\n * IAP (인앱결제) mock\n */\n\nimport { createMockProxy } from '../proxy.js';\nimport { aitState } from '../state.js';\n\n// orderCounter는 모듈 레벨 상태로 reset()에 의해 초기화되지 않는다.\n// 테스트에서는 orderId를 stringContaining('mock-order-')로 검증하여 카운터 값에 의존하지 않는다.\nlet orderCounter = 0;\n\nfunction generateOrderId(): string {\n return `mock-order-${++orderCounter}-${Date.now()}`;\n}\n\ninterface IapCreateOneTimePurchaseOrderOptions {\n options: {\n sku?: string;\n productId?: string;\n processProductGrant: (params: { orderId: string }) => boolean | Promise<boolean>;\n };\n onEvent: (event: { type: 'success'; data: IapOrderResult }) => void | Promise<void>;\n onError: (error: unknown) => void | Promise<void>;\n}\n\ninterface CreateSubscriptionPurchaseOrderOptions {\n options: {\n sku: string;\n offerId?: string | null;\n processProductGrant: (params: {\n orderId: string;\n subscriptionId?: string;\n }) => boolean | Promise<boolean>;\n };\n onEvent: (event: { type: 'success'; data: IapOrderResult }) => void | Promise<void>;\n onError: (error: unknown) => void | Promise<void>;\n}\n\ninterface IapOrderResult {\n orderId: string;\n displayName: string;\n displayAmount: string;\n amount: number;\n currency: string;\n fraction: number;\n miniAppIconUrl: string | null;\n}\n\nfunction buildOrderResult(sku: string): IapOrderResult {\n const product = aitState.state.iap.products.find((p) => p.sku === sku);\n const amountStr = product?.displayAmount?.replace(/[^0-9]/g, '') ?? '1000';\n return {\n orderId: generateOrderId(),\n displayName: product?.displayName ?? 'Mock Product',\n displayAmount: product?.displayAmount ?? '1,000원',\n amount: parseInt(amountStr, 10) || 1000,\n currency: 'KRW',\n fraction: 0,\n miniAppIconUrl: product?.iconUrl || null,\n };\n}\n\nasync function handlePurchase(\n sku: string,\n processProductGrant: (params: {\n orderId: string;\n subscriptionId?: string;\n }) => boolean | Promise<boolean>,\n onEvent: (event: { type: 'success'; data: IapOrderResult }) => void | Promise<void>,\n onError: (error: unknown) => void | Promise<void>,\n): Promise<void> {\n const nextResult = aitState.state.iap.nextResult;\n\n // 비동기 시뮬레이션 (실제로는 결제 UI가 뜨는 시간)\n await new Promise((r) => setTimeout(r, 300));\n\n if (nextResult !== 'success') {\n onError({ code: nextResult });\n return;\n }\n\n const result = buildOrderResult(sku);\n\n try {\n const granted = await processProductGrant({ orderId: result.orderId });\n if (!granted) {\n onError({ code: 'PRODUCT_NOT_GRANTED_BY_PARTNER' });\n return;\n }\n } catch (e) {\n onError(e);\n return;\n }\n\n // 주문 완료 기록\n aitState.patch('iap', {\n completedOrders: [\n ...aitState.state.iap.completedOrders,\n {\n orderId: result.orderId,\n sku,\n status: 'COMPLETED' as const,\n date: new Date().toISOString(),\n },\n ],\n });\n\n await onEvent({ type: 'success', data: result });\n}\n\nexport const IAP = createMockProxy('IAP', {\n // 반환되는 cancel 함수는 mock에서는 no-op이다 (실제 SDK는 결제 UI를 닫음)\n createOneTimePurchaseOrder(params: IapCreateOneTimePurchaseOrderOptions): () => void {\n const sku = params.options.sku ?? params.options.productId ?? '';\n handlePurchase(sku, params.options.processProductGrant, params.onEvent, params.onError).catch(\n (e) => console.error('[@ait-co/devtools] IAP unexpected error:', e),\n );\n return () => {};\n },\n\n createSubscriptionPurchaseOrder(params: CreateSubscriptionPurchaseOrderOptions): () => void {\n handlePurchase(\n params.options.sku,\n params.options.processProductGrant,\n params.onEvent,\n params.onError,\n ).catch((e) => console.error('[@ait-co/devtools] IAP unexpected error:', e));\n return () => {};\n },\n\n async getProductItemList(): Promise<{ products: unknown[] }> {\n return {\n products: aitState.state.iap.products.map((p) => ({\n ...p,\n ...(p.type === 'SUBSCRIPTION' ? { renewalCycle: p.renewalCycle ?? 'MONTHLY' } : {}),\n })),\n };\n },\n\n async getPendingOrders(): Promise<{\n orders: Array<{ orderId: string; sku: string; paymentCompletedDate: string }>;\n }> {\n return { orders: [...aitState.state.iap.pendingOrders] };\n },\n\n async getCompletedOrRefundedOrders(): Promise<{\n hasNext: boolean;\n nextKey?: string | null;\n orders: Array<{ orderId: string; sku: string; status: 'COMPLETED' | 'REFUNDED'; date: string }>;\n }> {\n return {\n hasNext: false,\n nextKey: null,\n orders: [...aitState.state.iap.completedOrders],\n };\n },\n\n async completeProductGrant(args: { params: { orderId: string } }): Promise<boolean> {\n // pending → completed 전이\n const idx = aitState.state.iap.pendingOrders.findIndex(\n (o) => o.orderId === args.params.orderId,\n );\n if (idx !== -1) {\n const order = aitState.state.iap.pendingOrders[idx];\n const pendingOrders = aitState.state.iap.pendingOrders.filter((_, i) => i !== idx);\n const completedOrders = [\n ...aitState.state.iap.completedOrders,\n {\n orderId: order.orderId,\n sku: order.sku,\n status: 'COMPLETED' as const,\n date: new Date().toISOString(),\n },\n ];\n aitState.patch('iap', { pendingOrders, completedOrders });\n }\n return true;\n },\n\n async getSubscriptionInfo(_args: { params: { orderId: string } }) {\n return {\n subscription: {\n catalogId: 1,\n status: 'ACTIVE',\n expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),\n isAutoRenew: true,\n gracePeriodExpiresAt: null,\n isAccessible: true,\n },\n };\n },\n});\n\n// --- TossPay ---\n\nexport async function checkoutPayment(options: {\n params: { payToken: string };\n}): Promise<{ success: boolean; reason?: string }> {\n const { nextResult, failReason } = aitState.state.payment;\n console.log('[@ait-co/devtools] checkoutPayment:', options.params.payToken);\n\n await new Promise((r) => setTimeout(r, 300));\n\n if (nextResult === 'success') {\n return { success: true };\n }\n return { success: false, reason: failReason || 'Mock payment failed' };\n}\n","/**\n * 화면/네비게이션/이벤트 mock\n */\n\nimport { getNetworkStatusByMode } from '../device/index.js';\nimport { aitState } from '../state.js';\nimport type { NetworkStatus } from '../types.js';\n\nexport async function closeView(): Promise<void> {\n console.log('[@ait-co/devtools] closeView called');\n window.history.back();\n}\n\nexport async function openURL(url: string): Promise<void> {\n console.log('[@ait-co/devtools] openURL:', url);\n window.open(url, '_blank');\n}\n\nexport async function share(message: { message: string }): Promise<void> {\n if (navigator.share) {\n await navigator.share({ text: message.message });\n return;\n }\n console.log('[@ait-co/devtools] share:', message.message);\n}\n\nexport async function getTossShareLink(path: string, _ogImageUrl?: string): Promise<string> {\n return `https://toss.im/share/mock${path}`;\n}\n\nexport async function setIosSwipeGestureEnabled(_options: { isEnabled: boolean }): Promise<void> {\n console.log('[@ait-co/devtools] setIosSwipeGestureEnabled:', _options.isEnabled);\n}\n\nexport async function setDeviceOrientation(_options: {\n type: 'portrait' | 'landscape';\n}): Promise<void> {\n console.log('[@ait-co/devtools] setDeviceOrientation:', _options.type);\n}\n\nexport async function setScreenAwakeMode(options: {\n enabled: boolean;\n}): Promise<{ enabled: boolean }> {\n console.log('[@ait-co/devtools] setScreenAwakeMode:', options.enabled);\n return { enabled: options.enabled };\n}\n\nexport async function setSecureScreen(options: {\n enabled: boolean;\n}): Promise<{ enabled: boolean }> {\n console.log('[@ait-co/devtools] setSecureScreen:', options.enabled);\n return { enabled: options.enabled };\n}\n\nexport async function requestReview(): Promise<void> {\n console.log('[@ait-co/devtools] requestReview called');\n}\n(requestReview as unknown as { isSupported: () => boolean }).isSupported = () => true;\n\n// --- 환경 정보 ---\n\nexport function getPlatformOS(): 'ios' | 'android' {\n return aitState.state.platform;\n}\n\nexport function getOperationalEnvironment(): 'toss' | 'sandbox' {\n return aitState.state.environment;\n}\n\nexport function getTossAppVersion(): string {\n return aitState.state.appVersion;\n}\n\nexport function isMinVersionSupported(minVersions: { android: string; ios: string }): boolean {\n const platform = aitState.state.platform;\n const required = platform === 'ios' ? minVersions.ios : minVersions.android;\n if (required === 'always') return true;\n if (required === 'never') return false;\n\n const current = aitState.state.appVersion.split('.').map(Number);\n const min = required.split('.').map(Number);\n for (let i = 0; i < 3; i++) {\n if ((current[i] ?? 0) > (min[i] ?? 0)) return true;\n if ((current[i] ?? 0) < (min[i] ?? 0)) return false;\n }\n return true; // equal\n}\n\nexport function getSchemeUri(): string {\n return aitState.state.schemeUri || window.location.pathname;\n}\n\nexport function getLocale(): string {\n return aitState.state.locale;\n}\n\nexport function getDeviceId(): string {\n return aitState.state.deviceId;\n}\n\nexport function getGroupId(): string {\n return aitState.state.groupId;\n}\n\nexport async function getNetworkStatus(): Promise<NetworkStatus> {\n const modeResult = getNetworkStatusByMode();\n if (modeResult) return modeResult;\n return aitState.state.networkStatus;\n}\n\nexport async function getServerTime(): Promise<number | undefined> {\n return Date.now();\n}\n(getServerTime as unknown as { isSupported: () => boolean }).isSupported = () => true;\n\n// --- 이벤트 시스템 ---\n\ninterface GraniteEventMap {\n backEvent: { onEvent: () => void; onError?: (error: Error) => void; options?: undefined };\n homeEvent: { onEvent: () => void; onError?: (error: Error) => void; options?: undefined };\n}\n\nexport const graniteEvent = {\n addEventListener<K extends keyof GraniteEventMap>(\n event: K,\n {\n onEvent,\n onError,\n }: {\n onEvent: GraniteEventMap[K]['onEvent'];\n onError?: GraniteEventMap[K]['onError'];\n options?: GraniteEventMap[K]['options'];\n },\n ): () => void {\n const handler = () => {\n try {\n onEvent();\n } catch (e) {\n onError?.(e instanceof Error ? e : new Error(String(e)));\n }\n };\n window.addEventListener(`__ait:${event}`, handler);\n return () => window.removeEventListener(`__ait:${event}`, handler);\n },\n};\n\nexport const appsInTossEvent = {\n addEventListener<K extends string>(\n _event: K,\n _handlers: {\n onEvent: (...args: unknown[]) => void;\n onError?: (error: Error) => void;\n options?: unknown;\n },\n ): () => void {\n return () => {};\n },\n};\n\ninterface TdsEventMap {\n navigationAccessoryEvent: {\n onEvent: (data: { id: string }) => void;\n onError?: (error: Error) => void;\n options: undefined;\n };\n}\n\nexport const tdsEvent = {\n addEventListener<K extends keyof TdsEventMap>(\n event: K,\n {\n onEvent,\n }: {\n onEvent: TdsEventMap[K]['onEvent'];\n onError?: TdsEventMap[K]['onError'];\n options?: TdsEventMap[K]['options'];\n },\n ): () => void {\n const handler = (e: Event) => {\n const detail = (e as CustomEvent).detail;\n onEvent(detail);\n };\n window.addEventListener(`__ait:${event}`, handler);\n return () => window.removeEventListener(`__ait:${event}`, handler);\n },\n};\n\nexport function onVisibilityChangedByTransparentServiceWeb(eventParams: {\n options: { callbackId: string };\n onEvent: (isVisible: boolean) => void;\n onError: (error: unknown) => void;\n}): () => void {\n const handler = () => eventParams.onEvent(!document.hidden);\n document.addEventListener('visibilitychange', handler);\n return () => document.removeEventListener('visibilitychange', handler);\n}\n\n// --- env / globals ---\n\nexport const env = {\n getDeploymentId: () => aitState.state.deploymentId,\n};\n\nexport function getAppsInTossGlobals() {\n return {\n deploymentId: aitState.state.deploymentId,\n brandDisplayName: aitState.state.brand.displayName,\n brandIcon: aitState.state.brand.icon,\n brandPrimaryColor: aitState.state.brand.primaryColor,\n };\n}\n\n// --- SafeAreaInsets ---\n\ntype SafeAreaInsetsValue = { top: number; bottom: number; left: number; right: number };\ntype SafeAreaInsetsSubscribeHandler = { onEvent: (data: SafeAreaInsetsValue) => void };\n\nexport const SafeAreaInsets = {\n get: (): SafeAreaInsetsValue => ({ ...aitState.state.safeAreaInsets }),\n // NOTE: aitState.subscribe에 위임하므로 safeAreaInsets 외 상태 변경에도 콜백이 호출된다.\n // 실제 SDK는 insets 변경 시에만 호출되지만, mock에서는 간소화를 위해 필터링하지 않는다.\n subscribe: ({ onEvent }: SafeAreaInsetsSubscribeHandler): (() => void) => {\n return aitState.subscribe(() => onEvent({ ...aitState.state.safeAreaInsets }));\n },\n};\n\n/** @deprecated */\nexport function getSafeAreaInsets(): number {\n return aitState.state.safeAreaInsets.top;\n}\n","/**\n * Partner / TDS mock\n */\n\ninterface AddAccessoryButtonOptions {\n id: string;\n title: string;\n icon: { name: string };\n}\n\nexport const partner = {\n async addAccessoryButton(options: AddAccessoryButtonOptions): Promise<void> {\n console.log('[@ait-co/devtools] partner.addAccessoryButton:', options);\n },\n async removeAccessoryButton(): Promise<void> {\n console.log('[@ait-co/devtools] partner.removeAccessoryButton');\n },\n};\n"],"mappings":";;;;;;;;;;AAUA,MAAM,aAAa;AAEnB,SAAgB,gBACd,YACA,iBACG;AACH,QAAO,IAAI,MAAM,iBAAiB,EAChC,IAAI,QAAQ,MAAM;AAGhB,MAAI,OAAO,SAAS,SAAU,QAAO,KAAA;AACrC,MAAI,QAAQ,OAAQ,QAAO,OAAO;AAElC,QAAM,IAAI,MACR,sBAAsB,WAAW,GAAG,KAAK,qIAGd,aAC5B;IAEJ,CAAC;;;;ACsGJ,MAAM,gBAAkC;CACtC,UAAU;CACV,aAAa;CACb,YAAY;CACZ,QAAQ;CACR,WAAW;CACX,SAAS;CACT,cAAc;CACd,UAAU;CAEV,OAAO;EACL,aAAa;EACb,MAAM;EACN,cAAc;EACf;CAED,eAAe;CAEf,aAAa;EACX,WAAW;EACX,UAAU;EACV,QAAQ;EACR,aAAa;EACb,QAAQ;EACR,YAAY;EACb;CAED,UAAU;EACR,QAAQ;GACN,UAAU;GACV,WAAW;GACX,UAAU;GACV,UAAU;GACV,kBAAkB;GAClB,SAAS;GACV;EACD,WAAW,KAAK,KAAK;EACrB,gBAAgB;EACjB;CAED,gBAAgB;EAAE,KAAK;EAAI,QAAQ;EAAI,MAAM;EAAG,OAAO;EAAG;CAE1D,UAAU,CACR;EAAE,MAAM;EAAO,aAAa;EAAiB,EAC7C;EAAE,MAAM;EAAO,aAAa;EAAiB,CAC9C;CAED,KAAK;EACH,UAAU,CACR;GACE,KAAK;GACL,MAAM;GACN,aAAa;GACb,eAAe;GACf,SAAS;GACT,aAAa;GACd,CACF;EACD,YAAY;EACZ,eAAe,EAAE;EACjB,iBAAiB,EAAE;EACpB;CAED,SAAS;EACP,YAAY;EACZ,YAAY;EACb;CAED,MAAM;EACJ,YAAY;EACZ,uBAAuB;EACvB,aAAa;EACd;CAED,KAAK;EACH,UAAU;EACV,WAAW;EACZ;CAED,MAAM;EACJ,SAAS;GAAE,UAAU;GAAc,iBAAiB;GAAI;EACxD,mBAAmB,EAAE;EACtB;CAED,cAAc,EAAE;CAEhB,aAAa;EACX,QAAQ;EACR,QAAQ;EACR,UAAU;EACV,SAAS;EACT,WAAW;EACZ;CAED,UAAU;EACR,QAAQ,EAAE;EACV,eAAe;EAChB;CAED,eAAe;CAChB;AAED,SAAS,mBAA2B;CAClC,MAAM,SAAS,aAAa,QAAQ,kBAAkB;AACtD,KAAI,OAAQ,QAAO;CACnB,MAAM,KAAK,OAAO,YAAY;AAC9B,cAAa,QAAQ,mBAAmB,GAAG;AAC3C,QAAO;;AAGT,IAAa,kBAAb,MAA6B;CAC3B;CACA,6BAAqB,IAAI,KAAe;CAExC,cAAc;AACZ,OAAK,SAAS,gBAAgB,cAAc;AAC5C,MAAI;AACF,QAAK,OAAO,WAAW,kBAAkB;UACnC;AACN,QAAK,OAAO,WAAW,eAAe,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,MAAM,EAAE;;;CAI7E,IAAI,QAA0B;AAC5B,SAAO,KAAK;;CAGd,OAAO,SAAoC;AACzC,OAAK,SAAS;GAAE,GAAG,KAAK;GAAQ,GAAG;GAAS;AAC5C,OAAK,SAAS;;;CAIhB,MAAwC,KAAQ,SAAuC;EACrF,MAAM,UAAU,KAAK,OAAO;AAC5B,MAAI,OAAO,YAAY,YAAY,YAAY,QAAQ,CAAC,MAAM,QAAQ,QAAQ,CAC5E,MAAK,SAAS;GACZ,GAAG,KAAK;IACP,MAAM;IAAE,GAAI;IAAqC,GAAI;IAAqC;GAC5F;MAED,MAAK,SAAS;GAAE,GAAG,KAAK;IAAS,MAAM;GAAgC;AAEzE,OAAK,SAAS;;CAGhB,UAAU,UAAgC;AACxC,OAAK,WAAW,IAAI,SAAS;AAC7B,eAAa,KAAK,WAAW,OAAO,SAAS;;;CAI/C,aAAa,OAA6C;AACxD,OAAK,SAAS;GACZ,GAAG,KAAK;GACR,cAAc,CAAC,GAAG,KAAK,OAAO,cAAc;IAAE,GAAG;IAAO,WAAW,KAAK,KAAK;IAAE,CAAC;GACjF;AACD,OAAK,SAAS;;;CAIhB,QAAQ,OAAe;AACrB,SAAO,cAAc,IAAI,YAAY,SAAS,QAAQ,CAAC;;CAGzD,QAAQ;EACN,MAAM,WAAW,KAAK,OAAO;AAC7B,OAAK,SAAS;GAAE,GAAG,gBAAgB,cAAc;GAAE;GAAU;AAC7D,OAAK,SAAS;;CAGhB,UAAkB;AAChB,OAAK,MAAM,YAAY,KAAK,WAC1B,WAAU;;;AAKhB,MAAa,WAAW,IAAI,iBAAiB;AAG7C,IAAI,OAAO,WAAW,YACpB,QAAO,QAAQ;;;;;;ACnTjB,SAAS,gBACP,IACoC;AACnC,IAA0C,oBAAoB;AAC/D,QAAO;;AAKT,MAAa,cAAc,gBAAgB,eAAe;CACxD,qBAAqB,iBAClB,SAImB;AAClB,mBAAiB;AACf,YAAS,MAAM,OAAO,EAAE,UAAU,MAAM,CAAC;AACzC,QAAK,QAAQ;IAAE,MAAM;IAAU,MAAM,EAAE,WAAW,KAAK,SAAS,WAAW;IAAE,CAAC;KAC7E,IAAI;AACP,eAAa;GAEhB;CAED,qBAAqB,iBAClB,SAImB;AAClB,MAAI,CAAC,SAAS,MAAM,IAAI,UAAU;AAChC,QAAK,wBAAQ,IAAI,MAAM,gBAAgB,CAAC;AACxC,gBAAa;;AAEf,mBAAiB,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC,EAAE,GAAG;AACzD,mBAAiB,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC,EAAE,IAAI;AACrD,mBAAiB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC,EAAE,IAAI;AAC3D,mBAAiB;AACf,QAAK,QAAQ;IAAE,MAAM;IAAoB,MAAM;KAAE,UAAU;KAAS,YAAY;KAAI;IAAE,CAAC;KACtF,IAAK;AACR,mBAAiB;AACf,QAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AACnC,YAAS,MAAM,OAAO,EAAE,UAAU,OAAO,CAAC;KACzC,KAAK;AACR,eAAa;GAEhB;CAED,yBAAyB,gBACvB,OAAO,aAAuD,SAAS,MAAM,IAAI,SAClF;CACF,CAAC;AAIF,MAAa,UAAU,gBAAgB,WAAW;CAChD,YAAY,iBAAiB,aAAsB;AACjD,UAAQ,IAAI,+CAA+C;GAC3D;CACF,QAAQ,iBACL,YAAoB,QAA8B,aAAuB;EACxE,MAAM,KAAK,OAAO,WAAW,WAAW,SAAS,cAAc,OAAO,GAAG;AACzE,MAAI,IAAI;GACN,MAAM,cAAc,SAAS,cAAc,MAAM;AACjD,eAAY,MAAM,UAChB;AACF,eAAY,cAAc;AAC1B,MAAG,YAAY,YAAY;;GAGhC;CACD,cAAc,iBACX,YAAoB,QAA8B,aAAuB;EACxE,MAAM,KAAK,OAAO,WAAW,WAAW,SAAS,cAAc,OAAO,GAAG;AACzE,MAAI,IAAI;GACN,MAAM,cAAc,SAAS,cAAc,MAAM;AACjD,eAAY,MAAM,UAChB;AACF,eAAY,cAAc;AAC1B,MAAG,YAAY,YAAY;;AAE7B,SAAO,EAAE,eAAe,IAAI;GAE/B;CACD,SAAS,iBAAiB,YAAoB,GAAG;CACjD,YAAY,sBAAsB,GAAG;CACtC,CAAC;AAIF,MAAa,mBAAmB,iBAC7B,SAImB;AAClB,kBAAiB;AACf,WAAS,MAAM,OAAO,EAAE,UAAU,MAAM,CAAC;AACzC,OAAK,QAAQ;GAAE,MAAM;GAAU,MAAM,EAAE,WAAW,KAAK,SAAS,WAAW;GAAE,CAAC;IAC7E,IAAI;AACP,cAAa;EAEhB;AAED,MAAa,mBAAmB,iBAC7B,SAImB;AAClB,KAAI,CAAC,SAAS,MAAM,IAAI,UAAU;AAChC,OAAK,wBAAQ,IAAI,MAAM,gBAAgB,CAAC;AACxC,eAAa;;AAEf,kBAAiB,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC,EAAE,IAAI;AACrD,kBAAiB,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC,EAAE,KAAK;AAC3D,cAAa;EAEhB;;;;;;AClHD,MAAa,YAAY;CACvB,SAAS,WAAqD;AAC5D,WAAS,aAAa;GAAE,MAAM;GAAU,QAAQ,UAAU,EAAE;GAAE,CAAC;AAC/D,SAAO,QAAQ,SAAS;;CAE1B,aAAa,WAAqD;AAChE,WAAS,aAAa;GAAE,MAAM;GAAc,QAAQ,UAAU,EAAE;GAAE,CAAC;AACnE,SAAO,QAAQ,SAAS;;CAE1B,QAAQ,WAAqD;AAC3D,WAAS,aAAa;GAAE,MAAM;GAAS,QAAQ,UAAU,EAAE;GAAE,CAAC;AAC9D,SAAO,QAAQ,SAAS;;CAE3B;AAED,eAAsB,SAAS,QAIb;AAChB,UAAS,aAAa;EACpB,MAAM,OAAO;EACb,QAAQ;GAAE,UAAU,OAAO;GAAU,GAAG,OAAO;GAAQ;EACxD,CAAC;;;;;;;AC5BJ,eAAsB,WAGnB;AACD,QAAO;EACL,mBAAmB,aAAa,OAAO,YAAY;EACnD,UAAU,SAAS,MAAM,gBAAgB,SAAS,YAAY;EAC/D;;AAGH,eAAsB,kCAAgE;AACpF,QAAO,SAAS,MAAM,KAAK;;AAG7B,eAAsB,oBAEpB;AACA,KAAI,CAAC,SAAS,MAAM,KAAK,YAAa,QAAO,KAAA;AAC7C,QAAO;EAAE,MAAM,SAAS,MAAM,KAAK;EAAa,MAAM;EAAQ;;AAOhE,eAAsB,uBAAuB,SAAsD;AACjG,SAAQ,IAAI,mEAAmE;;;;;;;ACxBjF,SAAS,yBACP,OACA,QACA,MACA,OACQ;CACR,MAAM,SAAS,SAAS,cAAc,SAAS;AAC/C,QAAO,QAAQ;AACf,QAAO,SAAS;CAChB,MAAM,MAAM,OAAO,WAAW,KAAK;AACnC,KAAI,CAAC,KAAK;EAER,MAAM,MAAM,kDAAkD,MAAM,YAAY,OAAO,gBAAgB,MAAM,WAAW,MAAM,YAAY,OAAO,uGAAuG,KAAK;AAC7P,SAAO,6BAA6B,KAAK,IAAI;;AAE/C,KAAI,YAAY;AAChB,KAAI,SAAS,GAAG,GAAG,OAAO,OAAO;AACjC,KAAI,YAAY;AAChB,KAAI,OAAO;AACX,KAAI,YAAY;AAChB,KAAI,eAAe;AACnB,KAAI,SAAS,MAAM,QAAQ,GAAG,SAAS,EAAE;AACzC,QAAO,OAAO,UAAU,YAAY;;AAGtC,MAAM,uBAAuB;CAC3B;EAAE,MAAM;EAAgB,OAAO;EAAW;CAC1C;EAAE,MAAM;EAAgB,OAAO;EAAW;CAC1C;EAAE,MAAM;EAAgB,OAAO;EAAW;CAC3C;AAED,IAAI,qBAAsC;AAE1C,SAAgB,8BAAwC;AACtD,KAAI,CAAC,mBACH,sBAAqB,qBAAqB,KAAK,MAC7C,yBAAyB,KAAK,KAAK,EAAE,MAAM,EAAE,MAAM,CACpD;AAEH,QAAO,CAAC,GAAG,mBAAmB;;;AAIhC,SAAgB,gBAA0B;CACxC,MAAM,SAAS,SAAS,MAAM,SAAS;AACvC,KAAI,OAAO,SAAS,EAAG,QAAO;AAC9B,QAAO,6BAA6B;;AAKtC,MAAM,oBAAoB;;AAG1B,SAAgB,sBAAyB,MAA0B;AACjE,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,YAAY,yBAAyB;EAC3C,MAAM,aAAa;EAEnB,SAAS,UAAU;AACjB,gBAAa,MAAM;AACnB,UAAO,oBAAoB,WAAW,QAAQ;AAC9C,UAAO,oBAAoB,YAAY,cAAc;;EAGvD,MAAM,QAAQ,iBAAiB;AAC7B,YAAS;GAET,MAAM,OADe,CAAC,CAAC,SAAS,cAAc,aAAa,GAEvD,iDACA;AACJ,0BACE,IAAI,MACF,0CAA0C,KAAK,UAAU,oBAAoB,IAAK,KAAK,OACxF,CACF;KACA,kBAAkB;EAErB,MAAM,WAAW,MAAa;AAC5B,YAAS;AACT,WAAS,EAAkB,OAAY;;EAGzC,MAAM,sBAAsB;AAC1B,YAAS;AACT,0BAAO,IAAI,MAAM,4CAA4C,KAAK,GAAG,CAAC;;AAGxE,SAAO,iBAAiB,WAAW,QAAQ;AAC3C,SAAO,iBAAiB,YAAY,cAAc;AAClD,SAAO,cAAc,IAAI,YAAY,wBAAwB,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;GACnF;;;;;;;;AC3FJ,eAAsB,cAAc,MAAiD;AACnF,QAAO,SAAS,MAAM,YAAY;;AAGpC,eAAsB,qBAAqB,MAAqD;AAE9F,KADgB,SAAS,MAAM,YAAY,UAC3B,UAAW,QAAO;AAGlC,UAAS,MAAM,eAAe,GAAG,OAAO,WAAW,CAAC;AACpD,QAAO;;AAGT,eAAsB,kBAAkB,YAGN;AAChC,QAAO,qBAAqB,WAAW,KAAK;;;AAI9C,SAAgB,eACd,IACA,gBAIA;CACA,MAAM,WAAW;AAIjB,UAAS,sBAAsB,cAAc,eAAe;AAC5D,UAAS,6BAA6B,qBAAqB,eAAe;AAC1E,QAAO;;;AAIT,SAAgB,gBAAgB,MAAsB,QAAsB;AAE1E,KADe,SAAS,MAAM,YAAY,UAC3B,SACb,OAAM,IAAI,MACR,sBAAsB,OAAO,gBAAgB,KAAK,+CACnD;;;;;;;;ACxCL,eAAe,iBAA2D;CACxE,MAAM,SAAS,eAAe;AAC9B,QAAO;EAAE,IAAI,OAAO,YAAY;EAAE,SAAS,OAAO;EAAI;;AAGxD,eAAe,gBAA0D;AACvE,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,QAAM,OAAO;AACb,QAAM,SAAS;AACf,QAAM,UAAU;EAChB,IAAI,UAAU;AACd,QAAM,iBAAiB;AACrB,aAAU;GACV,MAAM,OAAO,MAAM,QAAQ;AAC3B,OAAI,CAAC,MAAM;AACT,2BAAO,IAAI,MAAM,mBAAmB,CAAC;AACrC;;GAEF,MAAM,SAAS,IAAI,YAAY;AAC/B,UAAO,eAAe,QAAQ;IAAE,IAAI,OAAO,YAAY;IAAE,SAAS,OAAO;IAAkB,CAAC;AAC5F,UAAO,gBAAgB,uBAAO,IAAI,MAAM,sBAAsB,CAAC;AAC/D,UAAO,cAAc,KAAK;;EAI5B,MAAM,gBAAgB;AACpB,oBAAiB;AACf,QAAI,CAAC,QAAS,wBAAO,IAAI,MAAM,wBAAwB,CAAC;AACxD,WAAO,oBAAoB,SAAS,QAAQ;MAC3C,IAAI;;AAET,SAAO,iBAAiB,SAAS,QAAQ;AACzC,QAAM,OAAO;GACb;;AAGJ,eAAe,mBAA6D;CAC1E,MAAM,UAAU,MAAM,sBAA8B,SAAS;AAC7D,QAAO;EAAE,IAAI,OAAO,YAAY;EAAE;EAAS;;AAG7C,MAAM,cAAc,OAAO,aAGqB;AAC9C,iBAAgB,UAAU,aAAa;CACvC,MAAM,OAAO,SAAS,MAAM,YAAY;AACxC,KAAI,SAAS,MAAO,QAAO,eAAe;AAC1C,KAAI,SAAS,SAAU,QAAO,kBAAkB;AAChD,QAAO,gBAAgB;;AAEzB,MAAa,aAAa,eAAe,aAAa,SAAS;AAI/D,eAAe,qBACb,UACiD;AAEjD,QADe,eAAe,CAChB,MAAM,GAAG,SAAS,CAAC,KAAK,aAAa;EAAE,IAAI,OAAO,YAAY;EAAE;EAAS,EAAE;;AAG3F,eAAe,oBACb,UACiD;AACjD,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,QAAM,OAAO;AACb,QAAM,SAAS;AACf,QAAM,WAAW;EACjB,IAAI,UAAU;AACd,QAAM,WAAW,YAAY;AAC3B,aAAU;GACV,MAAM,QAAQ,MAAM,KAAK,MAAM,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,SAAS;AAC9D,OAAI,MAAM,WAAW,GAAG;AACtB,2BAAO,IAAI,MAAM,oBAAoB,CAAC;AACtC;;AAcF,WAZgB,MAAM,QAAQ,IAC5B,MAAM,KACH,SACC,IAAI,SAA0C,KAAK,QAAQ;IACzD,MAAM,SAAS,IAAI,YAAY;AAC/B,WAAO,eACL,IAAI;KAAE,IAAI,OAAO,YAAY;KAAE,SAAS,OAAO;KAAkB,CAAC;AACpE,WAAO,gBAAgB,oBAAI,IAAI,MAAM,sBAAsB,CAAC;AAC5D,WAAO,cAAc,KAAK;KAC1B,CACL,CACF,CACe;;EAElB,MAAM,gBAAgB;AACpB,oBAAiB;AACf,QAAI,CAAC,QAAS,wBAAO,IAAI,MAAM,wBAAwB,CAAC;AACxD,WAAO,oBAAoB,SAAS,QAAQ;MAC3C,IAAI;;AAET,SAAO,iBAAiB,SAAS,QAAQ;AACzC,QAAM,OAAO;GACb;;AAGJ,eAAe,uBACb,UACiD;AAEjD,SADiB,MAAM,sBAAgC,SAAS,EAChD,MAAM,GAAG,SAAS,CAAC,KAAK,aAAa;EAAE,IAAI,OAAO,YAAY;EAAE;EAAS,EAAE;;AAG7F,MAAM,oBAAoB,OAAO,YAIsB;AACrD,iBAAgB,UAAU,mBAAmB;CAC7C,MAAM,WAAW,SAAS,YAAY;CACtC,MAAM,OAAO,SAAS,MAAM,YAAY;AACxC,KAAI,SAAS,MAAO,QAAO,oBAAoB,SAAS;AACxD,KAAI,SAAS,SAAU,QAAO,uBAAuB,SAAS;AAC9D,QAAO,qBAAqB,SAAS;;AAEvC,MAAa,mBAAmB,eAAe,mBAAmB,SAAS;;;;;;;AC9H3E,MAAM,oBAAoB,YAA6B;AACrD,iBAAgB,aAAa,mBAAmB;AAEhD,KADa,SAAS,MAAM,YAAY,cAC3B,OAAQ,QAAO,SAAS,MAAM,SAAS;AAEpD,KAAI;AACF,SAAO,MAAM,UAAU,UAAU,UAAU;SACrC;AACN,SAAO;;;AAGX,MAAa,mBAAmB,eAAe,mBAAmB,YAAY;AAE9E,MAAM,oBAAoB,OAAO,SAAgC;AAC/D,iBAAgB,aAAa,mBAAmB;AAEhD,KADa,SAAS,MAAM,YAAY,cAC3B,QAAQ;AACnB,WAAS,MAAM,YAAY,EAAE,eAAe,MAAM,CAAC;AACnD;;AAGF,OAAM,UAAU,UAAU,UAAU,KAAK;;AAE3C,MAAa,mBAAmB,eAAe,mBAAmB,YAAY;;;;;;ACxB9E,MAAM,iBAAiB,OAAO,YAIxB;AACJ,iBAAgB,YAAY,gBAAgB;CAC5C,IAAI,WAAW,SAAS,MAAM;AAC9B,KAAI,QAAQ,OAAO,UAAU;EAC3B,MAAM,IAAI,QAAQ,MAAM,SAAS,aAAa;AAC9C,aAAW,SAAS,QACjB,MAAM,EAAE,KAAK,aAAa,CAAC,SAAS,EAAE,IAAI,EAAE,YAAY,SAAS,EAAE,CACrE;;CAEH,MAAM,SAAS,SAAS,MAAM,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,KAAK;CAC5E,MAAM,aAAa,QAAQ,SAAS,QAAQ;AAC5C,QAAO;EACL,QAAQ;EACR,YAAY,aAAa,SAAS,SAAS,aAAa;EACxD,MAAM,cAAc,SAAS;EAC9B;;AAEH,MAAa,gBAAgB,eAAe,gBAAgB,WAAW;;;;;;ACtBvE,eAAsB,uBAAuB,SAA0C;AACrF,SAAQ,IAAI,8BAA8B,QAAQ,OAAO;AACzD,UAAS,aAAa;EAAE,MAAM;EAAU,QAAQ,EAAE,YAAY,QAAQ,MAAM;EAAE,CAAC;;AAGjF,eAAsB,eAAe,QAInB;CAChB,MAAM,IAAI,SAAS,cAAc,IAAI;AACrC,GAAE,OAAO,QAAQ,OAAO,SAAS,UAAU,OAAO;AAClD,GAAE,WAAW,OAAO;AACpB,GAAE,OAAO;;;;;;;;ACTX,IAAK,WAAL,yBAAA,UAAA;AACE,UAAA,SAAA,YAAA,KAAA;AACA,UAAA,SAAA,SAAA,KAAA;AACA,UAAA,SAAA,cAAA,KAAA;AACA,UAAA,SAAA,UAAA,KAAA;AACA,UAAA,SAAA,aAAA,KAAA;AACA,UAAA,SAAA,uBAAA,KAAA;;EANG,YAAA,EAAA,CAOJ;AAID,SAAS,gBAA8B;AACrC,QAAO;EACL,QAAQ,EAAE,GAAG,SAAS,MAAM,SAAS,QAAQ;EAC7C,WAAW,KAAK,KAAK;EACrB,gBAAgB,SAAS,MAAM,SAAS;EACzC;;AAKH,eAAe,yBAAgD;AAC7D,QAAO,eAAe;;AAGxB,eAAe,wBAA+C;AAC5D,QAAO,IAAI,SAAS,YAAY;AAC9B,MAAI,CAAC,UAAU,aAAa;AAC1B,WAAQ,KAAK,yEAAyE;AACtF,WAAQ,eAAe,CAAC;AACxB;;AAEF,YAAU,YAAY,oBACnB,QAAQ;AACP,WAAQ;IACN,QAAQ;KACN,UAAU,IAAI,OAAO;KACrB,WAAW,IAAI,OAAO;KACtB,UAAU,IAAI,OAAO,YAAY;KACjC,UAAU,IAAI,OAAO;KACrB,kBAAkB,IAAI,OAAO,oBAAoB;KACjD,SAAS,IAAI,OAAO,WAAW;KAChC;IACD,WAAW,IAAI;IACf,gBAAgB;IACjB,CAAC;WAEE;AACJ,WAAQ,KAAK,8DAA8D;AAC3E,WAAQ,eAAe,CAAC;IAE3B;GACD;;AAGJ,eAAe,2BAAkD;AAC/D,QAAO,sBAAoC,WAAW;;AAGxD,MAAM,sBAAsB,OAAO,aAA6D;AAC9F,iBAAgB,eAAe,qBAAqB;CACpD,MAAM,OAAO,SAAS,MAAM,YAAY;AACxC,KAAI,SAAS,MAAO,QAAO,uBAAuB;AAClD,KAAI,SAAS,SAAU,QAAO,0BAA0B;AACxD,QAAO,wBAAwB;;AAEjC,MAAa,qBAAqB,eAAe,qBAAqB,cAAc;AAUpF,SAAS,wBAAwB,aAAyD;CACxF,MAAM,EAAE,SAAS,YAAY;CAC7B,MAAM,WAAW,KAAK,IAAI,QAAQ,cAAc,IAAI;CACpD,MAAM,KAAK,kBAAkB;EAC3B,MAAM,MAAM,eAAe;AAC3B,MAAI,OAAO,aAAa,KAAK,QAAQ,GAAG,MAAO;AAC/C,MAAI,OAAO,cAAc,KAAK,QAAQ,GAAG,MAAO;AAChD,UAAQ,IAAI;IACX,SAAS;AACZ,cAAa,cAAc,GAAG;;AAGhC,SAAS,uBAAuB,aAAyD;CACvF,MAAM,EAAE,SAAS,YAAY;AAC7B,KAAI,CAAC,UAAU,aAAa;AAC1B,UAAQ,KAAK,yEAAyE;AACtF,SAAO,wBAAwB,YAAY;;CAE7C,MAAM,UAAU,UAAU,YAAY,eACnC,QAAQ;AACP,UAAQ;GACN,QAAQ;IACN,UAAU,IAAI,OAAO;IACrB,WAAW,IAAI,OAAO;IACtB,UAAU,IAAI,OAAO,YAAY;IACjC,UAAU,IAAI,OAAO;IACrB,kBAAkB,IAAI,OAAO,oBAAoB;IACjD,SAAS,IAAI,OAAO,WAAW;IAChC;GACD,WAAW,IAAI;GACf,gBAAgB;GACjB,CAAC;KAEH,QAAQ,QAAQ,IAAI,CACtB;AACD,cAAa,UAAU,YAAY,WAAW,QAAQ;;AAGxD,SAAS,0BAA0B,aAAyD;CAC1F,MAAM,EAAE,YAAY;CACpB,MAAM,WAAW,MAAa;AAC5B,UAAS,EAAkB,OAAuB;;AAEpD,QAAO,iBAAiB,yCAAyC,QAAQ;AACzE,QAAO,cACL,IAAI,YAAY,wBAAwB,EAAE,QAAQ,EAAE,MAAM,mBAAmB,EAAE,CAAC,CACjF;AACD,cAAa,OAAO,oBAAoB,yCAAyC,QAAQ;;AAG3F,MAAM,wBAAwB,gBAA8D;CAC1F,MAAM,OAAO,SAAS,MAAM,YAAY;AACxC,KAAI,SAAS,MAAO,QAAO,uBAAuB,YAAY;AAC9D,KAAI,SAAS,SAAU,QAAO,0BAA0B,YAAY;AACpE,QAAO,wBAAwB,YAAY;;AAE7C,MAAa,sBAAsB,eAAe,sBAAsB,cAAc;;;;;;;;;;;;ACjItF,SAAgB,yBAA+C;CAC7D,MAAM,OAAO,SAAS,MAAM,YAAY;AACxC,KAAI,SAAS,OAAQ,QAAO;AAC5B,KAAI,SAAS,OAAO;AAClB,MAAI,CAAC,UAAU,OAAQ,QAAO;EAC9B,MAAM,OAAQ,UAAiD;AAG/D,MAAI,MAAM,cAOR,QAN+C;GAC7C,MAAM;GACN,MAAM;GACN,MAAM;GACN,WAAW;GACZ,CACc,KAAK,kBAAkB;AAExC,SAAO,SAAS,MAAM;;AAGxB,QAAO;;;;;;;;AC1BT,MAAa,UAAU,gBAAgB,WAAW;CAChD,SAAS,OAAO,QAAwC;AACtD,SAAO,aAAa,QAAQ,iBAAiB,MAAM;;CAErD,SAAS,OAAO,KAAa,UAAiC;AAC5D,eAAa,QAAQ,iBAAiB,OAAO,MAAM;;CAErD,YAAY,OAAO,QAA+B;AAChD,eAAa,WAAW,iBAAiB,MAAM;;CAEjD,YAAY,YAA2B;EACrC,MAAM,OAAO,OAAO,KAAK,aAAa,CAAC,QAAQ,MAAM,EAAE,WAAW,iBAAiB,CAAC;AACpF,OAAK,MAAM,KAAK,KACd,cAAa,WAAW,EAAE;;CAG/B,CAAC;;;;;;ACjBF,eAAsB,qBAAqB,QAEiD;AAC1F,SAAQ,IAAI,4CAA4C,OAAO,OAAO;AACtE,QAAO,EAAE,KAAK,eAAe,KAAK,KAAK,IAAI;;AAG7C,eAAsB,4BAA4B,QAE0C;AAC1F,SAAQ,IAAI,mDAAmD,OAAO,OAAO;AAC7E,QAAO,EAAE,KAAK,eAAe,KAAK,KAAK,IAAI;;AAG7C,eAAsB,iCAAiC,QAKrD;AACA,UAAS,MAAM,QAAQ,EACrB,mBAAmB,CACjB,GAAG,SAAS,MAAM,KAAK,mBACvB;EAAE,OAAO,OAAO;EAAO,WAAW,KAAK,KAAK;EAAE,CAC/C,EACF,CAAC;AACF,QAAO,EAAE,YAAY,WAAW;;AAGlC,eAAsB,2BAIpB;CACA,MAAM,UAAU,SAAS,MAAM,KAAK;AACpC,KAAI,CAAC,QAAS,QAAO,EAAE,YAAY,qBAAqB;AACxD,QAAO;EACL,YAAY;EACZ,UAAU,QAAQ;EAClB,iBAAiB,QAAQ;EAC1B;;AAGH,eAAsB,4BAA2C;AAC/D,SAAQ,IAAI,kEAAkE;;AAQhF,SAAgB,cAAc,QAIf;AACb,kBAAiB;AACf,SAAO,QAAQ;GACb,MAAM;GACN,MAAM;IACJ,aAAa;IACb,kBAAkB;IACnB;GACF,CAAC;IACD,IAAI;AACP,cAAa;;;;;;;AC/Df,IAAI,eAAe;AAEnB,SAAS,kBAA0B;AACjC,QAAO,cAAc,EAAE,aAAa,GAAG,KAAK,KAAK;;AAoCnD,SAAS,iBAAiB,KAA6B;CACrD,MAAM,UAAU,SAAS,MAAM,IAAI,SAAS,MAAM,MAAM,EAAE,QAAQ,IAAI;CACtE,MAAM,YAAY,SAAS,eAAe,QAAQ,WAAW,GAAG,IAAI;AACpE,QAAO;EACL,SAAS,iBAAiB;EAC1B,aAAa,SAAS,eAAe;EACrC,eAAe,SAAS,iBAAiB;EACzC,QAAQ,SAAS,WAAW,GAAG,IAAI;EACnC,UAAU;EACV,UAAU;EACV,gBAAgB,SAAS,WAAW;EACrC;;AAGH,eAAe,eACb,KACA,qBAIA,SACA,SACe;CACf,MAAM,aAAa,SAAS,MAAM,IAAI;AAGtC,OAAM,IAAI,SAAS,MAAM,WAAW,GAAG,IAAI,CAAC;AAE5C,KAAI,eAAe,WAAW;AAC5B,UAAQ,EAAE,MAAM,YAAY,CAAC;AAC7B;;CAGF,MAAM,SAAS,iBAAiB,IAAI;AAEpC,KAAI;AAEF,MAAI,CADY,MAAM,oBAAoB,EAAE,SAAS,OAAO,SAAS,CAAC,EACxD;AACZ,WAAQ,EAAE,MAAM,kCAAkC,CAAC;AACnD;;UAEK,GAAG;AACV,UAAQ,EAAE;AACV;;AAIF,UAAS,MAAM,OAAO,EACpB,iBAAiB,CACf,GAAG,SAAS,MAAM,IAAI,iBACtB;EACE,SAAS,OAAO;EAChB;EACA,QAAQ;EACR,uBAAM,IAAI,MAAM,EAAC,aAAa;EAC/B,CACF,EACF,CAAC;AAEF,OAAM,QAAQ;EAAE,MAAM;EAAW,MAAM;EAAQ,CAAC;;AAGlD,MAAa,MAAM,gBAAgB,OAAO;CAExC,2BAA2B,QAA0D;AAEnF,iBADY,OAAO,QAAQ,OAAO,OAAO,QAAQ,aAAa,IAC1C,OAAO,QAAQ,qBAAqB,OAAO,SAAS,OAAO,QAAQ,CAAC,OACrF,MAAM,QAAQ,MAAM,4CAA4C,EAAE,CACpE;AACD,eAAa;;CAGf,gCAAgC,QAA4D;AAC1F,iBACE,OAAO,QAAQ,KACf,OAAO,QAAQ,qBACf,OAAO,SACP,OAAO,QACR,CAAC,OAAO,MAAM,QAAQ,MAAM,4CAA4C,EAAE,CAAC;AAC5E,eAAa;;CAGf,MAAM,qBAAuD;AAC3D,SAAO,EACL,UAAU,SAAS,MAAM,IAAI,SAAS,KAAK,OAAO;GAChD,GAAG;GACH,GAAI,EAAE,SAAS,iBAAiB,EAAE,cAAc,EAAE,gBAAgB,WAAW,GAAG,EAAE;GACnF,EAAE,EACJ;;CAGH,MAAM,mBAEH;AACD,SAAO,EAAE,QAAQ,CAAC,GAAG,SAAS,MAAM,IAAI,cAAc,EAAE;;CAG1D,MAAM,+BAIH;AACD,SAAO;GACL,SAAS;GACT,SAAS;GACT,QAAQ,CAAC,GAAG,SAAS,MAAM,IAAI,gBAAgB;GAChD;;CAGH,MAAM,qBAAqB,MAAyD;EAElF,MAAM,MAAM,SAAS,MAAM,IAAI,cAAc,WAC1C,MAAM,EAAE,YAAY,KAAK,OAAO,QAClC;AACD,MAAI,QAAQ,IAAI;GACd,MAAM,QAAQ,SAAS,MAAM,IAAI,cAAc;GAC/C,MAAM,gBAAgB,SAAS,MAAM,IAAI,cAAc,QAAQ,GAAG,MAAM,MAAM,IAAI;GAClF,MAAM,kBAAkB,CACtB,GAAG,SAAS,MAAM,IAAI,iBACtB;IACE,SAAS,MAAM;IACf,KAAK,MAAM;IACX,QAAQ;IACR,uBAAM,IAAI,MAAM,EAAC,aAAa;IAC/B,CACF;AACD,YAAS,MAAM,OAAO;IAAE;IAAe;IAAiB,CAAC;;AAE3D,SAAO;;CAGT,MAAM,oBAAoB,OAAwC;AAChE,SAAO,EACL,cAAc;GACZ,WAAW;GACX,QAAQ;GACR,WAAW,IAAI,KAAK,KAAK,KAAK,GAAG,MAAU,KAAK,KAAK,IAAK,CAAC,aAAa;GACxE,aAAa;GACb,sBAAsB;GACtB,cAAc;GACf,EACF;;CAEJ,CAAC;AAIF,eAAsB,gBAAgB,SAEa;CACjD,MAAM,EAAE,YAAY,eAAe,SAAS,MAAM;AAClD,SAAQ,IAAI,uCAAuC,QAAQ,OAAO,SAAS;AAE3E,OAAM,IAAI,SAAS,MAAM,WAAW,GAAG,IAAI,CAAC;AAE5C,KAAI,eAAe,UACjB,QAAO,EAAE,SAAS,MAAM;AAE1B,QAAO;EAAE,SAAS;EAAO,QAAQ,cAAc;EAAuB;;;;;;;ACtMxE,eAAsB,YAA2B;AAC/C,SAAQ,IAAI,sCAAsC;AAClD,QAAO,QAAQ,MAAM;;AAGvB,eAAsB,QAAQ,KAA4B;AACxD,SAAQ,IAAI,+BAA+B,IAAI;AAC/C,QAAO,KAAK,KAAK,SAAS;;AAG5B,eAAsB,MAAM,SAA6C;AACvE,KAAI,UAAU,OAAO;AACnB,QAAM,UAAU,MAAM,EAAE,MAAM,QAAQ,SAAS,CAAC;AAChD;;AAEF,SAAQ,IAAI,6BAA6B,QAAQ,QAAQ;;AAG3D,eAAsB,iBAAiB,MAAc,aAAuC;AAC1F,QAAO,6BAA6B;;AAGtC,eAAsB,0BAA0B,UAAiD;AAC/F,SAAQ,IAAI,iDAAiD,SAAS,UAAU;;AAGlF,eAAsB,qBAAqB,UAEzB;AAChB,SAAQ,IAAI,4CAA4C,SAAS,KAAK;;AAGxE,eAAsB,mBAAmB,SAEP;AAChC,SAAQ,IAAI,0CAA0C,QAAQ,QAAQ;AACtE,QAAO,EAAE,SAAS,QAAQ,SAAS;;AAGrC,eAAsB,gBAAgB,SAEJ;AAChC,SAAQ,IAAI,uCAAuC,QAAQ,QAAQ;AACnE,QAAO,EAAE,SAAS,QAAQ,SAAS;;AAGrC,eAAsB,gBAA+B;AACnD,SAAQ,IAAI,0CAA0C;;AAExD,cAA6D,oBAAoB;AAIjF,SAAgB,gBAAmC;AACjD,QAAO,SAAS,MAAM;;AAGxB,SAAgB,4BAAgD;AAC9D,QAAO,SAAS,MAAM;;AAGxB,SAAgB,oBAA4B;AAC1C,QAAO,SAAS,MAAM;;AAGxB,SAAgB,sBAAsB,aAAwD;CAE5F,MAAM,WADW,SAAS,MAAM,aACF,QAAQ,YAAY,MAAM,YAAY;AACpE,KAAI,aAAa,SAAU,QAAO;AAClC,KAAI,aAAa,QAAS,QAAO;CAEjC,MAAM,UAAU,SAAS,MAAM,WAAW,MAAM,IAAI,CAAC,IAAI,OAAO;CAChE,MAAM,MAAM,SAAS,MAAM,IAAI,CAAC,IAAI,OAAO;AAC3C,MAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,OAAK,QAAQ,MAAM,MAAM,IAAI,MAAM,GAAI,QAAO;AAC9C,OAAK,QAAQ,MAAM,MAAM,IAAI,MAAM,GAAI,QAAO;;AAEhD,QAAO;;AAGT,SAAgB,eAAuB;AACrC,QAAO,SAAS,MAAM,aAAa,OAAO,SAAS;;AAGrD,SAAgB,YAAoB;AAClC,QAAO,SAAS,MAAM;;AAGxB,SAAgB,cAAsB;AACpC,QAAO,SAAS,MAAM;;AAGxB,SAAgB,aAAqB;AACnC,QAAO,SAAS,MAAM;;AAGxB,eAAsB,mBAA2C;CAC/D,MAAM,aAAa,wBAAwB;AAC3C,KAAI,WAAY,QAAO;AACvB,QAAO,SAAS,MAAM;;AAGxB,eAAsB,gBAA6C;AACjE,QAAO,KAAK,KAAK;;AAEnB,cAA6D,oBAAoB;AASjF,MAAa,eAAe,EAC1B,iBACE,OACA,EACE,SACA,WAMU;CACZ,MAAM,gBAAgB;AACpB,MAAI;AACF,YAAS;WACF,GAAG;AACV,aAAU,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,EAAE,CAAC,CAAC;;;AAG5D,QAAO,iBAAiB,SAAS,SAAS,QAAQ;AAClD,cAAa,OAAO,oBAAoB,SAAS,SAAS,QAAQ;GAErE;AAED,MAAa,kBAAkB,EAC7B,iBACE,QACA,WAKY;AACZ,cAAa;GAEhB;AAUD,MAAa,WAAW,EACtB,iBACE,OACA,EACE,WAMU;CACZ,MAAM,WAAW,MAAa;EAC5B,MAAM,SAAU,EAAkB;AAClC,UAAQ,OAAO;;AAEjB,QAAO,iBAAiB,SAAS,SAAS,QAAQ;AAClD,cAAa,OAAO,oBAAoB,SAAS,SAAS,QAAQ;GAErE;AAED,SAAgB,2CAA2C,aAI5C;CACb,MAAM,gBAAgB,YAAY,QAAQ,CAAC,SAAS,OAAO;AAC3D,UAAS,iBAAiB,oBAAoB,QAAQ;AACtD,cAAa,SAAS,oBAAoB,oBAAoB,QAAQ;;AAKxE,MAAa,MAAM,EACjB,uBAAuB,SAAS,MAAM,cACvC;AAED,SAAgB,uBAAuB;AACrC,QAAO;EACL,cAAc,SAAS,MAAM;EAC7B,kBAAkB,SAAS,MAAM,MAAM;EACvC,WAAW,SAAS,MAAM,MAAM;EAChC,mBAAmB,SAAS,MAAM,MAAM;EACzC;;AAQH,MAAa,iBAAiB;CAC5B,YAAiC,EAAE,GAAG,SAAS,MAAM,gBAAgB;CAGrE,YAAY,EAAE,cAA4D;AACxE,SAAO,SAAS,gBAAgB,QAAQ,EAAE,GAAG,SAAS,MAAM,gBAAgB,CAAC,CAAC;;CAEjF;;AAGD,SAAgB,oBAA4B;AAC1C,QAAO,SAAS,MAAM,eAAe;;;;AC1NvC,MAAa,UAAU;CACrB,MAAM,mBAAmB,SAAmD;AAC1E,UAAQ,IAAI,kDAAkD,QAAQ;;CAExE,MAAM,wBAAuC;AAC3C,UAAQ,IAAI,mDAAmD;;CAElE"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/mock/proxy.ts","../../src/mock/state.ts","../../src/mock/ads/index.ts","../../src/mock/analytics/index.ts","../../src/mock/auth/index.ts","../../src/mock/device/_helpers.ts","../../src/mock/permissions.ts","../../src/mock/device/camera.ts","../../src/mock/device/clipboard.ts","../../src/mock/device/contacts.ts","../../src/mock/device/haptic.ts","../../src/mock/device/location.ts","../../src/mock/device/network.ts","../../src/mock/device/storage.ts","../../src/mock/game/index.ts","../../src/mock/iap/index.ts","../../src/mock/navigation/index.ts","../../src/mock/partner/index.ts"],"sourcesContent":["/**\n * 미구현 API용 Proxy 트립와이어.\n *\n * 미구현 프로퍼티에 접근하면 throw한다. 이는 \"devtools에서는 멀쩡히 돌지만\n * 실 SDK에선 실제로 동작하는\" 시나리오를 차단하기 위한 의도적 선택이다.\n * mock이 미구현인 API는 실 SDK에서는 존재할 수 있고, 사용자가 이를 인지하지\n * 못한 채 개발을 이어가면 배포 시점에 놀라게 된다. 에러 메시지에 이슈 URL을\n * 포함해 사용자가 mock 누락을 제보할 수 있게 한다.\n */\n\nconst ISSUES_URL = 'https://github.com/apps-in-toss-community/devtools/issues';\n\nexport function createMockProxy<T extends Record<string, unknown>>(\n moduleName: string,\n implementations: T,\n): T {\n return new Proxy(implementations, {\n get(target, prop) {\n // 심볼 접근(Symbol.toPrimitive, Symbol.iterator 등)은 프레임워크/런타임이\n // 내부적으로 호출하므로 throw하면 console.log, 구조분해 등이 깨진다.\n if (typeof prop === 'symbol') return undefined;\n if (prop in target) return target[prop];\n\n throw new Error(\n `[@ait-co/devtools] ${moduleName}.${prop} is not mocked. ` +\n `This API may exist in @apps-in-toss/web-framework, ` +\n `but devtools' mock does not cover it yet. ` +\n `Please file an issue: ${ISSUES_URL}`,\n );\n },\n }) as T;\n}\n","/**\n * @ait-co/devtools 중앙 상태 관리\n * DevTools Panel과 mock 구현체가 이 상태를 공유한다.\n */\n\nimport type {\n AnalyticsLogEntry,\n DeviceModes,\n IapNextResult,\n MockContact,\n MockData,\n MockIapProduct,\n MockLocation,\n NetworkStatus,\n OperationalEnvironment,\n PermissionName,\n PermissionStatus,\n PlatformOS,\n SafeAreaInsets,\n} from './types.js';\n\nexport type {\n AnalyticsLogEntry,\n DeviceApiMode,\n DeviceModes,\n HapticFeedbackType,\n IapNextResult,\n LocationCoords,\n MockContact,\n MockData,\n MockIapProduct,\n MockLocation,\n NetworkStatus,\n OperationalEnvironment,\n PermissionName,\n PermissionStatus,\n PlatformOS,\n SafeAreaInsets,\n} from './types.js';\n\ntype Listener = () => void;\n\nexport interface AitDevtoolsState {\n // 환경\n platform: PlatformOS;\n environment: OperationalEnvironment;\n appVersion: string;\n locale: string;\n schemeUri: string;\n groupId: string;\n deploymentId: string;\n deviceId: string;\n\n // 브랜드\n brand: {\n displayName: string;\n icon: string;\n primaryColor: string;\n };\n\n // 네트워크\n networkStatus: NetworkStatus;\n\n // 권한\n permissions: Record<PermissionName, PermissionStatus>;\n\n // 위치\n location: MockLocation;\n\n // Safe Area\n safeAreaInsets: SafeAreaInsets;\n\n // 연락처\n contacts: MockContact[];\n\n // IAP\n iap: {\n products: MockIapProduct[];\n nextResult: IapNextResult;\n pendingOrders: Array<{ orderId: string; sku: string; paymentCompletedDate: string }>;\n completedOrders: Array<{\n orderId: string;\n sku: string;\n status: 'COMPLETED' | 'REFUNDED';\n date: string;\n }>;\n };\n\n // 결제 (TossPay)\n payment: {\n nextResult: 'success' | 'fail';\n failReason: string;\n };\n\n // 로그인\n auth: {\n isLoggedIn: boolean;\n isTossLoginIntegrated: boolean;\n userKeyHash: string;\n };\n\n // 광고\n ads: {\n isLoaded: boolean;\n nextEvent:\n | 'loaded'\n | 'clicked'\n | 'dismissed'\n | 'failedToShow'\n | 'impression'\n | 'userEarnedReward';\n };\n\n // 게임\n game: {\n profile: { nickname: string; profileImageUri: string } | null;\n leaderboardScores: Array<{ score: string; timestamp: number }>;\n };\n\n // 분석 로그\n analyticsLog: AnalyticsLogEntry[];\n\n // 디바이스 API 모드\n deviceModes: DeviceModes;\n\n // mock 모드용 더미 데이터\n mockData: MockData;\n\n // mock 활성화 상태\n panelEditable: boolean;\n}\n\nconst DEFAULT_STATE: AitDevtoolsState = {\n platform: 'ios',\n environment: 'sandbox',\n appVersion: '5.240.0',\n locale: 'ko-KR',\n schemeUri: '/',\n groupId: 'mock-group-id',\n deploymentId: 'mock-deployment-id',\n deviceId: '',\n\n brand: {\n displayName: 'Mock App',\n icon: '',\n primaryColor: '#3182F6',\n },\n\n networkStatus: 'WIFI',\n\n permissions: {\n clipboard: 'allowed',\n contacts: 'allowed',\n photos: 'allowed',\n geolocation: 'allowed',\n camera: 'allowed',\n microphone: 'notDetermined',\n },\n\n location: {\n coords: {\n latitude: 37.5665,\n longitude: 126.978,\n altitude: 0,\n accuracy: 10,\n altitudeAccuracy: 0,\n heading: 0,\n },\n timestamp: Date.now(),\n accessLocation: 'FINE',\n },\n\n safeAreaInsets: { top: 47, bottom: 34, left: 0, right: 0 },\n\n contacts: [\n { name: '홍길동', phoneNumber: '010-1234-5678' },\n { name: '김토스', phoneNumber: '010-9876-5432' },\n ],\n\n iap: {\n products: [\n {\n sku: 'mock-gem-100',\n type: 'CONSUMABLE',\n displayName: '보석 100개',\n displayAmount: '1,000원',\n iconUrl: '',\n description: '게임에서 사용할 수 있는 보석 100개',\n },\n ],\n nextResult: 'success',\n pendingOrders: [],\n completedOrders: [],\n },\n\n payment: {\n nextResult: 'success',\n failReason: '',\n },\n\n auth: {\n isLoggedIn: true,\n isTossLoginIntegrated: true,\n userKeyHash: 'mock-user-hash-abc123',\n },\n\n ads: {\n isLoaded: false,\n nextEvent: 'loaded',\n },\n\n game: {\n profile: { nickname: 'MockPlayer', profileImageUri: '' },\n leaderboardScores: [],\n },\n\n analyticsLog: [],\n\n deviceModes: {\n camera: 'mock',\n photos: 'mock',\n location: 'mock',\n network: 'mock',\n // 'mock' so the clipboard mock is self-contained. With 'web' the mock\n // calls `navigator.clipboard.readText()` directly, which — when paired\n // with `@ait-co/polyfill` — recurses: polyfill routes `navigator.clipboard`\n // back to the SDK's `getClipboardText`, which is this mock, which calls\n // `navigator.clipboard.readText`, … Users who want true browser\n // clipboard integration can flip this to 'web' from the panel.\n clipboard: 'mock',\n },\n\n mockData: {\n images: [],\n clipboardText: '',\n },\n\n panelEditable: true,\n};\n\nfunction generateDeviceId(): string {\n const stored = localStorage.getItem('__ait_device_id');\n if (stored) return stored;\n const id = crypto.randomUUID();\n localStorage.setItem('__ait_device_id', id);\n return id;\n}\n\nexport class AitStateManager {\n private _state: AitDevtoolsState;\n private _listeners = new Set<Listener>();\n\n constructor() {\n this._state = structuredClone(DEFAULT_STATE);\n try {\n this._state.deviceId = generateDeviceId();\n } catch {\n this._state.deviceId = `mock-device-${Math.random().toString(36).slice(2)}`;\n }\n }\n\n get state(): AitDevtoolsState {\n return this._state;\n }\n\n update(partial: Partial<AitDevtoolsState>) {\n this._state = { ...this._state, ...partial };\n this._notify();\n }\n\n /** 중첩 객체 업데이트용 */\n patch<K extends keyof AitDevtoolsState>(key: K, partial: Partial<AitDevtoolsState[K]>) {\n const current = this._state[key];\n if (typeof current === 'object' && current !== null && !Array.isArray(current)) {\n this._state = {\n ...this._state,\n [key]: { ...(current as Record<string, unknown>), ...(partial as Record<string, unknown>) },\n };\n } else {\n this._state = { ...this._state, [key]: partial as AitDevtoolsState[K] };\n }\n this._notify();\n }\n\n subscribe(listener: Listener): () => void {\n this._listeners.add(listener);\n return () => this._listeners.delete(listener);\n }\n\n /** 분석 로그 추가 */\n logAnalytics(entry: Omit<AnalyticsLogEntry, 'timestamp'>) {\n this._state = {\n ...this._state,\n analyticsLog: [...this._state.analyticsLog, { ...entry, timestamp: Date.now() }],\n };\n this._notify();\n }\n\n /** 이벤트 트리거 (backEvent, homeEvent 등) */\n trigger(event: string) {\n window.dispatchEvent(new CustomEvent(`__ait:${event}`));\n }\n\n reset() {\n const deviceId = this._state.deviceId;\n this._state = { ...structuredClone(DEFAULT_STATE), deviceId };\n this._notify();\n }\n\n private _notify() {\n for (const listener of this._listeners) {\n listener();\n }\n }\n}\n\nexport const aitState = new AitStateManager();\n\n// 브라우저 콘솔에서 접근 가능하도록\nif (typeof window !== 'undefined') {\n window.__ait = aitState;\n}\n","/**\n * 광고 mock (GoogleAdMob, TossAds, FullScreenAd)\n */\n\nimport { createMockProxy } from '../proxy.js';\nimport { aitState } from '../state.js';\n\nfunction withIsSupported<T extends (...args: never[]) => unknown>(\n fn: T,\n): T & { isSupported: () => boolean } {\n (fn as T & { isSupported: () => boolean }).isSupported = () => true;\n return fn as T & { isSupported: () => boolean };\n}\n\n// --- Google AdMob ---\n\nexport const GoogleAdMob = createMockProxy('GoogleAdMob', {\n loadAppsInTossAdMob: withIsSupported(\n (args: {\n onEvent: (data: { type: string; data?: unknown }) => void;\n onError: (error: Error) => void;\n options?: { adGroupId?: string };\n }): (() => void) => {\n setTimeout(() => {\n aitState.patch('ads', { isLoaded: true });\n args.onEvent({ type: 'loaded', data: { adGroupId: args.options?.adGroupId } });\n }, 200);\n return () => {};\n },\n ),\n\n showAppsInTossAdMob: withIsSupported(\n (args: {\n onEvent: (data: { type: string; data?: unknown }) => void;\n onError: (error: Error) => void;\n options?: { adGroupId?: string };\n }): (() => void) => {\n if (!aitState.state.ads.isLoaded) {\n args.onError(new Error('Ad not loaded'));\n return () => {};\n }\n setTimeout(() => args.onEvent({ type: 'requested' }), 50);\n setTimeout(() => args.onEvent({ type: 'show' }), 100);\n setTimeout(() => args.onEvent({ type: 'impression' }), 150);\n setTimeout(() => {\n args.onEvent({ type: 'userEarnedReward', data: { unitType: 'coins', unitAmount: 10 } });\n }, 1000);\n setTimeout(() => {\n args.onEvent({ type: 'dismissed' });\n aitState.patch('ads', { isLoaded: false });\n }, 1500);\n return () => {};\n },\n ),\n\n isAppsInTossAdMobLoaded: withIsSupported(\n async (_options: { adGroupId?: string }): Promise<boolean> => aitState.state.ads.isLoaded,\n ),\n});\n\n// --- TossAds ---\n\nexport const TossAds = createMockProxy('TossAds', {\n initialize: withIsSupported((_options: unknown) => {\n console.log('[@ait-co/devtools] TossAds.initialize (mock)');\n }),\n attach: withIsSupported(\n (_adGroupId: string, target: string | HTMLElement, _options?: unknown) => {\n const el = typeof target === 'string' ? document.querySelector(target) : target;\n if (el) {\n const placeholder = document.createElement('div');\n placeholder.style.cssText =\n 'background:#f0f0f0;border:1px dashed #999;padding:16px;text-align:center;color:#666;font-size:14px;';\n placeholder.textContent = '[@ait-co/devtools] TossAds Placeholder';\n el.appendChild(placeholder);\n }\n },\n ),\n attachBanner: withIsSupported(\n (_adGroupId: string, target: string | HTMLElement, _options?: unknown) => {\n const el = typeof target === 'string' ? document.querySelector(target) : target;\n if (el) {\n const placeholder = document.createElement('div');\n placeholder.style.cssText =\n 'background:#f0f0f0;border:1px dashed #999;padding:12px;text-align:center;color:#666;font-size:12px;';\n placeholder.textContent = '[@ait-co/devtools] Banner Ad Placeholder';\n el.appendChild(placeholder);\n }\n return { destroy: () => {} };\n },\n ),\n destroy: withIsSupported((_slotId: string) => {}),\n destroyAll: withIsSupported(() => {}),\n});\n\n// --- FullScreen Ad ---\n\nexport const loadFullScreenAd = withIsSupported(\n (args: {\n onEvent: (data: { type: string; data?: unknown }) => void;\n onError: (error: Error) => void;\n options?: { adGroupId?: string };\n }): (() => void) => {\n setTimeout(() => {\n aitState.patch('ads', { isLoaded: true });\n args.onEvent({ type: 'loaded', data: { adGroupId: args.options?.adGroupId } });\n }, 200);\n return () => {};\n },\n);\n\nexport const showFullScreenAd = withIsSupported(\n (args: {\n onEvent: (data: { type: string; data?: unknown }) => void;\n onError: (error: Error) => void;\n options?: { adGroupId?: string };\n }): (() => void) => {\n if (!aitState.state.ads.isLoaded) {\n args.onError(new Error('Ad not loaded'));\n return () => {};\n }\n setTimeout(() => args.onEvent({ type: 'show' }), 100);\n setTimeout(() => args.onEvent({ type: 'dismissed' }), 1500);\n return () => {};\n },\n);\n","/**\n * Analytics mock\n */\n\nimport { aitState } from '../state.js';\n\ntype Primitive = string | number | boolean | null | undefined | symbol;\ntype LoggerParams = { log_name?: string } & Record<string, Primitive>;\n\n// Analytics methods return `Promise<void> | undefined` to match the original SDK signature,\n// so they cannot use `async` (which always returns a Promise).\nexport const Analytics = {\n screen: (params?: LoggerParams): Promise<void> | undefined => {\n aitState.logAnalytics({ type: 'screen', params: params ?? {} });\n return Promise.resolve();\n },\n impression: (params?: LoggerParams): Promise<void> | undefined => {\n aitState.logAnalytics({ type: 'impression', params: params ?? {} });\n return Promise.resolve();\n },\n click: (params?: LoggerParams): Promise<void> | undefined => {\n aitState.logAnalytics({ type: 'click', params: params ?? {} });\n return Promise.resolve();\n },\n};\n\nexport async function eventLog(params: {\n log_name: string;\n log_type: 'debug' | 'info' | 'warn' | 'error' | 'event' | 'screen' | 'impression' | 'click';\n params: Record<string, Primitive>;\n}): Promise<void> {\n aitState.logAnalytics({\n type: params.log_type,\n params: { log_name: params.log_name, ...params.params },\n });\n}\n","/**\n * 인증/로그인 mock\n */\n\nimport { aitState } from '../state.js';\n\nexport async function appLogin(): Promise<{\n authorizationCode: string;\n referrer: 'DEFAULT' | 'SANDBOX';\n}> {\n return {\n authorizationCode: `mock-auth-${crypto.randomUUID()}`,\n referrer: aitState.state.environment === 'toss' ? 'DEFAULT' : 'SANDBOX',\n };\n}\n\nexport async function getIsTossLoginIntegratedService(): Promise<boolean | undefined> {\n return aitState.state.auth.isTossLoginIntegrated;\n}\n\nexport async function getUserKeyForGame(): Promise<\n { hash: string; type: 'HASH' } | 'INVALID_CATEGORY' | 'ERROR' | undefined\n> {\n if (!aitState.state.auth.userKeyHash) return undefined;\n return { hash: aitState.state.auth.userKeyHash, type: 'HASH' };\n}\n\nexport interface AppsInTossSignTossCertParams {\n txId: string;\n}\n\nexport async function appsInTossSignTossCert(_params: AppsInTossSignTossCertParams): Promise<void> {\n console.log('[@ait-co/devtools] appsInTossSignTossCert called (no-op in mock)');\n}\n","/**\n * 디바이스 모듈 내부 공유 헬퍼\n */\n\nimport { aitState } from '../state.js';\n\n// --- Placeholder Image Generator ---\n\nfunction generatePlaceholderImage(\n width: number,\n height: number,\n text: string,\n color: string,\n): string {\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n // jsdom 등 Canvas API 미지원 환경에서는 간단한 SVG data URI 반환\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\"><rect fill=\"${color}\" width=\"${width}\" height=\"${height}\"/><text x=\"50%\" y=\"50%\" fill=\"white\" font-size=\"16\" text-anchor=\"middle\" dominant-baseline=\"middle\">${text}</text></svg>`;\n return `data:image/svg+xml;base64,${btoa(svg)}`;\n }\n ctx.fillStyle = color;\n ctx.fillRect(0, 0, width, height);\n ctx.fillStyle = 'white';\n ctx.font = '16px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, width / 2, height / 2);\n return canvas.toDataURL('image/png');\n}\n\nconst DEFAULT_PLACEHOLDERS = [\n { text: 'Mock Photo 1', color: '#3182F6' },\n { text: 'Mock Photo 2', color: '#27ae60' },\n { text: 'Mock Photo 3', color: '#e67e22' },\n];\n\nlet cachedPlaceholders: string[] | null = null;\n\nexport function getDefaultPlaceholderImages(): string[] {\n if (!cachedPlaceholders) {\n cachedPlaceholders = DEFAULT_PLACEHOLDERS.map((p) =>\n generatePlaceholderImage(320, 240, p.text, p.color),\n );\n }\n return [...cachedPlaceholders];\n}\n\n/** @internal device 모듈 내부 전용 */\nexport function getMockImages(): string[] {\n const images = aitState.state.mockData.images;\n if (images.length > 0) return images;\n return getDefaultPlaceholderImages();\n}\n\n// --- Prompt Mode Helper ---\n\nconst PROMPT_TIMEOUT_MS = 30_000;\n\n/** @internal device 모듈 내부 전용 */\nexport function waitForPromptResponse<T>(type: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const eventName = `__ait:prompt-response:${type}`;\n const cancelName = '__ait:prompt-cancel';\n\n function cleanup() {\n clearTimeout(timer);\n window.removeEventListener(eventName, handler);\n window.removeEventListener(cancelName, cancelHandler);\n }\n\n const timer = setTimeout(() => {\n cleanup();\n const panelMounted = !!document.querySelector('.ait-panel');\n const hint = panelMounted\n ? 'Please provide input via the DevTools panel.'\n : 'Is @ait-co/devtools/panel imported?';\n reject(\n new Error(\n `[@ait-co/devtools] Prompt timeout for \"${type}\" after ${PROMPT_TIMEOUT_MS / 1000}s. ${hint}`,\n ),\n );\n }, PROMPT_TIMEOUT_MS);\n\n const handler = (e: Event) => {\n cleanup();\n resolve((e as CustomEvent).detail as T);\n };\n\n const cancelHandler = () => {\n cleanup();\n reject(new Error(`[@ait-co/devtools] Prompt cancelled for \"${type}\"`));\n };\n\n window.addEventListener(eventName, handler);\n window.addEventListener(cancelName, cancelHandler);\n window.dispatchEvent(new CustomEvent('__ait:prompt-request', { detail: { type } }));\n });\n}\n","/**\n * 권한 시스템 mock\n * 각 디바이스 API (.getPermission, .openPermissionDialog)에 부착된다.\n */\n\nimport { aitState } from './state.js';\nimport type { PermissionName, PermissionStatus } from './types.js';\n\nexport async function getPermission(name: PermissionName): Promise<PermissionStatus> {\n return aitState.state.permissions[name];\n}\n\nexport async function openPermissionDialog(name: PermissionName): Promise<'allowed' | 'denied'> {\n const current = aitState.state.permissions[name];\n if (current === 'allowed') return 'allowed';\n // notDetermined나 denied일 때 — Panel에서 설정된 값을 사용\n // 기본적으로는 allowed로 전환\n aitState.patch('permissions', { [name]: 'allowed' });\n return 'allowed';\n}\n\nexport async function requestPermission(permission: {\n name: PermissionName;\n access: string;\n}): Promise<'allowed' | 'denied'> {\n return openPermissionDialog(permission.name);\n}\n\n/** 권한이 필요한 함수에 .getPermission(), .openPermissionDialog()를 부착 */\nexport function withPermission<T extends (...args: never[]) => unknown>(\n fn: T,\n permissionName: PermissionName,\n): T & {\n getPermission: () => Promise<PermissionStatus>;\n openPermissionDialog: () => Promise<'allowed' | 'denied'>;\n} {\n const enhanced = fn as T & {\n getPermission: () => Promise<PermissionStatus>;\n openPermissionDialog: () => Promise<'allowed' | 'denied'>;\n };\n enhanced.getPermission = () => getPermission(permissionName);\n enhanced.openPermissionDialog = () => openPermissionDialog(permissionName);\n return enhanced;\n}\n\n/** 권한 체크 후 denied면 에러 throw */\nexport function checkPermission(name: PermissionName, fnName: string): void {\n const status = aitState.state.permissions[name];\n if (status === 'denied') {\n throw new Error(\n `[@ait-co/devtools] ${fnName}: Permission \"${name}\" is denied. Change it in the DevTools panel.`,\n );\n }\n}\n","/**\n * Camera & Album Photos mock\n * mock/web/prompt 모드 지원\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\nimport { getMockImages, waitForPromptResponse } from './_helpers.js';\n\n// --- Camera ---\n\nasync function openCameraMock(): Promise<{ id: string; dataUri: string }> {\n const images = getMockImages();\n return { id: crypto.randomUUID(), dataUri: images[0] };\n}\n\nasync function openCameraWeb(): Promise<{ id: string; dataUri: string }> {\n return new Promise((resolve, reject) => {\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = 'image/*';\n input.capture = 'environment';\n let settled = false;\n input.onchange = () => {\n settled = true;\n const file = input.files?.[0];\n if (!file) {\n reject(new Error('No file selected'));\n return;\n }\n const reader = new FileReader();\n reader.onload = () => resolve({ id: crypto.randomUUID(), dataUri: reader.result as string });\n reader.onerror = () => reject(new Error('Failed to read file'));\n reader.readAsDataURL(file);\n };\n // Detect file picker cancel via focus heuristic.\n // Note: unreliable on some mobile browsers and Safari where focus events differ.\n const onFocus = () => {\n setTimeout(() => {\n if (!settled) reject(new Error('File picker cancelled'));\n window.removeEventListener('focus', onFocus);\n }, 300);\n };\n window.addEventListener('focus', onFocus);\n input.click();\n });\n}\n\nasync function openCameraPrompt(): Promise<{ id: string; dataUri: string }> {\n const dataUri = await waitForPromptResponse<string>('camera');\n return { id: crypto.randomUUID(), dataUri };\n}\n\nconst _openCamera = async (_options?: {\n base64?: boolean;\n maxWidth?: number;\n}): Promise<{ id: string; dataUri: string }> => {\n checkPermission('camera', 'openCamera');\n const mode = aitState.state.deviceModes.camera;\n if (mode === 'web') return openCameraWeb();\n if (mode === 'prompt') return openCameraPrompt();\n return openCameraMock();\n};\nexport const openCamera = withPermission(_openCamera, 'camera');\n\n// --- Album Photos ---\n\nasync function fetchAlbumPhotosMock(\n maxCount: number,\n): Promise<Array<{ id: string; dataUri: string }>> {\n const images = getMockImages();\n return images.slice(0, maxCount).map((dataUri) => ({ id: crypto.randomUUID(), dataUri }));\n}\n\nasync function fetchAlbumPhotosWeb(\n maxCount: number,\n): Promise<Array<{ id: string; dataUri: string }>> {\n return new Promise((resolve, reject) => {\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = 'image/*';\n input.multiple = true;\n let settled = false;\n input.onchange = async () => {\n settled = true;\n const files = Array.from(input.files ?? []).slice(0, maxCount);\n if (files.length === 0) {\n reject(new Error('No files selected'));\n return;\n }\n const results = await Promise.all(\n files.map(\n (file) =>\n new Promise<{ id: string; dataUri: string }>((res, rej) => {\n const reader = new FileReader();\n reader.onload = () =>\n res({ id: crypto.randomUUID(), dataUri: reader.result as string });\n reader.onerror = () => rej(new Error('Failed to read file'));\n reader.readAsDataURL(file);\n }),\n ),\n );\n resolve(results);\n };\n const onFocus = () => {\n setTimeout(() => {\n if (!settled) reject(new Error('File picker cancelled'));\n window.removeEventListener('focus', onFocus);\n }, 300);\n };\n window.addEventListener('focus', onFocus);\n input.click();\n });\n}\n\nasync function fetchAlbumPhotosPrompt(\n maxCount: number,\n): Promise<Array<{ id: string; dataUri: string }>> {\n const dataUris = await waitForPromptResponse<string[]>('photos');\n return dataUris.slice(0, maxCount).map((dataUri) => ({ id: crypto.randomUUID(), dataUri }));\n}\n\nconst _fetchAlbumPhotos = async (options?: {\n maxCount?: number;\n maxWidth?: number;\n base64?: boolean;\n}): Promise<Array<{ id: string; dataUri: string }>> => {\n checkPermission('photos', 'fetchAlbumPhotos');\n const maxCount = options?.maxCount ?? 10;\n const mode = aitState.state.deviceModes.photos;\n if (mode === 'web') return fetchAlbumPhotosWeb(maxCount);\n if (mode === 'prompt') return fetchAlbumPhotosPrompt(maxCount);\n return fetchAlbumPhotosMock(maxCount);\n};\nexport const fetchAlbumPhotos = withPermission(_fetchAlbumPhotos, 'photos');\n","/**\n * Clipboard mock\n * mock/web 모드 지원\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\n\nconst _getClipboardText = async (): Promise<string> => {\n checkPermission('clipboard', 'getClipboardText');\n const mode = aitState.state.deviceModes.clipboard;\n if (mode === 'mock') return aitState.state.mockData.clipboardText;\n // web mode (default)\n try {\n return await navigator.clipboard.readText();\n } catch {\n return '';\n }\n};\nexport const getClipboardText = withPermission(_getClipboardText, 'clipboard');\n\nconst _setClipboardText = async (text: string): Promise<void> => {\n checkPermission('clipboard', 'setClipboardText');\n const mode = aitState.state.deviceModes.clipboard;\n if (mode === 'mock') {\n aitState.patch('mockData', { clipboardText: text });\n return;\n }\n // web mode (default)\n await navigator.clipboard.writeText(text);\n};\nexport const setClipboardText = withPermission(_setClipboardText, 'clipboard');\n","/**\n * Contacts mock\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\n\nconst _fetchContacts = async (options: {\n size: number;\n offset: number;\n query?: { contains?: string };\n}) => {\n checkPermission('contacts', 'fetchContacts');\n let contacts = aitState.state.contacts;\n if (options.query?.contains) {\n const q = options.query.contains.toLowerCase();\n contacts = contacts.filter(\n (c) => c.name.toLowerCase().includes(q) || c.phoneNumber.includes(q),\n );\n }\n const sliced = contacts.slice(options.offset, options.offset + options.size);\n const nextOffset = options.offset + options.size;\n return {\n result: sliced,\n nextOffset: nextOffset < contacts.length ? nextOffset : null,\n done: nextOffset >= contacts.length,\n };\n};\nexport const fetchContacts = withPermission(_fetchContacts, 'contacts');\n","/**\n * Haptic Feedback & saveBase64Data mock\n */\n\nimport { aitState } from '../state.js';\n\nexport async function generateHapticFeedback(options: { type: string }): Promise<void> {\n console.log(`[@ait-co/devtools] haptic: ${options.type}`);\n aitState.logAnalytics({ type: 'haptic', params: { hapticType: options.type } });\n}\n\nexport async function saveBase64Data(params: {\n data: string;\n fileName: string;\n mimeType: string;\n}): Promise<void> {\n const a = document.createElement('a');\n a.href = `data:${params.mimeType};base64,${params.data}`;\n a.download = params.fileName;\n a.click();\n}\n","/**\n * Location mock (getCurrentLocation, startUpdateLocation)\n * mock/web/prompt 모드 지원\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\nimport type { MockLocation } from '../types.js';\nimport { waitForPromptResponse } from './_helpers.js';\n\nenum Accuracy {\n Lowest = 1,\n Low = 2,\n Balanced = 3,\n High = 4,\n Highest = 5,\n BestForNavigation = 6,\n}\n\nexport { Accuracy };\n\nfunction buildLocation(): MockLocation {\n return {\n coords: { ...aitState.state.location.coords },\n timestamp: Date.now(),\n accessLocation: aitState.state.location.accessLocation,\n };\n}\n\n// -- getCurrentLocation --\n\nasync function getCurrentLocationMock(): Promise<MockLocation> {\n return buildLocation();\n}\n\nasync function getCurrentLocationWeb(): Promise<MockLocation> {\n return new Promise((resolve) => {\n if (!navigator.geolocation) {\n console.warn('[@ait-co/devtools] Geolocation API not available, falling back to mock');\n resolve(buildLocation());\n return;\n }\n navigator.geolocation.getCurrentPosition(\n (pos) => {\n resolve({\n coords: {\n latitude: pos.coords.latitude,\n longitude: pos.coords.longitude,\n altitude: pos.coords.altitude ?? 0,\n accuracy: pos.coords.accuracy,\n altitudeAccuracy: pos.coords.altitudeAccuracy ?? 0,\n heading: pos.coords.heading ?? 0,\n },\n timestamp: pos.timestamp,\n accessLocation: 'FINE',\n });\n },\n () => {\n console.warn('[@ait-co/devtools] Geolocation failed, falling back to mock');\n resolve(buildLocation());\n },\n );\n });\n}\n\nasync function getCurrentLocationPrompt(): Promise<MockLocation> {\n return waitForPromptResponse<MockLocation>('location');\n}\n\nconst _getCurrentLocation = async (_options?: { accuracy: Accuracy }): Promise<MockLocation> => {\n checkPermission('geolocation', 'getCurrentLocation');\n const mode = aitState.state.deviceModes.location;\n if (mode === 'web') return getCurrentLocationWeb();\n if (mode === 'prompt') return getCurrentLocationPrompt();\n return getCurrentLocationMock();\n};\nexport const getCurrentLocation = withPermission(_getCurrentLocation, 'geolocation');\n\n// -- startUpdateLocation --\n\ninterface StartUpdateLocationEventParams {\n onEvent: (response: MockLocation) => void;\n onError: (error: unknown) => void;\n options: { accuracy: Accuracy; timeInterval: number; distanceInterval: number };\n}\n\nfunction startUpdateLocationMock(eventParams: StartUpdateLocationEventParams): () => void {\n const { onEvent, options } = eventParams;\n const interval = Math.max(options.timeInterval, 500);\n const id = setInterval(() => {\n const loc = buildLocation();\n loc.coords.latitude += (Math.random() - 0.5) * 0.0001;\n loc.coords.longitude += (Math.random() - 0.5) * 0.0001;\n onEvent(loc);\n }, interval);\n return () => clearInterval(id);\n}\n\nfunction startUpdateLocationWeb(eventParams: StartUpdateLocationEventParams): () => void {\n const { onEvent, onError } = eventParams;\n if (!navigator.geolocation) {\n console.warn('[@ait-co/devtools] Geolocation API not available, falling back to mock');\n return startUpdateLocationMock(eventParams);\n }\n const watchId = navigator.geolocation.watchPosition(\n (pos) => {\n onEvent({\n coords: {\n latitude: pos.coords.latitude,\n longitude: pos.coords.longitude,\n altitude: pos.coords.altitude ?? 0,\n accuracy: pos.coords.accuracy,\n altitudeAccuracy: pos.coords.altitudeAccuracy ?? 0,\n heading: pos.coords.heading ?? 0,\n },\n timestamp: pos.timestamp,\n accessLocation: 'FINE',\n });\n },\n (err) => onError(err),\n );\n return () => navigator.geolocation.clearWatch(watchId);\n}\n\nfunction startUpdateLocationPrompt(eventParams: StartUpdateLocationEventParams): () => void {\n const { onEvent } = eventParams;\n const handler = (e: Event) => {\n onEvent((e as CustomEvent).detail as MockLocation);\n };\n window.addEventListener('__ait:prompt-response:location-update', handler);\n window.dispatchEvent(\n new CustomEvent('__ait:prompt-request', { detail: { type: 'location-update' } }),\n );\n return () => window.removeEventListener('__ait:prompt-response:location-update', handler);\n}\n\nconst _startUpdateLocation = (eventParams: StartUpdateLocationEventParams): (() => void) => {\n const mode = aitState.state.deviceModes.location;\n if (mode === 'web') return startUpdateLocationWeb(eventParams);\n if (mode === 'prompt') return startUpdateLocationPrompt(eventParams);\n return startUpdateLocationMock(eventParams);\n};\nexport const startUpdateLocation = withPermission(_startUpdateLocation, 'geolocation');\n","/**\n * Network Status mock (mode-aware helper)\n * navigation 모듈에서 사용. circular dep 방지를 위해 device에 위치.\n */\n\nimport { aitState } from '../state.js';\nimport type { NetworkStatus } from '../types.js';\n\n/**\n * Web mode: uses navigator.connection.effectiveType (4g/3g/2g) and navigator.onLine.\n * Limitations: WIFI, 5G, WWAN cannot be detected via the Network Information API.\n * Falls back to state-based value when effectiveType is unavailable.\n */\nexport function getNetworkStatusByMode(): NetworkStatus | null {\n const mode = aitState.state.deviceModes.network;\n if (mode === 'mock') return null; // use default state-based logic\n if (mode === 'web') {\n if (!navigator.onLine) return 'OFFLINE';\n const conn = (navigator as unknown as Record<string, unknown>).connection as\n | { effectiveType?: string }\n | undefined;\n if (conn?.effectiveType) {\n const mapping: Record<string, NetworkStatus> = {\n '4g': '4G',\n '3g': '3G',\n '2g': '2G',\n 'slow-2g': '2G',\n };\n return mapping[conn.effectiveType] ?? 'UNKNOWN';\n }\n return aitState.state.networkStatus;\n }\n // prompt mode: not supported for network, fall back to mock\n return null;\n}\n","/**\n * Storage mock\n * localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리\n */\n\nimport { createMockProxy } from '../proxy.js';\n\nexport const Storage = createMockProxy('Storage', {\n getItem: async (key: string): Promise<string | null> => {\n return localStorage.getItem(`__ait_storage:${key}`);\n },\n setItem: async (key: string, value: string): Promise<void> => {\n localStorage.setItem(`__ait_storage:${key}`, value);\n },\n removeItem: async (key: string): Promise<void> => {\n localStorage.removeItem(`__ait_storage:${key}`);\n },\n clearItems: async (): Promise<void> => {\n const keys = Object.keys(localStorage).filter((k) => k.startsWith('__ait_storage:'));\n for (const k of keys) {\n localStorage.removeItem(k);\n }\n },\n});\n","/**\n * 게임/프로모션 mock\n */\n\nimport { aitState } from '../state.js';\n\nexport async function grantPromotionReward(params: {\n params: { promotionCode: string; amount: number };\n}): Promise<{ key: string } | { errorCode: string; message: string } | 'ERROR' | undefined> {\n console.log('[@ait-co/devtools] grantPromotionReward:', params.params);\n return { key: `mock-reward-${Date.now()}` };\n}\n\nexport async function grantPromotionRewardForGame(params: {\n params: { promotionCode: string; amount: number };\n}): Promise<{ key: string } | { errorCode: string; message: string } | 'ERROR' | undefined> {\n console.log('[@ait-co/devtools] grantPromotionRewardForGame:', params.params);\n return { key: `mock-reward-${Date.now()}` };\n}\n\nexport async function submitGameCenterLeaderBoardScore(params: {\n score: string;\n}): Promise<\n | { statusCode: 'SUCCESS' | 'LEADERBOARD_NOT_FOUND' | 'PROFILE_NOT_FOUND' | 'UNPARSABLE_SCORE' }\n | undefined\n> {\n aitState.patch('game', {\n leaderboardScores: [\n ...aitState.state.game.leaderboardScores,\n { score: params.score, timestamp: Date.now() },\n ],\n });\n return { statusCode: 'SUCCESS' };\n}\n\nexport async function getGameCenterGameProfile(): Promise<\n | { statusCode: 'SUCCESS'; nickname: string; profileImageUri: string }\n | { statusCode: 'PROFILE_NOT_FOUND' }\n | undefined\n> {\n const profile = aitState.state.game.profile;\n if (!profile) return { statusCode: 'PROFILE_NOT_FOUND' };\n return {\n statusCode: 'SUCCESS',\n nickname: profile.nickname,\n profileImageUri: profile.profileImageUri,\n };\n}\n\nexport async function openGameCenterLeaderboard(): Promise<void> {\n console.log('[@ait-co/devtools] openGameCenterLeaderboard (no-op in browser)');\n}\n\ninterface ContactsViralEvent {\n type: string;\n data: Record<string, unknown>;\n}\n\nexport function contactsViral(params: {\n options: { moduleId: string };\n onEvent: (event: ContactsViralEvent) => void;\n onError: (error: unknown) => void;\n}): () => void {\n setTimeout(() => {\n params.onEvent({\n type: 'close',\n data: {\n closeReason: 'noReward',\n sentRewardsCount: 0,\n },\n });\n }, 500);\n return () => {};\n}\n","/**\n * IAP (인앱결제) mock\n */\n\nimport { createMockProxy } from '../proxy.js';\nimport { aitState } from '../state.js';\n\n// orderCounter는 모듈 레벨 상태로 reset()에 의해 초기화되지 않는다.\n// 테스트에서는 orderId를 stringContaining('mock-order-')로 검증하여 카운터 값에 의존하지 않는다.\nlet orderCounter = 0;\n\nfunction generateOrderId(): string {\n return `mock-order-${++orderCounter}-${Date.now()}`;\n}\n\ninterface IapCreateOneTimePurchaseOrderOptions {\n options: {\n sku?: string;\n productId?: string;\n processProductGrant: (params: { orderId: string }) => boolean | Promise<boolean>;\n };\n onEvent: (event: { type: 'success'; data: IapOrderResult }) => void | Promise<void>;\n onError: (error: unknown) => void | Promise<void>;\n}\n\ninterface CreateSubscriptionPurchaseOrderOptions {\n options: {\n sku: string;\n offerId?: string | null;\n processProductGrant: (params: {\n orderId: string;\n subscriptionId?: string;\n }) => boolean | Promise<boolean>;\n };\n onEvent: (event: { type: 'success'; data: IapOrderResult }) => void | Promise<void>;\n onError: (error: unknown) => void | Promise<void>;\n}\n\ninterface IapOrderResult {\n orderId: string;\n displayName: string;\n displayAmount: string;\n amount: number;\n currency: string;\n fraction: number;\n miniAppIconUrl: string | null;\n}\n\nfunction buildOrderResult(sku: string): IapOrderResult {\n const product = aitState.state.iap.products.find((p) => p.sku === sku);\n const amountStr = product?.displayAmount?.replace(/[^0-9]/g, '') ?? '1000';\n return {\n orderId: generateOrderId(),\n displayName: product?.displayName ?? 'Mock Product',\n displayAmount: product?.displayAmount ?? '1,000원',\n amount: parseInt(amountStr, 10) || 1000,\n currency: 'KRW',\n fraction: 0,\n miniAppIconUrl: product?.iconUrl || null,\n };\n}\n\nasync function handlePurchase(\n sku: string,\n processProductGrant: (params: {\n orderId: string;\n subscriptionId?: string;\n }) => boolean | Promise<boolean>,\n onEvent: (event: { type: 'success'; data: IapOrderResult }) => void | Promise<void>,\n onError: (error: unknown) => void | Promise<void>,\n): Promise<void> {\n const nextResult = aitState.state.iap.nextResult;\n\n // 비동기 시뮬레이션 (실제로는 결제 UI가 뜨는 시간)\n await new Promise((r) => setTimeout(r, 300));\n\n if (nextResult !== 'success') {\n onError({ code: nextResult });\n return;\n }\n\n const result = buildOrderResult(sku);\n\n try {\n const granted = await processProductGrant({ orderId: result.orderId });\n if (!granted) {\n onError({ code: 'PRODUCT_NOT_GRANTED_BY_PARTNER' });\n return;\n }\n } catch (e) {\n onError(e);\n return;\n }\n\n // 주문 완료 기록\n aitState.patch('iap', {\n completedOrders: [\n ...aitState.state.iap.completedOrders,\n {\n orderId: result.orderId,\n sku,\n status: 'COMPLETED' as const,\n date: new Date().toISOString(),\n },\n ],\n });\n\n await onEvent({ type: 'success', data: result });\n}\n\nexport const IAP = createMockProxy('IAP', {\n // 반환되는 cancel 함수는 mock에서는 no-op이다 (실제 SDK는 결제 UI를 닫음)\n createOneTimePurchaseOrder(params: IapCreateOneTimePurchaseOrderOptions): () => void {\n const sku = params.options.sku ?? params.options.productId ?? '';\n handlePurchase(sku, params.options.processProductGrant, params.onEvent, params.onError).catch(\n (e) => console.error('[@ait-co/devtools] IAP unexpected error:', e),\n );\n return () => {};\n },\n\n createSubscriptionPurchaseOrder(params: CreateSubscriptionPurchaseOrderOptions): () => void {\n handlePurchase(\n params.options.sku,\n params.options.processProductGrant,\n params.onEvent,\n params.onError,\n ).catch((e) => console.error('[@ait-co/devtools] IAP unexpected error:', e));\n return () => {};\n },\n\n async getProductItemList(): Promise<{ products: unknown[] }> {\n return {\n products: aitState.state.iap.products.map((p) => ({\n ...p,\n ...(p.type === 'SUBSCRIPTION' ? { renewalCycle: p.renewalCycle ?? 'MONTHLY' } : {}),\n })),\n };\n },\n\n async getPendingOrders(): Promise<{\n orders: Array<{ orderId: string; sku: string; paymentCompletedDate: string }>;\n }> {\n return { orders: [...aitState.state.iap.pendingOrders] };\n },\n\n async getCompletedOrRefundedOrders(): Promise<{\n hasNext: boolean;\n nextKey?: string | null;\n orders: Array<{ orderId: string; sku: string; status: 'COMPLETED' | 'REFUNDED'; date: string }>;\n }> {\n return {\n hasNext: false,\n nextKey: null,\n orders: [...aitState.state.iap.completedOrders],\n };\n },\n\n async completeProductGrant(args: { params: { orderId: string } }): Promise<boolean> {\n // pending → completed 전이\n const idx = aitState.state.iap.pendingOrders.findIndex(\n (o) => o.orderId === args.params.orderId,\n );\n if (idx !== -1) {\n const order = aitState.state.iap.pendingOrders[idx];\n const pendingOrders = aitState.state.iap.pendingOrders.filter((_, i) => i !== idx);\n const completedOrders = [\n ...aitState.state.iap.completedOrders,\n {\n orderId: order.orderId,\n sku: order.sku,\n status: 'COMPLETED' as const,\n date: new Date().toISOString(),\n },\n ];\n aitState.patch('iap', { pendingOrders, completedOrders });\n }\n return true;\n },\n\n async getSubscriptionInfo(_args: { params: { orderId: string } }) {\n return {\n subscription: {\n catalogId: 1,\n status: 'ACTIVE',\n expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),\n isAutoRenew: true,\n gracePeriodExpiresAt: null,\n isAccessible: true,\n },\n };\n },\n});\n\n// --- TossPay ---\n\nexport async function checkoutPayment(options: {\n params: { payToken: string };\n}): Promise<{ success: boolean; reason?: string }> {\n const { nextResult, failReason } = aitState.state.payment;\n console.log('[@ait-co/devtools] checkoutPayment:', options.params.payToken);\n\n await new Promise((r) => setTimeout(r, 300));\n\n if (nextResult === 'success') {\n return { success: true };\n }\n return { success: false, reason: failReason || 'Mock payment failed' };\n}\n","/**\n * 화면/네비게이션/이벤트 mock\n */\n\nimport { getNetworkStatusByMode } from '../device/index.js';\nimport { aitState } from '../state.js';\nimport type { NetworkStatus } from '../types.js';\n\nexport async function closeView(): Promise<void> {\n console.log('[@ait-co/devtools] closeView called');\n window.history.back();\n}\n\nexport async function openURL(url: string): Promise<void> {\n console.log('[@ait-co/devtools] openURL:', url);\n window.open(url, '_blank');\n}\n\nexport async function share(message: { message: string }): Promise<void> {\n if (navigator.share) {\n await navigator.share({ text: message.message });\n return;\n }\n console.log('[@ait-co/devtools] share:', message.message);\n}\n\nexport async function getTossShareLink(path: string, _ogImageUrl?: string): Promise<string> {\n return `https://toss.im/share/mock${path}`;\n}\n\nexport async function setIosSwipeGestureEnabled(_options: { isEnabled: boolean }): Promise<void> {\n console.log('[@ait-co/devtools] setIosSwipeGestureEnabled:', _options.isEnabled);\n}\n\nexport async function setDeviceOrientation(_options: {\n type: 'portrait' | 'landscape';\n}): Promise<void> {\n console.log('[@ait-co/devtools] setDeviceOrientation:', _options.type);\n}\n\nexport async function setScreenAwakeMode(options: {\n enabled: boolean;\n}): Promise<{ enabled: boolean }> {\n console.log('[@ait-co/devtools] setScreenAwakeMode:', options.enabled);\n return { enabled: options.enabled };\n}\n\nexport async function setSecureScreen(options: {\n enabled: boolean;\n}): Promise<{ enabled: boolean }> {\n console.log('[@ait-co/devtools] setSecureScreen:', options.enabled);\n return { enabled: options.enabled };\n}\n\nexport async function requestReview(): Promise<void> {\n console.log('[@ait-co/devtools] requestReview called');\n}\n(requestReview as unknown as { isSupported: () => boolean }).isSupported = () => true;\n\n// --- 환경 정보 ---\n\nexport function getPlatformOS(): 'ios' | 'android' {\n return aitState.state.platform;\n}\n\nexport function getOperationalEnvironment(): 'toss' | 'sandbox' {\n return aitState.state.environment;\n}\n\nexport function getTossAppVersion(): string {\n return aitState.state.appVersion;\n}\n\nexport function isMinVersionSupported(minVersions: { android: string; ios: string }): boolean {\n const platform = aitState.state.platform;\n const required = platform === 'ios' ? minVersions.ios : minVersions.android;\n if (required === 'always') return true;\n if (required === 'never') return false;\n\n const current = aitState.state.appVersion.split('.').map(Number);\n const min = required.split('.').map(Number);\n for (let i = 0; i < 3; i++) {\n if ((current[i] ?? 0) > (min[i] ?? 0)) return true;\n if ((current[i] ?? 0) < (min[i] ?? 0)) return false;\n }\n return true; // equal\n}\n\nexport function getSchemeUri(): string {\n return aitState.state.schemeUri || window.location.pathname;\n}\n\nexport function getLocale(): string {\n return aitState.state.locale;\n}\n\nexport function getDeviceId(): string {\n return aitState.state.deviceId;\n}\n\nexport function getGroupId(): string {\n return aitState.state.groupId;\n}\n\nexport async function getNetworkStatus(): Promise<NetworkStatus> {\n const modeResult = getNetworkStatusByMode();\n if (modeResult) return modeResult;\n return aitState.state.networkStatus;\n}\n\nexport async function getServerTime(): Promise<number | undefined> {\n return Date.now();\n}\n(getServerTime as unknown as { isSupported: () => boolean }).isSupported = () => true;\n\n// --- 이벤트 시스템 ---\n\ninterface GraniteEventMap {\n backEvent: { onEvent: () => void; onError?: (error: Error) => void; options?: undefined };\n homeEvent: { onEvent: () => void; onError?: (error: Error) => void; options?: undefined };\n}\n\nexport const graniteEvent = {\n addEventListener<K extends keyof GraniteEventMap>(\n event: K,\n {\n onEvent,\n onError,\n }: {\n onEvent: GraniteEventMap[K]['onEvent'];\n onError?: GraniteEventMap[K]['onError'];\n options?: GraniteEventMap[K]['options'];\n },\n ): () => void {\n const handler = () => {\n try {\n onEvent();\n } catch (e) {\n onError?.(e instanceof Error ? e : new Error(String(e)));\n }\n };\n window.addEventListener(`__ait:${event}`, handler);\n return () => window.removeEventListener(`__ait:${event}`, handler);\n },\n};\n\nexport const appsInTossEvent = {\n addEventListener<K extends string>(\n _event: K,\n _handlers: {\n onEvent: (...args: unknown[]) => void;\n onError?: (error: Error) => void;\n options?: unknown;\n },\n ): () => void {\n return () => {};\n },\n};\n\ninterface TdsEventMap {\n navigationAccessoryEvent: {\n onEvent: (data: { id: string }) => void;\n onError?: (error: Error) => void;\n options: undefined;\n };\n}\n\nexport const tdsEvent = {\n addEventListener<K extends keyof TdsEventMap>(\n event: K,\n {\n onEvent,\n }: {\n onEvent: TdsEventMap[K]['onEvent'];\n onError?: TdsEventMap[K]['onError'];\n options?: TdsEventMap[K]['options'];\n },\n ): () => void {\n const handler = (e: Event) => {\n const detail = (e as CustomEvent).detail;\n onEvent(detail);\n };\n window.addEventListener(`__ait:${event}`, handler);\n return () => window.removeEventListener(`__ait:${event}`, handler);\n },\n};\n\nexport function onVisibilityChangedByTransparentServiceWeb(eventParams: {\n options: { callbackId: string };\n onEvent: (isVisible: boolean) => void;\n onError: (error: unknown) => void;\n}): () => void {\n const handler = () => eventParams.onEvent(!document.hidden);\n document.addEventListener('visibilitychange', handler);\n return () => document.removeEventListener('visibilitychange', handler);\n}\n\n// --- env / globals ---\n\nexport const env = {\n getDeploymentId: () => aitState.state.deploymentId,\n};\n\nexport function getAppsInTossGlobals() {\n return {\n deploymentId: aitState.state.deploymentId,\n brandDisplayName: aitState.state.brand.displayName,\n brandIcon: aitState.state.brand.icon,\n brandPrimaryColor: aitState.state.brand.primaryColor,\n };\n}\n\n// --- SafeAreaInsets ---\n\ntype SafeAreaInsetsValue = { top: number; bottom: number; left: number; right: number };\ntype SafeAreaInsetsSubscribeHandler = { onEvent: (data: SafeAreaInsetsValue) => void };\n\nexport const SafeAreaInsets = {\n get: (): SafeAreaInsetsValue => ({ ...aitState.state.safeAreaInsets }),\n // NOTE: aitState.subscribe에 위임하므로 safeAreaInsets 외 상태 변경에도 콜백이 호출된다.\n // 실제 SDK는 insets 변경 시에만 호출되지만, mock에서는 간소화를 위해 필터링하지 않는다.\n subscribe: ({ onEvent }: SafeAreaInsetsSubscribeHandler): (() => void) => {\n return aitState.subscribe(() => onEvent({ ...aitState.state.safeAreaInsets }));\n },\n};\n\n/** @deprecated */\nexport function getSafeAreaInsets(): number {\n return aitState.state.safeAreaInsets.top;\n}\n","/**\n * Partner / TDS mock\n */\n\ninterface AddAccessoryButtonOptions {\n id: string;\n title: string;\n icon: { name: string };\n}\n\nexport const partner = {\n async addAccessoryButton(options: AddAccessoryButtonOptions): Promise<void> {\n console.log('[@ait-co/devtools] partner.addAccessoryButton:', options);\n },\n async removeAccessoryButton(): Promise<void> {\n console.log('[@ait-co/devtools] partner.removeAccessoryButton');\n },\n};\n"],"mappings":"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"}
@@ -86,7 +86,7 @@ const DEFAULT_STATE = {
86
86
  photos: "mock",
87
87
  location: "mock",
88
88
  network: "mock",
89
- clipboard: "web"
89
+ clipboard: "mock"
90
90
  },
91
91
  mockData: {
92
92
  images: [],
@@ -1564,7 +1564,7 @@ function mount() {
1564
1564
  mockBadge.textContent = aitState.state.panelEditable ? "EDIT" : "READ-ONLY";
1565
1565
  refreshPanel();
1566
1566
  });
1567
- const headerRight = h("span", { style: "display:flex;align-items:center;gap:6px" }, mockBadge, h("span", { style: "font-size:11px;color:#666;font-weight:400" }, `v0.1.1`), closeBtn);
1567
+ const headerRight = h("span", { style: "display:flex;align-items:center;gap:6px" }, mockBadge, h("span", { style: "font-size:11px;color:#666;font-weight:400" }, `v0.1.2`), closeBtn);
1568
1568
  const header = h("div", { className: "ait-panel-header" }, h("span", {}, "AIT DevTools"), headerRight);
1569
1569
  tabsEl = h("div", { className: "ait-panel-tabs" });
1570
1570
  for (const tab of TABS) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["refreshPanel"],"sources":["../../src/mock/state.ts","../../src/panel/helpers.ts","../../src/panel/styles.ts","../../src/mock/device/_helpers.ts","../../src/mock/permissions.ts","../../src/mock/device/camera.ts","../../src/mock/device/clipboard.ts","../../src/mock/device/contacts.ts","../../src/mock/device/location.ts","../../src/mock/proxy.ts","../../src/mock/device/storage.ts","../../src/panel/tabs/device.ts","../../src/panel/tabs/analytics.ts","../../src/panel/tabs/environment.ts","../../src/panel/tabs/events.ts","../../src/panel/tabs/iap.ts","../../src/panel/tabs/location.ts","../../src/panel/tabs/permissions.ts","../../src/panel/tabs/storage.ts","../../src/panel/tabs/index.ts","../../src/panel/index.ts"],"sourcesContent":["/**\n * @ait-co/devtools 중앙 상태 관리\n * DevTools Panel과 mock 구현체가 이 상태를 공유한다.\n */\n\nimport type {\n AnalyticsLogEntry,\n DeviceModes,\n IapNextResult,\n MockContact,\n MockData,\n MockIapProduct,\n MockLocation,\n NetworkStatus,\n OperationalEnvironment,\n PermissionName,\n PermissionStatus,\n PlatformOS,\n SafeAreaInsets,\n} from './types.js';\n\nexport type {\n AnalyticsLogEntry,\n DeviceApiMode,\n DeviceModes,\n HapticFeedbackType,\n IapNextResult,\n LocationCoords,\n MockContact,\n MockData,\n MockIapProduct,\n MockLocation,\n NetworkStatus,\n OperationalEnvironment,\n PermissionName,\n PermissionStatus,\n PlatformOS,\n SafeAreaInsets,\n} from './types.js';\n\ntype Listener = () => void;\n\nexport interface AitDevtoolsState {\n // 환경\n platform: PlatformOS;\n environment: OperationalEnvironment;\n appVersion: string;\n locale: string;\n schemeUri: string;\n groupId: string;\n deploymentId: string;\n deviceId: string;\n\n // 브랜드\n brand: {\n displayName: string;\n icon: string;\n primaryColor: string;\n };\n\n // 네트워크\n networkStatus: NetworkStatus;\n\n // 권한\n permissions: Record<PermissionName, PermissionStatus>;\n\n // 위치\n location: MockLocation;\n\n // Safe Area\n safeAreaInsets: SafeAreaInsets;\n\n // 연락처\n contacts: MockContact[];\n\n // IAP\n iap: {\n products: MockIapProduct[];\n nextResult: IapNextResult;\n pendingOrders: Array<{ orderId: string; sku: string; paymentCompletedDate: string }>;\n completedOrders: Array<{\n orderId: string;\n sku: string;\n status: 'COMPLETED' | 'REFUNDED';\n date: string;\n }>;\n };\n\n // 결제 (TossPay)\n payment: {\n nextResult: 'success' | 'fail';\n failReason: string;\n };\n\n // 로그인\n auth: {\n isLoggedIn: boolean;\n isTossLoginIntegrated: boolean;\n userKeyHash: string;\n };\n\n // 광고\n ads: {\n isLoaded: boolean;\n nextEvent:\n | 'loaded'\n | 'clicked'\n | 'dismissed'\n | 'failedToShow'\n | 'impression'\n | 'userEarnedReward';\n };\n\n // 게임\n game: {\n profile: { nickname: string; profileImageUri: string } | null;\n leaderboardScores: Array<{ score: string; timestamp: number }>;\n };\n\n // 분석 로그\n analyticsLog: AnalyticsLogEntry[];\n\n // 디바이스 API 모드\n deviceModes: DeviceModes;\n\n // mock 모드용 더미 데이터\n mockData: MockData;\n\n // mock 활성화 상태\n panelEditable: boolean;\n}\n\nconst DEFAULT_STATE: AitDevtoolsState = {\n platform: 'ios',\n environment: 'sandbox',\n appVersion: '5.240.0',\n locale: 'ko-KR',\n schemeUri: '/',\n groupId: 'mock-group-id',\n deploymentId: 'mock-deployment-id',\n deviceId: '',\n\n brand: {\n displayName: 'Mock App',\n icon: '',\n primaryColor: '#3182F6',\n },\n\n networkStatus: 'WIFI',\n\n permissions: {\n clipboard: 'allowed',\n contacts: 'allowed',\n photos: 'allowed',\n geolocation: 'allowed',\n camera: 'allowed',\n microphone: 'notDetermined',\n },\n\n location: {\n coords: {\n latitude: 37.5665,\n longitude: 126.978,\n altitude: 0,\n accuracy: 10,\n altitudeAccuracy: 0,\n heading: 0,\n },\n timestamp: Date.now(),\n accessLocation: 'FINE',\n },\n\n safeAreaInsets: { top: 47, bottom: 34, left: 0, right: 0 },\n\n contacts: [\n { name: '홍길동', phoneNumber: '010-1234-5678' },\n { name: '김토스', phoneNumber: '010-9876-5432' },\n ],\n\n iap: {\n products: [\n {\n sku: 'mock-gem-100',\n type: 'CONSUMABLE',\n displayName: '보석 100개',\n displayAmount: '1,000원',\n iconUrl: '',\n description: '게임에서 사용할 수 있는 보석 100개',\n },\n ],\n nextResult: 'success',\n pendingOrders: [],\n completedOrders: [],\n },\n\n payment: {\n nextResult: 'success',\n failReason: '',\n },\n\n auth: {\n isLoggedIn: true,\n isTossLoginIntegrated: true,\n userKeyHash: 'mock-user-hash-abc123',\n },\n\n ads: {\n isLoaded: false,\n nextEvent: 'loaded',\n },\n\n game: {\n profile: { nickname: 'MockPlayer', profileImageUri: '' },\n leaderboardScores: [],\n },\n\n analyticsLog: [],\n\n deviceModes: {\n camera: 'mock',\n photos: 'mock',\n location: 'mock',\n network: 'mock',\n clipboard: 'web',\n },\n\n mockData: {\n images: [],\n clipboardText: '',\n },\n\n panelEditable: true,\n};\n\nfunction generateDeviceId(): string {\n const stored = localStorage.getItem('__ait_device_id');\n if (stored) return stored;\n const id = crypto.randomUUID();\n localStorage.setItem('__ait_device_id', id);\n return id;\n}\n\nexport class AitStateManager {\n private _state: AitDevtoolsState;\n private _listeners = new Set<Listener>();\n\n constructor() {\n this._state = structuredClone(DEFAULT_STATE);\n try {\n this._state.deviceId = generateDeviceId();\n } catch {\n this._state.deviceId = `mock-device-${Math.random().toString(36).slice(2)}`;\n }\n }\n\n get state(): AitDevtoolsState {\n return this._state;\n }\n\n update(partial: Partial<AitDevtoolsState>) {\n this._state = { ...this._state, ...partial };\n this._notify();\n }\n\n /** 중첩 객체 업데이트용 */\n patch<K extends keyof AitDevtoolsState>(key: K, partial: Partial<AitDevtoolsState[K]>) {\n const current = this._state[key];\n if (typeof current === 'object' && current !== null && !Array.isArray(current)) {\n this._state = {\n ...this._state,\n [key]: { ...(current as Record<string, unknown>), ...(partial as Record<string, unknown>) },\n };\n } else {\n this._state = { ...this._state, [key]: partial as AitDevtoolsState[K] };\n }\n this._notify();\n }\n\n subscribe(listener: Listener): () => void {\n this._listeners.add(listener);\n return () => this._listeners.delete(listener);\n }\n\n /** 분석 로그 추가 */\n logAnalytics(entry: Omit<AnalyticsLogEntry, 'timestamp'>) {\n this._state = {\n ...this._state,\n analyticsLog: [...this._state.analyticsLog, { ...entry, timestamp: Date.now() }],\n };\n this._notify();\n }\n\n /** 이벤트 트리거 (backEvent, homeEvent 등) */\n trigger(event: string) {\n window.dispatchEvent(new CustomEvent(`__ait:${event}`));\n }\n\n reset() {\n const deviceId = this._state.deviceId;\n this._state = { ...structuredClone(DEFAULT_STATE), deviceId };\n this._notify();\n }\n\n private _notify() {\n for (const listener of this._listeners) {\n listener();\n }\n }\n}\n\nexport const aitState = new AitStateManager();\n\n// 브라우저 콘솔에서 접근 가능하도록\nif (typeof window !== 'undefined') {\n window.__ait = aitState;\n}\n","/**\n * 공통 DOM 헬퍼 함수\n */\n\nexport function 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\nexport function 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\nexport function inputRow(\n label: string,\n value: string,\n onChange: (v: string) => void,\n disabled = false,\n): 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\nexport function monitoringNotice(): HTMLElement {\n return h(\n 'div',\n { className: 'ait-monitoring-notice' },\n 'Read-only — mock responses are controlled at build time.',\n );\n}\n","/**\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 .ait-panel-tab-error {\n padding: 12px;\n color: #e53e3e; /* readable on both light (#fff) and dark (#1a1a2e) panel backgrounds */\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 * 디바이스 모듈 내부 공유 헬퍼\n */\n\nimport { aitState } from '../state.js';\n\n// --- Placeholder Image Generator ---\n\nfunction generatePlaceholderImage(\n width: number,\n height: number,\n text: string,\n color: string,\n): string {\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n // jsdom 등 Canvas API 미지원 환경에서는 간단한 SVG data URI 반환\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\"><rect fill=\"${color}\" width=\"${width}\" height=\"${height}\"/><text x=\"50%\" y=\"50%\" fill=\"white\" font-size=\"16\" text-anchor=\"middle\" dominant-baseline=\"middle\">${text}</text></svg>`;\n return `data:image/svg+xml;base64,${btoa(svg)}`;\n }\n ctx.fillStyle = color;\n ctx.fillRect(0, 0, width, height);\n ctx.fillStyle = 'white';\n ctx.font = '16px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, width / 2, height / 2);\n return canvas.toDataURL('image/png');\n}\n\nconst DEFAULT_PLACEHOLDERS = [\n { text: 'Mock Photo 1', color: '#3182F6' },\n { text: 'Mock Photo 2', color: '#27ae60' },\n { text: 'Mock Photo 3', color: '#e67e22' },\n];\n\nlet cachedPlaceholders: string[] | null = null;\n\nexport function getDefaultPlaceholderImages(): string[] {\n if (!cachedPlaceholders) {\n cachedPlaceholders = DEFAULT_PLACEHOLDERS.map((p) =>\n generatePlaceholderImage(320, 240, p.text, p.color),\n );\n }\n return [...cachedPlaceholders];\n}\n\n/** @internal device 모듈 내부 전용 */\nexport function getMockImages(): string[] {\n const images = aitState.state.mockData.images;\n if (images.length > 0) return images;\n return getDefaultPlaceholderImages();\n}\n\n// --- Prompt Mode Helper ---\n\nconst PROMPT_TIMEOUT_MS = 30_000;\n\n/** @internal device 모듈 내부 전용 */\nexport function waitForPromptResponse<T>(type: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const eventName = `__ait:prompt-response:${type}`;\n const cancelName = '__ait:prompt-cancel';\n\n function cleanup() {\n clearTimeout(timer);\n window.removeEventListener(eventName, handler);\n window.removeEventListener(cancelName, cancelHandler);\n }\n\n const timer = setTimeout(() => {\n cleanup();\n const panelMounted = !!document.querySelector('.ait-panel');\n const hint = panelMounted\n ? 'Please provide input via the DevTools panel.'\n : 'Is @ait-co/devtools/panel imported?';\n reject(\n new Error(\n `[@ait-co/devtools] Prompt timeout for \"${type}\" after ${PROMPT_TIMEOUT_MS / 1000}s. ${hint}`,\n ),\n );\n }, PROMPT_TIMEOUT_MS);\n\n const handler = (e: Event) => {\n cleanup();\n resolve((e as CustomEvent).detail as T);\n };\n\n const cancelHandler = () => {\n cleanup();\n reject(new Error(`[@ait-co/devtools] Prompt cancelled for \"${type}\"`));\n };\n\n window.addEventListener(eventName, handler);\n window.addEventListener(cancelName, cancelHandler);\n window.dispatchEvent(new CustomEvent('__ait:prompt-request', { detail: { type } }));\n });\n}\n","/**\n * 권한 시스템 mock\n * 각 디바이스 API (.getPermission, .openPermissionDialog)에 부착된다.\n */\n\nimport { aitState } from './state.js';\nimport type { PermissionName, PermissionStatus } from './types.js';\n\nexport async function getPermission(name: PermissionName): Promise<PermissionStatus> {\n return aitState.state.permissions[name];\n}\n\nexport async function openPermissionDialog(name: PermissionName): Promise<'allowed' | 'denied'> {\n const current = aitState.state.permissions[name];\n if (current === 'allowed') return 'allowed';\n // notDetermined나 denied일 때 — Panel에서 설정된 값을 사용\n // 기본적으로는 allowed로 전환\n aitState.patch('permissions', { [name]: 'allowed' });\n return 'allowed';\n}\n\nexport async function requestPermission(permission: {\n name: PermissionName;\n access: string;\n}): Promise<'allowed' | 'denied'> {\n return openPermissionDialog(permission.name);\n}\n\n/** 권한이 필요한 함수에 .getPermission(), .openPermissionDialog()를 부착 */\nexport function withPermission<T extends (...args: never[]) => unknown>(\n fn: T,\n permissionName: PermissionName,\n): T & {\n getPermission: () => Promise<PermissionStatus>;\n openPermissionDialog: () => Promise<'allowed' | 'denied'>;\n} {\n const enhanced = fn as T & {\n getPermission: () => Promise<PermissionStatus>;\n openPermissionDialog: () => Promise<'allowed' | 'denied'>;\n };\n enhanced.getPermission = () => getPermission(permissionName);\n enhanced.openPermissionDialog = () => openPermissionDialog(permissionName);\n return enhanced;\n}\n\n/** 권한 체크 후 denied면 에러 throw */\nexport function checkPermission(name: PermissionName, fnName: string): void {\n const status = aitState.state.permissions[name];\n if (status === 'denied') {\n throw new Error(\n `[@ait-co/devtools] ${fnName}: Permission \"${name}\" is denied. Change it in the DevTools panel.`,\n );\n }\n}\n","/**\n * Camera & Album Photos mock\n * mock/web/prompt 모드 지원\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\nimport { getMockImages, waitForPromptResponse } from './_helpers.js';\n\n// --- Camera ---\n\nasync function openCameraMock(): Promise<{ id: string; dataUri: string }> {\n const images = getMockImages();\n return { id: crypto.randomUUID(), dataUri: images[0] };\n}\n\nasync function openCameraWeb(): Promise<{ id: string; dataUri: string }> {\n return new Promise((resolve, reject) => {\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = 'image/*';\n input.capture = 'environment';\n let settled = false;\n input.onchange = () => {\n settled = true;\n const file = input.files?.[0];\n if (!file) {\n reject(new Error('No file selected'));\n return;\n }\n const reader = new FileReader();\n reader.onload = () => resolve({ id: crypto.randomUUID(), dataUri: reader.result as string });\n reader.onerror = () => reject(new Error('Failed to read file'));\n reader.readAsDataURL(file);\n };\n // Detect file picker cancel via focus heuristic.\n // Note: unreliable on some mobile browsers and Safari where focus events differ.\n const onFocus = () => {\n setTimeout(() => {\n if (!settled) reject(new Error('File picker cancelled'));\n window.removeEventListener('focus', onFocus);\n }, 300);\n };\n window.addEventListener('focus', onFocus);\n input.click();\n });\n}\n\nasync function openCameraPrompt(): Promise<{ id: string; dataUri: string }> {\n const dataUri = await waitForPromptResponse<string>('camera');\n return { id: crypto.randomUUID(), dataUri };\n}\n\nconst _openCamera = async (_options?: {\n base64?: boolean;\n maxWidth?: number;\n}): Promise<{ id: string; dataUri: string }> => {\n checkPermission('camera', 'openCamera');\n const mode = aitState.state.deviceModes.camera;\n if (mode === 'web') return openCameraWeb();\n if (mode === 'prompt') return openCameraPrompt();\n return openCameraMock();\n};\nexport const openCamera = withPermission(_openCamera, 'camera');\n\n// --- Album Photos ---\n\nasync function fetchAlbumPhotosMock(\n maxCount: number,\n): Promise<Array<{ id: string; dataUri: string }>> {\n const images = getMockImages();\n return images.slice(0, maxCount).map((dataUri) => ({ id: crypto.randomUUID(), dataUri }));\n}\n\nasync function fetchAlbumPhotosWeb(\n maxCount: number,\n): Promise<Array<{ id: string; dataUri: string }>> {\n return new Promise((resolve, reject) => {\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = 'image/*';\n input.multiple = true;\n let settled = false;\n input.onchange = async () => {\n settled = true;\n const files = Array.from(input.files ?? []).slice(0, maxCount);\n if (files.length === 0) {\n reject(new Error('No files selected'));\n return;\n }\n const results = await Promise.all(\n files.map(\n (file) =>\n new Promise<{ id: string; dataUri: string }>((res, rej) => {\n const reader = new FileReader();\n reader.onload = () =>\n res({ id: crypto.randomUUID(), dataUri: reader.result as string });\n reader.onerror = () => rej(new Error('Failed to read file'));\n reader.readAsDataURL(file);\n }),\n ),\n );\n resolve(results);\n };\n const onFocus = () => {\n setTimeout(() => {\n if (!settled) reject(new Error('File picker cancelled'));\n window.removeEventListener('focus', onFocus);\n }, 300);\n };\n window.addEventListener('focus', onFocus);\n input.click();\n });\n}\n\nasync function fetchAlbumPhotosPrompt(\n maxCount: number,\n): Promise<Array<{ id: string; dataUri: string }>> {\n const dataUris = await waitForPromptResponse<string[]>('photos');\n return dataUris.slice(0, maxCount).map((dataUri) => ({ id: crypto.randomUUID(), dataUri }));\n}\n\nconst _fetchAlbumPhotos = async (options?: {\n maxCount?: number;\n maxWidth?: number;\n base64?: boolean;\n}): Promise<Array<{ id: string; dataUri: string }>> => {\n checkPermission('photos', 'fetchAlbumPhotos');\n const maxCount = options?.maxCount ?? 10;\n const mode = aitState.state.deviceModes.photos;\n if (mode === 'web') return fetchAlbumPhotosWeb(maxCount);\n if (mode === 'prompt') return fetchAlbumPhotosPrompt(maxCount);\n return fetchAlbumPhotosMock(maxCount);\n};\nexport const fetchAlbumPhotos = withPermission(_fetchAlbumPhotos, 'photos');\n","/**\n * Clipboard mock\n * mock/web 모드 지원\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\n\nconst _getClipboardText = async (): Promise<string> => {\n checkPermission('clipboard', 'getClipboardText');\n const mode = aitState.state.deviceModes.clipboard;\n if (mode === 'mock') return aitState.state.mockData.clipboardText;\n // web mode (default)\n try {\n return await navigator.clipboard.readText();\n } catch {\n return '';\n }\n};\nexport const getClipboardText = withPermission(_getClipboardText, 'clipboard');\n\nconst _setClipboardText = async (text: string): Promise<void> => {\n checkPermission('clipboard', 'setClipboardText');\n const mode = aitState.state.deviceModes.clipboard;\n if (mode === 'mock') {\n aitState.patch('mockData', { clipboardText: text });\n return;\n }\n // web mode (default)\n await navigator.clipboard.writeText(text);\n};\nexport const setClipboardText = withPermission(_setClipboardText, 'clipboard');\n","/**\n * Contacts mock\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\n\nconst _fetchContacts = async (options: {\n size: number;\n offset: number;\n query?: { contains?: string };\n}) => {\n checkPermission('contacts', 'fetchContacts');\n let contacts = aitState.state.contacts;\n if (options.query?.contains) {\n const q = options.query.contains.toLowerCase();\n contacts = contacts.filter(\n (c) => c.name.toLowerCase().includes(q) || c.phoneNumber.includes(q),\n );\n }\n const sliced = contacts.slice(options.offset, options.offset + options.size);\n const nextOffset = options.offset + options.size;\n return {\n result: sliced,\n nextOffset: nextOffset < contacts.length ? nextOffset : null,\n done: nextOffset >= contacts.length,\n };\n};\nexport const fetchContacts = withPermission(_fetchContacts, 'contacts');\n","/**\n * Location mock (getCurrentLocation, startUpdateLocation)\n * mock/web/prompt 모드 지원\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\nimport type { MockLocation } from '../types.js';\nimport { waitForPromptResponse } from './_helpers.js';\n\nenum Accuracy {\n Lowest = 1,\n Low = 2,\n Balanced = 3,\n High = 4,\n Highest = 5,\n BestForNavigation = 6,\n}\n\nexport { Accuracy };\n\nfunction buildLocation(): MockLocation {\n return {\n coords: { ...aitState.state.location.coords },\n timestamp: Date.now(),\n accessLocation: aitState.state.location.accessLocation,\n };\n}\n\n// -- getCurrentLocation --\n\nasync function getCurrentLocationMock(): Promise<MockLocation> {\n return buildLocation();\n}\n\nasync function getCurrentLocationWeb(): Promise<MockLocation> {\n return new Promise((resolve) => {\n if (!navigator.geolocation) {\n console.warn('[@ait-co/devtools] Geolocation API not available, falling back to mock');\n resolve(buildLocation());\n return;\n }\n navigator.geolocation.getCurrentPosition(\n (pos) => {\n resolve({\n coords: {\n latitude: pos.coords.latitude,\n longitude: pos.coords.longitude,\n altitude: pos.coords.altitude ?? 0,\n accuracy: pos.coords.accuracy,\n altitudeAccuracy: pos.coords.altitudeAccuracy ?? 0,\n heading: pos.coords.heading ?? 0,\n },\n timestamp: pos.timestamp,\n accessLocation: 'FINE',\n });\n },\n () => {\n console.warn('[@ait-co/devtools] Geolocation failed, falling back to mock');\n resolve(buildLocation());\n },\n );\n });\n}\n\nasync function getCurrentLocationPrompt(): Promise<MockLocation> {\n return waitForPromptResponse<MockLocation>('location');\n}\n\nconst _getCurrentLocation = async (_options?: { accuracy: Accuracy }): Promise<MockLocation> => {\n checkPermission('geolocation', 'getCurrentLocation');\n const mode = aitState.state.deviceModes.location;\n if (mode === 'web') return getCurrentLocationWeb();\n if (mode === 'prompt') return getCurrentLocationPrompt();\n return getCurrentLocationMock();\n};\nexport const getCurrentLocation = withPermission(_getCurrentLocation, 'geolocation');\n\n// -- startUpdateLocation --\n\ninterface StartUpdateLocationEventParams {\n onEvent: (response: MockLocation) => void;\n onError: (error: unknown) => void;\n options: { accuracy: Accuracy; timeInterval: number; distanceInterval: number };\n}\n\nfunction startUpdateLocationMock(eventParams: StartUpdateLocationEventParams): () => void {\n const { onEvent, options } = eventParams;\n const interval = Math.max(options.timeInterval, 500);\n const id = setInterval(() => {\n const loc = buildLocation();\n loc.coords.latitude += (Math.random() - 0.5) * 0.0001;\n loc.coords.longitude += (Math.random() - 0.5) * 0.0001;\n onEvent(loc);\n }, interval);\n return () => clearInterval(id);\n}\n\nfunction startUpdateLocationWeb(eventParams: StartUpdateLocationEventParams): () => void {\n const { onEvent, onError } = eventParams;\n if (!navigator.geolocation) {\n console.warn('[@ait-co/devtools] Geolocation API not available, falling back to mock');\n return startUpdateLocationMock(eventParams);\n }\n const watchId = navigator.geolocation.watchPosition(\n (pos) => {\n onEvent({\n coords: {\n latitude: pos.coords.latitude,\n longitude: pos.coords.longitude,\n altitude: pos.coords.altitude ?? 0,\n accuracy: pos.coords.accuracy,\n altitudeAccuracy: pos.coords.altitudeAccuracy ?? 0,\n heading: pos.coords.heading ?? 0,\n },\n timestamp: pos.timestamp,\n accessLocation: 'FINE',\n });\n },\n (err) => onError(err),\n );\n return () => navigator.geolocation.clearWatch(watchId);\n}\n\nfunction startUpdateLocationPrompt(eventParams: StartUpdateLocationEventParams): () => void {\n const { onEvent } = eventParams;\n const handler = (e: Event) => {\n onEvent((e as CustomEvent).detail as MockLocation);\n };\n window.addEventListener('__ait:prompt-response:location-update', handler);\n window.dispatchEvent(\n new CustomEvent('__ait:prompt-request', { detail: { type: 'location-update' } }),\n );\n return () => window.removeEventListener('__ait:prompt-response:location-update', handler);\n}\n\nconst _startUpdateLocation = (eventParams: StartUpdateLocationEventParams): (() => void) => {\n const mode = aitState.state.deviceModes.location;\n if (mode === 'web') return startUpdateLocationWeb(eventParams);\n if (mode === 'prompt') return startUpdateLocationPrompt(eventParams);\n return startUpdateLocationMock(eventParams);\n};\nexport const startUpdateLocation = withPermission(_startUpdateLocation, 'geolocation');\n","/**\n * 미구현 API용 Proxy 트립와이어.\n *\n * 미구현 프로퍼티에 접근하면 throw한다. 이는 \"devtools에서는 멀쩡히 돌지만\n * 실 SDK에선 실제로 동작하는\" 시나리오를 차단하기 위한 의도적 선택이다.\n * mock이 미구현인 API는 실 SDK에서는 존재할 수 있고, 사용자가 이를 인지하지\n * 못한 채 개발을 이어가면 배포 시점에 놀라게 된다. 에러 메시지에 이슈 URL을\n * 포함해 사용자가 mock 누락을 제보할 수 있게 한다.\n */\n\nconst ISSUES_URL = 'https://github.com/apps-in-toss-community/devtools/issues';\n\nexport function createMockProxy<T extends Record<string, unknown>>(\n moduleName: string,\n implementations: T,\n): T {\n return new Proxy(implementations, {\n get(target, prop) {\n // 심볼 접근(Symbol.toPrimitive, Symbol.iterator 등)은 프레임워크/런타임이\n // 내부적으로 호출하므로 throw하면 console.log, 구조분해 등이 깨진다.\n if (typeof prop === 'symbol') return undefined;\n if (prop in target) return target[prop];\n\n throw new Error(\n `[@ait-co/devtools] ${moduleName}.${prop} is not mocked. ` +\n `This API may exist in @apps-in-toss/web-framework, ` +\n `but devtools' mock does not cover it yet. ` +\n `Please file an issue: ${ISSUES_URL}`,\n );\n },\n }) as T;\n}\n","/**\n * Storage mock\n * localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리\n */\n\nimport { createMockProxy } from '../proxy.js';\n\nexport const Storage = createMockProxy('Storage', {\n getItem: async (key: string): Promise<string | null> => {\n return localStorage.getItem(`__ait_storage:${key}`);\n },\n setItem: async (key: string, value: string): Promise<void> => {\n localStorage.setItem(`__ait_storage:${key}`, value);\n },\n removeItem: async (key: string): Promise<void> => {\n localStorage.removeItem(`__ait_storage:${key}`);\n },\n clearItems: async (): Promise<void> => {\n const keys = Object.keys(localStorage).filter((k) => k.startsWith('__ait_storage:'));\n for (const k of keys) {\n localStorage.removeItem(k);\n }\n },\n});\n","import { getDefaultPlaceholderImages } from '../../mock/device/index.js';\nimport { aitState } from '../../mock/state.js';\nimport { h, monitoringNotice, selectRow } from '../helpers.js';\n\n// --- Prompt mode state ---\ninterface PendingPrompt {\n type: string;\n}\nlet pendingPrompt: PendingPrompt | null = null;\n\nlet refreshPanel: () => void = () => {};\n\nexport function setDeviceRefreshPanel(fn: () => void) {\n refreshPanel = fn;\n}\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 — handled by index.ts listener which also calls refreshPanel\n window.dispatchEvent(new CustomEvent('__ait:panel-switch-tab', { detail: { tab: 'device' } }));\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(h('div', { className: 'ait-prompt-title' }, 'Camera Prompt — Select an image'));\n const input = h('input', {\n type: 'file',\n accept: 'image/*',\n style: 'font-size:11px;color:#aaa',\n });\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(h('div', { className: 'ait-prompt-title' }, 'Photos Prompt — Select images'));\n const input = h('input', {\n type: 'file',\n accept: 'image/*',\n multiple: '',\n style: 'font-size:11px;color:#aaa',\n });\n input.addEventListener('change', () => {\n const files = Array.from((input as HTMLInputElement).files ?? []);\n if (files.length === 0) return;\n Promise.all(\n files.map(\n (file) =>\n new Promise<string>((res) => {\n const reader = new FileReader();\n reader.onload = () => res(reader.result as string);\n reader.readAsDataURL(file);\n }),\n ),\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(\n 'div',\n { className: 'ait-prompt-title' },\n pendingPrompt.type === 'location'\n ? 'Location Prompt — Enter coordinates'\n : 'Location Update — Send coordinates',\n ),\n );\n const latInput = h('input', {\n className: 'ait-input',\n value: String(aitState.state.location.coords.latitude),\n style: 'width:80px',\n });\n const lngInput = h('input', {\n className: 'ait-input',\n value: String(aitState.state.location.coords.longitude),\n style: 'width:80px',\n });\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(\n 'div',\n { className: 'ait-prompt-input-row' },\n h('label', {}, 'Lat'),\n latInput,\n h('label', {}, 'Lng'),\n lngInput,\n sendBtn,\n ),\n );\n } else {\n // Fallback for unknown prompt types\n banner.append(h('div', { className: 'ait-prompt-title' }, `Prompt: ${pendingPrompt.type}`));\n }\n\n // Cancel button for all prompt types\n const cancelBtn = h(\n 'button',\n { className: 'ait-btn ait-btn-sm ait-btn-danger', style: 'margin-top:8px' },\n 'Cancel',\n );\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\nexport function 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 [\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(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Device API Modes'),\n ...modeEntries.map((entry) =>\n selectRow(\n entry.label,\n entry.options,\n s.deviceModes[entry.key],\n (v) => {\n aitState.patch('deviceModes', { [entry.key]: v } as Partial<typeof s.deviceModes>);\n },\n disabled,\n ),\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 });\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(\n files.map(\n (file) =>\n new Promise<string>((res) => {\n const reader = new FileReader();\n reader.onload = () => res(reader.result as string);\n reader.readAsDataURL(file);\n }),\n ),\n ).then((dataUris) => {\n aitState.patch('mockData', { images: [...aitState.state.mockData.images, ...dataUris] });\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 });\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 });\n if (disabled) clearImagesBtn.disabled = true;\n\n container.append(\n h(\n 'div',\n { 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","import { aitState } from '../../mock/state.js';\nimport { h, monitoringNotice } from '../helpers.js';\n\nexport function 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.update({ analyticsLog: [] });\n });\n\n container.append(\n h(\n 'div',\n { className: 'ait-section' },\n h(\n 'div',\n { className: 'ait-row' },\n h('div', { className: 'ait-section-title' }, `Analytics Log (${logs.length})`),\n clearBtn,\n ),\n ...logs\n .slice(-30)\n .reverse()\n .map((entry) => {\n const time = new Date(entry.timestamp).toLocaleTimeString('ko-KR', { hour12: false });\n return h(\n 'div',\n { 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","import { aitState } from '../../mock/state.js';\nimport type { NetworkStatus, OperationalEnvironment, PlatformOS } from '../../mock/types.js';\nimport { h, inputRow, monitoringNotice, selectRow } from '../helpers.js';\n\nexport function renderEnvironmentTab(): 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(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Platform'),\n selectRow(\n 'OS',\n ['ios', 'android'],\n s.platform,\n (v) => aitState.update({ platform: v as PlatformOS }),\n disabled,\n ),\n inputRow('App Version', s.appVersion, (v) => aitState.update({ appVersion: v }), disabled),\n selectRow(\n 'Environment',\n ['toss', 'sandbox'],\n s.environment,\n (v) => aitState.update({ environment: v as OperationalEnvironment }),\n disabled,\n ),\n inputRow('Locale', s.locale, (v) => aitState.update({ locale: v }), disabled),\n ),\n h(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Network'),\n selectRow(\n 'Status',\n ['WIFI', '4G', '5G', '3G', '2G', 'OFFLINE', 'WWAN', 'UNKNOWN'],\n s.networkStatus,\n (v) => aitState.update({ networkStatus: v as NetworkStatus }),\n disabled,\n ),\n ),\n h(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Safe Area Insets'),\n inputRow(\n 'Top',\n String(s.safeAreaInsets.top),\n (v) => aitState.patch('safeAreaInsets', { top: Number(v) }),\n disabled,\n ),\n inputRow(\n 'Bottom',\n String(s.safeAreaInsets.bottom),\n (v) => aitState.patch('safeAreaInsets', { bottom: Number(v) }),\n disabled,\n ),\n ),\n );\n return container;\n}\n","import { aitState } from '../../mock/state.js';\nimport { h, monitoringNotice, selectRow } from '../helpers.js';\n\nexport function 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(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Navigation Events'),\n h('div', { className: 'ait-row' }, backBtn, homeBtn),\n ),\n h(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Login'),\n selectRow(\n 'Logged In',\n ['true', 'false'],\n String(aitState.state.auth.isLoggedIn),\n (v) => {\n aitState.patch('auth', { isLoggedIn: v === 'true' });\n },\n disabled,\n ),\n selectRow(\n 'Toss Login Integrated',\n ['true', 'false'],\n String(aitState.state.auth.isTossLoginIntegrated),\n (v) => {\n aitState.patch('auth', { isTossLoginIntegrated: v === 'true' });\n },\n disabled,\n ),\n ),\n );\n return container;\n}\n","import { aitState } from '../../mock/state.js';\nimport type { IapNextResult } from '../../mock/types.js';\nimport { h, monitoringNotice, selectRow } from '../helpers.js';\n\nexport function renderIapTab(): HTMLElement {\n const s = aitState.state;\n const disabled = !s.panelEditable;\n const container = h('div');\n const results: IapNextResult[] = [\n 'success',\n 'USER_CANCELED',\n 'INVALID_PRODUCT_ID',\n 'PAYMENT_PENDING',\n 'NETWORK_ERROR',\n 'ITEM_ALREADY_OWNED',\n 'INTERNAL_ERROR',\n ];\n\n if (disabled) container.appendChild(monitoringNotice());\n\n container.append(\n h(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'IAP Simulator'),\n selectRow(\n 'Next Purchase Result',\n results,\n s.iap.nextResult,\n (v) => {\n aitState.patch('iap', { nextResult: v as IapNextResult });\n },\n disabled,\n ),\n ),\n h(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'TossPay'),\n selectRow(\n 'Next Payment Result',\n ['success', 'fail'],\n s.payment.nextResult,\n (v) => {\n aitState.patch('payment', { nextResult: v as 'success' | 'fail' });\n },\n disabled,\n ),\n ),\n h(\n 'div',\n { className: 'ait-section' },\n h(\n 'div',\n { className: 'ait-section-title' },\n `Completed Orders (${s.iap.completedOrders.length})`,\n ),\n ...s.iap.completedOrders\n .slice(-5)\n .map((o) =>\n h(\n 'div',\n { 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","import { aitState } from '../../mock/state.js';\nimport { h, inputRow, monitoringNotice } from '../helpers.js';\n\nexport function 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(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Current Location'),\n inputRow(\n 'Latitude',\n String(s.location.coords.latitude),\n (v) => {\n const coords = { ...s.location.coords, latitude: Number(v) };\n aitState.patch('location', { coords } as Partial<typeof s.location>);\n },\n disabled,\n ),\n inputRow(\n 'Longitude',\n String(s.location.coords.longitude),\n (v) => {\n const coords = { ...s.location.coords, longitude: Number(v) };\n aitState.patch('location', { coords } as Partial<typeof s.location>);\n },\n disabled,\n ),\n inputRow(\n 'Accuracy',\n String(s.location.coords.accuracy),\n (v) => {\n const coords = { ...s.location.coords, accuracy: Number(v) };\n aitState.patch('location', { coords } as Partial<typeof s.location>);\n },\n disabled,\n ),\n ),\n );\n return container;\n}\n","import { aitState } from '../../mock/state.js';\nimport type { PermissionName, PermissionStatus } from '../../mock/types.js';\nimport { h, monitoringNotice, selectRow } from '../helpers.js';\n\nexport function renderPermissionsTab(): HTMLElement {\n const s = aitState.state;\n const disabled = !s.panelEditable;\n const container = h('div');\n const names: PermissionName[] = [\n 'camera',\n 'photos',\n 'geolocation',\n 'clipboard',\n 'contacts',\n 'microphone',\n ];\n const statuses: PermissionStatus[] = ['allowed', 'denied', 'notDetermined'];\n\n if (disabled) container.appendChild(monitoringNotice());\n\n container.append(\n h(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Device Permissions'),\n ...names.map((name) =>\n selectRow(\n name,\n statuses,\n s.permissions[name],\n (v) => {\n aitState.patch('permissions', { [name]: v as PermissionStatus });\n },\n disabled,\n ),\n ),\n ),\n );\n return container;\n}\n","import { aitState } from '../../mock/state.js';\nimport { h, monitoringNotice } from '../helpers.js';\n\nexport function renderStorageTab(refreshPanel: () => void): 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 for (const [key] of entries) {\n localStorage.removeItem(prefix + key);\n }\n refreshPanel();\n });\n\n container.append(\n h(\n 'div',\n { className: 'ait-section' },\n h(\n 'div',\n { 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(\n 'div',\n {},\n ...entries.map(([key, value]) =>\n h(\n 'div',\n { className: 'ait-storage-row' },\n h('span', { className: 'ait-storage-key' }, key),\n h(\n 'span',\n { className: 'ait-storage-value' },\n value.length > 100 ? `${value.slice(0, 100)}...` : value,\n ),\n ),\n ),\n ),\n ),\n );\n return container;\n}\n","import { renderAnalyticsTab } from './analytics.js';\nimport { renderDeviceTab } from './device.js';\nimport { renderEnvironmentTab } from './environment.js';\nimport { renderEventsTab } from './events.js';\nimport { renderIapTab } from './iap.js';\nimport { renderLocationTab } from './location.js';\nimport { renderPermissionsTab } from './permissions.js';\nimport { renderStorageTab } from './storage.js';\n\nexport type TabId =\n | 'env'\n | 'permissions'\n | 'location'\n | 'iap'\n | 'events'\n | 'analytics'\n | 'storage'\n | 'device';\n\nexport const 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\n// storage tab receives refreshPanel because its clear button modifies localStorage\n// directly (not aitState), so it must trigger a re-render explicitly.\n// device tab uses setDeviceRefreshPanel() for prompt-related local state (pendingPrompt);\n// its aitState mutations are auto-refreshed via the subscription in index.ts.\n// Other tabs only modify aitState or use input controls that reflect changes immediately.\nexport function createTabRenderers(refreshPanel: () => void): Record<TabId, () => HTMLElement> {\n return {\n env: renderEnvironmentTab,\n permissions: renderPermissionsTab,\n location: renderLocationTab,\n device: renderDeviceTab,\n iap: renderIapTab,\n events: renderEventsTab,\n analytics: renderAnalyticsTab,\n storage: () => renderStorageTab(refreshPanel),\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 { h } from './helpers.js';\nimport { PANEL_HEIGHT, PANEL_STYLES, PANEL_WIDTH } from './styles.js';\nimport { setDeviceRefreshPanel } from './tabs/device.js';\nimport { createTabRenderers, TABS, type TabId } from './tabs/index.js';\n\n// --- Draggable toggle button ---\n\nfunction makeDraggable(el: HTMLElement, onClickOnly: () => void) {\n let isDragging = false;\n let startX = 0,\n startY = 0;\n let startLeft = 0,\n 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(\n '__ait_btn_pos',\n 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\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 {\n /* ignore */\n }\n } else {\n el.style.bottom = '16px';\n el.style.right = '16px';\n }\n}\n\n// --- Mount ---\n\nlet currentTab: TabId = 'env';\nlet isOpen = false;\nlet panelEl: HTMLElement | null = null;\nlet bodyEl: HTMLElement | null = null;\nlet tabsEl: HTMLElement | null = null;\n\n// Lazy-initialized after refreshPanel is defined\nlet tabRenderers: Record<TabId, () => HTMLElement> | null = null;\n\nfunction refreshPanel() {\n if (!bodyEl || !tabsEl) return;\n if (!tabRenderers) tabRenderers = createTabRenderers(refreshPanel);\n bodyEl.innerHTML = '';\n try {\n bodyEl.appendChild(tabRenderers[currentTab]());\n } catch (err) {\n console.error(`[@ait-co/devtools] Error rendering tab \"${currentTab}\":`, err);\n bodyEl.appendChild(\n h('div', { className: 'ait-panel-tab-error' }, `Error rendering \"${currentTab}\" tab.`),\n );\n }\n\n tabsEl.querySelectorAll('.ait-panel-tab').forEach((el) => {\n el.classList.toggle('active', el.getAttribute('data-tab') === currentTab);\n });\n}\n\n// Listen for tab switch requests from device tab (prompt auto-open)\nif (typeof window !== 'undefined') {\n window.addEventListener('__ait:panel-switch-tab', (e: Event) => {\n const detail = (e as CustomEvent).detail as { tab: TabId };\n currentTab = detail.tab;\n if (panelEl && !panelEl.classList.contains('open')) {\n isOpen = true;\n panelEl.classList.add('open');\n }\n refreshPanel();\n });\n}\n\nfunction mount() {\n if (typeof document === 'undefined') return;\n if (document.querySelector('.ait-panel-toggle')) return;\n\n // Wire up device tab's refreshPanel reference\n setDeviceRefreshPanel(refreshPanel);\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 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(\n 'span',\n {\n className: `ait-mock-badge ${aitState.state.panelEditable ? 'ait-mock-badge-on' : 'ait-mock-badge-off'}`,\n title: 'Toggle panel edit mode',\n },\n aitState.state.panelEditable ? 'EDIT' : 'READ-ONLY',\n );\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(\n 'span',\n { 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(\n 'div',\n { 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 // Defense-in-depth: outer catch complements refreshPanel's inner tab-rendering catch.\n aitState.subscribe(() => {\n try {\n if (\n isOpen &&\n (currentTab === 'analytics' || currentTab === 'storage' || currentTab === 'device')\n ) {\n refreshPanel();\n }\n } catch (err) {\n console.error('[@ait-co/devtools] Error in subscribe callback:', err);\n }\n });\n\n refreshPanel();\n}\n\n// DOM ready 시 마운트\nif (typeof document !== 'undefined') {\n const safeMount = () => {\n try {\n mount();\n } catch (err) {\n console.error('[@ait-co/devtools] Failed to mount panel:', err);\n }\n };\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', safeMount);\n } else {\n safeMount();\n }\n}\n\nexport { mount };\n"],"mappings":";AAoIA,MAAM,gBAAkC;CACtC,UAAU;CACV,aAAa;CACb,YAAY;CACZ,QAAQ;CACR,WAAW;CACX,SAAS;CACT,cAAc;CACd,UAAU;CAEV,OAAO;EACL,aAAa;EACb,MAAM;EACN,cAAc;EACf;CAED,eAAe;CAEf,aAAa;EACX,WAAW;EACX,UAAU;EACV,QAAQ;EACR,aAAa;EACb,QAAQ;EACR,YAAY;EACb;CAED,UAAU;EACR,QAAQ;GACN,UAAU;GACV,WAAW;GACX,UAAU;GACV,UAAU;GACV,kBAAkB;GAClB,SAAS;GACV;EACD,WAAW,KAAK,KAAK;EACrB,gBAAgB;EACjB;CAED,gBAAgB;EAAE,KAAK;EAAI,QAAQ;EAAI,MAAM;EAAG,OAAO;EAAG;CAE1D,UAAU,CACR;EAAE,MAAM;EAAO,aAAa;EAAiB,EAC7C;EAAE,MAAM;EAAO,aAAa;EAAiB,CAC9C;CAED,KAAK;EACH,UAAU,CACR;GACE,KAAK;GACL,MAAM;GACN,aAAa;GACb,eAAe;GACf,SAAS;GACT,aAAa;GACd,CACF;EACD,YAAY;EACZ,eAAe,EAAE;EACjB,iBAAiB,EAAE;EACpB;CAED,SAAS;EACP,YAAY;EACZ,YAAY;EACb;CAED,MAAM;EACJ,YAAY;EACZ,uBAAuB;EACvB,aAAa;EACd;CAED,KAAK;EACH,UAAU;EACV,WAAW;EACZ;CAED,MAAM;EACJ,SAAS;GAAE,UAAU;GAAc,iBAAiB;GAAI;EACxD,mBAAmB,EAAE;EACtB;CAED,cAAc,EAAE;CAEhB,aAAa;EACX,QAAQ;EACR,QAAQ;EACR,UAAU;EACV,SAAS;EACT,WAAW;EACZ;CAED,UAAU;EACR,QAAQ,EAAE;EACV,eAAe;EAChB;CAED,eAAe;CAChB;AAED,SAAS,mBAA2B;CAClC,MAAM,SAAS,aAAa,QAAQ,kBAAkB;AACtD,KAAI,OAAQ,QAAO;CACnB,MAAM,KAAK,OAAO,YAAY;AAC9B,cAAa,QAAQ,mBAAmB,GAAG;AAC3C,QAAO;;AAGT,IAAa,kBAAb,MAA6B;CAC3B;CACA,6BAAqB,IAAI,KAAe;CAExC,cAAc;AACZ,OAAK,SAAS,gBAAgB,cAAc;AAC5C,MAAI;AACF,QAAK,OAAO,WAAW,kBAAkB;UACnC;AACN,QAAK,OAAO,WAAW,eAAe,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,MAAM,EAAE;;;CAI7E,IAAI,QAA0B;AAC5B,SAAO,KAAK;;CAGd,OAAO,SAAoC;AACzC,OAAK,SAAS;GAAE,GAAG,KAAK;GAAQ,GAAG;GAAS;AAC5C,OAAK,SAAS;;;CAIhB,MAAwC,KAAQ,SAAuC;EACrF,MAAM,UAAU,KAAK,OAAO;AAC5B,MAAI,OAAO,YAAY,YAAY,YAAY,QAAQ,CAAC,MAAM,QAAQ,QAAQ,CAC5E,MAAK,SAAS;GACZ,GAAG,KAAK;IACP,MAAM;IAAE,GAAI;IAAqC,GAAI;IAAqC;GAC5F;MAED,MAAK,SAAS;GAAE,GAAG,KAAK;IAAS,MAAM;GAAgC;AAEzE,OAAK,SAAS;;CAGhB,UAAU,UAAgC;AACxC,OAAK,WAAW,IAAI,SAAS;AAC7B,eAAa,KAAK,WAAW,OAAO,SAAS;;;CAI/C,aAAa,OAA6C;AACxD,OAAK,SAAS;GACZ,GAAG,KAAK;GACR,cAAc,CAAC,GAAG,KAAK,OAAO,cAAc;IAAE,GAAG;IAAO,WAAW,KAAK,KAAK;IAAE,CAAC;GACjF;AACD,OAAK,SAAS;;;CAIhB,QAAQ,OAAe;AACrB,SAAO,cAAc,IAAI,YAAY,SAAS,QAAQ,CAAC;;CAGzD,QAAQ;EACN,MAAM,WAAW,KAAK,OAAO;AAC7B,OAAK,SAAS;GAAE,GAAG,gBAAgB,cAAc;GAAE;GAAU;AAC7D,OAAK,SAAS;;CAGhB,UAAkB;AAChB,OAAK,MAAM,YAAY,KAAK,WAC1B,WAAU;;;AAKhB,MAAa,WAAW,IAAI,iBAAiB;AAG7C,IAAI,OAAO,WAAW,YACpB,QAAO,QAAQ;;;;;;ACtTjB,SAAgB,EACd,KACA,OACA,GAAG,UACuB;CAC1B,MAAM,KAAK,SAAS,cAAc,IAAI;AACtC,KAAI,MACF,MAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,MAAM,CACxC,KAAI,MAAM,YAAa,IAAG,YAAY;KACjC,IAAG,aAAa,GAAG,EAAE;AAG9B,MAAK,MAAM,SAAS,SAClB,IAAG,OAAO,OAAO,UAAU,WAAW,SAAS,eAAe,MAAM,GAAG,MAAM;AAE/E,QAAO;;AAGT,SAAgB,UACd,OACA,SACA,OACA,UACA,WAAW,OACE;CACb,MAAM,SAAS,EAAE,UAAU,EAAE,WAAW,cAAc,CAAC;AACvD,KAAI,SAAU,QAAO,WAAW;AAChC,MAAK,MAAM,OAAO,SAAS;EACzB,MAAM,SAAS,EAAE,UAAU,EAAE,OAAO,KAAK,EAAE,IAAI;AAC/C,MAAI,QAAQ,MAAO,QAAO,WAAW;AACrC,SAAO,YAAY,OAAO;;AAE5B,QAAO,iBAAiB,gBAAgB,SAAS,OAAO,MAAM,CAAC;AAC/D,QAAO,EAAE,OAAO,EAAE,WAAW,WAAW,EAAE,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,OAAO;;AAG1E,SAAgB,SACd,OACA,OACA,UACA,WAAW,OACE;CACb,MAAM,QAAQ,EAAE,SAAS;EAAE,WAAW;EAAa;EAAO,CAAC;AAC3D,KAAI,SAAU,OAAM,WAAW;AAC/B,OAAM,iBAAiB,gBAAgB,SAAS,MAAM,MAAM,CAAC;AAC7D,QAAO,EAAE,OAAO,EAAE,WAAW,WAAW,EAAE,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,MAAM;;AAGzE,SAAgB,mBAAgC;AAC9C,QAAO,EACL,OACA,EAAE,WAAW,yBAAyB,EACtC,2DACD;;AClDH,MAAa,eAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACCtC,SAAS,yBACP,OACA,QACA,MACA,OACQ;CACR,MAAM,SAAS,SAAS,cAAc,SAAS;AAC/C,QAAO,QAAQ;AACf,QAAO,SAAS;CAChB,MAAM,MAAM,OAAO,WAAW,KAAK;AACnC,KAAI,CAAC,KAAK;EAER,MAAM,MAAM,kDAAkD,MAAM,YAAY,OAAO,gBAAgB,MAAM,WAAW,MAAM,YAAY,OAAO,uGAAuG,KAAK;AAC7P,SAAO,6BAA6B,KAAK,IAAI;;AAE/C,KAAI,YAAY;AAChB,KAAI,SAAS,GAAG,GAAG,OAAO,OAAO;AACjC,KAAI,YAAY;AAChB,KAAI,OAAO;AACX,KAAI,YAAY;AAChB,KAAI,eAAe;AACnB,KAAI,SAAS,MAAM,QAAQ,GAAG,SAAS,EAAE;AACzC,QAAO,OAAO,UAAU,YAAY;;AAGtC,MAAM,uBAAuB;CAC3B;EAAE,MAAM;EAAgB,OAAO;EAAW;CAC1C;EAAE,MAAM;EAAgB,OAAO;EAAW;CAC1C;EAAE,MAAM;EAAgB,OAAO;EAAW;CAC3C;AAED,IAAI,qBAAsC;AAE1C,SAAgB,8BAAwC;AACtD,KAAI,CAAC,mBACH,sBAAqB,qBAAqB,KAAK,MAC7C,yBAAyB,KAAK,KAAK,EAAE,MAAM,EAAE,MAAM,CACpD;AAEH,QAAO,CAAC,GAAG,mBAAmB;;;AAIhC,SAAgB,gBAA0B;CACxC,MAAM,SAAS,SAAS,MAAM,SAAS;AACvC,KAAI,OAAO,SAAS,EAAG,QAAO;AAC9B,QAAO,6BAA6B;;AAKtC,MAAM,oBAAoB;;AAG1B,SAAgB,sBAAyB,MAA0B;AACjE,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,YAAY,yBAAyB;EAC3C,MAAM,aAAa;EAEnB,SAAS,UAAU;AACjB,gBAAa,MAAM;AACnB,UAAO,oBAAoB,WAAW,QAAQ;AAC9C,UAAO,oBAAoB,YAAY,cAAc;;EAGvD,MAAM,QAAQ,iBAAiB;AAC7B,YAAS;GAET,MAAM,OADe,CAAC,CAAC,SAAS,cAAc,aAAa,GAEvD,iDACA;AACJ,0BACE,IAAI,MACF,0CAA0C,KAAK,UAAU,oBAAoB,IAAK,KAAK,OACxF,CACF;KACA,kBAAkB;EAErB,MAAM,WAAW,MAAa;AAC5B,YAAS;AACT,WAAS,EAAkB,OAAY;;EAGzC,MAAM,sBAAsB;AAC1B,YAAS;AACT,0BAAO,IAAI,MAAM,4CAA4C,KAAK,GAAG,CAAC;;AAGxE,SAAO,iBAAiB,WAAW,QAAQ;AAC3C,SAAO,iBAAiB,YAAY,cAAc;AAClD,SAAO,cAAc,IAAI,YAAY,wBAAwB,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;GACnF;;;;;;;;AC3FJ,eAAsB,cAAc,MAAiD;AACnF,QAAO,SAAS,MAAM,YAAY;;AAGpC,eAAsB,qBAAqB,MAAqD;AAE9F,KADgB,SAAS,MAAM,YAAY,UAC3B,UAAW,QAAO;AAGlC,UAAS,MAAM,eAAe,GAAG,OAAO,WAAW,CAAC;AACpD,QAAO;;;AAWT,SAAgB,eACd,IACA,gBAIA;CACA,MAAM,WAAW;AAIjB,UAAS,sBAAsB,cAAc,eAAe;AAC5D,UAAS,6BAA6B,qBAAqB,eAAe;AAC1E,QAAO;;;AAIT,SAAgB,gBAAgB,MAAsB,QAAsB;AAE1E,KADe,SAAS,MAAM,YAAY,UAC3B,SACb,OAAM,IAAI,MACR,sBAAsB,OAAO,gBAAgB,KAAK,+CACnD;;;;;;;;ACxCL,eAAe,iBAA2D;CACxE,MAAM,SAAS,eAAe;AAC9B,QAAO;EAAE,IAAI,OAAO,YAAY;EAAE,SAAS,OAAO;EAAI;;AAGxD,eAAe,gBAA0D;AACvE,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,QAAM,OAAO;AACb,QAAM,SAAS;AACf,QAAM,UAAU;EAChB,IAAI,UAAU;AACd,QAAM,iBAAiB;AACrB,aAAU;GACV,MAAM,OAAO,MAAM,QAAQ;AAC3B,OAAI,CAAC,MAAM;AACT,2BAAO,IAAI,MAAM,mBAAmB,CAAC;AACrC;;GAEF,MAAM,SAAS,IAAI,YAAY;AAC/B,UAAO,eAAe,QAAQ;IAAE,IAAI,OAAO,YAAY;IAAE,SAAS,OAAO;IAAkB,CAAC;AAC5F,UAAO,gBAAgB,uBAAO,IAAI,MAAM,sBAAsB,CAAC;AAC/D,UAAO,cAAc,KAAK;;EAI5B,MAAM,gBAAgB;AACpB,oBAAiB;AACf,QAAI,CAAC,QAAS,wBAAO,IAAI,MAAM,wBAAwB,CAAC;AACxD,WAAO,oBAAoB,SAAS,QAAQ;MAC3C,IAAI;;AAET,SAAO,iBAAiB,SAAS,QAAQ;AACzC,QAAM,OAAO;GACb;;AAGJ,eAAe,mBAA6D;CAC1E,MAAM,UAAU,MAAM,sBAA8B,SAAS;AAC7D,QAAO;EAAE,IAAI,OAAO,YAAY;EAAE;EAAS;;AAG7C,MAAM,cAAc,OAAO,aAGqB;AAC9C,iBAAgB,UAAU,aAAa;CACvC,MAAM,OAAO,SAAS,MAAM,YAAY;AACxC,KAAI,SAAS,MAAO,QAAO,eAAe;AAC1C,KAAI,SAAS,SAAU,QAAO,kBAAkB;AAChD,QAAO,gBAAgB;;AAEC,eAAe,aAAa,SAAS;AAI/D,eAAe,qBACb,UACiD;AAEjD,QADe,eAAe,CAChB,MAAM,GAAG,SAAS,CAAC,KAAK,aAAa;EAAE,IAAI,OAAO,YAAY;EAAE;EAAS,EAAE;;AAG3F,eAAe,oBACb,UACiD;AACjD,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,QAAM,OAAO;AACb,QAAM,SAAS;AACf,QAAM,WAAW;EACjB,IAAI,UAAU;AACd,QAAM,WAAW,YAAY;AAC3B,aAAU;GACV,MAAM,QAAQ,MAAM,KAAK,MAAM,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,SAAS;AAC9D,OAAI,MAAM,WAAW,GAAG;AACtB,2BAAO,IAAI,MAAM,oBAAoB,CAAC;AACtC;;AAcF,WAZgB,MAAM,QAAQ,IAC5B,MAAM,KACH,SACC,IAAI,SAA0C,KAAK,QAAQ;IACzD,MAAM,SAAS,IAAI,YAAY;AAC/B,WAAO,eACL,IAAI;KAAE,IAAI,OAAO,YAAY;KAAE,SAAS,OAAO;KAAkB,CAAC;AACpE,WAAO,gBAAgB,oBAAI,IAAI,MAAM,sBAAsB,CAAC;AAC5D,WAAO,cAAc,KAAK;KAC1B,CACL,CACF,CACe;;EAElB,MAAM,gBAAgB;AACpB,oBAAiB;AACf,QAAI,CAAC,QAAS,wBAAO,IAAI,MAAM,wBAAwB,CAAC;AACxD,WAAO,oBAAoB,SAAS,QAAQ;MAC3C,IAAI;;AAET,SAAO,iBAAiB,SAAS,QAAQ;AACzC,QAAM,OAAO;GACb;;AAGJ,eAAe,uBACb,UACiD;AAEjD,SADiB,MAAM,sBAAgC,SAAS,EAChD,MAAM,GAAG,SAAS,CAAC,KAAK,aAAa;EAAE,IAAI,OAAO,YAAY;EAAE;EAAS,EAAE;;AAG7F,MAAM,oBAAoB,OAAO,YAIsB;AACrD,iBAAgB,UAAU,mBAAmB;CAC7C,MAAM,WAAW,SAAS,YAAY;CACtC,MAAM,OAAO,SAAS,MAAM,YAAY;AACxC,KAAI,SAAS,MAAO,QAAO,oBAAoB,SAAS;AACxD,KAAI,SAAS,SAAU,QAAO,uBAAuB,SAAS;AAC9D,QAAO,qBAAqB,SAAS;;AAEP,eAAe,mBAAmB,SAAS;;;;;;;AC9H3E,MAAM,oBAAoB,YAA6B;AACrD,iBAAgB,aAAa,mBAAmB;AAEhD,KADa,SAAS,MAAM,YAAY,cAC3B,OAAQ,QAAO,SAAS,MAAM,SAAS;AAEpD,KAAI;AACF,SAAO,MAAM,UAAU,UAAU,UAAU;SACrC;AACN,SAAO;;;AAGqB,eAAe,mBAAmB,YAAY;AAE9E,MAAM,oBAAoB,OAAO,SAAgC;AAC/D,iBAAgB,aAAa,mBAAmB;AAEhD,KADa,SAAS,MAAM,YAAY,cAC3B,QAAQ;AACnB,WAAS,MAAM,YAAY,EAAE,eAAe,MAAM,CAAC;AACnD;;AAGF,OAAM,UAAU,UAAU,UAAU,KAAK;;AAEX,eAAe,mBAAmB,YAAY;;;;;;ACxB9E,MAAM,iBAAiB,OAAO,YAIxB;AACJ,iBAAgB,YAAY,gBAAgB;CAC5C,IAAI,WAAW,SAAS,MAAM;AAC9B,KAAI,QAAQ,OAAO,UAAU;EAC3B,MAAM,IAAI,QAAQ,MAAM,SAAS,aAAa;AAC9C,aAAW,SAAS,QACjB,MAAM,EAAE,KAAK,aAAa,CAAC,SAAS,EAAE,IAAI,EAAE,YAAY,SAAS,EAAE,CACrE;;CAEH,MAAM,SAAS,SAAS,MAAM,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,KAAK;CAC5E,MAAM,aAAa,QAAQ,SAAS,QAAQ;AAC5C,QAAO;EACL,QAAQ;EACR,YAAY,aAAa,SAAS,SAAS,aAAa;EACxD,MAAM,cAAc,SAAS;EAC9B;;AAE0B,eAAe,gBAAgB,WAAW;;;;;;;ACPvE,SAAS,gBAA8B;AACrC,QAAO;EACL,QAAQ,EAAE,GAAG,SAAS,MAAM,SAAS,QAAQ;EAC7C,WAAW,KAAK,KAAK;EACrB,gBAAgB,SAAS,MAAM,SAAS;EACzC;;AAKH,eAAe,yBAAgD;AAC7D,QAAO,eAAe;;AAGxB,eAAe,wBAA+C;AAC5D,QAAO,IAAI,SAAS,YAAY;AAC9B,MAAI,CAAC,UAAU,aAAa;AAC1B,WAAQ,KAAK,yEAAyE;AACtF,WAAQ,eAAe,CAAC;AACxB;;AAEF,YAAU,YAAY,oBACnB,QAAQ;AACP,WAAQ;IACN,QAAQ;KACN,UAAU,IAAI,OAAO;KACrB,WAAW,IAAI,OAAO;KACtB,UAAU,IAAI,OAAO,YAAY;KACjC,UAAU,IAAI,OAAO;KACrB,kBAAkB,IAAI,OAAO,oBAAoB;KACjD,SAAS,IAAI,OAAO,WAAW;KAChC;IACD,WAAW,IAAI;IACf,gBAAgB;IACjB,CAAC;WAEE;AACJ,WAAQ,KAAK,8DAA8D;AAC3E,WAAQ,eAAe,CAAC;IAE3B;GACD;;AAGJ,eAAe,2BAAkD;AAC/D,QAAO,sBAAoC,WAAW;;AAGxD,MAAM,sBAAsB,OAAO,aAA6D;AAC9F,iBAAgB,eAAe,qBAAqB;CACpD,MAAM,OAAO,SAAS,MAAM,YAAY;AACxC,KAAI,SAAS,MAAO,QAAO,uBAAuB;AAClD,KAAI,SAAS,SAAU,QAAO,0BAA0B;AACxD,QAAO,wBAAwB;;AAEC,eAAe,qBAAqB,cAAc;AAUpF,SAAS,wBAAwB,aAAyD;CACxF,MAAM,EAAE,SAAS,YAAY;CAC7B,MAAM,WAAW,KAAK,IAAI,QAAQ,cAAc,IAAI;CACpD,MAAM,KAAK,kBAAkB;EAC3B,MAAM,MAAM,eAAe;AAC3B,MAAI,OAAO,aAAa,KAAK,QAAQ,GAAG,MAAO;AAC/C,MAAI,OAAO,cAAc,KAAK,QAAQ,GAAG,MAAO;AAChD,UAAQ,IAAI;IACX,SAAS;AACZ,cAAa,cAAc,GAAG;;AAGhC,SAAS,uBAAuB,aAAyD;CACvF,MAAM,EAAE,SAAS,YAAY;AAC7B,KAAI,CAAC,UAAU,aAAa;AAC1B,UAAQ,KAAK,yEAAyE;AACtF,SAAO,wBAAwB,YAAY;;CAE7C,MAAM,UAAU,UAAU,YAAY,eACnC,QAAQ;AACP,UAAQ;GACN,QAAQ;IACN,UAAU,IAAI,OAAO;IACrB,WAAW,IAAI,OAAO;IACtB,UAAU,IAAI,OAAO,YAAY;IACjC,UAAU,IAAI,OAAO;IACrB,kBAAkB,IAAI,OAAO,oBAAoB;IACjD,SAAS,IAAI,OAAO,WAAW;IAChC;GACD,WAAW,IAAI;GACf,gBAAgB;GACjB,CAAC;KAEH,QAAQ,QAAQ,IAAI,CACtB;AACD,cAAa,UAAU,YAAY,WAAW,QAAQ;;AAGxD,SAAS,0BAA0B,aAAyD;CAC1F,MAAM,EAAE,YAAY;CACpB,MAAM,WAAW,MAAa;AAC5B,UAAS,EAAkB,OAAuB;;AAEpD,QAAO,iBAAiB,yCAAyC,QAAQ;AACzE,QAAO,cACL,IAAI,YAAY,wBAAwB,EAAE,QAAQ,EAAE,MAAM,mBAAmB,EAAE,CAAC,CACjF;AACD,cAAa,OAAO,oBAAoB,yCAAyC,QAAQ;;AAG3F,MAAM,wBAAwB,gBAA8D;CAC1F,MAAM,OAAO,SAAS,MAAM,YAAY;AACxC,KAAI,SAAS,MAAO,QAAO,uBAAuB,YAAY;AAC9D,KAAI,SAAS,SAAU,QAAO,0BAA0B,YAAY;AACpE,QAAO,wBAAwB,YAAY;;AAEV,eAAe,sBAAsB,cAAc;;;;;;;;;;;;ACpItF,MAAM,aAAa;AAEnB,SAAgB,gBACd,YACA,iBACG;AACH,QAAO,IAAI,MAAM,iBAAiB,EAChC,IAAI,QAAQ,MAAM;AAGhB,MAAI,OAAO,SAAS,SAAU,QAAO,KAAA;AACrC,MAAI,QAAQ,OAAQ,QAAO,OAAO;AAElC,QAAM,IAAI,MACR,sBAAsB,WAAW,GAAG,KAAK,qIAGd,aAC5B;IAEJ,CAAC;;ACvBmB,gBAAgB,WAAW;CAChD,SAAS,OAAO,QAAwC;AACtD,SAAO,aAAa,QAAQ,iBAAiB,MAAM;;CAErD,SAAS,OAAO,KAAa,UAAiC;AAC5D,eAAa,QAAQ,iBAAiB,OAAO,MAAM;;CAErD,YAAY,OAAO,QAA+B;AAChD,eAAa,WAAW,iBAAiB,MAAM;;CAEjD,YAAY,YAA2B;EACrC,MAAM,OAAO,OAAO,KAAK,aAAa,CAAC,QAAQ,MAAM,EAAE,WAAW,iBAAiB,CAAC;AACpF,OAAK,MAAM,KAAK,KACd,cAAa,WAAW,EAAE;;CAG/B,CAAC;;;ACfF,IAAI,gBAAsC;AAE1C,IAAIA,uBAAiC;AAErC,SAAgB,sBAAsB,IAAgB;AACpD,kBAAe;;AAIjB,IAAI,OAAO,WAAW,YACpB,QAAO,iBAAiB,yBAAyB,MAAa;AAE5D,iBAAgB,EAAE,MADF,EAAkB,OACH,MAAM;AAErC,QAAO,cAAc,IAAI,YAAY,0BAA0B,EAAE,QAAQ,EAAE,KAAK,UAAU,EAAE,CAAC,CAAC;EAC9F;AAGJ,SAAS,cAAc,MAAc,MAAe;AAClD,QAAO,cAAc,IAAI,YAAY,yBAAyB,QAAQ,EAAE,QAAQ,MAAM,CAAC,CAAC;AACxF,iBAAgB;AAChB,iBAAc;;AAGhB,SAAS,qBAAyC;AAChD,KAAI,CAAC,cAAe,QAAO;CAE3B,MAAM,SAAS,EAAE,OAAO,EAAE,WAAW,qBAAqB,CAAC;AAE3D,KAAI,cAAc,SAAS,UAAU;AACnC,SAAO,OAAO,EAAE,OAAO,EAAE,WAAW,oBAAoB,EAAE,kCAAkC,CAAC;EAC7F,MAAM,QAAQ,EAAE,SAAS;GACvB,MAAM;GACN,QAAQ;GACR,OAAO;GACR,CAAC;AACF,QAAM,iBAAiB,gBAAgB;GACrC,MAAM,OAAQ,MAA2B,QAAQ;AACjD,OAAI,CAAC,KAAM;GACX,MAAM,SAAS,IAAI,YAAY;AAC/B,UAAO,eAAe,cAAc,UAAU,OAAO,OAAiB;AACtE,UAAO,cAAc,KAAK;IAC1B;AACF,SAAO,YAAY,MAAM;YAChB,cAAc,SAAS,UAAU;AAC1C,SAAO,OAAO,EAAE,OAAO,EAAE,WAAW,oBAAoB,EAAE,gCAAgC,CAAC;EAC3F,MAAM,QAAQ,EAAE,SAAS;GACvB,MAAM;GACN,QAAQ;GACR,UAAU;GACV,OAAO;GACR,CAAC;AACF,QAAM,iBAAiB,gBAAgB;GACrC,MAAM,QAAQ,MAAM,KAAM,MAA2B,SAAS,EAAE,CAAC;AACjE,OAAI,MAAM,WAAW,EAAG;AACxB,WAAQ,IACN,MAAM,KACH,SACC,IAAI,SAAiB,QAAQ;IAC3B,MAAM,SAAS,IAAI,YAAY;AAC/B,WAAO,eAAe,IAAI,OAAO,OAAiB;AAClD,WAAO,cAAc,KAAK;KAC1B,CACL,CACF,CAAC,MAAM,aAAa,cAAc,UAAU,SAAS,CAAC;IACvD;AACF,SAAO,YAAY,MAAM;YAChB,cAAc,SAAS,cAAc,cAAc,SAAS,mBAAmB;AACxF,SAAO,OACL,EACE,OACA,EAAE,WAAW,oBAAoB,EACjC,cAAc,SAAS,aACnB,wCACA,qCACL,CACF;EACD,MAAM,WAAW,EAAE,SAAS;GAC1B,WAAW;GACX,OAAO,OAAO,SAAS,MAAM,SAAS,OAAO,SAAS;GACtD,OAAO;GACR,CAAC;EACF,MAAM,WAAW,EAAE,SAAS;GAC1B,WAAW;GACX,OAAO,OAAO,SAAS,MAAM,SAAS,OAAO,UAAU;GACvD,OAAO;GACR,CAAC;EACF,MAAM,UAAU,EAAE,UAAU,EAAE,WAAW,sBAAsB,EAAE,OAAO;AACxE,UAAQ,iBAAiB,eAAe;GACtC,MAAM,MAAM;IACV,QAAQ;KACN,UAAU,OAAQ,SAA8B,MAAM;KACtD,WAAW,OAAQ,SAA8B,MAAM;KACvD,UAAU;KACV,UAAU;KACV,kBAAkB;KAClB,SAAS;KACV;IACD,WAAW,KAAK,KAAK;IACrB,gBAAgB;IACjB;AACD,iBAAc,cAAe,MAAM,IAAI;IACvC;AACF,SAAO,OACL,EACE,OACA,EAAE,WAAW,wBAAwB,EACrC,EAAE,SAAS,EAAE,EAAE,MAAM,EACrB,UACA,EAAE,SAAS,EAAE,EAAE,MAAM,EACrB,UACA,QACD,CACF;OAGD,QAAO,OAAO,EAAE,OAAO,EAAE,WAAW,oBAAoB,EAAE,WAAW,cAAc,OAAO,CAAC;CAI7F,MAAM,YAAY,EAChB,UACA;EAAE,WAAW;EAAqC,OAAO;EAAkB,EAC3E,SACD;AACD,WAAU,iBAAiB,eAAe;AACxC,kBAAgB;AAChB,SAAO,cAAc,IAAI,YAAY,sBAAsB,CAAC;AAC5D,kBAAc;GACd;AACF,QAAO,YAAY,UAAU;AAE7B,QAAO;;AAGT,SAAgB,kBAA+B;CAC7C,MAAM,IAAI,SAAS;CACnB,MAAM,WAAW,CAAC,EAAE;CACpB,MAAM,YAAY,EAAE,MAAM;AAE1B,KAAI,SAAU,WAAU,YAAY,kBAAkB,CAAC;AAGvD,KAAI,EAAE,eAAe;EACnB,MAAM,eAAe,oBAAoB;AACzC,MAAI,aAAc,WAAU,YAAY,aAAa;;AAavD,WAAU,OACR,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,mBAAmB,EAChE,GAbF;EACE;GAAE,OAAO;GAAU,KAAK;GAAU,SAAS;IAAC;IAAQ;IAAO;IAAS;GAAE;EACtE;GAAE,OAAO;GAAU,KAAK;GAAU,SAAS;IAAC;IAAQ;IAAO;IAAS;GAAE;EACtE;GAAE,OAAO;GAAY,KAAK;GAAY,SAAS;IAAC;IAAQ;IAAO;IAAS;GAAE;EAC1E;GAAE,OAAO;GAAW,KAAK;GAAW,SAAS,CAAC,QAAQ,MAAM;GAAE;EAC9D;GAAE,OAAO;GAAa,KAAK;GAAa,SAAS,CAAC,QAAQ,MAAM;GAAE;EACnE,CAOgB,KAAK,UAClB,UACE,MAAM,OACN,MAAM,SACN,EAAE,YAAY,MAAM,OACnB,MAAM;AACL,WAAS,MAAM,eAAe,GAAG,MAAM,MAAM,GAAG,CAAkC;IAEpF,SACD,CACF,CACF,CACF;CAGD,MAAM,SAAS,EAAE,SAAS;CAC1B,MAAM,YAAY,EAAE,OAAO,EAAE,WAAW,kBAAkB,CAAC;AAC3D,QAAO,SAAS,SAAS,QAAQ;EAC/B,MAAM,QAAQ,EAAE,OAAO,EAAE,WAAW,mBAAmB,CAAC;EACxD,MAAM,MAAM,EAAE,OAAO,EAAE,KAAK,SAAS,CAAC;EACtC,MAAM,YAAY,EAAE,UAAU,EAAE,WAAW,oBAAoB,EAAE,IAAI;AACrE,YAAU,iBAAiB,eAAe;GACxC,MAAM,YAAY,CAAC,GAAG,SAAS,MAAM,SAAS,OAAO;AACrD,aAAU,OAAO,KAAK,EAAE;AACxB,YAAS,MAAM,YAAY,EAAE,QAAQ,WAAW,CAAC;IACjD;AACF,MAAI,SAAU,WAAU,WAAW;AACnC,QAAM,OAAO,KAAK,UAAU;AAC5B,YAAU,YAAY,MAAM;GAC5B;CAEF,MAAM,SAAS,EAAE,UAAU,EAAE,WAAW,qBAAqB,EAAE,QAAQ;AACvE,QAAO,iBAAiB,eAAe;EACrC,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,QAAM,OAAO;AACb,QAAM,SAAS;AACf,QAAM,WAAW;AACjB,QAAM,iBAAiB;GACrB,MAAM,QAAQ,MAAM,KAAK,MAAM,SAAS,EAAE,CAAC;AAC3C,WAAQ,IACN,MAAM,KACH,SACC,IAAI,SAAiB,QAAQ;IAC3B,MAAM,SAAS,IAAI,YAAY;AAC/B,WAAO,eAAe,IAAI,OAAO,OAAiB;AAClD,WAAO,cAAc,KAAK;KAC1B,CACL,CACF,CAAC,MAAM,aAAa;AACnB,aAAS,MAAM,YAAY,EAAE,QAAQ,CAAC,GAAG,SAAS,MAAM,SAAS,QAAQ,GAAG,SAAS,EAAE,CAAC;KACxF;;AAEJ,QAAM,OAAO;GACb;AACF,KAAI,SAAU,QAAO,WAAW;CAEhC,MAAM,cAAc,EAAE,UAAU,EAAE,WAAW,qBAAqB,EAAE,eAAe;AACnF,aAAY,iBAAiB,eAAe;AAC1C,WAAS,MAAM,YAAY,EAAE,QAAQ,CAAC,GAAG,6BAA6B,CAAC,EAAE,CAAC;GAC1E;AACF,KAAI,SAAU,aAAY,WAAW;CAErC,MAAM,iBAAiB,EAAE,UAAU,EAAE,WAAW,qBAAqB,EAAE,QAAQ;AAC/E,gBAAe,iBAAiB,eAAe;AAC7C,WAAS,MAAM,YAAY,EAAE,QAAQ,EAAE,EAAE,CAAC;GAC1C;AACF,KAAI,SAAU,gBAAe,WAAW;AAExC,WAAU,OACR,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,gBAAgB,OAAO,OAAO,GAAG,EAC9E,WACA,EAAE,OAAO,EAAE,WAAW,eAAe,EAAE,QAAQ,aAAa,eAAe,CAC5E,CACF;AAED,QAAO;;;;ACtPT,SAAgB,qBAAkC;CAChD,MAAM,WAAW,CAAC,SAAS,MAAM;CACjC,MAAM,YAAY,EAAE,MAAM;AAC1B,KAAI,SAAU,WAAU,YAAY,kBAAkB,CAAC;CACvD,MAAM,OAAO,SAAS,MAAM;CAE5B,MAAM,WAAW,EAAE,UAAU,EAAE,WAAW,qCAAqC,EAAE,QAAQ;AACzF,KAAI,SAAU,UAAS,WAAW;AAClC,UAAS,iBAAiB,eAAe;AACvC,WAAS,OAAO,EAAE,cAAc,EAAE,EAAE,CAAC;GACrC;AAEF,WAAU,OACR,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EACE,OACA,EAAE,WAAW,WAAW,EACxB,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,kBAAkB,KAAK,OAAO,GAAG,EAC9E,SACD,EACD,GAAG,KACA,MAAM,IAAI,CACV,SAAS,CACT,KAAK,UAAU;AAEd,SAAO,EACL,OACA,EAAE,WAAW,iBAAiB,EAC9B,EAAE,QAAQ,EAAE,WAAW,gBAAgB,EAJ5B,IAAI,KAAK,MAAM,UAAU,CAAC,mBAAmB,SAAS,EAAE,QAAQ,OAAO,CAAC,CAIrC,EAC9C,EAAE,QAAQ,EAAE,WAAW,gBAAgB,EAAE,MAAM,KAAK,EACpD,KAAK,UAAU,MAAM,OAAO,CAC7B;GACD,CACL,CACF;AACD,QAAO;;;;ACpCT,SAAgB,uBAAoC;CAClD,MAAM,IAAI,SAAS;CACnB,MAAM,WAAW,CAAC,EAAE;CACpB,MAAM,YAAY,EAAE,MAAM;AAE1B,KAAI,SAAU,WAAU,YAAY,kBAAkB,CAAC;AAEvD,WAAU,OACR,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,WAAW,EACxD,UACE,MACA,CAAC,OAAO,UAAU,EAClB,EAAE,WACD,MAAM,SAAS,OAAO,EAAE,UAAU,GAAiB,CAAC,EACrD,SACD,EACD,SAAS,eAAe,EAAE,aAAa,MAAM,SAAS,OAAO,EAAE,YAAY,GAAG,CAAC,EAAE,SAAS,EAC1F,UACE,eACA,CAAC,QAAQ,UAAU,EACnB,EAAE,cACD,MAAM,SAAS,OAAO,EAAE,aAAa,GAA6B,CAAC,EACpE,SACD,EACD,SAAS,UAAU,EAAE,SAAS,MAAM,SAAS,OAAO,EAAE,QAAQ,GAAG,CAAC,EAAE,SAAS,CAC9E,EACD,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,UAAU,EACvD,UACE,UACA;EAAC;EAAQ;EAAM;EAAM;EAAM;EAAM;EAAW;EAAQ;EAAU,EAC9D,EAAE,gBACD,MAAM,SAAS,OAAO,EAAE,eAAe,GAAoB,CAAC,EAC7D,SACD,CACF,EACD,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,mBAAmB,EAChE,SACE,OACA,OAAO,EAAE,eAAe,IAAI,GAC3B,MAAM,SAAS,MAAM,kBAAkB,EAAE,KAAK,OAAO,EAAE,EAAE,CAAC,EAC3D,SACD,EACD,SACE,UACA,OAAO,EAAE,eAAe,OAAO,GAC9B,MAAM,SAAS,MAAM,kBAAkB,EAAE,QAAQ,OAAO,EAAE,EAAE,CAAC,EAC9D,SACD,CACF,CACF;AACD,QAAO;;;;AC5DT,SAAgB,kBAA+B;CAC7C,MAAM,WAAW,CAAC,SAAS,MAAM;CACjC,MAAM,YAAY,EAAE,MAAM;AAE1B,KAAI,SAAU,WAAU,YAAY,kBAAkB,CAAC;CAEvD,MAAM,UAAU,EAAE,UAAU,EAAE,WAAW,WAAW,EAAE,qBAAqB;AAC3E,SAAQ,iBAAiB,eAAe,SAAS,QAAQ,YAAY,CAAC;AACtE,KAAI,SAAU,SAAQ,WAAW;CAEjC,MAAM,UAAU,EAAE,UAAU,EAAE,WAAW,WAAW,EAAE,qBAAqB;AAC3E,SAAQ,iBAAiB,eAAe,SAAS,QAAQ,YAAY,CAAC;AACtE,KAAI,SAAU,SAAQ,WAAW;AAEjC,WAAU,OACR,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,oBAAoB,EACjE,EAAE,OAAO,EAAE,WAAW,WAAW,EAAE,SAAS,QAAQ,CACrD,EACD,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,QAAQ,EACrD,UACE,aACA,CAAC,QAAQ,QAAQ,EACjB,OAAO,SAAS,MAAM,KAAK,WAAW,GACrC,MAAM;AACL,WAAS,MAAM,QAAQ,EAAE,YAAY,MAAM,QAAQ,CAAC;IAEtD,SACD,EACD,UACE,yBACA,CAAC,QAAQ,QAAQ,EACjB,OAAO,SAAS,MAAM,KAAK,sBAAsB,GAChD,MAAM;AACL,WAAS,MAAM,QAAQ,EAAE,uBAAuB,MAAM,QAAQ,CAAC;IAEjE,SACD,CACF,CACF;AACD,QAAO;;;;AC5CT,SAAgB,eAA4B;CAC1C,MAAM,IAAI,SAAS;CACnB,MAAM,WAAW,CAAC,EAAE;CACpB,MAAM,YAAY,EAAE,MAAM;CAC1B,MAAM,UAA2B;EAC/B;EACA;EACA;EACA;EACA;EACA;EACA;EACD;AAED,KAAI,SAAU,WAAU,YAAY,kBAAkB,CAAC;AAEvD,WAAU,OACR,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,gBAAgB,EAC7D,UACE,wBACA,SACA,EAAE,IAAI,aACL,MAAM;AACL,WAAS,MAAM,OAAO,EAAE,YAAY,GAAoB,CAAC;IAE3D,SACD,CACF,EACD,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,UAAU,EACvD,UACE,uBACA,CAAC,WAAW,OAAO,EACnB,EAAE,QAAQ,aACT,MAAM;AACL,WAAS,MAAM,WAAW,EAAE,YAAY,GAAyB,CAAC;IAEpE,SACD,CACF,EACD,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EACE,OACA,EAAE,WAAW,qBAAqB,EAClC,qBAAqB,EAAE,IAAI,gBAAgB,OAAO,GACnD,EACD,GAAG,EAAE,IAAI,gBACN,MAAM,GAAG,CACT,KAAK,MACJ,EACE,OACA,EAAE,WAAW,iBAAiB,EAC9B,EAAE,QAAQ,EAAE,WAAW,gBAAgB,EAAE,EAAE,OAAO,EAClD,GAAG,EAAE,IAAI,IAAI,EAAE,QAAQ,MAAM,GAAG,CAAC,GAClC,CACF,CACJ,CACF;AACD,QAAO;;;;AClET,SAAgB,oBAAiC;CAC/C,MAAM,IAAI,SAAS;CACnB,MAAM,WAAW,CAAC,EAAE;CACpB,MAAM,YAAY,EAAE,MAAM;AAE1B,KAAI,SAAU,WAAU,YAAY,kBAAkB,CAAC;AAEvD,WAAU,OACR,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,mBAAmB,EAChE,SACE,YACA,OAAO,EAAE,SAAS,OAAO,SAAS,GACjC,MAAM;EACL,MAAM,SAAS;GAAE,GAAG,EAAE,SAAS;GAAQ,UAAU,OAAO,EAAE;GAAE;AAC5D,WAAS,MAAM,YAAY,EAAE,QAAQ,CAA+B;IAEtE,SACD,EACD,SACE,aACA,OAAO,EAAE,SAAS,OAAO,UAAU,GAClC,MAAM;EACL,MAAM,SAAS;GAAE,GAAG,EAAE,SAAS;GAAQ,WAAW,OAAO,EAAE;GAAE;AAC7D,WAAS,MAAM,YAAY,EAAE,QAAQ,CAA+B;IAEtE,SACD,EACD,SACE,YACA,OAAO,EAAE,SAAS,OAAO,SAAS,GACjC,MAAM;EACL,MAAM,SAAS;GAAE,GAAG,EAAE,SAAS;GAAQ,UAAU,OAAO,EAAE;GAAE;AAC5D,WAAS,MAAM,YAAY,EAAE,QAAQ,CAA+B;IAEtE,SACD,CACF,CACF;AACD,QAAO;;;;ACxCT,SAAgB,uBAAoC;CAClD,MAAM,IAAI,SAAS;CACnB,MAAM,WAAW,CAAC,EAAE;CACpB,MAAM,YAAY,EAAE,MAAM;CAC1B,MAAM,QAA0B;EAC9B;EACA;EACA;EACA;EACA;EACA;EACD;CACD,MAAM,WAA+B;EAAC;EAAW;EAAU;EAAgB;AAE3E,KAAI,SAAU,WAAU,YAAY,kBAAkB,CAAC;AAEvD,WAAU,OACR,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,qBAAqB,EAClE,GAAG,MAAM,KAAK,SACZ,UACE,MACA,UACA,EAAE,YAAY,QACb,MAAM;AACL,WAAS,MAAM,eAAe,GAAG,OAAO,GAAuB,CAAC;IAElE,SACD,CACF,CACF,CACF;AACD,QAAO;;;;ACnCT,SAAgB,iBAAiB,cAAuC;CACtE,MAAM,WAAW,CAAC,SAAS,MAAM;CACjC,MAAM,YAAY,EAAE,MAAM;AAC1B,KAAI,SAAU,WAAU,YAAY,kBAAkB,CAAC;CACvD,MAAM,SAAS;CACf,MAAM,UAAmC,EAAE;AAC3C,MAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;EAC5C,MAAM,MAAM,aAAa,IAAI,EAAE;AAC/B,MAAI,KAAK,WAAW,OAAO,CACzB,SAAQ,KAAK,CAAC,IAAI,MAAM,GAAc,EAAE,aAAa,QAAQ,IAAI,IAAI,GAAG,CAAC;;CAI7E,MAAM,WAAW,EAAE,UAAU,EAAE,WAAW,qCAAqC,EAAE,YAAY;AAC7F,KAAI,SAAU,UAAS,WAAW;AAClC,UAAS,iBAAiB,eAAe;AACvC,OAAK,MAAM,CAAC,QAAQ,QAClB,cAAa,WAAW,SAAS,IAAI;AAEvC,gBAAc;GACd;AAEF,WAAU,OACR,EACE,OACA,EAAE,WAAW,eAAe,EAC5B,EACE,OACA,EAAE,WAAW,WAAW,EACxB,EAAE,OAAO,EAAE,WAAW,qBAAqB,EAAE,YAAY,QAAQ,OAAO,SAAS,EACjF,SACD,EACD,QAAQ,WAAW,IACf,EAAE,OAAO,EAAE,OAAO,6BAA6B,EAAE,sBAAsB,GACvE,EACE,OACA,EAAE,EACF,GAAG,QAAQ,KAAK,CAAC,KAAK,WACpB,EACE,OACA,EAAE,WAAW,mBAAmB,EAChC,EAAE,QAAQ,EAAE,WAAW,mBAAmB,EAAE,IAAI,EAChD,EACE,QACA,EAAE,WAAW,qBAAqB,EAClC,MAAM,SAAS,MAAM,GAAG,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,MACpD,CACF,CACF,CACF,CACN,CACF;AACD,QAAO;;;;ACpCT,MAAa,OAA4C;CACvD;EAAE,IAAI;EAAO,OAAO;EAAe;CACnC;EAAE,IAAI;EAAe,OAAO;EAAe;CAC3C;EAAE,IAAI;EAAY,OAAO;EAAY;CACrC;EAAE,IAAI;EAAU,OAAO;EAAU;CACjC;EAAE,IAAI;EAAO,OAAO;EAAO;CAC3B;EAAE,IAAI;EAAU,OAAO;EAAU;CACjC;EAAE,IAAI;EAAa,OAAO;EAAa;CACvC;EAAE,IAAI;EAAW,OAAO;EAAW;CACpC;AAOD,SAAgB,mBAAmB,cAA4D;AAC7F,QAAO;EACL,KAAK;EACL,aAAa;EACb,UAAU;EACV,QAAQ;EACR,KAAK;EACL,QAAQ;EACR,WAAW;EACX,eAAe,iBAAiB,aAAa;EAC9C;;;;;;;;;;AC9BH,SAAS,cAAc,IAAiB,aAAyB;CAC/D,IAAI,aAAa;CACjB,IAAI,SAAS,GACX,SAAS;CACX,IAAI,YAAY,GACd,WAAW;CACb,IAAI,WAAW;AAEf,IAAG,iBAAiB,gBAAgB,MAAM;AACxC,eAAa;AACb,aAAW;AACX,WAAS,EAAE;AACX,WAAS,EAAE;EACX,MAAM,OAAO,GAAG,uBAAuB;AACvC,cAAY,KAAK;AACjB,aAAW,KAAK;AAChB,KAAG,kBAAkB,EAAE,UAAU;AACjC,IAAE,gBAAgB;GAClB;AAEF,IAAG,iBAAiB,gBAAgB,MAAM;AACxC,MAAI,CAAC,WAAY;EACjB,MAAM,KAAK,EAAE,UAAU;EACvB,MAAM,KAAK,EAAE,UAAU;AACvB,MAAI,KAAK,IAAI,GAAG,GAAG,KAAK,KAAK,IAAI,GAAG,GAAG,GAAG;AACxC,cAAW;AACX,MAAG,UAAU,IAAI,WAAW;;AAE9B,MAAI,CAAC,SAAU;AAEf,KAAG,MAAM,OAAO,GAAG,YAAY,GAAG;AAClC,KAAG,MAAM,MAAM,GAAG,WAAW,GAAG;AAChC,KAAG,MAAM,QAAQ;AACjB,KAAG,MAAM,SAAS;GAClB;AAEF,IAAG,iBAAiB,cAAc,MAAM;AACtC,MAAI,CAAC,WAAY;AACjB,eAAa;AACb,KAAG,UAAU,OAAO,WAAW;AAC/B,KAAG,sBAAsB,EAAE,UAAU;AAErC,MAAI,UAAU;AACZ,cAAW,GAAG;AACd,uBAAoB,GAAG;AACvB,sBAAmB,GAAG;QAEtB,cAAa;GAEf;AAEF,IAAG,iBAAiB,kBAAkB,MAAM;AAC1C,eAAa;AACb,KAAG,UAAU,OAAO,WAAW;AAC/B,KAAG,sBAAsB,EAAE,UAAU;AACrC,MAAI,UAAU;AACZ,cAAW,GAAG;AACd,uBAAoB,GAAG;AACvB,sBAAmB,GAAG;;GAExB;;AAGJ,SAAS,WAAW,IAAiB;CACnC,MAAM,OAAO,GAAG,uBAAuB;CACvC,MAAM,KAAK,OAAO;CAClB,MAAM,KAAK,OAAO;CAClB,MAAM,KAAK,KAAK,OAAO,KAAK,QAAQ;CACpC,MAAM,SAAS;AAEf,KAAI,KAAK,KAAK,GAAG;AACf,KAAG,MAAM,OAAO,GAAG,OAAO;AAC1B,KAAG,MAAM,QAAQ;QACZ;AACL,KAAG,MAAM,OAAO;AAChB,KAAG,MAAM,QAAQ,GAAG,OAAO;;CAG7B,MAAM,MAAM,KAAK,IAAI,QAAQ,KAAK,IAAI,KAAK,KAAK,SAAS,QAAQ,KAAK,IAAI,CAAC;AAC3E,IAAG,MAAM,MAAM,GAAG,IAAI;AACtB,IAAG,MAAM,SAAS;;AAGpB,SAAS,oBAAoB,UAAuB;AAClD,KAAI,CAAC,QAAS;CACd,MAAM,KAAK,OAAO;CAClB,MAAM,KAAK,OAAO;AAGlB,KAAI,MAAM,KAAK;AACb,UAAQ,MAAM,MAAM;AACpB,UAAQ,MAAM,OAAO;AACrB,UAAQ,MAAM,QAAQ;AACtB,UAAQ,MAAM,SAAS;AACvB;;CAGF,MAAM,OAAO,SAAS,uBAAuB;CAE7C,MAAM,cAAA;CACN,MAAM,SAAS;AAGf,KAAI,KAAK,OAAO,KAAK,GAAG;AACtB,UAAQ,MAAM,OAAO,GAAG,OAAO;AAC/B,UAAQ,MAAM,QAAQ;QACjB;AACL,UAAQ,MAAM,OAAO;AACrB,UAAQ,MAAM,QAAQ,GAAG,OAAO;;AAKlC,KAAI,KAAK,MAAM,KAAK,GAAG;EACrB,MAAM,MAAM,KAAK,IAAI,KAAK,SAAS,GAAG,KAAK,cAAc,OAAO;AAChE,UAAQ,MAAM,MAAM,GAAG,KAAK,IAAI,QAAQ,IAAI,CAAC;AAC7C,UAAQ,MAAM,SAAS;QAClB;EACL,MAAM,SAAS,KAAK,IAAI,KAAK,KAAK,MAAM,GAAG,KAAK,cAAc,OAAO;AACrE,UAAQ,MAAM,MAAM;AACpB,UAAQ,MAAM,SAAS,GAAG,KAAK,IAAI,QAAQ,OAAO,CAAC;;;AAIvD,SAAS,mBAAmB,IAAiB;AAC3C,cAAa,QACX,iBACA,KAAK,UAAU;EACb,MAAM,GAAG,MAAM;EACf,KAAK,GAAG,MAAM;EACd,OAAO,GAAG,MAAM;EAChB,QAAQ,GAAG,MAAM;EAClB,CAAC,CACH;;AAIH,SAAS,sBAAsB,IAAiB;CAC9C,MAAM,QAAQ,aAAa,QAAQ,gBAAgB;AACnD,KAAI,MACF,KAAI;EACF,MAAM,MAAM,KAAK,MAAM,MAAM;AAC7B,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM;EAC7C,MAAM,cAAc;GAAC;GAAQ;GAAO;GAAS;GAAS;EACtD,MAAM,gBAAgB;AACtB,OAAK,MAAM,OAAO,YAChB,KAAI,OAAO,OAAO,OAAO,IAAI,SAAS,YAAY,cAAc,KAAK,IAAI,KAAK,CAC5E,IAAG,MAAM,OAAO,IAAI;SAGlB;MAGH;AACL,KAAG,MAAM,SAAS;AAClB,KAAG,MAAM,QAAQ;;;AAMrB,IAAI,aAAoB;AACxB,IAAI,SAAS;AACb,IAAI,UAA8B;AAClC,IAAI,SAA6B;AACjC,IAAI,SAA6B;AAGjC,IAAI,eAAwD;AAE5D,SAAS,eAAe;AACtB,KAAI,CAAC,UAAU,CAAC,OAAQ;AACxB,KAAI,CAAC,aAAc,gBAAe,mBAAmB,aAAa;AAClE,QAAO,YAAY;AACnB,KAAI;AACF,SAAO,YAAY,aAAa,aAAa,CAAC;UACvC,KAAK;AACZ,UAAQ,MAAM,2CAA2C,WAAW,KAAK,IAAI;AAC7E,SAAO,YACL,EAAE,OAAO,EAAE,WAAW,uBAAuB,EAAE,oBAAoB,WAAW,QAAQ,CACvF;;AAGH,QAAO,iBAAiB,iBAAiB,CAAC,SAAS,OAAO;AACxD,KAAG,UAAU,OAAO,UAAU,GAAG,aAAa,WAAW,KAAK,WAAW;GACzE;;AAIJ,IAAI,OAAO,WAAW,YACpB,QAAO,iBAAiB,2BAA2B,MAAa;AAE9D,cADgB,EAAkB,OACd;AACpB,KAAI,WAAW,CAAC,QAAQ,UAAU,SAAS,OAAO,EAAE;AAClD,WAAS;AACT,UAAQ,UAAU,IAAI,OAAO;;AAE/B,eAAc;EACd;AAGJ,SAAS,QAAQ;AACf,KAAI,OAAO,aAAa,YAAa;AACrC,KAAI,SAAS,cAAc,oBAAoB,CAAE;AAGjD,uBAAsB,aAAa;CAGnC,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,OAAM,cAAc;AACpB,UAAS,KAAK,YAAY,MAAM;CAGhC,MAAM,SAAS,EAAE,UAAU;EAAE,WAAW;EAAoB,OAAO;EAAgB,EAAE,MAAM;AAC3F,uBAAsB,OAAO;AAG7B,WAAU,EAAE,OAAO,EAAE,WAAW,aAAa,CAAC;CAE9C,MAAM,WAAW,EAAE,UAAU;EAAE,WAAW;EAAmB,OAAO;EAAS,EAAE,IAAS;AACxF,UAAS,iBAAiB,eAAe;AACvC,WAAS;AACT,UAAS,UAAU,OAAO,OAAO;GACjC;CAEF,MAAM,YAAY,EAChB,QACA;EACE,WAAW,kBAAkB,SAAS,MAAM,gBAAgB,sBAAsB;EAClF,OAAO;EACR,EACD,SAAS,MAAM,gBAAgB,SAAS,YACzC;AAED,WAAU,iBAAiB,eAAe;AACxC,WAAS,OAAO,EAAE,eAAe,CAAC,SAAS,MAAM,eAAe,CAAC;AACjE,YAAU,YAAY,kBAAkB,SAAS,MAAM,gBAAgB,sBAAsB;AAC7F,YAAU,cAAc,SAAS,MAAM,gBAAgB,SAAS;AAChE,gBAAc;GACd;CAEF,MAAM,cAAc,EAClB,QACA,EAAE,OAAO,2CAA2C,EACpD,WACA,EAAE,QAAQ,EAAE,OAAO,6CAA6C,EAAE,SAAkB,EACpF,SACD;CACD,MAAM,SAAS,EACb,OACA,EAAE,WAAW,oBAAoB,EACjC,EAAE,QAAQ,EAAE,EAAE,eAAe,EAC7B,YACD;AAED,UAAS,EAAE,OAAO,EAAE,WAAW,kBAAkB,CAAC;AAClD,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,QAAQ,EAAE,UAAU;GAAE,WAAW;GAAiB,YAAY,IAAI;GAAI,EAAE,IAAI,MAAM;AACxF,QAAM,iBAAiB,eAAe;AACpC,gBAAa,IAAI;AACjB,iBAAc;IACd;AACF,SAAO,YAAY,MAAM;;AAG3B,UAAS,EAAE,OAAO,EAAE,WAAW,kBAAkB,CAAC;AAElD,SAAQ,OAAO,QAAQ,QAAQ,OAAO;AACtC,UAAS,KAAK,OAAO,SAAS,OAAO;AAGrC,YAAW,OAAO;AAClB,oBAAmB,OAAO;AAE1B,eAAc,cAAc;AAC1B,WAAS,CAAC;AACV,UAAS,UAAU,OAAO,QAAQ,OAAO;AACzC,MAAI,QAAQ;AACV,uBAAoB,OAAO;AAC3B,iBAAc;;GAEhB;CAGF,IAAI,YAAY;AAChB,QAAO,iBAAiB,gBAAgB;AACtC,MAAI,UAAW;AACf,cAAY,4BAA4B;AACtC,eAAY;AACZ,cAAW,OAAO;AAClB,sBAAmB,OAAO;AAC1B,OAAI,OAAQ,qBAAoB,OAAO;IACvC;GACF;AAIF,UAAS,gBAAgB;AACvB,MAAI;AACF,OACE,WACC,eAAe,eAAe,eAAe,aAAa,eAAe,UAE1E,eAAc;WAET,KAAK;AACZ,WAAQ,MAAM,mDAAmD,IAAI;;GAEvE;AAEF,eAAc;;AAIhB,IAAI,OAAO,aAAa,aAAa;CACnC,MAAM,kBAAkB;AACtB,MAAI;AACF,UAAO;WACA,KAAK;AACZ,WAAQ,MAAM,6CAA6C,IAAI;;;AAGnE,KAAI,SAAS,eAAe,UAC1B,UAAS,iBAAiB,oBAAoB,UAAU;KAExD,YAAW"}
1
+ {"version":3,"file":"index.js","names":["refreshPanel"],"sources":["../../src/mock/state.ts","../../src/panel/helpers.ts","../../src/panel/styles.ts","../../src/mock/device/_helpers.ts","../../src/mock/permissions.ts","../../src/mock/device/camera.ts","../../src/mock/device/clipboard.ts","../../src/mock/device/contacts.ts","../../src/mock/device/location.ts","../../src/mock/proxy.ts","../../src/mock/device/storage.ts","../../src/panel/tabs/device.ts","../../src/panel/tabs/analytics.ts","../../src/panel/tabs/environment.ts","../../src/panel/tabs/events.ts","../../src/panel/tabs/iap.ts","../../src/panel/tabs/location.ts","../../src/panel/tabs/permissions.ts","../../src/panel/tabs/storage.ts","../../src/panel/tabs/index.ts","../../src/panel/index.ts"],"sourcesContent":["/**\n * @ait-co/devtools 중앙 상태 관리\n * DevTools Panel과 mock 구현체가 이 상태를 공유한다.\n */\n\nimport type {\n AnalyticsLogEntry,\n DeviceModes,\n IapNextResult,\n MockContact,\n MockData,\n MockIapProduct,\n MockLocation,\n NetworkStatus,\n OperationalEnvironment,\n PermissionName,\n PermissionStatus,\n PlatformOS,\n SafeAreaInsets,\n} from './types.js';\n\nexport type {\n AnalyticsLogEntry,\n DeviceApiMode,\n DeviceModes,\n HapticFeedbackType,\n IapNextResult,\n LocationCoords,\n MockContact,\n MockData,\n MockIapProduct,\n MockLocation,\n NetworkStatus,\n OperationalEnvironment,\n PermissionName,\n PermissionStatus,\n PlatformOS,\n SafeAreaInsets,\n} from './types.js';\n\ntype Listener = () => void;\n\nexport interface AitDevtoolsState {\n // 환경\n platform: PlatformOS;\n environment: OperationalEnvironment;\n appVersion: string;\n locale: string;\n schemeUri: string;\n groupId: string;\n deploymentId: string;\n deviceId: string;\n\n // 브랜드\n brand: {\n displayName: string;\n icon: string;\n primaryColor: string;\n };\n\n // 네트워크\n networkStatus: NetworkStatus;\n\n // 권한\n permissions: Record<PermissionName, PermissionStatus>;\n\n // 위치\n location: MockLocation;\n\n // Safe Area\n safeAreaInsets: SafeAreaInsets;\n\n // 연락처\n contacts: MockContact[];\n\n // IAP\n iap: {\n products: MockIapProduct[];\n nextResult: IapNextResult;\n pendingOrders: Array<{ orderId: string; sku: string; paymentCompletedDate: string }>;\n completedOrders: Array<{\n orderId: string;\n sku: string;\n status: 'COMPLETED' | 'REFUNDED';\n date: string;\n }>;\n };\n\n // 결제 (TossPay)\n payment: {\n nextResult: 'success' | 'fail';\n failReason: string;\n };\n\n // 로그인\n auth: {\n isLoggedIn: boolean;\n isTossLoginIntegrated: boolean;\n userKeyHash: string;\n };\n\n // 광고\n ads: {\n isLoaded: boolean;\n nextEvent:\n | 'loaded'\n | 'clicked'\n | 'dismissed'\n | 'failedToShow'\n | 'impression'\n | 'userEarnedReward';\n };\n\n // 게임\n game: {\n profile: { nickname: string; profileImageUri: string } | null;\n leaderboardScores: Array<{ score: string; timestamp: number }>;\n };\n\n // 분석 로그\n analyticsLog: AnalyticsLogEntry[];\n\n // 디바이스 API 모드\n deviceModes: DeviceModes;\n\n // mock 모드용 더미 데이터\n mockData: MockData;\n\n // mock 활성화 상태\n panelEditable: boolean;\n}\n\nconst DEFAULT_STATE: AitDevtoolsState = {\n platform: 'ios',\n environment: 'sandbox',\n appVersion: '5.240.0',\n locale: 'ko-KR',\n schemeUri: '/',\n groupId: 'mock-group-id',\n deploymentId: 'mock-deployment-id',\n deviceId: '',\n\n brand: {\n displayName: 'Mock App',\n icon: '',\n primaryColor: '#3182F6',\n },\n\n networkStatus: 'WIFI',\n\n permissions: {\n clipboard: 'allowed',\n contacts: 'allowed',\n photos: 'allowed',\n geolocation: 'allowed',\n camera: 'allowed',\n microphone: 'notDetermined',\n },\n\n location: {\n coords: {\n latitude: 37.5665,\n longitude: 126.978,\n altitude: 0,\n accuracy: 10,\n altitudeAccuracy: 0,\n heading: 0,\n },\n timestamp: Date.now(),\n accessLocation: 'FINE',\n },\n\n safeAreaInsets: { top: 47, bottom: 34, left: 0, right: 0 },\n\n contacts: [\n { name: '홍길동', phoneNumber: '010-1234-5678' },\n { name: '김토스', phoneNumber: '010-9876-5432' },\n ],\n\n iap: {\n products: [\n {\n sku: 'mock-gem-100',\n type: 'CONSUMABLE',\n displayName: '보석 100개',\n displayAmount: '1,000원',\n iconUrl: '',\n description: '게임에서 사용할 수 있는 보석 100개',\n },\n ],\n nextResult: 'success',\n pendingOrders: [],\n completedOrders: [],\n },\n\n payment: {\n nextResult: 'success',\n failReason: '',\n },\n\n auth: {\n isLoggedIn: true,\n isTossLoginIntegrated: true,\n userKeyHash: 'mock-user-hash-abc123',\n },\n\n ads: {\n isLoaded: false,\n nextEvent: 'loaded',\n },\n\n game: {\n profile: { nickname: 'MockPlayer', profileImageUri: '' },\n leaderboardScores: [],\n },\n\n analyticsLog: [],\n\n deviceModes: {\n camera: 'mock',\n photos: 'mock',\n location: 'mock',\n network: 'mock',\n // 'mock' so the clipboard mock is self-contained. With 'web' the mock\n // calls `navigator.clipboard.readText()` directly, which — when paired\n // with `@ait-co/polyfill` — recurses: polyfill routes `navigator.clipboard`\n // back to the SDK's `getClipboardText`, which is this mock, which calls\n // `navigator.clipboard.readText`, … Users who want true browser\n // clipboard integration can flip this to 'web' from the panel.\n clipboard: 'mock',\n },\n\n mockData: {\n images: [],\n clipboardText: '',\n },\n\n panelEditable: true,\n};\n\nfunction generateDeviceId(): string {\n const stored = localStorage.getItem('__ait_device_id');\n if (stored) return stored;\n const id = crypto.randomUUID();\n localStorage.setItem('__ait_device_id', id);\n return id;\n}\n\nexport class AitStateManager {\n private _state: AitDevtoolsState;\n private _listeners = new Set<Listener>();\n\n constructor() {\n this._state = structuredClone(DEFAULT_STATE);\n try {\n this._state.deviceId = generateDeviceId();\n } catch {\n this._state.deviceId = `mock-device-${Math.random().toString(36).slice(2)}`;\n }\n }\n\n get state(): AitDevtoolsState {\n return this._state;\n }\n\n update(partial: Partial<AitDevtoolsState>) {\n this._state = { ...this._state, ...partial };\n this._notify();\n }\n\n /** 중첩 객체 업데이트용 */\n patch<K extends keyof AitDevtoolsState>(key: K, partial: Partial<AitDevtoolsState[K]>) {\n const current = this._state[key];\n if (typeof current === 'object' && current !== null && !Array.isArray(current)) {\n this._state = {\n ...this._state,\n [key]: { ...(current as Record<string, unknown>), ...(partial as Record<string, unknown>) },\n };\n } else {\n this._state = { ...this._state, [key]: partial as AitDevtoolsState[K] };\n }\n this._notify();\n }\n\n subscribe(listener: Listener): () => void {\n this._listeners.add(listener);\n return () => this._listeners.delete(listener);\n }\n\n /** 분석 로그 추가 */\n logAnalytics(entry: Omit<AnalyticsLogEntry, 'timestamp'>) {\n this._state = {\n ...this._state,\n analyticsLog: [...this._state.analyticsLog, { ...entry, timestamp: Date.now() }],\n };\n this._notify();\n }\n\n /** 이벤트 트리거 (backEvent, homeEvent 등) */\n trigger(event: string) {\n window.dispatchEvent(new CustomEvent(`__ait:${event}`));\n }\n\n reset() {\n const deviceId = this._state.deviceId;\n this._state = { ...structuredClone(DEFAULT_STATE), deviceId };\n this._notify();\n }\n\n private _notify() {\n for (const listener of this._listeners) {\n listener();\n }\n }\n}\n\nexport const aitState = new AitStateManager();\n\n// 브라우저 콘솔에서 접근 가능하도록\nif (typeof window !== 'undefined') {\n window.__ait = aitState;\n}\n","/**\n * 공통 DOM 헬퍼 함수\n */\n\nexport function 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\nexport function 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\nexport function inputRow(\n label: string,\n value: string,\n onChange: (v: string) => void,\n disabled = false,\n): 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\nexport function monitoringNotice(): HTMLElement {\n return h(\n 'div',\n { className: 'ait-monitoring-notice' },\n 'Read-only — mock responses are controlled at build time.',\n );\n}\n","/**\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 .ait-panel-tab-error {\n padding: 12px;\n color: #e53e3e; /* readable on both light (#fff) and dark (#1a1a2e) panel backgrounds */\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 * 디바이스 모듈 내부 공유 헬퍼\n */\n\nimport { aitState } from '../state.js';\n\n// --- Placeholder Image Generator ---\n\nfunction generatePlaceholderImage(\n width: number,\n height: number,\n text: string,\n color: string,\n): string {\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n // jsdom 등 Canvas API 미지원 환경에서는 간단한 SVG data URI 반환\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\"><rect fill=\"${color}\" width=\"${width}\" height=\"${height}\"/><text x=\"50%\" y=\"50%\" fill=\"white\" font-size=\"16\" text-anchor=\"middle\" dominant-baseline=\"middle\">${text}</text></svg>`;\n return `data:image/svg+xml;base64,${btoa(svg)}`;\n }\n ctx.fillStyle = color;\n ctx.fillRect(0, 0, width, height);\n ctx.fillStyle = 'white';\n ctx.font = '16px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, width / 2, height / 2);\n return canvas.toDataURL('image/png');\n}\n\nconst DEFAULT_PLACEHOLDERS = [\n { text: 'Mock Photo 1', color: '#3182F6' },\n { text: 'Mock Photo 2', color: '#27ae60' },\n { text: 'Mock Photo 3', color: '#e67e22' },\n];\n\nlet cachedPlaceholders: string[] | null = null;\n\nexport function getDefaultPlaceholderImages(): string[] {\n if (!cachedPlaceholders) {\n cachedPlaceholders = DEFAULT_PLACEHOLDERS.map((p) =>\n generatePlaceholderImage(320, 240, p.text, p.color),\n );\n }\n return [...cachedPlaceholders];\n}\n\n/** @internal device 모듈 내부 전용 */\nexport function getMockImages(): string[] {\n const images = aitState.state.mockData.images;\n if (images.length > 0) return images;\n return getDefaultPlaceholderImages();\n}\n\n// --- Prompt Mode Helper ---\n\nconst PROMPT_TIMEOUT_MS = 30_000;\n\n/** @internal device 모듈 내부 전용 */\nexport function waitForPromptResponse<T>(type: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const eventName = `__ait:prompt-response:${type}`;\n const cancelName = '__ait:prompt-cancel';\n\n function cleanup() {\n clearTimeout(timer);\n window.removeEventListener(eventName, handler);\n window.removeEventListener(cancelName, cancelHandler);\n }\n\n const timer = setTimeout(() => {\n cleanup();\n const panelMounted = !!document.querySelector('.ait-panel');\n const hint = panelMounted\n ? 'Please provide input via the DevTools panel.'\n : 'Is @ait-co/devtools/panel imported?';\n reject(\n new Error(\n `[@ait-co/devtools] Prompt timeout for \"${type}\" after ${PROMPT_TIMEOUT_MS / 1000}s. ${hint}`,\n ),\n );\n }, PROMPT_TIMEOUT_MS);\n\n const handler = (e: Event) => {\n cleanup();\n resolve((e as CustomEvent).detail as T);\n };\n\n const cancelHandler = () => {\n cleanup();\n reject(new Error(`[@ait-co/devtools] Prompt cancelled for \"${type}\"`));\n };\n\n window.addEventListener(eventName, handler);\n window.addEventListener(cancelName, cancelHandler);\n window.dispatchEvent(new CustomEvent('__ait:prompt-request', { detail: { type } }));\n });\n}\n","/**\n * 권한 시스템 mock\n * 각 디바이스 API (.getPermission, .openPermissionDialog)에 부착된다.\n */\n\nimport { aitState } from './state.js';\nimport type { PermissionName, PermissionStatus } from './types.js';\n\nexport async function getPermission(name: PermissionName): Promise<PermissionStatus> {\n return aitState.state.permissions[name];\n}\n\nexport async function openPermissionDialog(name: PermissionName): Promise<'allowed' | 'denied'> {\n const current = aitState.state.permissions[name];\n if (current === 'allowed') return 'allowed';\n // notDetermined나 denied일 때 — Panel에서 설정된 값을 사용\n // 기본적으로는 allowed로 전환\n aitState.patch('permissions', { [name]: 'allowed' });\n return 'allowed';\n}\n\nexport async function requestPermission(permission: {\n name: PermissionName;\n access: string;\n}): Promise<'allowed' | 'denied'> {\n return openPermissionDialog(permission.name);\n}\n\n/** 권한이 필요한 함수에 .getPermission(), .openPermissionDialog()를 부착 */\nexport function withPermission<T extends (...args: never[]) => unknown>(\n fn: T,\n permissionName: PermissionName,\n): T & {\n getPermission: () => Promise<PermissionStatus>;\n openPermissionDialog: () => Promise<'allowed' | 'denied'>;\n} {\n const enhanced = fn as T & {\n getPermission: () => Promise<PermissionStatus>;\n openPermissionDialog: () => Promise<'allowed' | 'denied'>;\n };\n enhanced.getPermission = () => getPermission(permissionName);\n enhanced.openPermissionDialog = () => openPermissionDialog(permissionName);\n return enhanced;\n}\n\n/** 권한 체크 후 denied면 에러 throw */\nexport function checkPermission(name: PermissionName, fnName: string): void {\n const status = aitState.state.permissions[name];\n if (status === 'denied') {\n throw new Error(\n `[@ait-co/devtools] ${fnName}: Permission \"${name}\" is denied. Change it in the DevTools panel.`,\n );\n }\n}\n","/**\n * Camera & Album Photos mock\n * mock/web/prompt 모드 지원\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\nimport { getMockImages, waitForPromptResponse } from './_helpers.js';\n\n// --- Camera ---\n\nasync function openCameraMock(): Promise<{ id: string; dataUri: string }> {\n const images = getMockImages();\n return { id: crypto.randomUUID(), dataUri: images[0] };\n}\n\nasync function openCameraWeb(): Promise<{ id: string; dataUri: string }> {\n return new Promise((resolve, reject) => {\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = 'image/*';\n input.capture = 'environment';\n let settled = false;\n input.onchange = () => {\n settled = true;\n const file = input.files?.[0];\n if (!file) {\n reject(new Error('No file selected'));\n return;\n }\n const reader = new FileReader();\n reader.onload = () => resolve({ id: crypto.randomUUID(), dataUri: reader.result as string });\n reader.onerror = () => reject(new Error('Failed to read file'));\n reader.readAsDataURL(file);\n };\n // Detect file picker cancel via focus heuristic.\n // Note: unreliable on some mobile browsers and Safari where focus events differ.\n const onFocus = () => {\n setTimeout(() => {\n if (!settled) reject(new Error('File picker cancelled'));\n window.removeEventListener('focus', onFocus);\n }, 300);\n };\n window.addEventListener('focus', onFocus);\n input.click();\n });\n}\n\nasync function openCameraPrompt(): Promise<{ id: string; dataUri: string }> {\n const dataUri = await waitForPromptResponse<string>('camera');\n return { id: crypto.randomUUID(), dataUri };\n}\n\nconst _openCamera = async (_options?: {\n base64?: boolean;\n maxWidth?: number;\n}): Promise<{ id: string; dataUri: string }> => {\n checkPermission('camera', 'openCamera');\n const mode = aitState.state.deviceModes.camera;\n if (mode === 'web') return openCameraWeb();\n if (mode === 'prompt') return openCameraPrompt();\n return openCameraMock();\n};\nexport const openCamera = withPermission(_openCamera, 'camera');\n\n// --- Album Photos ---\n\nasync function fetchAlbumPhotosMock(\n maxCount: number,\n): Promise<Array<{ id: string; dataUri: string }>> {\n const images = getMockImages();\n return images.slice(0, maxCount).map((dataUri) => ({ id: crypto.randomUUID(), dataUri }));\n}\n\nasync function fetchAlbumPhotosWeb(\n maxCount: number,\n): Promise<Array<{ id: string; dataUri: string }>> {\n return new Promise((resolve, reject) => {\n const input = document.createElement('input');\n input.type = 'file';\n input.accept = 'image/*';\n input.multiple = true;\n let settled = false;\n input.onchange = async () => {\n settled = true;\n const files = Array.from(input.files ?? []).slice(0, maxCount);\n if (files.length === 0) {\n reject(new Error('No files selected'));\n return;\n }\n const results = await Promise.all(\n files.map(\n (file) =>\n new Promise<{ id: string; dataUri: string }>((res, rej) => {\n const reader = new FileReader();\n reader.onload = () =>\n res({ id: crypto.randomUUID(), dataUri: reader.result as string });\n reader.onerror = () => rej(new Error('Failed to read file'));\n reader.readAsDataURL(file);\n }),\n ),\n );\n resolve(results);\n };\n const onFocus = () => {\n setTimeout(() => {\n if (!settled) reject(new Error('File picker cancelled'));\n window.removeEventListener('focus', onFocus);\n }, 300);\n };\n window.addEventListener('focus', onFocus);\n input.click();\n });\n}\n\nasync function fetchAlbumPhotosPrompt(\n maxCount: number,\n): Promise<Array<{ id: string; dataUri: string }>> {\n const dataUris = await waitForPromptResponse<string[]>('photos');\n return dataUris.slice(0, maxCount).map((dataUri) => ({ id: crypto.randomUUID(), dataUri }));\n}\n\nconst _fetchAlbumPhotos = async (options?: {\n maxCount?: number;\n maxWidth?: number;\n base64?: boolean;\n}): Promise<Array<{ id: string; dataUri: string }>> => {\n checkPermission('photos', 'fetchAlbumPhotos');\n const maxCount = options?.maxCount ?? 10;\n const mode = aitState.state.deviceModes.photos;\n if (mode === 'web') return fetchAlbumPhotosWeb(maxCount);\n if (mode === 'prompt') return fetchAlbumPhotosPrompt(maxCount);\n return fetchAlbumPhotosMock(maxCount);\n};\nexport const fetchAlbumPhotos = withPermission(_fetchAlbumPhotos, 'photos');\n","/**\n * Clipboard mock\n * mock/web 모드 지원\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\n\nconst _getClipboardText = async (): Promise<string> => {\n checkPermission('clipboard', 'getClipboardText');\n const mode = aitState.state.deviceModes.clipboard;\n if (mode === 'mock') return aitState.state.mockData.clipboardText;\n // web mode (default)\n try {\n return await navigator.clipboard.readText();\n } catch {\n return '';\n }\n};\nexport const getClipboardText = withPermission(_getClipboardText, 'clipboard');\n\nconst _setClipboardText = async (text: string): Promise<void> => {\n checkPermission('clipboard', 'setClipboardText');\n const mode = aitState.state.deviceModes.clipboard;\n if (mode === 'mock') {\n aitState.patch('mockData', { clipboardText: text });\n return;\n }\n // web mode (default)\n await navigator.clipboard.writeText(text);\n};\nexport const setClipboardText = withPermission(_setClipboardText, 'clipboard');\n","/**\n * Contacts mock\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\n\nconst _fetchContacts = async (options: {\n size: number;\n offset: number;\n query?: { contains?: string };\n}) => {\n checkPermission('contacts', 'fetchContacts');\n let contacts = aitState.state.contacts;\n if (options.query?.contains) {\n const q = options.query.contains.toLowerCase();\n contacts = contacts.filter(\n (c) => c.name.toLowerCase().includes(q) || c.phoneNumber.includes(q),\n );\n }\n const sliced = contacts.slice(options.offset, options.offset + options.size);\n const nextOffset = options.offset + options.size;\n return {\n result: sliced,\n nextOffset: nextOffset < contacts.length ? nextOffset : null,\n done: nextOffset >= contacts.length,\n };\n};\nexport const fetchContacts = withPermission(_fetchContacts, 'contacts');\n","/**\n * Location mock (getCurrentLocation, startUpdateLocation)\n * mock/web/prompt 모드 지원\n */\n\nimport { checkPermission, withPermission } from '../permissions.js';\nimport { aitState } from '../state.js';\nimport type { MockLocation } from '../types.js';\nimport { waitForPromptResponse } from './_helpers.js';\n\nenum Accuracy {\n Lowest = 1,\n Low = 2,\n Balanced = 3,\n High = 4,\n Highest = 5,\n BestForNavigation = 6,\n}\n\nexport { Accuracy };\n\nfunction buildLocation(): MockLocation {\n return {\n coords: { ...aitState.state.location.coords },\n timestamp: Date.now(),\n accessLocation: aitState.state.location.accessLocation,\n };\n}\n\n// -- getCurrentLocation --\n\nasync function getCurrentLocationMock(): Promise<MockLocation> {\n return buildLocation();\n}\n\nasync function getCurrentLocationWeb(): Promise<MockLocation> {\n return new Promise((resolve) => {\n if (!navigator.geolocation) {\n console.warn('[@ait-co/devtools] Geolocation API not available, falling back to mock');\n resolve(buildLocation());\n return;\n }\n navigator.geolocation.getCurrentPosition(\n (pos) => {\n resolve({\n coords: {\n latitude: pos.coords.latitude,\n longitude: pos.coords.longitude,\n altitude: pos.coords.altitude ?? 0,\n accuracy: pos.coords.accuracy,\n altitudeAccuracy: pos.coords.altitudeAccuracy ?? 0,\n heading: pos.coords.heading ?? 0,\n },\n timestamp: pos.timestamp,\n accessLocation: 'FINE',\n });\n },\n () => {\n console.warn('[@ait-co/devtools] Geolocation failed, falling back to mock');\n resolve(buildLocation());\n },\n );\n });\n}\n\nasync function getCurrentLocationPrompt(): Promise<MockLocation> {\n return waitForPromptResponse<MockLocation>('location');\n}\n\nconst _getCurrentLocation = async (_options?: { accuracy: Accuracy }): Promise<MockLocation> => {\n checkPermission('geolocation', 'getCurrentLocation');\n const mode = aitState.state.deviceModes.location;\n if (mode === 'web') return getCurrentLocationWeb();\n if (mode === 'prompt') return getCurrentLocationPrompt();\n return getCurrentLocationMock();\n};\nexport const getCurrentLocation = withPermission(_getCurrentLocation, 'geolocation');\n\n// -- startUpdateLocation --\n\ninterface StartUpdateLocationEventParams {\n onEvent: (response: MockLocation) => void;\n onError: (error: unknown) => void;\n options: { accuracy: Accuracy; timeInterval: number; distanceInterval: number };\n}\n\nfunction startUpdateLocationMock(eventParams: StartUpdateLocationEventParams): () => void {\n const { onEvent, options } = eventParams;\n const interval = Math.max(options.timeInterval, 500);\n const id = setInterval(() => {\n const loc = buildLocation();\n loc.coords.latitude += (Math.random() - 0.5) * 0.0001;\n loc.coords.longitude += (Math.random() - 0.5) * 0.0001;\n onEvent(loc);\n }, interval);\n return () => clearInterval(id);\n}\n\nfunction startUpdateLocationWeb(eventParams: StartUpdateLocationEventParams): () => void {\n const { onEvent, onError } = eventParams;\n if (!navigator.geolocation) {\n console.warn('[@ait-co/devtools] Geolocation API not available, falling back to mock');\n return startUpdateLocationMock(eventParams);\n }\n const watchId = navigator.geolocation.watchPosition(\n (pos) => {\n onEvent({\n coords: {\n latitude: pos.coords.latitude,\n longitude: pos.coords.longitude,\n altitude: pos.coords.altitude ?? 0,\n accuracy: pos.coords.accuracy,\n altitudeAccuracy: pos.coords.altitudeAccuracy ?? 0,\n heading: pos.coords.heading ?? 0,\n },\n timestamp: pos.timestamp,\n accessLocation: 'FINE',\n });\n },\n (err) => onError(err),\n );\n return () => navigator.geolocation.clearWatch(watchId);\n}\n\nfunction startUpdateLocationPrompt(eventParams: StartUpdateLocationEventParams): () => void {\n const { onEvent } = eventParams;\n const handler = (e: Event) => {\n onEvent((e as CustomEvent).detail as MockLocation);\n };\n window.addEventListener('__ait:prompt-response:location-update', handler);\n window.dispatchEvent(\n new CustomEvent('__ait:prompt-request', { detail: { type: 'location-update' } }),\n );\n return () => window.removeEventListener('__ait:prompt-response:location-update', handler);\n}\n\nconst _startUpdateLocation = (eventParams: StartUpdateLocationEventParams): (() => void) => {\n const mode = aitState.state.deviceModes.location;\n if (mode === 'web') return startUpdateLocationWeb(eventParams);\n if (mode === 'prompt') return startUpdateLocationPrompt(eventParams);\n return startUpdateLocationMock(eventParams);\n};\nexport const startUpdateLocation = withPermission(_startUpdateLocation, 'geolocation');\n","/**\n * 미구현 API용 Proxy 트립와이어.\n *\n * 미구현 프로퍼티에 접근하면 throw한다. 이는 \"devtools에서는 멀쩡히 돌지만\n * 실 SDK에선 실제로 동작하는\" 시나리오를 차단하기 위한 의도적 선택이다.\n * mock이 미구현인 API는 실 SDK에서는 존재할 수 있고, 사용자가 이를 인지하지\n * 못한 채 개발을 이어가면 배포 시점에 놀라게 된다. 에러 메시지에 이슈 URL을\n * 포함해 사용자가 mock 누락을 제보할 수 있게 한다.\n */\n\nconst ISSUES_URL = 'https://github.com/apps-in-toss-community/devtools/issues';\n\nexport function createMockProxy<T extends Record<string, unknown>>(\n moduleName: string,\n implementations: T,\n): T {\n return new Proxy(implementations, {\n get(target, prop) {\n // 심볼 접근(Symbol.toPrimitive, Symbol.iterator 등)은 프레임워크/런타임이\n // 내부적으로 호출하므로 throw하면 console.log, 구조분해 등이 깨진다.\n if (typeof prop === 'symbol') return undefined;\n if (prop in target) return target[prop];\n\n throw new Error(\n `[@ait-co/devtools] ${moduleName}.${prop} is not mocked. ` +\n `This API may exist in @apps-in-toss/web-framework, ` +\n `but devtools' mock does not cover it yet. ` +\n `Please file an issue: ${ISSUES_URL}`,\n );\n },\n }) as T;\n}\n","/**\n * Storage mock\n * localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리\n */\n\nimport { createMockProxy } from '../proxy.js';\n\nexport const Storage = createMockProxy('Storage', {\n getItem: async (key: string): Promise<string | null> => {\n return localStorage.getItem(`__ait_storage:${key}`);\n },\n setItem: async (key: string, value: string): Promise<void> => {\n localStorage.setItem(`__ait_storage:${key}`, value);\n },\n removeItem: async (key: string): Promise<void> => {\n localStorage.removeItem(`__ait_storage:${key}`);\n },\n clearItems: async (): Promise<void> => {\n const keys = Object.keys(localStorage).filter((k) => k.startsWith('__ait_storage:'));\n for (const k of keys) {\n localStorage.removeItem(k);\n }\n },\n});\n","import { getDefaultPlaceholderImages } from '../../mock/device/index.js';\nimport { aitState } from '../../mock/state.js';\nimport { h, monitoringNotice, selectRow } from '../helpers.js';\n\n// --- Prompt mode state ---\ninterface PendingPrompt {\n type: string;\n}\nlet pendingPrompt: PendingPrompt | null = null;\n\nlet refreshPanel: () => void = () => {};\n\nexport function setDeviceRefreshPanel(fn: () => void) {\n refreshPanel = fn;\n}\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 — handled by index.ts listener which also calls refreshPanel\n window.dispatchEvent(new CustomEvent('__ait:panel-switch-tab', { detail: { tab: 'device' } }));\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(h('div', { className: 'ait-prompt-title' }, 'Camera Prompt — Select an image'));\n const input = h('input', {\n type: 'file',\n accept: 'image/*',\n style: 'font-size:11px;color:#aaa',\n });\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(h('div', { className: 'ait-prompt-title' }, 'Photos Prompt — Select images'));\n const input = h('input', {\n type: 'file',\n accept: 'image/*',\n multiple: '',\n style: 'font-size:11px;color:#aaa',\n });\n input.addEventListener('change', () => {\n const files = Array.from((input as HTMLInputElement).files ?? []);\n if (files.length === 0) return;\n Promise.all(\n files.map(\n (file) =>\n new Promise<string>((res) => {\n const reader = new FileReader();\n reader.onload = () => res(reader.result as string);\n reader.readAsDataURL(file);\n }),\n ),\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(\n 'div',\n { className: 'ait-prompt-title' },\n pendingPrompt.type === 'location'\n ? 'Location Prompt — Enter coordinates'\n : 'Location Update — Send coordinates',\n ),\n );\n const latInput = h('input', {\n className: 'ait-input',\n value: String(aitState.state.location.coords.latitude),\n style: 'width:80px',\n });\n const lngInput = h('input', {\n className: 'ait-input',\n value: String(aitState.state.location.coords.longitude),\n style: 'width:80px',\n });\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(\n 'div',\n { className: 'ait-prompt-input-row' },\n h('label', {}, 'Lat'),\n latInput,\n h('label', {}, 'Lng'),\n lngInput,\n sendBtn,\n ),\n );\n } else {\n // Fallback for unknown prompt types\n banner.append(h('div', { className: 'ait-prompt-title' }, `Prompt: ${pendingPrompt.type}`));\n }\n\n // Cancel button for all prompt types\n const cancelBtn = h(\n 'button',\n { className: 'ait-btn ait-btn-sm ait-btn-danger', style: 'margin-top:8px' },\n 'Cancel',\n );\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\nexport function 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 [\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(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Device API Modes'),\n ...modeEntries.map((entry) =>\n selectRow(\n entry.label,\n entry.options,\n s.deviceModes[entry.key],\n (v) => {\n aitState.patch('deviceModes', { [entry.key]: v } as Partial<typeof s.deviceModes>);\n },\n disabled,\n ),\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 });\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(\n files.map(\n (file) =>\n new Promise<string>((res) => {\n const reader = new FileReader();\n reader.onload = () => res(reader.result as string);\n reader.readAsDataURL(file);\n }),\n ),\n ).then((dataUris) => {\n aitState.patch('mockData', { images: [...aitState.state.mockData.images, ...dataUris] });\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 });\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 });\n if (disabled) clearImagesBtn.disabled = true;\n\n container.append(\n h(\n 'div',\n { 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","import { aitState } from '../../mock/state.js';\nimport { h, monitoringNotice } from '../helpers.js';\n\nexport function 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.update({ analyticsLog: [] });\n });\n\n container.append(\n h(\n 'div',\n { className: 'ait-section' },\n h(\n 'div',\n { className: 'ait-row' },\n h('div', { className: 'ait-section-title' }, `Analytics Log (${logs.length})`),\n clearBtn,\n ),\n ...logs\n .slice(-30)\n .reverse()\n .map((entry) => {\n const time = new Date(entry.timestamp).toLocaleTimeString('ko-KR', { hour12: false });\n return h(\n 'div',\n { 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","import { aitState } from '../../mock/state.js';\nimport type { NetworkStatus, OperationalEnvironment, PlatformOS } from '../../mock/types.js';\nimport { h, inputRow, monitoringNotice, selectRow } from '../helpers.js';\n\nexport function renderEnvironmentTab(): 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(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Platform'),\n selectRow(\n 'OS',\n ['ios', 'android'],\n s.platform,\n (v) => aitState.update({ platform: v as PlatformOS }),\n disabled,\n ),\n inputRow('App Version', s.appVersion, (v) => aitState.update({ appVersion: v }), disabled),\n selectRow(\n 'Environment',\n ['toss', 'sandbox'],\n s.environment,\n (v) => aitState.update({ environment: v as OperationalEnvironment }),\n disabled,\n ),\n inputRow('Locale', s.locale, (v) => aitState.update({ locale: v }), disabled),\n ),\n h(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Network'),\n selectRow(\n 'Status',\n ['WIFI', '4G', '5G', '3G', '2G', 'OFFLINE', 'WWAN', 'UNKNOWN'],\n s.networkStatus,\n (v) => aitState.update({ networkStatus: v as NetworkStatus }),\n disabled,\n ),\n ),\n h(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Safe Area Insets'),\n inputRow(\n 'Top',\n String(s.safeAreaInsets.top),\n (v) => aitState.patch('safeAreaInsets', { top: Number(v) }),\n disabled,\n ),\n inputRow(\n 'Bottom',\n String(s.safeAreaInsets.bottom),\n (v) => aitState.patch('safeAreaInsets', { bottom: Number(v) }),\n disabled,\n ),\n ),\n );\n return container;\n}\n","import { aitState } from '../../mock/state.js';\nimport { h, monitoringNotice, selectRow } from '../helpers.js';\n\nexport function 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(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Navigation Events'),\n h('div', { className: 'ait-row' }, backBtn, homeBtn),\n ),\n h(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Login'),\n selectRow(\n 'Logged In',\n ['true', 'false'],\n String(aitState.state.auth.isLoggedIn),\n (v) => {\n aitState.patch('auth', { isLoggedIn: v === 'true' });\n },\n disabled,\n ),\n selectRow(\n 'Toss Login Integrated',\n ['true', 'false'],\n String(aitState.state.auth.isTossLoginIntegrated),\n (v) => {\n aitState.patch('auth', { isTossLoginIntegrated: v === 'true' });\n },\n disabled,\n ),\n ),\n );\n return container;\n}\n","import { aitState } from '../../mock/state.js';\nimport type { IapNextResult } from '../../mock/types.js';\nimport { h, monitoringNotice, selectRow } from '../helpers.js';\n\nexport function renderIapTab(): HTMLElement {\n const s = aitState.state;\n const disabled = !s.panelEditable;\n const container = h('div');\n const results: IapNextResult[] = [\n 'success',\n 'USER_CANCELED',\n 'INVALID_PRODUCT_ID',\n 'PAYMENT_PENDING',\n 'NETWORK_ERROR',\n 'ITEM_ALREADY_OWNED',\n 'INTERNAL_ERROR',\n ];\n\n if (disabled) container.appendChild(monitoringNotice());\n\n container.append(\n h(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'IAP Simulator'),\n selectRow(\n 'Next Purchase Result',\n results,\n s.iap.nextResult,\n (v) => {\n aitState.patch('iap', { nextResult: v as IapNextResult });\n },\n disabled,\n ),\n ),\n h(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'TossPay'),\n selectRow(\n 'Next Payment Result',\n ['success', 'fail'],\n s.payment.nextResult,\n (v) => {\n aitState.patch('payment', { nextResult: v as 'success' | 'fail' });\n },\n disabled,\n ),\n ),\n h(\n 'div',\n { className: 'ait-section' },\n h(\n 'div',\n { className: 'ait-section-title' },\n `Completed Orders (${s.iap.completedOrders.length})`,\n ),\n ...s.iap.completedOrders\n .slice(-5)\n .map((o) =>\n h(\n 'div',\n { 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","import { aitState } from '../../mock/state.js';\nimport { h, inputRow, monitoringNotice } from '../helpers.js';\n\nexport function 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(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Current Location'),\n inputRow(\n 'Latitude',\n String(s.location.coords.latitude),\n (v) => {\n const coords = { ...s.location.coords, latitude: Number(v) };\n aitState.patch('location', { coords } as Partial<typeof s.location>);\n },\n disabled,\n ),\n inputRow(\n 'Longitude',\n String(s.location.coords.longitude),\n (v) => {\n const coords = { ...s.location.coords, longitude: Number(v) };\n aitState.patch('location', { coords } as Partial<typeof s.location>);\n },\n disabled,\n ),\n inputRow(\n 'Accuracy',\n String(s.location.coords.accuracy),\n (v) => {\n const coords = { ...s.location.coords, accuracy: Number(v) };\n aitState.patch('location', { coords } as Partial<typeof s.location>);\n },\n disabled,\n ),\n ),\n );\n return container;\n}\n","import { aitState } from '../../mock/state.js';\nimport type { PermissionName, PermissionStatus } from '../../mock/types.js';\nimport { h, monitoringNotice, selectRow } from '../helpers.js';\n\nexport function renderPermissionsTab(): HTMLElement {\n const s = aitState.state;\n const disabled = !s.panelEditable;\n const container = h('div');\n const names: PermissionName[] = [\n 'camera',\n 'photos',\n 'geolocation',\n 'clipboard',\n 'contacts',\n 'microphone',\n ];\n const statuses: PermissionStatus[] = ['allowed', 'denied', 'notDetermined'];\n\n if (disabled) container.appendChild(monitoringNotice());\n\n container.append(\n h(\n 'div',\n { className: 'ait-section' },\n h('div', { className: 'ait-section-title' }, 'Device Permissions'),\n ...names.map((name) =>\n selectRow(\n name,\n statuses,\n s.permissions[name],\n (v) => {\n aitState.patch('permissions', { [name]: v as PermissionStatus });\n },\n disabled,\n ),\n ),\n ),\n );\n return container;\n}\n","import { aitState } from '../../mock/state.js';\nimport { h, monitoringNotice } from '../helpers.js';\n\nexport function renderStorageTab(refreshPanel: () => void): 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 for (const [key] of entries) {\n localStorage.removeItem(prefix + key);\n }\n refreshPanel();\n });\n\n container.append(\n h(\n 'div',\n { className: 'ait-section' },\n h(\n 'div',\n { 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(\n 'div',\n {},\n ...entries.map(([key, value]) =>\n h(\n 'div',\n { className: 'ait-storage-row' },\n h('span', { className: 'ait-storage-key' }, key),\n h(\n 'span',\n { className: 'ait-storage-value' },\n value.length > 100 ? `${value.slice(0, 100)}...` : value,\n ),\n ),\n ),\n ),\n ),\n );\n return container;\n}\n","import { renderAnalyticsTab } from './analytics.js';\nimport { renderDeviceTab } from './device.js';\nimport { renderEnvironmentTab } from './environment.js';\nimport { renderEventsTab } from './events.js';\nimport { renderIapTab } from './iap.js';\nimport { renderLocationTab } from './location.js';\nimport { renderPermissionsTab } from './permissions.js';\nimport { renderStorageTab } from './storage.js';\n\nexport type TabId =\n | 'env'\n | 'permissions'\n | 'location'\n | 'iap'\n | 'events'\n | 'analytics'\n | 'storage'\n | 'device';\n\nexport const 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\n// storage tab receives refreshPanel because its clear button modifies localStorage\n// directly (not aitState), so it must trigger a re-render explicitly.\n// device tab uses setDeviceRefreshPanel() for prompt-related local state (pendingPrompt);\n// its aitState mutations are auto-refreshed via the subscription in index.ts.\n// Other tabs only modify aitState or use input controls that reflect changes immediately.\nexport function createTabRenderers(refreshPanel: () => void): Record<TabId, () => HTMLElement> {\n return {\n env: renderEnvironmentTab,\n permissions: renderPermissionsTab,\n location: renderLocationTab,\n device: renderDeviceTab,\n iap: renderIapTab,\n events: renderEventsTab,\n analytics: renderAnalyticsTab,\n storage: () => renderStorageTab(refreshPanel),\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 { h } from './helpers.js';\nimport { PANEL_HEIGHT, PANEL_STYLES, PANEL_WIDTH } from './styles.js';\nimport { setDeviceRefreshPanel } from './tabs/device.js';\nimport { createTabRenderers, TABS, type TabId } from './tabs/index.js';\n\n// --- Draggable toggle button ---\n\nfunction makeDraggable(el: HTMLElement, onClickOnly: () => void) {\n let isDragging = false;\n let startX = 0,\n startY = 0;\n let startLeft = 0,\n 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(\n '__ait_btn_pos',\n 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\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 {\n /* ignore */\n }\n } else {\n el.style.bottom = '16px';\n el.style.right = '16px';\n }\n}\n\n// --- Mount ---\n\nlet currentTab: TabId = 'env';\nlet isOpen = false;\nlet panelEl: HTMLElement | null = null;\nlet bodyEl: HTMLElement | null = null;\nlet tabsEl: HTMLElement | null = null;\n\n// Lazy-initialized after refreshPanel is defined\nlet tabRenderers: Record<TabId, () => HTMLElement> | null = null;\n\nfunction refreshPanel() {\n if (!bodyEl || !tabsEl) return;\n if (!tabRenderers) tabRenderers = createTabRenderers(refreshPanel);\n bodyEl.innerHTML = '';\n try {\n bodyEl.appendChild(tabRenderers[currentTab]());\n } catch (err) {\n console.error(`[@ait-co/devtools] Error rendering tab \"${currentTab}\":`, err);\n bodyEl.appendChild(\n h('div', { className: 'ait-panel-tab-error' }, `Error rendering \"${currentTab}\" tab.`),\n );\n }\n\n tabsEl.querySelectorAll('.ait-panel-tab').forEach((el) => {\n el.classList.toggle('active', el.getAttribute('data-tab') === currentTab);\n });\n}\n\n// Listen for tab switch requests from device tab (prompt auto-open)\nif (typeof window !== 'undefined') {\n window.addEventListener('__ait:panel-switch-tab', (e: Event) => {\n const detail = (e as CustomEvent).detail as { tab: TabId };\n currentTab = detail.tab;\n if (panelEl && !panelEl.classList.contains('open')) {\n isOpen = true;\n panelEl.classList.add('open');\n }\n refreshPanel();\n });\n}\n\nfunction mount() {\n if (typeof document === 'undefined') return;\n if (document.querySelector('.ait-panel-toggle')) return;\n\n // Wire up device tab's refreshPanel reference\n setDeviceRefreshPanel(refreshPanel);\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 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(\n 'span',\n {\n className: `ait-mock-badge ${aitState.state.panelEditable ? 'ait-mock-badge-on' : 'ait-mock-badge-off'}`,\n title: 'Toggle panel edit mode',\n },\n aitState.state.panelEditable ? 'EDIT' : 'READ-ONLY',\n );\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(\n 'span',\n { 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(\n 'div',\n { 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 // Defense-in-depth: outer catch complements refreshPanel's inner tab-rendering catch.\n aitState.subscribe(() => {\n try {\n if (\n isOpen &&\n (currentTab === 'analytics' || currentTab === 'storage' || currentTab === 'device')\n ) {\n refreshPanel();\n }\n } catch (err) {\n console.error('[@ait-co/devtools] Error in subscribe callback:', err);\n }\n });\n\n refreshPanel();\n}\n\n// DOM ready 시 마운트\nif (typeof document !== 'undefined') {\n const safeMount = () => {\n try {\n mount();\n } catch (err) {\n console.error('[@ait-co/devtools] Failed to mount panel:', err);\n }\n };\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', safeMount);\n } else {\n safeMount();\n }\n}\n\nexport { mount };\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ait-co/devtools",
3
- "version": "0.1.1",
3
+ "version": "0.1.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
  "engines": {