database-devtools 0.1.0

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.
Files changed (94) hide show
  1. package/LICENSE +5 -0
  2. package/dist/adapter/index.cjs +314 -0
  3. package/dist/adapter/index.cjs.map +1 -0
  4. package/dist/adapter/index.d.cts +34 -0
  5. package/dist/adapter/index.d.ts +34 -0
  6. package/dist/adapter/index.js +6 -0
  7. package/dist/adapter/index.js.map +1 -0
  8. package/dist/adapter-BjJm71wW.d.cts +30 -0
  9. package/dist/adapter-DJSjDewg.d.ts +30 -0
  10. package/dist/adapters/sqlite/index.cjs +251 -0
  11. package/dist/adapters/sqlite/index.cjs.map +1 -0
  12. package/dist/adapters/sqlite/index.d.cts +21 -0
  13. package/dist/adapters/sqlite/index.d.ts +21 -0
  14. package/dist/adapters/sqlite/index.js +6 -0
  15. package/dist/adapters/sqlite/index.js.map +1 -0
  16. package/dist/chunk-2JGL2JVD.js +52 -0
  17. package/dist/chunk-2JGL2JVD.js.map +1 -0
  18. package/dist/chunk-AZECU6D7.js +27 -0
  19. package/dist/chunk-AZECU6D7.js.map +1 -0
  20. package/dist/chunk-BLOSGEQV.js +71 -0
  21. package/dist/chunk-BLOSGEQV.js.map +1 -0
  22. package/dist/chunk-CPVVIH5G.js +258 -0
  23. package/dist/chunk-CPVVIH5G.js.map +1 -0
  24. package/dist/chunk-DGUM43GV.js +10 -0
  25. package/dist/chunk-DGUM43GV.js.map +1 -0
  26. package/dist/chunk-HIDZTOJ3.js +9 -0
  27. package/dist/chunk-HIDZTOJ3.js.map +1 -0
  28. package/dist/chunk-I65IM47D.js +243 -0
  29. package/dist/chunk-I65IM47D.js.map +1 -0
  30. package/dist/chunk-MXVIGMVT.js +3 -0
  31. package/dist/chunk-MXVIGMVT.js.map +1 -0
  32. package/dist/chunk-O6AO7KHA.js +3 -0
  33. package/dist/chunk-O6AO7KHA.js.map +1 -0
  34. package/dist/chunk-TNDOAHT5.js +1784 -0
  35. package/dist/chunk-TNDOAHT5.js.map +1 -0
  36. package/dist/chunk-ZS5MZR75.js +655 -0
  37. package/dist/chunk-ZS5MZR75.js.map +1 -0
  38. package/dist/cli.cjs +2053 -0
  39. package/dist/cli.cjs.map +1 -0
  40. package/dist/client/index.cjs +947 -0
  41. package/dist/client/index.cjs.map +1 -0
  42. package/dist/client/index.d.cts +75 -0
  43. package/dist/client/index.d.ts +75 -0
  44. package/dist/client/index.js +98 -0
  45. package/dist/client/index.js.map +1 -0
  46. package/dist/createDevToolsServer-B7NQ_5H4.d.cts +292 -0
  47. package/dist/createDevToolsServer-DlNMoCJR.d.ts +292 -0
  48. package/dist/handleDeviceSnapshot-CR-4QMdk.d.ts +116 -0
  49. package/dist/handleDeviceSnapshot-cYGuitSc.d.cts +116 -0
  50. package/dist/index.cjs +5877 -0
  51. package/dist/index.cjs.map +1 -0
  52. package/dist/index.d.cts +61 -0
  53. package/dist/index.d.ts +61 -0
  54. package/dist/index.js +2748 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/inspector/index.cjs +57 -0
  57. package/dist/inspector/index.cjs.map +1 -0
  58. package/dist/inspector/index.d.cts +26 -0
  59. package/dist/inspector/index.d.ts +26 -0
  60. package/dist/inspector/index.js +5 -0
  61. package/dist/inspector/index.js.map +1 -0
  62. package/dist/inspectors/sqlite/index.cjs +306 -0
  63. package/dist/inspectors/sqlite/index.cjs.map +1 -0
  64. package/dist/inspectors/sqlite/index.d.cts +53 -0
  65. package/dist/inspectors/sqlite/index.d.ts +53 -0
  66. package/dist/inspectors/sqlite/index.js +260 -0
  67. package/dist/inspectors/sqlite/index.js.map +1 -0
  68. package/dist/register-BuicFu9L.d.cts +32 -0
  69. package/dist/register-aITLN9Q9.d.ts +32 -0
  70. package/dist/server/index.cjs +1948 -0
  71. package/dist/server/index.cjs.map +1 -0
  72. package/dist/server/index.d.cts +15 -0
  73. package/dist/server/index.d.ts +15 -0
  74. package/dist/server/index.js +7 -0
  75. package/dist/server/index.js.map +1 -0
  76. package/dist/snapshot-Dhyecgo2.d.cts +33 -0
  77. package/dist/snapshot-Dhyecgo2.d.ts +33 -0
  78. package/dist/types/protocol.cjs +309 -0
  79. package/dist/types/protocol.cjs.map +1 -0
  80. package/dist/types/protocol.d.cts +291 -0
  81. package/dist/types/protocol.d.ts +291 -0
  82. package/dist/types/protocol.js +4 -0
  83. package/dist/types/protocol.js.map +1 -0
  84. package/dist/types-BRLJdBRY.d.cts +16 -0
  85. package/dist/types-CF6qEU-_.d.ts +16 -0
  86. package/dist/types-CIA11diJ.d.cts +62 -0
  87. package/dist/types-CKVRCX-e.d.ts +62 -0
  88. package/dist/web/assets/index-CLEaIsUd.css +1 -0
  89. package/dist/web/assets/index-DQrPRTOy.js +100 -0
  90. package/dist/web/assets/sql-wasm-UFUCzYNW.wasm +0 -0
  91. package/dist/web/index.html +26 -0
  92. package/dist/write-C3toEIMs.d.cts +21 -0
  93. package/dist/write-C3toEIMs.d.ts +21 -0
  94. package/package.json +137 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types/protocol.ts","../../src/utils/ids.ts","../../src/utils/reconnect.ts","../../src/client/createDevToolsClient.ts","../../src/client/fetchSnapshot.ts","../../src/client/resolveDeviceDatabaseUrl.ts","../../src/client/deviceDatabase.ts","../../src/client/resolveProjectDatabaseUrl.ts","../../src/client/projectDatabase.ts","../../src/client/resolveSnapshotDownloadUrl.ts","../../src/client/formatSyncError.ts","../../src/utils/deviceLabel.ts","../../src/utils/resolvePreferredDeviceId.ts","../../src/types/snapshot.ts","../../src/client/snapshotUpload.ts","../../src/client/handleDeviceSnapshot.ts"],"names":["resolveApiBase"],"mappings":";;;AAGO,IAAM,YAAA,GAAe;AAAA,EAC1B,MAAA,EAAQ,QAAA;AAAA,EACR,OAAA,EAAS;AACX,CAAA;AAKO,IAAM,WAAA,GAAc;AAAA,EACzB,QAAA,EAAU,UAAA;AAAA,EACV,IAAA,EAAM,MAAA;AAAA,EACN,IAAA,EAAM,MAAA;AAAA,EACN,aAAA,EAAe,cAAA;AAAA,EAEf,eAAA,EAAiB,gBAAA;AAAA,EACjB,yBAAA,EAA2B,yBAAA;AAAA,EAC3B,cAAA,EAAgB,eAAA;AAAA,EAChB,cAAA,EAAgB,eAAA;AAAA,EAChB,aAAA,EAAe,cAAA;AAAA,EACf,uBAAA,EAAyB,uBAAA;AAAA,EACzB,qBAAA,EAAuB,qBAAA;AAAA,EACvB,yBAAA,EAA2B,yBAAA;AAAA,EAC3B,0BAAA,EAA4B,0BAAA;AAAA,EAC5B,4BAAA,EAA8B,4BAAA;AAAA,EAC9B,aAAA,EAAe,cAAA;AAAA,EACf,iBAAA,EAAmB,kBAAA;AAAA,EACnB,kBAAA,EAAoB,mBAAA;AAAA,EACpB,oBAAA,EAAsB,qBAAA;AAAA,EACtB,aAAA,EAAe,cAAA;AAAA,EACf,eAAA,EAAiB,gBAAA;AAAA,EACjB,SAAA,EAAW,UAAA;AAAA,EACX,kBAAA,EAAoB,mBAAA;AAAA,EACpB,YAAA,EAAc,aAAA;AAAA,EACd,WAAA,EAAa;AACf,CAAA;AAySO,IAAM,gBAAA,GAAmB,KAAA;AAEzB,IAAM,qBAAA,GAAwB,IAAA;AAQ9B,IAAM,wBAAA,GAA2B,cAAA;AAEjC,IAAM,yBAAA,GAA4B,uBAAA;AAElC,IAAM,8BAAA,GAAiC,4BAAA;AAEvC,IAAM,0BAAA,GAA6B,wBAAA;AAEnC,IAAM,+BAAA,GAAkC,sBAAA;AA2BxC,SAAS,kBAAA,CACd,IAAA,GAAO,WAAA,EACP,IAAA,GAAO,qBAAA,EACC;AACR,EAAA,OAAO,CAAA,KAAA,EAAQ,IAAI,CAAA,CAAA,EAAI,IAAI,GAAG,gBAAgB,CAAA,CAAA;AAChD;AAEO,SAAS,sBAAA,CAAuB,aAAqB,QAAA,EAA0B;AACpF,EAAA,MAAM,IAAA,GAAO,WAAA,CAAY,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAC1C,EAAA,OAAO,GAAG,IAAI,CAAA,EAAG,wBAAwB,CAAA,CAAA,EAAI,kBAAA,CAAmB,QAAQ,CAAC,CAAA,SAAA,CAAA;AAC3E;AAOO,SAAS,eAAe,KAAA,EAAuB;AACpD,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,KAAK,CAAA;AACzB,EAAA,GAAA,CAAI,QAAA,GAAW,GAAA,CAAI,QAAA,KAAa,MAAA,GAAS,QAAA,GAAW,OAAA;AACpD,EAAA,GAAA,CAAI,QAAA,GAAW,EAAA;AACf,EAAA,GAAA,CAAI,MAAA,GAAS,EAAA;AACb,EAAA,GAAA,CAAI,IAAA,GAAO,EAAA;AACX,EAAA,OAAO,GAAA,CAAI,QAAA,EAAS,CAAE,OAAA,CAAQ,OAAO,EAAE,CAAA;AACzC;AAEA,SAAS,eAAe,KAAA,EAA2C;AACjE,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,UAAU,IAAA,IAAQ,OAAQ,MAA4B,IAAA,KAAS,QAAA;AACrG;AA+BO,SAAS,iCACd,KAAA,EACyC;AACzC,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,yBAAA,EAA2B;AAClF,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OAAO,OAAO,OAAA,CAAQ,QAAA,KAAa,QAAA,IAAY,QAAQ,WAAA,KAAgB,UAAA;AACzE;AAEO,SAAS,uBAAuB,KAAA,EAA+C;AACpF,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,cAAA,EAAgB;AACvE,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OAAO,OAAO,OAAA,CAAQ,QAAA,KAAa,QAAA,IAAY,OAAO,QAAQ,KAAA,KAAU,QAAA;AAC1E;AAEO,SAAS,uBAAuB,KAAA,EAA+C;AACpF,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,cAAA,EAAgB;AACvE,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OACE,OAAO,OAAA,CAAQ,QAAA,KAAa,YAC5B,OAAO,OAAA,CAAQ,SAAS,QAAA,IACxB,OAAO,OAAA,CAAQ,UAAA,KAAe,YAC9B,OAAO,OAAA,CAAQ,SAAS,QAAA,IACxB,OAAO,QAAQ,QAAA,KAAa,QAAA;AAEhC;AAEO,SAAS,sBAAsB,KAAA,EAA8C;AAClF,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,aAAA,EAAe;AACtE,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OAAO,OAAO,OAAA,CAAQ,QAAA,KAAa,QAAA,IAAY,OAAO,QAAQ,IAAA,KAAS,QAAA;AACzE;AAaO,SAAS,6BACd,KAAA,EACqC;AACrC,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,qBAAA,EAAuB;AAC9E,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OAAO,OAAO,OAAA,CAAQ,IAAA,KAAS,QAAA,IAAY,OAAO,QAAQ,OAAA,KAAY,QAAA;AACxE;AA2FO,SAAS,cAAc,KAAA,EAAsC;AAClE,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,IAAA,EAAM;AAC7D,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OAAO,OAAO,QAAQ,MAAA,KAAW,QAAA;AACnC;AAEO,SAAS,sBAAsB,KAAA,EAA8C;AAClF,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,aAAA,EAAe;AACtE,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OAAO,OAAO,OAAA,CAAQ,OAAA,KAAY,QAAA,IAAY,QAAQ,OAAA,KAAY,IAAA;AACpE;AAUO,SAAS,0BAA0B,KAAA,EAAkD;AAC1F,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,iBAAA,EAAmB;AAC1E,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OAAO,OAAO,QAAQ,aAAA,KAAkB,QAAA;AAC1C;AAEO,SAAS,2BAA2B,KAAA,EAAmD;AAC5F,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,kBAAA,EAAoB;AAC3E,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OAAO,OAAO,QAAQ,aAAA,KAAkB,QAAA;AAC1C;AAEO,SAAS,6BAA6B,KAAA,EAAqD;AAChG,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,oBAAA,EAAsB;AAC7E,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OAAO,OAAO,QAAQ,aAAA,KAAkB,QAAA;AAC1C;AAEO,SAAS,sBAAsB,KAAA,EAA8C;AAClF,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,aAAA,EAAe;AACtE,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OACE,OAAO,OAAA,CAAQ,OAAA,KAAY,QAAA,IAC3B,OAAO,OAAA,CAAQ,aAAA,KAAkB,QAAA,IACjC,OAAO,OAAA,CAAQ,SAAA,KAAc,QAAA,IAC7B,QAAQ,SAAA,KAAc,IAAA;AAE1B;AAEO,SAAS,2BAA2B,KAAA,EAAmD;AAC5F,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,kBAAA,EAAoB;AAC3E,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OACE,OAAO,OAAA,CAAQ,aAAA,KAAkB,QAAA,IACjC,OAAO,QAAQ,QAAA,KAAa,QAAA,IAC5B,OAAO,OAAA,CAAQ,KAAA,KAAU,QAAA;AAE7B;AAEO,SAAS,qBAAqB,KAAA,EAA6C;AAChF,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,YAAA,EAAc;AACrE,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OACE,OAAO,OAAA,CAAQ,OAAA,KAAY,QAAA,IAC3B,OAAO,QAAQ,aAAA,KAAkB,QAAA,IACjC,OAAO,OAAA,CAAQ,YAAA,KAAiB,QAAA;AAEpC;AAEO,SAAS,oBAAoB,KAAA,EAA4C;AAC9E,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,KAAK,KAAA,CAAM,IAAA,KAAS,YAAY,WAAA,EAAa;AACpE,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,OAAO,OAAO,OAAA,CAAQ,aAAA,KAAkB,QAAA,IAAY,OAAO,QAAQ,IAAA,KAAS,QAAA;AAC9E;;;ACjrBO,SAAS,gBAAA,GAA2B;AACzC,EAAA,OAAO,iBAAiB,QAAQ,CAAA;AAClC;AAUO,SAAS,qBAAA,GAAgC;AAC9C,EAAA,OAAO,iBAAiB,KAAK,CAAA;AAC/B;AAEO,SAAS,eAAA,GAA0B;AACxC,EAAA,OAAO,iBAAiB,OAAO,CAAA;AACjC;AAEA,SAAS,iBAAiB,MAAA,EAAwB;AAChD,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,MAAA,CAAO,eAAe,UAAA,EAAY;AAC5E,IAAA,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,MAAA,CAAO,YAAY,CAAA,CAAA;AAAA,EACzC;AAEA,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,EAAO,CAAE,SAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AACrD,EAAA,OAAO,GAAG,MAAM,CAAA,CAAA,EAAI,KAAK,GAAA,EAAK,IAAI,MAAM,CAAA,CAAA;AAC1C;;;ACzBA,IAAM,eAAA,GAAkB,GAAA;AACxB,IAAM,cAAA,GAAiB,GAAA;AACvB,IAAM,iBAAA,GAAoB,GAAA;AAEnB,SAAS,qBAAA,CAAsB,OAAA,EAAiB,OAAA,GAA4B,EAAC,EAAW;AAC7F,EAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,IAAU,eAAA;AACjC,EAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,cAAA;AAC/B,EAAA,MAAM,QAAA,GAAW,QAAQ,QAAA,IAAY,iBAAA;AAErC,EAAA,MAAM,WAAA,GAAc,SAAS,CAAA,IAAK,OAAA;AAClC,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,WAAA,EAAa,KAAK,CAAA;AAC1C,EAAA,MAAM,SAAS,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,MAAA,KAAW,QAAQ,CAAA;AAElD,EAAA,OAAO,MAAA,GAAS,MAAA;AAClB;AAMO,IAAM,qBAAN,MAAyB;AAAA,EACtB,OAAA,GAAU,CAAA;AAAA,EACV,KAAA,GAA8C,IAAA;AAAA,EACrC,WAAA;AAAA,EACA,OAAA;AAAA,EAEjB,WAAA,CAAY,EAAE,WAAA,EAAa,GAAG,SAAQ,EAA8B;AAClE,IAAA,IAAA,CAAK,WAAA,GAAc,WAAA;AACnB,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AAAA,EAEA,QAAA,GAAiB;AACf,IAAA,IAAI,IAAA,CAAK,UAAU,IAAA,EAAM;AACvB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQ,qBAAA,CAAsB,IAAA,CAAK,OAAA,EAAS,KAAK,OAAO,CAAA;AAC9D,IAAA,IAAA,CAAK,OAAA,IAAW,CAAA;AAEhB,IAAA,IAAA,CAAK,KAAA,GAAQ,WAAW,MAAM;AAC5B,MAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,MAAA,IAAA,CAAK,WAAA,EAAY;AAAA,IACnB,GAAG,KAAK,CAAA;AAAA,EACV;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,CAAA;AACf,IAAA,IAAA,CAAK,MAAA,EAAO;AAAA,EACd;AAAA,EAEA,MAAA,GAAe;AACb,IAAA,IAAI,IAAA,CAAK,UAAU,IAAA,EAAM;AACvB,MAAA,YAAA,CAAa,KAAK,KAAK,CAAA;AACvB,MAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AAAA,IACf;AAAA,EACF;AACF,CAAA;;;AC0CA,IAAM,gBAAA,GAAmB,GAAA;AAElB,SAAS,oBAAA,CAAqB,OAAA,GAAiC,EAAC,EAAmB;AACxF,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,IAAQ,YAAA,CAAa,MAAA;AAC1C,EAAA,MAAM,aAAA,GAAgB,OAAA,CAAQ,aAAA,IAAiB,UAAA,CAAW,SAAA;AAE1D,EAAA,IAAI,CAAC,aAAA,EAAe;AAClB,IAAA,MAAM,IAAI,MAAM,iDAAiD,CAAA;AAAA,EACnE;AAEA,EAAA,IAAI,MAAA,GAAoD,IAAA;AACxD,EAAA,IAAI,YAAA,GAA2C,IAAA;AAC/C,EAAA,IAAI,eAAA,GAAmC,cAAA;AACvC,EAAA,IAAI,mBAAA,GAAqC,IAAA;AACzC,EAAA,IAAI,qBAAA,GAAwB,KAAA;AAC5B,EAAA,IAAI,gBAAA,GAAqC,MAAA;AACzC,EAAA,IAAI,mBAAA,GAAqC,IAAA;AACzC,EAAA,IAAI,cAAA,GAAgC,IAAA;AAEpC,EAAA,MAAM,kBAAA,uBAAyB,GAAA,EAG7B;AACF,EAAA,MAAM,aAAA,uBAAoB,GAAA,EAGxB;AAEF,EAAA,MAAM,WACJ,IAAA,KAAS,YAAA,CAAa,SAAU,OAAA,CAAQ,QAAA,IAAY,kBAAiB,GAAK,MAAA;AAE5E,EAAA,IAAI,KAAA,GACF,OAAA,CAAQ,SAAA,IAAa,kBAAA,CAAmB,aAAa,qBAAqB,CAAA;AAE5E,EAAA,MAAM,kBAAA,GAAqB,CAAC,KAAA,KAAiC;AAC3D,IAAA,IAAI,oBAAoB,KAAA,EAAO;AAC7B,MAAA;AAAA,IACF;AAEA,IAAA,eAAA,GAAkB,KAAA;AAClB,IAAA,OAAA,CAAQ,0BAA0B,KAAK,CAAA;AAAA,EACzC,CAAA;AAEA,EAAA,MAAM,mBAAA,GAAsB,CAAC,KAAA,KAAkC;AAC7D,IAAA,IAAI,qBAAqB,KAAA,EAAO;AAC9B,MAAA;AAAA,IACF;AAEA,IAAA,gBAAA,GAAmB,KAAA;AACnB,IAAA,OAAA,CAAQ,2BAA2B,KAAK,CAAA;AAAA,EAC1C,CAAA;AAEA,EAAA,MAAM,mBAAmB,MAAY;AACnC,IAAA,mBAAA,CAAoB,MAAM,CAAA;AAC1B,IAAA,mBAAA,GAAsB,IAAA;AACtB,IAAA,cAAA,GAAiB,IAAA;AAAA,EACnB,CAAA;AAEA,EAAA,MAAM,wBAAA,GAA2B,CAAC,aAAA,EAAuB,KAAA,KAAuB;AAC9E,IAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,GAAA,CAAI,aAAa,CAAA;AAEpD,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,OAAA,CAAQ,OAAO,KAAK,CAAA;AACpB,MAAA,kBAAA,CAAmB,OAAO,aAAa,CAAA;AAAA,IACzC;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,CAAC,KAAA,KAAuB;AAC/C,IAAA,KAAA,MAAW,CAAC,EAAA,EAAI,OAAO,CAAA,IAAK,kBAAA,EAAoB;AAC9C,MAAA,OAAA,CAAQ,OAAO,KAAK,CAAA;AACpB,MAAA,kBAAA,CAAmB,OAAO,EAAE,CAAA;AAAA,IAC9B;AAEA,IAAA,KAAA,MAAW,CAAC,EAAA,EAAI,OAAO,CAAA,IAAK,aAAA,EAAe;AACzC,MAAA,OAAA,CAAQ,OAAO,KAAK,CAAA;AACpB,MAAA,aAAA,CAAc,OAAO,EAAE,CAAA;AAAA,IACzB;AAEA,IAAA,gBAAA,EAAiB;AAAA,EACnB,CAAA;AAEA,EAAA,MAAM,kBAAA,GAAqB,IAAI,kBAAA,CAAmB;AAAA,IAChD,aAAa,MAAM;AACjB,MAAA,UAAA,EAAW;AAAA,IACb;AAAA,GACD,CAAA;AAED,EAAA,MAAM,IAAA,GAAO,CAAC,OAAA,KAAsC;AAClD,IAAA,IAAI,CAAC,MAAA,IAAU,MAAA,CAAO,UAAA,KAAe,cAAc,IAAA,EAAM;AACvD,MAAA;AAAA,IACF;AAEA,IAAA,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,EAAE,GAAG,OAAA,EAAS,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,EAAG,CAAC,CAAA;AAAA,EACnE,CAAA;AAEA,EAAA,MAAM,eAAe,MAAY;AAC/B,IAAA,IAAA,CAAK;AAAA,MACH,MAAM,WAAA,CAAY,QAAA;AAAA,MAClB,IAAA;AAAA,MACA,GAAI,QAAA,GAAW,EAAE,QAAA,KAAa,EAAC;AAAA,MAC/B,GAAI,QAAQ,QAAA,GAAW,EAAE,UAAU,OAAA,CAAQ,QAAA,KAAa;AAAC,KAC1D,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,mBAAA,GAAsB,CAAC,MAAA,KAA0B;AACrD,IAAA,IAAI,aAAA,CAAc,MAAM,CAAA,EAAG;AACzB,MAAA,IAAA,CAAK;AAAA,QACH,MAAM,WAAA,CAAY,IAAA;AAAA,QAClB,QAAQ,MAAA,CAAO;AAAA,OAChB,CAAA;AACD,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,qBAAA,CAAsB,MAAM,CAAA,EAAG;AACjC,MAAA,YAAA,GAAe,MAAA,CAAO,OAAA;AACtB,MAAA,OAAA,CAAQ,cAAA,GAAiB,OAAO,OAAO,CAAA;AACvC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,gCAAA,CAAiC,MAAM,CAAA,EAAG;AAC5C,MAAA,OAAA,CAAQ,4BAA4B,MAAM,CAAA;AAC1C,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,4BAAA,CAA6B,MAAM,CAAA,EAAG;AACxC,MAAA,OAAA,CAAQ,wBAAwB,MAAM,CAAA;AACtC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,sBAAA,CAAuB,MAAM,CAAA,EAAG;AAClC,MAAA,OAAA,CAAQ,kBAAkB,MAAM,CAAA;AAChC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,sBAAA,CAAuB,MAAM,CAAA,EAAG;AAClC,MAAA,OAAA,CAAQ,kBAAkB,MAAM,CAAA;AAChC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,qBAAA,CAAsB,MAAM,CAAA,EAAG;AACjC,MAAA,OAAA,CAAQ,iBAAiB,MAAM,CAAA;AAC/B,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,yBAAA,CAA0B,MAAM,CAAA,EAAG;AACrC,MAAA,OAAA,CAAQ,qBAAqB,MAAM,CAAA;AACnC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,0BAAA,CAA2B,MAAM,CAAA,EAAG;AACtC,MAAA,OAAA,CAAQ,sBAAsB,MAAM,CAAA;AACpC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,4BAAA,CAA6B,MAAM,CAAA,EAAG;AACxC,MAAA,OAAA,CAAQ,wBAAwB,MAAM,CAAA;AACtC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,qBAAA,CAAsB,MAAM,CAAA,EAAG;AACjC,MAAA,OAAA,CAAQ,iBAAiB,MAAM,CAAA;AAC/B,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,0BAAA,CAA2B,MAAM,CAAA,EAAG;AACtC,MAAA,OAAA,CAAQ,sBAAsB,MAAM,CAAA;AAEpC,MAAA,IAAI,IAAA,KAAS,aAAa,OAAA,EAAS;AACjC,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,GAAA,CAAI,MAAA,CAAO,aAAa,CAAA;AAE3D,MAAA,IAAI,MAAA,CAAO,KAAA,KAAU,MAAA,IAAU,OAAA,EAAS,WAAW,OAAA,EAAS;AAC1D,QAAA,mBAAA,CAAoB,MAAM,CAAA;AAC1B,QAAA,mBAAA,GAAsB,MAAA,CAAO,aAAA;AAC7B,QAAA,cAAA,GAAiB,MAAA,CAAO,QAAA;AACxB,QAAA,OAAA,CAAQ,OAAA,EAAQ;AAChB,QAAA,kBAAA,CAAmB,MAAA,CAAO,OAAO,aAAa,CAAA;AAC9C,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,MAAA,CAAO,UAAU,MAAA,IAAU,OAAA,KAAY,QAAQ,MAAA,KAAW,QAAA,IAAY,OAAA,CAAQ,MAAA,KAAW,UAAA,CAAA,EAAa;AACxG,QAAA,gBAAA,EAAiB;AACjB,QAAA,OAAA,CAAQ,OAAA,EAAQ;AAChB,QAAA,kBAAA,CAAmB,MAAA,CAAO,OAAO,aAAa,CAAA;AAC9C,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,MAAA,CAAO,UAAU,QAAA,EAAU;AAC7B,QAAA,wBAAA;AAAA,UACE,MAAA,CAAO,aAAA;AAAA,UACP,IAAI,KAAA,CAAM,MAAA,CAAO,OAAA,IAAW,oBAAoB;AAAA,SAClD;AACA,QAAA,gBAAA,EAAiB;AAAA,MACnB;AAEA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,oBAAA,CAAqB,MAAM,CAAA,EAAG;AAChC,MAAA,OAAA,CAAQ,gBAAgB,MAAM,CAAA;AAE9B,MAAA,MAAM,OAAA,GAAU,aAAA,CAAc,GAAA,CAAI,MAAA,CAAO,OAAO,CAAA;AAEhD,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,OAAA,CAAQ,OAAA,CAAQ,EAAE,YAAA,EAAc,MAAA,CAAO,cAAc,CAAA;AACrD,QAAA,aAAA,CAAc,MAAA,CAAO,OAAO,OAAO,CAAA;AAAA,MACrC;AAEA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,mBAAA,CAAoB,MAAM,CAAA,EAAG;AAC/B,MAAA,OAAA,CAAQ,eAAe,MAAM,CAAA;AAE7B,MAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA;AAEtC,MAAA,IAAI,OAAO,OAAA,EAAS;AAClB,QAAA,MAAM,YAAA,GAAe,aAAA,CAAc,GAAA,CAAI,MAAA,CAAO,OAAO,CAAA;AAErD,QAAA,IAAI,YAAA,EAAc;AAChB,UAAA,YAAA,CAAa,OAAO,KAAK,CAAA;AACzB,UAAA,aAAA,CAAc,MAAA,CAAO,OAAO,OAAO,CAAA;AAAA,QACrC;AAAA,MACF,CAAA,MAAO;AACL,QAAA,wBAAA,CAAyB,MAAA,CAAO,eAAe,KAAK,CAAA;AACpD,QAAA,gBAAA,EAAiB;AAAA,MACnB;AAAA,IACF;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,aAAa,MAAY;AAC7B,IAAA,IACE,MAAA,KACC,OAAO,UAAA,KAAe,aAAA,CAAc,QAAQ,MAAA,CAAO,UAAA,KAAe,cAAc,UAAA,CAAA,EACjF;AACA,MAAA;AAAA,IACF;AAEA,IAAA,kBAAA,CAAmB,qBAAA,GAAwB,cAAA,GAAiB,eAAA,KAAoB,cAAA,GAAiB,eAAe,cAAc,CAAA;AAE9H,IAAA,MAAA,GAAS,IAAI,cAAc,KAAK,CAAA;AAEhC,IAAA,MAAA,CAAO,gBAAA,CAAiB,QAAQ,MAAM;AACpC,MAAA,kBAAA,CAAmB,KAAA,EAAM;AACzB,MAAA,mBAAA,GAAsB,IAAA;AACtB,MAAA,kBAAA,CAAmB,WAAW,CAAA;AAC9B,MAAA,OAAA,CAAQ,SAAA,IAAY;AACpB,MAAA,YAAA,EAAa;AAAA,IACf,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,gBAAA,CAAiB,SAAA,EAAW,CAAC,KAAA,KAAU;AAC5C,MAAA,IAAI,MAAA;AAEJ,MAAA,IAAI;AACF,QAAA,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,KAAA,CAAM,IAAI,CAAC,CAAA;AAAA,MACxC,CAAA,CAAA,MAAQ;AACN,QAAA;AAAA,MACF;AAEA,MAAA,mBAAA,CAAoB,MAAM,CAAA;AAAA,IAC5B,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,gBAAA,CAAiB,SAAS,MAAM;AACrC,MAAA,MAAA,GAAS,IAAA;AACT,MAAA,OAAA,CAAQ,YAAA,IAAe;AACvB,MAAA,gBAAA,CAAiB,IAAI,KAAA,CAAM,gCAAgC,CAAC,CAAA;AAE5D,MAAA,IAAI,qBAAA,EAAuB;AACzB,QAAA,kBAAA,CAAmB,cAAc,CAAA;AACjC,QAAA;AAAA,MACF;AAEA,MAAA,kBAAA,CAAmB,cAAc,CAAA;AACjC,MAAA,kBAAA,CAAmB,QAAA,EAAS;AAAA,IAC9B,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,gBAAA,CAAiB,SAAS,MAAM;AACrC,MAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,CAAA,6BAAA,EAAgC,KAAK,CAAA,CAAE,CAAA;AAC/D,MAAA,mBAAA,GAAsB,KAAA,CAAM,OAAA;AAC5B,MAAA,OAAA,CAAQ,UAAU,KAAK,CAAA;AAAA,IACzB,CAAC,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,UAAU,MAAY;AAC1B,IAAA,qBAAA,GAAwB,KAAA;AACxB,IAAA,UAAA,EAAW;AAAA,EACb,CAAA;AAEA,EAAA,MAAM,aAAa,MAAY;AAC7B,IAAA,qBAAA,GAAwB,IAAA;AACxB,IAAA,kBAAA,CAAmB,MAAA,EAAO;AAC1B,IAAA,MAAA,EAAQ,KAAA,EAAM;AACd,IAAA,MAAA,GAAS,IAAA;AACT,IAAA,gBAAA,CAAiB,IAAI,KAAA,CAAM,cAAc,CAAC,CAAA;AAC1C,IAAA,kBAAA,CAAmB,cAAc,CAAA;AAAA,EACnC,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,CAAC,GAAA,KAAsB;AAC1C,IAAA,KAAA,GAAQ,GAAA;AACR,IAAA,MAAM,YAAA,GACJ,eAAA,KAAoB,WAAA,IACpB,eAAA,KAAoB,gBACpB,eAAA,KAAoB,cAAA;AAEtB,IAAA,UAAA,EAAW;AACX,IAAA,qBAAA,GAAwB,KAAA;AAExB,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,OAAA,EAAQ;AAAA,IACV;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,cAAA,GAAiB,CAAC,cAAA,KAAiC;AACvD,IAAA,IAAA,CAAK;AAAA,MACH,MAAM,WAAA,CAAY,eAAA;AAAA,MAClB,QAAA,EAAU,cAAA;AAAA,MACV,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,wBAAwB,MAAY;AACxC,IAAA,IAAA,CAAK;AAAA,MACH,MAAM,WAAA,CAAY,uBAAA;AAAA,MAClB,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,kBAAA,GAAqB,CAAC,OAAA,KAAqE;AAC/F,IAAA,IAAA,CAAK;AAAA,MACH,MAAM,WAAA,CAAY,eAAA;AAAA,MAClB,GAAG;AAAA,KACJ,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,CAAC,OAAA,KAA+D;AACnF,IAAA,IAAA,CAAK;AAAA,MACH,MAAM,WAAA,CAAY,SAAA;AAAA,MAClB,GAAG;AAAA,KACJ,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,kBAAA,GAAqB,CACzB,aAAA,EACA,MAAA,KACkB;AAClB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,QAAA,kBAAA,CAAmB,OAAO,aAAa,CAAA;AACvC,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,YAAA,EAAe,MAAM,YAAY,CAAC,CAAA;AAAA,MACrD,GAAG,gBAAgB,CAAA;AAEnB,MAAA,kBAAA,CAAmB,IAAI,aAAA,EAAe;AAAA,QACpC,MAAA;AAAA,QACA,SAAS,MAAM;AACb,UAAA,YAAA,CAAa,KAAK,CAAA;AAClB,UAAA,OAAA,EAAQ;AAAA,QACV,CAAA;AAAA,QACA,MAAA,EAAQ,CAAC,KAAA,KAAU;AACjB,UAAA,YAAA,CAAa,KAAK,CAAA;AAClB,UAAA,MAAA,CAAO,KAAK,CAAA;AAAA,QACd;AAAA,OACD,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,OAAO,cAAA,KAA0C;AACxE,IAAA,IAAI,IAAA,KAAS,aAAa,OAAA,EAAS;AACjC,MAAA,MAAM,IAAI,MAAM,wDAAwD,CAAA;AAAA,IAC1E;AAEA,IAAA,IAAI,qBAAqB,MAAA,EAAQ;AAC/B,MAAA,MAAM,IAAI,MAAM,iCAAiC,CAAA;AAAA,IACnD;AAEA,IAAA,MAAM,gBAAgB,qBAAA,EAAsB;AAC5C,IAAA,mBAAA,CAAoB,SAAS,CAAA;AAC7B,IAAA,mBAAA,GAAsB,aAAA;AACtB,IAAA,cAAA,GAAiB,cAAA;AAEjB,IAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,aAAA,EAAe,OAAO,CAAA;AAEzD,IAAA,IAAA,CAAK;AAAA,MACH,MAAM,WAAA,CAAY,yBAAA;AAAA,MAClB,aAAA;AAAA,MACA,QAAA,EAAU;AAAA,KACX,CAAA;AAED,IAAA,MAAM,OAAA;AAAA,EACR,CAAA;AAEA,EAAA,MAAM,oBAAoB,YAA2B;AACnD,IAAA,IAAI,IAAA,KAAS,aAAa,OAAA,EAAS;AACjC,MAAA,MAAM,IAAI,MAAM,yDAAyD,CAAA;AAAA,IAC3E;AAEA,IAAA,IAAI,CAAC,mBAAA,IAAuB,CAAC,cAAA,IAAkB,qBAAqB,MAAA,EAAQ;AAC1E,MAAA,MAAM,IAAI,MAAM,qBAAqB,CAAA;AAAA,IACvC;AAEA,IAAA,MAAM,aAAA,GAAgB,mBAAA;AACtB,IAAA,MAAM,iBAAA,GAAoB,cAAA;AAC1B,IAAA,mBAAA,CAAoB,YAAY,CAAA;AAEhC,IAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,aAAA,EAAe,QAAQ,CAAA;AAE1D,IAAA,IAAA,CAAK;AAAA,MACH,MAAM,WAAA,CAAY,0BAAA;AAAA,MAClB,aAAA;AAAA,MACA,QAAA,EAAU;AAAA,KACX,CAAA;AAED,IAAA,MAAM,OAAA;AAAA,EACR,CAAA;AAEA,EAAA,MAAM,sBAAsB,YAA2B;AACrD,IAAA,IAAI,IAAA,KAAS,aAAa,OAAA,EAAS;AACjC,MAAA,MAAM,IAAI,MAAM,2DAA2D,CAAA;AAAA,IAC7E;AAEA,IAAA,IAAI,CAAC,mBAAA,IAAuB,CAAC,cAAA,EAAgB;AAC3C,MAAA,MAAM,IAAI,MAAM,uBAAuB,CAAA;AAAA,IACzC;AAEA,IAAA,MAAM,aAAA,GAAgB,mBAAA;AACtB,IAAA,MAAM,mBAAA,GAAsB,cAAA;AAC5B,IAAA,mBAAA,CAAoB,cAAc,CAAA;AAElC,IAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,aAAA,EAAe,UAAU,CAAA;AAE5D,IAAA,IAAA,CAAK;AAAA,MACH,MAAM,WAAA,CAAY,4BAAA;AAAA,MAClB,aAAA;AAAA,MACA,QAAA,EAAU;AAAA,KACX,CAAA;AAED,IAAA,MAAM,OAAA;AAAA,EACR,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,OAAO,SAAA,KAAiE;AAC3F,IAAA,IAAI,IAAA,KAAS,aAAa,OAAA,EAAS;AACjC,MAAA,MAAM,IAAI,MAAM,oDAAoD,CAAA;AAAA,IACtE;AAEA,IAAA,IAAI,CAAC,mBAAA,IAAuB,CAAC,cAAA,IAAkB,qBAAqB,MAAA,EAAQ;AAC1E,MAAA,MAAM,IAAI,MAAM,qBAAqB,CAAA;AAAA,IACvC;AAEA,IAAA,MAAM,UAAU,eAAA,EAAgB;AAEhC,IAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAkC,CAAC,SAAS,MAAA,KAAW;AACzE,MAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,QAAA,aAAA,CAAc,OAAO,OAAO,CAAA;AAC5B,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,2BAA2B,CAAC,CAAA;AAAA,MAC/C,GAAG,gBAAgB,CAAA;AAEnB,MAAA,aAAA,CAAc,IAAI,OAAA,EAAS;AAAA,QACzB,OAAA,EAAS,CAAC,MAAA,KAAW;AACnB,UAAA,YAAA,CAAa,KAAK,CAAA;AAClB,UAAA,OAAA,CAAQ,MAAM,CAAA;AAAA,QAChB,CAAA;AAAA,QACA,MAAA,EAAQ,CAAC,KAAA,KAAU;AACjB,UAAA,YAAA,CAAa,KAAK,CAAA;AAClB,UAAA,MAAA,CAAO,KAAK,CAAA;AAAA,QACd;AAAA,OACD,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,IAAA,CAAK;AAAA,MACH,MAAM,WAAA,CAAY,aAAA;AAAA,MAClB,OAAA;AAAA,MACA,aAAA,EAAe,mBAAA;AAAA,MACf,QAAA,EAAU,cAAA;AAAA,MACV;AAAA,KACD,CAAA;AAED,IAAA,OAAO,OAAA;AAAA,EACT,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,UAAA;AAAA,IACA,oBAAoB,MAAM,eAAA;AAAA,IAC1B,wBAAwB,MAAM,mBAAA;AAAA,IAC9B,iBAAiB,MAAM,YAAA;AAAA,IACvB,aAAa,MAAM,QAAA;AAAA,IACnB,cAAc,MAAM,KAAA;AAAA,IACpB,YAAA;AAAA,IACA,IAAA;AAAA,IACA,cAAA;AAAA,IACA,qBAAA;AAAA,IACA,kBAAA;AAAA,IACA,YAAA;AAAA,IACA,gBAAA;AAAA,IACA,iBAAA;AAAA,IACA,mBAAA;AAAA,IACA,YAAA;AAAA,IACA,qBAAqB,MAAM,gBAAA;AAAA,IAC3B,wBAAwB,MAAM;AAAA,GAChC;AACF;;;AC7lBA,eAAsB,cAAc,WAAA,EAA2C;AAC7E,EAAA,IAAI,QAAA;AAEJ,EAAA,IAAI;AACF,IAAA,QAAA,GAAW,MAAM,MAAM,WAAW,CAAA;AAAA,EACpC,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,iBAAiB,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAC5E,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,qCAAA,EAAwC,WAAW,CAAA,EAAA,EAAK,cAAc,CAAA,iGAAA;AAAA,KACxE;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,iCAAiC,WAAW,CAAA,EAAA,EAAK,SAAS,MAAM,CAAA,CAAA,EAAI,SAAS,UAAU,CAAA;AAAA,KACzF;AAAA,EACF;AAEA,EAAA,OAAO,SAAS,WAAA,EAAY;AAC9B;;;ACbA,SAAS,cAAA,CAAe,WAAmB,OAAA,EAAoD;AAC7F,EAAA,IAAI,OAAA,EAAS,gBAAA,IAAoB,OAAO,MAAA,KAAW,WAAA,EAAa;AAC9D,IAAA,OAAO,OAAO,QAAA,CAAS,MAAA;AAAA,EACzB;AAEA,EAAA,IAAI,UAAU,UAAA,CAAW,OAAO,KAAK,SAAA,CAAU,UAAA,CAAW,QAAQ,CAAA,EAAG;AACnE,IAAA,OAAO,eAAe,SAAS,CAAA;AAAA,EACjC;AAEA,EAAA,OAAO,SAAA,CAAU,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACpC;AAEO,SAAS,8BAAA,CACd,SAAA,EACA,QAAA,EACA,OAAA,EACQ;AACR,EAAA,MAAM,IAAA,GAAO,cAAA,CAAe,SAAA,EAAW,OAAO,CAAA;AAC9C,EAAA,OAAO,GAAG,IAAI,CAAA,EAAG,+BAA+B,CAAA,CAAA,EAAI,kBAAA,CAAmB,QAAQ,CAAC,CAAA,SAAA,CAAA;AAClF;AAEO,SAAS,kCAAA,CACd,SAAA,EACA,QAAA,EACA,OAAA,EACQ;AACR,EAAA,MAAM,IAAA,GAAO,cAAA,CAAe,SAAA,EAAW,OAAO,CAAA;AAC9C,EAAA,OAAO,GAAG,IAAI,CAAA,EAAG,+BAA+B,CAAA,CAAA,EAAI,kBAAA,CAAmB,QAAQ,CAAC,CAAA,cAAA,CAAA;AAClF;AAEO,SAAS,uBAAA,CACd,WACA,OAAA,EACQ;AACR,EAAA,MAAM,IAAA,GAAO,cAAA,CAAe,SAAA,EAAW,OAAO,CAAA;AAC9C,EAAA,OAAO,CAAA,EAAG,IAAI,CAAA,EAAG,+BAA+B,CAAA,CAAA;AAClD;;;AC9BA,eAAe,SAAA,CAAa,KAAa,UAAA,EAAgC;AACvE,EAAA,IAAI,QAAA;AAEJ,EAAA,IAAI;AACF,IAAA,QAAA,GAAW,MAAM,MAAM,GAAG,CAAA;AAAA,EAC5B,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,iBAAiB,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAC5E,IAAA,MAAM,IAAI,MAAM,CAAA,uBAAA,EAA0B,UAAU,SAAS,GAAG,CAAA,EAAA,EAAK,cAAc,CAAA,CAAE,CAAA;AAAA,EACvF;AAEA,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,UAAU,CAAA,MAAA,EAAS,GAAG,CAAA,EAAA,EAAK,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,QAAA,CAAS,UAAU,CAAA,CAAE,CAAA;AAAA,EACxG;AAEA,EAAA,OAAQ,MAAM,SAAS,IAAA,EAAK;AAC9B;AAEA,eAAsB,qBAAA,CACpB,SAAA,EACA,QAAA,EACA,OAAA,EAC2B;AAC3B,EAAA,MAAM,GAAA,GAAM,kCAAA,CAAmC,SAAA,EAAW,QAAA,EAAU,OAAO,CAAA;AAC3E,EAAA,OAAO,SAAA,CAA4B,KAAK,wBAAwB,CAAA;AAClE;AAEA,eAAsB,yBAAA,CACpB,SAAA,EACA,QAAA,EACA,OAAA,EACsB;AACtB,EAAA,MAAM,GAAA,GAAM,8BAAA,CAA+B,SAAA,EAAW,QAAA,EAAU,OAAO,CAAA;AACvE,EAAA,OAAO,cAAc,GAAG,CAAA;AAC1B;AAEA,eAAsB,kBAAA,CACpB,WACA,OAAA,EAC+B;AAC/B,EAAA,MAAM,GAAA,GAAM,uBAAA,CAAwB,SAAA,EAAW,OAAO,CAAA;AACtD,EAAA,MAAM,OAAA,GAAU,MAAM,SAAA,CAA8C,GAAA,EAAK,gBAAgB,CAAA;AACzF,EAAA,OAAO,OAAA,CAAQ,WAAW,EAAC;AAC7B;;;AC3CA,SAASA,eAAAA,CAAe,WAAmB,OAAA,EAAoD;AAC7F,EAAA,IAAI,OAAA,EAAS,gBAAA,IAAoB,OAAO,MAAA,KAAW,WAAA,EAAa;AAC9D,IAAA,OAAO,OAAO,QAAA,CAAS,MAAA;AAAA,EACzB;AAEA,EAAA,IAAI,UAAU,UAAA,CAAW,OAAO,KAAK,SAAA,CAAU,UAAA,CAAW,QAAQ,CAAA,EAAG;AACnE,IAAA,OAAO,eAAe,SAAS,CAAA;AAAA,EACjC;AAEA,EAAA,OAAO,SAAA,CAAU,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACpC;AAEO,SAAS,yBAAA,CACd,WACA,OAAA,EACQ;AACR,EAAA,OAAO,GAAGA,eAAAA,CAAe,SAAA,EAAW,OAAO,CAAC,GAAG,yBAAyB,CAAA,CAAA;AAC1E;AAEO,SAAS,6BAAA,CACd,WACA,OAAA,EACQ;AACR,EAAA,OAAO,GAAGA,eAAAA,CAAe,SAAA,EAAW,OAAO,CAAC,GAAG,8BAA8B,CAAA,CAAA;AAC/E;AAEO,SAAS,0BAAA,CACd,WACA,OAAA,EACQ;AACR,EAAA,OAAO,GAAGA,eAAAA,CAAe,SAAA,EAAW,OAAO,CAAC,GAAG,0BAA0B,CAAA,CAAA;AAC3E;;;ACPA,eAAsB,wBAAA,CACpB,WACA,OAAA,EAC8B;AAC9B,EAAA,MAAM,GAAA,GAAM,6BAAA,CAA8B,SAAA,EAAW,OAAO,CAAA;AAC5D,EAAA,IAAI,QAAA;AAEJ,EAAA,IAAI;AACF,IAAA,QAAA,GAAW,MAAM,MAAM,GAAG,CAAA;AAAA,EAC5B,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,iBAAiB,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAC5E,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sDAAA,EAAyD,GAAG,CAAA,EAAA,EAAK,cAAc,CAAA,CAAE,CAAA;AAAA,EACnG;AAEA,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,kDAAkD,GAAG,CAAA,EAAA,EAAK,SAAS,MAAM,CAAA,CAAA,EAAI,SAAS,UAAU,CAAA;AAAA,KAClG;AAAA,EACF;AAEA,EAAA,OAAQ,MAAM,SAAS,IAAA,EAAK;AAC9B;AAGA,eAAsB,oBAAA,CACpB,WACA,OAAA,EACsB;AACtB,EAAA,MAAM,GAAA,GAAM,yBAAA,CAA0B,SAAA,EAAW,OAAO,CAAA;AACxD,EAAA,OAAO,cAAc,GAAG,CAAA;AAC1B;AAGA,eAAsB,qBAAA,CACpB,WACA,OAAA,EACkC;AAClC,EAAA,MAAM,GAAA,GAAM,0BAAA,CAA2B,SAAA,EAAW,OAAO,CAAA;AACzD,EAAA,IAAI,QAAA;AAEJ,EAAA,IAAI;AACF,IAAA,QAAA,GAAW,MAAM,MAAM,GAAG,CAAA;AAAA,EAC5B,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,iBAAiB,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAC5E,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,8CAAA,EAAiD,GAAG,CAAA,EAAA,EAAK,cAAc,CAAA,CAAE,CAAA;AAAA,EAC3F;AAEA,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,0CAA0C,GAAG,CAAA,EAAA,EAAK,SAAS,MAAM,CAAA,CAAA,EAAI,SAAS,UAAU,CAAA;AAAA,KAC1F;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAW,MAAM,QAAA,CAAS,IAAA,EAAK;AACrC,EAAA,OAAO,OAAA,CAAQ,aAAa,EAAC;AAC/B;;;AC5EO,SAAS,0BAAA,CACd,QAAA,EACA,QAAA,EACA,OAAA,GAA6C,EAAC,EACtC;AACR,EAAA,MAAM,OAAO,CAAA,EAAG,wBAAwB,CAAA,CAAA,EAAI,kBAAA,CAAmB,QAAQ,CAAC,CAAA,SAAA,CAAA;AAExE,EAAA,IAAI,QAAQ,gBAAA,EAAkB;AAC5B,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,sBAAA,CAAuB,cAAA,CAAe,QAAQ,CAAA,EAAG,QAAQ,CAAA;AAClE;;;ACvBO,SAAS,sBAAA,CAAuB,MAAwB,OAAA,EAAyB;AACtF,EAAA,OAAO,yBAAA,CAA0B,MAAM,OAAO,CAAA;AAChD;AAEO,SAAS,yBAAA,CAA0B,MAAwB,OAAA,EAAyB;AACzF,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,gBAAA;AACH,MAAA,OAAO,uEAAA;AAAA,IACT,KAAK,qBAAA;AACH,MAAA,OAAO,mDAAA;AAAA,IACT,KAAK,eAAA;AACH,MAAA,OAAO,+CAA+C,OAAO,CAAA,CAAA;AAAA,IAC/D,KAAK,eAAA;AACH,MAAA,OAAO,sCAAsC,OAAO,CAAA,CAAA;AAAA,IACtD,KAAK,SAAA;AACH,MAAA,OAAO,wDAAA;AAAA,IACT,KAAK,oBAAA;AACH,MAAA,OAAO,yDAAA;AAAA,IACT,KAAK,iBAAA;AACH,MAAA,OAAO,4BAA4B,OAAO,CAAA,CAAA;AAAA,IAC5C;AACE,MAAA,OAAO,OAAA;AAAA;AAEb;;;ACdO,SAAS,eAAA,CAAgB,QAAA,EAAkB,YAAA,GAAe,CAAA,EAAW;AAC1E,EAAA,IAAI,QAAA,CAAS,MAAA,IAAU,YAAA,GAAe,CAAA,GAAI,CAAA,EAAG;AAC3C,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,OAAO,CAAA,EAAG,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,YAAY,CAAC,CAAA,MAAA,EAAI,QAAA,CAAS,KAAA,CAAM,CAAC,YAAY,CAAC,CAAA,CAAA;AAC5E;AAEO,SAAS,wBAAA,CACd,QAAA,EACA,YAAA,EACA,QAAA,EACQ;AACR,EAAA,MAAM,MAAA,GAAS,cAAc,OAAA,CAAQ,IAAA,CAAK,CAAC,MAAA,KAAW,MAAA,CAAO,aAAa,QAAQ,CAAA;AAElF,EAAA,IAAI,MAAA,EAAQ,UAAU,OAAA,EAAS;AAC7B,IAAA,OAAO,OAAO,QAAA,CAAS,OAAA;AAAA,EACzB;AAEA,EAAA,IAAI,UAAU,YAAA,EAAc;AAC1B,IAAA,OAAO,QAAA,CAAS,YAAA;AAAA,EAClB;AAEA,EAAA,IAAI,UAAU,KAAA,EAAO;AACnB,IAAA,OAAO,QAAA,CAAS,KAAA;AAAA,EAClB;AAEA,EAAA,OAAO,eAAA;AACT;AAEO,SAAS,kBAAA,CACd,QAAA,EACA,YAAA,EACA,QAAA,EACa;AACb,EAAA,OAAO;AAAA,IACL,QAAA;AAAA,IACA,UAAA,EAAY,wBAAA,CAAyB,QAAA,EAAU,YAAA,EAAc,QAAQ;AAAA,GACvE;AACF;AAEO,SAAS,6BAAA,CACd,aACA,YAAA,EACQ;AACR,EAAA,OAAO,CAAA,EAAG,YAAY,UAAU,CAAA,EAAA,EAAK,gBAAgB,WAAA,CAAY,QAAQ,CAAC,CAAA,OAAA,EAAO,YAAY,CAAA,CAAA;AAC/F;AAIO,SAAS,wBAAA,CACd,SAAA,EACA,QAAA,EACA,YAAA,EACA,cACA,QAAA,EACoC;AACpC,EAAA,MAAM,WAAA,GAAc,kBAAA,CAAmB,QAAA,EAAU,YAAA,EAAc,QAAQ,CAAA;AAEvE,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,SAAA,KAAc,QAAA,GAAW,uBAAA,GAA0B,oBAAA;AAAA,IAC1D,OAAA,EAAS,6BAAA,CAA8B,WAAA,EAAa,YAAY;AAAA,GAClE;AACF;;;AC9DA,SAAS,oBAAA,CACP,SACA,QAAA,EAC8B;AAC9B,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO,QAAQ,IAAA,CAAK,CAAC,WAAW,MAAA,CAAO,QAAA,EAAU,aAAa,QAAQ,CAAA;AACxE;AAEO,SAAS,yBAAyB,KAAA,EAAqD;AAC5F,EAAA,MAAM,YAAA,GAAe,IAAI,GAAA,CAAI,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAC,MAAA,KAAW,MAAA,CAAO,QAAQ,CAAC,CAAA;AAC3E,EAAA,MAAM,UAAA,GAAa,IAAI,GAAA,CAAI,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,CAAC,KAAA,KAAU,CAAC,KAAA,CAAM,QAAA,EAAU,KAAK,CAAC,CAAC,CAAA;AAEhF,EAAA,IAAI,MAAM,gBAAA,EAAkB;AAC1B,IAAA,IAAI,YAAA,CAAa,GAAA,CAAI,KAAA,CAAM,gBAAgB,CAAA,EAAG;AAC5C,MAAA,OAAO,KAAA,CAAM,gBAAA;AAAA,IACf;AAEA,IAAA,MAAM,cAAA,GAAiB,UAAA,CAAW,GAAA,CAAI,KAAA,CAAM,gBAAgB,CAAA;AAE5D,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,MAAM,WAAA,GAAc,oBAAA,CAAqB,KAAA,CAAM,OAAA,EAAS,eAAe,QAAQ,CAAA;AAE/E,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,OAAO,WAAA,CAAY,QAAA;AAAA,MACrB;AAEA,MAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG;AAC9B,QAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,CAAG,QAAA;AAAA,MAC3B;AAEA,MAAA,OAAO,KAAA,CAAM,gBAAA;AAAA,IACf;AAAA,EACF;AAEA,EAAA,OAAO,KAAA,CAAM,QAAQ,CAAC,CAAA,EAAG,YAAY,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG,QAAA,IAAY,IAAA;AACrE;AAEO,SAAS,wBAAwB,KAAA,EAItB;AAChB,EAAA,IAAI,CAAC,KAAA,CAAM,gBAAA,IAAoB,KAAA,CAAM,OAAA,CAAQ,WAAW,CAAA,EAAG;AACzD,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,KAAA,CAAM,QAAQ,IAAA,CAAK,CAAC,WAAW,MAAA,CAAO,QAAA,KAAa,KAAA,CAAM,gBAAgB,CAAA,EAAG;AAC9E,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,cAAA,GAAiB,MAAM,OAAA,CAAQ,IAAA,CAAK,CAAC,KAAA,KAAU,KAAA,CAAM,QAAA,KAAa,KAAA,CAAM,gBAAgB,CAAA;AAC9F,EAAA,MAAM,WAAA,GAAc,oBAAA,CAAqB,KAAA,CAAM,OAAA,EAAS,gBAAgB,QAAQ,CAAA;AAEhF,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,OAAO,WAAA,CAAY,QAAA;AAAA,EACrB;AAEA,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG,QAAA,IAAY,IAAA;AACvC;;;ACxEO,IAAM,oBAAA,GAAuB,iBAAA;AAC7B,IAAM,oBAAA,GAAuB,sBAAA;AAC7B,IAAM,oBAAA,GAAuB,iBAAA;;;ACE7B,SAAS,yBAAyB,KAAA,EAA+B;AACtE,EAAA,OAAO,KAAA;AACT;AAOO,SAAS,wBAAA,CAAyB,WAAmB,QAAA,EAA0B;AACpF,EAAA,MAAM,WAAA,GAAc,eAAe,QAAQ,CAAA;AAC3C,EAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,SAAS,CAAA;AAChC,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,WAAA,CAAY,QAAA,CAAS,GAAG,CAAA,GAAI,WAAA,GAAc,CAAA,EAAG,WAAW,CAAA,CAAA,CAAG,CAAA;AAE/E,EAAA,MAAA,CAAO,WAAW,GAAA,CAAI,QAAA;AACtB,EAAA,MAAA,CAAO,WAAW,GAAA,CAAI,QAAA;AACtB,EAAA,MAAA,CAAO,OAAO,GAAA,CAAI,IAAA;AAElB,EAAA,OAAO,OAAO,QAAA,EAAS;AACzB;AAWA,eAAsB,cAAA,CACpB,SAAA,EACA,KAAA,EACA,OAAA,EACe;AACf,EAAA,MAAM,OAAA,GAAkC;AAAA,IACtC,cAAA,EAAgB,0BAAA;AAAA,IAChB,CAAC,OAAA,CAAQ,UAAU,GAAG,OAAA,CAAQ,IAAA;AAAA,IAC9B,CAAC,OAAA,CAAQ,UAAU,GAAG,OAAA,CAAQ;AAAA,GAChC;AAEA,EAAA,IAAI,OAAA,CAAQ,YAAA,IAAgB,OAAA,CAAQ,UAAA,EAAY;AAC9C,IAAA,OAAA,CAAQ,OAAA,CAAQ,UAAU,CAAA,GAAI,OAAA,CAAQ,YAAA;AAAA,EACxC;AAEA,EAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,SAAA,EAAW;AAAA,IACtC,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA;AAAA,IACA,IAAA,EAAM,yBAAyB,KAAK;AAAA,GACrC,CAAA;AAED,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,EAChE;AACF;;;AC5CA,eAAsB,0BAAA,CACpB,QAAA,EACA,OAAA,EACA,OAAA,GAAuC,EAAC,EACzB;AACf,EAAA,IAAI,OAAA,CAAQ,QAAA,IAAY,OAAA,CAAQ,QAAA,KAAa,QAAQ,QAAA,EAAU;AAC7D,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAAA,EAClD;AAEA,EAAA,IAAI,CAAC,QAAQ,YAAA,EAAc;AACzB,IAAA,MAAM,IAAI,MAAM,sDAAsD,CAAA;AAAA,EACxE;AAEA,EAAA,MAAM,QAAA,GAAW,MAAM,QAAA,CAAS,cAAA,EAAe;AAC/C,EAAA,MAAM,OAAA,GAAU,cAAA,CAAe,OAAA,CAAQ,YAAY,CAAA;AACnD,EAAA,MAAM,SAAA,GAAY,sBAAA,CAAuB,OAAA,EAAS,OAAA,CAAQ,QAAQ,CAAA;AAElE,EAAA,MAAM,cAAA,CAAe,SAAA,EAAW,QAAA,CAAS,KAAA,EAAO;AAAA,IAC9C,MAAM,QAAA,CAAS,IAAA;AAAA,IACf,UAAU,QAAA,CAAS,QAAA;AAAA,IACnB,UAAA,EAAY,oBAAA;AAAA,IACZ,UAAA,EAAY,oBAAA;AAAA,IACZ,cAAc,QAAA,CAAS,IAAA;AAAA,IACvB,UAAA,EAAY;AAAA,GACb,CAAA;AACH","file":"index.cjs","sourcesContent":["import type { WriteOperation } from './write';\r\n\r\n/** Client and server roles on the WebSocket hub. */\r\nexport const DevToolsRole = {\r\n MOBILE: 'mobile',\r\n BROWSER: 'browser',\r\n} as const;\r\n\r\nexport type DevToolsRole = (typeof DevToolsRole)[keyof typeof DevToolsRole];\r\n\r\n/** All wire message type identifiers. */\r\nexport const MessageType = {\r\n REGISTER: 'register',\r\n PING: 'ping',\r\n PONG: 'pong',\r\n DEVICE_STATUS: 'deviceStatus',\r\n BROADCAST: 'broadcast',\r\n REFRESH_REQUEST: 'refreshRequest',\r\n SNAPSHOT_UPLOAD_REQUESTED: 'snapshotUploadRequested',\r\n REFRESH_STATUS: 'refreshStatus',\r\n SNAPSHOT_READY: 'snapshotReady',\r\n REFRESH_ERROR: 'refreshError',\r\n EXPORT_SNAPSHOT_REQUEST: 'exportSnapshotRequest',\r\n EXPORT_SNAPSHOT_ERROR: 'exportSnapshotError',\r\n BEGIN_TRANSACTION_REQUEST: 'beginTransactionRequest',\r\n COMMIT_TRANSACTION_REQUEST: 'commitTransactionRequest',\r\n ROLLBACK_TRANSACTION_REQUEST: 'rollbackTransactionRequest',\r\n WRITE_REQUEST: 'writeRequest',\r\n BEGIN_TRANSACTION: 'beginTransaction',\r\n COMMIT_TRANSACTION: 'commitTransaction',\r\n ROLLBACK_TRANSACTION: 'rollbackTransaction',\r\n EXECUTE_WRITE: 'executeWrite',\r\n TRANSACTION_ACK: 'transactionAck',\r\n WRITE_ACK: 'writeAck',\r\n TRANSACTION_STATUS: 'transactionStatus',\r\n WRITE_RESULT: 'writeResult',\r\n WRITE_ERROR: 'writeError',\r\n} as const;\r\n\r\nexport type MessageTypeValue = (typeof MessageType)[keyof typeof MessageType];\r\n\r\n/** Shared base for every protocol message. */\r\nexport interface DevToolsMessageBase {\r\n type: MessageTypeValue;\r\n timestamp: number;\r\n}\r\n\r\nexport type DeviceMetadata = {\r\n platform?: string;\r\n appName?: string;\r\n [key: string]: string | undefined;\r\n};\r\n\r\n/** Client → Server: register role on connect. */\r\nexport interface RegisterMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.REGISTER;\r\n role: DevToolsRole;\r\n deviceId?: string;\r\n metadata?: DeviceMetadata;\r\n}\r\n\r\n/** Server → Client: heartbeat probe. */\r\nexport interface PingMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.PING;\r\n pingId: string;\r\n}\r\n\r\n/** Client → Server: heartbeat response. */\r\nexport interface PongMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.PONG;\r\n pingId: string;\r\n}\r\n\r\nexport type BrowserConnectionInfo = {\r\n connectionId: string;\r\n connectedAt: number;\r\n};\r\n\r\nexport type MobileDeviceInfo = {\r\n deviceId: string;\r\n connectionId: string;\r\n connectedAt: number;\r\n metadata?: DeviceMetadata;\r\n};\r\n\r\nexport type DeviceStatusPayload = {\r\n browserCount: number;\r\n mobileCount: number;\r\n browsers: BrowserConnectionInfo[];\r\n mobiles: MobileDeviceInfo[];\r\n};\r\n\r\n/** Server → Client: hub snapshot after connect/disconnect. */\r\nexport interface DeviceStatusMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.DEVICE_STATUS;\r\n payload: DeviceStatusPayload;\r\n}\r\n\r\n/** Server → Client: generic routed envelope for future features. */\r\nexport interface BroadcastMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.BROADCAST;\r\n payload: unknown;\r\n}\r\n\r\nexport type RefreshType = 'snapshot';\r\n\r\nexport type RefreshState =\r\n | 'requested'\r\n | 'exporting'\r\n | 'uploading'\r\n | 'ready'\r\n | 'failed'\r\n | 'timeout';\r\n\r\n/** @deprecated Use RefreshState */\r\nexport type SyncState = RefreshState;\r\n\r\nexport type RefreshErrorCode =\r\n | 'DEVICE_OFFLINE'\r\n | 'REFRESH_IN_PROGRESS'\r\n | 'EXPORT_FAILED'\r\n | 'UPLOAD_FAILED'\r\n | 'TIMEOUT'\r\n | 'SNAPSHOT_NOT_FOUND'\r\n | 'INVALID_REQUEST';\r\n\r\n/** @deprecated Use RefreshErrorCode */\r\nexport type SyncErrorCode = RefreshErrorCode;\r\n\r\n/** Browser → Server: request a database snapshot from a mobile device. */\r\nexport interface RefreshRequestMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.REFRESH_REQUEST;\r\n deviceId: string;\r\n refreshType: RefreshType;\r\n}\r\n\r\n/** Server → Mobile: export database and upload via REST. */\r\nexport interface SnapshotUploadRequestedMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.SNAPSHOT_UPLOAD_REQUESTED;\r\n deviceId: string;\r\n refreshType: RefreshType;\r\n}\r\n\r\n/** Server → Browser: refresh progress update. */\r\nexport interface RefreshStatusMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.REFRESH_STATUS;\r\n deviceId: string;\r\n state: RefreshState;\r\n message?: string;\r\n}\r\n\r\n/** Server → Browser: snapshot uploaded and ready to download. */\r\nexport interface SnapshotReadyMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.SNAPSHOT_READY;\r\n deviceId: string;\r\n size: number;\r\n exportedAt: number;\r\n kind: string;\r\n mimeType: string;\r\n databaseName?: string;\r\n}\r\n\r\n/** Server → Browser: refresh failed. */\r\nexport interface RefreshErrorMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.REFRESH_ERROR;\r\n deviceId: string;\r\n code: RefreshErrorCode;\r\n message: string;\r\n}\r\n\r\n/** Mobile → Server: push database snapshot to the web inspector. */\r\nexport interface ExportSnapshotRequestMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.EXPORT_SNAPSHOT_REQUEST;\r\n refreshType: RefreshType;\r\n}\r\n\r\n/** Server → Mobile: export request failed before upload. */\r\nexport interface ExportSnapshotErrorMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.EXPORT_SNAPSHOT_ERROR;\r\n code: RefreshErrorCode;\r\n message: string;\r\n}\r\n\r\nexport type RefreshInitiator = 'browser' | 'mobile';\r\n\r\nexport type TransactionStatusState =\r\n | 'idle'\r\n | 'opening'\r\n | 'open'\r\n | 'committing'\r\n | 'rolling_back'\r\n | 'failed';\r\n\r\nexport type WriteErrorCode =\r\n | 'DEVICE_OFFLINE'\r\n | 'NO_TRANSACTION'\r\n | 'TRANSACTION_BUSY'\r\n | 'INVALID_OPERATION'\r\n | 'WRITE_FAILED'\r\n | 'ADAPTER_ERROR'\r\n | 'TIMEOUT';\r\n\r\n/** Browser → Server: open a write transaction on a device. */\r\nexport interface BeginTransactionRequestMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.BEGIN_TRANSACTION_REQUEST;\r\n transactionId: string;\r\n deviceId: string;\r\n}\r\n\r\n/** Browser → Server: commit the active transaction. */\r\nexport interface CommitTransactionRequestMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.COMMIT_TRANSACTION_REQUEST;\r\n transactionId: string;\r\n deviceId: string;\r\n}\r\n\r\n/** Browser → Server: roll back the active transaction. */\r\nexport interface RollbackTransactionRequestMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.ROLLBACK_TRANSACTION_REQUEST;\r\n transactionId: string;\r\n deviceId: string;\r\n}\r\n\r\n/** Browser → Server: execute a structured write inside a transaction. */\r\nexport interface WriteRequestMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.WRITE_REQUEST;\r\n writeId: string;\r\n transactionId: string;\r\n deviceId: string;\r\n operation: WriteOperation;\r\n}\r\n\r\n/** Server → Mobile: begin a transaction on the live database. */\r\nexport interface BeginTransactionMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.BEGIN_TRANSACTION;\r\n transactionId: string;\r\n}\r\n\r\n/** Server → Mobile: commit the open transaction. */\r\nexport interface CommitTransactionMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.COMMIT_TRANSACTION;\r\n transactionId: string;\r\n}\r\n\r\n/** Server → Mobile: roll back the open transaction. */\r\nexport interface RollbackTransactionMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.ROLLBACK_TRANSACTION;\r\n transactionId: string;\r\n}\r\n\r\n/** Server → Mobile: run a structured write operation. */\r\nexport interface ExecuteWriteMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.EXECUTE_WRITE;\r\n writeId: string;\r\n transactionId: string;\r\n operation: WriteOperation;\r\n}\r\n\r\n/** Mobile → Server: transaction lifecycle acknowledgement. */\r\nexport interface TransactionAckMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.TRANSACTION_ACK;\r\n transactionId: string;\r\n action: 'begin' | 'commit' | 'rollback';\r\n ok: boolean;\r\n message?: string;\r\n}\r\n\r\n/** Mobile → Server: write operation acknowledgement. */\r\nexport interface WriteAckMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.WRITE_ACK;\r\n writeId: string;\r\n transactionId: string;\r\n ok: boolean;\r\n rowsAffected?: number;\r\n message?: string;\r\n}\r\n\r\n/** Server → Browser: transaction state update. */\r\nexport interface TransactionStatusMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.TRANSACTION_STATUS;\r\n transactionId: string;\r\n deviceId: string;\r\n state: TransactionStatusState;\r\n message?: string;\r\n}\r\n\r\n/** Server → Browser: write succeeded. */\r\nexport interface WriteResultMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.WRITE_RESULT;\r\n writeId: string;\r\n transactionId: string;\r\n rowsAffected: number;\r\n}\r\n\r\n/** Server → Browser: write or transaction failed. */\r\nexport interface WriteErrorMessage extends DevToolsMessageBase {\r\n type: typeof MessageType.WRITE_ERROR;\r\n transactionId: string;\r\n writeId?: string;\r\n code: WriteErrorCode;\r\n message: string;\r\n}\r\n\r\nexport type ClientMessage =\r\n | RegisterMessage\r\n | PongMessage\r\n | RefreshRequestMessage\r\n | ExportSnapshotRequestMessage\r\n | BeginTransactionRequestMessage\r\n | CommitTransactionRequestMessage\r\n | RollbackTransactionRequestMessage\r\n | WriteRequestMessage\r\n | TransactionAckMessage\r\n | WriteAckMessage;\r\n\r\nexport type ServerMessage =\r\n | PingMessage\r\n | DeviceStatusMessage\r\n | BroadcastMessage\r\n | SnapshotUploadRequestedMessage\r\n | RefreshStatusMessage\r\n | SnapshotReadyMessage\r\n | RefreshErrorMessage\r\n | ExportSnapshotErrorMessage\r\n | BeginTransactionMessage\r\n | CommitTransactionMessage\r\n | RollbackTransactionMessage\r\n | ExecuteWriteMessage\r\n | TransactionStatusMessage\r\n | WriteResultMessage\r\n | WriteErrorMessage;\r\n\r\nexport type DevToolsMessage = ClientMessage | ServerMessage;\r\n\r\nexport const DEVTOOLS_WS_PATH = '/ws';\r\n\r\nexport const DEFAULT_DEVTOOLS_PORT = 3847;\r\n\r\nexport const DEFAULT_DEVTOOLS_HOST = '0.0.0.0';\r\n\r\nexport const HEARTBEAT_INTERVAL_MS = 30_000;\r\n\r\nexport const HEARTBEAT_TIMEOUT_MS = 10_000;\r\n\r\nexport const DEVICE_SNAPSHOT_API_PATH = '/api/devices';\r\n\r\nexport const PROJECT_DATABASE_API_PATH = '/api/project/database';\r\n\r\nexport const PROJECT_DATABASE_META_API_PATH = '/api/project/database/meta';\r\n\r\nexport const PROJECT_DATABASES_API_PATH = '/api/project/databases';\r\n\r\nexport const PROJECT_DEVICE_EXPORTS_API_PATH = '/api/project/devices';\r\n\r\n/** @deprecated Use DEVICE_SNAPSHOT_API_PATH */\r\nexport const SNAPSHOT_API_PATH = DEVICE_SNAPSHOT_API_PATH;\r\n\r\nexport const REFRESH_TIMEOUT_MS = 60_000;\r\n\r\n/** @deprecated Use REFRESH_TIMEOUT_MS */\r\nexport const SYNC_TIMEOUT_MS = REFRESH_TIMEOUT_MS;\r\n\r\nexport const WRITE_TRANSACTION_TIMEOUT_MS = 5 * 60 * 1000;\r\n\r\nexport const MAX_SNAPSHOT_BYTES = 50 * 1024 * 1024;\r\n\r\nexport function createMessage<T extends DevToolsMessageBase>(\r\n message: Omit<T, 'timestamp'>,\r\n): T {\r\n return { ...message, timestamp: Date.now() } as T;\r\n}\r\n\r\nexport function buildDevToolsHttpUrl(\r\n host = 'localhost',\r\n port = DEFAULT_DEVTOOLS_PORT,\r\n): string {\r\n return `http://${host}:${port}`;\r\n}\r\n\r\nexport function buildDevToolsWsUrl(\r\n host = 'localhost',\r\n port = DEFAULT_DEVTOOLS_PORT,\r\n): string {\r\n return `ws://${host}:${port}${DEVTOOLS_WS_PATH}`;\r\n}\r\n\r\nexport function buildDeviceSnapshotUrl(httpBaseUrl: string, deviceId: string): string {\r\n const base = httpBaseUrl.replace(/\\/$/, '');\r\n return `${base}${DEVICE_SNAPSHOT_API_PATH}/${encodeURIComponent(deviceId)}/snapshot`;\r\n}\r\n\r\n/** @deprecated Use buildDeviceSnapshotUrl */\r\nexport function buildSnapshotUrl(httpBaseUrl: string, deviceId: string): string {\r\n return buildDeviceSnapshotUrl(httpBaseUrl, deviceId);\r\n}\r\n\r\nexport function wsUrlToHttpUrl(wsUrl: string): string {\r\n const url = new URL(wsUrl);\r\n url.protocol = url.protocol === 'wss:' ? 'https:' : 'http:';\r\n url.pathname = '';\r\n url.search = '';\r\n url.hash = '';\r\n return url.toString().replace(/\\/$/, '');\r\n}\r\n\r\nfunction hasMessageType(value: unknown): value is { type: string } {\r\n return typeof value === 'object' && value !== null && typeof (value as { type: unknown }).type === 'string';\r\n}\r\n\r\nexport function isRegisterMessage(value: unknown): value is RegisterMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.REGISTER) {\r\n return false;\r\n }\r\n\r\n const message = value as RegisterMessage;\r\n return (\r\n message.role === DevToolsRole.MOBILE || message.role === DevToolsRole.BROWSER\r\n );\r\n}\r\n\r\nexport function isPongMessage(value: unknown): value is PongMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.PONG) {\r\n return false;\r\n }\r\n\r\n const message = value as PongMessage;\r\n return typeof message.pingId === 'string';\r\n}\r\n\r\nexport function isRefreshRequestMessage(value: unknown): value is RefreshRequestMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.REFRESH_REQUEST) {\r\n return false;\r\n }\r\n\r\n const message = value as RefreshRequestMessage;\r\n return typeof message.deviceId === 'string' && message.refreshType === 'snapshot';\r\n}\r\n\r\nexport function isSnapshotUploadRequestedMessage(\r\n value: unknown,\r\n): value is SnapshotUploadRequestedMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.SNAPSHOT_UPLOAD_REQUESTED) {\r\n return false;\r\n }\r\n\r\n const message = value as SnapshotUploadRequestedMessage;\r\n return typeof message.deviceId === 'string' && message.refreshType === 'snapshot';\r\n}\r\n\r\nexport function isRefreshStatusMessage(value: unknown): value is RefreshStatusMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.REFRESH_STATUS) {\r\n return false;\r\n }\r\n\r\n const message = value as RefreshStatusMessage;\r\n return typeof message.deviceId === 'string' && typeof message.state === 'string';\r\n}\r\n\r\nexport function isSnapshotReadyMessage(value: unknown): value is SnapshotReadyMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.SNAPSHOT_READY) {\r\n return false;\r\n }\r\n\r\n const message = value as SnapshotReadyMessage;\r\n return (\r\n typeof message.deviceId === 'string' &&\r\n typeof message.size === 'number' &&\r\n typeof message.exportedAt === 'number' &&\r\n typeof message.kind === 'string' &&\r\n typeof message.mimeType === 'string'\r\n );\r\n}\r\n\r\nexport function isRefreshErrorMessage(value: unknown): value is RefreshErrorMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.REFRESH_ERROR) {\r\n return false;\r\n }\r\n\r\n const message = value as RefreshErrorMessage;\r\n return typeof message.deviceId === 'string' && typeof message.code === 'string';\r\n}\r\n\r\nexport function isExportSnapshotRequestMessage(\r\n value: unknown,\r\n): value is ExportSnapshotRequestMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.EXPORT_SNAPSHOT_REQUEST) {\r\n return false;\r\n }\r\n\r\n const message = value as ExportSnapshotRequestMessage;\r\n return message.refreshType === 'snapshot';\r\n}\r\n\r\nexport function isExportSnapshotErrorMessage(\r\n value: unknown,\r\n): value is ExportSnapshotErrorMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.EXPORT_SNAPSHOT_ERROR) {\r\n return false;\r\n }\r\n\r\n const message = value as ExportSnapshotErrorMessage;\r\n return typeof message.code === 'string' && typeof message.message === 'string';\r\n}\r\n\r\nexport function isBeginTransactionRequestMessage(\r\n value: unknown,\r\n): value is BeginTransactionRequestMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.BEGIN_TRANSACTION_REQUEST) {\r\n return false;\r\n }\r\n\r\n const message = value as BeginTransactionRequestMessage;\r\n return typeof message.transactionId === 'string' && typeof message.deviceId === 'string';\r\n}\r\n\r\nexport function isCommitTransactionRequestMessage(\r\n value: unknown,\r\n): value is CommitTransactionRequestMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.COMMIT_TRANSACTION_REQUEST) {\r\n return false;\r\n }\r\n\r\n const message = value as CommitTransactionRequestMessage;\r\n return typeof message.transactionId === 'string' && typeof message.deviceId === 'string';\r\n}\r\n\r\nexport function isRollbackTransactionRequestMessage(\r\n value: unknown,\r\n): value is RollbackTransactionRequestMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.ROLLBACK_TRANSACTION_REQUEST) {\r\n return false;\r\n }\r\n\r\n const message = value as RollbackTransactionRequestMessage;\r\n return typeof message.transactionId === 'string' && typeof message.deviceId === 'string';\r\n}\r\n\r\nexport function isWriteRequestMessage(value: unknown): value is WriteRequestMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.WRITE_REQUEST) {\r\n return false;\r\n }\r\n\r\n const message = value as WriteRequestMessage;\r\n return (\r\n typeof message.writeId === 'string' &&\r\n typeof message.transactionId === 'string' &&\r\n typeof message.deviceId === 'string' &&\r\n typeof message.operation === 'object' &&\r\n message.operation !== null\r\n );\r\n}\r\n\r\nexport function isTransactionAckMessage(value: unknown): value is TransactionAckMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.TRANSACTION_ACK) {\r\n return false;\r\n }\r\n\r\n const message = value as TransactionAckMessage;\r\n return (\r\n typeof message.transactionId === 'string' &&\r\n (message.action === 'begin' || message.action === 'commit' || message.action === 'rollback') &&\r\n typeof message.ok === 'boolean'\r\n );\r\n}\r\n\r\nexport function isWriteAckMessage(value: unknown): value is WriteAckMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.WRITE_ACK) {\r\n return false;\r\n }\r\n\r\n const message = value as WriteAckMessage;\r\n return (\r\n typeof message.writeId === 'string' &&\r\n typeof message.transactionId === 'string' &&\r\n typeof message.ok === 'boolean'\r\n );\r\n}\r\n\r\nexport function isClientMessage(value: unknown): value is ClientMessage {\r\n return (\r\n isRegisterMessage(value) ||\r\n isPongMessage(value) ||\r\n isRefreshRequestMessage(value) ||\r\n isExportSnapshotRequestMessage(value) ||\r\n isBeginTransactionRequestMessage(value) ||\r\n isCommitTransactionRequestMessage(value) ||\r\n isRollbackTransactionRequestMessage(value) ||\r\n isWriteRequestMessage(value) ||\r\n isTransactionAckMessage(value) ||\r\n isWriteAckMessage(value)\r\n );\r\n}\r\n\r\nexport function isPingMessage(value: unknown): value is PingMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.PING) {\r\n return false;\r\n }\r\n\r\n const message = value as PingMessage;\r\n return typeof message.pingId === 'string';\r\n}\r\n\r\nexport function isDeviceStatusMessage(value: unknown): value is DeviceStatusMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.DEVICE_STATUS) {\r\n return false;\r\n }\r\n\r\n const message = value as DeviceStatusMessage;\r\n return typeof message.payload === 'object' && message.payload !== null;\r\n}\r\n\r\nexport function isBroadcastMessage(value: unknown): value is BroadcastMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.BROADCAST) {\r\n return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport function isBeginTransactionMessage(value: unknown): value is BeginTransactionMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.BEGIN_TRANSACTION) {\r\n return false;\r\n }\r\n\r\n const message = value as BeginTransactionMessage;\r\n return typeof message.transactionId === 'string';\r\n}\r\n\r\nexport function isCommitTransactionMessage(value: unknown): value is CommitTransactionMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.COMMIT_TRANSACTION) {\r\n return false;\r\n }\r\n\r\n const message = value as CommitTransactionMessage;\r\n return typeof message.transactionId === 'string';\r\n}\r\n\r\nexport function isRollbackTransactionMessage(value: unknown): value is RollbackTransactionMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.ROLLBACK_TRANSACTION) {\r\n return false;\r\n }\r\n\r\n const message = value as RollbackTransactionMessage;\r\n return typeof message.transactionId === 'string';\r\n}\r\n\r\nexport function isExecuteWriteMessage(value: unknown): value is ExecuteWriteMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.EXECUTE_WRITE) {\r\n return false;\r\n }\r\n\r\n const message = value as ExecuteWriteMessage;\r\n return (\r\n typeof message.writeId === 'string' &&\r\n typeof message.transactionId === 'string' &&\r\n typeof message.operation === 'object' &&\r\n message.operation !== null\r\n );\r\n}\r\n\r\nexport function isTransactionStatusMessage(value: unknown): value is TransactionStatusMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.TRANSACTION_STATUS) {\r\n return false;\r\n }\r\n\r\n const message = value as TransactionStatusMessage;\r\n return (\r\n typeof message.transactionId === 'string' &&\r\n typeof message.deviceId === 'string' &&\r\n typeof message.state === 'string'\r\n );\r\n}\r\n\r\nexport function isWriteResultMessage(value: unknown): value is WriteResultMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.WRITE_RESULT) {\r\n return false;\r\n }\r\n\r\n const message = value as WriteResultMessage;\r\n return (\r\n typeof message.writeId === 'string' &&\r\n typeof message.transactionId === 'string' &&\r\n typeof message.rowsAffected === 'number'\r\n );\r\n}\r\n\r\nexport function isWriteErrorMessage(value: unknown): value is WriteErrorMessage {\r\n if (!hasMessageType(value) || value.type !== MessageType.WRITE_ERROR) {\r\n return false;\r\n }\r\n\r\n const message = value as WriteErrorMessage;\r\n return typeof message.transactionId === 'string' && typeof message.code === 'string';\r\n}\r\n\r\nexport function isServerMessage(value: unknown): value is ServerMessage {\r\n return (\r\n isPingMessage(value) ||\r\n isDeviceStatusMessage(value) ||\r\n isBroadcastMessage(value) ||\r\n isSnapshotUploadRequestedMessage(value) ||\r\n isRefreshStatusMessage(value) ||\r\n isSnapshotReadyMessage(value) ||\r\n isRefreshErrorMessage(value) ||\r\n isExportSnapshotErrorMessage(value) ||\r\n isBeginTransactionMessage(value) ||\r\n isCommitTransactionMessage(value) ||\r\n isRollbackTransactionMessage(value) ||\r\n isExecuteWriteMessage(value) ||\r\n isTransactionStatusMessage(value) ||\r\n isWriteResultMessage(value) ||\r\n isWriteErrorMessage(value)\r\n );\r\n}\r\n","export function generateConnectionId(): string {\r\n return generateUniqueId('conn');\r\n}\r\n\r\nexport function generateDeviceId(): string {\r\n return generateUniqueId('device');\r\n}\r\n\r\nexport function generatePingId(): string {\r\n return generateUniqueId('ping');\r\n}\r\n\r\nexport function generateSyncId(): string {\r\n return generateUniqueId('sync');\r\n}\r\n\r\nexport function generateTransactionId(): string {\r\n return generateUniqueId('txn');\r\n}\r\n\r\nexport function generateWriteId(): string {\r\n return generateUniqueId('write');\r\n}\r\n\r\nfunction generateUniqueId(prefix: string): string {\r\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\r\n return `${prefix}-${crypto.randomUUID()}`;\r\n }\r\n\r\n const random = Math.random().toString(36).slice(2, 10);\r\n return `${prefix}-${Date.now()}-${random}`;\r\n}\r\n","export type ReconnectOptions = {\n baseMs?: number;\n maxMs?: number;\n jitterMs?: number;\n};\n\nconst DEFAULT_BASE_MS = 1_000;\nconst DEFAULT_MAX_MS = 30_000;\nconst DEFAULT_JITTER_MS = 500;\n\nexport function calculateBackoffDelay(attempt: number, options: ReconnectOptions = {}): number {\n const baseMs = options.baseMs ?? DEFAULT_BASE_MS;\n const maxMs = options.maxMs ?? DEFAULT_MAX_MS;\n const jitterMs = options.jitterMs ?? DEFAULT_JITTER_MS;\n\n const exponential = baseMs * 2 ** attempt;\n const capped = Math.min(exponential, maxMs);\n const jitter = Math.floor(Math.random() * jitterMs);\n\n return capped + jitter;\n}\n\nexport type ReconnectSchedulerOptions = ReconnectOptions & {\n onReconnect: () => void;\n};\n\nexport class ReconnectScheduler {\n private attempt = 0;\n private timer: ReturnType<typeof setTimeout> | null = null;\n private readonly onReconnect: () => void;\n private readonly options: ReconnectOptions;\n\n constructor({ onReconnect, ...options }: ReconnectSchedulerOptions) {\n this.onReconnect = onReconnect;\n this.options = options;\n }\n\n schedule(): void {\n if (this.timer !== null) {\n return;\n }\n\n const delay = calculateBackoffDelay(this.attempt, this.options);\n this.attempt += 1;\n\n this.timer = setTimeout(() => {\n this.timer = null;\n this.onReconnect();\n }, delay);\n }\n\n reset(): void {\n this.attempt = 0;\n this.cancel();\n }\n\n cancel(): void {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n}\n","import {\r\n buildDevToolsWsUrl,\r\n DEFAULT_DEVTOOLS_PORT,\r\n DevToolsRole,\r\n isBeginTransactionMessage,\r\n isCommitTransactionMessage,\r\n isDeviceStatusMessage,\r\n isExecuteWriteMessage,\r\n isExportSnapshotErrorMessage,\r\n isPingMessage,\r\n isRefreshErrorMessage,\r\n isRefreshStatusMessage,\r\n isRollbackTransactionMessage,\r\n isSnapshotReadyMessage,\r\n isSnapshotUploadRequestedMessage,\r\n isTransactionStatusMessage,\r\n isWriteErrorMessage,\r\n isWriteResultMessage,\r\n MessageType,\r\n type ClientMessage,\r\n type DeviceMetadata,\r\n type DeviceStatusPayload,\r\n type ExportSnapshotErrorMessage,\r\n type PongMessage,\r\n type RefreshErrorMessage,\r\n type RefreshRequestMessage,\r\n type RefreshStatusMessage,\r\n type RegisterMessage,\r\n type SnapshotReadyMessage,\r\n type SnapshotUploadRequestedMessage,\r\n type TransactionAckMessage,\r\n type TransactionStatusMessage,\r\n type WriteAckMessage,\r\n type WriteErrorMessage,\r\n type WriteResultMessage,\r\n} from '../types/protocol';\r\nimport type { WriteOperation } from '../types/write';\r\nimport { generateDeviceId, generateTransactionId, generateWriteId } from '../utils/ids';\r\nimport { ReconnectScheduler } from '../utils/reconnect';\r\n\r\nexport type ConnectionState = 'connecting' | 'connected' | 'reconnecting' | 'disconnected';\r\n\r\nexport type TransactionState = 'idle' | 'opening' | 'open' | 'committing' | 'rolling_back';\r\n\r\nexport type DevToolsClientOptions = {\r\n serverUrl?: string;\r\n role?: DevToolsRole;\r\n deviceId?: string;\r\n metadata?: DeviceMetadata;\r\n WebSocketImpl?: typeof WebSocket;\r\n onConnect?: () => void;\r\n onDisconnect?: () => void;\r\n onConnectionStateChange?: (state: ConnectionState) => void;\r\n onDeviceStatus?: (status: DeviceStatusPayload) => void;\r\n onSnapshotUploadRequested?: (message: SnapshotUploadRequestedMessage) => void;\r\n onExportSnapshotError?: (message: ExportSnapshotErrorMessage) => void;\r\n onRefreshStatus?: (message: RefreshStatusMessage) => void;\r\n onSnapshotReady?: (message: SnapshotReadyMessage) => void;\r\n onRefreshError?: (message: RefreshErrorMessage) => void;\r\n onBeginTransaction?: (message: import('../types/protocol').BeginTransactionMessage) => void;\r\n onCommitTransaction?: (message: import('../types/protocol').CommitTransactionMessage) => void;\r\n onRollbackTransaction?: (message: import('../types/protocol').RollbackTransactionMessage) => void;\r\n onExecuteWrite?: (message: import('../types/protocol').ExecuteWriteMessage) => void;\r\n onTransactionStatus?: (message: TransactionStatusMessage) => void;\r\n onWriteResult?: (message: WriteResultMessage) => void;\r\n onWriteError?: (message: WriteErrorMessage) => void;\r\n onTransactionStateChange?: (state: TransactionState) => void;\r\n onError?: (error: Error) => void;\r\n};\r\n\r\nexport type DevToolsClient = {\r\n connect: () => void;\r\n disconnect: () => void;\r\n getConnectionState: () => ConnectionState;\r\n getLastConnectionError: () => string | null;\r\n getDeviceStatus: () => DeviceStatusPayload | null;\r\n getDeviceId: () => string | undefined;\r\n getServerUrl: () => string;\r\n setServerUrl: (url: string) => void;\r\n send: (message: ClientMessageInput) => void;\r\n requestRefresh: (deviceId: string) => void;\r\n requestExportSnapshot: () => void;\r\n sendTransactionAck: (message: Omit<TransactionAckMessage, 'timestamp' | 'type'>) => void;\r\n sendWriteAck: (message: Omit<WriteAckMessage, 'timestamp' | 'type'>) => void;\r\n beginTransaction: (deviceId: string) => Promise<void>;\r\n commitTransaction: () => Promise<void>;\r\n rollbackTransaction: () => Promise<void>;\r\n executeWrite: (operation: WriteOperation) => Promise<{ rowsAffected: number }>;\r\n getTransactionState: () => TransactionState;\r\n getActiveTransactionId: () => string | null;\r\n};\r\n\r\ntype ClientMessageInput =\r\n | Omit<RegisterMessage, 'timestamp'>\r\n | Omit<PongMessage, 'timestamp'>\r\n | Omit<RefreshRequestMessage, 'timestamp'>\r\n | Omit<import('../types/protocol').ExportSnapshotRequestMessage, 'timestamp'>\r\n | Omit<TransactionAckMessage, 'timestamp'>\r\n | Omit<WriteAckMessage, 'timestamp'>\r\n | Omit<import('../types/protocol').BeginTransactionRequestMessage, 'timestamp'>\r\n | Omit<import('../types/protocol').CommitTransactionRequestMessage, 'timestamp'>\r\n | Omit<import('../types/protocol').RollbackTransactionRequestMessage, 'timestamp'>\r\n | Omit<import('../types/protocol').WriteRequestMessage, 'timestamp'>;\r\n\r\nconst WRITE_TIMEOUT_MS = 30_000;\r\n\r\nexport function createDevToolsClient(options: DevToolsClientOptions = {}): DevToolsClient {\r\n const role = options.role ?? DevToolsRole.MOBILE;\r\n const WebSocketImpl = options.WebSocketImpl ?? globalThis.WebSocket;\r\n\r\n if (!WebSocketImpl) {\r\n throw new Error('WebSocket is not available in this environment.');\r\n }\r\n\r\n let socket: InstanceType<typeof WebSocketImpl> | null = null;\r\n let deviceStatus: DeviceStatusPayload | null = null;\r\n let connectionState: ConnectionState = 'disconnected';\r\n let lastConnectionError: string | null = null;\r\n let intentionalDisconnect = false;\r\n let transactionState: TransactionState = 'idle';\r\n let activeTransactionId: string | null = null;\r\n let activeDeviceId: string | null = null;\r\n\r\n const pendingTransaction = new Map<\r\n string,\r\n { resolve: () => void; reject: (error: Error) => void; action: 'begin' | 'commit' | 'rollback' }\r\n >();\r\n const pendingWrites = new Map<\r\n string,\r\n { resolve: (result: { rowsAffected: number }) => void; reject: (error: Error) => void }\r\n >();\r\n\r\n const deviceId =\r\n role === DevToolsRole.MOBILE ? (options.deviceId ?? generateDeviceId()) : undefined;\r\n\r\n let wsUrl =\r\n options.serverUrl ?? buildDevToolsWsUrl('localhost', DEFAULT_DEVTOOLS_PORT);\r\n\r\n const setConnectionState = (state: ConnectionState): void => {\r\n if (connectionState === state) {\r\n return;\r\n }\r\n\r\n connectionState = state;\r\n options.onConnectionStateChange?.(state);\r\n };\r\n\r\n const setTransactionState = (state: TransactionState): void => {\r\n if (transactionState === state) {\r\n return;\r\n }\r\n\r\n transactionState = state;\r\n options.onTransactionStateChange?.(state);\r\n };\r\n\r\n const resetTransaction = (): void => {\r\n setTransactionState('idle');\r\n activeTransactionId = null;\r\n activeDeviceId = null;\r\n };\r\n\r\n const rejectPendingTransaction = (transactionId: string, error: Error): void => {\r\n const pending = pendingTransaction.get(transactionId);\r\n\r\n if (pending) {\r\n pending.reject(error);\r\n pendingTransaction.delete(transactionId);\r\n }\r\n };\r\n\r\n const rejectAllPending = (error: Error): void => {\r\n for (const [id, pending] of pendingTransaction) {\r\n pending.reject(error);\r\n pendingTransaction.delete(id);\r\n }\r\n\r\n for (const [id, pending] of pendingWrites) {\r\n pending.reject(error);\r\n pendingWrites.delete(id);\r\n }\r\n\r\n resetTransaction();\r\n };\r\n\r\n const reconnectScheduler = new ReconnectScheduler({\r\n onReconnect: () => {\r\n openSocket();\r\n },\r\n });\r\n\r\n const send = (message: ClientMessageInput): void => {\r\n if (!socket || socket.readyState !== WebSocketImpl.OPEN) {\r\n return;\r\n }\r\n\r\n socket.send(JSON.stringify({ ...message, timestamp: Date.now() }));\r\n };\r\n\r\n const sendRegister = (): void => {\r\n send({\r\n type: MessageType.REGISTER,\r\n role,\r\n ...(deviceId ? { deviceId } : {}),\r\n ...(options.metadata ? { metadata: options.metadata } : {}),\r\n });\r\n };\r\n\r\n const handleServerMessage = (parsed: unknown): void => {\r\n if (isPingMessage(parsed)) {\r\n send({\r\n type: MessageType.PONG,\r\n pingId: parsed.pingId,\r\n });\r\n return;\r\n }\r\n\r\n if (isDeviceStatusMessage(parsed)) {\r\n deviceStatus = parsed.payload;\r\n options.onDeviceStatus?.(parsed.payload);\r\n return;\r\n }\r\n\r\n if (isSnapshotUploadRequestedMessage(parsed)) {\r\n options.onSnapshotUploadRequested?.(parsed);\r\n return;\r\n }\r\n\r\n if (isExportSnapshotErrorMessage(parsed)) {\r\n options.onExportSnapshotError?.(parsed);\r\n return;\r\n }\r\n\r\n if (isRefreshStatusMessage(parsed)) {\r\n options.onRefreshStatus?.(parsed);\r\n return;\r\n }\r\n\r\n if (isSnapshotReadyMessage(parsed)) {\r\n options.onSnapshotReady?.(parsed);\r\n return;\r\n }\r\n\r\n if (isRefreshErrorMessage(parsed)) {\r\n options.onRefreshError?.(parsed);\r\n return;\r\n }\r\n\r\n if (isBeginTransactionMessage(parsed)) {\r\n options.onBeginTransaction?.(parsed);\r\n return;\r\n }\r\n\r\n if (isCommitTransactionMessage(parsed)) {\r\n options.onCommitTransaction?.(parsed);\r\n return;\r\n }\r\n\r\n if (isRollbackTransactionMessage(parsed)) {\r\n options.onRollbackTransaction?.(parsed);\r\n return;\r\n }\r\n\r\n if (isExecuteWriteMessage(parsed)) {\r\n options.onExecuteWrite?.(parsed);\r\n return;\r\n }\r\n\r\n if (isTransactionStatusMessage(parsed)) {\r\n options.onTransactionStatus?.(parsed);\r\n\r\n if (role !== DevToolsRole.BROWSER) {\r\n return;\r\n }\r\n\r\n const pending = pendingTransaction.get(parsed.transactionId);\r\n\r\n if (parsed.state === 'open' && pending?.action === 'begin') {\r\n setTransactionState('open');\r\n activeTransactionId = parsed.transactionId;\r\n activeDeviceId = parsed.deviceId;\r\n pending.resolve();\r\n pendingTransaction.delete(parsed.transactionId);\r\n return;\r\n }\r\n\r\n if (parsed.state === 'idle' && pending && (pending.action === 'commit' || pending.action === 'rollback')) {\r\n resetTransaction();\r\n pending.resolve();\r\n pendingTransaction.delete(parsed.transactionId);\r\n return;\r\n }\r\n\r\n if (parsed.state === 'failed') {\r\n rejectPendingTransaction(\r\n parsed.transactionId,\r\n new Error(parsed.message ?? 'Transaction failed'),\r\n );\r\n resetTransaction();\r\n }\r\n\r\n return;\r\n }\r\n\r\n if (isWriteResultMessage(parsed)) {\r\n options.onWriteResult?.(parsed);\r\n\r\n const pending = pendingWrites.get(parsed.writeId);\r\n\r\n if (pending) {\r\n pending.resolve({ rowsAffected: parsed.rowsAffected });\r\n pendingWrites.delete(parsed.writeId);\r\n }\r\n\r\n return;\r\n }\r\n\r\n if (isWriteErrorMessage(parsed)) {\r\n options.onWriteError?.(parsed);\r\n\r\n const error = new Error(parsed.message);\r\n\r\n if (parsed.writeId) {\r\n const pendingWrite = pendingWrites.get(parsed.writeId);\r\n\r\n if (pendingWrite) {\r\n pendingWrite.reject(error);\r\n pendingWrites.delete(parsed.writeId);\r\n }\r\n } else {\r\n rejectPendingTransaction(parsed.transactionId, error);\r\n resetTransaction();\r\n }\r\n }\r\n };\r\n\r\n const openSocket = (): void => {\r\n if (\r\n socket &&\r\n (socket.readyState === WebSocketImpl.OPEN || socket.readyState === WebSocketImpl.CONNECTING)\r\n ) {\r\n return;\r\n }\r\n\r\n setConnectionState(intentionalDisconnect ? 'disconnected' : connectionState === 'disconnected' ? 'connecting' : 'reconnecting');\r\n\r\n socket = new WebSocketImpl(wsUrl);\r\n\r\n socket.addEventListener('open', () => {\r\n reconnectScheduler.reset();\r\n lastConnectionError = null;\r\n setConnectionState('connected');\r\n options.onConnect?.();\r\n sendRegister();\r\n });\r\n\r\n socket.addEventListener('message', (event) => {\r\n let parsed: unknown;\r\n\r\n try {\r\n parsed = JSON.parse(String(event.data));\r\n } catch {\r\n return;\r\n }\r\n\r\n handleServerMessage(parsed);\r\n });\r\n\r\n socket.addEventListener('close', () => {\r\n socket = null;\r\n options.onDisconnect?.();\r\n rejectAllPending(new Error('Disconnected from DevTools hub'));\r\n\r\n if (intentionalDisconnect) {\r\n setConnectionState('disconnected');\r\n return;\r\n }\r\n\r\n setConnectionState('reconnecting');\r\n reconnectScheduler.schedule();\r\n });\r\n\r\n socket.addEventListener('error', () => {\r\n const error = new Error(`WebSocket connection failed: ${wsUrl}`);\r\n lastConnectionError = error.message;\r\n options.onError?.(error);\r\n });\r\n };\r\n\r\n const connect = (): void => {\r\n intentionalDisconnect = false;\r\n openSocket();\r\n };\r\n\r\n const disconnect = (): void => {\r\n intentionalDisconnect = true;\r\n reconnectScheduler.cancel();\r\n socket?.close();\r\n socket = null;\r\n rejectAllPending(new Error('Disconnected'));\r\n setConnectionState('disconnected');\r\n };\r\n\r\n const setServerUrl = (url: string): void => {\r\n wsUrl = url;\r\n const wasConnected =\r\n connectionState === 'connected' ||\r\n connectionState === 'connecting' ||\r\n connectionState === 'reconnecting';\r\n\r\n disconnect();\r\n intentionalDisconnect = false;\r\n\r\n if (wasConnected) {\r\n connect();\r\n }\r\n };\r\n\r\n const requestRefresh = (targetDeviceId: string): void => {\r\n send({\r\n type: MessageType.REFRESH_REQUEST,\r\n deviceId: targetDeviceId,\r\n refreshType: 'snapshot',\r\n });\r\n };\r\n\r\n const requestExportSnapshot = (): void => {\r\n send({\r\n type: MessageType.EXPORT_SNAPSHOT_REQUEST,\r\n refreshType: 'snapshot',\r\n });\r\n };\r\n\r\n const sendTransactionAck = (message: Omit<TransactionAckMessage, 'timestamp' | 'type'>): void => {\r\n send({\r\n type: MessageType.TRANSACTION_ACK,\r\n ...message,\r\n });\r\n };\r\n\r\n const sendWriteAck = (message: Omit<WriteAckMessage, 'timestamp' | 'type'>): void => {\r\n send({\r\n type: MessageType.WRITE_ACK,\r\n ...message,\r\n });\r\n };\r\n\r\n const waitForTransaction = (\r\n transactionId: string,\r\n action: 'begin' | 'commit' | 'rollback',\r\n ): Promise<void> => {\r\n return new Promise((resolve, reject) => {\r\n const timer = setTimeout(() => {\r\n pendingTransaction.delete(transactionId);\r\n reject(new Error(`Transaction ${action} timed out`));\r\n }, WRITE_TIMEOUT_MS);\r\n\r\n pendingTransaction.set(transactionId, {\r\n action,\r\n resolve: () => {\r\n clearTimeout(timer);\r\n resolve();\r\n },\r\n reject: (error) => {\r\n clearTimeout(timer);\r\n reject(error);\r\n },\r\n });\r\n });\r\n };\r\n\r\n const beginTransaction = async (targetDeviceId: string): Promise<void> => {\r\n if (role !== DevToolsRole.BROWSER) {\r\n throw new Error('beginTransaction is only available for browser clients');\r\n }\r\n\r\n if (transactionState !== 'idle') {\r\n throw new Error('A transaction is already active');\r\n }\r\n\r\n const transactionId = generateTransactionId();\r\n setTransactionState('opening');\r\n activeTransactionId = transactionId;\r\n activeDeviceId = targetDeviceId;\r\n\r\n const promise = waitForTransaction(transactionId, 'begin');\r\n\r\n send({\r\n type: MessageType.BEGIN_TRANSACTION_REQUEST,\r\n transactionId,\r\n deviceId: targetDeviceId,\r\n });\r\n\r\n await promise;\r\n };\r\n\r\n const commitTransaction = async (): Promise<void> => {\r\n if (role !== DevToolsRole.BROWSER) {\r\n throw new Error('commitTransaction is only available for browser clients');\r\n }\r\n\r\n if (!activeTransactionId || !activeDeviceId || transactionState !== 'open') {\r\n throw new Error('No open transaction');\r\n }\r\n\r\n const transactionId = activeTransactionId;\r\n const deviceIdForCommit = activeDeviceId;\r\n setTransactionState('committing');\r\n\r\n const promise = waitForTransaction(transactionId, 'commit');\r\n\r\n send({\r\n type: MessageType.COMMIT_TRANSACTION_REQUEST,\r\n transactionId,\r\n deviceId: deviceIdForCommit,\r\n });\r\n\r\n await promise;\r\n };\r\n\r\n const rollbackTransaction = async (): Promise<void> => {\r\n if (role !== DevToolsRole.BROWSER) {\r\n throw new Error('rollbackTransaction is only available for browser clients');\r\n }\r\n\r\n if (!activeTransactionId || !activeDeviceId) {\r\n throw new Error('No active transaction');\r\n }\r\n\r\n const transactionId = activeTransactionId;\r\n const deviceIdForRollback = activeDeviceId;\r\n setTransactionState('rolling_back');\r\n\r\n const promise = waitForTransaction(transactionId, 'rollback');\r\n\r\n send({\r\n type: MessageType.ROLLBACK_TRANSACTION_REQUEST,\r\n transactionId,\r\n deviceId: deviceIdForRollback,\r\n });\r\n\r\n await promise;\r\n };\r\n\r\n const executeWrite = async (operation: WriteOperation): Promise<{ rowsAffected: number }> => {\r\n if (role !== DevToolsRole.BROWSER) {\r\n throw new Error('executeWrite is only available for browser clients');\r\n }\r\n\r\n if (!activeTransactionId || !activeDeviceId || transactionState !== 'open') {\r\n throw new Error('No open transaction');\r\n }\r\n\r\n const writeId = generateWriteId();\r\n\r\n const promise = new Promise<{ rowsAffected: number }>((resolve, reject) => {\r\n const timer = setTimeout(() => {\r\n pendingWrites.delete(writeId);\r\n reject(new Error('Write operation timed out'));\r\n }, WRITE_TIMEOUT_MS);\r\n\r\n pendingWrites.set(writeId, {\r\n resolve: (result) => {\r\n clearTimeout(timer);\r\n resolve(result);\r\n },\r\n reject: (error) => {\r\n clearTimeout(timer);\r\n reject(error);\r\n },\r\n });\r\n });\r\n\r\n send({\r\n type: MessageType.WRITE_REQUEST,\r\n writeId,\r\n transactionId: activeTransactionId,\r\n deviceId: activeDeviceId,\r\n operation,\r\n });\r\n\r\n return promise;\r\n };\r\n\r\n return {\r\n connect,\r\n disconnect,\r\n getConnectionState: () => connectionState,\r\n getLastConnectionError: () => lastConnectionError,\r\n getDeviceStatus: () => deviceStatus,\r\n getDeviceId: () => deviceId,\r\n getServerUrl: () => wsUrl,\r\n setServerUrl,\r\n send,\r\n requestRefresh,\r\n requestExportSnapshot,\r\n sendTransactionAck,\r\n sendWriteAck,\r\n beginTransaction,\r\n commitTransaction,\r\n rollbackTransaction,\r\n executeWrite,\r\n getTransactionState: () => transactionState,\r\n getActiveTransactionId: () => activeTransactionId,\r\n };\r\n}\r\n","export async function fetchSnapshot(downloadUrl: string): Promise<ArrayBuffer> {\r\n let response: Response;\r\n\r\n try {\r\n response = await fetch(downloadUrl);\r\n } catch (error) {\r\n const networkMessage = error instanceof Error ? error.message : String(error);\r\n throw new Error(\r\n `Network error fetching snapshot from ${downloadUrl}. ${networkMessage} If the web UI runs on a different port than the hub, ensure CORS is enabled on the hub HTTP API.`,\r\n );\r\n }\r\n\r\n if (!response.ok) {\r\n throw new Error(\r\n `Failed to fetch snapshot from ${downloadUrl}: ${response.status} ${response.statusText}`,\r\n );\r\n }\r\n\r\n return response.arrayBuffer();\r\n}\r\n","import {\r\n PROJECT_DEVICE_EXPORTS_API_PATH,\r\n wsUrlToHttpUrl,\r\n} from '../types/protocol';\r\nimport type { ResolveProjectDatabaseUrlOptions } from './resolveProjectDatabaseUrl';\r\n\r\nfunction resolveApiBase(serverUrl: string, options?: ResolveProjectDatabaseUrlOptions): string {\r\n if (options?.useSameOriginApi && typeof window !== 'undefined') {\r\n return window.location.origin;\r\n }\r\n\r\n if (serverUrl.startsWith('ws://') || serverUrl.startsWith('wss://')) {\r\n return wsUrlToHttpUrl(serverUrl);\r\n }\r\n\r\n return serverUrl.replace(/\\/$/, '');\r\n}\r\n\r\nexport function resolveDeviceExportDatabaseUrl(\r\n serverUrl: string,\r\n deviceId: string,\r\n options?: ResolveProjectDatabaseUrlOptions,\r\n): string {\r\n const base = resolveApiBase(serverUrl, options);\r\n return `${base}${PROJECT_DEVICE_EXPORTS_API_PATH}/${encodeURIComponent(deviceId)}/database`;\r\n}\r\n\r\nexport function resolveDeviceExportDatabaseMetaUrl(\r\n serverUrl: string,\r\n deviceId: string,\r\n options?: ResolveProjectDatabaseUrlOptions,\r\n): string {\r\n const base = resolveApiBase(serverUrl, options);\r\n return `${base}${PROJECT_DEVICE_EXPORTS_API_PATH}/${encodeURIComponent(deviceId)}/database/meta`;\r\n}\r\n\r\nexport function resolveDeviceExportsUrl(\r\n serverUrl: string,\r\n options?: ResolveProjectDatabaseUrlOptions,\r\n): string {\r\n const base = resolveApiBase(serverUrl, options);\r\n return `${base}${PROJECT_DEVICE_EXPORTS_API_PATH}`;\r\n}\r\n","import { fetchSnapshot } from './fetchSnapshot';\r\nimport type { ListedProjectDatabase, ProjectDatabaseMeta } from './projectDatabase';\r\nimport {\r\n resolveDeviceExportDatabaseMetaUrl,\r\n resolveDeviceExportDatabaseUrl,\r\n resolveDeviceExportsUrl,\r\n} from './resolveDeviceDatabaseUrl';\r\nimport type { ResolveProjectDatabaseUrlOptions } from './resolveProjectDatabaseUrl';\r\n\r\nexport type DeviceExportMeta = ProjectDatabaseMeta;\r\nexport type ListedDeviceExport = ListedProjectDatabase;\r\n\r\nasync function fetchJson<T>(url: string, errorLabel: string): Promise<T> {\r\n let response: Response;\r\n\r\n try {\r\n response = await fetch(url);\r\n } catch (error) {\r\n const networkMessage = error instanceof Error ? error.message : String(error);\r\n throw new Error(`Network error fetching ${errorLabel} from ${url}. ${networkMessage}`);\r\n }\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch ${errorLabel} from ${url}: ${response.status} ${response.statusText}`);\r\n }\r\n\r\n return (await response.json()) as T;\r\n}\r\n\r\nexport async function fetchDeviceExportMeta(\r\n serverUrl: string,\r\n deviceId: string,\r\n options?: ResolveProjectDatabaseUrlOptions,\r\n): Promise<DeviceExportMeta> {\r\n const url = resolveDeviceExportDatabaseMetaUrl(serverUrl, deviceId, options);\r\n return fetchJson<DeviceExportMeta>(url, 'device export metadata');\r\n}\r\n\r\nexport async function fetchDeviceExportDatabase(\r\n serverUrl: string,\r\n deviceId: string,\r\n options?: ResolveProjectDatabaseUrlOptions,\r\n): Promise<ArrayBuffer> {\r\n const url = resolveDeviceExportDatabaseUrl(serverUrl, deviceId, options);\r\n return fetchSnapshot(url);\r\n}\r\n\r\nexport async function fetchDeviceExports(\r\n serverUrl: string,\r\n options?: ResolveProjectDatabaseUrlOptions,\r\n): Promise<ListedDeviceExport[]> {\r\n const url = resolveDeviceExportsUrl(serverUrl, options);\r\n const payload = await fetchJson<{ devices?: ListedDeviceExport[] }>(url, 'device exports');\r\n return payload.devices ?? [];\r\n}\r\n","import {\r\n PROJECT_DATABASE_API_PATH,\r\n PROJECT_DATABASE_META_API_PATH,\r\n PROJECT_DATABASES_API_PATH,\r\n wsUrlToHttpUrl,\r\n} from '../types/protocol';\r\n\r\nexport type ResolveProjectDatabaseUrlOptions = {\r\n useSameOriginApi?: boolean;\r\n};\r\n\r\nfunction resolveApiBase(serverUrl: string, options?: ResolveProjectDatabaseUrlOptions): string {\r\n if (options?.useSameOriginApi && typeof window !== 'undefined') {\r\n return window.location.origin;\r\n }\r\n\r\n if (serverUrl.startsWith('ws://') || serverUrl.startsWith('wss://')) {\r\n return wsUrlToHttpUrl(serverUrl);\r\n }\r\n\r\n return serverUrl.replace(/\\/$/, '');\r\n}\r\n\r\nexport function resolveProjectDatabaseUrl(\r\n serverUrl: string,\r\n options?: ResolveProjectDatabaseUrlOptions,\r\n): string {\r\n return `${resolveApiBase(serverUrl, options)}${PROJECT_DATABASE_API_PATH}`;\r\n}\r\n\r\nexport function resolveProjectDatabaseMetaUrl(\r\n serverUrl: string,\r\n options?: ResolveProjectDatabaseUrlOptions,\r\n): string {\r\n return `${resolveApiBase(serverUrl, options)}${PROJECT_DATABASE_META_API_PATH}`;\r\n}\r\n\r\nexport function resolveProjectDatabasesUrl(\r\n serverUrl: string,\r\n options?: ResolveProjectDatabaseUrlOptions,\r\n): string {\r\n return `${resolveApiBase(serverUrl, options)}${PROJECT_DATABASES_API_PATH}`;\r\n}\r\n","import { fetchSnapshot } from './fetchSnapshot';\r\nimport {\r\n resolveProjectDatabaseMetaUrl,\r\n resolveProjectDatabaseUrl,\r\n resolveProjectDatabasesUrl,\r\n type ResolveProjectDatabaseUrlOptions,\r\n} from './resolveProjectDatabaseUrl';\r\n\r\nexport type ProjectDatabaseMeta = {\r\n exists: boolean;\r\n relativePath?: string;\r\n absolutePath?: string;\r\n kind?: string;\r\n mimeType?: string;\r\n databaseName?: string;\r\n size?: number;\r\n updatedAt?: number;\r\n source?: 'active' | 'device';\r\n deviceId?: string;\r\n};\r\n\r\nexport type ListedProjectDatabase = {\r\n id: string;\r\n label: string;\r\n relativePath: string;\r\n source: 'active' | 'device';\r\n deviceId?: string;\r\n bundleId?: string;\r\n storageKey?: string;\r\n databaseName?: string;\r\n size: number;\r\n updatedAt: number;\r\n};\r\n\r\n/** @deprecated Use device-scoped `fetchDeviceExportMeta` instead. Proxies to the newest device export. */\r\nexport async function fetchProjectDatabaseMeta(\r\n serverUrl: string,\r\n options?: ResolveProjectDatabaseUrlOptions,\r\n): Promise<ProjectDatabaseMeta> {\r\n const url = resolveProjectDatabaseMetaUrl(serverUrl, options);\r\n let response: Response;\r\n\r\n try {\r\n response = await fetch(url);\r\n } catch (error) {\r\n const networkMessage = error instanceof Error ? error.message : String(error);\r\n throw new Error(`Network error fetching project database metadata from ${url}. ${networkMessage}`);\r\n }\r\n\r\n if (!response.ok) {\r\n throw new Error(\r\n `Failed to fetch project database metadata from ${url}: ${response.status} ${response.statusText}`,\r\n );\r\n }\r\n\r\n return (await response.json()) as ProjectDatabaseMeta;\r\n}\r\n\r\n/** @deprecated Use device-scoped `fetchDeviceExportDatabase` instead. Proxies to the newest device export. */\r\nexport async function fetchProjectDatabase(\r\n serverUrl: string,\r\n options?: ResolveProjectDatabaseUrlOptions,\r\n): Promise<ArrayBuffer> {\r\n const url = resolveProjectDatabaseUrl(serverUrl, options);\r\n return fetchSnapshot(url);\r\n}\r\n\r\n/** @deprecated Use `fetchDeviceExports` instead. */\r\nexport async function fetchProjectDatabases(\r\n serverUrl: string,\r\n options?: ResolveProjectDatabaseUrlOptions,\r\n): Promise<ListedProjectDatabase[]> {\r\n const url = resolveProjectDatabasesUrl(serverUrl, options);\r\n let response: Response;\r\n\r\n try {\r\n response = await fetch(url);\r\n } catch (error) {\r\n const networkMessage = error instanceof Error ? error.message : String(error);\r\n throw new Error(`Network error fetching project databases from ${url}. ${networkMessage}`);\r\n }\r\n\r\n if (!response.ok) {\r\n throw new Error(\r\n `Failed to fetch project databases from ${url}: ${response.status} ${response.statusText}`,\r\n );\r\n }\r\n\r\n const payload = (await response.json()) as { databases?: ListedProjectDatabase[] };\r\n return payload.databases ?? [];\r\n}\r\n","import {\r\n buildDeviceSnapshotUrl,\r\n DEVICE_SNAPSHOT_API_PATH,\r\n wsUrlToHttpUrl,\r\n} from '../types/protocol';\r\n\r\nexport type ResolveSnapshotDownloadUrlOptions = {\r\n /**\r\n * When true, returns a same-origin relative path (e.g. `/api/devices/:id/snapshot`).\r\n * Use with a dev-server proxy so the browser avoids cross-origin fetches.\r\n */\r\n useSameOriginApi?: boolean;\r\n};\r\n\r\nexport function resolveSnapshotDownloadUrl(\r\n hubWsUrl: string,\r\n deviceId: string,\r\n options: ResolveSnapshotDownloadUrlOptions = {},\r\n): string {\r\n const path = `${DEVICE_SNAPSHOT_API_PATH}/${encodeURIComponent(deviceId)}/snapshot`;\r\n\r\n if (options.useSameOriginApi) {\r\n return path;\r\n }\r\n\r\n return buildDeviceSnapshotUrl(wsUrlToHttpUrl(hubWsUrl), deviceId);\r\n}\r\n","import type { RefreshErrorCode } from '../types/protocol';\r\n\r\n/** @deprecated Use formatRefreshErrorMessage */\r\nexport function formatSyncErrorMessage(code: RefreshErrorCode, message: string): string {\r\n return formatRefreshErrorMessage(code, message);\r\n}\r\n\r\nexport function formatRefreshErrorMessage(code: RefreshErrorCode, message: string): string {\r\n switch (code) {\r\n case 'DEVICE_OFFLINE':\r\n return 'Selected device disconnected. Reconnect the mobile app and try again.';\r\n case 'REFRESH_IN_PROGRESS':\r\n return 'A refresh is already in progress for this device.';\r\n case 'EXPORT_FAILED':\r\n return `Device failed to export or upload snapshot: ${message}`;\r\n case 'UPLOAD_FAILED':\r\n return `Snapshot upload failed on the hub: ${message}`;\r\n case 'TIMEOUT':\r\n return 'Timed out waiting for the device to upload a snapshot.';\r\n case 'SNAPSHOT_NOT_FOUND':\r\n return 'Snapshot expired or was not found. Click Refresh again.';\r\n case 'INVALID_REQUEST':\r\n return `Invalid refresh request: ${message}`;\r\n default:\r\n return message;\r\n }\r\n}\r\n","import type { DeviceStatusPayload } from '../types/protocol';\r\n\r\nexport type DeviceLabel = {\r\n deviceId: string;\r\n deviceName: string;\r\n};\r\n\r\nexport type DeviceLabelFallback = {\r\n databaseName?: string | null;\r\n label?: string | null;\r\n};\r\n\r\nexport function shortenDeviceId(deviceId: string, visibleChars = 4): string {\r\n if (deviceId.length <= visibleChars * 2 + 1) {\r\n return deviceId;\r\n }\r\n\r\n return `${deviceId.slice(0, visibleChars)}…${deviceId.slice(-visibleChars)}`;\r\n}\r\n\r\nexport function resolveDeviceDisplayName(\r\n deviceId: string,\r\n deviceStatus: DeviceStatusPayload | null,\r\n fallback?: DeviceLabelFallback | null,\r\n): string {\r\n const mobile = deviceStatus?.mobiles.find((device) => device.deviceId === deviceId);\r\n\r\n if (mobile?.metadata?.appName) {\r\n return mobile.metadata.appName;\r\n }\r\n\r\n if (fallback?.databaseName) {\r\n return fallback.databaseName;\r\n }\r\n\r\n if (fallback?.label) {\r\n return fallback.label;\r\n }\r\n\r\n return 'Device export';\r\n}\r\n\r\nexport function resolveDeviceLabel(\r\n deviceId: string,\r\n deviceStatus: DeviceStatusPayload | null,\r\n fallback?: DeviceLabelFallback | null,\r\n): DeviceLabel {\r\n return {\r\n deviceId,\r\n deviceName: resolveDeviceDisplayName(deviceId, deviceStatus, fallback),\r\n };\r\n}\r\n\r\nexport function formatSnapshotReceivedMessage(\r\n deviceLabel: DeviceLabel,\r\n databaseName: string,\r\n): string {\r\n return `${deviceLabel.deviceName} (${shortenDeviceId(deviceLabel.deviceId)}) · ${databaseName}`;\r\n}\r\n\r\nexport type SnapshotToastInitiator = 'mobile' | 'browser';\r\n\r\nexport function buildSnapshotLoadedToast(\r\n initiator: SnapshotToastInitiator,\r\n deviceId: string,\r\n databaseName: string,\r\n deviceStatus: DeviceStatusPayload | null,\r\n fallback?: DeviceLabelFallback | null,\r\n): { title: string; message: string } {\r\n const deviceLabel = resolveDeviceLabel(deviceId, deviceStatus, fallback);\r\n\r\n return {\r\n title: initiator === 'mobile' ? 'New database received' : 'Database refreshed',\r\n message: formatSnapshotReceivedMessage(deviceLabel, databaseName),\r\n };\r\n}\r\n","import type { MobileDeviceInfo } from '../types/protocol';\r\n\r\nexport type DeviceExportRef = {\r\n deviceId: string;\r\n bundleId?: string;\r\n};\r\n\r\nexport type ResolvePreferredDeviceIdInput = {\r\n selectedDeviceId: string | null;\r\n mobiles: MobileDeviceInfo[];\r\n exports: DeviceExportRef[];\r\n};\r\n\r\nfunction findMobileByBundleId(\r\n mobiles: MobileDeviceInfo[],\r\n bundleId?: string,\r\n): MobileDeviceInfo | undefined {\r\n if (!bundleId) {\r\n return undefined;\r\n }\r\n\r\n return mobiles.find((mobile) => mobile.metadata?.bundleId === bundleId);\r\n}\r\n\r\nexport function resolvePreferredDeviceId(input: ResolvePreferredDeviceIdInput): string | null {\r\n const connectedIds = new Set(input.mobiles.map((device) => device.deviceId));\r\n const exportById = new Map(input.exports.map((entry) => [entry.deviceId, entry]));\r\n\r\n if (input.selectedDeviceId) {\r\n if (connectedIds.has(input.selectedDeviceId)) {\r\n return input.selectedDeviceId;\r\n }\r\n\r\n const selectedExport = exportById.get(input.selectedDeviceId);\r\n\r\n if (selectedExport) {\r\n const bundleMatch = findMobileByBundleId(input.mobiles, selectedExport.bundleId);\r\n\r\n if (bundleMatch) {\r\n return bundleMatch.deviceId;\r\n }\r\n\r\n if (input.mobiles.length === 1) {\r\n return input.mobiles[0]!.deviceId;\r\n }\r\n\r\n return input.selectedDeviceId;\r\n }\r\n }\r\n\r\n return input.mobiles[0]?.deviceId ?? input.exports[0]?.deviceId ?? null;\r\n}\r\n\r\nexport function resolveLiveSwitchTarget(input: {\r\n selectedDeviceId: string | null;\r\n mobiles: MobileDeviceInfo[];\r\n exports: DeviceExportRef[];\r\n}): string | null {\r\n if (!input.selectedDeviceId || input.mobiles.length === 0) {\r\n return null;\r\n }\r\n\r\n if (input.mobiles.some((mobile) => mobile.deviceId === input.selectedDeviceId)) {\r\n return null;\r\n }\r\n\r\n const selectedExport = input.exports.find((entry) => entry.deviceId === input.selectedDeviceId);\r\n const bundleMatch = findMobileByBundleId(input.mobiles, selectedExport?.bundleId);\r\n\r\n if (bundleMatch) {\r\n return bundleMatch.deviceId;\r\n }\r\n\r\n return input.mobiles[0]?.deviceId ?? null;\r\n}\r\n","import type { DatabaseKind } from '../types/kind';\r\n\r\nexport const SNAPSHOT_KIND_HEADER = 'x-database-kind';\r\nexport const SNAPSHOT_MIME_HEADER = 'x-snapshot-mime-type';\r\nexport const SNAPSHOT_NAME_HEADER = 'x-database-name';\r\n\r\nexport const SQLITE_SNAPSHOT_MIME_TYPE = 'application/x-sqlite3';\r\n\r\nexport type SnapshotExport = {\r\n bytes: Uint8Array;\r\n mimeType: string;\r\n kind: DatabaseKind;\r\n exportedAt?: number;\r\n};\r\n","import { wsUrlToHttpUrl } from '../types/protocol';\r\n\r\n/**\r\n * React Native fetch does not support `new Blob([ArrayBuffer])`.\r\n * Pass the Uint8Array directly as the request body.\r\n */\r\nexport function createSnapshotUploadBody(bytes: Uint8Array): Uint8Array {\r\n return bytes;\r\n}\r\n\r\n/**\r\n * The hub advertises snapshot URLs using its bind address (often localhost).\r\n * Mobile clients reach the hub via a different host (10.0.2.2, LAN IP, etc.).\r\n * Rewrite the upload URL to match the WebSocket hub URL the device already uses.\r\n */\r\nexport function resolveSnapshotUploadUrl(uploadUrl: string, hubWsUrl: string): string {\r\n const hubHttpBase = wsUrlToHttpUrl(hubWsUrl);\r\n const target = new URL(uploadUrl);\r\n const hub = new URL(hubHttpBase.endsWith('/') ? hubHttpBase : `${hubHttpBase}/`);\r\n\r\n target.protocol = hub.protocol;\r\n target.hostname = hub.hostname;\r\n target.port = hub.port;\r\n\r\n return target.toString();\r\n}\r\n\r\nexport type UploadSnapshotOptions = {\r\n kind: string;\r\n mimeType: string;\r\n kindHeader: string;\r\n mimeHeader: string;\r\n databaseName?: string;\r\n nameHeader?: string;\r\n};\r\n\r\nexport async function uploadSnapshot(\r\n uploadUrl: string,\r\n bytes: Uint8Array,\r\n options: UploadSnapshotOptions,\r\n): Promise<void> {\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/octet-stream',\r\n [options.kindHeader]: options.kind,\r\n [options.mimeHeader]: options.mimeType,\r\n };\r\n\r\n if (options.databaseName && options.nameHeader) {\r\n headers[options.nameHeader] = options.databaseName;\r\n }\r\n\r\n const response = await fetch(uploadUrl, {\r\n method: 'POST',\r\n headers,\r\n body: createSnapshotUploadBody(bytes) as BodyInit,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Upload failed with status ${response.status}`);\r\n }\r\n}\r\n","import type { DatabaseAdapter } from '../types/adapter';\r\nimport {\r\n buildDeviceSnapshotUrl,\r\n wsUrlToHttpUrl,\r\n type SnapshotUploadRequestedMessage,\r\n} from '../types/protocol';\r\nimport { SNAPSHOT_KIND_HEADER, SNAPSHOT_MIME_HEADER, SNAPSHOT_NAME_HEADER } from '../types/snapshot';\r\nimport { uploadSnapshot } from './snapshotUpload';\r\n\r\nexport type HandleDeviceSnapshotOptions = {\r\n /** WebSocket URL of the connected hub — used to build the upload URL on mobile. */\r\n hubServerUrl?: string;\r\n /** This mobile client's device ID — upload is ignored when it does not match. */\r\n deviceId?: string;\r\n};\r\n\r\nexport async function handleDeviceSnapshotUpload(\r\n database: DatabaseAdapter | undefined,\r\n message: SnapshotUploadRequestedMessage,\r\n options: HandleDeviceSnapshotOptions = {},\r\n): Promise<void> {\r\n if (options.deviceId && message.deviceId !== options.deviceId) {\r\n return;\r\n }\r\n\r\n if (!database) {\r\n throw new Error('No database adapter configured');\r\n }\r\n\r\n if (!options.hubServerUrl) {\r\n throw new Error('hubServerUrl is required to upload a device snapshot');\r\n }\r\n\r\n const snapshot = await database.exportSnapshot();\r\n const hubHttp = wsUrlToHttpUrl(options.hubServerUrl);\r\n const uploadUrl = buildDeviceSnapshotUrl(hubHttp, message.deviceId);\r\n\r\n await uploadSnapshot(uploadUrl, snapshot.bytes, {\r\n kind: snapshot.kind,\r\n mimeType: snapshot.mimeType,\r\n kindHeader: SNAPSHOT_KIND_HEADER,\r\n mimeHeader: SNAPSHOT_MIME_HEADER,\r\n databaseName: database.name,\r\n nameHeader: SNAPSHOT_NAME_HEADER,\r\n });\r\n}\r\n"]}
@@ -0,0 +1,75 @@
1
+ export { C as ConnectionState, D as DevToolsClient, a as DevToolsClientOptions, b as DeviceExportMeta, H as HandleDeviceSnapshotOptions, L as ListedDeviceExport, c as ListedProjectDatabase, P as ProjectDatabaseMeta, R as ResolveProjectDatabaseUrlOptions, T as TransactionState, d as createDevToolsClient, f as fetchDeviceExportDatabase, e as fetchDeviceExportMeta, g as fetchDeviceExports, h as fetchProjectDatabase, i as fetchProjectDatabaseMeta, j as fetchProjectDatabases, k as fetchSnapshot, l as handleDeviceSnapshotUpload, r as resolveDeviceExportDatabaseMetaUrl, m as resolveDeviceExportDatabaseUrl, n as resolveDeviceExportsUrl, o as resolveProjectDatabaseMetaUrl, p as resolveProjectDatabaseUrl, q as resolveProjectDatabasesUrl } from '../handleDeviceSnapshot-cYGuitSc.cjs';
2
+ import { RefreshErrorCode, DeviceStatusPayload, MobileDeviceInfo } from '../types/protocol.cjs';
3
+ import '../write-C3toEIMs.cjs';
4
+ import '../adapter-BjJm71wW.cjs';
5
+ import '../snapshot-Dhyecgo2.cjs';
6
+
7
+ type ResolveSnapshotDownloadUrlOptions = {
8
+ /**
9
+ * When true, returns a same-origin relative path (e.g. `/api/devices/:id/snapshot`).
10
+ * Use with a dev-server proxy so the browser avoids cross-origin fetches.
11
+ */
12
+ useSameOriginApi?: boolean;
13
+ };
14
+ declare function resolveSnapshotDownloadUrl(hubWsUrl: string, deviceId: string, options?: ResolveSnapshotDownloadUrlOptions): string;
15
+
16
+ /** @deprecated Use formatRefreshErrorMessage */
17
+ declare function formatSyncErrorMessage(code: RefreshErrorCode, message: string): string;
18
+ declare function formatRefreshErrorMessage(code: RefreshErrorCode, message: string): string;
19
+
20
+ type DeviceLabel = {
21
+ deviceId: string;
22
+ deviceName: string;
23
+ };
24
+ type DeviceLabelFallback = {
25
+ databaseName?: string | null;
26
+ label?: string | null;
27
+ };
28
+ declare function shortenDeviceId(deviceId: string, visibleChars?: number): string;
29
+ declare function resolveDeviceDisplayName(deviceId: string, deviceStatus: DeviceStatusPayload | null, fallback?: DeviceLabelFallback | null): string;
30
+ declare function resolveDeviceLabel(deviceId: string, deviceStatus: DeviceStatusPayload | null, fallback?: DeviceLabelFallback | null): DeviceLabel;
31
+ declare function formatSnapshotReceivedMessage(deviceLabel: DeviceLabel, databaseName: string): string;
32
+ type SnapshotToastInitiator = 'mobile' | 'browser';
33
+ declare function buildSnapshotLoadedToast(initiator: SnapshotToastInitiator, deviceId: string, databaseName: string, deviceStatus: DeviceStatusPayload | null, fallback?: DeviceLabelFallback | null): {
34
+ title: string;
35
+ message: string;
36
+ };
37
+
38
+ type DeviceExportRef = {
39
+ deviceId: string;
40
+ bundleId?: string;
41
+ };
42
+ type ResolvePreferredDeviceIdInput = {
43
+ selectedDeviceId: string | null;
44
+ mobiles: MobileDeviceInfo[];
45
+ exports: DeviceExportRef[];
46
+ };
47
+ declare function resolvePreferredDeviceId(input: ResolvePreferredDeviceIdInput): string | null;
48
+ declare function resolveLiveSwitchTarget(input: {
49
+ selectedDeviceId: string | null;
50
+ mobiles: MobileDeviceInfo[];
51
+ exports: DeviceExportRef[];
52
+ }): string | null;
53
+
54
+ /**
55
+ * React Native fetch does not support `new Blob([ArrayBuffer])`.
56
+ * Pass the Uint8Array directly as the request body.
57
+ */
58
+ declare function createSnapshotUploadBody(bytes: Uint8Array): Uint8Array;
59
+ /**
60
+ * The hub advertises snapshot URLs using its bind address (often localhost).
61
+ * Mobile clients reach the hub via a different host (10.0.2.2, LAN IP, etc.).
62
+ * Rewrite the upload URL to match the WebSocket hub URL the device already uses.
63
+ */
64
+ declare function resolveSnapshotUploadUrl(uploadUrl: string, hubWsUrl: string): string;
65
+ type UploadSnapshotOptions = {
66
+ kind: string;
67
+ mimeType: string;
68
+ kindHeader: string;
69
+ mimeHeader: string;
70
+ databaseName?: string;
71
+ nameHeader?: string;
72
+ };
73
+ declare function uploadSnapshot(uploadUrl: string, bytes: Uint8Array, options: UploadSnapshotOptions): Promise<void>;
74
+
75
+ export { type DeviceExportRef, type DeviceLabel, type DeviceLabelFallback, type ResolvePreferredDeviceIdInput, type ResolveSnapshotDownloadUrlOptions, type SnapshotToastInitiator, buildSnapshotLoadedToast, createSnapshotUploadBody, formatRefreshErrorMessage, formatSnapshotReceivedMessage, formatSyncErrorMessage, resolveDeviceDisplayName, resolveDeviceLabel, resolveLiveSwitchTarget, resolvePreferredDeviceId, resolveSnapshotDownloadUrl, resolveSnapshotUploadUrl, shortenDeviceId, uploadSnapshot };
@@ -0,0 +1,75 @@
1
+ export { C as ConnectionState, D as DevToolsClient, a as DevToolsClientOptions, b as DeviceExportMeta, H as HandleDeviceSnapshotOptions, L as ListedDeviceExport, c as ListedProjectDatabase, P as ProjectDatabaseMeta, R as ResolveProjectDatabaseUrlOptions, T as TransactionState, d as createDevToolsClient, f as fetchDeviceExportDatabase, e as fetchDeviceExportMeta, g as fetchDeviceExports, h as fetchProjectDatabase, i as fetchProjectDatabaseMeta, j as fetchProjectDatabases, k as fetchSnapshot, l as handleDeviceSnapshotUpload, r as resolveDeviceExportDatabaseMetaUrl, m as resolveDeviceExportDatabaseUrl, n as resolveDeviceExportsUrl, o as resolveProjectDatabaseMetaUrl, p as resolveProjectDatabaseUrl, q as resolveProjectDatabasesUrl } from '../handleDeviceSnapshot-CR-4QMdk.js';
2
+ import { RefreshErrorCode, DeviceStatusPayload, MobileDeviceInfo } from '../types/protocol.js';
3
+ import '../write-C3toEIMs.js';
4
+ import '../adapter-DJSjDewg.js';
5
+ import '../snapshot-Dhyecgo2.js';
6
+
7
+ type ResolveSnapshotDownloadUrlOptions = {
8
+ /**
9
+ * When true, returns a same-origin relative path (e.g. `/api/devices/:id/snapshot`).
10
+ * Use with a dev-server proxy so the browser avoids cross-origin fetches.
11
+ */
12
+ useSameOriginApi?: boolean;
13
+ };
14
+ declare function resolveSnapshotDownloadUrl(hubWsUrl: string, deviceId: string, options?: ResolveSnapshotDownloadUrlOptions): string;
15
+
16
+ /** @deprecated Use formatRefreshErrorMessage */
17
+ declare function formatSyncErrorMessage(code: RefreshErrorCode, message: string): string;
18
+ declare function formatRefreshErrorMessage(code: RefreshErrorCode, message: string): string;
19
+
20
+ type DeviceLabel = {
21
+ deviceId: string;
22
+ deviceName: string;
23
+ };
24
+ type DeviceLabelFallback = {
25
+ databaseName?: string | null;
26
+ label?: string | null;
27
+ };
28
+ declare function shortenDeviceId(deviceId: string, visibleChars?: number): string;
29
+ declare function resolveDeviceDisplayName(deviceId: string, deviceStatus: DeviceStatusPayload | null, fallback?: DeviceLabelFallback | null): string;
30
+ declare function resolveDeviceLabel(deviceId: string, deviceStatus: DeviceStatusPayload | null, fallback?: DeviceLabelFallback | null): DeviceLabel;
31
+ declare function formatSnapshotReceivedMessage(deviceLabel: DeviceLabel, databaseName: string): string;
32
+ type SnapshotToastInitiator = 'mobile' | 'browser';
33
+ declare function buildSnapshotLoadedToast(initiator: SnapshotToastInitiator, deviceId: string, databaseName: string, deviceStatus: DeviceStatusPayload | null, fallback?: DeviceLabelFallback | null): {
34
+ title: string;
35
+ message: string;
36
+ };
37
+
38
+ type DeviceExportRef = {
39
+ deviceId: string;
40
+ bundleId?: string;
41
+ };
42
+ type ResolvePreferredDeviceIdInput = {
43
+ selectedDeviceId: string | null;
44
+ mobiles: MobileDeviceInfo[];
45
+ exports: DeviceExportRef[];
46
+ };
47
+ declare function resolvePreferredDeviceId(input: ResolvePreferredDeviceIdInput): string | null;
48
+ declare function resolveLiveSwitchTarget(input: {
49
+ selectedDeviceId: string | null;
50
+ mobiles: MobileDeviceInfo[];
51
+ exports: DeviceExportRef[];
52
+ }): string | null;
53
+
54
+ /**
55
+ * React Native fetch does not support `new Blob([ArrayBuffer])`.
56
+ * Pass the Uint8Array directly as the request body.
57
+ */
58
+ declare function createSnapshotUploadBody(bytes: Uint8Array): Uint8Array;
59
+ /**
60
+ * The hub advertises snapshot URLs using its bind address (often localhost).
61
+ * Mobile clients reach the hub via a different host (10.0.2.2, LAN IP, etc.).
62
+ * Rewrite the upload URL to match the WebSocket hub URL the device already uses.
63
+ */
64
+ declare function resolveSnapshotUploadUrl(uploadUrl: string, hubWsUrl: string): string;
65
+ type UploadSnapshotOptions = {
66
+ kind: string;
67
+ mimeType: string;
68
+ kindHeader: string;
69
+ mimeHeader: string;
70
+ databaseName?: string;
71
+ nameHeader?: string;
72
+ };
73
+ declare function uploadSnapshot(uploadUrl: string, bytes: Uint8Array, options: UploadSnapshotOptions): Promise<void>;
74
+
75
+ export { type DeviceExportRef, type DeviceLabel, type DeviceLabelFallback, type ResolvePreferredDeviceIdInput, type ResolveSnapshotDownloadUrlOptions, type SnapshotToastInitiator, buildSnapshotLoadedToast, createSnapshotUploadBody, formatRefreshErrorMessage, formatSnapshotReceivedMessage, formatSyncErrorMessage, resolveDeviceDisplayName, resolveDeviceLabel, resolveLiveSwitchTarget, resolvePreferredDeviceId, resolveSnapshotDownloadUrl, resolveSnapshotUploadUrl, shortenDeviceId, uploadSnapshot };
@@ -0,0 +1,98 @@
1
+ export { createDevToolsClient, createSnapshotUploadBody, fetchDeviceExportDatabase, fetchDeviceExportMeta, fetchDeviceExports, fetchProjectDatabase, fetchProjectDatabaseMeta, fetchProjectDatabases, fetchSnapshot, formatRefreshErrorMessage, formatSyncErrorMessage, handleDeviceSnapshotUpload, resolveDeviceExportDatabaseMetaUrl, resolveDeviceExportDatabaseUrl, resolveDeviceExportsUrl, resolveProjectDatabaseMetaUrl, resolveProjectDatabaseUrl, resolveProjectDatabasesUrl, resolveSnapshotUploadUrl, uploadSnapshot } from '../chunk-ZS5MZR75.js';
2
+ import '../chunk-AZECU6D7.js';
3
+ import { DEVICE_SNAPSHOT_API_PATH, buildDeviceSnapshotUrl, wsUrlToHttpUrl } from '../chunk-CPVVIH5G.js';
4
+ import '../chunk-HIDZTOJ3.js';
5
+ import '../chunk-DGUM43GV.js';
6
+
7
+ // src/client/resolveSnapshotDownloadUrl.ts
8
+ function resolveSnapshotDownloadUrl(hubWsUrl, deviceId, options = {}) {
9
+ const path = `${DEVICE_SNAPSHOT_API_PATH}/${encodeURIComponent(deviceId)}/snapshot`;
10
+ if (options.useSameOriginApi) {
11
+ return path;
12
+ }
13
+ return buildDeviceSnapshotUrl(wsUrlToHttpUrl(hubWsUrl), deviceId);
14
+ }
15
+
16
+ // src/utils/deviceLabel.ts
17
+ function shortenDeviceId(deviceId, visibleChars = 4) {
18
+ if (deviceId.length <= visibleChars * 2 + 1) {
19
+ return deviceId;
20
+ }
21
+ return `${deviceId.slice(0, visibleChars)}\u2026${deviceId.slice(-visibleChars)}`;
22
+ }
23
+ function resolveDeviceDisplayName(deviceId, deviceStatus, fallback) {
24
+ const mobile = deviceStatus?.mobiles.find((device) => device.deviceId === deviceId);
25
+ if (mobile?.metadata?.appName) {
26
+ return mobile.metadata.appName;
27
+ }
28
+ if (fallback?.databaseName) {
29
+ return fallback.databaseName;
30
+ }
31
+ if (fallback?.label) {
32
+ return fallback.label;
33
+ }
34
+ return "Device export";
35
+ }
36
+ function resolveDeviceLabel(deviceId, deviceStatus, fallback) {
37
+ return {
38
+ deviceId,
39
+ deviceName: resolveDeviceDisplayName(deviceId, deviceStatus, fallback)
40
+ };
41
+ }
42
+ function formatSnapshotReceivedMessage(deviceLabel, databaseName) {
43
+ return `${deviceLabel.deviceName} (${shortenDeviceId(deviceLabel.deviceId)}) \xB7 ${databaseName}`;
44
+ }
45
+ function buildSnapshotLoadedToast(initiator, deviceId, databaseName, deviceStatus, fallback) {
46
+ const deviceLabel = resolveDeviceLabel(deviceId, deviceStatus, fallback);
47
+ return {
48
+ title: initiator === "mobile" ? "New database received" : "Database refreshed",
49
+ message: formatSnapshotReceivedMessage(deviceLabel, databaseName)
50
+ };
51
+ }
52
+
53
+ // src/utils/resolvePreferredDeviceId.ts
54
+ function findMobileByBundleId(mobiles, bundleId) {
55
+ if (!bundleId) {
56
+ return void 0;
57
+ }
58
+ return mobiles.find((mobile) => mobile.metadata?.bundleId === bundleId);
59
+ }
60
+ function resolvePreferredDeviceId(input) {
61
+ const connectedIds = new Set(input.mobiles.map((device) => device.deviceId));
62
+ const exportById = new Map(input.exports.map((entry) => [entry.deviceId, entry]));
63
+ if (input.selectedDeviceId) {
64
+ if (connectedIds.has(input.selectedDeviceId)) {
65
+ return input.selectedDeviceId;
66
+ }
67
+ const selectedExport = exportById.get(input.selectedDeviceId);
68
+ if (selectedExport) {
69
+ const bundleMatch = findMobileByBundleId(input.mobiles, selectedExport.bundleId);
70
+ if (bundleMatch) {
71
+ return bundleMatch.deviceId;
72
+ }
73
+ if (input.mobiles.length === 1) {
74
+ return input.mobiles[0].deviceId;
75
+ }
76
+ return input.selectedDeviceId;
77
+ }
78
+ }
79
+ return input.mobiles[0]?.deviceId ?? input.exports[0]?.deviceId ?? null;
80
+ }
81
+ function resolveLiveSwitchTarget(input) {
82
+ if (!input.selectedDeviceId || input.mobiles.length === 0) {
83
+ return null;
84
+ }
85
+ if (input.mobiles.some((mobile) => mobile.deviceId === input.selectedDeviceId)) {
86
+ return null;
87
+ }
88
+ const selectedExport = input.exports.find((entry) => entry.deviceId === input.selectedDeviceId);
89
+ const bundleMatch = findMobileByBundleId(input.mobiles, selectedExport?.bundleId);
90
+ if (bundleMatch) {
91
+ return bundleMatch.deviceId;
92
+ }
93
+ return input.mobiles[0]?.deviceId ?? null;
94
+ }
95
+
96
+ export { buildSnapshotLoadedToast, formatSnapshotReceivedMessage, resolveDeviceDisplayName, resolveDeviceLabel, resolveLiveSwitchTarget, resolvePreferredDeviceId, resolveSnapshotDownloadUrl, shortenDeviceId };
97
+ //# sourceMappingURL=index.js.map
98
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/client/resolveSnapshotDownloadUrl.ts","../../src/utils/deviceLabel.ts","../../src/utils/resolvePreferredDeviceId.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import {\r\n buildDeviceSnapshotUrl,\r\n DEVICE_SNAPSHOT_API_PATH,\r\n wsUrlToHttpUrl,\r\n} from '../types/protocol';\r\n\r\nexport type ResolveSnapshotDownloadUrlOptions = {\r\n /**\r\n * When true, returns a same-origin relative path (e.g. `/api/devices/:id/snapshot`).\r\n * Use with a dev-server proxy so the browser avoids cross-origin fetches.\r\n */\r\n useSameOriginApi?: boolean;\r\n};\r\n\r\nexport function resolveSnapshotDownloadUrl(\r\n hubWsUrl: string,\r\n deviceId: string,\r\n options: ResolveSnapshotDownloadUrlOptions = {},\r\n): string {\r\n const path = `${DEVICE_SNAPSHOT_API_PATH}/${encodeURIComponent(deviceId)}/snapshot`;\r\n\r\n if (options.useSameOriginApi) {\r\n return path;\r\n }\r\n\r\n return buildDeviceSnapshotUrl(wsUrlToHttpUrl(hubWsUrl), deviceId);\r\n}\r\n","import type { DeviceStatusPayload } from '../types/protocol';\r\n\r\nexport type DeviceLabel = {\r\n deviceId: string;\r\n deviceName: string;\r\n};\r\n\r\nexport type DeviceLabelFallback = {\r\n databaseName?: string | null;\r\n label?: string | null;\r\n};\r\n\r\nexport function shortenDeviceId(deviceId: string, visibleChars = 4): string {\r\n if (deviceId.length <= visibleChars * 2 + 1) {\r\n return deviceId;\r\n }\r\n\r\n return `${deviceId.slice(0, visibleChars)}…${deviceId.slice(-visibleChars)}`;\r\n}\r\n\r\nexport function resolveDeviceDisplayName(\r\n deviceId: string,\r\n deviceStatus: DeviceStatusPayload | null,\r\n fallback?: DeviceLabelFallback | null,\r\n): string {\r\n const mobile = deviceStatus?.mobiles.find((device) => device.deviceId === deviceId);\r\n\r\n if (mobile?.metadata?.appName) {\r\n return mobile.metadata.appName;\r\n }\r\n\r\n if (fallback?.databaseName) {\r\n return fallback.databaseName;\r\n }\r\n\r\n if (fallback?.label) {\r\n return fallback.label;\r\n }\r\n\r\n return 'Device export';\r\n}\r\n\r\nexport function resolveDeviceLabel(\r\n deviceId: string,\r\n deviceStatus: DeviceStatusPayload | null,\r\n fallback?: DeviceLabelFallback | null,\r\n): DeviceLabel {\r\n return {\r\n deviceId,\r\n deviceName: resolveDeviceDisplayName(deviceId, deviceStatus, fallback),\r\n };\r\n}\r\n\r\nexport function formatSnapshotReceivedMessage(\r\n deviceLabel: DeviceLabel,\r\n databaseName: string,\r\n): string {\r\n return `${deviceLabel.deviceName} (${shortenDeviceId(deviceLabel.deviceId)}) · ${databaseName}`;\r\n}\r\n\r\nexport type SnapshotToastInitiator = 'mobile' | 'browser';\r\n\r\nexport function buildSnapshotLoadedToast(\r\n initiator: SnapshotToastInitiator,\r\n deviceId: string,\r\n databaseName: string,\r\n deviceStatus: DeviceStatusPayload | null,\r\n fallback?: DeviceLabelFallback | null,\r\n): { title: string; message: string } {\r\n const deviceLabel = resolveDeviceLabel(deviceId, deviceStatus, fallback);\r\n\r\n return {\r\n title: initiator === 'mobile' ? 'New database received' : 'Database refreshed',\r\n message: formatSnapshotReceivedMessage(deviceLabel, databaseName),\r\n };\r\n}\r\n","import type { MobileDeviceInfo } from '../types/protocol';\r\n\r\nexport type DeviceExportRef = {\r\n deviceId: string;\r\n bundleId?: string;\r\n};\r\n\r\nexport type ResolvePreferredDeviceIdInput = {\r\n selectedDeviceId: string | null;\r\n mobiles: MobileDeviceInfo[];\r\n exports: DeviceExportRef[];\r\n};\r\n\r\nfunction findMobileByBundleId(\r\n mobiles: MobileDeviceInfo[],\r\n bundleId?: string,\r\n): MobileDeviceInfo | undefined {\r\n if (!bundleId) {\r\n return undefined;\r\n }\r\n\r\n return mobiles.find((mobile) => mobile.metadata?.bundleId === bundleId);\r\n}\r\n\r\nexport function resolvePreferredDeviceId(input: ResolvePreferredDeviceIdInput): string | null {\r\n const connectedIds = new Set(input.mobiles.map((device) => device.deviceId));\r\n const exportById = new Map(input.exports.map((entry) => [entry.deviceId, entry]));\r\n\r\n if (input.selectedDeviceId) {\r\n if (connectedIds.has(input.selectedDeviceId)) {\r\n return input.selectedDeviceId;\r\n }\r\n\r\n const selectedExport = exportById.get(input.selectedDeviceId);\r\n\r\n if (selectedExport) {\r\n const bundleMatch = findMobileByBundleId(input.mobiles, selectedExport.bundleId);\r\n\r\n if (bundleMatch) {\r\n return bundleMatch.deviceId;\r\n }\r\n\r\n if (input.mobiles.length === 1) {\r\n return input.mobiles[0]!.deviceId;\r\n }\r\n\r\n return input.selectedDeviceId;\r\n }\r\n }\r\n\r\n return input.mobiles[0]?.deviceId ?? input.exports[0]?.deviceId ?? null;\r\n}\r\n\r\nexport function resolveLiveSwitchTarget(input: {\r\n selectedDeviceId: string | null;\r\n mobiles: MobileDeviceInfo[];\r\n exports: DeviceExportRef[];\r\n}): string | null {\r\n if (!input.selectedDeviceId || input.mobiles.length === 0) {\r\n return null;\r\n }\r\n\r\n if (input.mobiles.some((mobile) => mobile.deviceId === input.selectedDeviceId)) {\r\n return null;\r\n }\r\n\r\n const selectedExport = input.exports.find((entry) => entry.deviceId === input.selectedDeviceId);\r\n const bundleMatch = findMobileByBundleId(input.mobiles, selectedExport?.bundleId);\r\n\r\n if (bundleMatch) {\r\n return bundleMatch.deviceId;\r\n }\r\n\r\n return input.mobiles[0]?.deviceId ?? null;\r\n}\r\n"]}