gps-plus-slam-app-framework 1.3.0 → 1.4.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 (225) hide show
  1. package/dist/{app-selectors-B8VQoMDY.d.ts → app-selectors-CrOucL00.d.ts} +1 -1
  2. package/dist/ar/bresenham3d.d.ts +1 -1
  3. package/dist/ar/camera-blit-capture.d.ts +2 -2
  4. package/dist/ar/camera-blit-capture.js +74 -9
  5. package/dist/ar/capability-checker.d.ts +1 -1
  6. package/dist/ar/capture-failure-tracker.d.ts +1 -1
  7. package/dist/ar/chromium-camera-access-workaround.d.ts +1 -1
  8. package/dist/ar/depth-grid-lookup.d.ts +2 -0
  9. package/dist/ar/depth-grid-lookup.js +43 -0
  10. package/dist/ar/depth-sampler.d.ts +2 -2
  11. package/dist/ar/depth-sampler.js +2 -4
  12. package/dist/ar/depth-unprojection.d.ts +1 -1
  13. package/dist/ar/enable-gps-ar.d.ts +1 -1
  14. package/dist/ar/enable-gps-ar.js +26 -1
  15. package/dist/ar/frame-loop.d.ts +1 -1
  16. package/dist/ar/image-capture.d.ts +1 -1
  17. package/dist/ar/index.d.ts +30 -19
  18. package/dist/ar/index.js +15 -4
  19. package/dist/ar/occupancy-grid.d.ts +1 -1
  20. package/dist/ar/occupancy-grid.js +29 -2
  21. package/dist/ar/planar-pnp.d.ts +2 -0
  22. package/dist/ar/planar-pnp.js +425 -0
  23. package/dist/ar/qr-debug-view.d.ts +2 -0
  24. package/dist/ar/qr-debug-view.js +89 -0
  25. package/dist/ar/qr-derived-pose.d.ts +2 -0
  26. package/dist/ar/qr-derived-pose.js +114 -0
  27. package/dist/ar/qr-detection-controller.d.ts +2 -0
  28. package/dist/ar/qr-detection-controller.js +2 -0
  29. package/dist/ar/qr-frontend.d.ts +2 -0
  30. package/dist/ar/qr-frontend.js +60 -0
  31. package/dist/ar/qr-pose.d.ts +2 -0
  32. package/dist/ar/qr-pose.js +267 -0
  33. package/dist/ar/qr-size-depth-context.d.ts +3 -0
  34. package/dist/ar/qr-size-depth-context.js +42 -0
  35. package/dist/ar/qr-size-measurer.d.ts +2 -0
  36. package/dist/ar/qr-size-measurer.js +2 -0
  37. package/dist/ar/replay-scene.d.ts +1 -1
  38. package/dist/ar/replay-scene.js +1 -1
  39. package/dist/ar/scene-node-names.d.ts +1 -1
  40. package/dist/ar/webxr-nue-basis.d.ts +1 -1
  41. package/dist/ar/webxr-session.d.ts +4 -4
  42. package/dist/ar/webxr-session.js +2 -2
  43. package/dist/ar/xr-camera-texture.d.ts +1 -1
  44. package/dist/ar/xr-error-handler.d.ts +1 -1
  45. package/dist/ar/xr-frame-loop.d.ts +1 -1
  46. package/dist/ar-Dc72Ksiu.js +382 -0
  47. package/dist/{ar-world-group-alignment-C9lwwIyI.d.ts → ar-world-group-alignment-DDLkgNf_.d.ts} +1 -1
  48. package/dist/{camera-blit-capture-CnxUDbKx.d.ts → camera-blit-capture-CqWe1G7s.d.ts} +57 -4
  49. package/dist/concurrency-DqAlKX4j.d.ts +50 -0
  50. package/dist/core/index.d.ts +1 -1
  51. package/dist/{create-slam-app-store-BljusOua.d.ts → create-slam-app-store-Ce2FMKCp.d.ts} +5 -5
  52. package/dist/depth-grid-lookup-vMDrGTk_.d.ts +21 -0
  53. package/dist/{depth-sampler-Bhanfwla.d.ts → depth-sampler-DwfPYzS7.d.ts} +1 -1
  54. package/dist/{depth-unprojection-Y6i_mJuT.d.ts → depth-unprojection-CK3b9htH.d.ts} +1 -1
  55. package/dist/{enable-gps-ar-BfUJOgpW.d.ts → enable-gps-ar-CjZ1nEdu.d.ts} +4 -4
  56. package/dist/{frame-conversions-BfsafGWR.d.ts → frame-conversions-D_Af8Dt3.d.ts} +1 -1
  57. package/dist/{fused-path-DJoVu98b.d.ts → fused-path-C0FHe67t.d.ts} +1 -1
  58. package/dist/geo/h3-proximity.d.ts +2 -2
  59. package/dist/geo/h3-proximity.js +61 -2
  60. package/dist/geo/index.d.ts +2 -2
  61. package/dist/geo/index.js +2 -2
  62. package/dist/{gps-anchor-dYeCvvp5.d.ts → gps-anchor-C6I9NDHA.d.ts} +1 -1
  63. package/dist/{gps-ar-pose-sampler-DVb96iOy.d.ts → gps-ar-pose-sampler-DaHg2aPZ.d.ts} +1 -1
  64. package/dist/{gps-event-coordinator-CWIDOk4U.d.ts → gps-event-coordinator-C7hwHyLA.d.ts} +3 -3
  65. package/dist/{gps-event-markers-Dc9FT-q1.d.ts → gps-event-markers-Dd0G2bD0.d.ts} +18 -0
  66. package/dist/{h3-proximity-I1msGPgE.d.ts → h3-proximity-B57C6rYL.d.ts} +39 -1
  67. package/dist/{image-capture-qAZ5Fh5X.d.ts → image-capture-C2Feywet.d.ts} +1 -1
  68. package/dist/index-BvLo2poy.d.ts +399 -0
  69. package/dist/{index-BYYUdf9v.d.ts → index-m_LneUSi.d.ts} +1 -1
  70. package/dist/index.d.ts +77 -67
  71. package/dist/index.js +18 -9
  72. package/dist/{leaflet-map-overlay-6CJC-E1l.d.ts → leaflet-map-overlay-bnb2U1NQ.d.ts} +1 -1
  73. package/dist/{map-data-CkloBxIl.d.ts → map-data-DdjPiSav.d.ts} +1 -1
  74. package/dist/{map-overlay-draw-krOKwDAq.d.ts → map-overlay-draw-CPVdAsFq.d.ts} +1 -1
  75. package/dist/{null-storage-backend-uKQE8tl7.d.ts → null-storage-backend-CuSdYFsM.d.ts} +2 -2
  76. package/dist/{occupancy-grid-BRNRaPyT.d.ts → occupancy-grid-Bvi2Gw1U.d.ts} +12 -2
  77. package/dist/{opfs-storage-D5zAn_lx.d.ts → opfs-storage-DMtlt57S.d.ts} +23 -4
  78. package/dist/{opfs-storage-backend-6aYMUZlJ.d.ts → opfs-storage-backend-CeQAb0SD.d.ts} +3 -3
  79. package/dist/{persistence-middleware-B9ei4Nhx.d.ts → persistence-middleware-5eearhSV.d.ts} +1 -1
  80. package/dist/planar-pnp-cjthe7Be.d.ts +67 -0
  81. package/dist/qr-debug-view-B8gTzjMm.d.ts +29 -0
  82. package/dist/qr-derived-pose-DinKE600.d.ts +122 -0
  83. package/dist/qr-detected-slice-Cpv-dg82.d.ts +166 -0
  84. package/dist/qr-detection-controller-B-tLVd-S.js +119 -0
  85. package/dist/qr-detection-controller-Cd2Ih4cC.d.ts +48 -0
  86. package/dist/qr-frontend-DufZp2xS.d.ts +58 -0
  87. package/dist/qr-pose-Bt2reSw7.d.ts +138 -0
  88. package/dist/qr-pose-aggregation-CFlmLm6w.d.ts +90 -0
  89. package/dist/qr-pose-aggregation-DXR9STHs.js +200 -0
  90. package/dist/qr-size-depth-context-onu36E9s.d.ts +13 -0
  91. package/dist/qr-size-measurer-D7739ZpB.d.ts +165 -0
  92. package/dist/qr-size-measurer-DLb33geH.js +596 -0
  93. package/dist/recording-options-D93kksJU.d.ts +369 -0
  94. package/dist/{recording-replayer-r0DZ9ALp.d.ts → recording-replayer-CUEK82tM.d.ts} +2 -2
  95. package/dist/recording-slice-B-uCgGoh.d.ts +55 -0
  96. package/dist/{replay-engine-XpDa0dy1.d.ts → replay-engine-BSVd7Zzb.d.ts} +7 -4
  97. package/dist/{replay-scene-Bw58VL6p.d.ts → replay-scene-CPt56pps.d.ts} +3 -3
  98. package/dist/sensors/gps-error-handler.d.ts +1 -1
  99. package/dist/sensors/gps.d.ts +1 -1
  100. package/dist/sensors/index.d.ts +3 -3
  101. package/dist/sensors/permission-checker.d.ts +1 -1
  102. package/dist/sensors/permission-checker.js +1 -1
  103. package/dist/state/app-selectors.d.ts +1 -1
  104. package/dist/state/combined-root-state.d.ts +1 -1
  105. package/dist/state/create-slam-app-store.d.ts +1 -1
  106. package/dist/state/gps-ar-pose-sampler.d.ts +3 -3
  107. package/dist/state/gps-event-coordinator.d.ts +1 -1
  108. package/dist/state/index.d.ts +20 -17
  109. package/dist/state/index.js +3 -2
  110. package/dist/state/persistence-middleware.d.ts +1 -1
  111. package/dist/state/qr-detected-slice.d.ts +4 -0
  112. package/dist/state/qr-detected-slice.js +311 -0
  113. package/dist/state/recording-options.d.ts +2 -2
  114. package/dist/state/recording-options.js +128 -4
  115. package/dist/state/recording-replayer.d.ts +2 -2
  116. package/dist/state/recording-slice.d.ts +1 -1
  117. package/dist/state/recording-slice.js +5 -1
  118. package/dist/state/replay-engine.d.ts +1 -1
  119. package/dist/state/replay-engine.js +7 -3
  120. package/dist/state/store-subscribers.d.ts +2 -2
  121. package/dist/state/subscribe-to-selector.d.ts +1 -1
  122. package/dist/state/tracking-quality.d.ts +1 -1
  123. package/dist/state/tracking-slice.d.ts +1 -1
  124. package/dist/{state-BkIfpiyA.js → state-IEw0ZsBu.js} +1 -0
  125. package/dist/storage/file-system-utils.d.ts +1 -1
  126. package/dist/storage/index.d.ts +9 -9
  127. package/dist/storage/index.js +4 -4
  128. package/dist/storage/null-storage-backend.d.ts +1 -1
  129. package/dist/storage/opfs-storage-backend.d.ts +1 -1
  130. package/dist/storage/opfs-storage-backend.js +3 -3
  131. package/dist/storage/opfs-storage.d.ts +1 -1
  132. package/dist/storage/opfs-storage.js +5 -4
  133. package/dist/storage/storage-backend.d.ts +1 -1
  134. package/dist/storage/zip-coverage-embed.d.ts +2 -0
  135. package/dist/storage/zip-coverage-embed.js +88 -0
  136. package/dist/storage/zip-export.d.ts +2 -2
  137. package/dist/storage/zip-export.js +37 -59
  138. package/dist/storage/zip-reader.d.ts +1 -1
  139. package/dist/{storage-backend-Do6YDpNo.d.ts → storage-backend-CTJHNdMp.d.ts} +1 -1
  140. package/dist/{store-subscribers-0YWyOLvV.d.ts → store-subscribers-BZP81hjh.d.ts} +2 -2
  141. package/dist/{subscribe-to-selector-CZ6k1NFP.d.ts → subscribe-to-selector-Bp3sLx8L.d.ts} +1 -1
  142. package/dist/test-utils/browser-mocks.d.ts +7 -1
  143. package/dist/test-utils/browser-mocks.js +6 -0
  144. package/dist/test-utils/zip-round-trip-helpers.d.ts +9 -1
  145. package/dist/test-utils/zip-round-trip-helpers.js +5 -1
  146. package/dist/{tracking-slice-CdK8c-8P.d.ts → tracking-slice-DJZ9qeGg.d.ts} +1 -1
  147. package/dist/types/ar-types.d.ts +1 -1
  148. package/dist/types/geo-types.d.ts +1 -1
  149. package/dist/types/index.d.ts +2 -2
  150. package/dist/utils/concurrency.d.ts +2 -2
  151. package/dist/utils/concurrency.js +66 -2
  152. package/dist/utils/failure-tracker.d.ts +1 -1
  153. package/dist/utils/format-file-size.d.ts +1 -1
  154. package/dist/utils/fused-path.d.ts +1 -1
  155. package/dist/utils/index.d.ts +6 -6
  156. package/dist/utils/list-formatter.d.ts +1 -1
  157. package/dist/utils/logger.d.ts +1 -1
  158. package/dist/visualization/accuracy-circles.d.ts +1 -1
  159. package/dist/visualization/alignment-lerper.d.ts +1 -1
  160. package/dist/visualization/ar-world-group-alignment.d.ts +1 -1
  161. package/dist/visualization/ar-world-group-alignment.js +1 -1
  162. package/dist/visualization/camera-follower.d.ts +1 -1
  163. package/dist/visualization/css3d-renderer-manager.d.ts +1 -1
  164. package/dist/visualization/frame-conversions.d.ts +1 -1
  165. package/dist/visualization/frustum-visibility.d.ts +1 -1
  166. package/dist/visualization/gps-anchor.d.ts +1 -1
  167. package/dist/visualization/gps-compass-cubes.d.ts +1 -1
  168. package/dist/visualization/gps-event-markers.d.ts +1 -1
  169. package/dist/visualization/gps-event-markers.js +40 -5
  170. package/dist/visualization/hit-test-reticle.d.ts +1 -1
  171. package/dist/visualization/hit-test-reticle.js +1 -0
  172. package/dist/visualization/index.d.ts +18 -18
  173. package/dist/visualization/leaflet-map-overlay.d.ts +1 -1
  174. package/dist/visualization/leaflet-map-overlay.js +15 -3
  175. package/dist/visualization/lerp-utils.d.ts +1 -1
  176. package/dist/visualization/map-data.d.ts +1 -1
  177. package/dist/visualization/map-overlay-draw.d.ts +1 -1
  178. package/dist/visualization/map-overlay.d.ts +1 -1
  179. package/dist/visualization/three-dispose.d.ts +1 -1
  180. package/dist/visualization/vis-colors.d.ts +1 -1
  181. package/dist/{webxr-session-TIaD883f.js → webxr-session-CJF9Nijp.js} +221 -9
  182. package/dist/{webxr-session-GjZ2BIpS.d.ts → webxr-session-COsOjJwn.d.ts} +76 -8
  183. package/dist/zip-coverage-embed-tFohI2J4.d.ts +41 -0
  184. package/dist/{zip-export-G14hkSPG.d.ts → zip-export-DDWXInTR.d.ts} +27 -23
  185. package/package.json +2 -2
  186. package/dist/concurrency-CO1FQvs3.d.ts +0 -24
  187. package/dist/file-system-CwXTNHmB.d.ts +0 -114
  188. package/dist/recording-options-DJBXuMxV.d.ts +0 -182
  189. package/dist/recording-slice-89O07ebs.d.ts +0 -36
  190. package/dist/storage/file-system.d.ts +0 -2
  191. package/dist/storage/file-system.js +0 -289
  192. /package/dist/{accuracy-circles-BpwWAs8G.d.ts → accuracy-circles-Pi2YeCrM.d.ts} +0 -0
  193. /package/dist/{alignment-lerper-Dm9G7JJO.d.ts → alignment-lerper-BUTsQ2yu.d.ts} +0 -0
  194. /package/dist/{ar-types-Dan1MVTi.d.ts → ar-types-BckI1E-O.d.ts} +0 -0
  195. /package/dist/{bresenham3d-CFfd7n6B.d.ts → bresenham3d-ByjcmEgM.d.ts} +0 -0
  196. /package/dist/{camera-follower-C2mwEn7c.d.ts → camera-follower-BTb2Yp12.d.ts} +0 -0
  197. /package/dist/{capability-checker-CQXJHxXg.d.ts → capability-checker-CXqoJYtb.d.ts} +0 -0
  198. /package/dist/{capture-failure-tracker-CUeU3L_M.d.ts → capture-failure-tracker-BL5SoG2a.d.ts} +0 -0
  199. /package/dist/{chromium-camera-access-workaround-Jqbn0apH.d.ts → chromium-camera-access-workaround-BNK189P0.d.ts} +0 -0
  200. /package/dist/{css3d-renderer-manager-ptu_t3B3.d.ts → css3d-renderer-manager-m-ab19vp.d.ts} +0 -0
  201. /package/dist/{failure-tracker-Cn8Fo9D4.d.ts → failure-tracker-Cnc_xWUw.d.ts} +0 -0
  202. /package/dist/{file-system-utils-CXIoL-DM.d.ts → file-system-utils-Bs7lpeVP.d.ts} +0 -0
  203. /package/dist/{format-file-size-CLCZz3lC.d.ts → format-file-size-BFUWvir1.d.ts} +0 -0
  204. /package/dist/{frame-loop-CMewS8cY.d.ts → frame-loop-BEO9_q3k.d.ts} +0 -0
  205. /package/dist/{frustum-visibility-CmI96ESS.d.ts → frustum-visibility-D_RGmH98.d.ts} +0 -0
  206. /package/dist/{geo-types-SaPnIEUM.d.ts → geo-types-DqiBzPO9.d.ts} +0 -0
  207. /package/dist/{gps-VuezJWK3.d.ts → gps-C5inWeNV.d.ts} +0 -0
  208. /package/dist/{gps-compass-cubes-BM1uGiYV.d.ts → gps-compass-cubes-BExxrWJ-.d.ts} +0 -0
  209. /package/dist/{gps-error-handler-CJl_2MVm.d.ts → gps-error-handler-C2bS69oJ.d.ts} +0 -0
  210. /package/dist/{hit-test-reticle-BEzEybxZ.d.ts → hit-test-reticle-Dqak9hiR.d.ts} +0 -0
  211. /package/dist/{index-CF05QV2m.d.ts → index-eaI1Z1KR.d.ts} +0 -0
  212. /package/dist/{lerp-utils-BpV-0Dtk.d.ts → lerp-utils-kLxMJ2Xj.d.ts} +0 -0
  213. /package/dist/{list-formatter-RRcBe8Vg.d.ts → list-formatter-ct8txwvR.d.ts} +0 -0
  214. /package/dist/{logger-BEHXsnnq.d.ts → logger-CzQrCe6C.d.ts} +0 -0
  215. /package/dist/{map-overlay-bcogY5fK.d.ts → map-overlay-Dci4yvm3.d.ts} +0 -0
  216. /package/dist/{permission-checker-GpAiSCwd.d.ts → permission-checker-CtPtPQRq.d.ts} +0 -0
  217. /package/dist/{scene-node-names-Bu0S66H1.d.ts → scene-node-names-CdNeQjOE.d.ts} +0 -0
  218. /package/dist/{session-disposers-M-oashRH.js → session-disposers-D8wnO-uW.js} +0 -0
  219. /package/dist/{three-dispose-D950t71B.d.ts → three-dispose-BCZkSJp2.d.ts} +0 -0
  220. /package/dist/{vis-colors-D6omC64K.d.ts → vis-colors-BZsSLI4i.d.ts} +0 -0
  221. /package/dist/{webxr-nue-basis-CqKQmZzT.d.ts → webxr-nue-basis-CW1wsbm6.d.ts} +0 -0
  222. /package/dist/{xr-camera-texture-DBwCaKTd.d.ts → xr-camera-texture-BmrP7iNZ.d.ts} +0 -0
  223. /package/dist/{xr-error-handler-C0AQRmxs.d.ts → xr-error-handler-BEjRgZjt.d.ts} +0 -0
  224. /package/dist/{xr-frame-loop-BtYytZJg.d.ts → xr-frame-loop-K8ebdjLw.d.ts} +0 -0
  225. /package/dist/{zip-reader-DSEXt7K6.d.ts → zip-reader-Q2ue6zlC.d.ts} +0 -0
@@ -1,9 +1,9 @@
1
- import { a as getAppRootHandle, c as initOpfsStorage, d as resetSessionHandles, h as writeSessionMetadata$1, i as createSession, l as listSessions, n as SessionMetadata, o as getSessionHandle, r as checkStorageQuota, s as getSessionsRootHandle, u as resetOpfsStorage } from "../opfs-storage-D5zAn_lx.js";
2
- import { n as StorageBackend, t as CreateSessionResult } from "../storage-backend-Do6YDpNo.js";
3
- import { a as ZipActionEntry, c as loadEntriesFromSubdir, d as loadSessionMetadataFromBlob, f as readZipEntries, i as RecordedAction, l as loadGpsPathFromBlob, n as GpsPathCoord, o as ZipSubdirEntry, r as MAX_ACTION_FILE_SIZE, s as loadActionsFromZip, t as Entry, u as loadSessionMetadata } from "../zip-reader-DSEXt7K6.js";
4
- import { t as NullStorageBackend } from "../null-storage-backend-uKQE8tl7.js";
5
- import { t as OpfsStorageBackend } from "../opfs-storage-backend-6aYMUZlJ.js";
6
- import { a as getCurrentScenarioHandle, c as resetForNewSession, d as startSession, f as verifyWriteAccess, h as writeSessionMetadata, i as ensureScenarioDirectory, l as resetStorageState, m as writeFrame, n as WriteAccessResult, o as initStorage, p as writeAction, s as listSessions$1, u as setCurrentScenario } from "../file-system-CwXTNHmB.js";
7
- import { a as formatTimestamp, i as formatFrameFilename, r as formatActionFilename } from "../file-system-utils-CXIoL-DM.js";
8
- import { a as downloadZip, c as syncToExternalZip, i as ZipExportResult, n as ZipContributorAddFile, o as exportAndDownloadSession, r as ZipExportContributor, s as exportSessionAsZip, t as ExportSessionAsZipOptions } from "../zip-export-G14hkSPG.js";
9
- export { type CreateSessionResult, type Entry, type ExportSessionAsZipOptions, type GpsPathCoord, MAX_ACTION_FILE_SIZE, NullStorageBackend, OpfsStorageBackend, type RecordedAction, type SessionMetadata, type StorageBackend, type WriteAccessResult, type ZipActionEntry, type ZipContributorAddFile, type ZipExportContributor, type ZipExportResult, type ZipSubdirEntry, checkStorageQuota, createSession, downloadZip, ensureScenarioDirectory, exportAndDownloadSession, exportSessionAsZip, formatActionFilename, formatFrameFilename, formatTimestamp, getAppRootHandle, getCurrentScenarioHandle, getSessionHandle, getSessionsRootHandle, initOpfsStorage, initStorage, listSessions, listSessions$1 as listSessionsFromFileSystem, loadActionsFromZip, loadEntriesFromSubdir, loadGpsPathFromBlob, loadSessionMetadataFromBlob, loadSessionMetadata as loadSessionMetadataFromZip, readZipEntries, resetForNewSession, resetOpfsStorage, resetSessionHandles, resetStorageState, setCurrentScenario, startSession as startStorageSession, syncToExternalZip, verifyWriteAccess, writeAction, writeFrame, writeSessionMetadata as writeSessionMeta, writeSessionMetadata$1 as writeSessionMetadata };
1
+ import { a as getAppRootHandle, c as initOpfsStorage, d as resetSessionHandles, h as writeSessionMetadata, i as createSession, l as listSessions, n as SessionMetadata, o as getSessionHandle, r as checkStorageQuota, s as getSessionsRootHandle, u as resetOpfsStorage } from "../opfs-storage-DMtlt57S.js";
2
+ import { n as StorageBackend, t as CreateSessionResult } from "../storage-backend-CTJHNdMp.js";
3
+ import { a as ZipActionEntry, c as loadEntriesFromSubdir, d as loadSessionMetadataFromBlob, f as readZipEntries, i as RecordedAction, l as loadGpsPathFromBlob, n as GpsPathCoord, o as ZipSubdirEntry, r as MAX_ACTION_FILE_SIZE, s as loadActionsFromZip, t as Entry, u as loadSessionMetadata } from "../zip-reader-Q2ue6zlC.js";
4
+ import { t as NullStorageBackend } from "../null-storage-backend-CuSdYFsM.js";
5
+ import { t as OpfsStorageBackend } from "../opfs-storage-backend-CeQAb0SD.js";
6
+ import { a as formatTimestamp, i as formatFrameFilename, r as formatActionFilename } from "../file-system-utils-Bs7lpeVP.js";
7
+ import { a as downloadZip, c as syncToExternalZip, i as ZipExportResult, n as ZipContributorAddFile, o as exportSessionAsZip, r as ZipExportContributor, s as exportSessionHandleAsZip, t as ExportSessionAsZipOptions } from "../zip-export-DDWXInTR.js";
8
+ import { t as embedCoverageInSessionJson } from "../zip-coverage-embed-tFohI2J4.js";
9
+ export { type CreateSessionResult, type Entry, type ExportSessionAsZipOptions, type GpsPathCoord, MAX_ACTION_FILE_SIZE, NullStorageBackend, OpfsStorageBackend, type RecordedAction, type SessionMetadata, type StorageBackend, type ZipActionEntry, type ZipContributorAddFile, type ZipExportContributor, type ZipExportResult, type ZipSubdirEntry, checkStorageQuota, createSession, downloadZip, embedCoverageInSessionJson, exportSessionAsZip, exportSessionHandleAsZip, formatActionFilename, formatFrameFilename, formatTimestamp, getAppRootHandle, getSessionHandle, getSessionsRootHandle, initOpfsStorage, listSessions, loadActionsFromZip, loadEntriesFromSubdir, loadGpsPathFromBlob, loadSessionMetadataFromBlob, loadSessionMetadata as loadSessionMetadataFromZip, readZipEntries, resetOpfsStorage, resetSessionHandles, syncToExternalZip, writeSessionMetadata };
@@ -1,8 +1,8 @@
1
1
  import { MAX_ACTION_FILE_SIZE, loadActionsFromZip, loadEntriesFromSubdir, loadGpsPathFromBlob, loadSessionMetadata, loadSessionMetadataFromBlob, readZipEntries } from "./zip-reader.js";
2
2
  import { formatActionFilename, formatFrameFilename, formatTimestamp } from "./file-system-utils.js";
3
3
  import { NullStorageBackend } from "./null-storage-backend.js";
4
- import { checkStorageQuota, createSession, getAppRootHandle, getSessionHandle, getSessionsRootHandle, initOpfsStorage, listSessions, resetOpfsStorage, resetSessionHandles, writeSessionMetadata as writeSessionMetadata$1 } from "./opfs-storage.js";
5
- import { ensureScenarioDirectory, getCurrentScenarioHandle, initStorage, listSessions as listSessions$1, resetForNewSession, resetStorageState, setCurrentScenario, startSession, verifyWriteAccess, writeAction, writeFrame, writeSessionMetadata } from "./file-system.js";
4
+ import { checkStorageQuota, createSession, getAppRootHandle, getSessionHandle, getSessionsRootHandle, initOpfsStorage, listSessions, resetOpfsStorage, resetSessionHandles, writeSessionMetadata } from "./opfs-storage.js";
6
5
  import { OpfsStorageBackend } from "./opfs-storage-backend.js";
7
- import { downloadZip, exportAndDownloadSession, exportSessionAsZip, syncToExternalZip } from "./zip-export.js";
8
- export { MAX_ACTION_FILE_SIZE, NullStorageBackend, OpfsStorageBackend, checkStorageQuota, createSession, downloadZip, ensureScenarioDirectory, exportAndDownloadSession, exportSessionAsZip, formatActionFilename, formatFrameFilename, formatTimestamp, getAppRootHandle, getCurrentScenarioHandle, getSessionHandle, getSessionsRootHandle, initOpfsStorage, initStorage, listSessions, listSessions$1 as listSessionsFromFileSystem, loadActionsFromZip, loadEntriesFromSubdir, loadGpsPathFromBlob, loadSessionMetadataFromBlob, loadSessionMetadata as loadSessionMetadataFromZip, readZipEntries, resetForNewSession, resetOpfsStorage, resetSessionHandles, resetStorageState, setCurrentScenario, startSession as startStorageSession, syncToExternalZip, verifyWriteAccess, writeAction, writeFrame, writeSessionMetadata as writeSessionMeta, writeSessionMetadata$1 as writeSessionMetadata };
6
+ import { downloadZip, exportSessionAsZip, exportSessionHandleAsZip, syncToExternalZip } from "./zip-export.js";
7
+ import { embedCoverageInSessionJson } from "./zip-coverage-embed.js";
8
+ export { MAX_ACTION_FILE_SIZE, NullStorageBackend, OpfsStorageBackend, checkStorageQuota, createSession, downloadZip, embedCoverageInSessionJson, exportSessionAsZip, exportSessionHandleAsZip, formatActionFilename, formatFrameFilename, formatTimestamp, getAppRootHandle, getSessionHandle, getSessionsRootHandle, initOpfsStorage, listSessions, loadActionsFromZip, loadEntriesFromSubdir, loadGpsPathFromBlob, loadSessionMetadataFromBlob, loadSessionMetadata as loadSessionMetadataFromZip, readZipEntries, resetOpfsStorage, resetSessionHandles, syncToExternalZip, writeSessionMetadata };
@@ -1,2 +1,2 @@
1
- import { t as NullStorageBackend } from "../null-storage-backend-uKQE8tl7.js";
1
+ import { t as NullStorageBackend } from "../null-storage-backend-CuSdYFsM.js";
2
2
  export { NullStorageBackend };
@@ -1,2 +1,2 @@
1
- import { t as OpfsStorageBackend } from "../opfs-storage-backend-6aYMUZlJ.js";
1
+ import { t as OpfsStorageBackend } from "../opfs-storage-backend-CeQAb0SD.js";
2
2
  export { OpfsStorageBackend };
@@ -1,8 +1,8 @@
1
- import { listSessions, startSession, writeAction, writeFrame, writeSessionMetadata } from "./file-system.js";
1
+ import { createSession, listSessions, writeAction, writeFrame, writeSessionMetadata } from "./opfs-storage.js";
2
2
  //#region ../src/storage/opfs-storage-backend.ts
3
3
  var OpfsStorageBackend = class {
4
- async createSession(_timestamp, _contextTag) {
5
- return { sessionName: (await startSession()).sessionPath };
4
+ async createSession(timestamp, _contextTag) {
5
+ return { sessionName: (await createSession(timestamp)).sessionName };
6
6
  }
7
7
  async listSessions() {
8
8
  return listSessions();
@@ -1,2 +1,2 @@
1
- import { a as getAppRootHandle, c as initOpfsStorage, d as resetSessionHandles, f as setSessionHandles, h as writeSessionMetadata, i as createSession, l as listSessions, m as writeFrame, n as SessionMetadata, o as getSessionHandle, p as writeAction, r as checkStorageQuota, s as getSessionsRootHandle, t as CreateSessionResult, u as resetOpfsStorage } from "../opfs-storage-D5zAn_lx.js";
1
+ import { a as getAppRootHandle, c as initOpfsStorage, d as resetSessionHandles, f as setSessionHandles, h as writeSessionMetadata, i as createSession, l as listSessions, m as writeFrame, n as SessionMetadata, o as getSessionHandle, p as writeAction, r as checkStorageQuota, s as getSessionsRootHandle, t as CreateSessionResult, u as resetOpfsStorage } from "../opfs-storage-DMtlt57S.js";
2
2
  export { CreateSessionResult, SessionMetadata, checkStorageQuota, createSession, getAppRootHandle, getSessionHandle, getSessionsRootHandle, initOpfsStorage, listSessions, resetOpfsStorage, resetSessionHandles, setSessionHandles, writeAction, writeFrame, writeSessionMetadata };
@@ -121,10 +121,11 @@ function getSessionHandle() {
121
121
  /**
122
122
  * Set the active session handles externally.
123
123
  *
124
- * Used by file-system.ts's scenario-based path to reuse opfs-storage's
125
- * write infrastructure for sessions created outside the flat layout.
126
- * This is a temporary bridge until the recorder migrates to
127
- * ScenarioWrappingStorageBackend.
124
+ * Lets a wrapping StorageBackend that creates sessions outside the flat layout
125
+ * (e.g. the recorder's `ScenarioWrappingStorageBackend`, which nests sessions
126
+ * under a named bucket) reuse opfs-storage's write infrastructure: it creates
127
+ * the session directory itself, then hands the handles here so subsequent
128
+ * `writeAction` / `writeFrame` / `writeSessionMetadata` calls target them.
128
129
  *
129
130
  * @internal
130
131
  */
@@ -1,2 +1,2 @@
1
- import { n as StorageBackend, t as CreateSessionResult } from "../storage-backend-Do6YDpNo.js";
1
+ import { n as StorageBackend, t as CreateSessionResult } from "../storage-backend-CTJHNdMp.js";
2
2
  export { CreateSessionResult, StorageBackend };
@@ -0,0 +1,2 @@
1
+ import { t as embedCoverageInSessionJson } from "../zip-coverage-embed-tFohI2J4.js";
2
+ export { embedCoverageInSessionJson };
@@ -0,0 +1,88 @@
1
+ import { createLogger } from "../utils/logger.js";
2
+ import { BlobReader, BlobWriter, TextReader, TextWriter, Uint8ArrayReader, Uint8ArrayWriter, ZipReader, ZipWriter } from "@zip.js/zip.js";
3
+ //#region ../src/storage/zip-coverage-embed.ts
4
+ /**
5
+ * Zip Coverage Embed — write a recording's H3 coverage into its `session.json`.
6
+ *
7
+ * The map-centric browser indexes legacy recordings (those predating the
8
+ * `h3Cells` field) by reading their full GPS path — slow, and repeated on every
9
+ * folder open. This primitive lets a one-time "upgrade" embed the derived
10
+ * coverage **inside the recording's own `session.json`**, so the recording
11
+ * indexes instantly on every future open in this app *and any other reader*
12
+ * (the portability the user asked for; O3 — in-zip rewrite).
13
+ *
14
+ * It is a pure transform `(zip, cells, resolution) -> zip`: it reads every entry
15
+ * and re-emits a new zip identical to the input except that `session.json` gains
16
+ * `h3Cells` + `h3Resolution`. It never mutates anything in place — the caller
17
+ * (the RecorderApp backfill) owns the safe write-then-verify-then-overwrite
18
+ * protocol around it.
19
+ *
20
+ * @see ./zip-coverage-embed.ts.md
21
+ * @see GpsPlusSlamJs_Docs/docs/2026-06-14-followup-progressive-map-browser-indexing-and-backfill.md (B3)
22
+ */
23
+ const log = createLogger("ZipCoverageEmbed");
24
+ /**
25
+ * Return a new zip blob identical to `zip` except its `session.json` gains
26
+ * `h3Cells` + `h3Resolution`.
27
+ *
28
+ * **Skips (returns the input blob unchanged, by reference) when:**
29
+ * - the zip has no `session.json` (nothing to embed into);
30
+ * - `session.json` is present but unparseable (never write over a broken one);
31
+ * - `session.json` already carries `h3Cells` (idempotent — re-running the
32
+ * upgrade is a no-op, and new recordings are skipped).
33
+ *
34
+ * On any unexpected read/write failure it also returns the input untouched —
35
+ * it never emits a partial zip. Callers can detect a skip via reference
36
+ * equality (`result === zip`).
37
+ *
38
+ * Built on `@zip.js/zip.js` (the same library as the exporter) in store mode, so
39
+ * every non-`session.json` entry is re-emitted with byte-identical uncompressed
40
+ * content.
41
+ */
42
+ async function embedCoverageInSessionJson(zip, h3Cells, h3Resolution) {
43
+ const reader = new ZipReader(new BlobReader(zip));
44
+ try {
45
+ const entries = await reader.getEntries();
46
+ const sessionEntry = entries.find((e) => !e.directory && e.filename.endsWith("session.json"));
47
+ if (!sessionEntry) {
48
+ log.warn("No session.json found; leaving zip untouched");
49
+ return zip;
50
+ }
51
+ let session;
52
+ try {
53
+ const text = await sessionEntry.getData(new TextWriter());
54
+ session = JSON.parse(text);
55
+ } catch (err) {
56
+ log.warn("session.json unparseable; leaving zip untouched", err);
57
+ return zip;
58
+ }
59
+ if (session.h3Cells !== void 0) return zip;
60
+ const merged = {
61
+ ...session,
62
+ h3Cells,
63
+ h3Resolution
64
+ };
65
+ const writer = new ZipWriter(new BlobWriter("application/zip"), { level: 0 });
66
+ try {
67
+ for (const entry of entries) {
68
+ if (entry.directory || !entry.getData) continue;
69
+ if (entry === sessionEntry) await writer.add(entry.filename, new TextReader(JSON.stringify(merged)));
70
+ else {
71
+ const bytes = await entry.getData(new Uint8ArrayWriter());
72
+ await writer.add(entry.filename, new Uint8ArrayReader(bytes));
73
+ }
74
+ }
75
+ return await writer.close();
76
+ } catch (err) {
77
+ log.warn("Failed to re-emit zip; leaving original untouched", err);
78
+ return zip;
79
+ }
80
+ } catch (err) {
81
+ log.warn("Failed to read zip for coverage embed; leaving untouched", err);
82
+ return zip;
83
+ } finally {
84
+ await reader.close();
85
+ }
86
+ }
87
+ //#endregion
88
+ export { embedCoverageInSessionJson };
@@ -1,2 +1,2 @@
1
- import { a as downloadZip, c as syncToExternalZip, i as ZipExportResult, n as ZipContributorAddFile, o as exportAndDownloadSession, r as ZipExportContributor, s as exportSessionAsZip, t as ExportSessionAsZipOptions } from "../zip-export-G14hkSPG.js";
2
- export { ExportSessionAsZipOptions, ZipContributorAddFile, ZipExportContributor, ZipExportResult, downloadZip, exportAndDownloadSession, exportSessionAsZip, syncToExternalZip };
1
+ import { a as downloadZip, c as syncToExternalZip, i as ZipExportResult, n as ZipContributorAddFile, o as exportSessionAsZip, r as ZipExportContributor, s as exportSessionHandleAsZip, t as ExportSessionAsZipOptions } from "../zip-export-DDWXInTR.js";
2
+ export { ExportSessionAsZipOptions, ZipContributorAddFile, ZipExportContributor, ZipExportResult, downloadZip, exportSessionAsZip, exportSessionHandleAsZip, syncToExternalZip };
@@ -20,14 +20,6 @@ import { BlobReader, BlobWriter, ZipWriter } from "@zip.js/zip.js";
20
20
  */
21
21
  const log = createLogger("ZipExport");
22
22
  /**
23
- * Get the OPFS scenarios directory handle.
24
- * Re-acquires from navigator.storage to avoid holding stale references.
25
- * Creates on demand so it works even when initOpfsStorage only creates sessions/.
26
- */
27
- async function getScenariosHandle() {
28
- return (await (await navigator.storage.getDirectory()).getDirectoryHandle("gps-plus-slam")).getDirectoryHandle("scenarios", { create: true });
29
- }
30
- /**
31
23
  * Get the OPFS sessions directory handle (flat layout).
32
24
  */
33
25
  async function getSessionsHandle() {
@@ -56,49 +48,48 @@ async function streamDirectoryToZip(dirHandle, zipWriter, basePath = "") {
56
48
  return count;
57
49
  }
58
50
  /**
59
- * Export a session from OPFS as a ZIP blob.
51
+ * Export a flat-layout session from OPFS as a ZIP blob.
60
52
  *
61
53
  * The ZIP structure mirrors the OPFS session structure:
62
54
  * - session.json (at root)
63
55
  * - actions/000001.json, actions/000002.json, ...
64
56
  * - images/frame-000001.jpg, images/frame-000002.jpg, ... (legacy: frames/)
65
- * - refPoints/{h3}.json (only observations from this session, scenario layout only)
66
57
  *
67
- * Uses "store" mode (compression level 0) for fast packaging.
68
- *
69
- * Supports both flat and scenario-based layouts:
70
- * - `exportSessionAsZip(sessionName)` — flat layout (sessions/)
71
- * - `exportSessionAsZip(scenarioName, sessionName)` — scenario layout (scenarios/{name}/)
58
+ * Uses "store" mode (compression level 0) for fast packaging. Consumers with a
59
+ * different on-disk layout (one that nests sessions under a named bucket)
60
+ * resolve their own session handle and call {@link exportSessionHandleAsZip}.
72
61
  *
62
+ * @param sessionName - Name of the session folder under `sessions/`.
73
63
  * @returns ZIP export result with blob and file count
74
- * @throws Error if session not found
64
+ * @throws Error if the session is not found
75
65
  */
76
- async function exportSessionAsZip(scenarioNameOrSessionName, sessionName, options) {
66
+ async function exportSessionAsZip(sessionName, options) {
67
+ log.info(`Exporting session: ${sessionName}`);
68
+ const sessionsDir = await getSessionsHandle();
77
69
  let sessionHandle;
78
- if (sessionName) {
79
- const scenarioName = scenarioNameOrSessionName;
80
- log.info(`Exporting session: ${scenarioName}/${sessionName}`);
81
- const scenariosDir = await getScenariosHandle();
82
- let scenarioHandle;
83
- try {
84
- scenarioHandle = await scenariosDir.getDirectoryHandle(scenarioName);
85
- } catch {
86
- throw new Error(`Scenario "${scenarioName}" not found in OPFS storage`);
87
- }
88
- try {
89
- sessionHandle = await scenarioHandle.getDirectoryHandle(sessionName);
90
- } catch {
91
- throw new Error(`Session "${sessionName}" not found in scenario "${scenarioName}"`);
92
- }
93
- } else {
94
- log.info(`Exporting session: ${scenarioNameOrSessionName}`);
95
- const sessionsDir = await getSessionsHandle();
96
- try {
97
- sessionHandle = await sessionsDir.getDirectoryHandle(scenarioNameOrSessionName);
98
- } catch {
99
- throw new Error(`Session "${scenarioNameOrSessionName}" not found in OPFS storage`);
100
- }
70
+ try {
71
+ sessionHandle = await sessionsDir.getDirectoryHandle(sessionName);
72
+ } catch {
73
+ throw new Error(`Session "${sessionName}" not found in OPFS storage`);
101
74
  }
75
+ return exportSessionHandleAsZip(sessionHandle, options);
76
+ }
77
+ /**
78
+ * Stream an already-resolved session directory handle to a ZIP blob, running
79
+ * any caller-supplied extension {@link ZipExportContributor}s after the
80
+ * framework-owned files.
81
+ *
82
+ * This is the layout-agnostic core of {@link exportSessionAsZip}: consumers
83
+ * that resolve a session directory handle themselves (e.g. an app that nests
84
+ * sessions under its own grouping layer) call this directly so the framework's
85
+ * ZIP schema stays the single source of truth without the framework needing to
86
+ * know how the handle was located.
87
+ *
88
+ * @param sessionHandle - The session directory to package (must contain the
89
+ * framework-owned `session.json` / `actions/` / `images/` tree).
90
+ * @returns ZIP export result with blob and file count.
91
+ */
92
+ async function exportSessionHandleAsZip(sessionHandle, options) {
102
93
  const zipWriter = new ZipWriter(new BlobWriter("application/zip"), { level: 0 });
103
94
  let fileCount = await streamDirectoryToZip(sessionHandle, zipWriter);
104
95
  const contributors = options?.contributors ?? [];
@@ -136,14 +127,13 @@ async function exportSessionAsZip(scenarioNameOrSessionName, sessionName, option
136
127
  * the last synced ZIP contains all data up to that point.
137
128
  *
138
129
  * @param fileHandle - File handle from showSaveFilePicker
139
- * @param scenarioName - Name of the scenario
140
- * @param sessionName - Name of the session folder
130
+ * @param sessionName - Name of the session folder under `sessions/`
141
131
  * @returns ZIP export result with blob and file count
142
- * @throws Error if scenario or session not found
132
+ * @throws Error if the session is not found
143
133
  */
144
- async function syncToExternalZip(fileHandle, scenarioName, sessionName, options) {
145
- log.info(`Syncing to external ZIP: ${scenarioName}/${sessionName}`);
146
- const result = await exportSessionAsZip(scenarioName, sessionName, options);
134
+ async function syncToExternalZip(fileHandle, sessionName, options) {
135
+ log.info(`Syncing to external ZIP: ${sessionName}`);
136
+ const result = await exportSessionAsZip(sessionName, options);
147
137
  const writable = await fileHandle.createWritable();
148
138
  await writable.write(result.blob);
149
139
  await writable.close();
@@ -191,17 +181,5 @@ async function downloadZip(blob, filename) {
191
181
  setTimeout(() => URL.revokeObjectURL(url), 1e3);
192
182
  log.info(`Download triggered via <a download>: ${filename}`);
193
183
  }
194
- /**
195
- * Export and download a session in one step.
196
- *
197
- * Convenience function combining exportSessionAsZip and downloadZip.
198
- *
199
- * @param scenarioName - Name of the scenario
200
- * @param sessionName - Name of the session folder
201
- */
202
- async function exportAndDownloadSession(scenarioName, sessionName) {
203
- const { blob } = await exportSessionAsZip(scenarioName, sessionName);
204
- await downloadZip(blob, `${scenarioName}-${sessionName}.zip`);
205
- }
206
184
  //#endregion
207
- export { downloadZip, exportAndDownloadSession, exportSessionAsZip, syncToExternalZip };
185
+ export { downloadZip, exportSessionAsZip, exportSessionHandleAsZip, syncToExternalZip };
@@ -1,2 +1,2 @@
1
- import { a as ZipActionEntry, c as loadEntriesFromSubdir, d as loadSessionMetadataFromBlob, f as readZipEntries, i as RecordedAction, l as loadGpsPathFromBlob, n as GpsPathCoord, o as ZipSubdirEntry, r as MAX_ACTION_FILE_SIZE, s as loadActionsFromZip, t as Entry, u as loadSessionMetadata } from "../zip-reader-DSEXt7K6.js";
1
+ import { a as ZipActionEntry, c as loadEntriesFromSubdir, d as loadSessionMetadataFromBlob, f as readZipEntries, i as RecordedAction, l as loadGpsPathFromBlob, n as GpsPathCoord, o as ZipSubdirEntry, r as MAX_ACTION_FILE_SIZE, s as loadActionsFromZip, t as Entry, u as loadSessionMetadata } from "../zip-reader-Q2ue6zlC.js";
2
2
  export { Entry, GpsPathCoord, MAX_ACTION_FILE_SIZE, RecordedAction, ZipActionEntry, ZipSubdirEntry, loadActionsFromZip, loadEntriesFromSubdir, loadGpsPathFromBlob, loadSessionMetadata, loadSessionMetadataFromBlob, readZipEntries };
@@ -1,4 +1,4 @@
1
- import { n as SessionMetadata } from "./opfs-storage-D5zAn_lx.js";
1
+ import { n as SessionMetadata } from "./opfs-storage-DMtlt57S.js";
2
2
 
3
3
  //#region ../src/storage/storage-backend.d.ts
4
4
  interface CreateSessionResult {
@@ -1,5 +1,5 @@
1
- import { t as MapData } from "./map-data-CkloBxIl.js";
2
- import { t as SubscribableStore } from "./subscribe-to-selector-CZ6k1NFP.js";
1
+ import { t as MapData } from "./map-data-DdjPiSav.js";
2
+ import { t as SubscribableStore } from "./subscribe-to-selector-Bp3sLx8L.js";
3
3
  import { LatLong, Matrix4, Quaternion, Vector3 } from "gps-plus-slam-js";
4
4
 
5
5
  //#region ../src/state/store-subscribers.d.ts
@@ -1,4 +1,4 @@
1
- import { L as CombinedRootState } from "./create-slam-app-store-BljusOua.js";
1
+ import { L as CombinedRootState } from "./create-slam-app-store-Ce2FMKCp.js";
2
2
 
3
3
  //#region ../src/state/subscribe-to-selector.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { o as WebXRQuaternion, s as WebXRVec3 } from "../ar-types-Dan1MVTi.js";
1
+ import { o as WebXRQuaternion, s as WebXRVec3 } from "../ar-types-BckI1E-O.js";
2
2
  import { Mock } from "vitest";
3
3
 
4
4
  //#region ../src/test-utils/browser-mocks.d.ts
@@ -195,6 +195,9 @@ declare class MockFSDirectoryHandle implements FileSystemDirectoryHandle {
195
195
  queryPermission(_descriptor?: {
196
196
  mode?: 'read' | 'readwrite';
197
197
  }): Promise<PermissionState>;
198
+ requestPermission(_descriptor?: {
199
+ mode?: 'read' | 'readwrite';
200
+ }): Promise<PermissionState>;
198
201
  }
199
202
  /**
200
203
  * Install File System Access API mocks on the global window object.
@@ -251,6 +254,9 @@ declare class MockOPFSDirectoryHandle implements FileSystemDirectoryHandle {
251
254
  queryPermission(_descriptor?: {
252
255
  mode?: 'read' | 'readwrite';
253
256
  }): Promise<PermissionState>;
257
+ requestPermission(_descriptor?: {
258
+ mode?: 'read' | 'readwrite';
259
+ }): Promise<PermissionState>;
254
260
  }
255
261
  /**
256
262
  * Mock OPFS file handle with writable stream support.
@@ -348,6 +348,9 @@ var MockFSDirectoryHandle = class MockFSDirectoryHandle {
348
348
  queryPermission(_descriptor) {
349
349
  return Promise.resolve("granted");
350
350
  }
351
+ requestPermission(_descriptor) {
352
+ return Promise.resolve("granted");
353
+ }
351
354
  };
352
355
  /**
353
356
  * Install File System Access API mocks on the global window object.
@@ -462,6 +465,9 @@ var MockOPFSDirectoryHandle = class MockOPFSDirectoryHandle {
462
465
  queryPermission(_descriptor) {
463
466
  return Promise.resolve("granted");
464
467
  }
468
+ requestPermission(_descriptor) {
469
+ return Promise.resolve("granted");
470
+ }
465
471
  };
466
472
  /**
467
473
  * Mock OPFS file handle with writable stream support.
@@ -1,4 +1,4 @@
1
- import { i as RecordedAction } from "../zip-reader-DSEXt7K6.js";
1
+ import { i as RecordedAction } from "../zip-reader-Q2ue6zlC.js";
2
2
  import { LatLong } from "gps-plus-slam-js";
3
3
 
4
4
  //#region ../src/test-utils/zip-round-trip-helpers.d.ts
@@ -18,6 +18,14 @@ interface ProduceTestZipOptions {
18
18
  * the field is left off — matching pre-accuracy recordings.
19
19
  */
20
20
  gpsAccuracy?: number;
21
+ /**
22
+ * Optional per-tour H3 coverage index written into `session.json`. When
23
+ * omitted, the fields are left off — matching legacy recordings that predate
24
+ * the coverage index (so the browser must backfill from the GPS path).
25
+ * When provided, `h3Resolution` defaults to 11.
26
+ */
27
+ h3Cells?: string[];
28
+ h3Resolution?: number;
21
29
  }
22
30
  /** Result of producing a test zip, with all metadata needed for assertions. */
23
31
  interface TestZipResult {
@@ -179,7 +179,11 @@ async function produceTestZip(opts) {
179
179
  contextTag: options.scenarioName,
180
180
  actionCount: actionIndex,
181
181
  frameCount: options.frameCount,
182
- userAgent: options.deviceInfo
182
+ userAgent: options.deviceInfo,
183
+ ...options.h3Cells ? {
184
+ h3Cells: options.h3Cells,
185
+ h3Resolution: options.h3Resolution ?? 11
186
+ } : {}
183
187
  });
184
188
  const { blob } = await exportSessionAsZip(sessionName);
185
189
  return {
@@ -1,4 +1,4 @@
1
- import { t as ARPose } from "./ar-types-Dan1MVTi.js";
1
+ import { t as ARPose } from "./ar-types-BckI1E-O.js";
2
2
  import { OdometryTrackingRestartedPayload, Quaternion, Vector3 } from "gps-plus-slam-js";
3
3
  import * as _$_reduxjs_toolkit0 from "@reduxjs/toolkit";
4
4
 
@@ -1,2 +1,2 @@
1
- import { a as RgbTuple, i as DepthSample, n as ArPoseTuples, o as WebXRQuaternion, r as DepthPoint, s as WebXRVec3, t as ARPose } from "../ar-types-Dan1MVTi.js";
1
+ import { a as RgbTuple, i as DepthSample, n as ArPoseTuples, o as WebXRQuaternion, r as DepthPoint, s as WebXRVec3, t as ARPose } from "../ar-types-BckI1E-O.js";
2
2
  export { ARPose, ArPoseTuples, DepthPoint, DepthSample, RgbTuple, WebXRQuaternion, WebXRVec3 };
@@ -1,2 +1,2 @@
1
- import { n as RawGpsSample, r as RefPointMarker, t as GpsCoord } from "../geo-types-SaPnIEUM.js";
1
+ import { n as RawGpsSample, r as RefPointMarker, t as GpsCoord } from "../geo-types-DqiBzPO9.js";
2
2
  export { GpsCoord, RawGpsSample, RefPointMarker };
@@ -1,3 +1,3 @@
1
- import { a as RgbTuple, i as DepthSample, n as ArPoseTuples, o as WebXRQuaternion, r as DepthPoint, s as WebXRVec3, t as ARPose } from "../ar-types-Dan1MVTi.js";
2
- import { n as RawGpsSample, r as RefPointMarker, t as GpsCoord } from "../geo-types-SaPnIEUM.js";
1
+ import { a as RgbTuple, i as DepthSample, n as ArPoseTuples, o as WebXRQuaternion, r as DepthPoint, s as WebXRVec3, t as ARPose } from "../ar-types-BckI1E-O.js";
2
+ import { n as RawGpsSample, r as RefPointMarker, t as GpsCoord } from "../geo-types-DqiBzPO9.js";
3
3
  export { ARPose, ArPoseTuples, DepthPoint, DepthSample, GpsCoord, RawGpsSample, RefPointMarker, RgbTuple, WebXRQuaternion, WebXRVec3 };
@@ -1,2 +1,2 @@
1
- import { t as mapWithConcurrencyLimit } from "../concurrency-CO1FQvs3.js";
2
- export { mapWithConcurrencyLimit };
1
+ import { n as mapWithConcurrencyLimit, t as forEachWithConcurrencyLimit } from "../concurrency-DqAlKX4j.js";
2
+ export { forEachWithConcurrencyLimit, mapWithConcurrencyLimit };
@@ -24,17 +24,81 @@ async function mapWithConcurrencyLimit(items, limit, mapper) {
24
24
  const results = new Array(items.length);
25
25
  if (items.length === 0) return results;
26
26
  let nextIndex = 0;
27
+ let failed = false;
28
+ let firstError;
27
29
  const worker = async () => {
28
30
  while (nextIndex < items.length) {
31
+ if (failed) return;
29
32
  const currentIndex = nextIndex++;
30
- results[currentIndex] = await mapper(items[currentIndex], currentIndex);
33
+ try {
34
+ results[currentIndex] = await mapper(items[currentIndex], currentIndex);
35
+ } catch (err) {
36
+ if (!failed) {
37
+ failed = true;
38
+ firstError = err;
39
+ }
40
+ return;
41
+ }
31
42
  }
32
43
  };
33
44
  const workerCount = Math.min(limit, items.length);
34
45
  const workers = [];
35
46
  for (let i = 0; i < workerCount; i++) workers.push(worker());
36
47
  await Promise.all(workers);
48
+ if (failed) throw firstError;
37
49
  return results;
38
50
  }
51
+ /**
52
+ * Run an async worker over each item with a concurrency cap, invoking the worker
53
+ * per item as the pool pulls it (rather than collecting results into an array).
54
+ *
55
+ * Unlike {@link mapWithConcurrencyLimit}, this returns no values — the worker is
56
+ * expected to produce its side effect (e.g. emit a streaming callback) itself.
57
+ * This is the shape progressive consumers need: each item is handled and can be
58
+ * reported as soon as it settles, instead of waiting for the whole batch.
59
+ *
60
+ * Completion order is **not** guaranteed (it depends on which worker finishes
61
+ * first). Each item's worker is invoked exactly once unless the run is aborted.
62
+ *
63
+ * When an `AbortSignal` is supplied, workers stop pulling **new** items as soon
64
+ * as the signal is aborted (checked before each pull). Items already in flight
65
+ * run to completion — the File System Access reads underneath cannot be torn
66
+ * mid-read — but no further items are started, so a destroyed consumer stops
67
+ * accumulating work. If the signal is already aborted, no work starts at all.
68
+ *
69
+ * @param items - Items to process
70
+ * @param limit - Maximum number of concurrent worker invocations (`>= 1`)
71
+ * @param worker - Async side-effecting function applied to each item
72
+ * @param signal - Optional abort signal that halts pulling new items
73
+ * @throws RangeError if `limit < 1`
74
+ * @throws Re-throws the first error from any worker invocation (fail-fast)
75
+ */
76
+ async function forEachWithConcurrencyLimit(items, limit, worker, signal) {
77
+ if (limit < 1) throw new RangeError(`Concurrency limit must be >= 1, got ${limit}`);
78
+ if (items.length === 0) return;
79
+ let nextIndex = 0;
80
+ let failed = false;
81
+ let firstError;
82
+ const pump = async () => {
83
+ while (nextIndex < items.length) {
84
+ if (signal?.aborted || failed) return;
85
+ const currentIndex = nextIndex++;
86
+ try {
87
+ await worker(items[currentIndex], currentIndex);
88
+ } catch (err) {
89
+ if (!failed) {
90
+ failed = true;
91
+ firstError = err;
92
+ }
93
+ return;
94
+ }
95
+ }
96
+ };
97
+ const workerCount = Math.min(limit, items.length);
98
+ const workers = [];
99
+ for (let i = 0; i < workerCount; i++) workers.push(pump());
100
+ await Promise.all(workers);
101
+ if (failed) throw firstError;
102
+ }
39
103
  //#endregion
40
- export { mapWithConcurrencyLimit };
104
+ export { forEachWithConcurrencyLimit, mapWithConcurrencyLimit };
@@ -1,2 +1,2 @@
1
- import { n as FailureTrackerConfig, r as createFailureTracker, t as FailureTracker } from "../failure-tracker-Cn8Fo9D4.js";
1
+ import { n as FailureTrackerConfig, r as createFailureTracker, t as FailureTracker } from "../failure-tracker-Cnc_xWUw.js";
2
2
  export { FailureTracker, FailureTrackerConfig, createFailureTracker };
@@ -1,2 +1,2 @@
1
- import { t as formatFileSize } from "../format-file-size-CLCZz3lC.js";
1
+ import { t as formatFileSize } from "../format-file-size-BFUWvir1.js";
2
2
  export { formatFileSize };
@@ -1,2 +1,2 @@
1
- import { n as computeFusedPath, r as fusedGpsFromOdom, t as FusedPathInput } from "../fused-path-DJoVu98b.js";
1
+ import { n as computeFusedPath, r as fusedGpsFromOdom, t as FusedPathInput } from "../fused-path-C0FHe67t.js";
2
2
  export { FusedPathInput, computeFusedPath, fusedGpsFromOdom };
@@ -1,7 +1,7 @@
1
- import { a as createLogger, c as setGlobalLogLevel, i as clearLogBuffer, l as subscribeToLogs, n as LogLevel, o as getGlobalLogLevel, r as Logger, s as getLogBuffer, t as LogEntry } from "../logger-BEHXsnnq.js";
2
- import { n as computeFusedPath, r as fusedGpsFromOdom, t as FusedPathInput } from "../fused-path-DJoVu98b.js";
3
- import { n as FailureTrackerConfig, r as createFailureTracker, t as FailureTracker } from "../failure-tracker-Cn8Fo9D4.js";
4
- import { t as mapWithConcurrencyLimit } from "../concurrency-CO1FQvs3.js";
5
- import { t as formatFileSize } from "../format-file-size-CLCZz3lC.js";
6
- import { t as listFormatter } from "../list-formatter-RRcBe8Vg.js";
1
+ import { a as createLogger, c as setGlobalLogLevel, i as clearLogBuffer, l as subscribeToLogs, n as LogLevel, o as getGlobalLogLevel, r as Logger, s as getLogBuffer, t as LogEntry } from "../logger-CzQrCe6C.js";
2
+ import { n as computeFusedPath, r as fusedGpsFromOdom, t as FusedPathInput } from "../fused-path-C0FHe67t.js";
3
+ import { n as FailureTrackerConfig, r as createFailureTracker, t as FailureTracker } from "../failure-tracker-Cnc_xWUw.js";
4
+ import { n as mapWithConcurrencyLimit } from "../concurrency-DqAlKX4j.js";
5
+ import { t as formatFileSize } from "../format-file-size-BFUWvir1.js";
6
+ import { t as listFormatter } from "../list-formatter-ct8txwvR.js";
7
7
  export { type FailureTracker, type FailureTrackerConfig, type FusedPathInput, type LogEntry, LogLevel, type Logger, clearLogBuffer, computeFusedPath, createFailureTracker, createLogger, formatFileSize, fusedGpsFromOdom, getGlobalLogLevel, getLogBuffer, listFormatter, mapWithConcurrencyLimit, setGlobalLogLevel, subscribeToLogs };
@@ -1,2 +1,2 @@
1
- import { t as listFormatter } from "../list-formatter-RRcBe8Vg.js";
1
+ import { t as listFormatter } from "../list-formatter-ct8txwvR.js";
2
2
  export { listFormatter };
@@ -1,2 +1,2 @@
1
- import { a as createLogger, c as setGlobalLogLevel, i as clearLogBuffer, l as subscribeToLogs, n as LogLevel, o as getGlobalLogLevel, r as Logger, s as getLogBuffer, t as LogEntry } from "../logger-BEHXsnnq.js";
1
+ import { a as createLogger, c as setGlobalLogLevel, i as clearLogBuffer, l as subscribeToLogs, n as LogLevel, o as getGlobalLogLevel, r as Logger, s as getLogBuffer, t as LogEntry } from "../logger-CzQrCe6C.js";
2
2
  export { LogEntry, LogLevel, Logger, clearLogBuffer, createLogger, getGlobalLogLevel, getLogBuffer, setGlobalLogLevel, subscribeToLogs };
@@ -1,2 +1,2 @@
1
- import { a as addAccuracyCircles, i as AccuracyCircleSample, n as ACCURACY_CIRCLE_STROKE_OPACITY, r as ACCURACY_CIRCLE_WEIGHT, t as ACCURACY_CIRCLE_FILL_OPACITY } from "../accuracy-circles-BpwWAs8G.js";
1
+ import { a as addAccuracyCircles, i as AccuracyCircleSample, n as ACCURACY_CIRCLE_STROKE_OPACITY, r as ACCURACY_CIRCLE_WEIGHT, t as ACCURACY_CIRCLE_FILL_OPACITY } from "../accuracy-circles-Pi2YeCrM.js";
2
2
  export { ACCURACY_CIRCLE_FILL_OPACITY, ACCURACY_CIRCLE_STROKE_OPACITY, ACCURACY_CIRCLE_WEIGHT, AccuracyCircleSample, addAccuracyCircles };
@@ -1,2 +1,2 @@
1
- import { n as createAlignmentLerper, t as AlignmentLerper } from "../alignment-lerper-Dm9G7JJO.js";
1
+ import { n as createAlignmentLerper, t as AlignmentLerper } from "../alignment-lerper-BUTsQ2yu.js";
2
2
  export { AlignmentLerper, createAlignmentLerper };
@@ -1,2 +1,2 @@
1
- import { n as ArWorldGroupAlignmentOptions, r as enableArWorldGroupAlignment, t as ArWorldGroupAlignmentHandle } from "../ar-world-group-alignment-C9lwwIyI.js";
1
+ import { n as ArWorldGroupAlignmentOptions, r as enableArWorldGroupAlignment, t as ArWorldGroupAlignmentHandle } from "../ar-world-group-alignment-DDLkgNf_.js";
2
2
  export { ArWorldGroupAlignmentHandle, ArWorldGroupAlignmentOptions, enableArWorldGroupAlignment };
@@ -1,5 +1,5 @@
1
1
  import { registerFrameUpdate } from "../ar/frame-loop.js";
2
- import { t as registerSessionDisposer } from "../session-disposers-M-oashRH.js";
2
+ import { t as registerSessionDisposer } from "../session-disposers-D8wnO-uW.js";
3
3
  import { createAlignmentLerper } from "./alignment-lerper.js";
4
4
  import { selectAlignmentMatrix } from "../state/app-selectors.js";
5
5
  import { subscribeToSelector } from "../state/subscribe-to-selector.js";