@bvdmitri/gyroview 0.0.0-stage → 0.9.0-cutaway.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/CHANGELOG.md +402 -0
  2. package/LICENSE +21 -0
  3. package/README.md +313 -2
  4. package/dist/define.d.ts +3 -0
  5. package/dist/define.js +4 -0
  6. package/dist/index.d.ts +1204 -0
  7. package/dist/index.js +12 -0
  8. package/dist/packages/adapters/blob/src/BlobRandomAccessSource.js +36 -0
  9. package/dist/packages/adapters/fetch/src/HttpByteStream.js +173 -0
  10. package/dist/packages/adapters/fetch/src/HttpRangeSource.js +37 -0
  11. package/dist/packages/adapters/fetch/src/HttpResource.js +227 -0
  12. package/dist/packages/adapters/fetch/src/HttpResourceLocator.js +35 -0
  13. package/dist/packages/adapters/fetch/src/contentRange.js +15 -0
  14. package/dist/packages/adapters/fetch/src/httpRequest.js +136 -0
  15. package/dist/packages/adapters/fetch/src/passingFailures.js +23 -0
  16. package/dist/packages/adapters/fetch/src/rangeFailures.js +16 -0
  17. package/dist/packages/adapters/fetch/src/recordingVersion.js +37 -0
  18. package/dist/packages/adapters/mediabunny/src/MediabunnyAudioPackager.js +162 -0
  19. package/dist/packages/adapters/mediabunny/src/MediabunnyCodecReader.js +93 -0
  20. package/dist/packages/adapters/mediabunny/src/SegmentChannel.js +135 -0
  21. package/dist/packages/adapters/mediabunny/src/bufferSources.js +12 -0
  22. package/dist/packages/adapters/mediabunny/src/decoderConfigurations.js +43 -0
  23. package/dist/packages/adapters/mediabunny/src/trackColour.js +20 -0
  24. package/dist/packages/adapters/mse-audio/src/MediaSourceAudioClock.js +138 -0
  25. package/dist/packages/adapters/mse-audio/src/SourceBufferFeeder.js +263 -0
  26. package/dist/packages/adapters/mse-audio/src/events.js +26 -0
  27. package/dist/packages/adapters/mse-audio/src/mediaSourceSupport.js +81 -0
  28. package/dist/packages/adapters/three/src/ThreeFrameRenderer.js +215 -0
  29. package/dist/packages/adapters/three/src/compileAndProve.js +14 -0
  30. package/dist/packages/adapters/three/src/conversionUniforms.js +60 -0
  31. package/dist/packages/adapters/three/src/drawSchedules.js +13 -0
  32. package/dist/packages/adapters/three/src/fullscreenPass.js +52 -0
  33. package/dist/packages/adapters/three/src/glslLiterals.js +10 -0
  34. package/dist/packages/adapters/three/src/lensTextures.js +34 -0
  35. package/dist/packages/adapters/three/src/matrixCorrections.js +34 -0
  36. package/dist/packages/adapters/three/src/pictureMaterials.js +44 -0
  37. package/dist/packages/adapters/three/src/renderInto.js +15 -0
  38. package/dist/packages/adapters/three/src/rendererParts.js +108 -0
  39. package/dist/packages/adapters/three/src/rendererUniforms.js +176 -0
  40. package/dist/packages/adapters/three/src/samplingStrategies.js +26 -0
  41. package/dist/packages/adapters/three/src/scissorBox.js +20 -0
  42. package/dist/packages/adapters/three/src/seamMeter/SeamMeterPass.js +85 -0
  43. package/dist/packages/adapters/three/src/seamMeter/rowMeans.js +42 -0
  44. package/dist/packages/adapters/three/src/shaderPrograms.js +68 -0
  45. package/dist/packages/adapters/three/src/shaders/analysis.frag.js +4 -0
  46. package/dist/packages/adapters/three/src/shaders/displayConversion.js +4 -0
  47. package/dist/packages/adapters/three/src/shaders/equirectangularRays.js +4 -0
  48. package/dist/packages/adapters/three/src/shaders/fixedJoin.js +4 -0
  49. package/dist/packages/adapters/three/src/shaders/fullscreen.vert.js +4 -0
  50. package/dist/packages/adapters/three/src/shaders/header.js +4 -0
  51. package/dist/packages/adapters/three/src/shaders/lensModels.js +4 -0
  52. package/dist/packages/adapters/three/src/shaders/lensSampling.js +4 -0
  53. package/dist/packages/adapters/three/src/shaders/lensTextures.js +4 -0
  54. package/dist/packages/adapters/three/src/shaders/rawLenses.frag.js +4 -0
  55. package/dist/packages/adapters/three/src/shaders/rectilinearRays.js +4 -0
  56. package/dist/packages/adapters/three/src/shaders/screenAreas.js +4 -0
  57. package/dist/packages/adapters/three/src/shaders/stitch.frag.js +4 -0
  58. package/dist/packages/adapters/three/src/threeMatrix.js +10 -0
  59. package/dist/packages/adapters/three/src/webglRenderer.js +37 -0
  60. package/dist/packages/adapters/webcodecs/src/WebCodecsVideoDecoderPort.js +152 -0
  61. package/dist/packages/adapters/webcodecs/src/colorSpaceOf.js +32 -0
  62. package/dist/packages/core/src/application/download/BlockStore.js +97 -0
  63. package/dist/packages/core/src/application/download/DownloadedAudioSamples.js +50 -0
  64. package/dist/packages/core/src/application/download/DownloadedVideoTrack.js +122 -0
  65. package/dist/packages/core/src/application/download/FileDownload.js +208 -0
  66. package/dist/packages/core/src/application/download/RecordingBuffer.js +22 -0
  67. package/dist/packages/core/src/application/download/SampleCursor.js +89 -0
  68. package/dist/packages/core/src/application/download/SourceByteStream.js +46 -0
  69. package/dist/packages/core/src/application/download/Transfers.js +82 -0
  70. package/dist/packages/core/src/application/download/startFileDownload.js +37 -0
  71. package/dist/packages/core/src/application/gainMatching/GainMatching.js +76 -0
  72. package/dist/packages/core/src/application/gainMatching/GainMatchingFrameSink.js +80 -0
  73. package/dist/packages/core/src/application/gainMatching/referenceLensOf.js +18 -0
  74. package/dist/packages/core/src/application/playback/Buffering.js +54 -0
  75. package/dist/packages/core/src/application/playback/ClockStart.js +55 -0
  76. package/dist/packages/core/src/application/playback/ClockWatch.js +76 -0
  77. package/dist/packages/core/src/application/playback/DecodePipeline.js +234 -0
  78. package/dist/packages/core/src/application/playback/DecodeRun.js +108 -0
  79. package/dist/packages/core/src/application/playback/FramePairQueue.js +93 -0
  80. package/dist/packages/core/src/application/playback/FramePairer.js +77 -0
  81. package/dist/packages/core/src/application/playback/PictureOnScreen.js +56 -0
  82. package/dist/packages/core/src/application/playback/PlaybackSession.js +410 -0
  83. package/dist/packages/core/src/application/playback/SeekOrder.js +35 -0
  84. package/dist/packages/core/src/application/playback/SessionLifecycle.js +42 -0
  85. package/dist/packages/core/src/application/playback/StartGate.js +69 -0
  86. package/dist/packages/core/src/application/playback/TimeUpdates.js +31 -0
  87. package/dist/packages/core/src/application/playback/WallClock.js +46 -0
  88. package/dist/packages/core/src/application/playback/keyframeTimeAt.js +15 -0
  89. package/dist/packages/core/src/application/playback/probeDecoding.js +182 -0
  90. package/dist/packages/core/src/application/recording/frameTimesOf.js +21 -0
  91. package/dist/packages/core/src/application/recording/inspectLayout.js +21 -0
  92. package/dist/packages/core/src/application/recording/inspectRecording.js +125 -0
  93. package/dist/packages/core/src/application/recording/locateOtherLensFile.js +18 -0
  94. package/dist/packages/core/src/application/recording/motionOf.js +43 -0
  95. package/dist/packages/core/src/application/recording/readRecording.js +31 -0
  96. package/dist/packages/core/src/application/recording/readRecordingFiles.js +130 -0
  97. package/dist/packages/core/src/application/recording/readSampleTable.js +27 -0
  98. package/dist/packages/core/src/application/recording/timeRecording.js +57 -0
  99. package/dist/packages/core/src/application/stabilization/StabilizingFrameSink.js +33 -0
  100. package/dist/packages/core/src/domain/colour/DisplayConversion.js +137 -0
  101. package/dist/packages/core/src/domain/colour/TrackColour.js +38 -0
  102. package/dist/packages/core/src/domain/colour/gainMatch.js +64 -0
  103. package/dist/packages/core/src/domain/colour/matrixCorrection.js +76 -0
  104. package/dist/packages/core/src/domain/container/KeyframeRule.js +7 -0
  105. package/dist/packages/core/src/domain/container/SampleTable.js +29 -0
  106. package/dist/packages/core/src/domain/container/TrackSampleTable.js +96 -0
  107. package/dist/packages/core/src/domain/container/presentationOrder.js +10 -0
  108. package/dist/packages/core/src/domain/download/DownloadPolicy.js +84 -0
  109. package/dist/packages/core/src/domain/download/isReadyToResume.js +27 -0
  110. package/dist/packages/core/src/domain/download/planDownloads.js +175 -0
  111. package/dist/packages/core/src/domain/download/trackNeeds.js +32 -0
  112. package/dist/packages/core/src/domain/format/boxes/BoxLayout.js +7 -0
  113. package/dist/packages/core/src/domain/format/boxes/boxConstants.js +16 -0
  114. package/dist/packages/core/src/domain/format/boxes/boxHeader.js +44 -0
  115. package/dist/packages/core/src/domain/format/boxes/scanBoxes.js +32 -0
  116. package/dist/packages/core/src/domain/format/calibration/CalibrationVersion.js +16 -0
  117. package/dist/packages/core/src/domain/format/calibration/layouts/CalibrationStringLayout.js +34 -0
  118. package/dist/packages/core/src/domain/format/calibration/layouts/LegacyCalibrationLayout.js +46 -0
  119. package/dist/packages/core/src/domain/format/calibration/layouts/MeiCalibrationLayout.js +121 -0
  120. package/dist/packages/core/src/domain/format/calibration/layouts/PolynomialCalibrationLayout.js +46 -0
  121. package/dist/packages/core/src/domain/format/calibration/offsetTokens.js +94 -0
  122. package/dist/packages/core/src/domain/format/calibration/parseOffsetString.js +77 -0
  123. package/dist/packages/core/src/domain/format/calibration/selectCalibration.js +59 -0
  124. package/dist/packages/core/src/domain/format/calibration/v6TermReading.js +20 -0
  125. package/dist/packages/core/src/domain/format/captureOrigin.js +34 -0
  126. package/dist/packages/core/src/domain/format/constants.js +35 -0
  127. package/dist/packages/core/src/domain/format/info/calibrationSources.js +27 -0
  128. package/dist/packages/core/src/domain/format/info/infoFields.js +116 -0
  129. package/dist/packages/core/src/domain/format/info/parseInfoRecord.js +107 -0
  130. package/dist/packages/core/src/domain/format/info/readInfoRecord.js +14 -0
  131. package/dist/packages/core/src/domain/format/layout/detectLensLayout.js +133 -0
  132. package/dist/packages/core/src/domain/format/mp4/hevcCodecString.js +161 -0
  133. package/dist/packages/core/src/domain/format/mp4/keyframeRules.js +81 -0
  134. package/dist/packages/core/src/domain/format/mp4/movieBoxes.js +52 -0
  135. package/dist/packages/core/src/domain/format/mp4/mp4BoxTypes.js +46 -0
  136. package/dist/packages/core/src/domain/format/mp4/mp4Layouts.js +183 -0
  137. package/dist/packages/core/src/domain/format/mp4/parseMovie.js +72 -0
  138. package/dist/packages/core/src/domain/format/mp4/readTable.js +31 -0
  139. package/dist/packages/core/src/domain/format/mp4/sampleLocations.js +76 -0
  140. package/dist/packages/core/src/domain/format/mp4/sampleTiming.js +120 -0
  141. package/dist/packages/core/src/domain/format/mp4/trackHeaders.js +88 -0
  142. package/dist/packages/core/src/domain/format/naming/RecordingFileName.js +70 -0
  143. package/dist/packages/core/src/domain/format/records/TrailerRecords.js +100 -0
  144. package/dist/packages/core/src/domain/format/records/exposure/parseExposureRecord.js +48 -0
  145. package/dist/packages/core/src/domain/format/records/gyro/FloatGyroSampleLayout.js +38 -0
  146. package/dist/packages/core/src/domain/format/records/gyro/RawGyroSampleLayout.js +55 -0
  147. package/dist/packages/core/src/domain/format/records/gyro/SampleColumns.js +89 -0
  148. package/dist/packages/core/src/domain/format/records/gyro/gyroLayouts.js +12 -0
  149. package/dist/packages/core/src/domain/format/records/gyro/parseGyroRecord.js +138 -0
  150. package/dist/packages/core/src/domain/format/records/trim/parseTrimRecord.js +24 -0
  151. package/dist/packages/core/src/domain/format/trailer/RecordHeader.js +23 -0
  152. package/dist/packages/core/src/domain/format/trailer/Trailer.js +23 -0
  153. package/dist/packages/core/src/domain/format/trailer/TrailerFooter.js +27 -0
  154. package/dist/packages/core/src/domain/format/trailer/locateRecords.js +80 -0
  155. package/dist/packages/core/src/domain/format/trailer/parseRecordIndex.js +28 -0
  156. package/dist/packages/core/src/domain/format/trailer/readTrailer.js +60 -0
  157. package/dist/packages/core/src/domain/motion/exposure/ExposureRecord.js +48 -0
  158. package/dist/packages/core/src/domain/motion/gyro/GyroTrack.js +70 -0
  159. package/dist/packages/core/src/domain/motion/gyro/medianStep.js +11 -0
  160. package/dist/packages/core/src/domain/motion/gyro/repairedTimeline.js +101 -0
  161. package/dist/packages/core/src/domain/motion/imu/ImuFrame.js +178 -0
  162. package/dist/packages/core/src/domain/motion/mounting/Mounting.js +131 -0
  163. package/dist/packages/core/src/domain/motion/orientation/OrientationTrack.js +142 -0
  164. package/dist/packages/core/src/domain/motion/orientation/estimateGyroBias.js +72 -0
  165. package/dist/packages/core/src/domain/motion/orientation/gravity.js +97 -0
  166. package/dist/packages/core/src/domain/motion/stabilization/Stabilizer.js +13 -0
  167. package/dist/packages/core/src/domain/motion/stabilization/stabilizers.js +86 -0
  168. package/dist/packages/core/src/domain/motion/timing/CaptureClock.js +41 -0
  169. package/dist/packages/core/src/domain/motion/timing/FrameTimes.js +85 -0
  170. package/dist/packages/core/src/domain/motion/timing/frameTimeSources.js +58 -0
  171. package/dist/packages/core/src/domain/motion/timing/resolveFrameTimes.js +68 -0
  172. package/dist/packages/core/src/domain/optics/EquidistantModel.js +34 -0
  173. package/dist/packages/core/src/domain/optics/MeiDistortion.js +27 -0
  174. package/dist/packages/core/src/domain/optics/MeiModel.js +27 -0
  175. package/dist/packages/core/src/domain/optics/PolynomialModel.js +39 -0
  176. package/dist/packages/core/src/domain/optics/lensPose.js +49 -0
  177. package/dist/packages/core/src/domain/optics/opticsConstants.js +5 -0
  178. package/dist/packages/core/src/domain/optics/scaledProjection.js +30 -0
  179. package/dist/packages/core/src/domain/playback/PlayerState.js +83 -0
  180. package/dist/packages/core/src/domain/rendition/RenditionSpan.js +70 -0
  181. package/dist/packages/core/src/domain/stitching/LensLayout.js +21 -0
  182. package/dist/packages/core/src/domain/stitching/StitchingSetup.js +87 -0
  183. package/dist/packages/core/src/domain/stitching/seamRing.js +4 -0
  184. package/dist/packages/core/src/domain/view/Framing.js +37 -0
  185. package/dist/packages/core/src/domain/view/Picture.js +12 -0
  186. package/dist/packages/core/src/domain/view/PictureQuality.js +26 -0
  187. package/dist/packages/core/src/domain/view/ViewMode.js +9 -0
  188. package/dist/packages/core/src/domain/view/ViewState.js +54 -0
  189. package/dist/packages/core/src/domain/view/lensTilesView.js +64 -0
  190. package/dist/packages/core/src/domain/view/magnification.js +103 -0
  191. package/dist/packages/core/src/domain/view/motionLookView.js +100 -0
  192. package/dist/packages/core/src/domain/view/normalView.js +37 -0
  193. package/dist/packages/core/src/domain/view/panoramaView.js +95 -0
  194. package/dist/packages/core/src/domain/view/rectilinear.js +53 -0
  195. package/dist/packages/core/src/domain/view/screenLayout.js +129 -0
  196. package/dist/packages/core/src/domain/view/screenLook.js +74 -0
  197. package/dist/packages/core/src/domain/view/viewGestures.js +104 -0
  198. package/dist/packages/core/src/domain/view/viewModes.js +31 -0
  199. package/dist/packages/core/src/ports/FramePair.js +6 -0
  200. package/dist/packages/core/src/shared/async/Deferred.js +42 -0
  201. package/dist/packages/core/src/shared/async/RunStop.js +40 -0
  202. package/dist/packages/core/src/shared/async/iteration.js +24 -0
  203. package/dist/packages/core/src/shared/binary/ByteRange.js +50 -0
  204. package/dist/packages/core/src/shared/binary/ByteRangeSet.js +85 -0
  205. package/dist/packages/core/src/shared/binary/ByteReader.js +104 -0
  206. package/dist/packages/core/src/shared/binary/concatenated.js +15 -0
  207. package/dist/packages/core/src/shared/errors/GyroViewError.js +140 -0
  208. package/dist/packages/core/src/shared/errors/reportLater.js +11 -0
  209. package/dist/packages/core/src/shared/events/Outbox.js +68 -0
  210. package/dist/packages/core/src/shared/events/TypedEmitter.js +55 -0
  211. package/dist/packages/core/src/shared/keysOf.js +10 -0
  212. package/dist/packages/core/src/shared/lazy.js +11 -0
  213. package/dist/packages/core/src/shared/mapRecord.js +11 -0
  214. package/dist/packages/core/src/shared/math/Matrix3.js +121 -0
  215. package/dist/packages/core/src/shared/math/Quaternion.js +133 -0
  216. package/dist/packages/core/src/shared/math/Vector3.js +58 -0
  217. package/dist/packages/core/src/shared/math/clamp.js +9 -0
  218. package/dist/packages/core/src/shared/math/countAtOrBelow.js +31 -0
  219. package/dist/packages/core/src/shared/math/minimum.js +17 -0
  220. package/dist/packages/core/src/shared/protobuf/ProtobufMessage.js +143 -0
  221. package/dist/packages/core/src/shared/protobuf/wireFormat.js +16 -0
  222. package/dist/packages/core/src/shared/text/urlPath.js +31 -0
  223. package/dist/packages/core/src/shared/text/utf8.js +12 -0
  224. package/dist/packages/core/src/shared/units/angle.js +22 -0
  225. package/dist/packages/core/src/shared/units/time.js +13 -0
  226. package/dist/packages/player/src/PlayerSource.js +14 -0
  227. package/dist/packages/player/src/browserPlayer.js +20 -0
  228. package/dist/packages/player/src/choices.js +24 -0
  229. package/dist/packages/player/src/composition/AnimationFrameDraws.js +38 -0
  230. package/dist/packages/player/src/composition/BrowserAttitudeSensor.js +191 -0
  231. package/dist/packages/player/src/composition/Disposables.js +31 -0
  232. package/dist/packages/player/src/composition/DrawingBufferFit.js +119 -0
  233. package/dist/packages/player/src/composition/animationFrames.js +9 -0
  234. package/dist/packages/player/src/composition/attitudeSensor.js +18 -0
  235. package/dist/packages/player/src/composition/browserPorts.js +80 -0
  236. package/dist/packages/player/src/composition/buildPipeline.js +186 -0
  237. package/dist/packages/player/src/composition/ensureDecodable.js +62 -0
  238. package/dist/packages/player/src/composition/openInputs.js +120 -0
  239. package/dist/packages/player/src/composition/openRecording.js +41 -0
  240. package/dist/packages/player/src/composition/readInputs.js +25 -0
  241. package/dist/packages/player/src/composition/renditionFrames.js +160 -0
  242. package/dist/packages/player/src/controls/ChoiceMenu.js +125 -0
  243. package/dist/packages/player/src/controls/FullscreenButton.js +29 -0
  244. package/dist/packages/player/src/controls/MotionLookButton.js +34 -0
  245. package/dist/packages/player/src/controls/PictureMenus.js +60 -0
  246. package/dist/packages/player/src/controls/SeekBar.js +126 -0
  247. package/dist/packages/player/src/controls/SoundControls.js +43 -0
  248. package/dist/packages/player/src/controls/TransportButtons.js +28 -0
  249. package/dist/packages/player/src/controls/ViewGestures.js +135 -0
  250. package/dist/packages/player/src/controls/Wording.js +79 -0
  251. package/dist/packages/player/src/controls/controlParts.js +38 -0
  252. package/dist/packages/player/src/controls/controls.js +4 -0
  253. package/dist/packages/player/src/controls/controlsBar.js +33 -0
  254. package/dist/packages/player/src/controls/controlsMarkup.js +100 -0
  255. package/dist/packages/player/src/controls/customControls.js +43 -0
  256. package/dist/packages/player/src/controls/formatTime.js +19 -0
  257. package/dist/packages/player/src/controls/icons.js +66 -0
  258. package/dist/packages/player/src/controls/keyboard.js +120 -0
  259. package/dist/packages/player/src/controls/messages.js +130 -0
  260. package/dist/packages/player/src/controls/nativeFullscreen.js +27 -0
  261. package/dist/packages/player/src/controls/parseMarkup.js +30 -0
  262. package/dist/packages/player/src/controls/resetViewButton.js +11 -0
  263. package/dist/packages/player/src/controls/sliderFill.js +15 -0
  264. package/dist/packages/player/src/element/ElementLoads.js +130 -0
  265. package/dist/packages/player/src/element/FullscreenToggle.js +93 -0
  266. package/dist/packages/player/src/element/GyroViewElement.js +358 -0
  267. package/dist/packages/player/src/element/IdleWatcher.js +71 -0
  268. package/dist/packages/player/src/element/PlayerCanvas.js +72 -0
  269. package/dist/packages/player/src/element/TypedEventElement.js +22 -0
  270. package/dist/packages/player/src/element/accessibleRegion.js +19 -0
  271. package/dist/packages/player/src/element/attributeNames.js +62 -0
  272. package/dist/packages/player/src/element/attributes.js +123 -0
  273. package/dist/packages/player/src/element/defineGyroView.js +20 -0
  274. package/dist/packages/player/src/element/earlyProperties.js +35 -0
  275. package/dist/packages/player/src/element/elementProperties.js +34 -0
  276. package/dist/packages/player/src/element/elementSource.js +39 -0
  277. package/dist/packages/player/src/element/fetchProperty.js +48 -0
  278. package/dist/packages/player/src/element/liveSettings.js +137 -0
  279. package/dist/packages/player/src/element/playbackAttributes.js +52 -0
  280. package/dist/packages/player/src/element/playerEventMirror.js +33 -0
  281. package/dist/packages/player/src/element/reflectedProperties.js +96 -0
  282. package/dist/packages/player/src/element/styles.js +4 -0
  283. package/dist/packages/player/src/element/template.js +46 -0
  284. package/dist/packages/player/src/inspectRecording.js +21 -0
  285. package/dist/packages/player/src/player/FrameLoop.js +35 -0
  286. package/dist/packages/player/src/player/MotionLook.js +150 -0
  287. package/dist/packages/player/src/player/PictureSettings.js +59 -0
  288. package/dist/packages/player/src/player/PlaybackStarts.js +38 -0
  289. package/dist/packages/player/src/player/Player.js +379 -0
  290. package/dist/packages/player/src/player/PlayerEvents.js +28 -0
  291. package/dist/packages/player/src/player/PlayerPhase.js +38 -0
  292. package/dist/packages/player/src/player/PlayerSound.js +60 -0
  293. package/dist/packages/player/src/player/PlayerView.js +143 -0
  294. package/dist/packages/player/src/player/SessionRelay.js +74 -0
  295. package/dist/packages/player/src/player/StatusAnnouncer.js +29 -0
  296. package/dist/packages/player/src/player/ensureFinite.js +26 -0
  297. package/dist/packages/player/src/player/loadRecording.js +47 -0
  298. package/dist/packages/player/src/player/transportEvents.js +30 -0
  299. package/dist/packages/player/src/player/viewAngles.js +17 -0
  300. package/dist/packages/player/src/rendition.js +52 -0
  301. package/dist/standalone.js +5633 -0
  302. package/package.json +70 -3
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ import { GYRO_VIEW_ERROR_CATEGORIES, GYRO_VIEW_ERROR_CODES, GyroViewError, hasErrorCode, isGyroViewErrorCode } from "./packages/core/src/shared/errors/GyroViewError.js";
2
+ import { STABILIZATION_MODES } from "./packages/core/src/domain/motion/stabilization/Stabilizer.js";
3
+ import { PICTURE_QUALITIES } from "./packages/core/src/domain/view/PictureQuality.js";
4
+ import { VIEW_MODES } from "./packages/core/src/domain/view/ViewMode.js";
5
+ import { attachKeyboard, attachViewGestures } from "./packages/player/src/controls/customControls.js";
6
+ import { Player } from "./packages/player/src/player/Player.js";
7
+ import { createBrowserPlayer } from "./packages/player/src/browserPlayer.js";
8
+ import { inspectRecording } from "./packages/player/src/inspectRecording.js";
9
+ import { openRendition } from "./packages/player/src/rendition.js";
10
+ import { GyroViewElement } from "./packages/player/src/element/GyroViewElement.js";
11
+ import { GYRO_VIEW_TAG, defineGyroView } from "./packages/player/src/element/defineGyroView.js";
12
+ export { GYRO_VIEW_ERROR_CATEGORIES, GYRO_VIEW_ERROR_CODES, GYRO_VIEW_TAG, GyroViewElement, GyroViewError, PICTURE_QUALITIES, Player, STABILIZATION_MODES, VIEW_MODES, attachKeyboard, attachViewGestures, createBrowserPlayer, defineGyroView, hasErrorCode, inspectRecording, isGyroViewErrorCode, openRendition };
@@ -0,0 +1,36 @@
1
+ import { GyroViewError } from "../../../core/src/shared/errors/GyroViewError.js";
2
+ //#region ../../packages/adapters/blob/src/BlobRandomAccessSource.ts
3
+ /**
4
+ * RandomAccessSource over a `Blob` (a `File` from a picker or a drop). Each read slices the
5
+ * blob, which browsers serve from disk without loading the whole file, so multi-gigabyte
6
+ * recordings play from local storage the same way they play from a URL.
7
+ */
8
+ var BlobRandomAccessSource = class {
9
+ blob;
10
+ constructor(blob) {
11
+ this.blob = blob;
12
+ }
13
+ size() {
14
+ return Promise.resolve(this.blob.size);
15
+ }
16
+ async read(range) {
17
+ range.ensureWithin(this.blob.size, "blob");
18
+ if (range.length === 0) return /* @__PURE__ */ new Uint8Array();
19
+ const bytes = await this.bytesOf(this.blob.slice(range.offset, range.end));
20
+ if (bytes.byteLength !== range.length) throw new GyroViewError("source-truncated", `the blob yielded ${bytes.byteLength} bytes for a ${range.length}-byte range at ${range.offset}; the file may have changed on disk`);
21
+ return bytes;
22
+ }
23
+ /**
24
+ * Reading is what fails, with a `NotReadableError`, when a picked file has changed or gone on
25
+ * disk; slicing only clamps its arguments.
26
+ */
27
+ async bytesOf(slice) {
28
+ try {
29
+ return new Uint8Array(await slice.arrayBuffer());
30
+ } catch (error) {
31
+ throw new GyroViewError("source-unreadable", "the blob could not be read", { cause: error });
32
+ }
33
+ }
34
+ };
35
+ //#endregion
36
+ export { BlobRandomAccessSource };
@@ -0,0 +1,173 @@
1
+ import { GyroViewError, isAbortError } from "../../../core/src/shared/errors/GyroViewError.js";
2
+ import { ByteRange } from "../../../core/src/shared/binary/ByteRange.js";
3
+ import { Ending, ITERATION_END } from "../../../core/src/shared/async/iteration.js";
4
+ import { contentRangeOf } from "./contentRange.js";
5
+ import { passing } from "./passingFailures.js";
6
+ import { brokenOff, truncated } from "./rangeFailures.js";
7
+ //#region ../../packages/adapters/fetch/src/HttpByteStream.ts
8
+ /**
9
+ * Long enough for a slow mobile network to deliver its next packet, short enough that playback
10
+ * waiting on a dead connection recovers well before the viewer gives up.
11
+ */
12
+ var DEFAULT_STALL_TIMEOUT_MS = 1e4;
13
+ /**
14
+ * ByteStream over HTTP: a range is one request, its body handed on a chunk at a time as it
15
+ * comes, and given up by aborting the request. A body that breaks off or stalls is asked for
16
+ * again from its next byte, as the resource's retry rules allow.
17
+ */
18
+ var HttpByteStream = class {
19
+ resource;
20
+ stallTimeoutMs;
21
+ constructor(resource, options = {}) {
22
+ this.resource = resource;
23
+ this.stallTimeoutMs = options.stallTimeoutMs ?? DEFAULT_STALL_TIMEOUT_MS;
24
+ }
25
+ stream(range) {
26
+ return { [Symbol.asyncIterator]: () => new RangeReading({
27
+ resource: this.resource,
28
+ range,
29
+ stallTimeoutMs: this.stallTimeoutMs
30
+ }) };
31
+ }
32
+ };
33
+ /**
34
+ * One range's requests and bodies. The answer must be the bytes asked for, every one and no
35
+ * more; returning the iteration aborts the request at once, a chunk still awaited coming as the
36
+ * end.
37
+ */
38
+ var RangeReading = class {
39
+ parts;
40
+ attempt;
41
+ received = 0;
42
+ ending = new Ending();
43
+ constructor(parts) {
44
+ this.parts = parts;
45
+ }
46
+ async next() {
47
+ try {
48
+ const chunk = await this.parts.resource.askingAgain(() => this.readChunk());
49
+ if (chunk) return {
50
+ done: false,
51
+ value: chunk
52
+ };
53
+ } catch (error) {
54
+ if (!this.ending.hasEnded()) {
55
+ this.end();
56
+ throw error;
57
+ }
58
+ }
59
+ this.end();
60
+ return ITERATION_END;
61
+ }
62
+ return() {
63
+ this.end();
64
+ return Promise.resolve(ITERATION_END);
65
+ }
66
+ /**
67
+ * The next chunk; none at the range's end. An attempt that fails is dropped, so the next
68
+ * asks anew for the rest of the range.
69
+ */
70
+ async readChunk() {
71
+ const { resource, range } = this.parts;
72
+ await resource.ensureFits(range);
73
+ if (this.ending.hasEnded() || range.length === 0) return void 0;
74
+ this.attempt ??= this.attemptAtTheRest();
75
+ const { attempt } = this;
76
+ try {
77
+ const read = await this.withinStallTimeout(this.readFrom(attempt));
78
+ return this.taken(read);
79
+ } catch (error) {
80
+ this.drop(attempt);
81
+ throw error;
82
+ }
83
+ }
84
+ attemptAtTheRest() {
85
+ const { range } = this.parts;
86
+ const rest = ByteRange.of(range.offset + this.received, range.length - this.received);
87
+ const request = new AbortController();
88
+ return {
89
+ request,
90
+ body: this.bodyOf(rest, request.signal)
91
+ };
92
+ }
93
+ async bodyOf(rest, signal) {
94
+ const response = await this.parts.resource.rangeAnswer(rest, signal);
95
+ this.ensureAnswers(response, rest);
96
+ return response.body?.getReader() ?? new ReadableStream().getReader();
97
+ }
98
+ /**
99
+ * A server may answer other bytes than asked (a cache serving a range it holds); the answer
100
+ * says which in its Content-Range, where the page may read it.
101
+ */
102
+ ensureAnswers(response, rest) {
103
+ const answered = contentRangeOf(response);
104
+ if (!answered) return;
105
+ const asked = `${rest.offset}-${rest.end - 1}`;
106
+ const given = `${answered.first}-${answered.last}`;
107
+ if (given === asked) return;
108
+ throw new GyroViewError("source-unreadable", `${this.parts.resource.url} answered bytes ${given} to a request for bytes ${asked}`);
109
+ }
110
+ async readFrom(attempt) {
111
+ const body = await attempt.body;
112
+ try {
113
+ return await body.read();
114
+ } catch (error) {
115
+ if (isAbortError(error)) throw error;
116
+ throw brokenOff(this.parts.resource.url, this.parts.range, error);
117
+ }
118
+ }
119
+ /**
120
+ * A request that brings no byte for the stall timeout, answer or body, is taken for stalled:
121
+ * a connection a network change left dead never fails by itself.
122
+ */
123
+ async withinStallTimeout(pending) {
124
+ let timer;
125
+ const stalled = new Promise((_, reject) => {
126
+ timer = setTimeout(() => {
127
+ reject(this.stalled());
128
+ }, this.parts.stallTimeoutMs);
129
+ });
130
+ try {
131
+ return await Promise.race([pending, stalled]);
132
+ } finally {
133
+ clearTimeout(timer);
134
+ }
135
+ }
136
+ stalled() {
137
+ const { resource, range, stallTimeoutMs } = this.parts;
138
+ const message = `${resource.url} sent nothing of the ${range.length}-byte range at ${range.offset} for ${stallTimeoutMs} ms`;
139
+ return passing(new GyroViewError("source-unreadable", message));
140
+ }
141
+ taken(read) {
142
+ if (read.done) {
143
+ this.ensureWhole();
144
+ return;
145
+ }
146
+ this.count(read.value);
147
+ return read.value;
148
+ }
149
+ count(chunk) {
150
+ const { resource, range } = this.parts;
151
+ this.received += chunk.byteLength;
152
+ if (this.received <= range.length) return;
153
+ throw new GyroViewError("source-unreadable", `${resource.url} sent more than the ${range.length}-byte range at ${range.offset}`);
154
+ }
155
+ ensureWhole() {
156
+ const { resource, range } = this.parts;
157
+ if (this.received !== range.length) throw truncated(resource.url, this.received, range);
158
+ }
159
+ drop(attempt) {
160
+ attempt.request.abort();
161
+ if (this.attempt === attempt) this.attempt = void 0;
162
+ }
163
+ /**
164
+ * Aborting the request once it is over, however it ended, also lets go of the listeners it
165
+ * put on the resource's own signal.
166
+ */
167
+ end() {
168
+ this.ending.end();
169
+ if (this.attempt) this.drop(this.attempt);
170
+ }
171
+ };
172
+ //#endregion
173
+ export { HttpByteStream };
@@ -0,0 +1,37 @@
1
+ import { isAbortError } from "../../../core/src/shared/errors/GyroViewError.js";
2
+ import { brokenOff, truncated } from "./rangeFailures.js";
3
+ //#region ../../packages/adapters/fetch/src/HttpRangeSource.ts
4
+ /**
5
+ * RandomAccessSource over HTTP: each range read whole, in one request, asked for again when it
6
+ * fails on the way. It shares its resource with the recording's byte stream, so both know one
7
+ * size, one proof of CORS and one version.
8
+ */
9
+ var HttpRangeSource = class {
10
+ resource;
11
+ constructor(resource) {
12
+ this.resource = resource;
13
+ }
14
+ size() {
15
+ return this.resource.size();
16
+ }
17
+ async read(range) {
18
+ await this.resource.ensureFits(range);
19
+ return range.length === 0 ? /* @__PURE__ */ new Uint8Array() : this.resource.askingAgain(() => this.readOnce(range));
20
+ }
21
+ async readOnce(range) {
22
+ const response = await this.resource.rangeAnswer(range);
23
+ const bytes = await this.bodyOf(response, range);
24
+ if (bytes.byteLength !== range.length) throw truncated(this.resource.url, bytes.byteLength, range);
25
+ return bytes;
26
+ }
27
+ async bodyOf(response, range) {
28
+ try {
29
+ return new Uint8Array(await response.arrayBuffer());
30
+ } catch (error) {
31
+ if (isAbortError(error)) throw error;
32
+ throw brokenOff(this.resource.url, range, error);
33
+ }
34
+ }
35
+ };
36
+ //#endregion
37
+ export { HttpRangeSource };
@@ -0,0 +1,227 @@
1
+ import { GyroViewError, isAbortError } from "../../../core/src/shared/errors/GyroViewError.js";
2
+ import { milliseconds, millisecondsToSeconds } from "../../../core/src/shared/units/time.js";
3
+ import { contentRangeOf } from "./contentRange.js";
4
+ import { isPassing, passing, passingIfUnreachable } from "./passingFailures.js";
5
+ import { EXPOSED_HEADERS_ADVICE, FIRST_BYTE_RANGE, discardBody, httpRequest, plainHttpRequest, withAbortSignal } from "./httpRequest.js";
6
+ import { isSameVersion, versionOf } from "./recordingVersion.js";
7
+ //#region ../../packages/adapters/fetch/src/HttpResource.ts
8
+ var HTTP_OK = 200;
9
+ var HTTP_PARTIAL_CONTENT = 206;
10
+ var HTTP_TOO_MANY_REQUESTS = 429;
11
+ var HTTP_SERVER_ERROR = 500;
12
+ var DEFAULT_RETRY_DELAYS_MS = [250, 1e3];
13
+ /**
14
+ * One recording at a URL, as every reader of it sees it: its size, whether its server has shown
15
+ * it lets this page read it (CORS), the version its first answer told of (ADR 0029), and how a
16
+ * range that failed on the way is asked for again.
17
+ * The server must answer `Range` requests with 206 and, for cross-origin use, send CORS headers
18
+ * that expose `Content-Range`; both are hard requirements of playing a remote recording and are
19
+ * reported with distinct error codes.
20
+ */
21
+ var HttpResource = class {
22
+ url;
23
+ options;
24
+ retryDelaysMs;
25
+ sizePromise;
26
+ /**
27
+ * A range has come through: CORS is proven for this resource, so a request that fails from
28
+ * here on failed on the way, whatever the diagnosis says of an error page without CORS headers.
29
+ */
30
+ hasReadRange = false;
31
+ version;
32
+ now;
33
+ shortestAnswerMs;
34
+ /**
35
+ * `signal` ends every request made for the resource, with the host's own `requestInit` signal.
36
+ */
37
+ constructor(url, options = {}, signal) {
38
+ this.url = url;
39
+ this.options = signal ? withAbortSignal(options, signal) : options;
40
+ this.retryDelaysMs = options.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS;
41
+ this.now = options.now ?? (() => performance.now());
42
+ }
43
+ /**
44
+ * How long its server took to answer a byte range, from asking to the answer's headers: the
45
+ * shortest wait of the ranges answered so far, so a first one slowed by a new connection, a
46
+ * CORS preflight or a cold cache counts for nothing (ADR 0044). A HEAD, which a server may
47
+ * answer from what it knows of the file without reading it, and a refusal tell nothing.
48
+ * Undefined until a range was answered.
49
+ */
50
+ answerWait() {
51
+ const shortest = this.shortestAnswerMs;
52
+ return shortest === void 0 ? void 0 : millisecondsToSeconds(milliseconds(shortest));
53
+ }
54
+ /**
55
+ * One HEAD request (or a one-byte range where HEAD is refused or gives no length), cached for
56
+ * the lifetime of the resource once it succeeded; a failed lookup is retried on the next call.
57
+ */
58
+ size() {
59
+ this.sizePromise ??= this.rememberSize();
60
+ return this.sizePromise;
61
+ }
62
+ /**
63
+ * Servers clamp out-of-range requests instead of failing them; the port contracts want a
64
+ * typed error, so the range is checked against the (cached) size first.
65
+ */
66
+ async ensureFits(range) {
67
+ range.ensureWithin(await this.size(), `resource ${this.url}`);
68
+ }
69
+ /**
70
+ * Runs `attempt`, and after a short wait again, a few times, while it fails on the way: one
71
+ * dropped connection must not end a long playback, nor a server's 5xx or its 429 asking the
72
+ * player to slow down. What asking again cannot change (an abort, any other refusal, a server
73
+ * ignoring ranges, CORS) fails at once.
74
+ */
75
+ async askingAgain(attempt) {
76
+ for (const delayMs of this.retryDelaysMs) {
77
+ try {
78
+ return await attempt();
79
+ } catch (error) {
80
+ if (!isPassing(error)) throw error;
81
+ }
82
+ await wait(delayMs, this.options.requestInit?.signal);
83
+ }
84
+ return attempt();
85
+ }
86
+ /**
87
+ * The server's answer to a byte range, its body still to be read: a 206, or the refusal it
88
+ * amounts to. `signal` ends this request alone.
89
+ */
90
+ async rangeAnswer(range, signal) {
91
+ const options = signal ? withAbortSignal(this.options, signal) : this.options;
92
+ const response = await this.requestRange(range, options);
93
+ if (response.status !== HTTP_PARTIAL_CONTENT) {
94
+ discardBody(response);
95
+ throw this.refusalOf(response.status);
96
+ }
97
+ this.hasReadRange = true;
98
+ this.ensureUnchanged(response);
99
+ return response;
100
+ }
101
+ /**
102
+ * Every answer is of the version the first one told of: bytes of a recording replaced while it
103
+ * plays must not be put together with the old ones'.
104
+ */
105
+ ensureUnchanged(response) {
106
+ const seen = versionOf(response);
107
+ this.version ??= seen;
108
+ if (isSameVersion(this.version, seen)) return;
109
+ discardBody(response);
110
+ throw new GyroViewError("source-changed", `${this.url} was replaced while it played; load it again`);
111
+ }
112
+ /**
113
+ * A request that did not get through for want of a network is worth another try; one CORS
114
+ * refused before any range came through is not.
115
+ */
116
+ async requestRange(range, options) {
117
+ const headers = { Range: `bytes=${range.offset}-${range.end - 1}` };
118
+ try {
119
+ return await this.timed(() => this.hasReadRange ? plainHttpRequest(this.url, {
120
+ method: "GET",
121
+ headers
122
+ }, options) : httpRequest(this.url, {
123
+ method: "GET",
124
+ headers
125
+ }, options));
126
+ } catch (error) {
127
+ throw this.hasReadRange ? this.passingOnceAnswered(error) : passingIfUnreachable(error);
128
+ }
129
+ }
130
+ passingOnceAnswered(error) {
131
+ const message = `${this.url} could not be reached for a byte range`;
132
+ return isAbortError(error) ? error : passing(new GyroViewError("source-unreadable", message, { cause: error }));
133
+ }
134
+ refusalOf(status) {
135
+ if (status === HTTP_OK) return new GyroViewError("range-unsupported", `${this.url} ignores Range requests (answered 200 to a byte range)`);
136
+ const message = `${this.url} answered ${status} to a byte range`;
137
+ return isPassingStatus(status) ? passing(new GyroViewError("source-unreadable", message)) : new GyroViewError("source-unreadable", message);
138
+ }
139
+ async rememberSize() {
140
+ try {
141
+ return await this.fetchSize();
142
+ } catch (error) {
143
+ this.sizePromise = void 0;
144
+ throw error;
145
+ }
146
+ }
147
+ async fetchSize() {
148
+ const response = await this.request("HEAD");
149
+ discardBody(response);
150
+ if (!response.ok) return this.sizeFromContentRange();
151
+ this.ensureUnchanged(response);
152
+ const contentLength = Number(response.headers.get("content-length"));
153
+ return Number.isSafeInteger(contentLength) && contentLength > 0 ? contentLength : this.sizeFromContentRange();
154
+ }
155
+ /**
156
+ * Some servers omit Content-Length on HEAD or refuse HEAD; a one-byte range reveals the total.
157
+ */
158
+ async sizeFromContentRange() {
159
+ const response = await this.request("GET", { Range: FIRST_BYTE_RANGE });
160
+ discardBody(response);
161
+ if (response.status !== HTTP_PARTIAL_CONTENT) throw new GyroViewError("source-unreadable", `${this.url} answered ${response.status} to a byte range; cannot determine the file size`);
162
+ this.hasReadRange = true;
163
+ this.ensureUnchanged(response);
164
+ return this.totalOf(response);
165
+ }
166
+ totalOf(response) {
167
+ if (!response.headers.has("content-range") && response.type === "cors") throw this.hiddenContentRange();
168
+ const total = contentRangeOf(response)?.total;
169
+ if (total === void 0) throw new GyroViewError("source-unreadable", `${this.url} reports neither Content-Length nor Content-Range; cannot determine the file size`);
170
+ return total;
171
+ }
172
+ hiddenContentRange() {
173
+ return new GyroViewError("cors", `${this.url} answered a byte range but hides its Content-Range from this origin; add ${EXPOSED_HEADERS_ADVICE}`);
174
+ }
175
+ request(method, headers) {
176
+ return this.timed(() => httpRequest(this.url, {
177
+ method,
178
+ ...headers && { headers }
179
+ }, this.options));
180
+ }
181
+ /**
182
+ * The request, its wait noted when it brought a range's bytes (206); one that failed, was
183
+ * given up or was refused tells nothing.
184
+ */
185
+ async timed(send) {
186
+ const askedAt = this.now();
187
+ const response = await send();
188
+ if (response.status !== HTTP_PARTIAL_CONTENT) return response;
189
+ const waitMs = this.now() - askedAt;
190
+ this.shortestAnswerMs = Math.min(waitMs, this.shortestAnswerMs ?? waitMs);
191
+ return response;
192
+ }
193
+ };
194
+ /**
195
+ * A server error, or a server asking the player to slow down (429, as rate-limited APIs answer):
196
+ * both may pass by the time the range is asked for again. Any other refusal stands.
197
+ */
198
+ function isPassingStatus(status) {
199
+ return status >= HTTP_SERVER_ERROR || status === HTTP_TOO_MANY_REQUESTS;
200
+ }
201
+ /**
202
+ * A pause before asking again, which an abort of the resource's requests ends at once.
203
+ */
204
+ function wait(ms, signal) {
205
+ return new Promise((resolve, reject) => {
206
+ signal?.throwIfAborted();
207
+ const settled = new AbortController();
208
+ const timer = setTimeout(() => {
209
+ settled.abort();
210
+ resolve();
211
+ }, ms);
212
+ const onAbort = () => {
213
+ clearTimeout(timer);
214
+ reject(abortErrorOf(signal));
215
+ };
216
+ signal?.addEventListener("abort", onAbort, {
217
+ once: true,
218
+ signal: settled.signal
219
+ });
220
+ });
221
+ }
222
+ function abortErrorOf(signal) {
223
+ const reason = signal?.reason;
224
+ return reason instanceof Error ? reason : new DOMException("the read was aborted", "AbortError");
225
+ }
226
+ //#endregion
227
+ export { HttpResource };
@@ -0,0 +1,35 @@
1
+ import { FIRST_BYTE_RANGE, discardBody, plainHttpRequest } from "./httpRequest.js";
2
+ //#region ../../packages/adapters/fetch/src/HttpResourceLocator.ts
3
+ /**
4
+ * How a server refuses HEAD: a 405, or a 403 from a URL signed for GET alone. The first byte
5
+ * then answers what HEAD would.
6
+ */
7
+ var REFUSED_HEAD = /* @__PURE__ */ new Set([405, 403]);
8
+ /**
9
+ * ResourceLocator over HTTP: one HEAD request, or a one-byte GET when the server refuses HEAD.
10
+ * Every failure, including a missing CORS header, means "not available"; the file looked for is
11
+ * optional, so nothing here throws, and no request is spent explaining a failure.
12
+ */
13
+ var HttpResourceLocator = class {
14
+ options;
15
+ constructor(options = {}) {
16
+ this.options = options;
17
+ }
18
+ async exists(url) {
19
+ try {
20
+ const head = await plainHttpRequest(url, { method: "HEAD" }, this.options);
21
+ discardBody(head);
22
+ if (!REFUSED_HEAD.has(head.status)) return head.ok;
23
+ const firstByte = await plainHttpRequest(url, {
24
+ method: "GET",
25
+ headers: { Range: FIRST_BYTE_RANGE }
26
+ }, this.options);
27
+ discardBody(firstByte);
28
+ return firstByte.ok;
29
+ } catch {
30
+ return false;
31
+ }
32
+ }
33
+ };
34
+ //#endregion
35
+ export { HttpResourceLocator };
@@ -0,0 +1,15 @@
1
+ //#region ../../packages/adapters/fetch/src/contentRange.ts
2
+ var CONTENT_RANGE = /^bytes (\d+)-(\d+)\/(\d+|\*)$/u;
3
+ var UNKNOWN_TOTAL = "*";
4
+ function contentRangeOf(response) {
5
+ const match = CONTENT_RANGE.exec(response.headers.get("content-range") ?? "");
6
+ if (!match) return void 0;
7
+ const [, first, last, total] = match;
8
+ return {
9
+ first: Number(first),
10
+ last: Number(last),
11
+ total: total === UNKNOWN_TOTAL ? void 0 : Number(total)
12
+ };
13
+ }
14
+ //#endregion
15
+ export { contentRangeOf };
@@ -0,0 +1,136 @@
1
+ import { GyroViewError, isAbortError } from "../../../core/src/shared/errors/GyroViewError.js";
2
+ //#region ../../packages/adapters/fetch/src/httpRequest.ts
3
+ /**
4
+ * The Range header value that asks for the first byte only: enough to learn whether a resource
5
+ * is there, or its total size from Content-Range.
6
+ */
7
+ var FIRST_BYTE_RANGE = "bytes=0-0";
8
+ /**
9
+ * The response headers a cross-origin page must be let read, as the fix a CORS failure names;
10
+ * `ETag` is optional, and tells a recording replaced while it plays more surely than
11
+ * `Last-Modified`, which a page may always read.
12
+ */
13
+ var EXPOSED_HEADERS_ADVICE = "Access-Control-Expose-Headers: Content-Range, Content-Length, Accept-Ranges, ETag";
14
+ /**
15
+ * What a server must add for a page to read it across origins. A request that carries the
16
+ * visitor's cookies is held to more: the Fetch standard refuses a wildcard origin for it.
17
+ */
18
+ var ANONYMOUS_CORS_ADVICE = `Access-Control-Allow-Origin, ${EXPOSED_HEADERS_ADVICE}`;
19
+ var CREDENTIALED_CORS_ADVICE = `Access-Control-Allow-Origin naming this page's origin, not *; Access-Control-Allow-Credentials: true; ${EXPOSED_HEADERS_ADVICE}`;
20
+ /**
21
+ * Browsers keep byte ranges of one URL as a sparse cache entry and revalidate them with
22
+ * conditional requests. A 304 to such a request makes the browser answer from that entry, and
23
+ * Chrome has been seen to hand back an empty body for a range it believed it held (ADR 0013).
24
+ * The download holds what it needs itself, so nothing is lost by leaving the cache out.
25
+ */
26
+ var CACHE_MODE = "no-store";
27
+ /**
28
+ * One request with the shared settings merged in, failures explained: a request that fails
29
+ * outright is told apart from one the browser blocked for want of CORS headers (the latter is
30
+ * `cors`, the former `source-unreadable`). A caller's abort is passed on as it is.
31
+ */
32
+ async function httpRequest(url, request, options) {
33
+ try {
34
+ return await plainHttpRequest(url, request, options);
35
+ } catch (error) {
36
+ if (isAbortError(error)) throw error;
37
+ throw await diagnoseFailure(url, options, error);
38
+ }
39
+ }
40
+ /**
41
+ * One request with the shared settings merged in and its failure left as the platform reported
42
+ * it, for callers to whom any failure means the same.
43
+ */
44
+ function plainHttpRequest(url, request, options) {
45
+ return (options.fetch ?? fetch)(url, {
46
+ cache: CACHE_MODE,
47
+ ...options.requestInit,
48
+ method: request.method,
49
+ headers: {
50
+ ...headersOf(options.requestInit),
51
+ ...request.headers
52
+ }
53
+ });
54
+ }
55
+ /**
56
+ * The options with `signal` ending their requests too, beside any signal the host gave: made once
57
+ * per source, so the listeners it adds do not pile up per request.
58
+ */
59
+ function withAbortSignal(options, signal) {
60
+ const hostSignal = options.requestInit?.signal ?? void 0;
61
+ const either = hostSignal ? eitherSignal(hostSignal, signal) : signal;
62
+ return {
63
+ ...options,
64
+ requestInit: {
65
+ ...options.requestInit,
66
+ signal: either
67
+ }
68
+ };
69
+ }
70
+ /**
71
+ * Fires when either does. `AbortSignal.any` would do, but iOS Safari has it only from 17.4.
72
+ * Whichever fires takes both listeners along, so a long-lived host signal keeps none.
73
+ */
74
+ function eitherSignal(first, second) {
75
+ const controller = new AbortController();
76
+ for (const signal of [first, second]) {
77
+ if (signal.aborted) controller.abort(signal.reason);
78
+ signal.addEventListener("abort", () => {
79
+ controller.abort(signal.reason);
80
+ }, {
81
+ once: true,
82
+ signal: controller.signal
83
+ });
84
+ }
85
+ return controller.signal;
86
+ }
87
+ /**
88
+ * Browsers report a CORS refusal and a network failure alike, as a rejected fetch. A request
89
+ * that asks for no CORS answer at all (an opaque response) still succeeds when the server is
90
+ * reachable, so its outcome tells the two apart.
91
+ */
92
+ async function diagnoseFailure(url, options, cause) {
93
+ return await isReachableWithoutCors(url, options) ? new GyroViewError("cors", `${url} answered, but its server does not allow this page's origin to read it; add CORS headers (${corsAdviceFor(options)})`, { cause }) : new GyroViewError("source-unreadable", `${url} could not be fetched; check the URL and the network`, { cause });
94
+ }
95
+ function corsAdviceFor(options) {
96
+ return options.requestInit?.credentials === "include" ? CREDENTIALED_CORS_ADVICE : ANONYMOUS_CORS_ADVICE;
97
+ }
98
+ /**
99
+ * The probe ends with the request it diagnoses: an abort of the load ends it too.
100
+ */
101
+ async function isReachableWithoutCors(url, options) {
102
+ const doFetch = options.fetch ?? fetch;
103
+ const signal = options.requestInit?.signal ?? null;
104
+ try {
105
+ discardBody(await doFetch(url, {
106
+ method: "HEAD",
107
+ mode: "no-cors",
108
+ signal
109
+ }));
110
+ return true;
111
+ } catch (error) {
112
+ if (isAbortError(error)) throw error;
113
+ return false;
114
+ }
115
+ }
116
+ /**
117
+ * Lets the browser stop streaming a body that will not be read, for example a whole file
118
+ * answered to a byte range.
119
+ */
120
+ function discardBody(response) {
121
+ cancelBody(response);
122
+ }
123
+ /**
124
+ * A body the request's abort already ended refuses the cancel with that abort: there is nothing
125
+ * left to stop, and the abort reaches the caller through the request itself.
126
+ */
127
+ async function cancelBody(response) {
128
+ try {
129
+ await response.body?.cancel();
130
+ } catch {}
131
+ }
132
+ function headersOf(init) {
133
+ return Object.fromEntries(new Headers(init?.headers).entries());
134
+ }
135
+ //#endregion
136
+ export { EXPOSED_HEADERS_ADVICE, FIRST_BYTE_RANGE, discardBody, httpRequest, plainHttpRequest, withAbortSignal };